blob: bfc85fc02acac3441c7c20524606a1ee6faf10b5 [file] [log] [blame]
niklase@google.com470e71d2011-07-07 08:21:25 +00001/*
xians@webrtc.org79af7342012-01-31 12:22:14 +00002 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
niklase@google.com470e71d2011-07-07 08:21:25 +00003 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000011#include "webrtc/voice_engine/voe_base_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000012
Peter Kastingdce40cf2015-08-24 14:52:23 -070013#include "webrtc/base/format_macros.h"
pbosad856222015-11-27 09:48:36 -080014#include "webrtc/base/logging.h"
turaj@webrtc.org03f33702013-11-13 00:02:48 +000015#include "webrtc/common.h"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000016#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
ossu5f7cfa52016-05-30 08:11:28 -070017#include "webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h"
kjellander3e6db232015-11-26 04:44:54 -080018#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000019#include "webrtc/modules/audio_device/audio_device_impl.h"
20#include "webrtc/modules/audio_processing/include/audio_processing.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010021#include "webrtc/system_wrappers/include/file_wrapper.h"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000022#include "webrtc/voice_engine/channel.h"
23#include "webrtc/voice_engine/include/voe_errors.h"
24#include "webrtc/voice_engine/output_mixer.h"
25#include "webrtc/voice_engine/transmit_mixer.h"
26#include "webrtc/voice_engine/utility.h"
27#include "webrtc/voice_engine/voice_engine_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000028
Jelena Marusic2dd6a272015-04-14 09:47:00 +020029namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000030
Jelena Marusic2dd6a272015-04-14 09:47:00 +020031VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine) {
32 if (nullptr == voiceEngine) {
33 return nullptr;
34 }
35 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
36 s->AddRef();
37 return s;
niklase@google.com470e71d2011-07-07 08:21:25 +000038}
39
Jelena Marusic2dd6a272015-04-14 09:47:00 +020040VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared)
41 : voiceEngineObserverPtr_(nullptr),
Jelena Marusic2dd6a272015-04-14 09:47:00 +020042 shared_(shared) {}
43
44VoEBaseImpl::~VoEBaseImpl() {
45 TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +000046}
47
solenberg13725082015-11-25 08:16:52 -080048void VoEBaseImpl::OnErrorIsReported(const ErrorCode error) {
tommi31fc21f2016-01-21 10:37:37 -080049 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +020050 int errCode = 0;
51 if (error == AudioDeviceObserver::kRecordingError) {
52 errCode = VE_RUNTIME_REC_ERROR;
53 LOG_F(LS_ERROR) << "VE_RUNTIME_REC_ERROR";
54 } else if (error == AudioDeviceObserver::kPlayoutError) {
55 errCode = VE_RUNTIME_PLAY_ERROR;
56 LOG_F(LS_ERROR) << "VE_RUNTIME_PLAY_ERROR";
57 }
58 if (voiceEngineObserverPtr_) {
59 // Deliver callback (-1 <=> no channel dependency)
60 voiceEngineObserverPtr_->CallbackOnError(-1, errCode);
61 }
niklase@google.com470e71d2011-07-07 08:21:25 +000062}
63
solenberg13725082015-11-25 08:16:52 -080064void VoEBaseImpl::OnWarningIsReported(const WarningCode warning) {
tommi31fc21f2016-01-21 10:37:37 -080065 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +020066 int warningCode = 0;
67 if (warning == AudioDeviceObserver::kRecordingWarning) {
68 warningCode = VE_RUNTIME_REC_WARNING;
69 LOG_F(LS_WARNING) << "VE_RUNTIME_REC_WARNING";
70 } else if (warning == AudioDeviceObserver::kPlayoutWarning) {
71 warningCode = VE_RUNTIME_PLAY_WARNING;
72 LOG_F(LS_WARNING) << "VE_RUNTIME_PLAY_WARNING";
73 }
74 if (voiceEngineObserverPtr_) {
75 // Deliver callback (-1 <=> no channel dependency)
76 voiceEngineObserverPtr_->CallbackOnError(-1, warningCode);
77 }
niklase@google.com470e71d2011-07-07 08:21:25 +000078}
79
solenberg13725082015-11-25 08:16:52 -080080int32_t VoEBaseImpl::RecordedDataIsAvailable(const void* audioSamples,
81 const size_t nSamples,
82 const size_t nBytesPerSample,
Peter Kasting69558702016-01-12 16:26:35 -080083 const size_t nChannels,
solenberg13725082015-11-25 08:16:52 -080084 const uint32_t samplesPerSec,
85 const uint32_t totalDelayMS,
86 const int32_t clockDrift,
87 const uint32_t currentMicLevel,
88 const bool keyPressed,
89 uint32_t& newMicLevel) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020090 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
91 nullptr, 0, audioSamples, samplesPerSec, nChannels, nSamples,
solenberg13725082015-11-25 08:16:52 -080092 totalDelayMS, clockDrift, currentMicLevel, keyPressed));
Jelena Marusic2dd6a272015-04-14 09:47:00 +020093 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000094}
95
solenberg13725082015-11-25 08:16:52 -080096int32_t VoEBaseImpl::NeedMorePlayData(const size_t nSamples,
97 const size_t nBytesPerSample,
Peter Kasting69558702016-01-12 16:26:35 -080098 const size_t nChannels,
solenberg13725082015-11-25 08:16:52 -080099 const uint32_t samplesPerSec,
100 void* audioSamples,
101 size_t& nSamplesOut,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200102 int64_t* elapsed_time_ms,
103 int64_t* ntp_time_ms) {
Peter Kasting69558702016-01-12 16:26:35 -0800104 GetPlayoutData(static_cast<int>(samplesPerSec), nChannels, nSamples, true,
105 audioSamples, elapsed_time_ms, ntp_time_ms);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200106 nSamplesOut = audioFrame_.samples_per_channel_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000107 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000108}
109
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000110int VoEBaseImpl::OnDataAvailable(const int voe_channels[],
Peter Kasting69558702016-01-12 16:26:35 -0800111 size_t number_of_voe_channels,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200112 const int16_t* audio_data, int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800113 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700114 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200115 int audio_delay_milliseconds, int volume,
116 bool key_pressed, bool need_audio_processing) {
117 if (number_of_voe_channels == 0) return 0;
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000118
119 if (need_audio_processing) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000120 return ProcessRecordedDataWithAPM(
121 voe_channels, number_of_voe_channels, audio_data, sample_rate,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200122 number_of_channels, number_of_frames, audio_delay_milliseconds, 0,
123 volume, key_pressed);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000124 }
125
126 // No need to go through the APM, demultiplex the data to each VoE channel,
127 // encode and send to the network.
Peter Kasting69558702016-01-12 16:26:35 -0800128 for (size_t i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000129 // TODO(ajm): In the case where multiple channels are using the same codec
130 // rate, this path needlessly does extra conversions. We should convert once
131 // and share between channels.
xians@webrtc.org56925312014-04-14 10:50:37 +0000132 PushCaptureData(voe_channels[i], audio_data, 16, sample_rate,
133 number_of_channels, number_of_frames);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000134 }
135
136 // Return 0 to indicate no need to change the volume.
137 return 0;
138}
139
xians@webrtc.orgc1e28032014-02-02 15:30:20 +0000140void VoEBaseImpl::OnData(int voe_channel, const void* audio_data,
141 int bits_per_sample, int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800142 size_t number_of_channels, size_t number_of_frames) {
xians@webrtc.org56925312014-04-14 10:50:37 +0000143 PushCaptureData(voe_channel, audio_data, bits_per_sample, sample_rate,
144 number_of_channels, number_of_frames);
145}
146
147void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
148 int bits_per_sample, int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800149 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700150 size_t number_of_frames) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200151 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel);
xians@webrtc.org07e51962014-01-29 13:54:02 +0000152 voe::Channel* channel_ptr = ch.channel();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200153 if (!channel_ptr) return;
xians@webrtc.org07e51962014-01-29 13:54:02 +0000154
henrika@webrtc.org66803482014-04-17 10:45:01 +0000155 if (channel_ptr->Sending()) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000156 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
157 sample_rate, number_of_frames, number_of_channels);
158 channel_ptr->PrepareEncodeAndSend(sample_rate);
159 channel_ptr->EncodeAndSend();
160 }
161}
162
Peter Kastingdce40cf2015-08-24 14:52:23 -0700163void VoEBaseImpl::PullRenderData(int bits_per_sample,
164 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800165 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700166 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200167 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000168 int64_t* ntp_time_ms) {
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200169 assert(bits_per_sample == 16);
Peter Kastingdce40cf2015-08-24 14:52:23 -0700170 assert(number_of_frames == static_cast<size_t>(sample_rate / 100));
xians@webrtc.org56925312014-04-14 10:50:37 +0000171
172 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000173 audio_data, elapsed_time_ms, ntp_time_ms);
xians@webrtc.org56925312014-04-14 10:50:37 +0000174}
175
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200176int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer) {
tommi31fc21f2016-01-21 10:37:37 -0800177 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200178 if (voiceEngineObserverPtr_) {
179 shared_->SetLastError(
180 VE_INVALID_OPERATION, kTraceError,
181 "RegisterVoiceEngineObserver() observer already enabled");
182 return -1;
183 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000184
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200185 // Register the observer in all active channels
186 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
187 it.IsValid(); it.Increment()) {
188 it.GetChannel()->RegisterVoiceEngineObserver(observer);
189 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000190
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200191 shared_->transmit_mixer()->RegisterVoiceEngineObserver(observer);
192 voiceEngineObserverPtr_ = &observer;
193 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000194}
195
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200196int VoEBaseImpl::DeRegisterVoiceEngineObserver() {
tommi31fc21f2016-01-21 10:37:37 -0800197 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200198 if (!voiceEngineObserverPtr_) {
199 shared_->SetLastError(
200 VE_INVALID_OPERATION, kTraceError,
201 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000202 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200203 }
204 voiceEngineObserverPtr_ = nullptr;
205
206 // Deregister the observer in all active channels
207 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
208 it.IsValid(); it.Increment()) {
209 it.GetChannel()->DeRegisterVoiceEngineObserver();
210 }
211
212 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000213}
214
ossu5f7cfa52016-05-30 08:11:28 -0700215int VoEBaseImpl::Init(
216 AudioDeviceModule* external_adm,
217 AudioProcessing* audioproc,
218 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
tommi31fc21f2016-01-21 10:37:37 -0800219 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200220 WebRtcSpl_Init();
221 if (shared_->statistics().Initialized()) {
222 return 0;
223 }
224 if (shared_->process_thread()) {
225 shared_->process_thread()->Start();
226 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000227
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200228 // Create an internal ADM if the user has not added an external
229 // ADM implementation as input to Init().
230 if (external_adm == nullptr) {
Tommi931e6582015-05-20 09:44:38 +0200231#if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
232 return -1;
233#else
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200234 // Create the internal ADM implementation.
Peter Boström4adbbcf2016-05-03 15:51:26 -0400235 shared_->set_audio_device(AudioDeviceModule::Create(
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200236 VoEId(shared_->instance_id(), -1), shared_->audio_device_layer()));
kma@webrtc.org0221b782012-09-08 00:09:26 +0000237
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200238 if (shared_->audio_device() == nullptr) {
239 shared_->SetLastError(VE_NO_MEMORY, kTraceCritical,
240 "Init() failed to create the ADM");
241 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000242 }
Tommi931e6582015-05-20 09:44:38 +0200243#endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200244 } else {
245 // Use the already existing external ADM implementation.
246 shared_->set_audio_device(external_adm);
247 LOG_F(LS_INFO)
248 << "An external ADM implementation will be used in VoiceEngine";
249 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000250
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200251 // Register the ADM to the process thread, which will drive the error
252 // callback mechanism
253 if (shared_->process_thread()) {
254 shared_->process_thread()->RegisterModule(shared_->audio_device());
255 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000256
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200257 bool available = false;
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000258
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200259 // --------------------
260 // Reinitialize the ADM
henrika@google.com73d65512011-09-07 15:11:18 +0000261
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200262 // Register the AudioObserver implementation
263 if (shared_->audio_device()->RegisterEventObserver(this) != 0) {
264 shared_->SetLastError(
265 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
266 "Init() failed to register event observer for the ADM");
267 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000268
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200269 // Register the AudioTransport implementation
270 if (shared_->audio_device()->RegisterAudioCallback(this) != 0) {
271 shared_->SetLastError(
272 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
273 "Init() failed to register audio callback for the ADM");
274 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000275
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200276 // ADM initialization
277 if (shared_->audio_device()->Init() != 0) {
278 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
279 "Init() failed to initialize the ADM");
280 return -1;
281 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000282
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200283 // Initialize the default speaker
284 if (shared_->audio_device()->SetPlayoutDevice(
285 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
286 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
287 "Init() failed to set the default output device");
288 }
289 if (shared_->audio_device()->InitSpeaker() != 0) {
290 shared_->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
291 "Init() failed to initialize the speaker");
292 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000293
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200294 // Initialize the default microphone
295 if (shared_->audio_device()->SetRecordingDevice(
296 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
297 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
298 "Init() failed to set the default input device");
299 }
300 if (shared_->audio_device()->InitMicrophone() != 0) {
301 shared_->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
302 "Init() failed to initialize the microphone");
303 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000304
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200305 // Set number of channels
306 if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
307 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
308 "Init() failed to query stereo playout mode");
309 }
310 if (shared_->audio_device()->SetStereoPlayout(available) != 0) {
311 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
312 "Init() failed to set mono/stereo playout mode");
313 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000314
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200315 // TODO(andrew): These functions don't tell us whether stereo recording
316 // is truly available. We simply set the AudioProcessing input to stereo
317 // here, because we have to wait until receiving the first frame to
318 // determine the actual number of channels anyway.
319 //
320 // These functions may be changed; tracked here:
321 // http://code.google.com/p/webrtc/issues/detail?id=204
322 shared_->audio_device()->StereoRecordingIsAvailable(&available);
323 if (shared_->audio_device()->SetStereoRecording(available) != 0) {
324 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
325 "Init() failed to set mono/stereo recording mode");
326 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000327
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200328 if (!audioproc) {
329 audioproc = AudioProcessing::Create();
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000330 if (!audioproc) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200331 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
332 shared_->SetLastError(VE_NO_MEMORY);
333 return -1;
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000334 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200335 }
336 shared_->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000337
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200338 // Set the error state for any failures in this block.
339 shared_->SetLastError(VE_APM_ERROR);
340 // Configure AudioProcessing components.
341 if (audioproc->high_pass_filter()->Enable(true) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200342 LOG_F(LS_ERROR) << "Failed to enable high pass filter.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200343 return -1;
344 }
345 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200346 LOG_F(LS_ERROR) << "Failed to disable drift compensation.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200347 return -1;
348 }
349 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200350 LOG_F(LS_ERROR) << "Failed to set noise suppression level: "
351 << kDefaultNsMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200352 return -1;
353 }
354 GainControl* agc = audioproc->gain_control();
355 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200356 LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: "
357 << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200358 return -1;
359 }
360 if (agc->set_mode(kDefaultAgcMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200361 LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200362 return -1;
363 }
364 if (agc->Enable(kDefaultAgcState) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200365 LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200366 return -1;
367 }
368 shared_->SetLastError(0); // Clear error state.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000369
niklase@google.com470e71d2011-07-07 08:21:25 +0000370#ifdef WEBRTC_VOICE_ENGINE_AGC
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200371 bool agc_enabled =
372 agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled();
373 if (shared_->audio_device()->SetAGC(agc_enabled) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200374 LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200375 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
376 // TODO(ajm): No error return here due to
377 // https://code.google.com/p/webrtc/issues/detail?id=1464
378 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000379#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000380
ossu5f7cfa52016-05-30 08:11:28 -0700381 if (decoder_factory)
382 decoder_factory_ = decoder_factory;
383 else
384 decoder_factory_ = CreateBuiltinAudioDecoderFactory();
385
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200386 return shared_->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000387}
388
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200389int VoEBaseImpl::Terminate() {
tommi31fc21f2016-01-21 10:37:37 -0800390 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200391 return TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000392}
393
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000394int VoEBaseImpl::CreateChannel() {
tommi31fc21f2016-01-21 10:37:37 -0800395 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200396 if (!shared_->statistics().Initialized()) {
397 shared_->SetLastError(VE_NOT_INITED, kTraceError);
398 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000399 }
400
ossu5f7cfa52016-05-30 08:11:28 -0700401 voe::ChannelOwner channel_owner =
402 shared_->channel_manager().CreateChannel(decoder_factory_);
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000403 return InitializeChannel(&channel_owner);
404}
405
406int VoEBaseImpl::CreateChannel(const Config& config) {
tommi31fc21f2016-01-21 10:37:37 -0800407 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200408 if (!shared_->statistics().Initialized()) {
409 shared_->SetLastError(VE_NOT_INITED, kTraceError);
410 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000411 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200412 voe::ChannelOwner channel_owner =
ossu5f7cfa52016-05-30 08:11:28 -0700413 shared_->channel_manager().CreateChannel(config, decoder_factory_);
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000414 return InitializeChannel(&channel_owner);
415}
416
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200417int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) {
418 if (channel_owner->channel()->SetEngineInformation(
419 shared_->statistics(), *shared_->output_mixer(),
420 *shared_->transmit_mixer(), *shared_->process_thread(),
421 *shared_->audio_device(), voiceEngineObserverPtr_,
422 &callbackCritSect_) != 0) {
423 shared_->SetLastError(
424 VE_CHANNEL_NOT_CREATED, kTraceError,
425 "CreateChannel() failed to associate engine and channel."
426 " Destroying channel.");
427 shared_->channel_manager().DestroyChannel(
428 channel_owner->channel()->ChannelId());
429 return -1;
430 } else if (channel_owner->channel()->Init() != 0) {
431 shared_->SetLastError(
432 VE_CHANNEL_NOT_CREATED, kTraceError,
433 "CreateChannel() failed to initialize channel. Destroying"
434 " channel.");
435 shared_->channel_manager().DestroyChannel(
436 channel_owner->channel()->ChannelId());
437 return -1;
438 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200439 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000440}
441
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200442int VoEBaseImpl::DeleteChannel(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800443 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200444 if (!shared_->statistics().Initialized()) {
445 shared_->SetLastError(VE_NOT_INITED, kTraceError);
446 return -1;
447 }
448
449 {
450 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
451 voe::Channel* channelPtr = ch.channel();
452 if (channelPtr == nullptr) {
453 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
454 "DeleteChannel() failed to locate channel");
455 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000456 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200457 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000458
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200459 shared_->channel_manager().DestroyChannel(channel);
460 if (StopSend() != 0) {
461 return -1;
462 }
463 if (StopPlayout() != 0) {
464 return -1;
465 }
466 return 0;
467}
niklase@google.com470e71d2011-07-07 08:21:25 +0000468
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200469int VoEBaseImpl::StartReceive(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800470 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200471 if (!shared_->statistics().Initialized()) {
472 shared_->SetLastError(VE_NOT_INITED, kTraceError);
473 return -1;
474 }
475 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
476 voe::Channel* channelPtr = ch.channel();
477 if (channelPtr == nullptr) {
478 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
479 "StartReceive() failed to locate channel");
480 return -1;
481 }
482 return channelPtr->StartReceiving();
483}
niklase@google.com470e71d2011-07-07 08:21:25 +0000484
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200485int VoEBaseImpl::StopReceive(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800486 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200487 if (!shared_->statistics().Initialized()) {
488 shared_->SetLastError(VE_NOT_INITED, kTraceError);
489 return -1;
490 }
491 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
492 voe::Channel* channelPtr = ch.channel();
493 if (channelPtr == nullptr) {
494 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
495 "SetLocalReceiver() failed to locate channel");
496 return -1;
497 }
498 return channelPtr->StopReceiving();
499}
niklase@google.com470e71d2011-07-07 08:21:25 +0000500
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200501int VoEBaseImpl::StartPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800502 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200503 if (!shared_->statistics().Initialized()) {
504 shared_->SetLastError(VE_NOT_INITED, kTraceError);
505 return -1;
506 }
507 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
508 voe::Channel* channelPtr = ch.channel();
509 if (channelPtr == nullptr) {
510 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
511 "StartPlayout() failed to locate channel");
512 return -1;
513 }
514 if (channelPtr->Playing()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000515 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200516 }
517 if (StartPlayout() != 0) {
518 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
519 "StartPlayout() failed to start playout");
520 return -1;
521 }
522 return channelPtr->StartPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000523}
524
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200525int VoEBaseImpl::StopPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800526 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200527 if (!shared_->statistics().Initialized()) {
528 shared_->SetLastError(VE_NOT_INITED, kTraceError);
529 return -1;
530 }
531 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
532 voe::Channel* channelPtr = ch.channel();
533 if (channelPtr == nullptr) {
534 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
535 "StopPlayout() failed to locate channel");
536 return -1;
537 }
538 if (channelPtr->StopPlayout() != 0) {
539 LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
540 << channel;
541 }
542 return StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000543}
544
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200545int VoEBaseImpl::StartSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800546 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200547 if (!shared_->statistics().Initialized()) {
548 shared_->SetLastError(VE_NOT_INITED, kTraceError);
549 return -1;
550 }
551 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
552 voe::Channel* channelPtr = ch.channel();
553 if (channelPtr == nullptr) {
554 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
555 "StartSend() failed to locate channel");
556 return -1;
557 }
558 if (channelPtr->Sending()) {
559 return 0;
560 }
561 if (StartSend() != 0) {
562 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
563 "StartSend() failed to start recording");
564 return -1;
565 }
566 return channelPtr->StartSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000567}
568
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200569int VoEBaseImpl::StopSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800570 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200571 if (!shared_->statistics().Initialized()) {
572 shared_->SetLastError(VE_NOT_INITED, kTraceError);
573 return -1;
574 }
575 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
576 voe::Channel* channelPtr = ch.channel();
577 if (channelPtr == nullptr) {
578 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
579 "StopSend() failed to locate channel");
580 return -1;
581 }
582 if (channelPtr->StopSend() != 0) {
583 LOG_F(LS_WARNING) << "StopSend() failed to stop sending for channel "
584 << channel;
585 }
586 return StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000587}
588
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200589int VoEBaseImpl::GetVersion(char version[1024]) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200590 if (version == nullptr) {
591 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200592 return -1;
593 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000594
solenberg2515af22015-12-02 06:19:36 -0800595 std::string versionString = VoiceEngine::GetVersionString();
596 RTC_DCHECK_GT(1024u, versionString.size() + 1);
597 char* end = std::copy(versionString.cbegin(), versionString.cend(), version);
598 end[0] = '\n';
599 end[1] = '\0';
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200600 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000601}
602
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200603int VoEBaseImpl::LastError() { return (shared_->statistics().LastError()); }
niklase@google.com470e71d2011-07-07 08:21:25 +0000604
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200605int32_t VoEBaseImpl::StartPlayout() {
solenberge313e022015-09-08 02:16:04 -0700606 if (!shared_->audio_device()->Playing()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200607 if (shared_->audio_device()->InitPlayout() != 0) {
608 LOG_F(LS_ERROR) << "Failed to initialize playout";
609 return -1;
610 }
611 if (shared_->audio_device()->StartPlayout() != 0) {
612 LOG_F(LS_ERROR) << "Failed to start playout";
613 return -1;
614 }
615 }
616 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000617}
618
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000619int32_t VoEBaseImpl::StopPlayout() {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000620 // Stop audio-device playing if no channel is playing out
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200621 if (shared_->NumOfPlayingChannels() == 0) {
622 if (shared_->audio_device()->StopPlayout() != 0) {
623 shared_->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000624 "StopPlayout() failed to stop playout");
625 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000626 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000627 }
628 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000629}
630
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200631int32_t VoEBaseImpl::StartSend() {
solenbergd53a3f92016-04-14 13:56:37 -0700632 if (!shared_->audio_device()->RecordingIsInitialized() &&
633 !shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200634 if (shared_->audio_device()->InitRecording() != 0) {
635 LOG_F(LS_ERROR) << "Failed to initialize recording";
636 return -1;
637 }
solenbergd53a3f92016-04-14 13:56:37 -0700638 }
639 if (!shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200640 if (shared_->audio_device()->StartRecording() != 0) {
641 LOG_F(LS_ERROR) << "Failed to start recording";
642 return -1;
643 }
644 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200645 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000646}
647
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200648int32_t VoEBaseImpl::StopSend() {
649 if (shared_->NumOfSendingChannels() == 0 &&
650 !shared_->transmit_mixer()->IsRecordingMic()) {
651 // Stop audio-device recording if no channel is recording
652 if (shared_->audio_device()->StopRecording() != 0) {
653 shared_->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
654 "StopSend() failed to stop recording");
655 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000656 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200657 shared_->transmit_mixer()->StopSend();
658 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000659
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200660 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000661}
662
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200663int32_t VoEBaseImpl::TerminateInternal() {
664 // Delete any remaining channel objects
665 shared_->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000666
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200667 if (shared_->process_thread()) {
668 if (shared_->audio_device()) {
669 shared_->process_thread()->DeRegisterModule(shared_->audio_device());
niklase@google.com470e71d2011-07-07 08:21:25 +0000670 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200671 shared_->process_thread()->Stop();
672 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000673
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200674 if (shared_->audio_device()) {
675 if (shared_->audio_device()->StopPlayout() != 0) {
676 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
677 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000678 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200679 if (shared_->audio_device()->StopRecording() != 0) {
680 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
681 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000682 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200683 if (shared_->audio_device()->RegisterEventObserver(nullptr) != 0) {
684 shared_->SetLastError(
685 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
686 "TerminateInternal() failed to de-register event observer "
687 "for the ADM");
688 }
689 if (shared_->audio_device()->RegisterAudioCallback(nullptr) != 0) {
690 shared_->SetLastError(
691 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
692 "TerminateInternal() failed to de-register audio callback "
693 "for the ADM");
694 }
695 if (shared_->audio_device()->Terminate() != 0) {
696 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
697 "TerminateInternal() failed to terminate the ADM");
698 }
699 shared_->set_audio_device(nullptr);
700 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000701
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200702 if (shared_->audio_processing()) {
703 shared_->set_audio_processing(nullptr);
704 }
705
706 return shared_->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000707}
708
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000709int VoEBaseImpl::ProcessRecordedDataWithAPM(
Peter Kasting69558702016-01-12 16:26:35 -0800710 const int voe_channels[], size_t number_of_voe_channels,
711 const void* audio_data, uint32_t sample_rate, size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700712 size_t number_of_frames, uint32_t audio_delay_milliseconds,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200713 int32_t clock_drift, uint32_t volume, bool key_pressed) {
714 assert(shared_->transmit_mixer() != nullptr);
715 assert(shared_->audio_device() != nullptr);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000716
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000717 uint32_t max_volume = 0;
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000718 uint16_t voe_mic_level = 0;
andrew@webrtc.org023cc5a2014-01-11 01:25:53 +0000719 // Check for zero to skip this calculation; the consumer may use this to
720 // indicate no volume is available.
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000721 if (volume != 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000722 // Scale from ADM to VoE level range
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200723 if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000724 if (max_volume) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000725 voe_mic_level = static_cast<uint16_t>(
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200726 (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) /
727 max_volume);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000728 }
729 }
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000730 // We learned that on certain systems (e.g Linux) the voe_mic_level
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000731 // can be greater than the maxVolumeLevel therefore
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000732 // we are going to cap the voe_mic_level to the maxVolumeLevel
733 // and change the maxVolume to volume if it turns out that
734 // the voe_mic_level is indeed greater than the maxVolumeLevel.
735 if (voe_mic_level > kMaxVolumeLevel) {
736 voe_mic_level = kMaxVolumeLevel;
737 max_volume = volume;
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000738 }
739 }
740
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000741 // Perform channel-independent operations
742 // (APM, mix with file, record to file, mute, etc.)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200743 shared_->transmit_mixer()->PrepareDemux(
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000744 audio_data, number_of_frames, number_of_channels, sample_rate,
745 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000746 voe_mic_level, key_pressed);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000747
748 // Copy the audio frame to each sending channel and perform
749 // channel-dependent operations (file mixing, mute, etc.), encode and
750 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
751 // do the operations on all the existing VoE channels; otherwise the
752 // operations will be done on specific channels.
753 if (number_of_voe_channels == 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200754 shared_->transmit_mixer()->DemuxAndMix();
755 shared_->transmit_mixer()->EncodeAndSend();
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000756 } else {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200757 shared_->transmit_mixer()->DemuxAndMix(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000758 number_of_voe_channels);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200759 shared_->transmit_mixer()->EncodeAndSend(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000760 number_of_voe_channels);
761 }
762
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000763 // Scale from VoE to ADM level range.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200764 uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel();
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000765 if (new_voe_mic_level != voe_mic_level) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000766 // Return the new volume if AGC has changed the volume.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200767 return static_cast<int>((new_voe_mic_level * max_volume +
768 static_cast<int>(kMaxVolumeLevel / 2)) /
769 kMaxVolumeLevel);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000770 }
771
772 // Return 0 to indicate no change on the volume.
773 return 0;
774}
775
Peter Kasting69558702016-01-12 16:26:35 -0800776void VoEBaseImpl::GetPlayoutData(int sample_rate, size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700777 size_t number_of_frames, bool feed_data_to_apm,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200778 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000779 int64_t* ntp_time_ms) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200780 assert(shared_->output_mixer() != nullptr);
xians@webrtc.org56925312014-04-14 10:50:37 +0000781
782 // TODO(andrew): if the device is running in mono, we should tell the mixer
783 // here so that it will only request mono from AudioCodingModule.
784 // Perform mixing of all active participants (channel-based mixing)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200785 shared_->output_mixer()->MixActiveChannels();
xians@webrtc.org56925312014-04-14 10:50:37 +0000786
787 // Additional operations on the combined signal
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200788 shared_->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
xians@webrtc.org56925312014-04-14 10:50:37 +0000789
790 // Retrieve the final output mix (resampled to match the ADM)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200791 shared_->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
792 &audioFrame_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000793
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200794 assert(number_of_frames == audioFrame_.samples_per_channel_);
795 assert(sample_rate == audioFrame_.sample_rate_hz_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000796
797 // Deliver audio (PCM) samples to the ADM
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200798 memcpy(audio_data, audioFrame_.data_,
xians@webrtc.org56925312014-04-14 10:50:37 +0000799 sizeof(int16_t) * number_of_frames * number_of_channels);
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000800
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200801 *elapsed_time_ms = audioFrame_.elapsed_time_ms_;
802 *ntp_time_ms = audioFrame_.ntp_time_ms_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000803}
804
Minyue2013aec2015-05-13 14:14:42 +0200805int VoEBaseImpl::AssociateSendChannel(int channel,
806 int accociate_send_channel) {
tommi31fc21f2016-01-21 10:37:37 -0800807 rtc::CritScope cs(shared_->crit_sec());
Minyue2013aec2015-05-13 14:14:42 +0200808
809 if (!shared_->statistics().Initialized()) {
810 shared_->SetLastError(VE_NOT_INITED, kTraceError);
811 return -1;
812 }
813
814 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
815 voe::Channel* channel_ptr = ch.channel();
816 if (channel_ptr == NULL) {
817 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
818 "AssociateSendChannel() failed to locate channel");
819 return -1;
820 }
821
822 ch = shared_->channel_manager().GetChannel(accociate_send_channel);
823 voe::Channel* accociate_send_channel_ptr = ch.channel();
824 if (accociate_send_channel_ptr == NULL) {
825 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
826 "AssociateSendChannel() failed to locate accociate_send_channel");
827 return -1;
828 }
829
830 channel_ptr->set_associate_send_channel(ch);
831 return 0;
832}
833
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000834} // namespace webrtc