test_audio_device_impl.cc (6197B)
1 /* 2 * Copyright (c) 2023 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 #include "modules/audio_device/test_audio_device_impl.h" 11 12 #include <cstddef> 13 #include <cstdint> 14 #include <memory> 15 #include <optional> 16 #include <utility> 17 18 #include "api/array_view.h" 19 #include "api/environment/environment.h" 20 #include "api/task_queue/task_queue_factory.h" 21 #include "api/units/time_delta.h" 22 #include "modules/audio_device/audio_device_buffer.h" 23 #include "modules/audio_device/audio_device_generic.h" 24 #include "modules/audio_device/include/test_audio_device.h" 25 #include "rtc_base/checks.h" 26 #include "rtc_base/synchronization/mutex.h" 27 #include "rtc_base/task_utils/repeating_task.h" 28 29 namespace webrtc { 30 namespace { 31 32 constexpr int kFrameLengthUs = 10000; 33 34 } // namespace 35 36 TestAudioDevice::TestAudioDevice( 37 const Environment& env, 38 std::unique_ptr<TestAudioDeviceModule::Capturer> capturer, 39 std::unique_ptr<TestAudioDeviceModule::Renderer> renderer, 40 float speed) 41 : env_(env), 42 capturer_(std::move(capturer)), 43 renderer_(std::move(renderer)), 44 process_interval_us_(kFrameLengthUs / speed), 45 audio_buffer_(nullptr), 46 rendering_(false), 47 capturing_(false) { 48 auto good_sample_rate = [](int sr) { 49 return sr == 8000 || sr == 16000 || sr == 24000 || sr == 32000 || 50 sr == 44100 || sr == 48000; 51 }; 52 53 if (renderer_) { 54 const int sample_rate = renderer_->SamplingFrequency(); 55 playout_buffer_.resize(TestAudioDeviceModule::SamplesPerFrame(sample_rate) * 56 renderer_->NumChannels(), 57 0); 58 RTC_CHECK(good_sample_rate(sample_rate)); 59 } 60 if (capturer_) { 61 RTC_CHECK(good_sample_rate(capturer_->SamplingFrequency())); 62 } 63 } 64 65 AudioDeviceGeneric::InitStatus TestAudioDevice::Init() { 66 task_queue_ = env_.task_queue_factory().CreateTaskQueue( 67 "TestAudioDeviceModuleImpl", TaskQueueFactory::Priority::NORMAL); 68 69 RepeatingTaskHandle::Start(task_queue_.get(), [this]() { 70 ProcessAudio(); 71 return TimeDelta::Micros(process_interval_us_); 72 }); 73 return InitStatus::OK; 74 } 75 76 int32_t TestAudioDevice::PlayoutIsAvailable(bool& available) { 77 MutexLock lock(&lock_); 78 available = renderer_ != nullptr; 79 return 0; 80 } 81 82 int32_t TestAudioDevice::InitPlayout() { 83 MutexLock lock(&lock_); 84 85 if (rendering_) { 86 return -1; 87 } 88 89 if (audio_buffer_ != nullptr && renderer_ != nullptr) { 90 // Update webrtc audio buffer with the selected parameters 91 audio_buffer_->SetPlayoutSampleRate(renderer_->SamplingFrequency()); 92 audio_buffer_->SetPlayoutChannels(renderer_->NumChannels()); 93 } 94 rendering_initialized_ = true; 95 return 0; 96 } 97 98 bool TestAudioDevice::PlayoutIsInitialized() const { 99 MutexLock lock(&lock_); 100 return rendering_initialized_; 101 } 102 103 int32_t TestAudioDevice::StartPlayout() { 104 MutexLock lock(&lock_); 105 RTC_CHECK(renderer_); 106 rendering_ = true; 107 return 0; 108 } 109 110 int32_t TestAudioDevice::StopPlayout() { 111 MutexLock lock(&lock_); 112 rendering_ = false; 113 return 0; 114 } 115 116 int32_t TestAudioDevice::RecordingIsAvailable(bool& available) { 117 MutexLock lock(&lock_); 118 available = capturer_ != nullptr; 119 return 0; 120 } 121 122 int32_t TestAudioDevice::InitRecording() { 123 MutexLock lock(&lock_); 124 125 if (capturing_) { 126 return -1; 127 } 128 129 if (audio_buffer_ != nullptr && capturer_ != nullptr) { 130 // Update webrtc audio buffer with the selected parameters 131 audio_buffer_->SetRecordingSampleRate(capturer_->SamplingFrequency()); 132 audio_buffer_->SetRecordingChannels(capturer_->NumChannels()); 133 } 134 capturing_initialized_ = true; 135 return 0; 136 } 137 138 bool TestAudioDevice::RecordingIsInitialized() const { 139 MutexLock lock(&lock_); 140 return capturing_initialized_; 141 } 142 143 int32_t TestAudioDevice::StartRecording() { 144 MutexLock lock(&lock_); 145 capturing_ = true; 146 return 0; 147 } 148 149 int32_t TestAudioDevice::StopRecording() { 150 MutexLock lock(&lock_); 151 capturing_ = false; 152 return 0; 153 } 154 155 bool TestAudioDevice::Playing() const { 156 MutexLock lock(&lock_); 157 return rendering_; 158 } 159 160 bool TestAudioDevice::Recording() const { 161 MutexLock lock(&lock_); 162 return capturing_; 163 } 164 165 void TestAudioDevice::ProcessAudio() { 166 MutexLock lock(&lock_); 167 if (audio_buffer_ == nullptr) { 168 return; 169 } 170 if (capturing_ && capturer_ != nullptr) { 171 // Capture 10ms of audio. 2 bytes per sample. 172 const bool keep_capturing = capturer_->Capture(&recording_buffer_); 173 if (!recording_buffer_.empty()) { 174 audio_buffer_->SetRecordedBuffer( 175 recording_buffer_.data(), 176 recording_buffer_.size() / capturer_->NumChannels(), 177 std::make_optional(env_.clock().CurrentTime().ns())); 178 audio_buffer_->DeliverRecordedData(); 179 } 180 if (!keep_capturing) { 181 capturing_ = false; 182 } 183 } 184 if (rendering_) { 185 const int sampling_frequency = renderer_->SamplingFrequency(); 186 int32_t samples_per_channel = audio_buffer_->RequestPlayoutData( 187 TestAudioDeviceModule::SamplesPerFrame(sampling_frequency)); 188 audio_buffer_->GetPlayoutData(playout_buffer_.data()); 189 size_t samples_out = samples_per_channel * renderer_->NumChannels(); 190 RTC_CHECK_LE(samples_out, playout_buffer_.size()); 191 const bool keep_rendering = renderer_->Render( 192 ArrayView<const int16_t>(playout_buffer_.data(), samples_out)); 193 if (!keep_rendering) { 194 rendering_ = false; 195 } 196 } 197 } 198 199 void TestAudioDevice::AttachAudioBuffer(AudioDeviceBuffer* audio_buffer) { 200 MutexLock lock(&lock_); 201 RTC_DCHECK(audio_buffer || audio_buffer_); 202 audio_buffer_ = audio_buffer; 203 204 if (renderer_ != nullptr) { 205 audio_buffer_->SetPlayoutSampleRate(renderer_->SamplingFrequency()); 206 audio_buffer_->SetPlayoutChannels(renderer_->NumChannels()); 207 } 208 if (capturer_ != nullptr) { 209 audio_buffer_->SetRecordingSampleRate(capturer_->SamplingFrequency()); 210 audio_buffer_->SetRecordingChannels(capturer_->NumChannels()); 211 } 212 } 213 214 } // namespace webrtc