From b3b83c1f41933a386cd9089bebce11acf5ef342b Mon Sep 17 00:00:00 2001 From: Matias Ezequiel Vara Larsen Date: Tue, 4 Jul 2023 15:58:26 +0200 Subject: [PATCH] Sound: initialize StreamInfo This commit adds a vector named StreamInfo that contains the supported configuration for the audio backends, e.g., rate, format. This information is stored in the context of VhostUserSoundBackend. The device reponses this information when getting the VIRTIO_SND_R_PCM_INFO msg. The number of streams that are exposed in the device configuration is got from this table. Signed-off-by: Matias Ezequiel Vara Larsen --- crates/sound/src/audio_backends/null.rs | 2 +- crates/sound/src/audio_backends/pw_backend.rs | 17 +-- crates/sound/src/vhu_sound.rs | 105 ++++++++++++------ 3 files changed, 78 insertions(+), 46 deletions(-) diff --git a/crates/sound/src/audio_backends/null.rs b/crates/sound/src/audio_backends/null.rs index de4f3e1..9b1ec24 100644 --- a/crates/sound/src/audio_backends/null.rs +++ b/crates/sound/src/audio_backends/null.rs @@ -1,7 +1,7 @@ // SPDX-License-Identifier: Apache-2.0 or BSD-3-Clause use super::AudioBackend; -use crate::{Error, Result}; +use crate::Result; pub struct NullBackend {} diff --git a/crates/sound/src/audio_backends/pw_backend.rs b/crates/sound/src/audio_backends/pw_backend.rs index 6e9194f..945401a 100644 --- a/crates/sound/src/audio_backends/pw_backend.rs +++ b/crates/sound/src/audio_backends/pw_backend.rs @@ -4,22 +4,11 @@ use super::AudioBackend; use std::{thread}; use std::{cell::Cell, rc::Rc}; -use crate::{Error, Result}; +use crate::Result; -use vm_memory::{Le32, Le64}; +use vm_memory::Le32; use pipewire as pw; -use pw::{sys::*}; - -#[derive(Default, Debug)] -pub struct StreamInfo { - pub id: usize, - pub params: PCMParams, - pub formats: Le64, - pub rates: Le64, - pub direction: u8, - pub channels_min: u8, - pub channels_max: u8, -} +use pw::sys::PW_ID_CORE; #[derive(Default, Debug)] pub struct PCMParams { diff --git a/crates/sound/src/vhu_sound.rs b/crates/sound/src/vhu_sound.rs index 4f42df5..d0a3653 100644 --- a/crates/sound/src/vhu_sound.rs +++ b/crates/sound/src/vhu_sound.rs @@ -21,6 +21,7 @@ use vmm_sys_util::{ use crate::audio_backends::{alloc_audio_backend, AudioBackend}; use crate::virtio_sound::*; use crate::{Error, Result, SoundConfig}; +use vm_memory::{Le32, Le64}; pub const SUPPORTED_FORMATS: u64 = 1 << VIRTIO_SND_PCM_FMT_U8 | 1 << VIRTIO_SND_PCM_FMT_S16 @@ -35,6 +36,30 @@ pub const SUPPORTED_RATES: u64 = 1 << VIRTIO_SND_PCM_RATE_8000 | 1 << VIRTIO_SND_PCM_RATE_44100 | 1 << VIRTIO_SND_PCM_RATE_48000; +pub const NR_STREAMS: usize = 1; + +pub struct StreamInfo { + pub features: Le32, /* 1 << VIRTIO_SND_PCM_F_XXX */ + pub formats: Le64, /* 1 << VIRTIO_SND_PCM_FMT_XXX */ + pub rates: Le64, /* 1 << VIRTIO_SND_PCM_RATE_XXX */ + pub direction: u8, + pub channels_min: u8, + pub channels_max: u8, +} + +impl StreamInfo { + pub fn output() -> Self { + Self { + features : 0.into(), + formats : SUPPORTED_FORMATS.into(), + rates : SUPPORTED_RATES.into(), + direction : VIRTIO_SND_D_OUTPUT, + channels_min : 1, + channels_max : 6, + } + } +} + struct VhostUserSoundThread { mem: Option>, event_idx: bool, @@ -72,7 +97,7 @@ impl VhostUserSoundThread { Ok(()) } - fn handle_event(&self, device_event: u16, vrings: &[VringRwLock], audio_backend: &RwLock>) -> IoResult { + fn handle_event(&self, device_event: u16, vrings: &[VringRwLock], audio_backend: &RwLock>, stream_info: &[StreamInfo]) -> IoResult { let vring = &vrings[device_event as usize]; let queue_idx = self.queue_indexes[device_event as usize]; debug!("handle event call queue: {}", queue_idx); @@ -88,14 +113,14 @@ impl VhostUserSoundThread { // new requests on the queue. loop { vring.disable_notification().unwrap(); - self.process_control(vring)?; + self.process_control(vring, stream_info)?; if !vring.enable_notification().unwrap() { break; } } } else { // Without EVENT_IDX, a single call is enough. - self.process_control(vring)?; + self.process_control(vring, stream_info)?; } } EVENT_QUEUE_IDX => { @@ -131,7 +156,7 @@ impl VhostUserSoundThread { } /// Process the messages in the vring and dispatch replies - fn process_control(&self, vring: &VringRwLock) -> Result { + fn process_control(&self, vring: &VringRwLock, stream_info: &[StreamInfo]) -> Result { let requests: Vec = vring .get_mut() .get_queue_mut() @@ -174,6 +199,7 @@ impl VhostUserSoundThread { let response = VirtioSoundHeader { code: VIRTIO_SND_S_OK.into(), }; let mut len = desc_response.len() as u32; + let request_type = hdr_request.code.to_native(); match request_type { VIRTIO_SND_R_JACK_INFO => todo!(), @@ -192,42 +218,51 @@ impl VhostUserSoundThread { let start_id: usize = u32::from(query_info.start_id) as usize; let count: usize = u32::from(query_info.count) as usize; - let mut pcm_info = vec![VirtioSoundPcmInfo::default(); count]; - for pcm in &mut pcm_info { - pcm.hdr.hda_fn_nid = 0.into(); - pcm.features = 0.into(); - pcm.formats = SUPPORTED_FORMATS.into(); - pcm.rates = SUPPORTED_RATES.into(); - pcm.direction = VIRTIO_SND_D_OUTPUT; - pcm.channels_min = 1; - pcm.channels_max = 6; - pcm.padding = [0; 5]; - } - if start_id + count > pcm_info.len() { + + if start_id + count > stream_info.len() { error!( "start_id({}) + count({}) must be smaller than the number of streams ({})", start_id, count, - pcm_info.len() + stream_info.len() ); desc_chain .memory() .write_obj(VIRTIO_SND_S_BAD_MSG, desc_response.addr()) .map_err(|_| Error::DescriptorWriteFailed)?; - } - desc_chain - .memory() - .write_obj(response, desc_response.addr()) - .map_err(|_| Error::DescriptorWriteFailed)?; - //let mut len = desc_response.len() as u32; - - for i in start_id..(start_id + count) { + } else { desc_chain .memory() - .write_slice(pcm_info[i].as_slice(), desc_pcm.addr()) + .write_obj(response, desc_response.addr()) .map_err(|_| Error::DescriptorWriteFailed)?; + + let mut buf = vec![]; + + for i in start_id..start_id+count { + let pcm_info = VirtioSoundPcmInfo { + hdr : VirtioSoundInfo { + hda_fn_nid : Le32::from(i as u32) + }, + features : stream_info[i].features, + formats : stream_info[i].formats, + rates : stream_info[i].rates, + direction : stream_info[i].direction, + channels_min : stream_info[i].channels_min, + channels_max : stream_info[i].channels_max, + padding : [0; 5] + }; + buf.extend_from_slice(pcm_info.as_slice()); + }; + + // TODO: to support the case when the number of items + // do not fit in a single descriptor + desc_chain + .memory() + .write_slice(&buf, desc_pcm.addr()) + .map_err(|_| Error::DescriptorWriteFailed)?; + + len += desc_pcm.len(); } - len += desc_pcm.len(); }, VIRTIO_SND_R_CHMAP_INFO => todo!(), VIRTIO_SND_R_JACK_REMAP => todo!(), @@ -424,7 +459,8 @@ pub struct VhostUserSoundBackend { threads: Vec>, virtio_cfg: VirtioSoundConfig, exit_event: EventFd, - _audio_backend: RwLock>, + audio_backend: RwLock>, + streams_info: Vec } type SndDescriptorChain = DescriptorChain>>; @@ -451,15 +487,22 @@ impl VhostUserSoundBackend { let audio_backend = alloc_audio_backend(config.audio_backend_name)?; + let mut streams = Vec::::with_capacity(NR_STREAMS); + + let stream_out_info = StreamInfo::output(); + // TODO: to add a input stream + streams.push(stream_out_info); + Ok(Self { threads, virtio_cfg: VirtioSoundConfig { jacks: 0.into(), - streams: 1.into(), + streams: Le32::from(streams.len() as u32), chmaps: 0.into(), }, + streams_info: streams, exit_event: EventFd::new(EFD_NONBLOCK).map_err(Error::EventFdCreate)?, - _audio_backend: RwLock::new(audio_backend), + audio_backend: RwLock::new(audio_backend), }) } @@ -517,7 +560,7 @@ impl VhostUserBackend for VhostUserSoundBackend { self.threads[thread_id] .read() .unwrap() - .handle_event(device_event, vrings, &self._audio_backend) + .handle_event(device_event, vrings, &self.audio_backend, &self.streams_info) } fn get_config(&self, offset: u32, size: u32) -> Vec {