mirror of
https://github.com/rust-vmm/vhost-device.git
synced 2025-12-28 08:01:04 +00:00
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 <mvaralar@redhat.com>
This commit is contained in:
parent
4cf4e675ff
commit
b3b83c1f41
@ -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 {}
|
||||
|
||||
|
||||
@ -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 {
|
||||
|
||||
@ -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<GuestMemoryAtomic<GuestMemoryMmap>>,
|
||||
event_idx: bool,
|
||||
@ -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);
|
||||
@ -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<bool> {
|
||||
fn process_control(&self, vring: &VringRwLock, stream_info: &[StreamInfo]) -> Result<bool> {
|
||||
let requests: Vec<SndDescriptorChain> = 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<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<()>>>;
|
||||
@ -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),
|
||||
})
|
||||
}
|
||||
|
||||
@ -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> {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user