blob: 0c4a6c92ab86b30c8d95a896e11572e614d3990d [file] [log] [blame]
// Copyright 2022 The ChromiumOS Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
use async_trait::async_trait;
use audio_streams::AsyncPlaybackBufferStream;
use audio_streams::StreamSource;
use audio_streams::StreamSourceGenerator;
#[cfg(feature = "audio_cras")]
use base::error;
use base::set_rt_prio_limit;
use base::set_rt_round_robin;
use cros_async::Executor;
use futures::channel::mpsc::UnboundedSender;
#[cfg(feature = "audio_cras")]
use libcras::CrasStreamSourceGenerator;
#[cfg(feature = "audio_cras")]
use libcras::CrasStreamType;
use serde::Deserialize;
use serde::Serialize;
use crate::virtio::common_backend::PcmResponse;
use crate::virtio::snd::common_backend::async_funcs::PlaybackBufferWriter;
use crate::virtio::snd::common_backend::stream_info::StreamInfo;
use crate::virtio::snd::common_backend::DirectionalStream;
use crate::virtio::snd::common_backend::Error;
use crate::virtio::snd::common_backend::SndData;
use crate::virtio::snd::parameters::Error as ParametersError;
use crate::virtio::snd::parameters::Parameters;
const AUDIO_THREAD_RTPRIO: u16 = 10; // Matches other cros audio clients.
pub(crate) type SysAudioStreamSourceGenerator = Box<dyn StreamSourceGenerator>;
pub(crate) type SysAudioStreamSource = Box<dyn StreamSource>;
pub(crate) type SysBufferWriter = UnixBufferWriter;
pub(crate) struct SysAsyncStream {
pub(crate) async_playback_buffer_stream: Box<dyn AsyncPlaybackBufferStream>,
}
pub(crate) struct SysAsyncStreamObjects {
pub(crate) stream: DirectionalStream,
pub(crate) pcm_sender: UnboundedSender<PcmResponse>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
pub enum StreamSourceBackend {
#[cfg(feature = "audio_cras")]
CRAS,
}
// Implemented to make backend serialization possible, since we deserialize from str.
impl From<StreamSourceBackend> for String {
fn from(backend: StreamSourceBackend) -> Self {
match backend {
#[cfg(feature = "audio_cras")]
StreamSourceBackend::CRAS => "cras".to_owned(),
}
}
}
impl TryFrom<&str> for StreamSourceBackend {
type Error = ParametersError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
match s {
#[cfg(feature = "audio_cras")]
"cras" => Ok(StreamSourceBackend::CRAS),
_ => Err(ParametersError::InvalidBackend),
}
}
}
#[cfg(feature = "audio_cras")]
pub(crate) fn create_cras_stream_source_generators(
params: &Parameters,
snd_data: &SndData,
) -> Vec<Box<dyn StreamSourceGenerator>> {
let mut generators: Vec<Box<dyn StreamSourceGenerator>> =
Vec::with_capacity(snd_data.pcm_info_len());
for pcm_info in snd_data.pcm_info_iter() {
let device_params = params.get_device_params(pcm_info).unwrap_or_else(|err| {
error!("Create cras stream source generator error: {}", err);
Default::default()
});
generators.push(Box::new(CrasStreamSourceGenerator::with_stream_type(
params.capture,
device_params.client_type.unwrap_or(params.client_type),
params.socket_type,
device_params
.stream_type
.unwrap_or(CrasStreamType::CRAS_STREAM_TYPE_DEFAULT),
)));
}
generators
}
#[allow(unused_variables)]
pub(crate) fn create_stream_source_generators(
backend: StreamSourceBackend,
params: &Parameters,
snd_data: &SndData,
) -> Vec<Box<dyn StreamSourceGenerator>> {
match backend {
#[cfg(feature = "audio_cras")]
StreamSourceBackend::CRAS => create_cras_stream_source_generators(params, snd_data),
}
}
pub(crate) fn set_audio_thread_priority() -> Result<(), base::Error> {
set_rt_prio_limit(u64::from(AUDIO_THREAD_RTPRIO))
.and_then(|_| set_rt_round_robin(i32::from(AUDIO_THREAD_RTPRIO)))
}
impl StreamInfo {
/// (*)
/// `buffer_size` in `audio_streams` API indicates the buffer size in bytes that the stream
/// consumes (or transmits) each time (next_playback/capture_buffer).
/// `period_bytes` in virtio-snd device (or ALSA) indicates the device transmits (or
/// consumes) for each PCM message.
/// Therefore, `buffer_size` in `audio_streams` == `period_bytes` in virtio-snd.
pub(crate) async fn set_up_async_playback_stream(
&mut self,
frame_size: usize,
ex: &Executor,
) -> Result<SysAsyncStream, Error> {
Ok(SysAsyncStream {
async_playback_buffer_stream: self
.stream_source
.as_mut()
.ok_or(Error::EmptyStreamSource)?
.async_new_async_playback_stream(
self.channels as usize,
self.format,
self.frame_rate,
// See (*)
self.period_bytes / frame_size,
ex,
)
.await
.map_err(Error::CreateStream)?
.1,
})
}
}
pub(crate) struct UnixBufferWriter {
guest_period_bytes: usize,
}
#[async_trait(?Send)]
impl PlaybackBufferWriter for UnixBufferWriter {
fn new(guest_period_bytes: usize) -> Self {
UnixBufferWriter { guest_period_bytes }
}
fn endpoint_period_bytes(&self) -> usize {
self.guest_period_bytes
}
}