25 explicit ThreadedMockHardwareAudioInterface (
26 units::sample_rate_t sample_rate = units::sample_rate (48000),
27 units::sample_u32_t block_length = units::samples (256),
28 units::channel_count_t input_channels = units::channels (2),
29 units::channel_count_t output_channels = units::channels (2))
32 .sample_rate = sample_rate,
33 .block_length = block_length,
34 .input_channel_count = input_channels,
35 .output_channel_count = output_channels,
40 ~ThreadedMockHardwareAudioInterface ()
override { stop (); }
55 assert (!processing_active_.load (std::memory_order_acquire));
56 device_info_ = std::move (info);
67 return process_call_count_.load (std::memory_order_acquire);
73 auto * old_cb = callback_.load (std::memory_order_acquire);
74 if (old_cb !=
nullptr)
78 if (callback !=
nullptr)
80 callback_.store (callback, std::memory_order_release);
81 start_callback_thread ();
88 auto * cb = callback_.load (std::memory_order_acquire);
93 callback_.store (
nullptr, std::memory_order_release);
94 processing_active_.store (
false, std::memory_order_release);
100 auto * cb = callback_.load (std::memory_order_acquire);
104 processing_active_.store (
false, std::memory_order_release);
105 device_info_ = std::move (new_info);
106 start_callback_thread ();
111 void start_callback_thread ()
113 auto * cb = callback_.load (std::memory_order_acquire);
114 cb->about_to_start ();
115 processing_active_.store (
true, std::memory_order_release);
117 is_running_.store (
true, std::memory_order_release);
118 callback_thread_ = std::jthread ([
this] (std::stop_token stoken) {
119 const auto num_channels =
120 device_info_.input_channel_count.in<
int> (units::channels);
121 const auto bl = device_info_.block_length.in (units::samples);
122 std::vector<float> output_buf (bl * num_channels, 0.f);
123 std::vector<float> input_buf (bl * num_channels, 0.f);
124 std::vector<float *> output_ptrs (num_channels);
125 std::vector<const float *> input_ptrs (num_channels);
126 for (
int ch = 0; ch < num_channels; ++ch)
128 output_ptrs[ch] = output_buf.data () + (
static_cast<size_t> (ch) * bl);
129 input_ptrs[ch] = input_buf.data () + (
static_cast<size_t> (ch) * bl);
133 !stoken.stop_requested ()
134 && is_running_.load (std::memory_order_acquire))
136 auto * current_cb = callback_.load (std::memory_order_acquire);
139 current_cb->process_audio (
140 { input_ptrs.data (),
static_cast<size_t> (num_channels) },
141 { output_ptrs.data (),
static_cast<size_t> (num_channels) },
142 device_info_.block_length);
143 process_call_count_.fetch_add (1, std::memory_order_acq_rel);
145 auto sleep_us =
static_cast<int64_t
> (
146 device_info_.block_length.in<
double> (units::samples) * 1'000'000.0
147 / device_info_.sample_rate.in (units::sample_rate));
148 std::this_thread::sleep_for (std::chrono::microseconds (sleep_us));
155 is_running_.store (
false, std::memory_order_release);
156 if (callback_thread_.joinable ())
158 callback_thread_.request_stop ();
159 callback_thread_.join ();
163 dsp::AudioDeviceInfo device_info_;
164 std::atomic<bool> processing_active_{
false };
165 std::atomic<dsp::IAudioCallback *> callback_{
nullptr };
166 std::atomic<bool> is_running_{
false };
167 std::atomic<std::size_t> process_call_count_{ 0 };
168 std::jthread callback_thread_;