1 /*
2 * Copyright (C) 2020 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include "host/frontend/webrtc/audio_handler.h"
18
19 #include <algorithm>
20 #include <chrono>
21
22 #include <android-base/logging.h>
23 #include <rtc_base/time_utils.h>
24
25 namespace cuttlefish {
26 namespace {
27
28 const virtio_snd_pcm_info STREAMS[] = {{
29 .hdr =
30 {
31 .hda_fn_nid = Le32(0),
32 },
33 .features = Le32(0),
34 // webrtc's api is quite primitive and doesn't allow for many different
35 // formats: It only takes the bits_per_sample as a parameter and assumes
36 // the underlying format to be one of the following:
37 .formats = Le64(
38 (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U8) |
39 (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U16) |
40 (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U24) |
41 (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U32)),
42 .rates = Le64(
43 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_5512) |
44 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_8000) |
45 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_11025) |
46 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_16000) |
47 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_22050) |
48 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_32000) |
49 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_44100) |
50 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_48000) |
51 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_64000) |
52 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_88200) |
53 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_96000) |
54 (((uint64_t)1) << (uint8_t)
55 AudioStreamRate::VIRTIO_SND_PCM_RATE_176400) |
56 (((uint64_t)1) << (uint8_t)
57 AudioStreamRate::VIRTIO_SND_PCM_RATE_192000) |
58 (((uint64_t)1) << (uint8_t)
59 AudioStreamRate::VIRTIO_SND_PCM_RATE_384000)),
60 .direction = (uint8_t)AudioStreamDirection::VIRTIO_SND_D_OUTPUT,
61 .channels_min = 1,
62 .channels_max = 2,
63 }, {
64 .hdr =
65 {
66 .hda_fn_nid = Le32(0),
67 },
68 .features = Le32(0),
69 // webrtc's api is quite primitive and doesn't allow for many different
70 // formats: It only takes the bits_per_sample as a parameter and assumes
71 // the underlying format to be one of the following:
72 .formats = Le64(
73 (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U8) |
74 (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U16) |
75 (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U24) |
76 (((uint64_t)1) << (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U32)),
77 .rates = Le64(
78 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_5512) |
79 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_8000) |
80 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_11025) |
81 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_16000) |
82 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_22050) |
83 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_32000) |
84 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_44100) |
85 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_48000) |
86 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_64000) |
87 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_88200) |
88 (((uint64_t)1) << (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_96000) |
89 (((uint64_t)1) << (uint8_t)
90 AudioStreamRate::VIRTIO_SND_PCM_RATE_176400) |
91 (((uint64_t)1) << (uint8_t)
92 AudioStreamRate::VIRTIO_SND_PCM_RATE_192000) |
93 (((uint64_t)1) << (uint8_t)
94 AudioStreamRate::VIRTIO_SND_PCM_RATE_384000)),
95 .direction = (uint8_t)AudioStreamDirection::VIRTIO_SND_D_INPUT,
96 .channels_min = 1,
97 .channels_max = 2,
98 }};
99 constexpr uint32_t NUM_STREAMS = sizeof(STREAMS) / sizeof(STREAMS[0]);
100
IsCapture(uint32_t stream_id)101 bool IsCapture(uint32_t stream_id) {
102 CHECK(stream_id < NUM_STREAMS) << "Invalid stream id: " << stream_id;
103 return STREAMS[stream_id].direction ==
104 (uint8_t)AudioStreamDirection::VIRTIO_SND_D_INPUT;
105 }
106
107 class CvdAudioFrameBuffer : public webrtc_streaming::AudioFrameBuffer {
108 public:
CvdAudioFrameBuffer(const uint8_t * buffer,int bits_per_sample,int sample_rate,int channels,int frames)109 CvdAudioFrameBuffer(const uint8_t* buffer, int bits_per_sample,
110 int sample_rate, int channels, int frames)
111 : buffer_(buffer),
112 bits_per_sample_(bits_per_sample),
113 sample_rate_(sample_rate),
114 channels_(channels),
115 frames_(frames) {}
116
bits_per_sample() const117 int bits_per_sample() const override { return bits_per_sample_; }
118
sample_rate() const119 int sample_rate() const override { return sample_rate_; }
120
channels() const121 int channels() const override { return channels_; }
122
frames() const123 int frames() const override { return frames_; }
124
data() const125 const uint8_t* data() const override { return buffer_; }
126
127 private:
128 const uint8_t* buffer_;
129 int bits_per_sample_;
130 int sample_rate_;
131 int channels_;
132 int frames_;
133 };
134
BitsPerSample(uint8_t virtio_format)135 int BitsPerSample(uint8_t virtio_format) {
136 switch (virtio_format) {
137 /* analog formats (width / physical width) */
138 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_IMA_ADPCM:
139 /* 4 / 4 bits */
140 return 4;
141 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_MU_LAW:
142 /* 8 / 8 bits */
143 return 8;
144 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_A_LAW:
145 /* 8 / 8 bits */
146 return 8;
147 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S8:
148 /* 8 / 8 bits */
149 return 8;
150 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U8:
151 /* 8 / 8 bits */
152 return 8;
153 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S16:
154 /* 16 / 16 bits */
155 return 16;
156 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U16:
157 /* 16 / 16 bits */
158 return 16;
159 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S18_3:
160 /* 18 / 24 bits */
161 return 24;
162 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U18_3:
163 /* 18 / 24 bits */
164 return 24;
165 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S20_3:
166 /* 20 / 24 bits */
167 return 24;
168 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U20_3:
169 /* 20 / 24 bits */
170 return 24;
171 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S24_3:
172 /* 24 / 24 bits */
173 return 24;
174 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U24_3:
175 /* 24 / 24 bits */
176 return 24;
177 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S20:
178 /* 20 / 32 bits */
179 return 32;
180 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U20:
181 /* 20 / 32 bits */
182 return 32;
183 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S24:
184 /* 24 / 32 bits */
185 return 32;
186 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U24:
187 /* 24 / 32 bits */
188 return 32;
189 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_S32:
190 /* 32 / 32 bits */
191 return 32;
192 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_U32:
193 /* 32 / 32 bits */
194 return 32;
195 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_FLOAT:
196 /* 32 / 32 bits */
197 return 32;
198 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_FLOAT64:
199 /* 64 / 64 bits */
200 return 64;
201 /* digital formats (width / physical width) */
202 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_DSD_U8:
203 /* 8 / 8 bits */
204 return 8;
205 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_DSD_U16:
206 /* 16 / 16 bits */
207 return 16;
208 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_DSD_U32:
209 /* 32 / 32 bits */
210 return 32;
211 case (uint8_t)AudioStreamFormat::VIRTIO_SND_PCM_FMT_IEC958_SUBFRAME:
212 /* 32 / 32 bits */
213 return 32;
214 default:
215 LOG(ERROR) << "Unknown virtio-snd audio format: " << virtio_format;
216 return -1;
217 }
218 }
219
SampleRate(uint8_t virtio_rate)220 int SampleRate(uint8_t virtio_rate) {
221 switch (virtio_rate) {
222 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_5512:
223 return 5512;
224 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_8000:
225 return 8000;
226 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_11025:
227 return 11025;
228 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_16000:
229 return 16000;
230 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_22050:
231 return 22050;
232 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_32000:
233 return 32000;
234 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_44100:
235 return 44100;
236 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_48000:
237 return 48000;
238 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_64000:
239 return 64000;
240 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_88200:
241 return 88200;
242 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_96000:
243 return 96000;
244 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_176400:
245 return 176400;
246 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_192000:
247 return 192000;
248 case (uint8_t)AudioStreamRate::VIRTIO_SND_PCM_RATE_384000:
249 return 384000;
250 default:
251 LOG(ERROR) << "Unknown virtio-snd sample rate: " << virtio_rate;
252 return -1;
253 }
254 }
255
256 } // namespace
257
AudioHandler(std::unique_ptr<AudioServer> audio_server,std::shared_ptr<webrtc_streaming::AudioSink> audio_sink,std::shared_ptr<webrtc_streaming::AudioSource> audio_source)258 AudioHandler::AudioHandler(
259 std::unique_ptr<AudioServer> audio_server,
260 std::shared_ptr<webrtc_streaming::AudioSink> audio_sink,
261 std::shared_ptr<webrtc_streaming::AudioSource> audio_source)
262 : audio_sink_(audio_sink),
263 audio_server_(std::move(audio_server)),
264 stream_descs_(NUM_STREAMS),
265 audio_source_(audio_source) {}
266
Start()267 void AudioHandler::Start() {
268 server_thread_ = std::thread([this]() { Loop(); });
269 }
270
Loop()271 [[noreturn]] void AudioHandler::Loop() {
272 for (;;) {
273 auto audio_client = audio_server_->AcceptClient(
274 NUM_STREAMS, 0 /* num_jacks, */, 0 /* num_chmaps, */,
275 262144 /* tx_shm_len */, 262144 /* rx_shm_len */);
276 CHECK(audio_client) << "Failed to create audio client connection instance";
277
278 std::thread playback_thread([this, &audio_client]() {
279 while (audio_client->ReceivePlayback(*this)) {
280 }
281 });
282 std::thread capture_thread([this, &audio_client]() {
283 while (audio_client->ReceiveCapture(*this)) {
284 }
285 });
286 // Wait for the client to do something
287 while (audio_client->ReceiveCommands(*this)) {
288 }
289 playback_thread.join();
290 capture_thread.join();
291 }
292 }
293
StreamsInfo(StreamInfoCommand & cmd)294 void AudioHandler::StreamsInfo(StreamInfoCommand& cmd) {
295 if (cmd.start_id() >= NUM_STREAMS ||
296 cmd.start_id() + cmd.count() > NUM_STREAMS) {
297 cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG, {});
298 return;
299 }
300 std::vector<virtio_snd_pcm_info> stream_info(
301 &STREAMS[cmd.start_id()], &STREAMS[0] + cmd.start_id() + cmd.count());
302 cmd.Reply(AudioStatus::VIRTIO_SND_S_OK, stream_info);
303 }
304
SetStreamParameters(StreamSetParamsCommand & cmd)305 void AudioHandler::SetStreamParameters(StreamSetParamsCommand& cmd) {
306 if (cmd.stream_id() >= NUM_STREAMS) {
307 cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
308 return;
309 }
310 const auto& stream_info = STREAMS[cmd.stream_id()];
311 auto bits_per_sample = BitsPerSample(cmd.format());
312 auto sample_rate = SampleRate(cmd.rate());
313 auto channels = cmd.channels();
314 if (bits_per_sample < 0 || sample_rate < 0 ||
315 channels < stream_info.channels_min ||
316 channels > stream_info.channels_max) {
317 cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
318 return;
319 }
320 {
321 std::lock_guard<std::mutex> lock(stream_descs_[cmd.stream_id()].mtx);
322 stream_descs_[cmd.stream_id()].bits_per_sample = bits_per_sample;
323 stream_descs_[cmd.stream_id()].sample_rate = sample_rate;
324 stream_descs_[cmd.stream_id()].channels = channels;
325 auto len10ms = (channels * (sample_rate / 100) * bits_per_sample) / 8;
326 stream_descs_[cmd.stream_id()].buffer.Reset(len10ms);
327 }
328 cmd.Reply(AudioStatus::VIRTIO_SND_S_OK);
329 }
330
PrepareStream(StreamControlCommand & cmd)331 void AudioHandler::PrepareStream(StreamControlCommand& cmd) {
332 if (cmd.stream_id() >= NUM_STREAMS) {
333 cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
334 return;
335 }
336 cmd.Reply(AudioStatus::VIRTIO_SND_S_OK);
337 }
338
ReleaseStream(StreamControlCommand & cmd)339 void AudioHandler::ReleaseStream(StreamControlCommand& cmd) {
340 if (cmd.stream_id() >= NUM_STREAMS) {
341 cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
342 return;
343 }
344 cmd.Reply(AudioStatus::VIRTIO_SND_S_OK);
345 }
346
StartStream(StreamControlCommand & cmd)347 void AudioHandler::StartStream(StreamControlCommand& cmd) {
348 if (cmd.stream_id() >= NUM_STREAMS) {
349 cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
350 return;
351 }
352 stream_descs_[cmd.stream_id()].active = true;
353 cmd.Reply(AudioStatus::VIRTIO_SND_S_OK);
354 }
355
StopStream(StreamControlCommand & cmd)356 void AudioHandler::StopStream(StreamControlCommand& cmd) {
357 if (cmd.stream_id() >= NUM_STREAMS) {
358 cmd.Reply(AudioStatus::VIRTIO_SND_S_BAD_MSG);
359 return;
360 }
361 stream_descs_[cmd.stream_id()].active = false;
362 cmd.Reply(AudioStatus::VIRTIO_SND_S_OK);
363 }
364
OnPlaybackBuffer(TxBuffer buffer)365 void AudioHandler::OnPlaybackBuffer(TxBuffer buffer) {
366 auto stream_id = buffer.stream_id();
367 auto& stream_desc = stream_descs_[stream_id];
368 {
369 std::lock_guard<std::mutex> lock(stream_desc.mtx);
370 auto& holding_buffer = stream_descs_[stream_id].buffer;
371 // Invalid or capture streams shouldn't send tx buffers
372 if (stream_id >= NUM_STREAMS || IsCapture(stream_id)) {
373 buffer.SendStatus(AudioStatus::VIRTIO_SND_S_BAD_MSG, 0, 0);
374 return;
375 }
376 // A buffer may be received for an inactive stream if we were slow to
377 // process it and the other side stopped the stream. Quitely ignore it in
378 // that case
379 if (!stream_desc.active) {
380 buffer.SendStatus(AudioStatus::VIRTIO_SND_S_OK, 0, buffer.len());
381 return;
382 }
383 // Webrtc will silently ignore any buffer with a length different than 10ms,
384 // so we must split any buffer bigger than that and temporarily store any
385 // remaining frames that are less than that size.
386 auto current_time = rtc::TimeMillis();
387 // The timestamp of the first 10ms chunk to be sent so that the last one
388 // will have the current time
389 auto base_time =
390 current_time - ((buffer.len() - 1) / holding_buffer.buffer.size()) * 10;
391 // number of frames in a 10 ms buffer
392 const int frames = stream_desc.sample_rate / 100;
393 size_t pos = 0;
394 while (pos < buffer.len()) {
395 if (holding_buffer.empty() &&
396 buffer.len() - pos >= holding_buffer.buffer.size()) {
397 // Avoid the extra copy into holding buffer
398 // This casts away volatility of the pointer, necessary because the
399 // webrtc api doesn't expect volatile memory. This should be safe though
400 // because webrtc will use the contents of the buffer before returning
401 // and only then we release it.
402 auto audio_frame_buffer = std::make_shared<CvdAudioFrameBuffer>(
403 const_cast<const uint8_t*>(&buffer.get()[pos]),
404 stream_desc.bits_per_sample, stream_desc.sample_rate,
405 stream_desc.channels, frames);
406 audio_sink_->OnFrame(audio_frame_buffer, base_time);
407 pos += holding_buffer.buffer.size();
408 } else {
409 pos += holding_buffer.Add(buffer.get() + pos, buffer.len() - pos);
410 if (holding_buffer.full()) {
411 auto buffer_ptr = const_cast<const uint8_t*>(holding_buffer.data());
412 auto audio_frame_buffer = std::make_shared<CvdAudioFrameBuffer>(
413 buffer_ptr, stream_desc.bits_per_sample,
414 stream_desc.sample_rate, stream_desc.channels, frames);
415 audio_sink_->OnFrame(audio_frame_buffer, base_time);
416 holding_buffer.count = 0;
417 }
418 }
419 base_time += 10;
420 }
421 }
422 buffer.SendStatus(AudioStatus::VIRTIO_SND_S_OK, 0, buffer.len());
423 }
424
OnCaptureBuffer(RxBuffer buffer)425 void AudioHandler::OnCaptureBuffer(RxBuffer buffer) {
426 auto stream_id = buffer.stream_id();
427 auto& stream_desc = stream_descs_[stream_id];
428 {
429 std::lock_guard<std::mutex> lock(stream_desc.mtx);
430 // Invalid or playback streams shouldn't send rx buffers
431 if (stream_id >= NUM_STREAMS || !IsCapture(stream_id)) {
432 LOG(ERROR) << "Received capture buffers on playback stream " << stream_id;
433 buffer.SendStatus(AudioStatus::VIRTIO_SND_S_BAD_MSG, 0, 0);
434 return;
435 }
436 // A buffer may be received for an inactive stream if we were slow to
437 // process it and the other side stopped the stream. Quitely ignore it in
438 // that case
439 if (!stream_desc.active) {
440 buffer.SendStatus(AudioStatus::VIRTIO_SND_S_OK, 0, buffer.len());
441 return;
442 }
443 auto bytes_per_sample = stream_desc.bits_per_sample / 8;
444 auto samples_per_channel =
445 buffer.len() / stream_desc.channels / bytes_per_sample;
446 bool muted = false;
447 auto res = audio_source_->GetMoreAudioData(
448 const_cast<uint8_t*>(buffer.get()), bytes_per_sample,
449 samples_per_channel, stream_desc.channels, stream_desc.sample_rate,
450 muted);
451 if (res < 0) {
452 // This is likely a recoverable error, log the error but don't let the VMM
453 // know about it so that it doesn't crash.
454 LOG(ERROR) << "Failed to receive audio data from client";
455 }
456 }
457 buffer.SendStatus(AudioStatus::VIRTIO_SND_S_OK, 0, buffer.len());
458 }
459
Reset(size_t size)460 void AudioHandler::HoldingBuffer::Reset(size_t size) {
461 buffer.resize(size);
462 count = 0;
463 }
464
Add(const volatile uint8_t * data,size_t max_len)465 size_t AudioHandler::HoldingBuffer::Add(const volatile uint8_t* data,
466 size_t max_len) {
467 auto added_len = std::min(max_len, buffer.size() - count);
468 std::copy(data, data + added_len, &buffer[count]);
469 count += added_len;
470 return added_len;
471 }
472
empty() const473 bool AudioHandler::HoldingBuffer::empty() const { return count == 0; }
474
full() const475 bool AudioHandler::HoldingBuffer::full() const {
476 return count == buffer.size();
477 }
478
data()479 uint8_t* AudioHandler::HoldingBuffer::data() { return buffer.data(); }
480
481 } // namespace cuttlefish
482