Skip to content
This repository has been archived by the owner on Oct 25, 2023. It is now read-only.

Commit

Permalink
Sound: initialize StreamInfo
Browse files Browse the repository at this point in the history
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 <mvaralar@redhat.com>
  • Loading branch information
MatiasVara committed Jul 5, 2023
1 parent 4cf4e67 commit b3b83c1
Show file tree
Hide file tree
Showing 3 changed files with 77 additions and 45 deletions.
2 changes: 1 addition & 1 deletion crates/sound/src/audio_backends/null.rs
Original file line number Diff line number Diff line change
@@ -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 {}

Expand Down
17 changes: 3 additions & 14 deletions crates/sound/src/audio_backends/pw_backend.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
103 changes: 73 additions & 30 deletions crates/sound/src/vhu_sound.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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<GuestMemoryAtomic<GuestMemoryMmap>>,
event_idx: bool,
Expand Down Expand Up @@ -72,7 +97,7 @@ impl VhostUserSoundThread {
Ok(())
}

fn handle_event(&self, device_event: u16, vrings: &[VringRwLock], audio_backend: &RwLock<Box<dyn AudioBackend + Send + Sync>>) -> IoResult<bool> {
fn handle_event(&self, device_event: u16, vrings: &[VringRwLock], audio_backend: &RwLock<Box<dyn AudioBackend + Send + Sync>>, stream_info: &[StreamInfo]) -> IoResult<bool> {
let vring = &vrings[device_event as usize];
let queue_idx = self.queue_indexes[device_event as usize];
debug!("handle event call queue: {}", queue_idx);
Expand All @@ -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 => {
Expand Down Expand Up @@ -131,7 +156,7 @@ impl VhostUserSoundThread {
}

/// Process the messages in the vring and dispatch replies
fn process_control(&self, vring: &VringRwLock) -> Result<bool> {
fn process_control(&self, vring: &VringRwLock, stream_info: &[StreamInfo]) -> Result<bool> {
let requests: Vec<SndDescriptorChain> = vring
.get_mut()
.get_queue_mut()
Expand Down Expand Up @@ -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!(),
Expand All @@ -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;
} else {
desc_chain
.memory()
.write_obj(response, desc_response.addr())
.map_err(|_| Error::DescriptorWriteFailed)?;

for i in start_id..(start_id + count) {
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(pcm_info[i].as_slice(), desc_pcm.addr())
.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!(),
Expand Down Expand Up @@ -424,7 +459,8 @@ pub struct VhostUserSoundBackend {
threads: Vec<RwLock<VhostUserSoundThread>>,
virtio_cfg: VirtioSoundConfig,
exit_event: EventFd,
_audio_backend: RwLock<Box<dyn AudioBackend + Send + Sync>>,
audio_backend: RwLock<Box<dyn AudioBackend + Send + Sync>>,
streams_info: Vec<StreamInfo>
}

type SndDescriptorChain = DescriptorChain<GuestMemoryLoadGuard<GuestMemoryMmap<()>>>;
Expand All @@ -451,15 +487,22 @@ impl VhostUserSoundBackend {

let audio_backend = alloc_audio_backend(config.audio_backend_name)?;

let mut streams = Vec::<StreamInfo>::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),
})
}

Expand Down Expand Up @@ -517,7 +560,7 @@ impl VhostUserBackend<VringRwLock, ()> 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<u8> {
Expand Down

0 comments on commit b3b83c1

Please sign in to comment.