blob: 8e93778f7ed572657264aa060095216a51e36198 [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"
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.org8fff1f02013-07-31 16:27:42 +0000109int VoEBaseImpl::OnDataAvailable(const int voe_channels[],
Peter Kasting69558702016-01-12 16:26:35 -0800110 size_t number_of_voe_channels,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200111 const int16_t* audio_data, 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 int audio_delay_milliseconds, int volume,
115 bool key_pressed, bool need_audio_processing) {
116 if (number_of_voe_channels == 0) return 0;
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000117
118 if (need_audio_processing) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000119 return ProcessRecordedDataWithAPM(
120 voe_channels, number_of_voe_channels, audio_data, sample_rate,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200121 number_of_channels, number_of_frames, audio_delay_milliseconds, 0,
122 volume, key_pressed);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000123 }
124
125 // No need to go through the APM, demultiplex the data to each VoE channel,
126 // encode and send to the network.
Peter Kasting69558702016-01-12 16:26:35 -0800127 for (size_t i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000128 // TODO(ajm): In the case where multiple channels are using the same codec
129 // rate, this path needlessly does extra conversions. We should convert once
130 // and share between channels.
xians@webrtc.org56925312014-04-14 10:50:37 +0000131 PushCaptureData(voe_channels[i], audio_data, 16, sample_rate,
132 number_of_channels, number_of_frames);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000133 }
134
135 // Return 0 to indicate no need to change the volume.
136 return 0;
137}
138
xians@webrtc.orgc1e28032014-02-02 15:30:20 +0000139void VoEBaseImpl::OnData(int voe_channel, const void* audio_data,
140 int bits_per_sample, int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800141 size_t number_of_channels, size_t number_of_frames) {
xians@webrtc.org56925312014-04-14 10:50:37 +0000142 PushCaptureData(voe_channel, audio_data, bits_per_sample, sample_rate,
143 number_of_channels, number_of_frames);
144}
145
146void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
147 int bits_per_sample, int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800148 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700149 size_t number_of_frames) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200150 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel);
xians@webrtc.org07e51962014-01-29 13:54:02 +0000151 voe::Channel* channel_ptr = ch.channel();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200152 if (!channel_ptr) return;
xians@webrtc.org07e51962014-01-29 13:54:02 +0000153
henrika@webrtc.org66803482014-04-17 10:45:01 +0000154 if (channel_ptr->Sending()) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000155 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
156 sample_rate, number_of_frames, number_of_channels);
157 channel_ptr->PrepareEncodeAndSend(sample_rate);
158 channel_ptr->EncodeAndSend();
159 }
160}
161
Peter Kastingdce40cf2015-08-24 14:52:23 -0700162void VoEBaseImpl::PullRenderData(int bits_per_sample,
163 int sample_rate,
Peter Kasting69558702016-01-12 16:26:35 -0800164 size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700165 size_t number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200166 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000167 int64_t* ntp_time_ms) {
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200168 assert(bits_per_sample == 16);
Peter Kastingdce40cf2015-08-24 14:52:23 -0700169 assert(number_of_frames == static_cast<size_t>(sample_rate / 100));
xians@webrtc.org56925312014-04-14 10:50:37 +0000170
171 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000172 audio_data, elapsed_time_ms, ntp_time_ms);
xians@webrtc.org56925312014-04-14 10:50:37 +0000173}
174
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200175int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer) {
tommi31fc21f2016-01-21 10:37:37 -0800176 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200177 if (voiceEngineObserverPtr_) {
178 shared_->SetLastError(
179 VE_INVALID_OPERATION, kTraceError,
180 "RegisterVoiceEngineObserver() observer already enabled");
181 return -1;
182 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000183
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200184 // Register the observer in all active channels
185 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
186 it.IsValid(); it.Increment()) {
187 it.GetChannel()->RegisterVoiceEngineObserver(observer);
188 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000189
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200190 shared_->transmit_mixer()->RegisterVoiceEngineObserver(observer);
191 voiceEngineObserverPtr_ = &observer;
192 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000193}
194
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200195int VoEBaseImpl::DeRegisterVoiceEngineObserver() {
tommi31fc21f2016-01-21 10:37:37 -0800196 rtc::CritScope cs(&callbackCritSect_);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200197 if (!voiceEngineObserverPtr_) {
198 shared_->SetLastError(
199 VE_INVALID_OPERATION, kTraceError,
200 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000201 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200202 }
203 voiceEngineObserverPtr_ = nullptr;
204
205 // Deregister the observer in all active channels
206 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
207 it.IsValid(); it.Increment()) {
208 it.GetChannel()->DeRegisterVoiceEngineObserver();
209 }
210
211 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000212}
213
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000214int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200215 AudioProcessing* audioproc) {
tommi31fc21f2016-01-21 10:37:37 -0800216 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200217 WebRtcSpl_Init();
218 if (shared_->statistics().Initialized()) {
219 return 0;
220 }
221 if (shared_->process_thread()) {
222 shared_->process_thread()->Start();
223 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000224
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200225 // Create an internal ADM if the user has not added an external
226 // ADM implementation as input to Init().
227 if (external_adm == nullptr) {
Tommi931e6582015-05-20 09:44:38 +0200228#if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
229 return -1;
230#else
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200231 // Create the internal ADM implementation.
Peter Boström4adbbcf2016-05-03 15:51:26 -0400232 shared_->set_audio_device(AudioDeviceModule::Create(
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200233 VoEId(shared_->instance_id(), -1), shared_->audio_device_layer()));
kma@webrtc.org0221b782012-09-08 00:09:26 +0000234
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200235 if (shared_->audio_device() == nullptr) {
236 shared_->SetLastError(VE_NO_MEMORY, kTraceCritical,
237 "Init() failed to create the ADM");
238 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000239 }
Tommi931e6582015-05-20 09:44:38 +0200240#endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200241 } else {
242 // Use the already existing external ADM implementation.
243 shared_->set_audio_device(external_adm);
244 LOG_F(LS_INFO)
245 << "An external ADM implementation will be used in VoiceEngine";
246 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000247
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200248 // Register the ADM to the process thread, which will drive the error
249 // callback mechanism
250 if (shared_->process_thread()) {
251 shared_->process_thread()->RegisterModule(shared_->audio_device());
252 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000253
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200254 bool available = false;
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000255
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200256 // --------------------
257 // Reinitialize the ADM
henrika@google.com73d65512011-09-07 15:11:18 +0000258
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200259 // Register the AudioObserver implementation
260 if (shared_->audio_device()->RegisterEventObserver(this) != 0) {
261 shared_->SetLastError(
262 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
263 "Init() failed to register event observer for the ADM");
264 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000265
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200266 // Register the AudioTransport implementation
267 if (shared_->audio_device()->RegisterAudioCallback(this) != 0) {
268 shared_->SetLastError(
269 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
270 "Init() failed to register audio callback for the ADM");
271 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000272
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200273 // ADM initialization
274 if (shared_->audio_device()->Init() != 0) {
275 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
276 "Init() failed to initialize the ADM");
277 return -1;
278 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000279
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200280 // Initialize the default speaker
281 if (shared_->audio_device()->SetPlayoutDevice(
282 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
283 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
284 "Init() failed to set the default output device");
285 }
286 if (shared_->audio_device()->InitSpeaker() != 0) {
287 shared_->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
288 "Init() failed to initialize the speaker");
289 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000290
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200291 // Initialize the default microphone
292 if (shared_->audio_device()->SetRecordingDevice(
293 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
294 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
295 "Init() failed to set the default input device");
296 }
297 if (shared_->audio_device()->InitMicrophone() != 0) {
298 shared_->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
299 "Init() failed to initialize the microphone");
300 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000301
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200302 // Set number of channels
303 if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
304 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
305 "Init() failed to query stereo playout mode");
306 }
307 if (shared_->audio_device()->SetStereoPlayout(available) != 0) {
308 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
309 "Init() failed to set mono/stereo playout mode");
310 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000311
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200312 // TODO(andrew): These functions don't tell us whether stereo recording
313 // is truly available. We simply set the AudioProcessing input to stereo
314 // here, because we have to wait until receiving the first frame to
315 // determine the actual number of channels anyway.
316 //
317 // These functions may be changed; tracked here:
318 // http://code.google.com/p/webrtc/issues/detail?id=204
319 shared_->audio_device()->StereoRecordingIsAvailable(&available);
320 if (shared_->audio_device()->SetStereoRecording(available) != 0) {
321 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
322 "Init() failed to set mono/stereo recording mode");
323 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000324
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200325 if (!audioproc) {
326 audioproc = AudioProcessing::Create();
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000327 if (!audioproc) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200328 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
329 shared_->SetLastError(VE_NO_MEMORY);
330 return -1;
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000331 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200332 }
333 shared_->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000334
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200335 // Set the error state for any failures in this block.
336 shared_->SetLastError(VE_APM_ERROR);
337 // Configure AudioProcessing components.
338 if (audioproc->high_pass_filter()->Enable(true) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200339 LOG_F(LS_ERROR) << "Failed to enable high pass filter.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200340 return -1;
341 }
342 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200343 LOG_F(LS_ERROR) << "Failed to disable drift compensation.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200344 return -1;
345 }
346 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200347 LOG_F(LS_ERROR) << "Failed to set noise suppression level: "
348 << kDefaultNsMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200349 return -1;
350 }
351 GainControl* agc = audioproc->gain_control();
352 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200353 LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: "
354 << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200355 return -1;
356 }
357 if (agc->set_mode(kDefaultAgcMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200358 LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200359 return -1;
360 }
361 if (agc->Enable(kDefaultAgcState) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200362 LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200363 return -1;
364 }
365 shared_->SetLastError(0); // Clear error state.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000366
niklase@google.com470e71d2011-07-07 08:21:25 +0000367#ifdef WEBRTC_VOICE_ENGINE_AGC
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200368 bool agc_enabled =
369 agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled();
370 if (shared_->audio_device()->SetAGC(agc_enabled) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200371 LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200372 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
373 // TODO(ajm): No error return here due to
374 // https://code.google.com/p/webrtc/issues/detail?id=1464
375 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000376#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000377
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200378 return shared_->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000379}
380
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200381int VoEBaseImpl::Terminate() {
tommi31fc21f2016-01-21 10:37:37 -0800382 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200383 return TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000384}
385
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000386int VoEBaseImpl::CreateChannel() {
tommi31fc21f2016-01-21 10:37:37 -0800387 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200388 if (!shared_->statistics().Initialized()) {
389 shared_->SetLastError(VE_NOT_INITED, kTraceError);
390 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000391 }
392
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200393 voe::ChannelOwner channel_owner = shared_->channel_manager().CreateChannel();
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000394 return InitializeChannel(&channel_owner);
395}
396
397int VoEBaseImpl::CreateChannel(const Config& config) {
tommi31fc21f2016-01-21 10:37:37 -0800398 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200399 if (!shared_->statistics().Initialized()) {
400 shared_->SetLastError(VE_NOT_INITED, kTraceError);
401 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000402 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200403 voe::ChannelOwner channel_owner =
404 shared_->channel_manager().CreateChannel(config);
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000405 return InitializeChannel(&channel_owner);
406}
407
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200408int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) {
409 if (channel_owner->channel()->SetEngineInformation(
410 shared_->statistics(), *shared_->output_mixer(),
411 *shared_->transmit_mixer(), *shared_->process_thread(),
412 *shared_->audio_device(), voiceEngineObserverPtr_,
413 &callbackCritSect_) != 0) {
414 shared_->SetLastError(
415 VE_CHANNEL_NOT_CREATED, kTraceError,
416 "CreateChannel() failed to associate engine and channel."
417 " Destroying channel.");
418 shared_->channel_manager().DestroyChannel(
419 channel_owner->channel()->ChannelId());
420 return -1;
421 } else if (channel_owner->channel()->Init() != 0) {
422 shared_->SetLastError(
423 VE_CHANNEL_NOT_CREATED, kTraceError,
424 "CreateChannel() failed to initialize channel. Destroying"
425 " channel.");
426 shared_->channel_manager().DestroyChannel(
427 channel_owner->channel()->ChannelId());
428 return -1;
429 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200430 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000431}
432
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200433int VoEBaseImpl::DeleteChannel(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800434 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200435 if (!shared_->statistics().Initialized()) {
436 shared_->SetLastError(VE_NOT_INITED, kTraceError);
437 return -1;
438 }
439
440 {
441 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
442 voe::Channel* channelPtr = ch.channel();
443 if (channelPtr == nullptr) {
444 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
445 "DeleteChannel() failed to locate channel");
446 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000447 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200448 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000449
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200450 shared_->channel_manager().DestroyChannel(channel);
451 if (StopSend() != 0) {
452 return -1;
453 }
454 if (StopPlayout() != 0) {
455 return -1;
456 }
457 return 0;
458}
niklase@google.com470e71d2011-07-07 08:21:25 +0000459
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200460int VoEBaseImpl::StartReceive(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800461 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200462 if (!shared_->statistics().Initialized()) {
463 shared_->SetLastError(VE_NOT_INITED, kTraceError);
464 return -1;
465 }
466 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
467 voe::Channel* channelPtr = ch.channel();
468 if (channelPtr == nullptr) {
469 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
470 "StartReceive() failed to locate channel");
471 return -1;
472 }
473 return channelPtr->StartReceiving();
474}
niklase@google.com470e71d2011-07-07 08:21:25 +0000475
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200476int VoEBaseImpl::StopReceive(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800477 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200478 if (!shared_->statistics().Initialized()) {
479 shared_->SetLastError(VE_NOT_INITED, kTraceError);
480 return -1;
481 }
482 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
483 voe::Channel* channelPtr = ch.channel();
484 if (channelPtr == nullptr) {
485 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
486 "SetLocalReceiver() failed to locate channel");
487 return -1;
488 }
489 return channelPtr->StopReceiving();
490}
niklase@google.com470e71d2011-07-07 08:21:25 +0000491
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200492int VoEBaseImpl::StartPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800493 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200494 if (!shared_->statistics().Initialized()) {
495 shared_->SetLastError(VE_NOT_INITED, kTraceError);
496 return -1;
497 }
498 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
499 voe::Channel* channelPtr = ch.channel();
500 if (channelPtr == nullptr) {
501 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
502 "StartPlayout() failed to locate channel");
503 return -1;
504 }
505 if (channelPtr->Playing()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000506 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200507 }
508 if (StartPlayout() != 0) {
509 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
510 "StartPlayout() failed to start playout");
511 return -1;
512 }
513 return channelPtr->StartPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000514}
515
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200516int VoEBaseImpl::StopPlayout(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800517 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200518 if (!shared_->statistics().Initialized()) {
519 shared_->SetLastError(VE_NOT_INITED, kTraceError);
520 return -1;
521 }
522 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
523 voe::Channel* channelPtr = ch.channel();
524 if (channelPtr == nullptr) {
525 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
526 "StopPlayout() failed to locate channel");
527 return -1;
528 }
529 if (channelPtr->StopPlayout() != 0) {
530 LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
531 << channel;
532 }
533 return StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000534}
535
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200536int VoEBaseImpl::StartSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800537 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200538 if (!shared_->statistics().Initialized()) {
539 shared_->SetLastError(VE_NOT_INITED, kTraceError);
540 return -1;
541 }
542 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
543 voe::Channel* channelPtr = ch.channel();
544 if (channelPtr == nullptr) {
545 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
546 "StartSend() failed to locate channel");
547 return -1;
548 }
549 if (channelPtr->Sending()) {
550 return 0;
551 }
552 if (StartSend() != 0) {
553 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
554 "StartSend() failed to start recording");
555 return -1;
556 }
557 return channelPtr->StartSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000558}
559
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200560int VoEBaseImpl::StopSend(int channel) {
tommi31fc21f2016-01-21 10:37:37 -0800561 rtc::CritScope cs(shared_->crit_sec());
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200562 if (!shared_->statistics().Initialized()) {
563 shared_->SetLastError(VE_NOT_INITED, kTraceError);
564 return -1;
565 }
566 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
567 voe::Channel* channelPtr = ch.channel();
568 if (channelPtr == nullptr) {
569 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
570 "StopSend() failed to locate channel");
571 return -1;
572 }
573 if (channelPtr->StopSend() != 0) {
574 LOG_F(LS_WARNING) << "StopSend() failed to stop sending for channel "
575 << channel;
576 }
577 return StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000578}
579
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200580int VoEBaseImpl::GetVersion(char version[1024]) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200581 if (version == nullptr) {
582 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200583 return -1;
584 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000585
solenberg2515af22015-12-02 06:19:36 -0800586 std::string versionString = VoiceEngine::GetVersionString();
587 RTC_DCHECK_GT(1024u, versionString.size() + 1);
588 char* end = std::copy(versionString.cbegin(), versionString.cend(), version);
589 end[0] = '\n';
590 end[1] = '\0';
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200591 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000592}
593
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200594int VoEBaseImpl::LastError() { return (shared_->statistics().LastError()); }
niklase@google.com470e71d2011-07-07 08:21:25 +0000595
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200596int32_t VoEBaseImpl::StartPlayout() {
solenberge313e022015-09-08 02:16:04 -0700597 if (!shared_->audio_device()->Playing()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200598 if (shared_->audio_device()->InitPlayout() != 0) {
599 LOG_F(LS_ERROR) << "Failed to initialize playout";
600 return -1;
601 }
602 if (shared_->audio_device()->StartPlayout() != 0) {
603 LOG_F(LS_ERROR) << "Failed to start playout";
604 return -1;
605 }
606 }
607 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000608}
609
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000610int32_t VoEBaseImpl::StopPlayout() {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000611 // Stop audio-device playing if no channel is playing out
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200612 if (shared_->NumOfPlayingChannels() == 0) {
613 if (shared_->audio_device()->StopPlayout() != 0) {
614 shared_->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000615 "StopPlayout() failed to stop playout");
616 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000617 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000618 }
619 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000620}
621
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200622int32_t VoEBaseImpl::StartSend() {
solenbergd53a3f92016-04-14 13:56:37 -0700623 if (!shared_->audio_device()->RecordingIsInitialized() &&
624 !shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200625 if (shared_->audio_device()->InitRecording() != 0) {
626 LOG_F(LS_ERROR) << "Failed to initialize recording";
627 return -1;
628 }
solenbergd53a3f92016-04-14 13:56:37 -0700629 }
630 if (!shared_->audio_device()->Recording()) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200631 if (shared_->audio_device()->StartRecording() != 0) {
632 LOG_F(LS_ERROR) << "Failed to start recording";
633 return -1;
634 }
635 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200636 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000637}
638
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200639int32_t VoEBaseImpl::StopSend() {
640 if (shared_->NumOfSendingChannels() == 0 &&
641 !shared_->transmit_mixer()->IsRecordingMic()) {
642 // Stop audio-device recording if no channel is recording
643 if (shared_->audio_device()->StopRecording() != 0) {
644 shared_->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
645 "StopSend() failed to stop recording");
646 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000647 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200648 shared_->transmit_mixer()->StopSend();
649 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000650
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200651 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000652}
653
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200654int32_t VoEBaseImpl::TerminateInternal() {
655 // Delete any remaining channel objects
656 shared_->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000657
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200658 if (shared_->process_thread()) {
659 if (shared_->audio_device()) {
660 shared_->process_thread()->DeRegisterModule(shared_->audio_device());
niklase@google.com470e71d2011-07-07 08:21:25 +0000661 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200662 shared_->process_thread()->Stop();
663 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000664
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200665 if (shared_->audio_device()) {
666 if (shared_->audio_device()->StopPlayout() != 0) {
667 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
668 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000669 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200670 if (shared_->audio_device()->StopRecording() != 0) {
671 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
672 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000673 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200674 if (shared_->audio_device()->RegisterEventObserver(nullptr) != 0) {
675 shared_->SetLastError(
676 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
677 "TerminateInternal() failed to de-register event observer "
678 "for the ADM");
679 }
680 if (shared_->audio_device()->RegisterAudioCallback(nullptr) != 0) {
681 shared_->SetLastError(
682 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
683 "TerminateInternal() failed to de-register audio callback "
684 "for the ADM");
685 }
686 if (shared_->audio_device()->Terminate() != 0) {
687 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
688 "TerminateInternal() failed to terminate the ADM");
689 }
690 shared_->set_audio_device(nullptr);
691 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000692
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200693 if (shared_->audio_processing()) {
694 shared_->set_audio_processing(nullptr);
695 }
696
697 return shared_->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000698}
699
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000700int VoEBaseImpl::ProcessRecordedDataWithAPM(
Peter Kasting69558702016-01-12 16:26:35 -0800701 const int voe_channels[], size_t number_of_voe_channels,
702 const void* audio_data, uint32_t sample_rate, size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700703 size_t number_of_frames, uint32_t audio_delay_milliseconds,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200704 int32_t clock_drift, uint32_t volume, bool key_pressed) {
705 assert(shared_->transmit_mixer() != nullptr);
706 assert(shared_->audio_device() != nullptr);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000707
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000708 uint32_t max_volume = 0;
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000709 uint16_t voe_mic_level = 0;
andrew@webrtc.org023cc5a2014-01-11 01:25:53 +0000710 // Check for zero to skip this calculation; the consumer may use this to
711 // indicate no volume is available.
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000712 if (volume != 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000713 // Scale from ADM to VoE level range
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200714 if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000715 if (max_volume) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000716 voe_mic_level = static_cast<uint16_t>(
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200717 (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) /
718 max_volume);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000719 }
720 }
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000721 // We learned that on certain systems (e.g Linux) the voe_mic_level
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000722 // can be greater than the maxVolumeLevel therefore
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000723 // we are going to cap the voe_mic_level to the maxVolumeLevel
724 // and change the maxVolume to volume if it turns out that
725 // the voe_mic_level is indeed greater than the maxVolumeLevel.
726 if (voe_mic_level > kMaxVolumeLevel) {
727 voe_mic_level = kMaxVolumeLevel;
728 max_volume = volume;
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000729 }
730 }
731
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000732 // Perform channel-independent operations
733 // (APM, mix with file, record to file, mute, etc.)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200734 shared_->transmit_mixer()->PrepareDemux(
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000735 audio_data, number_of_frames, number_of_channels, sample_rate,
736 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000737 voe_mic_level, key_pressed);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000738
739 // Copy the audio frame to each sending channel and perform
740 // channel-dependent operations (file mixing, mute, etc.), encode and
741 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
742 // do the operations on all the existing VoE channels; otherwise the
743 // operations will be done on specific channels.
744 if (number_of_voe_channels == 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200745 shared_->transmit_mixer()->DemuxAndMix();
746 shared_->transmit_mixer()->EncodeAndSend();
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000747 } else {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200748 shared_->transmit_mixer()->DemuxAndMix(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000749 number_of_voe_channels);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200750 shared_->transmit_mixer()->EncodeAndSend(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000751 number_of_voe_channels);
752 }
753
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000754 // Scale from VoE to ADM level range.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200755 uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel();
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000756 if (new_voe_mic_level != voe_mic_level) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000757 // Return the new volume if AGC has changed the volume.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200758 return static_cast<int>((new_voe_mic_level * max_volume +
759 static_cast<int>(kMaxVolumeLevel / 2)) /
760 kMaxVolumeLevel);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000761 }
762
763 // Return 0 to indicate no change on the volume.
764 return 0;
765}
766
Peter Kasting69558702016-01-12 16:26:35 -0800767void VoEBaseImpl::GetPlayoutData(int sample_rate, size_t number_of_channels,
Peter Kastingdce40cf2015-08-24 14:52:23 -0700768 size_t number_of_frames, bool feed_data_to_apm,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200769 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000770 int64_t* ntp_time_ms) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200771 assert(shared_->output_mixer() != nullptr);
xians@webrtc.org56925312014-04-14 10:50:37 +0000772
773 // TODO(andrew): if the device is running in mono, we should tell the mixer
774 // here so that it will only request mono from AudioCodingModule.
775 // Perform mixing of all active participants (channel-based mixing)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200776 shared_->output_mixer()->MixActiveChannels();
xians@webrtc.org56925312014-04-14 10:50:37 +0000777
778 // Additional operations on the combined signal
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200779 shared_->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
xians@webrtc.org56925312014-04-14 10:50:37 +0000780
781 // Retrieve the final output mix (resampled to match the ADM)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200782 shared_->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
783 &audioFrame_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000784
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200785 assert(number_of_frames == audioFrame_.samples_per_channel_);
786 assert(sample_rate == audioFrame_.sample_rate_hz_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000787
788 // Deliver audio (PCM) samples to the ADM
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200789 memcpy(audio_data, audioFrame_.data_,
xians@webrtc.org56925312014-04-14 10:50:37 +0000790 sizeof(int16_t) * number_of_frames * number_of_channels);
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000791
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200792 *elapsed_time_ms = audioFrame_.elapsed_time_ms_;
793 *ntp_time_ms = audioFrame_.ntp_time_ms_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000794}
795
Minyue2013aec2015-05-13 14:14:42 +0200796int VoEBaseImpl::AssociateSendChannel(int channel,
797 int accociate_send_channel) {
tommi31fc21f2016-01-21 10:37:37 -0800798 rtc::CritScope cs(shared_->crit_sec());
Minyue2013aec2015-05-13 14:14:42 +0200799
800 if (!shared_->statistics().Initialized()) {
801 shared_->SetLastError(VE_NOT_INITED, kTraceError);
802 return -1;
803 }
804
805 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
806 voe::Channel* channel_ptr = ch.channel();
807 if (channel_ptr == NULL) {
808 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
809 "AssociateSendChannel() failed to locate channel");
810 return -1;
811 }
812
813 ch = shared_->channel_manager().GetChannel(accociate_send_channel);
814 voe::Channel* accociate_send_channel_ptr = ch.channel();
815 if (accociate_send_channel_ptr == NULL) {
816 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
817 "AssociateSendChannel() failed to locate accociate_send_channel");
818 return -1;
819 }
820
821 channel_ptr->set_associate_send_channel(ch);
822 return 0;
823}
824
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000825} // namespace webrtc