1 /* 2 * libjingle 3 * Copyright 2012 Google Inc. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions are met: 7 * 8 * 1. Redistributions of source code must retain the above copyright notice, 9 * this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright notice, 11 * this list of conditions and the following disclaimer in the documentation 12 * and/or other materials provided with the distribution. 13 * 3. The name of the author may not be used to endorse or promote products 14 * derived from this software without specific prior written permission. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED 17 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 18 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO 19 * EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 21 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; 22 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 23 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 25 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include "talk/app/webrtc/test/fakeaudiocapturemodule.h" 29 30 #include "webrtc/base/common.h" 31 #include "webrtc/base/refcount.h" 32 #include "webrtc/base/thread.h" 33 #include "webrtc/base/timeutils.h" 34 35 // Audio sample value that is high enough that it doesn't occur naturally when 36 // frames are being faked. E.g. NetEq will not generate this large sample value 37 // unless it has received an audio frame containing a sample of this value. 38 // Even simpler buffers would likely just contain audio sample values of 0. 39 static const int kHighSampleValue = 10000; 40 41 // Same value as src/modules/audio_device/main/source/audio_device_config.h in 42 // https://code.google.com/p/webrtc/ 43 static const uint32_t kAdmMaxIdleTimeProcess = 1000; 44 45 // Constants here are derived by running VoE using a real ADM. 46 // The constants correspond to 10ms of mono audio at 44kHz. 47 static const int kTimePerFrameMs = 10; 48 static const uint8_t kNumberOfChannels = 1; 49 static const int kSamplesPerSecond = 44000; 50 static const int kTotalDelayMs = 0; 51 static const int kClockDriftMs = 0; 52 static const uint32_t kMaxVolume = 14392; 53 54 enum { 55 MSG_START_PROCESS, 56 MSG_RUN_PROCESS, 57 }; 58 59 FakeAudioCaptureModule::FakeAudioCaptureModule() 60 : last_process_time_ms_(0), 61 audio_callback_(nullptr), 62 recording_(false), 63 playing_(false), 64 play_is_initialized_(false), 65 rec_is_initialized_(false), 66 current_mic_level_(kMaxVolume), 67 started_(false), 68 next_frame_time_(0), 69 frames_received_(0) { 70 } 71 72 FakeAudioCaptureModule::~FakeAudioCaptureModule() { 73 if (process_thread_) { 74 process_thread_->Stop(); 75 } 76 } 77 78 rtc::scoped_refptr<FakeAudioCaptureModule> FakeAudioCaptureModule::Create() { 79 rtc::scoped_refptr<FakeAudioCaptureModule> capture_module( 80 new rtc::RefCountedObject<FakeAudioCaptureModule>()); 81 if (!capture_module->Initialize()) { 82 return nullptr; 83 } 84 return capture_module; 85 } 86 87 int FakeAudioCaptureModule::frames_received() const { 88 rtc::CritScope cs(&crit_); 89 return frames_received_; 90 } 91 92 int64_t FakeAudioCaptureModule::TimeUntilNextProcess() { 93 const uint32_t current_time = rtc::Time(); 94 if (current_time < last_process_time_ms_) { 95 // TODO: wraparound could be handled more gracefully. 96 return 0; 97 } 98 const uint32_t elapsed_time = current_time - last_process_time_ms_; 99 if (kAdmMaxIdleTimeProcess < elapsed_time) { 100 return 0; 101 } 102 return kAdmMaxIdleTimeProcess - elapsed_time; 103 } 104 105 int32_t FakeAudioCaptureModule::Process() { 106 last_process_time_ms_ = rtc::Time(); 107 return 0; 108 } 109 110 int32_t FakeAudioCaptureModule::ActiveAudioLayer( 111 AudioLayer* /*audio_layer*/) const { 112 ASSERT(false); 113 return 0; 114 } 115 116 webrtc::AudioDeviceModule::ErrorCode FakeAudioCaptureModule::LastError() const { 117 ASSERT(false); 118 return webrtc::AudioDeviceModule::kAdmErrNone; 119 } 120 121 int32_t FakeAudioCaptureModule::RegisterEventObserver( 122 webrtc::AudioDeviceObserver* /*event_callback*/) { 123 // Only used to report warnings and errors. This fake implementation won't 124 // generate any so discard this callback. 125 return 0; 126 } 127 128 int32_t FakeAudioCaptureModule::RegisterAudioCallback( 129 webrtc::AudioTransport* audio_callback) { 130 rtc::CritScope cs(&crit_callback_); 131 audio_callback_ = audio_callback; 132 return 0; 133 } 134 135 int32_t FakeAudioCaptureModule::Init() { 136 // Initialize is called by the factory method. Safe to ignore this Init call. 137 return 0; 138 } 139 140 int32_t FakeAudioCaptureModule::Terminate() { 141 // Clean up in the destructor. No action here, just success. 142 return 0; 143 } 144 145 bool FakeAudioCaptureModule::Initialized() const { 146 ASSERT(false); 147 return 0; 148 } 149 150 int16_t FakeAudioCaptureModule::PlayoutDevices() { 151 ASSERT(false); 152 return 0; 153 } 154 155 int16_t FakeAudioCaptureModule::RecordingDevices() { 156 ASSERT(false); 157 return 0; 158 } 159 160 int32_t FakeAudioCaptureModule::PlayoutDeviceName( 161 uint16_t /*index*/, 162 char /*name*/[webrtc::kAdmMaxDeviceNameSize], 163 char /*guid*/[webrtc::kAdmMaxGuidSize]) { 164 ASSERT(false); 165 return 0; 166 } 167 168 int32_t FakeAudioCaptureModule::RecordingDeviceName( 169 uint16_t /*index*/, 170 char /*name*/[webrtc::kAdmMaxDeviceNameSize], 171 char /*guid*/[webrtc::kAdmMaxGuidSize]) { 172 ASSERT(false); 173 return 0; 174 } 175 176 int32_t FakeAudioCaptureModule::SetPlayoutDevice(uint16_t /*index*/) { 177 // No playout device, just playing from file. Return success. 178 return 0; 179 } 180 181 int32_t FakeAudioCaptureModule::SetPlayoutDevice(WindowsDeviceType /*device*/) { 182 if (play_is_initialized_) { 183 return -1; 184 } 185 return 0; 186 } 187 188 int32_t FakeAudioCaptureModule::SetRecordingDevice(uint16_t /*index*/) { 189 // No recording device, just dropping audio. Return success. 190 return 0; 191 } 192 193 int32_t FakeAudioCaptureModule::SetRecordingDevice( 194 WindowsDeviceType /*device*/) { 195 if (rec_is_initialized_) { 196 return -1; 197 } 198 return 0; 199 } 200 201 int32_t FakeAudioCaptureModule::PlayoutIsAvailable(bool* /*available*/) { 202 ASSERT(false); 203 return 0; 204 } 205 206 int32_t FakeAudioCaptureModule::InitPlayout() { 207 play_is_initialized_ = true; 208 return 0; 209 } 210 211 bool FakeAudioCaptureModule::PlayoutIsInitialized() const { 212 return play_is_initialized_; 213 } 214 215 int32_t FakeAudioCaptureModule::RecordingIsAvailable(bool* /*available*/) { 216 ASSERT(false); 217 return 0; 218 } 219 220 int32_t FakeAudioCaptureModule::InitRecording() { 221 rec_is_initialized_ = true; 222 return 0; 223 } 224 225 bool FakeAudioCaptureModule::RecordingIsInitialized() const { 226 ASSERT(false); 227 return 0; 228 } 229 230 int32_t FakeAudioCaptureModule::StartPlayout() { 231 if (!play_is_initialized_) { 232 return -1; 233 } 234 { 235 rtc::CritScope cs(&crit_); 236 playing_ = true; 237 } 238 bool start = true; 239 UpdateProcessing(start); 240 return 0; 241 } 242 243 int32_t FakeAudioCaptureModule::StopPlayout() { 244 bool start = false; 245 { 246 rtc::CritScope cs(&crit_); 247 playing_ = false; 248 start = ShouldStartProcessing(); 249 } 250 UpdateProcessing(start); 251 return 0; 252 } 253 254 bool FakeAudioCaptureModule::Playing() const { 255 rtc::CritScope cs(&crit_); 256 return playing_; 257 } 258 259 int32_t FakeAudioCaptureModule::StartRecording() { 260 if (!rec_is_initialized_) { 261 return -1; 262 } 263 { 264 rtc::CritScope cs(&crit_); 265 recording_ = true; 266 } 267 bool start = true; 268 UpdateProcessing(start); 269 return 0; 270 } 271 272 int32_t FakeAudioCaptureModule::StopRecording() { 273 bool start = false; 274 { 275 rtc::CritScope cs(&crit_); 276 recording_ = false; 277 start = ShouldStartProcessing(); 278 } 279 UpdateProcessing(start); 280 return 0; 281 } 282 283 bool FakeAudioCaptureModule::Recording() const { 284 rtc::CritScope cs(&crit_); 285 return recording_; 286 } 287 288 int32_t FakeAudioCaptureModule::SetAGC(bool /*enable*/) { 289 // No AGC but not needed since audio is pregenerated. Return success. 290 return 0; 291 } 292 293 bool FakeAudioCaptureModule::AGC() const { 294 ASSERT(false); 295 return 0; 296 } 297 298 int32_t FakeAudioCaptureModule::SetWaveOutVolume(uint16_t /*volume_left*/, 299 uint16_t /*volume_right*/) { 300 ASSERT(false); 301 return 0; 302 } 303 304 int32_t FakeAudioCaptureModule::WaveOutVolume( 305 uint16_t* /*volume_left*/, 306 uint16_t* /*volume_right*/) const { 307 ASSERT(false); 308 return 0; 309 } 310 311 int32_t FakeAudioCaptureModule::InitSpeaker() { 312 // No speaker, just playing from file. Return success. 313 return 0; 314 } 315 316 bool FakeAudioCaptureModule::SpeakerIsInitialized() const { 317 ASSERT(false); 318 return 0; 319 } 320 321 int32_t FakeAudioCaptureModule::InitMicrophone() { 322 // No microphone, just playing from file. Return success. 323 return 0; 324 } 325 326 bool FakeAudioCaptureModule::MicrophoneIsInitialized() const { 327 ASSERT(false); 328 return 0; 329 } 330 331 int32_t FakeAudioCaptureModule::SpeakerVolumeIsAvailable(bool* /*available*/) { 332 ASSERT(false); 333 return 0; 334 } 335 336 int32_t FakeAudioCaptureModule::SetSpeakerVolume(uint32_t /*volume*/) { 337 ASSERT(false); 338 return 0; 339 } 340 341 int32_t FakeAudioCaptureModule::SpeakerVolume(uint32_t* /*volume*/) const { 342 ASSERT(false); 343 return 0; 344 } 345 346 int32_t FakeAudioCaptureModule::MaxSpeakerVolume( 347 uint32_t* /*max_volume*/) const { 348 ASSERT(false); 349 return 0; 350 } 351 352 int32_t FakeAudioCaptureModule::MinSpeakerVolume( 353 uint32_t* /*min_volume*/) const { 354 ASSERT(false); 355 return 0; 356 } 357 358 int32_t FakeAudioCaptureModule::SpeakerVolumeStepSize( 359 uint16_t* /*step_size*/) const { 360 ASSERT(false); 361 return 0; 362 } 363 364 int32_t FakeAudioCaptureModule::MicrophoneVolumeIsAvailable( 365 bool* /*available*/) { 366 ASSERT(false); 367 return 0; 368 } 369 370 int32_t FakeAudioCaptureModule::SetMicrophoneVolume(uint32_t volume) { 371 rtc::CritScope cs(&crit_); 372 current_mic_level_ = volume; 373 return 0; 374 } 375 376 int32_t FakeAudioCaptureModule::MicrophoneVolume(uint32_t* volume) const { 377 rtc::CritScope cs(&crit_); 378 *volume = current_mic_level_; 379 return 0; 380 } 381 382 int32_t FakeAudioCaptureModule::MaxMicrophoneVolume( 383 uint32_t* max_volume) const { 384 *max_volume = kMaxVolume; 385 return 0; 386 } 387 388 int32_t FakeAudioCaptureModule::MinMicrophoneVolume( 389 uint32_t* /*min_volume*/) const { 390 ASSERT(false); 391 return 0; 392 } 393 394 int32_t FakeAudioCaptureModule::MicrophoneVolumeStepSize( 395 uint16_t* /*step_size*/) const { 396 ASSERT(false); 397 return 0; 398 } 399 400 int32_t FakeAudioCaptureModule::SpeakerMuteIsAvailable(bool* /*available*/) { 401 ASSERT(false); 402 return 0; 403 } 404 405 int32_t FakeAudioCaptureModule::SetSpeakerMute(bool /*enable*/) { 406 ASSERT(false); 407 return 0; 408 } 409 410 int32_t FakeAudioCaptureModule::SpeakerMute(bool* /*enabled*/) const { 411 ASSERT(false); 412 return 0; 413 } 414 415 int32_t FakeAudioCaptureModule::MicrophoneMuteIsAvailable(bool* /*available*/) { 416 ASSERT(false); 417 return 0; 418 } 419 420 int32_t FakeAudioCaptureModule::SetMicrophoneMute(bool /*enable*/) { 421 ASSERT(false); 422 return 0; 423 } 424 425 int32_t FakeAudioCaptureModule::MicrophoneMute(bool* /*enabled*/) const { 426 ASSERT(false); 427 return 0; 428 } 429 430 int32_t FakeAudioCaptureModule::MicrophoneBoostIsAvailable( 431 bool* /*available*/) { 432 ASSERT(false); 433 return 0; 434 } 435 436 int32_t FakeAudioCaptureModule::SetMicrophoneBoost(bool /*enable*/) { 437 ASSERT(false); 438 return 0; 439 } 440 441 int32_t FakeAudioCaptureModule::MicrophoneBoost(bool* /*enabled*/) const { 442 ASSERT(false); 443 return 0; 444 } 445 446 int32_t FakeAudioCaptureModule::StereoPlayoutIsAvailable( 447 bool* available) const { 448 // No recording device, just dropping audio. Stereo can be dropped just 449 // as easily as mono. 450 *available = true; 451 return 0; 452 } 453 454 int32_t FakeAudioCaptureModule::SetStereoPlayout(bool /*enable*/) { 455 // No recording device, just dropping audio. Stereo can be dropped just 456 // as easily as mono. 457 return 0; 458 } 459 460 int32_t FakeAudioCaptureModule::StereoPlayout(bool* /*enabled*/) const { 461 ASSERT(false); 462 return 0; 463 } 464 465 int32_t FakeAudioCaptureModule::StereoRecordingIsAvailable( 466 bool* available) const { 467 // Keep thing simple. No stereo recording. 468 *available = false; 469 return 0; 470 } 471 472 int32_t FakeAudioCaptureModule::SetStereoRecording(bool enable) { 473 if (!enable) { 474 return 0; 475 } 476 return -1; 477 } 478 479 int32_t FakeAudioCaptureModule::StereoRecording(bool* /*enabled*/) const { 480 ASSERT(false); 481 return 0; 482 } 483 484 int32_t FakeAudioCaptureModule::SetRecordingChannel( 485 const ChannelType channel) { 486 if (channel != AudioDeviceModule::kChannelBoth) { 487 // There is no right or left in mono. I.e. kChannelBoth should be used for 488 // mono. 489 ASSERT(false); 490 return -1; 491 } 492 return 0; 493 } 494 495 int32_t FakeAudioCaptureModule::RecordingChannel(ChannelType* channel) const { 496 // Stereo recording not supported. However, WebRTC ADM returns kChannelBoth 497 // in that case. Do the same here. 498 *channel = AudioDeviceModule::kChannelBoth; 499 return 0; 500 } 501 502 int32_t FakeAudioCaptureModule::SetPlayoutBuffer(const BufferType /*type*/, 503 uint16_t /*size_ms*/) { 504 ASSERT(false); 505 return 0; 506 } 507 508 int32_t FakeAudioCaptureModule::PlayoutBuffer(BufferType* /*type*/, 509 uint16_t* /*size_ms*/) const { 510 ASSERT(false); 511 return 0; 512 } 513 514 int32_t FakeAudioCaptureModule::PlayoutDelay(uint16_t* delay_ms) const { 515 // No delay since audio frames are dropped. 516 *delay_ms = 0; 517 return 0; 518 } 519 520 int32_t FakeAudioCaptureModule::RecordingDelay(uint16_t* /*delay_ms*/) const { 521 ASSERT(false); 522 return 0; 523 } 524 525 int32_t FakeAudioCaptureModule::CPULoad(uint16_t* /*load*/) const { 526 ASSERT(false); 527 return 0; 528 } 529 530 int32_t FakeAudioCaptureModule::StartRawOutputFileRecording( 531 const char /*pcm_file_name_utf8*/[webrtc::kAdmMaxFileNameSize]) { 532 ASSERT(false); 533 return 0; 534 } 535 536 int32_t FakeAudioCaptureModule::StopRawOutputFileRecording() { 537 ASSERT(false); 538 return 0; 539 } 540 541 int32_t FakeAudioCaptureModule::StartRawInputFileRecording( 542 const char /*pcm_file_name_utf8*/[webrtc::kAdmMaxFileNameSize]) { 543 ASSERT(false); 544 return 0; 545 } 546 547 int32_t FakeAudioCaptureModule::StopRawInputFileRecording() { 548 ASSERT(false); 549 return 0; 550 } 551 552 int32_t FakeAudioCaptureModule::SetRecordingSampleRate( 553 const uint32_t /*samples_per_sec*/) { 554 ASSERT(false); 555 return 0; 556 } 557 558 int32_t FakeAudioCaptureModule::RecordingSampleRate( 559 uint32_t* /*samples_per_sec*/) const { 560 ASSERT(false); 561 return 0; 562 } 563 564 int32_t FakeAudioCaptureModule::SetPlayoutSampleRate( 565 const uint32_t /*samples_per_sec*/) { 566 ASSERT(false); 567 return 0; 568 } 569 570 int32_t FakeAudioCaptureModule::PlayoutSampleRate( 571 uint32_t* /*samples_per_sec*/) const { 572 ASSERT(false); 573 return 0; 574 } 575 576 int32_t FakeAudioCaptureModule::ResetAudioDevice() { 577 ASSERT(false); 578 return 0; 579 } 580 581 int32_t FakeAudioCaptureModule::SetLoudspeakerStatus(bool /*enable*/) { 582 ASSERT(false); 583 return 0; 584 } 585 586 int32_t FakeAudioCaptureModule::GetLoudspeakerStatus(bool* /*enabled*/) const { 587 ASSERT(false); 588 return 0; 589 } 590 591 void FakeAudioCaptureModule::OnMessage(rtc::Message* msg) { 592 switch (msg->message_id) { 593 case MSG_START_PROCESS: 594 StartProcessP(); 595 break; 596 case MSG_RUN_PROCESS: 597 ProcessFrameP(); 598 break; 599 default: 600 // All existing messages should be caught. Getting here should never 601 // happen. 602 ASSERT(false); 603 } 604 } 605 606 bool FakeAudioCaptureModule::Initialize() { 607 // Set the send buffer samples high enough that it would not occur on the 608 // remote side unless a packet containing a sample of that magnitude has been 609 // sent to it. Note that the audio processing pipeline will likely distort the 610 // original signal. 611 SetSendBuffer(kHighSampleValue); 612 last_process_time_ms_ = rtc::Time(); 613 return true; 614 } 615 616 void FakeAudioCaptureModule::SetSendBuffer(int value) { 617 Sample* buffer_ptr = reinterpret_cast<Sample*>(send_buffer_); 618 const size_t buffer_size_in_samples = 619 sizeof(send_buffer_) / kNumberBytesPerSample; 620 for (size_t i = 0; i < buffer_size_in_samples; ++i) { 621 buffer_ptr[i] = value; 622 } 623 } 624 625 void FakeAudioCaptureModule::ResetRecBuffer() { 626 memset(rec_buffer_, 0, sizeof(rec_buffer_)); 627 } 628 629 bool FakeAudioCaptureModule::CheckRecBuffer(int value) { 630 const Sample* buffer_ptr = reinterpret_cast<const Sample*>(rec_buffer_); 631 const size_t buffer_size_in_samples = 632 sizeof(rec_buffer_) / kNumberBytesPerSample; 633 for (size_t i = 0; i < buffer_size_in_samples; ++i) { 634 if (buffer_ptr[i] >= value) return true; 635 } 636 return false; 637 } 638 639 bool FakeAudioCaptureModule::ShouldStartProcessing() { 640 return recording_ || playing_; 641 } 642 643 void FakeAudioCaptureModule::UpdateProcessing(bool start) { 644 if (start) { 645 if (!process_thread_) { 646 process_thread_.reset(new rtc::Thread()); 647 process_thread_->Start(); 648 } 649 process_thread_->Post(this, MSG_START_PROCESS); 650 } else { 651 if (process_thread_) { 652 process_thread_->Stop(); 653 process_thread_.reset(nullptr); 654 } 655 started_ = false; 656 } 657 } 658 659 void FakeAudioCaptureModule::StartProcessP() { 660 ASSERT(process_thread_->IsCurrent()); 661 if (started_) { 662 // Already started. 663 return; 664 } 665 ProcessFrameP(); 666 } 667 668 void FakeAudioCaptureModule::ProcessFrameP() { 669 ASSERT(process_thread_->IsCurrent()); 670 if (!started_) { 671 next_frame_time_ = rtc::Time(); 672 started_ = true; 673 } 674 675 { 676 rtc::CritScope cs(&crit_); 677 // Receive and send frames every kTimePerFrameMs. 678 if (playing_) { 679 ReceiveFrameP(); 680 } 681 if (recording_) { 682 SendFrameP(); 683 } 684 } 685 686 next_frame_time_ += kTimePerFrameMs; 687 const uint32_t current_time = rtc::Time(); 688 const uint32_t wait_time = 689 (next_frame_time_ > current_time) ? next_frame_time_ - current_time : 0; 690 process_thread_->PostDelayed(wait_time, this, MSG_RUN_PROCESS); 691 } 692 693 void FakeAudioCaptureModule::ReceiveFrameP() { 694 ASSERT(process_thread_->IsCurrent()); 695 { 696 rtc::CritScope cs(&crit_callback_); 697 if (!audio_callback_) { 698 return; 699 } 700 ResetRecBuffer(); 701 size_t nSamplesOut = 0; 702 int64_t elapsed_time_ms = 0; 703 int64_t ntp_time_ms = 0; 704 if (audio_callback_->NeedMorePlayData(kNumberSamples, kNumberBytesPerSample, 705 kNumberOfChannels, kSamplesPerSecond, 706 rec_buffer_, nSamplesOut, 707 &elapsed_time_ms, &ntp_time_ms) != 0) { 708 ASSERT(false); 709 } 710 ASSERT(nSamplesOut == kNumberSamples); 711 } 712 // The SetBuffer() function ensures that after decoding, the audio buffer 713 // should contain samples of similar magnitude (there is likely to be some 714 // distortion due to the audio pipeline). If one sample is detected to 715 // have the same or greater magnitude somewhere in the frame, an actual frame 716 // has been received from the remote side (i.e. faked frames are not being 717 // pulled). 718 if (CheckRecBuffer(kHighSampleValue)) { 719 rtc::CritScope cs(&crit_); 720 ++frames_received_; 721 } 722 } 723 724 void FakeAudioCaptureModule::SendFrameP() { 725 ASSERT(process_thread_->IsCurrent()); 726 rtc::CritScope cs(&crit_callback_); 727 if (!audio_callback_) { 728 return; 729 } 730 bool key_pressed = false; 731 uint32_t current_mic_level = 0; 732 MicrophoneVolume(¤t_mic_level); 733 if (audio_callback_->RecordedDataIsAvailable(send_buffer_, kNumberSamples, 734 kNumberBytesPerSample, 735 kNumberOfChannels, 736 kSamplesPerSecond, kTotalDelayMs, 737 kClockDriftMs, current_mic_level, 738 key_pressed, 739 current_mic_level) != 0) { 740 ASSERT(false); 741 } 742 SetMicrophoneVolume(current_mic_level); 743 } 744 745