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