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