blob: f74bdb1dbc106ad8c1e0a2f62523a51df51deab1 [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"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000015#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
ossu5f7cfa52016-05-30 08:11:28 -070016#include "webrtc/modules/audio_coding/codecs/builtin_audio_decoder_factory.h"
kjellander3e6db232015-11-26 04:44:54 -080017#include "webrtc/modules/audio_coding/include/audio_coding_module.h"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000018#include "webrtc/modules/audio_device/audio_device_impl.h"
19#include "webrtc/modules/audio_processing/include/audio_processing.h"
Henrik Kjellander98f53512015-10-28 18:17:40 +010020#include "webrtc/system_wrappers/include/file_wrapper.h"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000021#include "webrtc/voice_engine/channel.h"
22#include "webrtc/voice_engine/include/voe_errors.h"
23#include "webrtc/voice_engine/output_mixer.h"
24#include "webrtc/voice_engine/transmit_mixer.h"
25#include "webrtc/voice_engine/utility.h"
26#include "webrtc/voice_engine/voice_engine_impl.h"
niklase@google.com470e71d2011-07-07 08:21:25 +000027
Jelena Marusic2dd6a272015-04-14 09:47:00 +020028namespace webrtc {
niklase@google.com470e71d2011-07-07 08:21:25 +000029
Jelena Marusic2dd6a272015-04-14 09:47:00 +020030VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine) {
31 if (nullptr == voiceEngine) {
32 return nullptr;
33 }
34 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
35 s->AddRef();
36 return s;
niklase@google.com470e71d2011-07-07 08:21:25 +000037}
38
Jelena Marusic2dd6a272015-04-14 09:47:00 +020039VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared)
40 : voiceEngineObserverPtr_(nullptr),
Jelena Marusic2dd6a272015-04-14 09:47:00 +020041 shared_(shared) {}
42
43VoEBaseImpl::~VoEBaseImpl() {
44 TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +000045}
46
solenberg13725082015-11-25 08:16:52 -080047void VoEBaseImpl::OnErrorIsReported(const ErrorCode error) {
tommi31fc21f2016-01-21 10:37:37 -080048 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +020049 int errCode = 0;
50 if (error == AudioDeviceObserver::kRecordingError) {
51 errCode = VE_RUNTIME_REC_ERROR;
52 LOG_F(LS_ERROR) << "VE_RUNTIME_REC_ERROR";
53 } else if (error == AudioDeviceObserver::kPlayoutError) {
54 errCode = VE_RUNTIME_PLAY_ERROR;
55 LOG_F(LS_ERROR) << "VE_RUNTIME_PLAY_ERROR";
56 }
57 if (voiceEngineObserverPtr_) {
58 // Deliver callback (-1 <=> no channel dependency)
59 voiceEngineObserverPtr_->CallbackOnError(-1, errCode);
60 }
niklase@google.com470e71d2011-07-07 08:21:25 +000061}
62
solenberg13725082015-11-25 08:16:52 -080063void VoEBaseImpl::OnWarningIsReported(const WarningCode warning) {
tommi31fc21f2016-01-21 10:37:37 -080064 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +020065 int warningCode = 0;
66 if (warning == AudioDeviceObserver::kRecordingWarning) {
67 warningCode = VE_RUNTIME_REC_WARNING;
68 LOG_F(LS_WARNING) << "VE_RUNTIME_REC_WARNING";
69 } else if (warning == AudioDeviceObserver::kPlayoutWarning) {
70 warningCode = VE_RUNTIME_PLAY_WARNING;
71 LOG_F(LS_WARNING) << "VE_RUNTIME_PLAY_WARNING";
72 }
73 if (voiceEngineObserverPtr_) {
74 // Deliver callback (-1 <=> no channel dependency)
75 voiceEngineObserverPtr_->CallbackOnError(-1, warningCode);
76 }
niklase@google.com470e71d2011-07-07 08:21:25 +000077}
78
solenberg13725082015-11-25 08:16:52 -080079int32_t VoEBaseImpl::RecordedDataIsAvailable(const void* audioSamples,
80 const size_t nSamples,
81 const size_t nBytesPerSample,
Peter Kasting69558702016-01-12 16:26:35 -080082 const size_t nChannels,
solenberg13725082015-11-25 08:16:52 -080083 const uint32_t samplesPerSec,
84 const uint32_t totalDelayMS,
85 const int32_t clockDrift,
86 const uint32_t currentMicLevel,
87 const bool keyPressed,
88 uint32_t& newMicLevel) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +020089 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
90 nullptr, 0, audioSamples, samplesPerSec, nChannels, nSamples,
solenberg13725082015-11-25 08:16:52 -080091 totalDelayMS, clockDrift, currentMicLevel, keyPressed));
Jelena Marusic2dd6a272015-04-14 09:47:00 +020092 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000093}
94
solenberg13725082015-11-25 08:16:52 -080095int32_t VoEBaseImpl::NeedMorePlayData(const size_t nSamples,
96 const size_t nBytesPerSample,
Peter Kasting69558702016-01-12 16:26:35 -080097 const size_t nChannels,
solenberg13725082015-11-25 08:16:52 -080098 const uint32_t samplesPerSec,
99 void* audioSamples,
100 size_t& nSamplesOut,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200101 int64_t* elapsed_time_ms,
102 int64_t* ntp_time_ms) {
Peter Kasting69558702016-01-12 16:26:35 -0800103 GetPlayoutData(static_cast<int>(samplesPerSec), nChannels, nSamples, true,
104 audioSamples, elapsed_time_ms, ntp_time_ms);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200105 nSamplesOut = audioFrame_.samples_per_channel_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000106 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000107}
108
xians@webrtc.org56925312014-04-14 10:50:37 +0000109void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
110 int bits_per_sample, int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800111 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700112 size_t number_of_frames) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200113 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel);
xians@webrtc.org07e51962014-01-29 13:54:02 +0000114 voe::Channel* channel_ptr = ch.channel();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200115 if (!channel_ptr) return;
xians@webrtc.org07e51962014-01-29 13:54:02 +0000116
henrika@webrtc.org66803482014-04-17 10:45:01 +0000117 if (channel_ptr->Sending()) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000118 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
119 sample_rate, number_of_frames, number_of_channels);
120 channel_ptr->PrepareEncodeAndSend(sample_rate);
121 channel_ptr->EncodeAndSend();
122 }
123}
124
Peter Kastingdce40cf2015-08-24 14:52:23 -0700125void VoEBaseImpl::PullRenderData(int bits_per_sample,
126 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800127 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700128 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200129 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000130 int64_t* ntp_time_ms) {
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200131 assert(bits_per_sample == 16);
Peter Kastingdce40cf2015-08-24 14:52:23 -0700132 assert(number_of_frames == static_cast<size_t>(sample_rate / 100));
xians@webrtc.org56925312014-04-14 10:50:37 +0000133
134 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000135 audio_data, elapsed_time_ms, ntp_time_ms);
xians@webrtc.org56925312014-04-14 10:50:37 +0000136}
137
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200138int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer) {
tommi31fc21f2016-01-21 10:37:37 -0800139 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200140 if (voiceEngineObserverPtr_) {
141 shared_->SetLastError(
142 VE_INVALID_OPERATION, kTraceError,
143 "RegisterVoiceEngineObserver() observer already enabled");
144 return -1;
145 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000146
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200147 // Register the observer in all active channels
148 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
149 it.IsValid(); it.Increment()) {
150 it.GetChannel()->RegisterVoiceEngineObserver(observer);
151 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000152
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200153 shared_->transmit_mixer()->RegisterVoiceEngineObserver(observer);
154 voiceEngineObserverPtr_ = &observer;
155 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000156}
157
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200158int VoEBaseImpl::DeRegisterVoiceEngineObserver() {
tommi31fc21f2016-01-21 10:37:37 -0800159 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200160 if (!voiceEngineObserverPtr_) {
161 shared_->SetLastError(
162 VE_INVALID_OPERATION, kTraceError,
163 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000164 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200165 }
166 voiceEngineObserverPtr_ = nullptr;
167
168 // Deregister the observer in all active channels
169 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
170 it.IsValid(); it.Increment()) {
171 it.GetChannel()->DeRegisterVoiceEngineObserver();
172 }
173
174 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000175}
176
ossu5f7cfa52016-05-30 08:11:28 -0700177int VoEBaseImpl::Init(
178 AudioDeviceModule* external_adm,
179 AudioProcessing* audioproc,
180 const rtc::scoped_refptr<AudioDecoderFactory>& decoder_factory) {
tommi31fc21f2016-01-21 10:37:37 -0800181 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200182 WebRtcSpl_Init();
183 if (shared_->statistics().Initialized()) {
184 return 0;
185 }
186 if (shared_->process_thread()) {
187 shared_->process_thread()->Start();
188 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000189
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200190 // Create an internal ADM if the user has not added an external
191 // ADM implementation as input to Init().
192 if (external_adm == nullptr) {
Tommi931e6582015-05-20 09:44:38 +0200193#if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
194 return -1;
195#else
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200196 // Create the internal ADM implementation.
Peter Boström4adbbcf2016-05-03 15:51:26 -0400197 shared_->set_audio_device(AudioDeviceModule::Create(
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200198 VoEId(shared_->instance_id(), -1), shared_->audio_device_layer()));
kma@webrtc.org0221b782012-09-08 00:09:26 +0000199
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200200 if (shared_->audio_device() == nullptr) {
201 shared_->SetLastError(VE_NO_MEMORY, kTraceCritical,
202 "Init() failed to create the ADM");
203 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000204 }
Tommi931e6582015-05-20 09:44:38 +0200205#endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200206 } else {
207 // Use the already existing external ADM implementation.
208 shared_->set_audio_device(external_adm);
209 LOG_F(LS_INFO)
210 << "An external ADM implementation will be used in VoiceEngine";
211 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000212
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200213 // Register the ADM to the process thread, which will drive the error
214 // callback mechanism
215 if (shared_->process_thread()) {
216 shared_->process_thread()->RegisterModule(shared_->audio_device());
217 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000218
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200219 bool available = false;
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000220
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200221 // --------------------
222 // Reinitialize the ADM
henrika@google.com73d65512011-09-07 15:11:18 +0000223
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200224 // Register the AudioObserver implementation
225 if (shared_->audio_device()->RegisterEventObserver(this) != 0) {
226 shared_->SetLastError(
227 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
228 "Init() failed to register event observer for the ADM");
229 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000230
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200231 // Register the AudioTransport implementation
232 if (shared_->audio_device()->RegisterAudioCallback(this) != 0) {
233 shared_->SetLastError(
234 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
235 "Init() failed to register audio callback for the ADM");
236 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000237
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200238 // ADM initialization
239 if (shared_->audio_device()->Init() != 0) {
240 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
241 "Init() failed to initialize the ADM");
242 return -1;
243 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000244
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200245 // Initialize the default speaker
246 if (shared_->audio_device()->SetPlayoutDevice(
247 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
248 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
249 "Init() failed to set the default output device");
250 }
251 if (shared_->audio_device()->InitSpeaker() != 0) {
252 shared_->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
253 "Init() failed to initialize the speaker");
254 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000255
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200256 // Initialize the default microphone
257 if (shared_->audio_device()->SetRecordingDevice(
258 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
259 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
260 "Init() failed to set the default input device");
261 }
262 if (shared_->audio_device()->InitMicrophone() != 0) {
263 shared_->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
264 "Init() failed to initialize the microphone");
265 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000266
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200267 // Set number of channels
268 if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
269 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
270 "Init() failed to query stereo playout mode");
271 }
272 if (shared_->audio_device()->SetStereoPlayout(available) != 0) {
273 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
274 "Init() failed to set mono/stereo playout mode");
275 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000276
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200277 // TODO(andrew): These functions don't tell us whether stereo recording
278 // is truly available. We simply set the AudioProcessing input to stereo
279 // here, because we have to wait until receiving the first frame to
280 // determine the actual number of channels anyway.
281 //
282 // These functions may be changed; tracked here:
283 // http://code.google.com/p/webrtc/issues/detail?id=204
284 shared_->audio_device()->StereoRecordingIsAvailable(&available);
285 if (shared_->audio_device()->SetStereoRecording(available) != 0) {
286 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
287 "Init() failed to set mono/stereo recording mode");
288 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000289
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200290 if (!audioproc) {
291 audioproc = AudioProcessing::Create();
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000292 if (!audioproc) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200293 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
294 shared_->SetLastError(VE_NO_MEMORY);
295 return -1;
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000296 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200297 }
298 shared_->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000299
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200300 // Set the error state for any failures in this block.
301 shared_->SetLastError(VE_APM_ERROR);
302 // Configure AudioProcessing components.
303 if (audioproc->high_pass_filter()->Enable(true) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200304 LOG_F(LS_ERROR) << "Failed to enable high pass filter.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200305 return -1;
306 }
307 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200308 LOG_F(LS_ERROR) << "Failed to disable drift compensation.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200309 return -1;
310 }
311 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200312 LOG_F(LS_ERROR) << "Failed to set noise suppression level: "
313 << kDefaultNsMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200314 return -1;
315 }
316 GainControl* agc = audioproc->gain_control();
317 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200318 LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: "
319 << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200320 return -1;
321 }
322 if (agc->set_mode(kDefaultAgcMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200323 LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200324 return -1;
325 }
326 if (agc->Enable(kDefaultAgcState) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200327 LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200328 return -1;
329 }
330 shared_->SetLastError(0); // Clear error state.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000331
niklase@google.com470e71d2011-07-07 08:21:25 +0000332#ifdef WEBRTC_VOICE_ENGINE_AGC
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200333 bool agc_enabled =
334 agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled();
335 if (shared_->audio_device()->SetAGC(agc_enabled) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200336 LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200337 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
338 // TODO(ajm): No error return here due to
339 // https://code.google.com/p/webrtc/issues/detail?id=1464
340 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000341#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000342
ossu5f7cfa52016-05-30 08:11:28 -0700343 if (decoder_factory)
344 decoder_factory_ = decoder_factory;
345 else
346 decoder_factory_ = CreateBuiltinAudioDecoderFactory();
347
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200348 return shared_->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000349}
350
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200351int VoEBaseImpl::Terminate() {
tommi31fc21f2016-01-21 10:37:37 -0800352 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200353 return TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000354}
355
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000356int VoEBaseImpl::CreateChannel() {
solenberg88499ec2016-09-07 07:34:41 -0700357 return CreateChannel(ChannelConfig());
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000358}
359
solenberg88499ec2016-09-07 07:34:41 -0700360int VoEBaseImpl::CreateChannel(const ChannelConfig& config) {
tommi31fc21f2016-01-21 10:37:37 -0800361 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200362 if (!shared_->statistics().Initialized()) {
363 shared_->SetLastError(VE_NOT_INITED, kTraceError);
364 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000365 }
solenberg88499ec2016-09-07 07:34:41 -0700366
367 ChannelConfig config_copy(config);
368 config_copy.acm_config.decoder_factory = decoder_factory_;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200369 voe::ChannelOwner channel_owner =
solenberg88499ec2016-09-07 07:34:41 -0700370 shared_->channel_manager().CreateChannel(config_copy);
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000371 return InitializeChannel(&channel_owner);
372}
373
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200374int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) {
375 if (channel_owner->channel()->SetEngineInformation(
376 shared_->statistics(), *shared_->output_mixer(),
377 *shared_->transmit_mixer(), *shared_->process_thread(),
378 *shared_->audio_device(), voiceEngineObserverPtr_,
379 &callbackCritSect_) != 0) {
380 shared_->SetLastError(
381 VE_CHANNEL_NOT_CREATED, kTraceError,
382 "CreateChannel() failed to associate engine and channel."
383 " Destroying channel.");
384 shared_->channel_manager().DestroyChannel(
385 channel_owner->channel()->ChannelId());
386 return -1;
387 } else if (channel_owner->channel()->Init() != 0) {
388 shared_->SetLastError(
389 VE_CHANNEL_NOT_CREATED, kTraceError,
390 "CreateChannel() failed to initialize channel. Destroying"
391 " channel.");
392 shared_->channel_manager().DestroyChannel(
393 channel_owner->channel()->ChannelId());
394 return -1;
395 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200396 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000397}
398
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200399int VoEBaseImpl::DeleteChannel(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800400 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200401 if (!shared_->statistics().Initialized()) {
402 shared_->SetLastError(VE_NOT_INITED, kTraceError);
403 return -1;
404 }
405
406 {
407 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
408 voe::Channel* channelPtr = ch.channel();
409 if (channelPtr == nullptr) {
410 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
411 "DeleteChannel() failed to locate channel");
412 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000413 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200414 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000415
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200416 shared_->channel_manager().DestroyChannel(channel);
417 if (StopSend() != 0) {
418 return -1;
419 }
420 if (StopPlayout() != 0) {
421 return -1;
422 }
423 return 0;
424}
niklase@google.com470e71d2011-07-07 08:21:25 +0000425
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200426int VoEBaseImpl::StartReceive(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800427 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200428 if (!shared_->statistics().Initialized()) {
429 shared_->SetLastError(VE_NOT_INITED, kTraceError);
430 return -1;
431 }
432 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
433 voe::Channel* channelPtr = ch.channel();
434 if (channelPtr == nullptr) {
435 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
436 "StartReceive() failed to locate channel");
437 return -1;
438 }
439 return channelPtr->StartReceiving();
440}
niklase@google.com470e71d2011-07-07 08:21:25 +0000441
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200442int VoEBaseImpl::StopReceive(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 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
449 voe::Channel* channelPtr = ch.channel();
450 if (channelPtr == nullptr) {
451 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
452 "SetLocalReceiver() failed to locate channel");
453 return -1;
454 }
455 return channelPtr->StopReceiving();
456}
niklase@google.com470e71d2011-07-07 08:21:25 +0000457
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200458int VoEBaseImpl::StartPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800459 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200460 if (!shared_->statistics().Initialized()) {
461 shared_->SetLastError(VE_NOT_INITED, kTraceError);
462 return -1;
463 }
464 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
465 voe::Channel* channelPtr = ch.channel();
466 if (channelPtr == nullptr) {
467 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
468 "StartPlayout() failed to locate channel");
469 return -1;
470 }
471 if (channelPtr->Playing()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000472 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200473 }
474 if (StartPlayout() != 0) {
475 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
476 "StartPlayout() failed to start playout");
477 return -1;
478 }
479 return channelPtr->StartPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000480}
481
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200482int VoEBaseImpl::StopPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800483 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200484 if (!shared_->statistics().Initialized()) {
485 shared_->SetLastError(VE_NOT_INITED, kTraceError);
486 return -1;
487 }
488 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
489 voe::Channel* channelPtr = ch.channel();
490 if (channelPtr == nullptr) {
491 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
492 "StopPlayout() failed to locate channel");
493 return -1;
494 }
495 if (channelPtr->StopPlayout() != 0) {
496 LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
497 << channel;
498 }
499 return StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000500}
501
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200502int VoEBaseImpl::StartSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800503 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200504 if (!shared_->statistics().Initialized()) {
505 shared_->SetLastError(VE_NOT_INITED, kTraceError);
506 return -1;
507 }
508 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
509 voe::Channel* channelPtr = ch.channel();
510 if (channelPtr == nullptr) {
511 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
512 "StartSend() failed to locate channel");
513 return -1;
514 }
515 if (channelPtr->Sending()) {
516 return 0;
517 }
518 if (StartSend() != 0) {
519 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
520 "StartSend() failed to start recording");
521 return -1;
522 }
523 return channelPtr->StartSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000524}
525
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200526int VoEBaseImpl::StopSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800527 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200528 if (!shared_->statistics().Initialized()) {
529 shared_->SetLastError(VE_NOT_INITED, kTraceError);
530 return -1;
531 }
532 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
533 voe::Channel* channelPtr = ch.channel();
534 if (channelPtr == nullptr) {
535 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
536 "StopSend() failed to locate channel");
537 return -1;
538 }
539 if (channelPtr->StopSend() != 0) {
540 LOG_F(LS_WARNING) << "StopSend() failed to stop sending for channel "
541 << channel;
542 }
543 return StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000544}
545
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200546int VoEBaseImpl::GetVersion(char version[1024]) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200547 if (version == nullptr) {
548 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200549 return -1;
550 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000551
solenberg2515af22015-12-02 06:19:36 -0800552 std::string versionString = VoiceEngine::GetVersionString();
553 RTC_DCHECK_GT(1024u, versionString.size() + 1);
554 char* end = std::copy(versionString.cbegin(), versionString.cend(), version);
555 end[0] = '\n';
556 end[1] = '\0';
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200557 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000558}
559
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200560int VoEBaseImpl::LastError() { return (shared_->statistics().LastError()); }
niklase@google.com470e71d2011-07-07 08:21:25 +0000561
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200562int32_t VoEBaseImpl::StartPlayout() {
solenberge313e022015-09-08 02:16:04 -0700563 if (!shared_->audio_device()->Playing()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200564 if (shared_->audio_device()->InitPlayout() != 0) {
565 LOG_F(LS_ERROR) << "Failed to initialize playout";
566 return -1;
567 }
568 if (shared_->audio_device()->StartPlayout() != 0) {
569 LOG_F(LS_ERROR) << "Failed to start playout";
570 return -1;
571 }
572 }
573 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000574}
575
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000576int32_t VoEBaseImpl::StopPlayout() {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000577 // Stop audio-device playing if no channel is playing out
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200578 if (shared_->NumOfPlayingChannels() == 0) {
579 if (shared_->audio_device()->StopPlayout() != 0) {
580 shared_->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000581 "StopPlayout() failed to stop playout");
582 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000583 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000584 }
585 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000586}
587
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200588int32_t VoEBaseImpl::StartSend() {
solenbergd53a3f92016-04-14 13:56:37 -0700589 if (!shared_->audio_device()->RecordingIsInitialized() &&
590 !shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200591 if (shared_->audio_device()->InitRecording() != 0) {
592 LOG_F(LS_ERROR) << "Failed to initialize recording";
593 return -1;
594 }
solenbergd53a3f92016-04-14 13:56:37 -0700595 }
596 if (!shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200597 if (shared_->audio_device()->StartRecording() != 0) {
598 LOG_F(LS_ERROR) << "Failed to start recording";
599 return -1;
600 }
601 }
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::StopSend() {
606 if (shared_->NumOfSendingChannels() == 0 &&
607 !shared_->transmit_mixer()->IsRecordingMic()) {
608 // Stop audio-device recording if no channel is recording
609 if (shared_->audio_device()->StopRecording() != 0) {
610 shared_->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
611 "StopSend() failed to stop recording");
612 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000613 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200614 shared_->transmit_mixer()->StopSend();
615 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000616
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200617 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000618}
619
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200620int32_t VoEBaseImpl::TerminateInternal() {
621 // Delete any remaining channel objects
622 shared_->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000623
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200624 if (shared_->process_thread()) {
625 if (shared_->audio_device()) {
626 shared_->process_thread()->DeRegisterModule(shared_->audio_device());
niklase@google.com470e71d2011-07-07 08:21:25 +0000627 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200628 shared_->process_thread()->Stop();
629 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000630
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200631 if (shared_->audio_device()) {
632 if (shared_->audio_device()->StopPlayout() != 0) {
633 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
634 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000635 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200636 if (shared_->audio_device()->StopRecording() != 0) {
637 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
638 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000639 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200640 if (shared_->audio_device()->RegisterEventObserver(nullptr) != 0) {
641 shared_->SetLastError(
642 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
643 "TerminateInternal() failed to de-register event observer "
644 "for the ADM");
645 }
646 if (shared_->audio_device()->RegisterAudioCallback(nullptr) != 0) {
647 shared_->SetLastError(
648 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
649 "TerminateInternal() failed to de-register audio callback "
650 "for the ADM");
651 }
652 if (shared_->audio_device()->Terminate() != 0) {
653 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
654 "TerminateInternal() failed to terminate the ADM");
655 }
656 shared_->set_audio_device(nullptr);
657 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000658
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200659 if (shared_->audio_processing()) {
660 shared_->set_audio_processing(nullptr);
661 }
662
663 return shared_->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000664}
665
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000666int VoEBaseImpl::ProcessRecordedDataWithAPM(
Peter Kasting69558702016-01-12 16:26:35 -0800667 const int voe_channels[], size_t number_of_voe_channels,
668 const void* audio_data, uint32_t sample_rate, size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700669 size_t number_of_frames, uint32_t audio_delay_milliseconds,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200670 int32_t clock_drift, uint32_t volume, bool key_pressed) {
671 assert(shared_->transmit_mixer() != nullptr);
672 assert(shared_->audio_device() != nullptr);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000673
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000674 uint32_t max_volume = 0;
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000675 uint16_t voe_mic_level = 0;
andrew@webrtc.org023cc5a2014-01-11 01:25:53 +0000676 // Check for zero to skip this calculation; the consumer may use this to
677 // indicate no volume is available.
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000678 if (volume != 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000679 // Scale from ADM to VoE level range
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200680 if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000681 if (max_volume) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000682 voe_mic_level = static_cast<uint16_t>(
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200683 (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) /
684 max_volume);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000685 }
686 }
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000687 // We learned that on certain systems (e.g Linux) the voe_mic_level
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000688 // can be greater than the maxVolumeLevel therefore
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000689 // we are going to cap the voe_mic_level to the maxVolumeLevel
690 // and change the maxVolume to volume if it turns out that
691 // the voe_mic_level is indeed greater than the maxVolumeLevel.
692 if (voe_mic_level > kMaxVolumeLevel) {
693 voe_mic_level = kMaxVolumeLevel;
694 max_volume = volume;
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000695 }
696 }
697
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000698 // Perform channel-independent operations
699 // (APM, mix with file, record to file, mute, etc.)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200700 shared_->transmit_mixer()->PrepareDemux(
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000701 audio_data, number_of_frames, number_of_channels, sample_rate,
702 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000703 voe_mic_level, key_pressed);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000704
705 // Copy the audio frame to each sending channel and perform
706 // channel-dependent operations (file mixing, mute, etc.), encode and
707 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
708 // do the operations on all the existing VoE channels; otherwise the
709 // operations will be done on specific channels.
710 if (number_of_voe_channels == 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200711 shared_->transmit_mixer()->DemuxAndMix();
712 shared_->transmit_mixer()->EncodeAndSend();
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000713 } else {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200714 shared_->transmit_mixer()->DemuxAndMix(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000715 number_of_voe_channels);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200716 shared_->transmit_mixer()->EncodeAndSend(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000717 number_of_voe_channels);
718 }
719
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000720 // Scale from VoE to ADM level range.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200721 uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel();
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000722 if (new_voe_mic_level != voe_mic_level) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000723 // Return the new volume if AGC has changed the volume.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200724 return static_cast<int>((new_voe_mic_level * max_volume +
725 static_cast<int>(kMaxVolumeLevel / 2)) /
726 kMaxVolumeLevel);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000727 }
728
729 // Return 0 to indicate no change on the volume.
730 return 0;
731}
732
Peter Kasting69558702016-01-12 16:26:35 -0800733void VoEBaseImpl::GetPlayoutData(int sample_rate, size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700734 size_t number_of_frames, bool feed_data_to_apm,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200735 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000736 int64_t* ntp_time_ms) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200737 assert(shared_->output_mixer() != nullptr);
xians@webrtc.org56925312014-04-14 10:50:37 +0000738
739 // TODO(andrew): if the device is running in mono, we should tell the mixer
740 // here so that it will only request mono from AudioCodingModule.
741 // Perform mixing of all active participants (channel-based mixing)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200742 shared_->output_mixer()->MixActiveChannels();
xians@webrtc.org56925312014-04-14 10:50:37 +0000743
744 // Additional operations on the combined signal
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200745 shared_->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
xians@webrtc.org56925312014-04-14 10:50:37 +0000746
747 // Retrieve the final output mix (resampled to match the ADM)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200748 shared_->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
749 &audioFrame_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000750
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200751 assert(number_of_frames == audioFrame_.samples_per_channel_);
752 assert(sample_rate == audioFrame_.sample_rate_hz_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000753
754 // Deliver audio (PCM) samples to the ADM
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200755 memcpy(audio_data, audioFrame_.data_,
xians@webrtc.org56925312014-04-14 10:50:37 +0000756 sizeof(int16_t) * number_of_frames * number_of_channels);
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000757
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200758 *elapsed_time_ms = audioFrame_.elapsed_time_ms_;
759 *ntp_time_ms = audioFrame_.ntp_time_ms_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000760}
761
Minyue2013aec2015-05-13 14:14:42 +0200762int VoEBaseImpl::AssociateSendChannel(int channel,
763 int accociate_send_channel) {
tommi31fc21f2016-01-21 10:37:37 -0800764 rtc::CritScope cs(shared_->crit_sec());
Minyue2013aec2015-05-13 14:14:42 +0200765
766 if (!shared_->statistics().Initialized()) {
767 shared_->SetLastError(VE_NOT_INITED, kTraceError);
768 return -1;
769 }
770
771 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
772 voe::Channel* channel_ptr = ch.channel();
773 if (channel_ptr == NULL) {
774 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
775 "AssociateSendChannel() failed to locate channel");
776 return -1;
777 }
778
779 ch = shared_->channel_manager().GetChannel(accociate_send_channel);
780 voe::Channel* accociate_send_channel_ptr = ch.channel();
781 if (accociate_send_channel_ptr == NULL) {
782 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
783 "AssociateSendChannel() failed to locate accociate_send_channel");
784 return -1;
785 }
786
787 channel_ptr->set_associate_send_channel(ch);
788 return 0;
789}
790
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000791} // namespace webrtc