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