blob: d1981a4a3a72a55495009f4e9dbcff4c004d7d15 [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
kwiberg087bd342017-02-10 08:15:44 -080013#include "webrtc/api/audio_codecs/builtin_audio_decoder_factory.h"
Peter Kastingdce40cf2015-08-24 14:52:23 -070014#include "webrtc/base/format_macros.h"
tommidea489f2017-03-03 03:20:24 -080015#include "webrtc/base/location.h"
pbosad856222015-11-27 09:48:36 -080016#include "webrtc/base/logging.h"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000017#include "webrtc/common_audio/signal_processing/include/signal_processing_library.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.org56925312014-04-14 10:50:37 +0000110void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
111 int bits_per_sample, int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800112 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700113 size_t number_of_frames) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200114 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel);
xians@webrtc.org07e51962014-01-29 13:54:02 +0000115 voe::Channel* channel_ptr = ch.channel();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200116 if (!channel_ptr) return;
xians@webrtc.org07e51962014-01-29 13:54:02 +0000117
henrika@webrtc.org66803482014-04-17 10:45:01 +0000118 if (channel_ptr->Sending()) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000119 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
120 sample_rate, number_of_frames, number_of_channels);
121 channel_ptr->PrepareEncodeAndSend(sample_rate);
122 channel_ptr->EncodeAndSend();
123 }
124}
125
Peter Kastingdce40cf2015-08-24 14:52:23 -0700126void VoEBaseImpl::PullRenderData(int bits_per_sample,
127 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800128 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700129 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200130 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000131 int64_t* ntp_time_ms) {
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200132 assert(bits_per_sample == 16);
Peter Kastingdce40cf2015-08-24 14:52:23 -0700133 assert(number_of_frames == static_cast<size_t>(sample_rate / 100));
xians@webrtc.org56925312014-04-14 10:50:37 +0000134
135 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000136 audio_data, elapsed_time_ms, ntp_time_ms);
xians@webrtc.org56925312014-04-14 10:50:37 +0000137}
138
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200139int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer) {
tommi31fc21f2016-01-21 10:37:37 -0800140 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200141 if (voiceEngineObserverPtr_) {
142 shared_->SetLastError(
143 VE_INVALID_OPERATION, kTraceError,
144 "RegisterVoiceEngineObserver() observer already enabled");
145 return -1;
146 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000147
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200148 // Register the observer in all active channels
149 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
150 it.IsValid(); it.Increment()) {
151 it.GetChannel()->RegisterVoiceEngineObserver(observer);
152 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000153
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200154 shared_->transmit_mixer()->RegisterVoiceEngineObserver(observer);
155 voiceEngineObserverPtr_ = &observer;
156 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000157}
158
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200159int VoEBaseImpl::DeRegisterVoiceEngineObserver() {
tommi31fc21f2016-01-21 10:37:37 -0800160 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200161 if (!voiceEngineObserverPtr_) {
162 shared_->SetLastError(
163 VE_INVALID_OPERATION, kTraceError,
164 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000165 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200166 }
167 voiceEngineObserverPtr_ = nullptr;
168
169 // Deregister the observer in all active channels
170 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
171 it.IsValid(); it.Increment()) {
172 it.GetChannel()->DeRegisterVoiceEngineObserver();
173 }
174
175 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000176}
177
ossu5f7cfa52016-05-30 08:11:28 -0700178int VoEBaseImpl::Init(
179 AudioDeviceModule* external_adm,
180 AudioProcessing* audioproc,
181 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
tommi31fc21f2016-01-21 10:37:37 -0800182 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200183 WebRtcSpl_Init();
184 if (shared_->statistics().Initialized()) {
185 return 0;
186 }
187 if (shared_->process_thread()) {
188 shared_->process_thread()->Start();
189 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000190
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200191 // Create an internal ADM if the user has not added an external
192 // ADM implementation as input to Init().
193 if (external_adm == nullptr) {
Tommi931e6582015-05-20 09:44:38 +0200194#if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
195 return -1;
196#else
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200197 // Create the internal ADM implementation.
Peter Boström4adbbcf2016-05-03 15:51:26 -0400198 shared_->set_audio_device(AudioDeviceModule::Create(
solenberg5b3e49a2017-03-15 08:08:07 -0700199 VoEId(shared_->instance_id(), -1),
200 AudioDeviceModule::kPlatformDefaultAudio));
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200201 if (shared_->audio_device() == nullptr) {
202 shared_->SetLastError(VE_NO_MEMORY, kTraceCritical,
203 "Init() failed to create the ADM");
204 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205 }
Tommi931e6582015-05-20 09:44:38 +0200206#endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200207 } else {
208 // Use the already existing external ADM implementation.
209 shared_->set_audio_device(external_adm);
210 LOG_F(LS_INFO)
211 << "An external ADM implementation will be used in VoiceEngine";
212 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000213
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200214 // Register the ADM to the process thread, which will drive the error
215 // callback mechanism
216 if (shared_->process_thread()) {
tommidea489f2017-03-03 03:20:24 -0800217 shared_->process_thread()->RegisterModule(shared_->audio_device(),
218 RTC_FROM_HERE);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200219 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000220
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200221 bool available = false;
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000222
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200223 // --------------------
224 // Reinitialize the ADM
henrika@google.com73d65512011-09-07 15:11:18 +0000225
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200226 // Register the AudioObserver implementation
227 if (shared_->audio_device()->RegisterEventObserver(this) != 0) {
228 shared_->SetLastError(
229 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
230 "Init() failed to register event observer for the ADM");
231 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000232
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200233 // Register the AudioTransport implementation
234 if (shared_->audio_device()->RegisterAudioCallback(this) != 0) {
235 shared_->SetLastError(
236 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
237 "Init() failed to register audio callback for the ADM");
238 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000239
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200240 // ADM initialization
241 if (shared_->audio_device()->Init() != 0) {
242 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
243 "Init() failed to initialize the ADM");
244 return -1;
245 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000246
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200247 // Initialize the default speaker
248 if (shared_->audio_device()->SetPlayoutDevice(
249 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
250 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
251 "Init() failed to set the default output device");
252 }
253 if (shared_->audio_device()->InitSpeaker() != 0) {
254 shared_->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
255 "Init() failed to initialize the speaker");
256 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000257
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200258 // Initialize the default microphone
259 if (shared_->audio_device()->SetRecordingDevice(
260 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
261 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
262 "Init() failed to set the default input device");
263 }
264 if (shared_->audio_device()->InitMicrophone() != 0) {
265 shared_->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
266 "Init() failed to initialize the microphone");
267 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000268
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200269 // Set number of channels
270 if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
271 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
272 "Init() failed to query stereo playout mode");
273 }
274 if (shared_->audio_device()->SetStereoPlayout(available) != 0) {
275 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
276 "Init() failed to set mono/stereo playout mode");
277 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000278
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200279 // TODO(andrew): These functions don't tell us whether stereo recording
280 // is truly available. We simply set the AudioProcessing input to stereo
281 // here, because we have to wait until receiving the first frame to
282 // determine the actual number of channels anyway.
283 //
284 // These functions may be changed; tracked here:
285 // http://code.google.com/p/webrtc/issues/detail?id=204
286 shared_->audio_device()->StereoRecordingIsAvailable(&available);
287 if (shared_->audio_device()->SetStereoRecording(available) != 0) {
288 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
289 "Init() failed to set mono/stereo recording mode");
290 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000291
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200292 if (!audioproc) {
293 audioproc = AudioProcessing::Create();
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000294 if (!audioproc) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200295 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
296 shared_->SetLastError(VE_NO_MEMORY);
297 return -1;
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000298 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200299 }
300 shared_->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000301
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200302 // Set the error state for any failures in this block.
303 shared_->SetLastError(VE_APM_ERROR);
304 // Configure AudioProcessing components.
305 if (audioproc->high_pass_filter()->Enable(true) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200306 LOG_F(LS_ERROR) << "Failed to enable high pass filter.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200307 return -1;
308 }
309 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200310 LOG_F(LS_ERROR) << "Failed to disable drift compensation.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200311 return -1;
312 }
313 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200314 LOG_F(LS_ERROR) << "Failed to set noise suppression level: "
315 << kDefaultNsMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200316 return -1;
317 }
318 GainControl* agc = audioproc->gain_control();
319 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200320 LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: "
321 << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200322 return -1;
323 }
324 if (agc->set_mode(kDefaultAgcMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200325 LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200326 return -1;
327 }
328 if (agc->Enable(kDefaultAgcState) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200329 LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200330 return -1;
331 }
332 shared_->SetLastError(0); // Clear error state.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000333
niklase@google.com470e71d2011-07-07 08:21:25 +0000334#ifdef WEBRTC_VOICE_ENGINE_AGC
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200335 bool agc_enabled =
336 agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled();
337 if (shared_->audio_device()->SetAGC(agc_enabled) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200338 LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200339 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
340 // TODO(ajm): No error return here due to
341 // https://code.google.com/p/webrtc/issues/detail?id=1464
342 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000343#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000344
ossu5f7cfa52016-05-30 08:11:28 -0700345 if (decoder_factory)
346 decoder_factory_ = decoder_factory;
347 else
348 decoder_factory_ = CreateBuiltinAudioDecoderFactory();
349
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200350 return shared_->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000351}
352
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200353int VoEBaseImpl::Terminate() {
tommi31fc21f2016-01-21 10:37:37 -0800354 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200355 return TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000356}
357
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000358int VoEBaseImpl::CreateChannel() {
solenberg88499ec2016-09-07 07:34:41 -0700359 return CreateChannel(ChannelConfig());
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000360}
361
solenberg88499ec2016-09-07 07:34:41 -0700362int VoEBaseImpl::CreateChannel(const ChannelConfig& config) {
tommi31fc21f2016-01-21 10:37:37 -0800363 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200364 if (!shared_->statistics().Initialized()) {
365 shared_->SetLastError(VE_NOT_INITED, kTraceError);
366 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000367 }
solenberg88499ec2016-09-07 07:34:41 -0700368
369 ChannelConfig config_copy(config);
370 config_copy.acm_config.decoder_factory = decoder_factory_;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200371 voe::ChannelOwner channel_owner =
solenberg88499ec2016-09-07 07:34:41 -0700372 shared_->channel_manager().CreateChannel(config_copy);
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000373 return InitializeChannel(&channel_owner);
374}
375
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200376int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) {
377 if (channel_owner->channel()->SetEngineInformation(
378 shared_->statistics(), *shared_->output_mixer(),
solenberg796b8f92017-03-01 17:02:23 -0800379 *shared_->process_thread(), *shared_->audio_device(),
380 voiceEngineObserverPtr_, &callbackCritSect_) != 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200381 shared_->SetLastError(
382 VE_CHANNEL_NOT_CREATED, kTraceError,
383 "CreateChannel() failed to associate engine and channel."
384 " Destroying channel.");
385 shared_->channel_manager().DestroyChannel(
386 channel_owner->channel()->ChannelId());
387 return -1;
388 } else if (channel_owner->channel()->Init() != 0) {
389 shared_->SetLastError(
390 VE_CHANNEL_NOT_CREATED, kTraceError,
391 "CreateChannel() failed to initialize channel. Destroying"
392 " channel.");
393 shared_->channel_manager().DestroyChannel(
394 channel_owner->channel()->ChannelId());
395 return -1;
396 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200397 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000398}
399
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200400int VoEBaseImpl::DeleteChannel(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800401 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200402 if (!shared_->statistics().Initialized()) {
403 shared_->SetLastError(VE_NOT_INITED, kTraceError);
404 return -1;
405 }
406
407 {
408 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
409 voe::Channel* channelPtr = ch.channel();
410 if (channelPtr == nullptr) {
411 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
412 "DeleteChannel() failed to locate channel");
413 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000414 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200415 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000416
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200417 shared_->channel_manager().DestroyChannel(channel);
418 if (StopSend() != 0) {
419 return -1;
420 }
421 if (StopPlayout() != 0) {
422 return -1;
423 }
424 return 0;
425}
niklase@google.com470e71d2011-07-07 08:21:25 +0000426
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200427int VoEBaseImpl::StartReceive(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800428 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200429 if (!shared_->statistics().Initialized()) {
430 shared_->SetLastError(VE_NOT_INITED, kTraceError);
431 return -1;
432 }
433 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
434 voe::Channel* channelPtr = ch.channel();
435 if (channelPtr == nullptr) {
436 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
437 "StartReceive() failed to locate channel");
438 return -1;
439 }
solenberge566ac72016-10-31 12:52:33 -0700440 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200441}
niklase@google.com470e71d2011-07-07 08:21:25 +0000442
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200443int VoEBaseImpl::StartPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800444 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200445 if (!shared_->statistics().Initialized()) {
446 shared_->SetLastError(VE_NOT_INITED, kTraceError);
447 return -1;
448 }
449 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
450 voe::Channel* channelPtr = ch.channel();
451 if (channelPtr == nullptr) {
452 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
453 "StartPlayout() failed to locate channel");
454 return -1;
455 }
456 if (channelPtr->Playing()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000457 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200458 }
459 if (StartPlayout() != 0) {
460 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
461 "StartPlayout() failed to start playout");
462 return -1;
463 }
464 return channelPtr->StartPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000465}
466
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200467int VoEBaseImpl::StopPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800468 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200469 if (!shared_->statistics().Initialized()) {
470 shared_->SetLastError(VE_NOT_INITED, kTraceError);
471 return -1;
472 }
473 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
474 voe::Channel* channelPtr = ch.channel();
475 if (channelPtr == nullptr) {
476 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
477 "StopPlayout() failed to locate channel");
478 return -1;
479 }
480 if (channelPtr->StopPlayout() != 0) {
481 LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
482 << channel;
483 }
484 return StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000485}
486
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200487int VoEBaseImpl::StartSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800488 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200489 if (!shared_->statistics().Initialized()) {
490 shared_->SetLastError(VE_NOT_INITED, kTraceError);
491 return -1;
492 }
493 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
494 voe::Channel* channelPtr = ch.channel();
495 if (channelPtr == nullptr) {
496 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
497 "StartSend() failed to locate channel");
498 return -1;
499 }
500 if (channelPtr->Sending()) {
501 return 0;
502 }
503 if (StartSend() != 0) {
504 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
505 "StartSend() failed to start recording");
506 return -1;
507 }
508 return channelPtr->StartSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000509}
510
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200511int VoEBaseImpl::StopSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800512 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200513 if (!shared_->statistics().Initialized()) {
514 shared_->SetLastError(VE_NOT_INITED, kTraceError);
515 return -1;
516 }
517 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
518 voe::Channel* channelPtr = ch.channel();
519 if (channelPtr == nullptr) {
520 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
521 "StopSend() failed to locate channel");
522 return -1;
523 }
524 if (channelPtr->StopSend() != 0) {
525 LOG_F(LS_WARNING) << "StopSend() failed to stop sending for channel "
526 << channel;
527 }
528 return StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000529}
530
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200531int VoEBaseImpl::GetVersion(char version[1024]) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200532 if (version == nullptr) {
533 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200534 return -1;
535 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000536
solenberg2515af22015-12-02 06:19:36 -0800537 std::string versionString = VoiceEngine::GetVersionString();
kwibergaf476c72016-11-28 15:21:39 -0800538 RTC_DCHECK_GT(1024, versionString.size() + 1);
solenberg2515af22015-12-02 06:19:36 -0800539 char* end = std::copy(versionString.cbegin(), versionString.cend(), version);
540 end[0] = '\n';
541 end[1] = '\0';
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200542 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000543}
544
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200545int VoEBaseImpl::LastError() { return (shared_->statistics().LastError()); }
niklase@google.com470e71d2011-07-07 08:21:25 +0000546
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200547int32_t VoEBaseImpl::StartPlayout() {
solenberge313e022015-09-08 02:16:04 -0700548 if (!shared_->audio_device()->Playing()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200549 if (shared_->audio_device()->InitPlayout() != 0) {
550 LOG_F(LS_ERROR) << "Failed to initialize playout";
551 return -1;
552 }
553 if (shared_->audio_device()->StartPlayout() != 0) {
554 LOG_F(LS_ERROR) << "Failed to start playout";
555 return -1;
556 }
557 }
558 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000559}
560
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000561int32_t VoEBaseImpl::StopPlayout() {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000562 // Stop audio-device playing if no channel is playing out
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200563 if (shared_->NumOfPlayingChannels() == 0) {
564 if (shared_->audio_device()->StopPlayout() != 0) {
565 shared_->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000566 "StopPlayout() failed to stop playout");
567 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000568 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000569 }
570 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000571}
572
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200573int32_t VoEBaseImpl::StartSend() {
solenbergd53a3f92016-04-14 13:56:37 -0700574 if (!shared_->audio_device()->RecordingIsInitialized() &&
575 !shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200576 if (shared_->audio_device()->InitRecording() != 0) {
577 LOG_F(LS_ERROR) << "Failed to initialize recording";
578 return -1;
579 }
solenbergd53a3f92016-04-14 13:56:37 -0700580 }
581 if (!shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200582 if (shared_->audio_device()->StartRecording() != 0) {
583 LOG_F(LS_ERROR) << "Failed to start recording";
584 return -1;
585 }
586 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200587 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000588}
589
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200590int32_t VoEBaseImpl::StopSend() {
591 if (shared_->NumOfSendingChannels() == 0 &&
592 !shared_->transmit_mixer()->IsRecordingMic()) {
593 // Stop audio-device recording if no channel is recording
594 if (shared_->audio_device()->StopRecording() != 0) {
595 shared_->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
596 "StopSend() failed to stop recording");
597 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000598 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200599 shared_->transmit_mixer()->StopSend();
600 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000601
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200602 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000603}
604
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200605int32_t VoEBaseImpl::TerminateInternal() {
606 // Delete any remaining channel objects
607 shared_->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000608
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200609 if (shared_->process_thread()) {
610 if (shared_->audio_device()) {
611 shared_->process_thread()->DeRegisterModule(shared_->audio_device());
niklase@google.com470e71d2011-07-07 08:21:25 +0000612 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200613 shared_->process_thread()->Stop();
614 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000615
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200616 if (shared_->audio_device()) {
617 if (shared_->audio_device()->StopPlayout() != 0) {
618 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
619 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000620 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200621 if (shared_->audio_device()->StopRecording() != 0) {
622 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
623 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000624 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200625 if (shared_->audio_device()->RegisterEventObserver(nullptr) != 0) {
626 shared_->SetLastError(
627 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
628 "TerminateInternal() failed to de-register event observer "
629 "for the ADM");
630 }
631 if (shared_->audio_device()->RegisterAudioCallback(nullptr) != 0) {
632 shared_->SetLastError(
633 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
634 "TerminateInternal() failed to de-register audio callback "
635 "for the ADM");
636 }
637 if (shared_->audio_device()->Terminate() != 0) {
638 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
639 "TerminateInternal() failed to terminate the ADM");
640 }
641 shared_->set_audio_device(nullptr);
642 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000643
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200644 if (shared_->audio_processing()) {
645 shared_->set_audio_processing(nullptr);
646 }
647
648 return shared_->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000649}
650
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000651int VoEBaseImpl::ProcessRecordedDataWithAPM(
Peter Kasting69558702016-01-12 16:26:35 -0800652 const int voe_channels[], size_t number_of_voe_channels,
653 const void* audio_data, uint32_t sample_rate, size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700654 size_t number_of_frames, uint32_t audio_delay_milliseconds,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200655 int32_t clock_drift, uint32_t volume, bool key_pressed) {
656 assert(shared_->transmit_mixer() != nullptr);
657 assert(shared_->audio_device() != nullptr);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000658
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000659 uint32_t max_volume = 0;
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000660 uint16_t voe_mic_level = 0;
andrew@webrtc.org023cc5a2014-01-11 01:25:53 +0000661 // Check for zero to skip this calculation; the consumer may use this to
662 // indicate no volume is available.
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000663 if (volume != 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000664 // Scale from ADM to VoE level range
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200665 if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000666 if (max_volume) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000667 voe_mic_level = static_cast<uint16_t>(
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200668 (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) /
669 max_volume);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000670 }
671 }
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000672 // We learned that on certain systems (e.g Linux) the voe_mic_level
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000673 // can be greater than the maxVolumeLevel therefore
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000674 // we are going to cap the voe_mic_level to the maxVolumeLevel
675 // and change the maxVolume to volume if it turns out that
676 // the voe_mic_level is indeed greater than the maxVolumeLevel.
677 if (voe_mic_level > kMaxVolumeLevel) {
678 voe_mic_level = kMaxVolumeLevel;
679 max_volume = volume;
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000680 }
681 }
682
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000683 // Perform channel-independent operations
684 // (APM, mix with file, record to file, mute, etc.)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200685 shared_->transmit_mixer()->PrepareDemux(
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000686 audio_data, number_of_frames, number_of_channels, sample_rate,
687 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000688 voe_mic_level, key_pressed);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000689
690 // Copy the audio frame to each sending channel and perform
691 // channel-dependent operations (file mixing, mute, etc.), encode and
692 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
693 // do the operations on all the existing VoE channels; otherwise the
694 // operations will be done on specific channels.
695 if (number_of_voe_channels == 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200696 shared_->transmit_mixer()->DemuxAndMix();
697 shared_->transmit_mixer()->EncodeAndSend();
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000698 } else {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200699 shared_->transmit_mixer()->DemuxAndMix(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000700 number_of_voe_channels);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200701 shared_->transmit_mixer()->EncodeAndSend(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000702 number_of_voe_channels);
703 }
704
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000705 // Scale from VoE to ADM level range.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200706 uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel();
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000707 if (new_voe_mic_level != voe_mic_level) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000708 // Return the new volume if AGC has changed the volume.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200709 return static_cast<int>((new_voe_mic_level * max_volume +
710 static_cast<int>(kMaxVolumeLevel / 2)) /
711 kMaxVolumeLevel);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000712 }
713
714 // Return 0 to indicate no change on the volume.
715 return 0;
716}
717
Peter Kasting69558702016-01-12 16:26:35 -0800718void VoEBaseImpl::GetPlayoutData(int sample_rate, size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700719 size_t number_of_frames, bool feed_data_to_apm,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200720 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000721 int64_t* ntp_time_ms) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200722 assert(shared_->output_mixer() != nullptr);
xians@webrtc.org56925312014-04-14 10:50:37 +0000723
724 // TODO(andrew): if the device is running in mono, we should tell the mixer
725 // here so that it will only request mono from AudioCodingModule.
726 // Perform mixing of all active participants (channel-based mixing)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200727 shared_->output_mixer()->MixActiveChannels();
xians@webrtc.org56925312014-04-14 10:50:37 +0000728
729 // Additional operations on the combined signal
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200730 shared_->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
xians@webrtc.org56925312014-04-14 10:50:37 +0000731
732 // Retrieve the final output mix (resampled to match the ADM)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200733 shared_->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
734 &audioFrame_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000735
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200736 assert(number_of_frames == audioFrame_.samples_per_channel_);
737 assert(sample_rate == audioFrame_.sample_rate_hz_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000738
739 // Deliver audio (PCM) samples to the ADM
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200740 memcpy(audio_data, audioFrame_.data_,
xians@webrtc.org56925312014-04-14 10:50:37 +0000741 sizeof(int16_t) * number_of_frames * number_of_channels);
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000742
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200743 *elapsed_time_ms = audioFrame_.elapsed_time_ms_;
744 *ntp_time_ms = audioFrame_.ntp_time_ms_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000745}
746
Minyue2013aec2015-05-13 14:14:42 +0200747int VoEBaseImpl::AssociateSendChannel(int channel,
748 int accociate_send_channel) {
tommi31fc21f2016-01-21 10:37:37 -0800749 rtc::CritScope cs(shared_->crit_sec());
Minyue2013aec2015-05-13 14:14:42 +0200750
751 if (!shared_->statistics().Initialized()) {
752 shared_->SetLastError(VE_NOT_INITED, kTraceError);
753 return -1;
754 }
755
756 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
757 voe::Channel* channel_ptr = ch.channel();
758 if (channel_ptr == NULL) {
759 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
760 "AssociateSendChannel() failed to locate channel");
761 return -1;
762 }
763
764 ch = shared_->channel_manager().GetChannel(accociate_send_channel);
765 voe::Channel* accociate_send_channel_ptr = ch.channel();
766 if (accociate_send_channel_ptr == NULL) {
767 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
768 "AssociateSendChannel() failed to locate accociate_send_channel");
769 return -1;
770 }
771
772 channel_ptr->set_associate_send_channel(ch);
773 return 0;
774}
775
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000776} // namespace webrtc