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/common.h" 14 #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" 20 #include "webrtc/system_wrappers/interface/trace.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 31 VoEBase* VoEBase::GetInterface(VoiceEngine* voiceEngine) 32 { 33 if (NULL == voiceEngine) 34 { 35 return NULL; 36 } 37 VoiceEngineImpl* s = static_cast<VoiceEngineImpl*>(voiceEngine); 38 s->AddRef(); 39 return s; 40 } 41 42 VoEBaseImpl::VoEBaseImpl(voe::SharedData* shared) : 43 _voiceEngineObserverPtr(NULL), 44 _callbackCritSect(*CriticalSectionWrapper::CreateCriticalSection()), 45 _voiceEngineObserver(false), _shared(shared) 46 { 47 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), 48 "VoEBaseImpl() - ctor"); 49 } 50 51 VoEBaseImpl::~VoEBaseImpl() 52 { 53 WEBRTC_TRACE(kTraceMemory, kTraceVoice, VoEId(_shared->instance_id(), -1), 54 "~VoEBaseImpl() - dtor"); 55 56 TerminateInternal(); 57 58 delete &_callbackCritSect; 59 } 60 61 void VoEBaseImpl::OnErrorIsReported(ErrorCode error) 62 { 63 CriticalSectionScoped cs(&_callbackCritSect); 64 if (_voiceEngineObserver) 65 { 66 if (_voiceEngineObserverPtr) 67 { 68 int errCode(0); 69 if (error == AudioDeviceObserver::kRecordingError) 70 { 71 errCode = VE_RUNTIME_REC_ERROR; 72 WEBRTC_TRACE(kTraceInfo, kTraceVoice, 73 VoEId(_shared->instance_id(), -1), 74 "VoEBaseImpl::OnErrorIsReported() => VE_RUNTIME_REC_ERROR"); 75 } 76 else if (error == AudioDeviceObserver::kPlayoutError) 77 { 78 errCode = VE_RUNTIME_PLAY_ERROR; 79 WEBRTC_TRACE(kTraceInfo, kTraceVoice, 80 VoEId(_shared->instance_id(), -1), 81 "VoEBaseImpl::OnErrorIsReported() => " 82 "VE_RUNTIME_PLAY_ERROR"); 83 } 84 // Deliver callback (-1 <=> no channel dependency) 85 _voiceEngineObserverPtr->CallbackOnError(-1, errCode); 86 } 87 } 88 } 89 90 void VoEBaseImpl::OnWarningIsReported(WarningCode warning) 91 { 92 CriticalSectionScoped cs(&_callbackCritSect); 93 if (_voiceEngineObserver) 94 { 95 if (_voiceEngineObserverPtr) 96 { 97 int warningCode(0); 98 if (warning == AudioDeviceObserver::kRecordingWarning) 99 { 100 warningCode = VE_RUNTIME_REC_WARNING; 101 WEBRTC_TRACE(kTraceInfo, kTraceVoice, 102 VoEId(_shared->instance_id(), -1), 103 "VoEBaseImpl::OnErrorIsReported() => " 104 "VE_RUNTIME_REC_WARNING"); 105 } 106 else if (warning == AudioDeviceObserver::kPlayoutWarning) 107 { 108 warningCode = VE_RUNTIME_PLAY_WARNING; 109 WEBRTC_TRACE(kTraceInfo, kTraceVoice, 110 VoEId(_shared->instance_id(), -1), 111 "VoEBaseImpl::OnErrorIsReported() => " 112 "VE_RUNTIME_PLAY_WARNING"); 113 } 114 // Deliver callback (-1 <=> no channel dependency) 115 _voiceEngineObserverPtr->CallbackOnError(-1, warningCode); 116 } 117 } 118 } 119 120 int32_t VoEBaseImpl::RecordedDataIsAvailable( 121 const void* audioSamples, 122 uint32_t nSamples, 123 uint8_t nBytesPerSample, 124 uint8_t nChannels, 125 uint32_t samplesPerSec, 126 uint32_t totalDelayMS, 127 int32_t clockDrift, 128 uint32_t micLevel, 129 bool keyPressed, 130 uint32_t& newMicLevel) 131 { 132 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1), 133 "VoEBaseImpl::RecordedDataIsAvailable(nSamples=%u, " 134 "nBytesPerSample=%u, nChannels=%u, samplesPerSec=%u, " 135 "totalDelayMS=%u, clockDrift=%d, micLevel=%u)", 136 nSamples, nBytesPerSample, nChannels, samplesPerSec, 137 totalDelayMS, clockDrift, micLevel); 138 newMicLevel = static_cast<uint32_t>(ProcessRecordedDataWithAPM( 139 NULL, 0, audioSamples, samplesPerSec, nChannels, nSamples, 140 totalDelayMS, clockDrift, micLevel, keyPressed)); 141 142 return 0; 143 } 144 145 int32_t VoEBaseImpl::NeedMorePlayData( 146 uint32_t nSamples, 147 uint8_t nBytesPerSample, 148 uint8_t nChannels, 149 uint32_t samplesPerSec, 150 void* audioSamples, 151 uint32_t& nSamplesOut, 152 int64_t* elapsed_time_ms, 153 int64_t* ntp_time_ms) 154 { 155 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1), 156 "VoEBaseImpl::NeedMorePlayData(nSamples=%u, " 157 "nBytesPerSample=%d, nChannels=%d, samplesPerSec=%u)", 158 nSamples, nBytesPerSample, nChannels, samplesPerSec); 159 160 GetPlayoutData(static_cast<int>(samplesPerSec), 161 static_cast<int>(nChannels), 162 static_cast<int>(nSamples), true, audioSamples, 163 elapsed_time_ms, ntp_time_ms); 164 165 nSamplesOut = _audioFrame.samples_per_channel_; 166 167 return 0; 168 } 169 170 int VoEBaseImpl::OnDataAvailable(const int voe_channels[], 171 int number_of_voe_channels, 172 const int16_t* audio_data, 173 int sample_rate, 174 int number_of_channels, 175 int number_of_frames, 176 int audio_delay_milliseconds, 177 int volume, 178 bool key_pressed, 179 bool need_audio_processing) { 180 WEBRTC_TRACE(kTraceStream, kTraceVoice, VoEId(_shared->instance_id(), -1), 181 "VoEBaseImpl::OnDataAvailable(number_of_voe_channels=%d, " 182 "sample_rate=%d, number_of_channels=%d, number_of_frames=%d, " 183 "audio_delay_milliseconds=%d, volume=%d, " 184 "key_pressed=%d, need_audio_processing=%d)", 185 number_of_voe_channels, sample_rate, number_of_channels, 186 number_of_frames, audio_delay_milliseconds, volume, 187 key_pressed, need_audio_processing); 188 if (number_of_voe_channels == 0) 189 return 0; 190 191 if (need_audio_processing) { 192 return ProcessRecordedDataWithAPM( 193 voe_channels, number_of_voe_channels, audio_data, sample_rate, 194 number_of_channels, number_of_frames, audio_delay_milliseconds, 195 0, volume, key_pressed); 196 } 197 198 // No need to go through the APM, demultiplex the data to each VoE channel, 199 // encode and send to the network. 200 for (int i = 0; i < number_of_voe_channels; ++i) { 201 // TODO(ajm): In the case where multiple channels are using the same codec 202 // rate, this path needlessly does extra conversions. We should convert once 203 // and share between channels. 204 PushCaptureData(voe_channels[i], audio_data, 16, sample_rate, 205 number_of_channels, number_of_frames); 206 } 207 208 // Return 0 to indicate no need to change the volume. 209 return 0; 210 } 211 212 void VoEBaseImpl::OnData(int voe_channel, const void* audio_data, 213 int bits_per_sample, int sample_rate, 214 int number_of_channels, 215 int number_of_frames) { 216 PushCaptureData(voe_channel, audio_data, bits_per_sample, sample_rate, 217 number_of_channels, number_of_frames); 218 } 219 220 void VoEBaseImpl::PushCaptureData(int voe_channel, const void* audio_data, 221 int bits_per_sample, int sample_rate, 222 int number_of_channels, 223 int number_of_frames) { 224 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(voe_channel); 225 voe::Channel* channel_ptr = ch.channel(); 226 if (!channel_ptr) 227 return; 228 229 if (channel_ptr->Sending()) { 230 channel_ptr->Demultiplex(static_cast<const int16_t*>(audio_data), 231 sample_rate, number_of_frames, number_of_channels); 232 channel_ptr->PrepareEncodeAndSend(sample_rate); 233 channel_ptr->EncodeAndSend(); 234 } 235 } 236 237 void VoEBaseImpl::PullRenderData(int bits_per_sample, int sample_rate, 238 int number_of_channels, int number_of_frames, 239 void* audio_data, 240 int64_t* elapsed_time_ms, 241 int64_t* ntp_time_ms) { 242 assert(bits_per_sample == 16); 243 assert(number_of_frames == static_cast<int>(sample_rate / 100)); 244 245 GetPlayoutData(sample_rate, number_of_channels, number_of_frames, false, 246 audio_data, elapsed_time_ms, ntp_time_ms); 247 } 248 249 int VoEBaseImpl::RegisterVoiceEngineObserver(VoiceEngineObserver& observer) 250 { 251 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 252 "RegisterVoiceEngineObserver(observer=0x%d)", &observer); 253 CriticalSectionScoped cs(&_callbackCritSect); 254 if (_voiceEngineObserverPtr) 255 { 256 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError, 257 "RegisterVoiceEngineObserver() observer already enabled"); 258 return -1; 259 } 260 261 // Register the observer in all active channels 262 for (voe::ChannelManager::Iterator it(&_shared->channel_manager()); 263 it.IsValid(); 264 it.Increment()) { 265 it.GetChannel()->RegisterVoiceEngineObserver(observer); 266 } 267 268 _shared->transmit_mixer()->RegisterVoiceEngineObserver(observer); 269 270 _voiceEngineObserverPtr = &observer; 271 _voiceEngineObserver = true; 272 273 return 0; 274 } 275 276 int VoEBaseImpl::DeRegisterVoiceEngineObserver() 277 { 278 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 279 "DeRegisterVoiceEngineObserver()"); 280 CriticalSectionScoped cs(&_callbackCritSect); 281 if (!_voiceEngineObserverPtr) 282 { 283 _shared->SetLastError(VE_INVALID_OPERATION, kTraceError, 284 "DeRegisterVoiceEngineObserver() observer already disabled"); 285 return 0; 286 } 287 288 _voiceEngineObserver = false; 289 _voiceEngineObserverPtr = NULL; 290 291 // Deregister the observer in all active channels 292 for (voe::ChannelManager::Iterator it(&_shared->channel_manager()); 293 it.IsValid(); 294 it.Increment()) { 295 it.GetChannel()->DeRegisterVoiceEngineObserver(); 296 } 297 298 return 0; 299 } 300 301 int VoEBaseImpl::Init(AudioDeviceModule* external_adm, 302 AudioProcessing* audioproc) 303 { 304 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 305 "Init(external_adm=0x%p)", external_adm); 306 CriticalSectionScoped cs(_shared->crit_sec()); 307 308 WebRtcSpl_Init(); 309 310 if (_shared->statistics().Initialized()) 311 { 312 return 0; 313 } 314 315 if (_shared->process_thread()) 316 { 317 if (_shared->process_thread()->Start() != 0) 318 { 319 _shared->SetLastError(VE_THREAD_ERROR, kTraceError, 320 "Init() failed to start module process thread"); 321 return -1; 322 } 323 } 324 325 // Create an internal ADM if the user has not added an external 326 // ADM implementation as input to Init(). 327 if (external_adm == NULL) 328 { 329 // Create the internal ADM implementation. 330 _shared->set_audio_device(AudioDeviceModuleImpl::Create( 331 VoEId(_shared->instance_id(), -1), _shared->audio_device_layer())); 332 333 if (_shared->audio_device() == NULL) 334 { 335 _shared->SetLastError(VE_NO_MEMORY, kTraceCritical, 336 "Init() failed to create the ADM"); 337 return -1; 338 } 339 } 340 else 341 { 342 // Use the already existing external ADM implementation. 343 _shared->set_audio_device(external_adm); 344 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), 345 "An external ADM implementation will be used in VoiceEngine"); 346 } 347 348 // Register the ADM to the process thread, which will drive the error 349 // callback mechanism 350 if (_shared->process_thread() && 351 _shared->process_thread()->RegisterModule(_shared->audio_device()) != 0) 352 { 353 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError, 354 "Init() failed to register the ADM"); 355 return -1; 356 } 357 358 bool available(false); 359 360 // -------------------- 361 // Reinitialize the ADM 362 363 // Register the AudioObserver implementation 364 if (_shared->audio_device()->RegisterEventObserver(this) != 0) { 365 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning, 366 "Init() failed to register event observer for the ADM"); 367 } 368 369 // Register the AudioTransport implementation 370 if (_shared->audio_device()->RegisterAudioCallback(this) != 0) { 371 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning, 372 "Init() failed to register audio callback for the ADM"); 373 } 374 375 // ADM initialization 376 if (_shared->audio_device()->Init() != 0) 377 { 378 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError, 379 "Init() failed to initialize the ADM"); 380 return -1; 381 } 382 383 // Initialize the default speaker 384 if (_shared->audio_device()->SetPlayoutDevice( 385 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) 386 { 387 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceInfo, 388 "Init() failed to set the default output device"); 389 } 390 if (_shared->audio_device()->InitSpeaker() != 0) 391 { 392 _shared->SetLastError(VE_CANNOT_ACCESS_SPEAKER_VOL, kTraceInfo, 393 "Init() failed to initialize the speaker"); 394 } 395 396 // Initialize the default microphone 397 if (_shared->audio_device()->SetRecordingDevice( 398 WEBRTC_VOICE_ENGINE_DEFAULT_DEVICE) != 0) 399 { 400 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceInfo, 401 "Init() failed to set the default input device"); 402 } 403 if (_shared->audio_device()->InitMicrophone() != 0) 404 { 405 _shared->SetLastError(VE_CANNOT_ACCESS_MIC_VOL, kTraceInfo, 406 "Init() failed to initialize the microphone"); 407 } 408 409 // Set number of channels 410 if (_shared->audio_device()->StereoPlayoutIsAvailable(&available) != 0) { 411 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning, 412 "Init() failed to query stereo playout mode"); 413 } 414 if (_shared->audio_device()->SetStereoPlayout(available) != 0) 415 { 416 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning, 417 "Init() failed to set mono/stereo playout mode"); 418 } 419 420 // TODO(andrew): These functions don't tell us whether stereo recording 421 // is truly available. We simply set the AudioProcessing input to stereo 422 // here, because we have to wait until receiving the first frame to 423 // determine the actual number of channels anyway. 424 // 425 // These functions may be changed; tracked here: 426 // http://code.google.com/p/webrtc/issues/detail?id=204 427 _shared->audio_device()->StereoRecordingIsAvailable(&available); 428 if (_shared->audio_device()->SetStereoRecording(available) != 0) 429 { 430 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning, 431 "Init() failed to set mono/stereo recording mode"); 432 } 433 434 if (!audioproc) { 435 audioproc = AudioProcessing::Create(VoEId(_shared->instance_id(), -1)); 436 if (!audioproc) { 437 LOG(LS_ERROR) << "Failed to create AudioProcessing."; 438 _shared->SetLastError(VE_NO_MEMORY); 439 return -1; 440 } 441 } 442 _shared->set_audio_processing(audioproc); 443 444 // Set the error state for any failures in this block. 445 _shared->SetLastError(VE_APM_ERROR); 446 // Configure AudioProcessing components. 447 if (audioproc->high_pass_filter()->Enable(true) != 0) { 448 LOG_FERR1(LS_ERROR, high_pass_filter()->Enable, true); 449 return -1; 450 } 451 if (audioproc->echo_cancellation()->enable_drift_compensation(false) != 0) { 452 LOG_FERR1(LS_ERROR, enable_drift_compensation, false); 453 return -1; 454 } 455 if (audioproc->noise_suppression()->set_level(kDefaultNsMode) != 0) { 456 LOG_FERR1(LS_ERROR, noise_suppression()->set_level, kDefaultNsMode); 457 return -1; 458 } 459 GainControl* agc = audioproc->gain_control(); 460 if (agc->set_analog_level_limits(kMinVolumeLevel, kMaxVolumeLevel) != 0) { 461 LOG_FERR2(LS_ERROR, agc->set_analog_level_limits, kMinVolumeLevel, 462 kMaxVolumeLevel); 463 return -1; 464 } 465 if (agc->set_mode(kDefaultAgcMode) != 0) { 466 LOG_FERR1(LS_ERROR, agc->set_mode, kDefaultAgcMode); 467 return -1; 468 } 469 if (agc->Enable(kDefaultAgcState) != 0) { 470 LOG_FERR1(LS_ERROR, agc->Enable, kDefaultAgcState); 471 return -1; 472 } 473 _shared->SetLastError(0); // Clear error state. 474 475 #ifdef WEBRTC_VOICE_ENGINE_AGC 476 bool agc_enabled = agc->mode() == GainControl::kAdaptiveAnalog && 477 agc->is_enabled(); 478 if (_shared->audio_device()->SetAGC(agc_enabled) != 0) { 479 LOG_FERR1(LS_ERROR, audio_device()->SetAGC, agc_enabled); 480 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR); 481 // TODO(ajm): No error return here due to 482 // https://code.google.com/p/webrtc/issues/detail?id=1464 483 } 484 #endif 485 486 return _shared->statistics().SetInitialized(); 487 } 488 489 int VoEBaseImpl::Terminate() 490 { 491 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 492 "Terminate()"); 493 CriticalSectionScoped cs(_shared->crit_sec()); 494 return TerminateInternal(); 495 } 496 497 int VoEBaseImpl::CreateChannel() { 498 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 499 "CreateChannel()"); 500 CriticalSectionScoped cs(_shared->crit_sec()); 501 if (!_shared->statistics().Initialized()) { 502 _shared->SetLastError(VE_NOT_INITED, kTraceError); 503 return -1; 504 } 505 506 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel(); 507 508 return InitializeChannel(&channel_owner); 509 } 510 511 int VoEBaseImpl::CreateChannel(const Config& config) { 512 CriticalSectionScoped cs(_shared->crit_sec()); 513 if (!_shared->statistics().Initialized()) { 514 _shared->SetLastError(VE_NOT_INITED, kTraceError); 515 return -1; 516 } 517 voe::ChannelOwner channel_owner = _shared->channel_manager().CreateChannel( 518 config); 519 return InitializeChannel(&channel_owner); 520 } 521 522 int VoEBaseImpl::InitializeChannel(voe::ChannelOwner* channel_owner) 523 { 524 if (channel_owner->channel()->SetEngineInformation( 525 _shared->statistics(), 526 *_shared->output_mixer(), 527 *_shared->transmit_mixer(), 528 *_shared->process_thread(), 529 *_shared->audio_device(), 530 _voiceEngineObserverPtr, 531 &_callbackCritSect) != 0) { 532 _shared->SetLastError( 533 VE_CHANNEL_NOT_CREATED, 534 kTraceError, 535 "CreateChannel() failed to associate engine and channel." 536 " Destroying channel."); 537 _shared->channel_manager() 538 .DestroyChannel(channel_owner->channel()->ChannelId()); 539 return -1; 540 } else if (channel_owner->channel()->Init() != 0) { 541 _shared->SetLastError( 542 VE_CHANNEL_NOT_CREATED, 543 kTraceError, 544 "CreateChannel() failed to initialize channel. Destroying" 545 " channel."); 546 _shared->channel_manager() 547 .DestroyChannel(channel_owner->channel()->ChannelId()); 548 return -1; 549 } 550 551 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, 552 VoEId(_shared->instance_id(), -1), 553 "CreateChannel() => %d", channel_owner->channel()->ChannelId()); 554 return channel_owner->channel()->ChannelId(); 555 } 556 557 int VoEBaseImpl::DeleteChannel(int channel) 558 { 559 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 560 "DeleteChannel(channel=%d)", channel); 561 CriticalSectionScoped cs(_shared->crit_sec()); 562 563 if (!_shared->statistics().Initialized()) 564 { 565 _shared->SetLastError(VE_NOT_INITED, kTraceError); 566 return -1; 567 } 568 569 { 570 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 571 voe::Channel* channelPtr = ch.channel(); 572 if (channelPtr == NULL) 573 { 574 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 575 "DeleteChannel() failed to locate channel"); 576 return -1; 577 } 578 } 579 580 _shared->channel_manager().DestroyChannel(channel); 581 582 if (StopSend() != 0) 583 { 584 return -1; 585 } 586 587 if (StopPlayout() != 0) 588 { 589 return -1; 590 } 591 592 return 0; 593 } 594 595 int VoEBaseImpl::StartReceive(int channel) 596 { 597 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 598 "StartReceive(channel=%d)", channel); 599 CriticalSectionScoped cs(_shared->crit_sec()); 600 if (!_shared->statistics().Initialized()) 601 { 602 _shared->SetLastError(VE_NOT_INITED, kTraceError); 603 return -1; 604 } 605 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 606 voe::Channel* channelPtr = ch.channel(); 607 if (channelPtr == NULL) 608 { 609 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 610 "StartReceive() failed to locate channel"); 611 return -1; 612 } 613 return channelPtr->StartReceiving(); 614 } 615 616 int VoEBaseImpl::StopReceive(int channel) 617 { 618 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 619 "StopListen(channel=%d)", channel); 620 CriticalSectionScoped cs(_shared->crit_sec()); 621 if (!_shared->statistics().Initialized()) 622 { 623 _shared->SetLastError(VE_NOT_INITED, kTraceError); 624 return -1; 625 } 626 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 627 voe::Channel* channelPtr = ch.channel(); 628 if (channelPtr == NULL) 629 { 630 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 631 "SetLocalReceiver() failed to locate channel"); 632 return -1; 633 } 634 return channelPtr->StopReceiving(); 635 } 636 637 int VoEBaseImpl::StartPlayout(int channel) 638 { 639 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 640 "StartPlayout(channel=%d)", channel); 641 CriticalSectionScoped cs(_shared->crit_sec()); 642 if (!_shared->statistics().Initialized()) 643 { 644 _shared->SetLastError(VE_NOT_INITED, kTraceError); 645 return -1; 646 } 647 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 648 voe::Channel* channelPtr = ch.channel(); 649 if (channelPtr == NULL) 650 { 651 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 652 "StartPlayout() failed to locate channel"); 653 return -1; 654 } 655 if (channelPtr->Playing()) 656 { 657 return 0; 658 } 659 if (StartPlayout() != 0) 660 { 661 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError, 662 "StartPlayout() failed to start playout"); 663 return -1; 664 } 665 return channelPtr->StartPlayout(); 666 } 667 668 int VoEBaseImpl::StopPlayout(int channel) 669 { 670 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 671 "StopPlayout(channel=%d)", channel); 672 CriticalSectionScoped cs(_shared->crit_sec()); 673 if (!_shared->statistics().Initialized()) 674 { 675 _shared->SetLastError(VE_NOT_INITED, kTraceError); 676 return -1; 677 } 678 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 679 voe::Channel* channelPtr = ch.channel(); 680 if (channelPtr == NULL) 681 { 682 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 683 "StopPlayout() failed to locate channel"); 684 return -1; 685 } 686 if (channelPtr->StopPlayout() != 0) 687 { 688 WEBRTC_TRACE(kTraceWarning, kTraceVoice, 689 VoEId(_shared->instance_id(), -1), 690 "StopPlayout() failed to stop playout for channel %d", channel); 691 } 692 return StopPlayout(); 693 } 694 695 int VoEBaseImpl::StartSend(int channel) 696 { 697 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 698 "StartSend(channel=%d)", channel); 699 CriticalSectionScoped cs(_shared->crit_sec()); 700 if (!_shared->statistics().Initialized()) 701 { 702 _shared->SetLastError(VE_NOT_INITED, kTraceError); 703 return -1; 704 } 705 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 706 voe::Channel* channelPtr = ch.channel(); 707 if (channelPtr == NULL) 708 { 709 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 710 "StartSend() failed to locate channel"); 711 return -1; 712 } 713 if (channelPtr->Sending()) 714 { 715 return 0; 716 } 717 if (StartSend() != 0) 718 { 719 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError, 720 "StartSend() failed to start recording"); 721 return -1; 722 } 723 return channelPtr->StartSend(); 724 } 725 726 int VoEBaseImpl::StopSend(int channel) 727 { 728 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 729 "StopSend(channel=%d)", channel); 730 CriticalSectionScoped cs(_shared->crit_sec()); 731 if (!_shared->statistics().Initialized()) 732 { 733 _shared->SetLastError(VE_NOT_INITED, kTraceError); 734 return -1; 735 } 736 voe::ChannelOwner ch = _shared->channel_manager().GetChannel(channel); 737 voe::Channel* channelPtr = ch.channel(); 738 if (channelPtr == NULL) 739 { 740 _shared->SetLastError(VE_CHANNEL_NOT_VALID, kTraceError, 741 "StopSend() failed to locate channel"); 742 return -1; 743 } 744 if (channelPtr->StopSend() != 0) 745 { 746 WEBRTC_TRACE(kTraceWarning, kTraceVoice, 747 VoEId(_shared->instance_id(), -1), 748 "StopSend() failed to stop sending for channel %d", channel); 749 } 750 return StopSend(); 751 } 752 753 int VoEBaseImpl::GetVersion(char version[1024]) 754 { 755 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 756 "GetVersion(version=?)"); 757 assert(kVoiceEngineVersionMaxMessageSize == 1024); 758 759 if (version == NULL) 760 { 761 _shared->SetLastError(VE_INVALID_ARGUMENT, kTraceError); 762 return (-1); 763 } 764 765 char versionBuf[kVoiceEngineVersionMaxMessageSize]; 766 char* versionPtr = versionBuf; 767 768 int32_t len = 0; 769 int32_t accLen = 0; 770 771 len = AddVoEVersion(versionPtr); 772 if (len == -1) 773 { 774 return -1; 775 } 776 versionPtr += len; 777 accLen += len; 778 assert(accLen < kVoiceEngineVersionMaxMessageSize); 779 780 len = AddBuildInfo(versionPtr); 781 if (len == -1) 782 { 783 return -1; 784 } 785 versionPtr += len; 786 accLen += len; 787 assert(accLen < kVoiceEngineVersionMaxMessageSize); 788 789 #ifdef WEBRTC_EXTERNAL_TRANSPORT 790 len = AddExternalTransportBuild(versionPtr); 791 if (len == -1) 792 { 793 return -1; 794 } 795 versionPtr += len; 796 accLen += len; 797 assert(accLen < kVoiceEngineVersionMaxMessageSize); 798 #endif 799 800 memcpy(version, versionBuf, accLen); 801 version[accLen] = '\0'; 802 803 // to avoid the truncation in the trace, split the string into parts 804 char partOfVersion[256]; 805 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, 806 VoEId(_shared->instance_id(), -1), "GetVersion() =>"); 807 for (int partStart = 0; partStart < accLen;) 808 { 809 memset(partOfVersion, 0, sizeof(partOfVersion)); 810 int partEnd = partStart + 180; 811 while (version[partEnd] != '\n' && version[partEnd] != '\0') 812 { 813 partEnd--; 814 } 815 if (partEnd < accLen) 816 { 817 memcpy(partOfVersion, &version[partStart], partEnd - partStart); 818 } 819 else 820 { 821 memcpy(partOfVersion, &version[partStart], accLen - partStart); 822 } 823 partStart = partEnd; 824 WEBRTC_TRACE(kTraceStateInfo, kTraceVoice, 825 VoEId(_shared->instance_id(), -1), "%s", partOfVersion); 826 } 827 828 return 0; 829 } 830 831 int32_t VoEBaseImpl::AddBuildInfo(char* str) const 832 { 833 return sprintf(str, "Build: %s\n", BUILDINFO); 834 } 835 836 int32_t VoEBaseImpl::AddVoEVersion(char* str) const 837 { 838 return sprintf(str, "VoiceEngine 4.1.0\n"); 839 } 840 841 #ifdef WEBRTC_EXTERNAL_TRANSPORT 842 int32_t VoEBaseImpl::AddExternalTransportBuild(char* str) const 843 { 844 return sprintf(str, "External transport build\n"); 845 } 846 #endif 847 848 int VoEBaseImpl::LastError() 849 { 850 WEBRTC_TRACE(kTraceApiCall, kTraceVoice, VoEId(_shared->instance_id(), -1), 851 "LastError()"); 852 return (_shared->statistics().LastError()); 853 } 854 855 int32_t VoEBaseImpl::StartPlayout() 856 { 857 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), 858 "VoEBaseImpl::StartPlayout()"); 859 if (_shared->audio_device()->Playing()) 860 { 861 return 0; 862 } 863 if (!_shared->ext_playout()) 864 { 865 if (_shared->audio_device()->InitPlayout() != 0) 866 { 867 WEBRTC_TRACE(kTraceError, kTraceVoice, 868 VoEId(_shared->instance_id(), -1), 869 "StartPlayout() failed to initialize playout"); 870 return -1; 871 } 872 if (_shared->audio_device()->StartPlayout() != 0) 873 { 874 WEBRTC_TRACE(kTraceError, kTraceVoice, 875 VoEId(_shared->instance_id(), -1), 876 "StartPlayout() failed to start playout"); 877 return -1; 878 } 879 } 880 return 0; 881 } 882 883 int32_t VoEBaseImpl::StopPlayout() { 884 WEBRTC_TRACE(kTraceInfo, 885 kTraceVoice, 886 VoEId(_shared->instance_id(), -1), 887 "VoEBaseImpl::StopPlayout()"); 888 // Stop audio-device playing if no channel is playing out 889 if (_shared->NumOfPlayingChannels() == 0) { 890 if (_shared->audio_device()->StopPlayout() != 0) { 891 _shared->SetLastError(VE_CANNOT_STOP_PLAYOUT, 892 kTraceError, 893 "StopPlayout() failed to stop playout"); 894 return -1; 895 } 896 } 897 return 0; 898 } 899 900 int32_t VoEBaseImpl::StartSend() 901 { 902 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), 903 "VoEBaseImpl::StartSend()"); 904 if (_shared->audio_device()->Recording()) 905 { 906 return 0; 907 } 908 if (!_shared->ext_recording()) 909 { 910 if (_shared->audio_device()->InitRecording() != 0) 911 { 912 WEBRTC_TRACE(kTraceError, kTraceVoice, 913 VoEId(_shared->instance_id(), -1), 914 "StartSend() failed to initialize recording"); 915 return -1; 916 } 917 if (_shared->audio_device()->StartRecording() != 0) 918 { 919 WEBRTC_TRACE(kTraceError, kTraceVoice, 920 VoEId(_shared->instance_id(), -1), 921 "StartSend() failed to start recording"); 922 return -1; 923 } 924 } 925 926 return 0; 927 } 928 929 int32_t VoEBaseImpl::StopSend() 930 { 931 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), 932 "VoEBaseImpl::StopSend()"); 933 934 if (_shared->NumOfSendingChannels() == 0 && 935 !_shared->transmit_mixer()->IsRecordingMic()) 936 { 937 // Stop audio-device recording if no channel is recording 938 if (_shared->audio_device()->StopRecording() != 0) 939 { 940 _shared->SetLastError(VE_CANNOT_STOP_RECORDING, kTraceError, 941 "StopSend() failed to stop recording"); 942 return -1; 943 } 944 _shared->transmit_mixer()->StopSend(); 945 } 946 947 return 0; 948 } 949 950 int32_t VoEBaseImpl::TerminateInternal() 951 { 952 WEBRTC_TRACE(kTraceInfo, kTraceVoice, VoEId(_shared->instance_id(), -1), 953 "VoEBaseImpl::TerminateInternal()"); 954 955 // Delete any remaining channel objects 956 _shared->channel_manager().DestroyAllChannels(); 957 958 if (_shared->process_thread()) 959 { 960 if (_shared->audio_device()) 961 { 962 if (_shared->process_thread()-> 963 DeRegisterModule(_shared->audio_device()) != 0) 964 { 965 _shared->SetLastError(VE_THREAD_ERROR, kTraceError, 966 "TerminateInternal() failed to deregister ADM"); 967 } 968 } 969 if (_shared->process_thread()->Stop() != 0) 970 { 971 _shared->SetLastError(VE_THREAD_ERROR, kTraceError, 972 "TerminateInternal() failed to stop module process thread"); 973 } 974 } 975 976 if (_shared->audio_device()) 977 { 978 if (_shared->audio_device()->StopPlayout() != 0) 979 { 980 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning, 981 "TerminateInternal() failed to stop playout"); 982 } 983 if (_shared->audio_device()->StopRecording() != 0) 984 { 985 _shared->SetLastError(VE_SOUNDCARD_ERROR, kTraceWarning, 986 "TerminateInternal() failed to stop recording"); 987 } 988 if (_shared->audio_device()->RegisterEventObserver(NULL) != 0) { 989 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning, 990 "TerminateInternal() failed to de-register event observer " 991 "for the ADM"); 992 } 993 if (_shared->audio_device()->RegisterAudioCallback(NULL) != 0) { 994 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceWarning, 995 "TerminateInternal() failed to de-register audio callback " 996 "for the ADM"); 997 } 998 if (_shared->audio_device()->Terminate() != 0) 999 { 1000 _shared->SetLastError(VE_AUDIO_DEVICE_MODULE_ERROR, kTraceError, 1001 "TerminateInternal() failed to terminate the ADM"); 1002 } 1003 _shared->set_audio_device(NULL); 1004 } 1005 1006 if (_shared->audio_processing()) { 1007 _shared->set_audio_processing(NULL); 1008 } 1009 1010 return _shared->statistics().SetUnInitialized(); 1011 } 1012 1013 int VoEBaseImpl::ProcessRecordedDataWithAPM( 1014 const int voe_channels[], 1015 int number_of_voe_channels, 1016 const void* audio_data, 1017 uint32_t sample_rate, 1018 uint8_t number_of_channels, 1019 uint32_t number_of_frames, 1020 uint32_t audio_delay_milliseconds, 1021 int32_t clock_drift, 1022 uint32_t volume, 1023 bool key_pressed) { 1024 assert(_shared->transmit_mixer() != NULL); 1025 assert(_shared->audio_device() != NULL); 1026 1027 uint32_t max_volume = 0; 1028 uint16_t voe_mic_level = 0; 1029 // Check for zero to skip this calculation; the consumer may use this to 1030 // indicate no volume is available. 1031 if (volume != 0) { 1032 // Scale from ADM to VoE level range 1033 if (_shared->audio_device()->MaxMicrophoneVolume(&max_volume) == 0) { 1034 if (max_volume) { 1035 voe_mic_level = static_cast<uint16_t>( 1036 (volume * kMaxVolumeLevel + 1037 static_cast<int>(max_volume / 2)) / max_volume); 1038 } 1039 } 1040 // We learned that on certain systems (e.g Linux) the voe_mic_level 1041 // can be greater than the maxVolumeLevel therefore 1042 // we are going to cap the voe_mic_level to the maxVolumeLevel 1043 // and change the maxVolume to volume if it turns out that 1044 // the voe_mic_level is indeed greater than the maxVolumeLevel. 1045 if (voe_mic_level > kMaxVolumeLevel) { 1046 voe_mic_level = kMaxVolumeLevel; 1047 max_volume = volume; 1048 } 1049 } 1050 1051 // Perform channel-independent operations 1052 // (APM, mix with file, record to file, mute, etc.) 1053 _shared->transmit_mixer()->PrepareDemux( 1054 audio_data, number_of_frames, number_of_channels, sample_rate, 1055 static_cast<uint16_t>(audio_delay_milliseconds), clock_drift, 1056 voe_mic_level, key_pressed); 1057 1058 // Copy the audio frame to each sending channel and perform 1059 // channel-dependent operations (file mixing, mute, etc.), encode and 1060 // packetize+transmit the RTP packet. When |number_of_voe_channels| == 0, 1061 // do the operations on all the existing VoE channels; otherwise the 1062 // operations will be done on specific channels. 1063 if (number_of_voe_channels == 0) { 1064 _shared->transmit_mixer()->DemuxAndMix(); 1065 _shared->transmit_mixer()->EncodeAndSend(); 1066 } else { 1067 _shared->transmit_mixer()->DemuxAndMix(voe_channels, 1068 number_of_voe_channels); 1069 _shared->transmit_mixer()->EncodeAndSend(voe_channels, 1070 number_of_voe_channels); 1071 } 1072 1073 // Scale from VoE to ADM level range. 1074 uint32_t new_voe_mic_level = _shared->transmit_mixer()->CaptureLevel(); 1075 1076 if (new_voe_mic_level != voe_mic_level) { 1077 // Return the new volume if AGC has changed the volume. 1078 return static_cast<int>( 1079 (new_voe_mic_level * max_volume + 1080 static_cast<int>(kMaxVolumeLevel / 2)) / kMaxVolumeLevel); 1081 } 1082 1083 // Return 0 to indicate no change on the volume. 1084 return 0; 1085 } 1086 1087 void VoEBaseImpl::GetPlayoutData(int sample_rate, int number_of_channels, 1088 int number_of_frames, bool feed_data_to_apm, 1089 void* audio_data, 1090 int64_t* elapsed_time_ms, 1091 int64_t* ntp_time_ms) { 1092 assert(_shared->output_mixer() != NULL); 1093 1094 // TODO(andrew): if the device is running in mono, we should tell the mixer 1095 // here so that it will only request mono from AudioCodingModule. 1096 // Perform mixing of all active participants (channel-based mixing) 1097 _shared->output_mixer()->MixActiveChannels(); 1098 1099 // Additional operations on the combined signal 1100 _shared->output_mixer()->DoOperationsOnCombinedSignal(feed_data_to_apm); 1101 1102 // Retrieve the final output mix (resampled to match the ADM) 1103 _shared->output_mixer()->GetMixedAudio(sample_rate, number_of_channels, 1104 &_audioFrame); 1105 1106 assert(number_of_frames == _audioFrame.samples_per_channel_); 1107 assert(sample_rate == _audioFrame.sample_rate_hz_); 1108 1109 // Deliver audio (PCM) samples to the ADM 1110 memcpy(audio_data, _audioFrame.data_, 1111 sizeof(int16_t) * number_of_frames * number_of_channels); 1112 1113 *elapsed_time_ms = _audioFrame.elapsed_time_ms_; 1114 *ntp_time_ms = _audioFrame.ntp_time_ms_; 1115 } 1116 1117 } // namespace webrtc 1118