|  | /* | 
|  | *  Copyright (c) 2013 The WebRTC project authors. All Rights Reserved. | 
|  | * | 
|  | *  Use of this source code is governed by a BSD-style license | 
|  | *  that can be found in the LICENSE file in the root of the source | 
|  | *  tree. An additional intellectual property rights grant can be found | 
|  | *  in the file PATENTS.  All contributing project authors may | 
|  | *  be found in the AUTHORS file in the root of the source tree. | 
|  | */ | 
|  |  | 
|  | #include "webrtc/test/fake_audio_device.h" | 
|  |  | 
|  | #include <algorithm> | 
|  |  | 
|  | #include "testing/gtest/include/gtest/gtest.h" | 
|  | #include "webrtc/modules/media_file/source/media_file_utility.h" | 
|  | #include "webrtc/system_wrappers/interface/clock.h" | 
|  | #include "webrtc/system_wrappers/interface/event_wrapper.h" | 
|  | #include "webrtc/system_wrappers/interface/file_wrapper.h" | 
|  | #include "webrtc/system_wrappers/interface/thread_wrapper.h" | 
|  |  | 
|  | namespace webrtc { | 
|  | namespace test { | 
|  |  | 
|  | FakeAudioDevice::FakeAudioDevice(Clock* clock, const std::string& filename) | 
|  | : audio_callback_(NULL), | 
|  | capturing_(false), | 
|  | captured_audio_(), | 
|  | playout_buffer_(), | 
|  | last_playout_ms_(-1), | 
|  | clock_(clock), | 
|  | tick_(EventTimerWrapper::Create()), | 
|  | file_utility_(new ModuleFileUtility(0)), | 
|  | input_stream_(FileWrapper::Create()) { | 
|  | memset(captured_audio_, 0, sizeof(captured_audio_)); | 
|  | memset(playout_buffer_, 0, sizeof(playout_buffer_)); | 
|  | // Open audio input file as read-only and looping. | 
|  | EXPECT_EQ(0, input_stream_->OpenFile(filename.c_str(), true, true)) | 
|  | << filename; | 
|  | } | 
|  |  | 
|  | FakeAudioDevice::~FakeAudioDevice() { | 
|  | Stop(); | 
|  |  | 
|  | if (thread_.get() != NULL) | 
|  | thread_->Stop(); | 
|  | } | 
|  |  | 
|  | int32_t FakeAudioDevice::Init() { | 
|  | rtc::CritScope cs(&lock_); | 
|  | if (file_utility_->InitPCMReading(*input_stream_.get()) != 0) | 
|  | return -1; | 
|  |  | 
|  | if (!tick_->StartTimer(true, 10)) | 
|  | return -1; | 
|  | thread_ = ThreadWrapper::CreateThread(FakeAudioDevice::Run, this, | 
|  | "FakeAudioDevice"); | 
|  | if (thread_.get() == NULL) | 
|  | return -1; | 
|  | if (!thread_->Start()) { | 
|  | thread_.reset(); | 
|  | return -1; | 
|  | } | 
|  | thread_->SetPriority(webrtc::kHighPriority); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | int32_t FakeAudioDevice::RegisterAudioCallback(AudioTransport* callback) { | 
|  | rtc::CritScope cs(&lock_); | 
|  | audio_callback_ = callback; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | bool FakeAudioDevice::Playing() const { | 
|  | rtc::CritScope cs(&lock_); | 
|  | return capturing_; | 
|  | } | 
|  |  | 
|  | int32_t FakeAudioDevice::PlayoutDelay(uint16_t* delay_ms) const { | 
|  | *delay_ms = 0; | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | bool FakeAudioDevice::Recording() const { | 
|  | rtc::CritScope cs(&lock_); | 
|  | return capturing_; | 
|  | } | 
|  |  | 
|  | bool FakeAudioDevice::Run(void* obj) { | 
|  | static_cast<FakeAudioDevice*>(obj)->CaptureAudio(); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void FakeAudioDevice::CaptureAudio() { | 
|  | { | 
|  | rtc::CritScope cs(&lock_); | 
|  | if (capturing_) { | 
|  | int bytes_read = file_utility_->ReadPCMData( | 
|  | *input_stream_.get(), captured_audio_, kBufferSizeBytes); | 
|  | if (bytes_read <= 0) | 
|  | return; | 
|  | int num_samples = bytes_read / 2;  // 2 bytes per sample. | 
|  | uint32_t new_mic_level; | 
|  | EXPECT_EQ(0, | 
|  | audio_callback_->RecordedDataIsAvailable(captured_audio_, | 
|  | num_samples, | 
|  | 2, | 
|  | 1, | 
|  | kFrequencyHz, | 
|  | 0, | 
|  | 0, | 
|  | 0, | 
|  | false, | 
|  | new_mic_level)); | 
|  | uint32_t samples_needed = kFrequencyHz / 100; | 
|  | int64_t now_ms = clock_->TimeInMilliseconds(); | 
|  | uint32_t time_since_last_playout_ms = now_ms - last_playout_ms_; | 
|  | if (last_playout_ms_ > 0 && time_since_last_playout_ms > 0) { | 
|  | samples_needed = std::min(kFrequencyHz / time_since_last_playout_ms, | 
|  | kBufferSizeBytes / 2); | 
|  | } | 
|  | uint32_t samples_out = 0; | 
|  | int64_t elapsed_time_ms = -1; | 
|  | int64_t ntp_time_ms = -1; | 
|  | EXPECT_EQ(0, | 
|  | audio_callback_->NeedMorePlayData(samples_needed, | 
|  | 2, | 
|  | 1, | 
|  | kFrequencyHz, | 
|  | playout_buffer_, | 
|  | samples_out, | 
|  | &elapsed_time_ms, | 
|  | &ntp_time_ms)); | 
|  | } | 
|  | } | 
|  | tick_->Wait(WEBRTC_EVENT_INFINITE); | 
|  | } | 
|  |  | 
|  | void FakeAudioDevice::Start() { | 
|  | rtc::CritScope cs(&lock_); | 
|  | capturing_ = true; | 
|  | } | 
|  |  | 
|  | void FakeAudioDevice::Stop() { | 
|  | rtc::CritScope cs(&lock_); | 
|  | capturing_ = false; | 
|  | } | 
|  | }  // namespace test | 
|  | }  // namespace webrtc |