1 /*
2 * Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
3 *
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
11 #include "webrtc/voice_engine/voe_base_impl.h"
12
13 #include "webrtc/base/format_macros.h"
14 #include "webrtc/base/logging.h"
15 #include "webrtc/common.h"
16 #include "webrtc/common_audio/signal_processing/include/signal_processing_library.h"
17 #include "webrtc/modules/audio_coding/include/audio_coding_module.h"
18 #include "webrtc/modules/audio_device/audio_device_impl.h"
19 #include "webrtc/modules/audio_processing/include/audio_processing.h"
20 #include "webrtc/system_wrappers/include/critical_section_wrapper.h"
21 #include "webrtc/system_wrappers/include/file_wrapper.h"
22 #include "webrtc/voice_engine/channel.h"
23 #include "webrtc/voice_engine/include/voe_errors.h"
24 #include "webrtc/voice_engine/output_mixer.h"
25 #include "webrtc/voice_engine/transmit_mixer.h"
26 #include "webrtc/voice_engine/utility.h"
27 #include "webrtc/voice_engine/voice_engine_impl.h"
28
29 namespace webrtc {
30
GetInterface(VoiceEngine * voiceEngine)31 VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine) {
32 if (nullptr == voiceEngine) {
33 return nullptr;
34 }
35 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine);
36 s->AddRef();
37 return s;
38 }
39
VoEBaseImpl(voe::SharedData * shared)40 VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared)
41 : voiceEngineObserverPtr_(nullptr),
42 callbackCritSect_(*CriticalSectionWrapper::CreateCriticalSection()),
43 shared_(shared) {}
44
~VoEBaseImpl()45 VoEBaseImpl::~VoEBaseImpl() {
46 TerminateInternal();
47 delete &callbackCritSect_;
48 }
49
OnErrorIsReported(const ErrorCode error)50 void VoEBaseImpl::OnErrorIsReported(const ErrorCode error) {
51 CriticalSectionScoped cs(&callbackCritSect_);
52 int errCode = 0;
53 if (error == AudioDeviceObserver::kRecordingError) {
54 errCode = VE_RUNTIME_REC_ERROR;
55 LOG_F(LS_ERROR) << "VE_RUNTIME_REC_ERROR";
56 } else if (error == AudioDeviceObserver::kPlayoutError) {
57 errCode = VE_RUNTIME_PLAY_ERROR;
58 LOG_F(LS_ERROR) << "VE_RUNTIME_PLAY_ERROR";
59 }
60 if (voiceEngineObserverPtr_) {
61 // Deliver callback (-1 <=> no channel dependency)
62 voiceEngineObserverPtr_->CallbackOnError(-1, errCode);
63 }
64 }
65
OnWarningIsReported(const WarningCode warning)66 void VoEBaseImpl::OnWarningIsReported(const WarningCode warning) {
67 CriticalSectionScoped cs(&callbackCritSect_);
68 int warningCode = 0;
69 if (warning == AudioDeviceObserver::kRecordingWarning) {
70 warningCode = VE_RUNTIME_REC_WARNING;
71 LOG_F(LS_WARNING) << "VE_RUNTIME_REC_WARNING";
72 } else if (warning == AudioDeviceObserver::kPlayoutWarning) {
73 warningCode = VE_RUNTIME_PLAY_WARNING;
74 LOG_F(LS_WARNING) << "VE_RUNTIME_PLAY_WARNING";
75 }
76 if (voiceEngineObserverPtr_) {
77 // Deliver callback (-1 <=> no channel dependency)
78 voiceEngineObserverPtr_->CallbackOnError(-1, warningCode);
79 }
80 }
81
RecordedDataIsAvailable(const void * audioSamples,const size_t nSamples,const size_t nBytesPerSample,const size_t nChannels,const uint32_t samplesPerSec,const uint32_t totalDelayMS,const int32_t clockDrift,const uint32_t currentMicLevel,const bool keyPressed,uint32_t & newMicLevel)82 int32_t VoEBaseImpl::RecordedDataIsAvailable(const void* audioSamples,
83 const size_t nSamples,
84 const size_t nBytesPerSample,
85 const size_t nChannels,
86 const uint32_t samplesPerSec,
87 const uint32_t totalDelayMS,
88 const int32_t clockDrift,
89 const uint32_t currentMicLevel,
90 const bool keyPressed,
91 uint32_t& newMicLevel) {
92 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM(
93 nullptr, 0, audioSamples, samplesPerSec, nChannels, nSamples,
94 totalDelayMS, clockDrift, currentMicLevel, keyPressed));
95 return 0;
96 }
97
NeedMorePlayData(const size_t nSamples,const size_t nBytesPerSample,const size_t nChannels,const uint32_t samplesPerSec,void * audioSamples,size_t & nSamplesOut,int64_t * elapsed_time_ms,int64_t * ntp_time_ms)98 int32_t VoEBaseImpl::NeedMorePlayData(const size_t nSamples,
99 const size_t nBytesPerSample,
100 const size_t nChannels,
101 const uint32_t samplesPerSec,
102 void* audioSamples,
103 size_t& nSamplesOut,
104 int64_t* elapsed_time_ms,
105 int64_t* ntp_time_ms) {
106 GetPlayoutData(static_cast<int>(samplesPerSec), nChannels, nSamples, true,
107 audioSamples, elapsed_time_ms, ntp_time_ms);
108 nSamplesOut = audioFrame_.samples_per_channel_;
109 return 0;
110 }
111
OnDataAvailable(const int voe_channels[],size_t number_of_voe_channels,const int16_t * audio_data,int sample_rate,size_t number_of_channels,size_t number_of_frames,int audio_delay_milliseconds,int volume,bool key_pressed,bool need_audio_processing)112 int VoEBaseImpl::OnDataAvailable(const int voe_channels[],
113 size_t number_of_voe_channels,
114 const int16_t* audio_data, int sample_rate,
115 size_t number_of_channels,
116 size_t number_of_frames,
117 int audio_delay_milliseconds, int volume,
118 bool key_pressed, bool need_audio_processing) {
119 if (number_of_voe_channels == 0) return 0;
120
121 if (need_audio_processing) {
122 return ProcessRecordedDataWithAPM(
123 voe_channels, number_of_voe_channels, audio_data, sample_rate,
124 number_of_channels, number_of_frames, audio_delay_milliseconds, 0,
125 volume, key_pressed);
126 }
127
128 // No need to go through the APM, demultiplex the data to each VoE channel,
129 // encode and send to the network.
130 for (size_t i = 0; i < number_of_voe_channels; ++i) {
131 // TODO(ajm): In the case where multiple channels are using the same codec
132 // rate, this path needlessly does extra conversions. We should convert once
133 // and share between channels.
134 PushCaptureData(voe_channels[i], audio_data, 16, sample_rate,
135 number_of_channels, number_of_frames);
136 }
137
138 // Return 0 to indicate no need to change the volume.
139 return 0;
140 }
141
OnData(int voe_channel,const void * audio_data,int bits_per_sample,int sample_rate,size_t number_of_channels,size_t number_of_frames)142 void VoEBaseImpl::OnData(int voe_channel, const void* audio_data,
143 int bits_per_sample, int sample_rate,
144 size_t number_of_channels, size_t number_of_frames) {
145 PushCaptureData(voe_channel, audio_data, bits_per_sample, sample_rate,
146 number_of_channels, number_of_frames);
147 }
148
PushCaptureData(int voe_channel,const void * audio_data,int bits_per_sample,int sample_rate,size_t number_of_channels,size_t number_of_frames)149 void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data,
150 int bits_per_sample, int sample_rate,
151 size_t number_of_channels,
152 size_t number_of_frames) {
153 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(voe_channel);
154 voe::Channel* channel_ptr = ch.channel();
155 if (!channel_ptr) return;
156
157 if (channel_ptr->Sending()) {
158 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data),
159 sample_rate, number_of_frames, number_of_channels);
160 channel_ptr->PrepareEncodeAndSend(sample_rate);
161 channel_ptr->EncodeAndSend();
162 }
163 }
164
PullRenderData(int bits_per_sample,int sample_rate,size_t number_of_channels,size_t number_of_frames,void * audio_data,int64_t * elapsed_time_ms,int64_t * ntp_time_ms)165 void VoEBaseImpl::PullRenderData(int bits_per_sample,
166 int sample_rate,
167 size_t number_of_channels,
168 size_t number_of_frames,
169 void* audio_data, int64_t* elapsed_time_ms,
170 int64_t* ntp_time_ms) {
171 assert(bits_per_sample == 16);
172 assert(number_of_frames == static_cast<size_t>(sample_rate / 100));
173
174 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false,
175 audio_data, elapsed_time_ms, ntp_time_ms);
176 }
177
RegisterVoiceEngineObserver(VoiceEngineObserver & observer)178 int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer) {
179 CriticalSectionScoped cs(&callbackCritSect_);
180 if (voiceEngineObserverPtr_) {
181 shared_->SetLastError(
182 VE_INVALID_OPERATION, kTraceError,
183 "RegisterVoiceEngineObserver() observer already enabled");
184 return -1;
185 }
186
187 // Register the observer in all active channels
188 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
189 it.IsValid(); it.Increment()) {
190 it.GetChannel()->RegisterVoiceEngineObserver(observer);
191 }
192
193 shared_->transmit_mixer()->RegisterVoiceEngineObserver(observer);
194 voiceEngineObserverPtr_ = &observer;
195 return 0;
196 }
197
DeRegisterVoiceEngineObserver()198 int VoEBaseImpl::DeRegisterVoiceEngineObserver() {
199 CriticalSectionScoped cs(&callbackCritSect_);
200 if (!voiceEngineObserverPtr_) {
201 shared_->SetLastError(
202 VE_INVALID_OPERATION, kTraceError,
203 "DeRegisterVoiceEngineObserver() observer already disabled");
204 return 0;
205 }
206 voiceEngineObserverPtr_ = nullptr;
207
208 // Deregister the observer in all active channels
209 for (voe::ChannelManager::Iterator it(&shared_->channel_manager());
210 it.IsValid(); it.Increment()) {
211 it.GetChannel()->DeRegisterVoiceEngineObserver();
212 }
213
214 return 0;
215 }
216
Init(AudioDeviceModule * external_adm,AudioProcessing * audioproc)217 int VoEBaseImpl::Init(AudioDeviceModule* external_adm,
218 AudioProcessing* audioproc) {
219 CriticalSectionScoped cs(shared_->crit_sec());
220 WebRtcSpl_Init();
221 if (shared_->statistics().Initialized()) {
222 return 0;
223 }
224 if (shared_->process_thread()) {
225 shared_->process_thread()->Start();
226 }
227
228 // Create an internal ADM if the user has not added an external
229 // ADM implementation as input to Init().
230 if (external_adm == nullptr) {
231 #if !defined(WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE)
232 return -1;
233 #else
234 // Create the internal ADM implementation.
235 shared_->set_audio_device(AudioDeviceModuleImpl::Create(
236 VoEId(shared_->instance_id(), -1), shared_->audio_device_layer()));
237
238 if (shared_->audio_device() == nullptr) {
239 shared_->SetLastError(VE_NO_MEMORY, kTraceCritical,
240 "Init() failed to create the ADM");
241 return -1;
242 }
243 #endif // WEBRTC_INCLUDE_INTERNAL_AUDIO_DEVICE
244 } else {
245 // Use the already existing external ADM implementation.
246 shared_->set_audio_device(external_adm);
247 LOG_F(LS_INFO)
248 << "An external ADM implementation will be used in VoiceEngine";
249 }
250
251 // Register the ADM to the process thread, which will drive the error
252 // callback mechanism
253 if (shared_->process_thread()) {
254 shared_->process_thread()->RegisterModule(shared_->audio_device());
255 }
256
257 bool available = false;
258
259 // --------------------
260 // Reinitialize the ADM
261
262 // Register the AudioObserver implementation
263 if (shared_->audio_device()->RegisterEventObserver(this) != 0) {
264 shared_->SetLastError(
265 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
266 "Init() failed to register event observer for the ADM");
267 }
268
269 // Register the AudioTransport implementation
270 if (shared_->audio_device()->RegisterAudioCallback(this) != 0) {
271 shared_->SetLastError(
272 VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning,
273 "Init() failed to register audio callback for the ADM");
274 }
275
276 // ADM initialization
277 if (shared_->audio_device()->Init() != 0) {
278 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
279 "Init() failed to initialize the ADM");
280 return -1;
281 }
282
283 // Initialize the default speaker
284 if (shared_->audio_device()->SetPlayoutDevice(
285 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
286 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo,
287 "Init() failed to set the default output device");
288 }
289 if (shared_->audio_device()->InitSpeaker() != 0) {
290 shared_->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo,
291 "Init() failed to initialize the speaker");
292 }
293
294 // Initialize the default microphone
295 if (shared_->audio_device()->SetRecordingDevice(
296 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) {
297 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo,
298 "Init() failed to set the default input device");
299 }
300 if (shared_->audio_device()->InitMicrophone() != 0) {
301 shared_->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo,
302 "Init() failed to initialize the microphone");
303 }
304
305 // Set number of channels
306 if (shared_->audio_device()->StereoPlayoutIsAvailable(&available) != 0) {
307 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
308 "Init() failed to query stereo playout mode");
309 }
310 if (shared_->audio_device()->SetStereoPlayout(available) != 0) {
311 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
312 "Init() failed to set mono/stereo playout mode");
313 }
314
315 // TODO(andrew): These functions don't tell us whether stereo recording
316 // is truly available. We simply set the AudioProcessing input to stereo
317 // here, because we have to wait until receiving the first frame to
318 // determine the actual number of channels anyway.
319 //
320 // These functions may be changed; tracked here:
321 // http://code.google.com/p/webrtc/issues/detail?id=204
322 shared_->audio_device()->StereoRecordingIsAvailable(&available);
323 if (shared_->audio_device()->SetStereoRecording(available) != 0) {
324 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
325 "Init() failed to set mono/stereo recording mode");
326 }
327
328 if (!audioproc) {
329 audioproc = AudioProcessing::Create();
330 if (!audioproc) {
331 LOG(LS_ERROR) << "Failed to create AudioProcessing.";
332 shared_->SetLastError(VE_NO_MEMORY);
333 return -1;
334 }
335 }
336 shared_->set_audio_processing(audioproc);
337
338 // Set the error state for any failures in this block.
339 shared_->SetLastError(VE_APM_ERROR);
340 // Configure AudioProcessing components.
341 if (audioproc->high_pass_filter()->Enable(true) != 0) {
342 LOG_F(LS_ERROR) << "Failed to enable high pass filter.";
343 return -1;
344 }
345 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) {
346 LOG_F(LS_ERROR) << "Failed to disable drift compensation.";
347 return -1;
348 }
349 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) {
350 LOG_F(LS_ERROR) << "Failed to set noise suppression level: "
351 << kDefaultNsMode;
352 return -1;
353 }
354 GainControl* agc = audioproc->gain_control();
355 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) {
356 LOG_F(LS_ERROR) << "Failed to set analog level limits with minimum: "
357 << kMinVolumeLevel << " and maximum: " << kMaxVolumeLevel;
358 return -1;
359 }
360 if (agc->set_mode(kDefaultAgcMode) != 0) {
361 LOG_F(LS_ERROR) << "Failed to set mode: " << kDefaultAgcMode;
362 return -1;
363 }
364 if (agc->Enable(kDefaultAgcState) != 0) {
365 LOG_F(LS_ERROR) << "Failed to set agc state: " << kDefaultAgcState;
366 return -1;
367 }
368 shared_->SetLastError(0); // Clear error state.
369
370 #ifdef WEBRTC_VOICE_ENGINE_AGC
371 bool agc_enabled =
372 agc->mode() == GainControl::kAdaptiveAnalog && agc->is_enabled();
373 if (shared_->audio_device()->SetAGC(agc_enabled) != 0) {
374 LOG_F(LS_ERROR) << "Failed to set agc to enabled: " << agc_enabled;
375 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR);
376 // TODO(ajm): No error return here due to
377 // https://code.google.com/p/webrtc/issues/detail?id=1464
378 }
379 #endif
380
381 return shared_->statistics().SetInitialized();
382 }
383
Terminate()384 int VoEBaseImpl::Terminate() {
385 CriticalSectionScoped cs(shared_->crit_sec());
386 return TerminateInternal();
387 }
388
CreateChannel()389 int VoEBaseImpl::CreateChannel() {
390 CriticalSectionScoped cs(shared_->crit_sec());
391 if (!shared_->statistics().Initialized()) {
392 shared_->SetLastError(VE_NOT_INITED, kTraceError);
393 return -1;
394 }
395
396 voe::ChannelOwner channel_owner = shared_->channel_manager().CreateChannel();
397 return InitializeChannel(&channel_owner);
398 }
399
CreateChannel(const Config & config)400 int VoEBaseImpl::CreateChannel(const Config& config) {
401 CriticalSectionScoped cs(shared_->crit_sec());
402 if (!shared_->statistics().Initialized()) {
403 shared_->SetLastError(VE_NOT_INITED, kTraceError);
404 return -1;
405 }
406 voe::ChannelOwner channel_owner =
407 shared_->channel_manager().CreateChannel(config);
408 return InitializeChannel(&channel_owner);
409 }
410
InitializeChannel(voe::ChannelOwner * channel_owner)411 int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) {
412 if (channel_owner->channel()->SetEngineInformation(
413 shared_->statistics(), *shared_->output_mixer(),
414 *shared_->transmit_mixer(), *shared_->process_thread(),
415 *shared_->audio_device(), voiceEngineObserverPtr_,
416 &callbackCritSect_) != 0) {
417 shared_->SetLastError(
418 VE_CHANNEL_NOT_CREATED, kTraceError,
419 "CreateChannel() failed to associate engine and channel."
420 " Destroying channel.");
421 shared_->channel_manager().DestroyChannel(
422 channel_owner->channel()->ChannelId());
423 return -1;
424 } else if (channel_owner->channel()->Init() != 0) {
425 shared_->SetLastError(
426 VE_CHANNEL_NOT_CREATED, kTraceError,
427 "CreateChannel() failed to initialize channel. Destroying"
428 " channel.");
429 shared_->channel_manager().DestroyChannel(
430 channel_owner->channel()->ChannelId());
431 return -1;
432 }
433 return channel_owner->channel()->ChannelId();
434 }
435
DeleteChannel(int channel)436 int VoEBaseImpl::DeleteChannel(int channel) {
437 CriticalSectionScoped cs(shared_->crit_sec());
438 if (!shared_->statistics().Initialized()) {
439 shared_->SetLastError(VE_NOT_INITED, kTraceError);
440 return -1;
441 }
442
443 {
444 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
445 voe::Channel* channelPtr = ch.channel();
446 if (channelPtr == nullptr) {
447 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
448 "DeleteChannel() failed to locate channel");
449 return -1;
450 }
451 }
452
453 shared_->channel_manager().DestroyChannel(channel);
454 if (StopSend() != 0) {
455 return -1;
456 }
457 if (StopPlayout() != 0) {
458 return -1;
459 }
460 return 0;
461 }
462
StartReceive(int channel)463 int VoEBaseImpl::StartReceive(int channel) {
464 CriticalSectionScoped cs(shared_->crit_sec());
465 if (!shared_->statistics().Initialized()) {
466 shared_->SetLastError(VE_NOT_INITED, kTraceError);
467 return -1;
468 }
469 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
470 voe::Channel* channelPtr = ch.channel();
471 if (channelPtr == nullptr) {
472 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
473 "StartReceive() failed to locate channel");
474 return -1;
475 }
476 return channelPtr->StartReceiving();
477 }
478
StopReceive(int channel)479 int VoEBaseImpl::StopReceive(int channel) {
480 CriticalSectionScoped cs(shared_->crit_sec());
481 if (!shared_->statistics().Initialized()) {
482 shared_->SetLastError(VE_NOT_INITED, kTraceError);
483 return -1;
484 }
485 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
486 voe::Channel* channelPtr = ch.channel();
487 if (channelPtr == nullptr) {
488 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
489 "SetLocalReceiver() failed to locate channel");
490 return -1;
491 }
492 return channelPtr->StopReceiving();
493 }
494
StartPlayout(int channel)495 int VoEBaseImpl::StartPlayout(int channel) {
496 CriticalSectionScoped cs(shared_->crit_sec());
497 if (!shared_->statistics().Initialized()) {
498 shared_->SetLastError(VE_NOT_INITED, kTraceError);
499 return -1;
500 }
501 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
502 voe::Channel* channelPtr = ch.channel();
503 if (channelPtr == nullptr) {
504 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
505 "StartPlayout() failed to locate channel");
506 return -1;
507 }
508 if (channelPtr->Playing()) {
509 return 0;
510 }
511 if (StartPlayout() != 0) {
512 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
513 "StartPlayout() failed to start playout");
514 return -1;
515 }
516 return channelPtr->StartPlayout();
517 }
518
StopPlayout(int channel)519 int VoEBaseImpl::StopPlayout(int channel) {
520 CriticalSectionScoped cs(shared_->crit_sec());
521 if (!shared_->statistics().Initialized()) {
522 shared_->SetLastError(VE_NOT_INITED, kTraceError);
523 return -1;
524 }
525 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
526 voe::Channel* channelPtr = ch.channel();
527 if (channelPtr == nullptr) {
528 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
529 "StopPlayout() failed to locate channel");
530 return -1;
531 }
532 if (channelPtr->StopPlayout() != 0) {
533 LOG_F(LS_WARNING) << "StopPlayout() failed to stop playout for channel "
534 << channel;
535 }
536 return StopPlayout();
537 }
538
StartSend(int channel)539 int VoEBaseImpl::StartSend(int channel) {
540 CriticalSectionScoped cs(shared_->crit_sec());
541 if (!shared_->statistics().Initialized()) {
542 shared_->SetLastError(VE_NOT_INITED, kTraceError);
543 return -1;
544 }
545 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
546 voe::Channel* channelPtr = ch.channel();
547 if (channelPtr == nullptr) {
548 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
549 "StartSend() failed to locate channel");
550 return -1;
551 }
552 if (channelPtr->Sending()) {
553 return 0;
554 }
555 if (StartSend() != 0) {
556 shared_->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError,
557 "StartSend() failed to start recording");
558 return -1;
559 }
560 return channelPtr->StartSend();
561 }
562
StopSend(int channel)563 int VoEBaseImpl::StopSend(int channel) {
564 CriticalSectionScoped cs(shared_->crit_sec());
565 if (!shared_->statistics().Initialized()) {
566 shared_->SetLastError(VE_NOT_INITED, kTraceError);
567 return -1;
568 }
569 voe::ChannelOwner ch = shared_->channel_manager().GetChannel(channel);
570 voe::Channel* channelPtr = ch.channel();
571 if (channelPtr == nullptr) {
572 shared_->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError,
573 "StopSend() failed to locate channel");
574 return -1;
575 }
576 if (channelPtr->StopSend() != 0) {
577 LOG_F(LS_WARNING) << "StopSend() failed to stop sending for channel "
578 << channel;
579 }
580 return StopSend();
581 }
582
GetVersion(char version[1024])583 int VoEBaseImpl::GetVersion(char version[1024]) {
584 if (version == nullptr) {
585 shared_->SetLastError(VE_INVALID_ARGUMENT, kTraceError);
586 return -1;
587 }
588
589 std::string versionString = VoiceEngine::GetVersionString();
590 RTC_DCHECK_GT(1024u, versionString.size() + 1);
591 char* end = std::copy(versionString.cbegin(), versionString.cend(), version);
592 end[0] = '\n';
593 end[1] = '\0';
594 return 0;
595 }
596
LastError()597 int VoEBaseImpl::LastError() { return (shared_->statistics().LastError()); }
598
StartPlayout()599 int32_t VoEBaseImpl::StartPlayout() {
600 if (!shared_->audio_device()->Playing()) {
601 if (shared_->audio_device()->InitPlayout() != 0) {
602 LOG_F(LS_ERROR) << "Failed to initialize playout";
603 return -1;
604 }
605 if (shared_->audio_device()->StartPlayout() != 0) {
606 LOG_F(LS_ERROR) << "Failed to start playout";
607 return -1;
608 }
609 }
610 return 0;
611 }
612
StopPlayout()613 int32_t VoEBaseImpl::StopPlayout() {
614 // Stop audio-device playing if no channel is playing out
615 if (shared_->NumOfPlayingChannels() == 0) {
616 if (shared_->audio_device()->StopPlayout() != 0) {
617 shared_->SetLastError(VE_CANNOT_STOP_PLAYOUT, kTraceError,
618 "StopPlayout() failed to stop playout");
619 return -1;
620 }
621 }
622 return 0;
623 }
624
StartSend()625 int32_t VoEBaseImpl::StartSend() {
626 if (!shared_->audio_device()->Recording()) {
627 if (shared_->audio_device()->InitRecording() != 0) {
628 LOG_F(LS_ERROR) << "Failed to initialize recording";
629 return -1;
630 }
631 if (shared_->audio_device()->StartRecording() != 0) {
632 LOG_F(LS_ERROR) << "Failed to start recording";
633 return -1;
634 }
635 }
636 return 0;
637 }
638
StopSend()639 int32_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;
647 }
648 shared_->transmit_mixer()->StopSend();
649 }
650
651 return 0;
652 }
653
TerminateInternal()654 int32_t VoEBaseImpl::TerminateInternal() {
655 // Delete any remaining channel objects
656 shared_->channel_manager().DestroyAllChannels();
657
658 if (shared_->process_thread()) {
659 if (shared_->audio_device()) {
660 shared_->process_thread()->DeRegisterModule(shared_->audio_device());
661 }
662 shared_->process_thread()->Stop();
663 }
664
665 if (shared_->audio_device()) {
666 if (shared_->audio_device()->StopPlayout() != 0) {
667 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
668 "TerminateInternal() failed to stop playout");
669 }
670 if (shared_->audio_device()->StopRecording() != 0) {
671 shared_->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning,
672 "TerminateInternal() failed to stop recording");
673 }
674 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 }
692
693 if (shared_->audio_processing()) {
694 shared_->set_audio_processing(nullptr);
695 }
696
697 return shared_->statistics().SetUnInitialized();
698 }
699
ProcessRecordedDataWithAPM(const int voe_channels[],size_t number_of_voe_channels,const void * audio_data,uint32_t sample_rate,size_t number_of_channels,size_t number_of_frames,uint32_t audio_delay_milliseconds,int32_t clock_drift,uint32_t volume,bool key_pressed)700 int VoEBaseImpl::ProcessRecordedDataWithAPM(
701 const int voe_channels[], size_t number_of_voe_channels,
702 const void* audio_data, uint32_t sample_rate, size_t number_of_channels,
703 size_t number_of_frames, uint32_t audio_delay_milliseconds,
704 int32_t clock_drift, uint32_t volume, bool key_pressed) {
705 assert(shared_->transmit_mixer() != nullptr);
706 assert(shared_->audio_device() != nullptr);
707
708 uint32_t max_volume = 0;
709 uint16_t voe_mic_level = 0;
710 // Check for zero to skip this calculation; the consumer may use this to
711 // indicate no volume is available.
712 if (volume != 0) {
713 // Scale from ADM to VoE level range
714 if (shared_->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) {
715 if (max_volume) {
716 voe_mic_level = static_cast<uint16_t>(
717 (volume * kMaxVolumeLevel + static_cast<int>(max_volume / 2)) /
718 max_volume);
719 }
720 }
721 // We learned that on certain systems (e.g Linux) the voe_mic_level
722 // can be greater than the maxVolumeLevel therefore
723 // 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;
729 }
730 }
731
732 // Perform channel-independent operations
733 // (APM, mix with file, record to file, mute, etc.)
734 shared_->transmit_mixer()->PrepareDemux(
735 audio_data, number_of_frames, number_of_channels, sample_rate,
736 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift,
737 voe_mic_level, key_pressed);
738
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) {
745 shared_->transmit_mixer()->DemuxAndMix();
746 shared_->transmit_mixer()->EncodeAndSend();
747 } else {
748 shared_->transmit_mixer()->DemuxAndMix(voe_channels,
749 number_of_voe_channels);
750 shared_->transmit_mixer()->EncodeAndSend(voe_channels,
751 number_of_voe_channels);
752 }
753
754 // Scale from VoE to ADM level range.
755 uint32_t new_voe_mic_level = shared_->transmit_mixer()->CaptureLevel();
756 if (new_voe_mic_level != voe_mic_level) {
757 // Return the new volume if AGC has changed the volume.
758 return static_cast<int>((new_voe_mic_level * max_volume +
759 static_cast<int>(kMaxVolumeLevel / 2)) /
760 kMaxVolumeLevel);
761 }
762
763 // Return 0 to indicate no change on the volume.
764 return 0;
765 }
766
GetPlayoutData(int sample_rate,size_t number_of_channels,size_t number_of_frames,bool feed_data_to_apm,void * audio_data,int64_t * elapsed_time_ms,int64_t * ntp_time_ms)767 void VoEBaseImpl::GetPlayoutData(int sample_rate, size_t number_of_channels,
768 size_t number_of_frames, bool feed_data_to_apm,
769 void* audio_data, int64_t* elapsed_time_ms,
770 int64_t* ntp_time_ms) {
771 assert(shared_->output_mixer() != nullptr);
772
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)
776 shared_->output_mixer()->MixActiveChannels();
777
778 // Additional operations on the combined signal
779 shared_->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm);
780
781 // Retrieve the final output mix (resampled to match the ADM)
782 shared_->output_mixer()->GetMixedAudio(sample_rate, number_of_channels,
783 &audioFrame_);
784
785 assert(number_of_frames == audioFrame_.samples_per_channel_);
786 assert(sample_rate == audioFrame_.sample_rate_hz_);
787
788 // Deliver audio (PCM) samples to the ADM
789 memcpy(audio_data, audioFrame_.data_,
790 sizeof(int16_t) * number_of_frames * number_of_channels);
791
792 *elapsed_time_ms = audioFrame_.elapsed_time_ms_;
793 *ntp_time_ms = audioFrame_.ntp_time_ms_;
794 }
795
AssociateSendChannel(int channel,int accociate_send_channel)796 int VoEBaseImpl::AssociateSendChannel(int channel,
797 int accociate_send_channel) {
798 CriticalSectionScoped cs(shared_->crit_sec());
799
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
825 } // namespace webrtc
826