Path: blob/main/devices/src/virtio/vhost_user_backend/snd/sys/windows.rs
5394 views
// Copyright 2023 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34use anyhow::bail;5use anyhow::Context;6use argh::FromArgs;7use base::info;8use base::warn;9use base::Event;10use base::RawDescriptor;11use base::Tube;12use cros_async::Executor;13use proc_init::common_child_setup;14use proc_init::CommonChildStartupArgs;15use serde::Deserialize;16use serde::Serialize;17use tube_transporter::TubeToken;1819use crate::virtio::snd::parameters::Parameters;20use crate::virtio::snd::sys::set_audio_thread_priority;21use crate::virtio::vhost_user_backend::handler::sys::windows::read_from_tube_transporter;22use crate::virtio::vhost_user_backend::handler::sys::windows::run_handler;23use crate::virtio::vhost_user_backend::snd::SndBackend;24use crate::virtio::vhost_user_backend::VhostUserDeviceBuilder;2526pub mod generic;27pub use generic as product;2829#[derive(FromArgs, Debug)]30#[argh(subcommand, name = "snd", description = "")]31pub struct Options {32#[argh(33option,34description = "pipe handle end for Tube Transporter",35arg_name = "HANDLE"36)]37bootstrap: usize,38}3940/// Main process end for a sound device.41#[derive(Deserialize, Serialize)]42pub struct SndVmmConfig {43// Tube for setting up the vhost-user connection. May not exist if not using vhost-user.44pub main_vhost_user_tube: Option<Tube>,45// GUID that will be passed into `IAudioClient::Initialize`.46pub audio_client_guid: String,47// Used to identify the device backend.48pub card_index: usize,49// Product related configuration.50pub product_config: product::SndVmmConfig,51}5253/// Config arguments passed through the bootstrap Tube from the broker to the Snd backend54/// process.55#[derive(Deserialize, Serialize)]56pub struct SndBackendConfig {57// Tube for setting up the vhost-user connection. May not exist if not using vhost-user.58pub device_vhost_user_tube: Option<Tube>,59// An event for an incoming exit request.60pub exit_event: Event,61// Sound device parameters.62pub parameters: Parameters,63// This field is used to pass this GUID to `IAudioClient::Initialize`.64pub audio_client_guid: String,65// Used to append to logs in the vhost user device backends.66pub card_index: usize,67// Product related configuration.68pub product_config: product::SndBackendConfig,69}7071/// Configuration for running a Snd device, split by a part sent to the main VMM and a part sent to72/// where the Snd worker will be running (either main process or a vhost-user process).73#[derive(Deserialize, Serialize)]74pub struct SndSplitConfig {75// Config sent to the backend.76pub backend_config: Option<SndBackendConfig>,77// Config sent to the main process.78pub vmm_config: Option<SndVmmConfig>,79}8081/// Starts a vhost-user snd device.82/// Returns an error if the given `args` is invalid or the device fails to run.83pub fn run_snd_device(opts: Options) -> anyhow::Result<()> {84let raw_transport_tube = opts.bootstrap as RawDescriptor;8586let mut tubes = read_from_tube_transporter(raw_transport_tube)?;8788let bootstrap_tube = tubes.get_tube(TubeToken::Bootstrap)?;8990let startup_args: CommonChildStartupArgs = bootstrap_tube.recv::<CommonChildStartupArgs>()?;91let _child_cleanup = common_child_setup(startup_args)?;9293let mut config: SndBackendConfig = bootstrap_tube94.recv()95.context("failed to parse Snd backend config from bootstrap tube")?;9697// TODO(b/213170185): Uncomment once sandbox is upstreamed.98// if sandbox::is_sandbox_target() {99// sandbox::TargetServices::get()100// .expect("failed to get target services")101// .unwrap()102// .lower_token();103// }104105run_snd_device_worker(config)106}107108/// Run the SND device worker.109pub fn run_snd_device_worker(config: SndBackendConfig) -> anyhow::Result<()> {110let card_index = config.card_index;111let vhost_user_tube = config112.device_vhost_user_tube113.unwrap_or_else(|| panic!("[Card {card_index}] vhost-user Snd tube must be set"));114115let ex = Executor::new()116.with_context(|| format!("[Card {card_index}] Failed to create executor"))?;117118let snd_device = Box::new(SndBackend::new(119&ex,120config.parameters,121Some(config.audio_client_guid),122config.card_index,123)?);124125// Set the audio thread priority here. This assumes our executor is running on a single thread.126let _thread_priority_handle = set_audio_thread_priority();127if let Err(e) = _thread_priority_handle {128warn!(129"[Card {}] Failed to set audio thread to real time: {}",130card_index, e131);132};133134let handler = snd_device.build(&ex)?;135136info!(137"[Card {}] vhost-user snd device ready, starting run loop...",138card_index139);140ex.run_until(run_handler(141handler,142vhost_user_tube,143config.exit_event,144&ex,145))146.context("run_until error")?147.context("run_handler error")148}149150151