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