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