blob: e245fca1107ff6afc3e4f761ad3ef4b41d0b9ae4 [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
turaj@webrtc.org03f33702013-11-13 00:02:48 +000013#include "webrtc/common.h"
pbos@webrtc.org956aa7e2013-05-21 13:52:32 +000014#include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
15#include "webrtc/modules/audio_coding/main/interface/audio_coding_module.h"
16#include "webrtc/modules/audio_device/audio_device_impl.h"
17#include "webrtc/modules/audio_processing/include/audio_processing.h"
18#include "webrtc/system_wrappers/interface/critical_section_wrapper.h"
19#include "webrtc/system_wrappers/interface/file_wrapper.h"
Jelena Marusic9e5e4212015-04-13 13:41:56 +020020#include "webrtc/system_wrappers/interface/logging.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),
41 callbackCritSect_(*CriticalSectionWrapper::CreateCriticalSection()),
42 shared_(shared) {}
43
44VoEBaseImpl::~VoEBaseImpl() {
45 TerminateInternal();
46 delete &callbackCritSect_;
niklase@google.com470e71d2011-07-07 08:21:25 +000047}
48
Jelena Marusic2dd6a272015-04-14 09:47:00 +020049void VoEBaseImpl::OnErrorIsReported(ErrorCode error) {
50 CriticalSectionScoped cs(&callbackCritSect_);
51 int errCode = 0;
52 if (error == AudioDeviceObserver::kRecordingError) {
53 errCode = VE_RUNTIME_REC_ERROR;
54 LOG_F(LS_ERROR) << "VE_RUNTIME_REC_ERROR";
55 } else if (error == AudioDeviceObserver::kPlayoutError) {
56 errCode = VE_RUNTIME_PLAY_ERROR;
57 LOG_F(LS_ERROR) << "VE_RUNTIME_PLAY_ERROR";
58 }
59 if (voiceEngineObserverPtr_) {
60 // Deliver callback (-1 <=> no channel dependency)
61 voiceEngineObserverPtr_->CallbackOnError(-1, errCode);
62 }
niklase@google.com470e71d2011-07-07 08:21:25 +000063}
64
Jelena Marusic2dd6a272015-04-14 09:47:00 +020065void VoEBaseImpl::OnWarningIsReported(WarningCode warning) {
66 CriticalSectionScoped cs(&callbackCritSect_);
67 int warningCode = 0;
68 if (warning == AudioDeviceObserver::kRecordingWarning) {
69 warningCode = VE_RUNTIME_REC_WARNING;
70 LOG_F(LS_WARNING) << "VE_RUNTIME_REC_WARNING";
71 } else if (warning == AudioDeviceObserver::kPlayoutWarning) {
72 warningCode = VE_RUNTIME_PLAY_WARNING;
73 LOG_F(LS_WARNING) << "VE_RUNTIME_PLAY_WARNING";
74 }
75 if (voiceEngineObserverPtr_) {
76 // Deliver callback (-1 <=> no channel dependency)
77 voiceEngineObserverPtr_->CallbackOnError(-1, warningCode);
78 }
niklase@google.com470e71d2011-07-07 08:21:25 +000079}
80
pbos@webrtc.org6141e132013-04-09 10:09:10 +000081int32_t VoEBaseImpl::RecordedDataIsAvailable(
Jelena Marusic2dd6a272015-04-14 09:47:00 +020082 const void* audioSamples, uint32_t nSamples, uint8_t nBytesPerSample,
83 uint8_t nChannels, uint32_t samplesPerSec, uint32_t totalDelayMS,
84 int32_t clockDrift, uint32_t micLevel, bool keyPressed,
85 uint32_t& newMicLevel) {
86 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
87 nullptr, 0, audioSamples, samplesPerSec, nChannels, nSamples,
88 totalDelayMS, clockDrift, micLevel, keyPressed));
89 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +000090}
91
Jelena Marusic2dd6a272015-04-14 09:47:00 +020092int32_t VoEBaseImpl::NeedMorePlayData(uint32_t nSamples,
93 uint8_t nBytesPerSample,
94 uint8_t nChannels, uint32_t samplesPerSec,
95 void* audioSamples, uint32_t& nSamplesOut,
96 int64_t* elapsed_time_ms,
97 int64_t* ntp_time_ms) {
98 GetPlayoutData(static_cast<int>(samplesPerSec), static_cast<int>(nChannels),
wu@webrtc.orgcb711f72014-05-19 17:39:11 +000099 static_cast<int>(nSamples), true, audioSamples,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000100 elapsed_time_ms, ntp_time_ms);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200101 nSamplesOut = audioFrame_.samples_per_channel_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000102 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000103}
104
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000105int VoEBaseImpl::OnDataAvailable(const int voe_channels[],
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000106 int number_of_voe_channels,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200107 const int16_t* audio_data, int sample_rate,
108 int number_of_channels, int number_of_frames,
109 int audio_delay_milliseconds, int volume,
110 bool key_pressed, bool need_audio_processing) {
111 if (number_of_voe_channels == 0) return 0;
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000112
113 if (need_audio_processing) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000114 return ProcessRecordedDataWithAPM(
115 voe_channels, number_of_voe_channels, audio_data, sample_rate,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200116 number_of_channels, number_of_frames, audio_delay_milliseconds, 0,
117 volume, key_pressed);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000118 }
119
120 // No need to go through the APM, demultiplex the data to each VoE channel,
121 // encode and send to the network.
122 for (int i = 0; i < number_of_voe_channels; ++i) {
andrew@webrtc.org40ee3d02014-04-03 21:56:01 +0000123 // TODO(ajm): In the case where multiple channels are using the same codec
124 // rate, this path needlessly does extra conversions. We should convert once
125 // and share between channels.
xians@webrtc.org56925312014-04-14 10:50:37 +0000126 PushCaptureData(voe_channels[i], audio_data, 16, sample_rate,
127 number_of_channels, number_of_frames);
xians@webrtc.org2f84afa2013-07-31 16:23:37 +0000128 }
129
130 // Return 0 to indicate no need to change the volume.
131 return 0;
132}
133
xians@webrtc.orgc1e28032014-02-02 15:30:20 +0000134void VoEBaseImpl::OnData(int voe_channel, const void* audio_data,
135 int bits_per_sample, int sample_rate,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200136 int number_of_channels, int number_of_frames) {
xians@webrtc.org56925312014-04-14 10:50:37 +0000137 PushCaptureData(voe_channel, audio_data, bits_per_sample, sample_rate,
138 number_of_channels, number_of_frames);
139}
140
141void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
142 int bits_per_sample, int sample_rate,
143 int number_of_channels,
144 int number_of_frames) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200145 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel);
xians@webrtc.org07e51962014-01-29 13:54:02 +0000146 voe::Channel* channel_ptr = ch.channel();
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200147 if (!channel_ptr) return;
xians@webrtc.org07e51962014-01-29 13:54:02 +0000148
henrika@webrtc.org66803482014-04-17 10:45:01 +0000149 if (channel_ptr->Sending()) {
xians@webrtc.org07e51962014-01-29 13:54:02 +0000150 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
151 sample_rate, number_of_frames, number_of_channels);
152 channel_ptr->PrepareEncodeAndSend(sample_rate);
153 channel_ptr->EncodeAndSend();
154 }
155}
156
xians@webrtc.org56925312014-04-14 10:50:37 +0000157void VoEBaseImpl::PullRenderData(int bits_per_sample, int sample_rate,
158 int number_of_channels, int number_of_frames,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200159 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000160 int64_t* ntp_time_ms) {
Jelena Marusic6fc2d2f2015-04-13 14:07:04 +0200161 assert(bits_per_sample == 16);
162 assert(number_of_frames == static_cast<int>(sample_rate / 100));
xians@webrtc.org56925312014-04-14 10:50:37 +0000163
164 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
wu@webrtc.org94454b72014-06-05 20:34:08 +0000165 audio_data, elapsed_time_ms, ntp_time_ms);
xians@webrtc.org56925312014-04-14 10:50:37 +0000166}
167
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200168int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer) {
169 CriticalSectionScoped cs(&callbackCritSect_);
170 if (voiceEngineObserverPtr_) {
171 shared_->SetLastError(
172 VE_INVALID_OPERATION, kTraceError,
173 "RegisterVoiceEngineObserver() observer already enabled");
174 return -1;
175 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000176
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200177 // Register the observer in all active channels
178 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
179 it.IsValid(); it.Increment()) {
180 it.GetChannel()->RegisterVoiceEngineObserver(observer);
181 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000182
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200183 shared_->transmit_mixer()->RegisterVoiceEngineObserver(observer);
184 voiceEngineObserverPtr_ = &observer;
185 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000186}
187
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200188int VoEBaseImpl::DeRegisterVoiceEngineObserver() {
189 CriticalSectionScoped cs(&callbackCritSect_);
190 if (!voiceEngineObserverPtr_) {
191 shared_->SetLastError(
192 VE_INVALID_OPERATION, kTraceError,
193 "DeRegisterVoiceEngineObserver() observer already disabled");
niklase@google.com470e71d2011-07-07 08:21:25 +0000194 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200195 }
196 voiceEngineObserverPtr_ = nullptr;
197
198 // Deregister the observer in all active channels
199 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
200 it.IsValid(); it.Increment()) {
201 it.GetChannel()->DeRegisterVoiceEngineObserver();
202 }
203
204 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000205}
206
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000207int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200208 AudioProcessing* audioproc) {
209 CriticalSectionScoped cs(shared_->crit_sec());
210 WebRtcSpl_Init();
211 if (shared_->statistics().Initialized()) {
212 return 0;
213 }
214 if (shared_->process_thread()) {
215 shared_->process_thread()->Start();
216 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000217
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200218 // Create an internal ADM if the user has not added an external
219 // ADM implementation as input to Init().
220 if (external_adm == nullptr) {
Tommi931e6582015-05-20 09:44:38 +0200221#if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
222 return -1;
223#else
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200224 // Create the internal ADM implementation.
225 shared_->set_audio_device(AudioDeviceModuleImpl::Create(
226 VoEId(shared_->instance_id(), -1), shared_->audio_device_layer()));
kma@webrtc.org0221b782012-09-08 00:09:26 +0000227
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200228 if (shared_->audio_device() == nullptr) {
229 shared_->SetLastError(VE_NO_MEMORY, kTraceCritical,
230 "Init() failed to create the ADM");
231 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000232 }
Tommi931e6582015-05-20 09:44:38 +0200233#endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200234 } else {
235 // Use the already existing external ADM implementation.
236 shared_->set_audio_device(external_adm);
237 LOG_F(LS_INFO)
238 << "An external ADM implementation will be used in VoiceEngine";
239 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000240
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200241 // Register the ADM to the process thread, which will drive the error
242 // callback mechanism
243 if (shared_->process_thread()) {
244 shared_->process_thread()->RegisterModule(shared_->audio_device());
245 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000246
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200247 bool available = false;
andrew@webrtc.orgf4589162011-10-03 15:22:28 +0000248
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200249 // --------------------
250 // Reinitialize the ADM
henrika@google.com73d65512011-09-07 15:11:18 +0000251
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200252 // Register the AudioObserver implementation
253 if (shared_->audio_device()->RegisterEventObserver(this) != 0) {
254 shared_->SetLastError(
255 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
256 "Init() failed to register event observer for the ADM");
257 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000258
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200259 // Register the AudioTransport implementation
260 if (shared_->audio_device()->RegisterAudioCallback(this) != 0) {
261 shared_->SetLastError(
262 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
263 "Init() failed to register audio callback for the ADM");
264 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000265
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200266 // ADM initialization
267 if (shared_->audio_device()->Init() != 0) {
268 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
269 "Init() failed to initialize the ADM");
270 return -1;
271 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000272
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200273 // Initialize the default speaker
274 if (shared_->audio_device()->SetPlayoutDevice(
275 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
276 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
277 "Init() failed to set the default output device");
278 }
279 if (shared_->audio_device()->InitSpeaker() != 0) {
280 shared_->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
281 "Init() failed to initialize the speaker");
282 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000283
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200284 // Initialize the default microphone
285 if (shared_->audio_device()->SetRecordingDevice(
286 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
287 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
288 "Init() failed to set the default input device");
289 }
290 if (shared_->audio_device()->InitMicrophone() != 0) {
291 shared_->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
292 "Init() failed to initialize the microphone");
293 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000294
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200295 // Set number of channels
296 if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
297 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
298 "Init() failed to query stereo playout mode");
299 }
300 if (shared_->audio_device()->SetStereoPlayout(available) != 0) {
301 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
302 "Init() failed to set mono/stereo playout mode");
303 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000304
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200305 // TODO(andrew): These functions don't tell us whether stereo recording
306 // is truly available. We simply set the AudioProcessing input to stereo
307 // here, because we have to wait until receiving the first frame to
308 // determine the actual number of channels anyway.
309 //
310 // These functions may be changed; tracked here:
311 // http://code.google.com/p/webrtc/issues/detail?id=204
312 shared_->audio_device()->StereoRecordingIsAvailable(&available);
313 if (shared_->audio_device()->SetStereoRecording(available) != 0) {
314 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
315 "Init() failed to set mono/stereo recording mode");
316 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000317
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200318 if (!audioproc) {
319 audioproc = AudioProcessing::Create();
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000320 if (!audioproc) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200321 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
322 shared_->SetLastError(VE_NO_MEMORY);
323 return -1;
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000324 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200325 }
326 shared_->set_audio_processing(audioproc);
niklas.enbom@webrtc.orge33a1022011-11-16 10:33:53 +0000327
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200328 // Set the error state for any failures in this block.
329 shared_->SetLastError(VE_APM_ERROR);
330 // Configure AudioProcessing components.
331 if (audioproc->high_pass_filter()->Enable(true) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200332 LOG_F(LS_ERROR) << "Failed to enable high pass filter.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200333 return -1;
334 }
335 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200336 LOG_F(LS_ERROR) << "Failed to disable drift compensation.";
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200337 return -1;
338 }
339 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200340 LOG_F(LS_ERROR) << "Failed to set noise suppression level: "
341 << kDefaultNsMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200342 return -1;
343 }
344 GainControl* agc = audioproc->gain_control();
345 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200346 LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: "
347 << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200348 return -1;
349 }
350 if (agc->set_mode(kDefaultAgcMode) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200351 LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200352 return -1;
353 }
354 if (agc->Enable(kDefaultAgcState) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200355 LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200356 return -1;
357 }
358 shared_->SetLastError(0); // Clear error state.
andrew@webrtc.orgf0a90c32013-03-05 01:12:49 +0000359
niklase@google.com470e71d2011-07-07 08:21:25 +0000360#ifdef WEBRTC_VOICE_ENGINE_AGC
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200361 bool agc_enabled =
362 agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled();
363 if (shared_->audio_device()->SetAGC(agc_enabled) != 0) {
Jelena Marusicf353dd52015-05-06 15:04:22 +0200364 LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200365 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
366 // TODO(ajm): No error return here due to
367 // https://code.google.com/p/webrtc/issues/detail?id=1464
368 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000369#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000370
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200371 return shared_->statistics().SetInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000372}
373
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200374int VoEBaseImpl::Terminate() {
375 CriticalSectionScoped cs(shared_->crit_sec());
376 return TerminateInternal();
niklase@google.com470e71d2011-07-07 08:21:25 +0000377}
378
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000379int VoEBaseImpl::CreateChannel() {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200380 CriticalSectionScoped cs(shared_->crit_sec());
381 if (!shared_->statistics().Initialized()) {
382 shared_->SetLastError(VE_NOT_INITED, kTraceError);
383 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000384 }
385
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200386 voe::ChannelOwner channel_owner = shared_->channel_manager().CreateChannel();
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000387 return InitializeChannel(&channel_owner);
388}
389
390int VoEBaseImpl::CreateChannel(const Config& config) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200391 CriticalSectionScoped cs(shared_->crit_sec());
392 if (!shared_->statistics().Initialized()) {
393 shared_->SetLastError(VE_NOT_INITED, kTraceError);
394 return -1;
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000395 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200396 voe::ChannelOwner channel_owner =
397 shared_->channel_manager().CreateChannel(config);
turaj@webrtc.org03f33702013-11-13 00:02:48 +0000398 return InitializeChannel(&channel_owner);
399}
400
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200401int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) {
402 if (channel_owner->channel()->SetEngineInformation(
403 shared_->statistics(), *shared_->output_mixer(),
404 *shared_->transmit_mixer(), *shared_->process_thread(),
405 *shared_->audio_device(), voiceEngineObserverPtr_,
406 &callbackCritSect_) != 0) {
407 shared_->SetLastError(
408 VE_CHANNEL_NOT_CREATED, kTraceError,
409 "CreateChannel() failed to associate engine and channel."
410 " Destroying channel.");
411 shared_->channel_manager().DestroyChannel(
412 channel_owner->channel()->ChannelId());
413 return -1;
414 } else if (channel_owner->channel()->Init() != 0) {
415 shared_->SetLastError(
416 VE_CHANNEL_NOT_CREATED, kTraceError,
417 "CreateChannel() failed to initialize channel. Destroying"
418 " channel.");
419 shared_->channel_manager().DestroyChannel(
420 channel_owner->channel()->ChannelId());
421 return -1;
422 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000423
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200424 return channel_owner->channel()->ChannelId();
niklase@google.com470e71d2011-07-07 08:21:25 +0000425}
426
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200427int VoEBaseImpl::DeleteChannel(int channel) {
428 CriticalSectionScoped cs(shared_->crit_sec());
429 if (!shared_->statistics().Initialized()) {
430 shared_->SetLastError(VE_NOT_INITED, kTraceError);
431 return -1;
432 }
433
434 {
435 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
436 voe::Channel* channelPtr = ch.channel();
437 if (channelPtr == nullptr) {
438 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
439 "DeleteChannel() failed to locate channel");
440 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000441 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200442 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000443
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200444 shared_->channel_manager().DestroyChannel(channel);
445 if (StopSend() != 0) {
446 return -1;
447 }
448 if (StopPlayout() != 0) {
449 return -1;
450 }
451 return 0;
452}
niklase@google.com470e71d2011-07-07 08:21:25 +0000453
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200454int VoEBaseImpl::StartReceive(int channel) {
455 CriticalSectionScoped cs(shared_->crit_sec());
456 if (!shared_->statistics().Initialized()) {
457 shared_->SetLastError(VE_NOT_INITED, kTraceError);
458 return -1;
459 }
460 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
461 voe::Channel* channelPtr = ch.channel();
462 if (channelPtr == nullptr) {
463 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
464 "StartReceive() failed to locate channel");
465 return -1;
466 }
467 return channelPtr->StartReceiving();
468}
niklase@google.com470e71d2011-07-07 08:21:25 +0000469
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200470int VoEBaseImpl::StopReceive(int channel) {
471 CriticalSectionScoped cs(shared_->crit_sec());
472 if (!shared_->statistics().Initialized()) {
473 shared_->SetLastError(VE_NOT_INITED, kTraceError);
474 return -1;
475 }
476 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
477 voe::Channel* channelPtr = ch.channel();
478 if (channelPtr == nullptr) {
479 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
480 "SetLocalReceiver() failed to locate channel");
481 return -1;
482 }
483 return channelPtr->StopReceiving();
484}
niklase@google.com470e71d2011-07-07 08:21:25 +0000485
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200486int VoEBaseImpl::StartPlayout(int channel) {
487 CriticalSectionScoped cs(shared_->crit_sec());
488 if (!shared_->statistics().Initialized()) {
489 shared_->SetLastError(VE_NOT_INITED, kTraceError);
490 return -1;
491 }
492 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
493 voe::Channel* channelPtr = ch.channel();
494 if (channelPtr == nullptr) {
495 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
496 "StartPlayout() failed to locate channel");
497 return -1;
498 }
499 if (channelPtr->Playing()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000500 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200501 }
502 if (StartPlayout() != 0) {
503 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
504 "StartPlayout() failed to start playout");
505 return -1;
506 }
507 return channelPtr->StartPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000508}
509
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200510int VoEBaseImpl::StopPlayout(int channel) {
511 CriticalSectionScoped cs(shared_->crit_sec());
512 if (!shared_->statistics().Initialized()) {
513 shared_->SetLastError(VE_NOT_INITED, kTraceError);
514 return -1;
515 }
516 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
517 voe::Channel* channelPtr = ch.channel();
518 if (channelPtr == nullptr) {
519 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
520 "StopPlayout() failed to locate channel");
521 return -1;
522 }
523 if (channelPtr->StopPlayout() != 0) {
524 LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
525 << channel;
526 }
527 return StopPlayout();
niklase@google.com470e71d2011-07-07 08:21:25 +0000528}
529
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200530int VoEBaseImpl::StartSend(int channel) {
531 CriticalSectionScoped cs(shared_->crit_sec());
532 if (!shared_->statistics().Initialized()) {
533 shared_->SetLastError(VE_NOT_INITED, kTraceError);
534 return -1;
535 }
536 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
537 voe::Channel* channelPtr = ch.channel();
538 if (channelPtr == nullptr) {
539 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
540 "StartSend() failed to locate channel");
541 return -1;
542 }
543 if (channelPtr->Sending()) {
544 return 0;
545 }
546 if (StartSend() != 0) {
547 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
548 "StartSend() failed to start recording");
549 return -1;
550 }
551 return channelPtr->StartSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000552}
553
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200554int VoEBaseImpl::StopSend(int channel) {
555 CriticalSectionScoped cs(shared_->crit_sec());
556 if (!shared_->statistics().Initialized()) {
557 shared_->SetLastError(VE_NOT_INITED, kTraceError);
558 return -1;
559 }
560 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
561 voe::Channel* channelPtr = ch.channel();
562 if (channelPtr == nullptr) {
563 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
564 "StopSend() failed to locate channel");
565 return -1;
566 }
567 if (channelPtr->StopSend() != 0) {
568 LOG_F(LS_WARNING) << "StopSend() failed to stop sending for channel "
569 << channel;
570 }
571 return StopSend();
niklase@google.com470e71d2011-07-07 08:21:25 +0000572}
573
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200574int VoEBaseImpl::GetVersion(char version[1024]) {
575 assert(kVoiceEngineVersionMaxMessageSize == 1024);
niklase@google.com470e71d2011-07-07 08:21:25 +0000576
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200577 if (version == nullptr) {
578 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
579 return (-1);
580 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000581
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200582 char versionBuf[kVoiceEngineVersionMaxMessageSize];
583 char* versionPtr = versionBuf;
niklase@google.com470e71d2011-07-07 08:21:25 +0000584
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200585 int32_t len = 0;
586 int32_t accLen = 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000587
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200588 len = AddVoEVersion(versionPtr);
589 if (len == -1) {
590 return -1;
591 }
592 versionPtr += len;
593 accLen += len;
594 assert(accLen < kVoiceEngineVersionMaxMessageSize);
niklase@google.com470e71d2011-07-07 08:21:25 +0000595
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000596#ifdef WEBRTC_EXTERNAL_TRANSPORT
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200597 len = AddExternalTransportBuild(versionPtr);
598 if (len == -1) {
599 return -1;
600 }
601 versionPtr += len;
602 accLen += len;
603 assert(accLen < kVoiceEngineVersionMaxMessageSize);
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000604#endif
niklase@google.com470e71d2011-07-07 08:21:25 +0000605
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200606 memcpy(version, versionBuf, accLen);
607 version[accLen] = '\0';
niklase@google.com470e71d2011-07-07 08:21:25 +0000608
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200609 // to avoid the truncation in the trace, split the string into parts
610 char partOfVersion[256];
611 for (int partStart = 0; partStart < accLen;) {
612 memset(partOfVersion, 0, sizeof(partOfVersion));
613 int partEnd = partStart + 180;
614 while (version[partEnd] != '\n' && version[partEnd] != '\0') {
615 partEnd--;
niklase@google.com470e71d2011-07-07 08:21:25 +0000616 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200617 if (partEnd < accLen) {
618 memcpy(partOfVersion, &version[partStart], partEnd - partStart);
619 } else {
620 memcpy(partOfVersion, &version[partStart], accLen - partStart);
621 }
622 partStart = partEnd;
623 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000624
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200625 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000626}
627
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200628int32_t VoEBaseImpl::AddVoEVersion(char* str) const {
629 return sprintf(str, "VoiceEngine 4.1.0\n");
niklase@google.com470e71d2011-07-07 08:21:25 +0000630}
631
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000632#ifdef WEBRTC_EXTERNAL_TRANSPORT
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200633int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const {
634 return sprintf(str, "External transport build\n");
pwestin@webrtc.org684f0572013-03-13 23:20:57 +0000635}
636#endif
637
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200638int VoEBaseImpl::LastError() { return (shared_->statistics().LastError()); }
niklase@google.com470e71d2011-07-07 08:21:25 +0000639
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200640int32_t VoEBaseImpl::StartPlayout() {
641 if (shared_->audio_device()->Playing()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000642 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200643 }
644 if (!shared_->ext_playout()) {
645 if (shared_->audio_device()->InitPlayout() != 0) {
646 LOG_F(LS_ERROR) << "Failed to initialize playout";
647 return -1;
648 }
649 if (shared_->audio_device()->StartPlayout() != 0) {
650 LOG_F(LS_ERROR) << "Failed to start playout";
651 return -1;
652 }
653 }
654 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000655}
656
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000657int32_t VoEBaseImpl::StopPlayout() {
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000658 // Stop audio-device playing if no channel is playing out
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200659 if (shared_->NumOfPlayingChannels() == 0) {
660 if (shared_->audio_device()->StopPlayout() != 0) {
661 shared_->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000662 "StopPlayout() failed to stop playout");
663 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000664 }
pbos@webrtc.org676ff1e2013-08-07 17:57:36 +0000665 }
666 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000667}
668
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200669int32_t VoEBaseImpl::StartSend() {
670 if (shared_->audio_device()->Recording()) {
niklase@google.com470e71d2011-07-07 08:21:25 +0000671 return 0;
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200672 }
673 if (!shared_->ext_recording()) {
674 if (shared_->audio_device()->InitRecording() != 0) {
675 LOG_F(LS_ERROR) << "Failed to initialize recording";
676 return -1;
677 }
678 if (shared_->audio_device()->StartRecording() != 0) {
679 LOG_F(LS_ERROR) << "Failed to start recording";
680 return -1;
681 }
682 }
683
684 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000685}
686
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200687int32_t VoEBaseImpl::StopSend() {
688 if (shared_->NumOfSendingChannels() == 0 &&
689 !shared_->transmit_mixer()->IsRecordingMic()) {
690 // Stop audio-device recording if no channel is recording
691 if (shared_->audio_device()->StopRecording() != 0) {
692 shared_->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError,
693 "StopSend() failed to stop recording");
694 return -1;
niklase@google.com470e71d2011-07-07 08:21:25 +0000695 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200696 shared_->transmit_mixer()->StopSend();
697 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000698
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200699 return 0;
niklase@google.com470e71d2011-07-07 08:21:25 +0000700}
701
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200702int32_t VoEBaseImpl::TerminateInternal() {
703 // Delete any remaining channel objects
704 shared_->channel_manager().DestroyAllChannels();
niklase@google.com470e71d2011-07-07 08:21:25 +0000705
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200706 if (shared_->process_thread()) {
707 if (shared_->audio_device()) {
708 shared_->process_thread()->DeRegisterModule(shared_->audio_device());
niklase@google.com470e71d2011-07-07 08:21:25 +0000709 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200710 shared_->process_thread()->Stop();
711 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000712
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200713 if (shared_->audio_device()) {
714 if (shared_->audio_device()->StopPlayout() != 0) {
715 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
716 "TerminateInternal() failed to stop playout");
niklase@google.com470e71d2011-07-07 08:21:25 +0000717 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200718 if (shared_->audio_device()->StopRecording() != 0) {
719 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
720 "TerminateInternal() failed to stop recording");
niklase@google.com470e71d2011-07-07 08:21:25 +0000721 }
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200722 if (shared_->audio_device()->RegisterEventObserver(nullptr) != 0) {
723 shared_->SetLastError(
724 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
725 "TerminateInternal() failed to de-register event observer "
726 "for the ADM");
727 }
728 if (shared_->audio_device()->RegisterAudioCallback(nullptr) != 0) {
729 shared_->SetLastError(
730 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
731 "TerminateInternal() failed to de-register audio callback "
732 "for the ADM");
733 }
734 if (shared_->audio_device()->Terminate() != 0) {
735 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
736 "TerminateInternal() failed to terminate the ADM");
737 }
738 shared_->set_audio_device(nullptr);
739 }
niklase@google.com470e71d2011-07-07 08:21:25 +0000740
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200741 if (shared_->audio_processing()) {
742 shared_->set_audio_processing(nullptr);
743 }
744
745 return shared_->statistics().SetUnInitialized();
niklase@google.com470e71d2011-07-07 08:21:25 +0000746}
747
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000748int VoEBaseImpl::ProcessRecordedDataWithAPM(
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200749 const int voe_channels[], int number_of_voe_channels,
750 const void* audio_data, uint32_t sample_rate, uint8_t number_of_channels,
751 uint32_t number_of_frames, uint32_t audio_delay_milliseconds,
752 int32_t clock_drift, uint32_t volume, bool key_pressed) {
753 assert(shared_->transmit_mixer() != nullptr);
754 assert(shared_->audio_device() != nullptr);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000755
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000756 uint32_t max_volume = 0;
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000757 uint16_t voe_mic_level = 0;
andrew@webrtc.org023cc5a2014-01-11 01:25:53 +0000758 // Check for zero to skip this calculation; the consumer may use this to
759 // indicate no volume is available.
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000760 if (volume != 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000761 // Scale from ADM to VoE level range
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200762 if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000763 if (max_volume) {
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000764 voe_mic_level = static_cast<uint16_t>(
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200765 (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) /
766 max_volume);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000767 }
768 }
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000769 // We learned that on certain systems (e.g Linux) the voe_mic_level
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000770 // can be greater than the maxVolumeLevel therefore
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000771 // we are going to cap the voe_mic_level to the maxVolumeLevel
772 // and change the maxVolume to volume if it turns out that
773 // the voe_mic_level is indeed greater than the maxVolumeLevel.
774 if (voe_mic_level > kMaxVolumeLevel) {
775 voe_mic_level = kMaxVolumeLevel;
776 max_volume = volume;
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000777 }
778 }
779
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000780 // Perform channel-independent operations
781 // (APM, mix with file, record to file, mute, etc.)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200782 shared_->transmit_mixer()->PrepareDemux(
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000783 audio_data, number_of_frames, number_of_channels, sample_rate,
784 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000785 voe_mic_level, key_pressed);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000786
787 // Copy the audio frame to each sending channel and perform
788 // channel-dependent operations (file mixing, mute, etc.), encode and
789 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0,
790 // do the operations on all the existing VoE channels; otherwise the
791 // operations will be done on specific channels.
792 if (number_of_voe_channels == 0) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200793 shared_->transmit_mixer()->DemuxAndMix();
794 shared_->transmit_mixer()->EncodeAndSend();
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000795 } else {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200796 shared_->transmit_mixer()->DemuxAndMix(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000797 number_of_voe_channels);
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200798 shared_->transmit_mixer()->EncodeAndSend(voe_channels,
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000799 number_of_voe_channels);
800 }
801
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000802 // Scale from VoE to ADM level range.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200803 uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel();
andrew@webrtc.org27c69802014-02-18 20:24:56 +0000804 if (new_voe_mic_level != voe_mic_level) {
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000805 // Return the new volume if AGC has changed the volume.
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200806 return static_cast<int>((new_voe_mic_level * max_volume +
807 static_cast<int>(kMaxVolumeLevel / 2)) /
808 kMaxVolumeLevel);
xians@webrtc.org8fff1f02013-07-31 16:27:42 +0000809 }
810
811 // Return 0 to indicate no change on the volume.
812 return 0;
813}
814
xians@webrtc.org56925312014-04-14 10:50:37 +0000815void VoEBaseImpl::GetPlayoutData(int sample_rate, int number_of_channels,
816 int number_of_frames, bool feed_data_to_apm,
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200817 void* audio_data, int64_t* elapsed_time_ms,
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000818 int64_t* ntp_time_ms) {
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200819 assert(shared_->output_mixer() != nullptr);
xians@webrtc.org56925312014-04-14 10:50:37 +0000820
821 // TODO(andrew): if the device is running in mono, we should tell the mixer
822 // here so that it will only request mono from AudioCodingModule.
823 // Perform mixing of all active participants (channel-based mixing)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200824 shared_->output_mixer()->MixActiveChannels();
xians@webrtc.org56925312014-04-14 10:50:37 +0000825
826 // Additional operations on the combined signal
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200827 shared_->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
xians@webrtc.org56925312014-04-14 10:50:37 +0000828
829 // Retrieve the final output mix (resampled to match the ADM)
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200830 shared_->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
831 &audioFrame_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000832
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200833 assert(number_of_frames == audioFrame_.samples_per_channel_);
834 assert(sample_rate == audioFrame_.sample_rate_hz_);
xians@webrtc.org56925312014-04-14 10:50:37 +0000835
836 // Deliver audio (PCM) samples to the ADM
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200837 memcpy(audio_data, audioFrame_.data_,
xians@webrtc.org56925312014-04-14 10:50:37 +0000838 sizeof(int16_t) * number_of_frames * number_of_channels);
wu@webrtc.orgcb711f72014-05-19 17:39:11 +0000839
Jelena Marusic2dd6a272015-04-14 09:47:00 +0200840 *elapsed_time_ms = audioFrame_.elapsed_time_ms_;
841 *ntp_time_ms = audioFrame_.ntp_time_ms_;
xians@webrtc.org56925312014-04-14 10:50:37 +0000842}
843
Minyue2013aec2015-05-13 14:14:42 +0200844int VoEBaseImpl::AssociateSendChannel(int channel,
845 int accociate_send_channel) {
846 CriticalSectionScoped cs(shared_->crit_sec());
847
848 if (!shared_->statistics().Initialized()) {
849 shared_->SetLastError(VE_NOT_INITED, kTraceError);
850 return -1;
851 }
852
853 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
854 voe::Channel* channel_ptr = ch.channel();
855 if (channel_ptr == NULL) {
856 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
857 "AssociateSendChannel() failed to locate channel");
858 return -1;
859 }
860
861 ch = shared_->channel_manager().GetChannel(accociate_send_channel);
862 voe::Channel* accociate_send_channel_ptr = ch.channel();
863 if (accociate_send_channel_ptr == NULL) {
864 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
865 "AssociateSendChannel() failed to locate accociate_send_channel");
866 return -1;
867 }
868
869 channel_ptr->set_associate_send_channel(ch);
870 return 0;
871}
872
pbos@webrtc.orgd900e8b2013-07-03 15:12:26 +0000873} // namespace webrtc