1717#include " cuttlefish/host/frontend/webrtc/audio_handler.h"
1818
1919#include < algorithm>
20- #include < array>
21- #include < chrono>
20+ #include < cstdint>
2221#include < cstring>
22+ #include < format>
2323
24- #include < rtc_base/time_utils.h>
2524#include " absl/log/check.h"
2625#include " absl/log/log.h"
2726
27+ #include < rtc_base/time_utils.h>
28+
2829#include " cuttlefish/host/frontend/webrtc/audio_mixer.h"
2930
3031namespace cuttlefish {
@@ -50,8 +51,7 @@ virtio_snd_chmap_info GetVirtioSndChmapInfo(
5051 const AudioStreamSettings& settings) {
5152 const static std::unordered_map<AudioChannelsLayout, std::vector<uint8_t >>
5253 kChannelPositions = {
53- {AudioChannelsLayout::Mono,
54- {AudioChannelMap::VIRTIO_SND_CHMAP_MONO}},
54+ {AudioChannelsLayout::Mono, {AudioChannelMap::VIRTIO_SND_CHMAP_MONO}},
5555 {AudioChannelsLayout::Stereo,
5656 {AudioChannelMap::VIRTIO_SND_CHMAP_FL,
5757 AudioChannelMap::VIRTIO_SND_CHMAP_FR}},
@@ -77,6 +77,59 @@ virtio_snd_chmap_info GetVirtioSndChmapInfo(
7777 return info;
7878}
7979
80+ inline constexpr const char * GetDirectionString (
81+ AudioStreamSettings::Direction direction) {
82+ switch (direction) {
83+ case AudioStreamSettings::Direction::Capture:
84+ return " Capture" ;
85+ case AudioStreamSettings::Direction::Playback:
86+ return " Playback" ;
87+ }
88+ }
89+
90+ virtio_snd_ctl_info GetVirtioCtlInfoVolume (
91+ const AudioStreamSettings::VolumeControl& settings,
92+ AudioStreamSettings::Direction stream_direction, uint32_t card_id,
93+ uint32_t device_id, uint32_t ctl_id) {
94+ virtio_snd_ctl_info info = {
95+ .hdr = {.hda_fn_nid = Le32 (ctl_id)},
96+ .role = Le32 (static_cast <uint8_t >(AudioControlRole::VIRTIO_SND_CTL_ROLE_VOLUME)),
97+ .type = Le32 (static_cast <uint8_t >(AudioControlType::VIRTIO_SND_CTL_TYPE_INTEGER)),
98+ .access = Le32 ((1 << AudioControlAccess::VIRTIO_SND_CTL_ACCESS_READ) |
99+ (1 << AudioControlAccess::VIRTIO_SND_CTL_ACCESS_WRITE)),
100+ .count = Le32 (1 ),
101+ .index = Le32 (0 ),
102+ .name = {},
103+ .value = {.integer = {
104+ .min = Le32 (settings.min ),
105+ .max = Le32 (settings.max ),
106+ .step = Le32 (settings.step ),
107+ }}};
108+ std::format_to_n (info.name , sizeof (info.name ) - 1 ,
109+ " Master {} Volume (C{}D{})" ,
110+ GetDirectionString (stream_direction), card_id, device_id);
111+ return info;
112+ }
113+
114+ virtio_snd_ctl_info GetVirtioCtlInfoMute (
115+ AudioStreamSettings::Direction stream_direction, uint32_t card_id,
116+ uint32_t device_id, uint32_t ctl_id) {
117+ virtio_snd_ctl_info info = {
118+ .hdr = {.hda_fn_nid = Le32 (ctl_id)},
119+ .role = Le32 (static_cast <uint8_t >(AudioControlRole::VIRTIO_SND_CTL_ROLE_MUTE)),
120+ .type = Le32 (static_cast <uint8_t >(AudioControlType::VIRTIO_SND_CTL_TYPE_BOOLEAN)),
121+ .access = Le32 ((1 << AudioControlAccess::VIRTIO_SND_CTL_ACCESS_READ) |
122+ (1 << AudioControlAccess::VIRTIO_SND_CTL_ACCESS_WRITE)),
123+ .count = Le32 (1 ),
124+ .index = Le32 (0 ),
125+ .name = {},
126+ .value = {} // Ignored when VIRTIO_SND_CTL_TYPE_BOOLEAN
127+ };
128+ std::format_to_n (info.name , sizeof (info.name ) - 1 , " Master {} Mute (C{}D{})" ,
129+ GetDirectionString (stream_direction), card_id, device_id);
130+ return info;
131+ }
132+
80133virtio_snd_pcm_info GetVirtioSndPcmInfo (const AudioStreamSettings& settings) {
81134 return {
82135 .hdr =
@@ -278,6 +331,31 @@ AudioHandler::AudioHandler(
278331 : 0 );
279332 streams_[stream_id] = GetVirtioSndPcmInfo (settings);
280333 chmaps_[stream_id] = GetVirtioSndChmapInfo (settings);
334+
335+ constexpr uint32_t kCardId = 0 ; // As of now only one card is supported
336+ if (settings.has_mute_control ) {
337+ controls_.push_back (GetVirtioCtlInfoMute (settings.direction , kCardId ,
338+ settings.id , controls_.size ()));
339+ controls_to_streams_map_.push_back (
340+ ControlDesc{.type = ControlDesc::Type::Mute, .stream_id = stream_id});
341+ }
342+ if (settings.master_volume_control .has_value ()) {
343+ const auto & control = settings.master_volume_control .value ();
344+ CHECK (control.max > control.min )
345+ << " Volume control 'min' value must be lower than 'max'." ;
346+ CHECK ((control.max - control.min ) % control.step == 0 )
347+ << " Volume control 'step' value must divide the total volume range "
348+ " evenly." ;
349+ controls_.push_back (GetVirtioCtlInfoVolume (
350+ control, settings.direction , kCardId , settings.id , controls_.size ()));
351+ controls_to_streams_map_.push_back (ControlDesc{
352+ .type = ControlDesc::Type::Volume, .stream_id = stream_id});
353+ stream_descs_[stream_id].volume = {
354+ .min = control.min ,
355+ .max = control.max ,
356+ .current = control.max ,
357+ };
358+ }
281359 }
282360}
283361
@@ -291,8 +369,8 @@ void AudioHandler::Start() {
291369[[noreturn]] void AudioHandler::Loop () {
292370 for (;;) {
293371 auto audio_client = audio_server_->AcceptClient (
294- streams_.size (), NUM_JACKS, chmaps_.size (), 262144 /* tx_shm_len */ ,
295- 262144 /* rx_shm_len */ );
372+ streams_.size (), NUM_JACKS, chmaps_.size (), controls_. size () ,
373+ 262144 /* tx_shm_len */ , 262144 /* rx_shm_len */ );
296374 CHECK (audio_client) << " Failed to create audio client connection instance" ;
297375
298376 std::thread playback_thread ([this , &audio_client]() {
@@ -404,26 +482,111 @@ void AudioHandler::JacksInfo(JackInfoCommand& cmd) {
404482 cmd.Reply (AudioStatus::VIRTIO_SND_S_OK, jack_info);
405483}
406484
485+ void AudioHandler::ControlsInfo (ControlInfoCommand& cmd) {
486+ if (cmd.start_id () + cmd.count () > controls_.size ()) {
487+ cmd.Reply (AudioStatus::VIRTIO_SND_S_BAD_MSG, {});
488+ return ;
489+ }
490+
491+ cmd.Reply (AudioStatus::VIRTIO_SND_S_OK,
492+ {controls_.cbegin () + cmd.start_id (), cmd.count ()});
493+ }
494+
495+ AudioStatus AudioHandler::HandleControlMute (ControlCommand& cmd) {
496+ const auto stream_id = controls_to_streams_map_[cmd.control_id ()].stream_id ;
497+ auto & stream = stream_descs_[stream_id];
498+ std::lock_guard<std::mutex> lock (stream.mtx );
499+
500+ if (cmd.type () == AudioCommandType::VIRTIO_SND_R_CTL_READ) {
501+ auto & val = cmd.value ()->value .integer ;
502+ val[0 ] = Le32 (stream.muted ? 1 : 0 );
503+ return AudioStatus::VIRTIO_SND_S_OK;
504+ }
505+
506+ if (cmd.type () == AudioCommandType::VIRTIO_SND_R_CTL_WRITE) {
507+ const auto val = cmd.value ()->value .integer [0 ].as_uint32_t ();
508+ // For VIRTIO_SND_CTL_TYPE_BOOLEAN, the guest driver (virtio_snd)
509+ // inherently knows that the control acts as a toggle. It implicitly
510+ // enforces a minimum of 0 and a maximum of 1.
511+ if (val > 1 ) {
512+ return AudioStatus::VIRTIO_SND_S_BAD_MSG;
513+ }
514+
515+ stream.muted = val == 1 ;
516+ return AudioStatus::VIRTIO_SND_S_OK;
517+ }
518+
519+ return AudioStatus::VIRTIO_SND_S_NOT_SUPP;
520+ }
521+
522+ AudioStatus AudioHandler::HandleControlVolume (ControlCommand& cmd) {
523+ const auto stream_id = controls_to_streams_map_[cmd.control_id ()].stream_id ;
524+ auto & stream = stream_descs_[stream_id];
525+ std::lock_guard<std::mutex> lock (stream.mtx );
526+
527+ if (cmd.type () == AudioCommandType::VIRTIO_SND_R_CTL_READ) {
528+ auto & val = cmd.value ()->value .integer ;
529+ val[0 ] = Le32 (stream.volume .current );
530+ return AudioStatus::VIRTIO_SND_S_OK;
531+ }
532+
533+ if (cmd.type () == AudioCommandType::VIRTIO_SND_R_CTL_WRITE) {
534+ const auto val = cmd.value ()->value .integer [0 ].as_uint32_t ();
535+ if (val < stream.volume .min || val > stream.volume .max ) {
536+ VLOG (0 ) << " Wrongs volume value for control " << cmd.control_id ()
537+ << " provided: " << val;
538+ return AudioStatus::VIRTIO_SND_S_BAD_MSG;
539+ }
540+ VLOG (0 ) << " Setting volume for stream " << stream_id << " to " << val;
541+ stream.volume .current = val;
542+ return AudioStatus::VIRTIO_SND_S_OK;
543+ }
544+
545+ return AudioStatus::VIRTIO_SND_S_NOT_SUPP;
546+ }
547+
548+ void AudioHandler::OnControlCommand (ControlCommand& cmd) {
549+ const auto id = cmd.control_id ();
550+ if (id >= controls_.size ()) {
551+ cmd.Reply (AudioStatus::VIRTIO_SND_S_BAD_MSG);
552+ return ;
553+ }
554+
555+ auto result = AudioStatus::VIRTIO_SND_S_NOT_SUPP;
556+ switch (controls_to_streams_map_[id].type ) {
557+ case ControlDesc::Type::Mute:
558+ result = HandleControlMute (cmd);
559+ break ;
560+ case ControlDesc::Type::Volume:
561+ result = HandleControlVolume (cmd);
562+ break ;
563+ }
564+ cmd.Reply (result);
565+ }
566+
407567void AudioHandler::OnPlaybackBuffer (TxBuffer buffer) {
408568 const auto stream_id = buffer.stream_id ();
409569 // Invalid or capture streams shouldn't send tx buffers
410570 if (stream_id >= streams_.size () || IsCapture (stream_id)) {
411- LOG (ERROR ) << " Invalid or capture streams have sent tx buffers" ;
571+ VLOG ( 0 ) << " Invalid or capture streams have sent tx buffers" ;
412572 buffer.SendStatus (AudioStatus::VIRTIO_SND_S_BAD_MSG, 0 , 0 );
413573 return ;
414574 }
415575
416576 uint32_t sample_rate = 0 ;
417577 uint8_t channels = 0 ;
418578 uint8_t bits_per_channel = 0 ;
579+ float volume = 0 ;
419580 {
420581 auto & stream_desc = stream_descs_[stream_id];
421582 std::lock_guard<std::mutex> lock (stream_desc.mtx );
422583
584+ volume = stream_desc.volume .GetCurrentVolumeLevel ();
585+
423586 // A buffer may be received for an inactive stream if we were slow to
424587 // process it and the other side stopped the stream. Quietly ignore it in
425588 // that case
426- if (!stream_desc.active ) {
589+ if (!stream_desc.active || stream_desc. muted || volume == 0 ) {
427590 buffer.SendStatus (AudioStatus::VIRTIO_SND_S_OK, 0 , buffer.len ());
428591 return ;
429592 }
@@ -433,11 +596,17 @@ void AudioHandler::OnPlaybackBuffer(TxBuffer buffer) {
433596 bits_per_channel = stream_desc.bits_per_sample ;
434597 }
435598 audio_mixer_->OnPlayback (stream_id, sample_rate, channels, bits_per_channel,
436- buffer.get (), buffer.len ());
599+ volume, buffer.get (), buffer.len ());
437600 buffer.SendStatus (AudioStatus::VIRTIO_SND_S_OK, 0 , buffer.len ());
438601}
439602
440603void AudioHandler::OnCaptureBuffer (RxBuffer buffer) {
604+ const auto rx_buffer = buffer.get ();
605+ size_t bytes_read = 0 ;
606+ float volume = 0 ;
607+ uint32_t bytes_per_sample = 0 ;
608+ bool is_muted_by_control = false ;
609+
441610 auto stream_id = buffer.stream_id ();
442611 auto & stream_desc = stream_descs_[stream_id];
443612 {
@@ -448,31 +617,32 @@ void AudioHandler::OnCaptureBuffer(RxBuffer buffer) {
448617 buffer.SendStatus (AudioStatus::VIRTIO_SND_S_BAD_MSG, 0 , 0 );
449618 return ;
450619 }
620+
451621 // A buffer may be received for an inactive stream if we were slow to
452622 // process it and the other side stopped the stream. Quietly ignore it in
453623 // that case
454624 if (!stream_desc.active ) {
455625 buffer.SendStatus (AudioStatus::VIRTIO_SND_S_OK, 0 , buffer.len ());
456626 return ;
457627 }
458- const auto bytes_per_sample = stream_desc.bits_per_sample / 8 ;
628+ volume = stream_desc.volume .GetCurrentVolumeLevel ();
629+ is_muted_by_control = stream_desc.muted ;
630+ bytes_per_sample = stream_desc.bits_per_sample / 8 ;
459631 const auto samples_per_channel = stream_desc.sample_rate / 100 ;
460632 const auto bytes_per_request =
461633 samples_per_channel * bytes_per_sample * stream_desc.channels ;
634+
635+ // Fill remaining data from previous iteration
462636 auto & holding_buffer = stream_descs_[stream_id].holding_buffer ;
463- size_t bytes_read = 0 ;
464- const auto rx_buffer = buffer.get ();
465- if (!holding_buffer.empty ()) {
466- // Fill remaining data from previous iteration
467- bytes_read = holding_buffer.size ();
468- std::copy (holding_buffer.cbegin (), holding_buffer.cend (), rx_buffer);
469- holding_buffer.clear ();
470- }
637+ bytes_read = holding_buffer.size ();
638+ std::copy (holding_buffer.cbegin (), holding_buffer.cend (), rx_buffer);
639+ holding_buffer.clear ();
640+
471641 bool muted = false ;
472642 while (buffer.len () - bytes_read >= bytes_per_request) {
473643 // Skip the holding buffer in as many reads as possible to avoid the extra
474644 // copies
475- auto write_pos = rx_buffer + bytes_read;
645+ const auto write_pos = rx_buffer + bytes_read;
476646 auto res = audio_source_->GetMoreAudioData (
477647 write_pos, bytes_per_sample, samples_per_channel,
478648 stream_desc.channels , stream_desc.sample_rate , muted);
@@ -521,6 +691,31 @@ void AudioHandler::OnCaptureBuffer(RxBuffer buffer) {
521691 }
522692 }
523693 }
694+
695+ if (is_muted_by_control) {
696+ memset (rx_buffer, 0 , bytes_read);
697+ } else if (volume < 1 .) {
698+ static const auto apply_volume = [](auto * data, size_t size_bytes,
699+ float volume) {
700+ for (auto & val : std::span{data, size_bytes / sizeof (*data)}) {
701+ val *= volume;
702+ }
703+ };
704+ switch (bytes_per_sample) {
705+ case 1 :
706+ apply_volume (rx_buffer, bytes_read, volume);
707+ break ;
708+ case 2 :
709+ apply_volume (reinterpret_cast <uint16_t *>(rx_buffer), bytes_read,
710+ volume);
711+ break ;
712+ case 4 :
713+ apply_volume (reinterpret_cast <uint32_t *>(rx_buffer), bytes_read,
714+ volume);
715+ break ;
716+ }
717+ }
718+
524719 buffer.SendStatus (AudioStatus::VIRTIO_SND_S_OK, 0 , buffer.len ());
525720}
526721
0 commit comments