1 #include "FakeAudioDeviceModule.h"
2
3 #include "modules/audio_device/include/audio_device_default.h"
4 #include "rtc_base/ref_counted_object.h"
5 #include "rtc_base/platform_thread.h"
6 #include "rtc_base/time_utils.h"
7
8 #include <thread>
9 #include <mutex>
10 #include <condition_variable>
11
12 namespace tgcalls {
13 class FakeAudioDeviceModuleImpl : public webrtc::webrtc_impl::AudioDeviceModuleDefault<webrtc::AudioDeviceModule> {
14 public:
Create(webrtc::TaskQueueFactory * taskQueueFactory,std::shared_ptr<FakeAudioDeviceModule::Renderer> renderer,std::shared_ptr<FakeAudioDeviceModule::Recorder> recorder,FakeAudioDeviceModule::Options options)15 static rtc::scoped_refptr<webrtc::AudioDeviceModule> Create(webrtc::TaskQueueFactory* taskQueueFactory,
16 std::shared_ptr<FakeAudioDeviceModule::Renderer> renderer,
17 std::shared_ptr<FakeAudioDeviceModule::Recorder> recorder,
18 FakeAudioDeviceModule::Options options) {
19 return rtc::scoped_refptr<webrtc::AudioDeviceModule>(
20 new rtc::RefCountedObject<FakeAudioDeviceModuleImpl>(taskQueueFactory, options, std::move(renderer), std::move(recorder)));
21 }
22
FakeAudioDeviceModuleImpl(webrtc::TaskQueueFactory *,FakeAudioDeviceModule::Options options,std::shared_ptr<FakeAudioDeviceModule::Renderer> renderer,std::shared_ptr<FakeAudioDeviceModule::Recorder> recorder)23 FakeAudioDeviceModuleImpl(webrtc::TaskQueueFactory*, FakeAudioDeviceModule::Options options,
24 std::shared_ptr<FakeAudioDeviceModule::Renderer> renderer,
25 std::shared_ptr<FakeAudioDeviceModule::Recorder> recorder)
26 : num_channels_{options.num_channels}, samples_per_sec_{options.samples_per_sec}, scheduler_(options.scheduler_),
27 renderer_(std::move(renderer)), recorder_(std::move(recorder)) {
28 if (!scheduler_) {
__anon7545dce60102(auto f) 29 scheduler_ = [](auto f) {
30 std::thread([f = std::move(f)]() {
31 while (true) {
32 double wait = f();
33 if (wait < 0) {
34 return;
35 }
36 std::this_thread::sleep_for(std::chrono::microseconds (static_cast<int64_t>(wait * 1000000)));
37 }
38 }).detach();
39 };
40 }
41 RTC_CHECK(num_channels_ == 1 || num_channels_ == 2);
__anon7545dce60302(size_t sr) 42 auto good_sample_rate = [](size_t sr) {
43 return sr == 8000 || sr == 16000 || sr == 32000 || sr == 44100 || sr == 48000;
44 };
45 RTC_CHECK(good_sample_rate(samples_per_sec_));
46 samples_per_frame_ = samples_per_sec_ / 100;
47 playout_buffer_.resize(samples_per_frame_ * 2 /* 2 in case stereo will be turned on later */, 0);
48 }
49
~FakeAudioDeviceModuleImpl()50 ~FakeAudioDeviceModuleImpl() override {
51 StopPlayout();
52 }
53
PlayoutIsAvailable(bool * available)54 int32_t PlayoutIsAvailable(bool* available) override {
55 if (available) {
56 *available = true;
57 }
58 return 0;
59 }
60
StereoPlayoutIsAvailable(bool * available) const61 int32_t StereoPlayoutIsAvailable(bool* available) const override {
62 if (available) {
63 *available = true;
64 }
65 return 0;
66 }
StereoPlayout(bool * enabled) const67 int32_t StereoPlayout(bool* enabled) const override {
68 if (enabled) {
69 *enabled = num_channels_ == 2;
70 }
71 return 0;
72 }
SetStereoPlayout(bool enable)73 int32_t SetStereoPlayout(bool enable) override {
74 size_t new_num_channels = enable ? 2 : 1;
75 if (new_num_channels != num_channels_) {
76 return -1;
77 }
78 return 0;
79 }
80
Init()81 int32_t Init() override {
82 return 0;
83 }
84
RegisterAudioCallback(webrtc::AudioTransport * callback)85 int32_t RegisterAudioCallback(webrtc::AudioTransport* callback) override {
86 std::unique_lock<std::mutex> lock(render_mutex_);
87 audio_callback_ = callback;
88 return 0;
89 }
90
StartPlayout()91 int32_t StartPlayout() override {
92 std::unique_lock<std::mutex> lock(render_mutex_);
93 if (!renderer_) {
94 return 0;
95 }
96 if (rendering_) {
97 return 0;
98 }
99 need_rendering_ = true;
100 rendering_ = true;
101 scheduler_([this]{
102 return Render() / 1000000.0;
103 });
104 return 0;
105 }
106
StopPlayout()107 int32_t StopPlayout() override {
108 if (!rendering_) {
109 return 0;
110 }
111
112 need_rendering_ = false;
113 std::unique_lock<std::mutex> lock(render_mutex_);
114 render_cond_.wait(lock, [this]{ return !rendering_; });
115
116 return 0;
117 }
118
Playing() const119 bool Playing() const override {
120 return rendering_;
121 }
122
StartRecording()123 int32_t StartRecording() override {
124 std::unique_lock<std::mutex> lock(record_mutex_);
125 if (!recorder_) {
126 return 0;
127 }
128 if (recording_) {
129 return 0;
130 }
131 need_recording_ = true;
132 recording_ = true;
133 scheduler_([this]{
134 return Record() / 1000000.0;
135 });
136 return 0;
137 }
StopRecording()138 int32_t StopRecording() override {
139 if (!recording_) {
140 return 0;
141 }
142
143 need_recording_ = false;
144 std::unique_lock<std::mutex> lock(record_mutex_);
145 record_cond_.wait(lock, [this]{ return !recording_; });
146
147 return 0;
148 }
Recording() const149 bool Recording() const override {
150 return recording_;
151 }
152
153 private:
154
Render()155 int32_t Render() {
156 std::unique_lock<std::mutex> lock(render_mutex_);
157 if (!need_rendering_) {
158 rendering_ = false;
159 render_cond_.notify_all();
160 return -1;
161 }
162
163 size_t samples_out = 0;
164 int64_t elapsed_time_ms = -1;
165 int64_t ntp_time_ms = -1;
166 size_t bytes_per_sample = 2 * num_channels_;
167
168 RTC_CHECK(audio_callback_);
169 if (renderer_) {
170 renderer_->BeginFrame(0);
171 }
172 audio_callback_->NeedMorePlayData(samples_per_frame_, bytes_per_sample, num_channels_, samples_per_sec_,
173 playout_buffer_.data(), samples_out, &elapsed_time_ms, &ntp_time_ms);
174 if (renderer_) {
175 renderer_->EndFrame();
176 }
177 if (samples_out != 0 && renderer_) {
178 AudioFrame frame;
179 frame.audio_samples = playout_buffer_.data();
180 frame.num_samples = samples_out;
181 frame.bytes_per_sample = bytes_per_sample;
182 frame.num_channels = num_channels_;
183 frame.samples_per_sec = samples_per_sec_;
184 frame.elapsed_time_ms = elapsed_time_ms;
185 frame.ntp_time_ms = ntp_time_ms;
186 renderer_->Render(frame);
187 }
188 int32_t wait_for_us = -1;
189 if (renderer_) {
190 wait_for_us = renderer_->WaitForUs();
191 }
192 return wait_for_us;
193 }
194
Record()195 int32_t Record() {
196 std::unique_lock<std::mutex> lock(record_mutex_);
197 if (!need_recording_) {
198 recording_ = false;
199 record_cond_.notify_all();
200 return -1;
201 }
202
203 auto frame = recorder_->Record();
204 if (frame.num_samples != 0) {
205 uint32_t new_mic_level;
206 audio_callback_->RecordedDataIsAvailable(frame.audio_samples,
207 frame.num_samples, frame.bytes_per_sample, frame.num_channels,
208 frame.samples_per_sec, 0, 0, 0, false, new_mic_level);
209 }
210
211 int32_t wait_for_us = -1;
212 if (recorder_) {
213 wait_for_us = recorder_->WaitForUs();
214 }
215 return wait_for_us;
216 }
217
218 size_t num_channels_;
219 const uint32_t samples_per_sec_;
220 size_t samples_per_frame_{0};
221
222 std::function<void(FakeAudioDeviceModule::Task)> scheduler_;
223
224 mutable std::mutex render_mutex_;
225 std::atomic<bool> need_rendering_{false};
226 std::atomic<bool> rendering_{false};
227 std::condition_variable render_cond_;
228 std::unique_ptr<rtc::PlatformThread> renderThread_;
229
230 mutable std::mutex record_mutex_;
231 std::atomic<bool> need_recording_{false};
232 std::atomic<bool> recording_{false};
233 std::condition_variable record_cond_;
234 std::unique_ptr<rtc::PlatformThread> recordThread_;
235
236
237 webrtc::AudioTransport* audio_callback_{nullptr};
238 const std::shared_ptr<FakeAudioDeviceModule::Renderer> renderer_;
239 const std::shared_ptr<FakeAudioDeviceModule::Recorder> recorder_;
240 std::vector<int16_t> playout_buffer_;
241 };
242
Creator(std::shared_ptr<Renderer> renderer,std::shared_ptr<Recorder> recorder,Options options)243 std::function<rtc::scoped_refptr<webrtc::AudioDeviceModule>(webrtc::TaskQueueFactory*)> FakeAudioDeviceModule::Creator(
244 std::shared_ptr<Renderer> renderer, std::shared_ptr<Recorder> recorder, Options options) {
245 bool is_renderer_empty = bool(renderer);
246 auto boxed_renderer = std::make_shared<std::shared_ptr<Renderer>>(std::move(renderer));
247 bool is_recorder_empty = bool(recorder);
248 auto boxed_recorder = std::make_shared<std::shared_ptr<Recorder>>(std::move(recorder));
249 return
250 [boxed_renderer = std::move(boxed_renderer), is_renderer_empty,
251 boxed_recorder = std::move(boxed_recorder), is_recorder_empty, options](webrtc::TaskQueueFactory* task_factory) {
252 RTC_CHECK(is_renderer_empty == bool(*boxed_renderer)); // call only once if renderer exists
253 RTC_CHECK(is_recorder_empty == bool(*boxed_recorder)); // call only once if recorder exists
254 return FakeAudioDeviceModuleImpl::Create(task_factory, std::move(*boxed_renderer), std::move(*boxed_recorder), options);
255 };
256 }
257 } // namespace tgcalls
258