Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
google
GitHub Repository: google/crosvm
Path: blob/main/devices/src/virtio/vhost_user_backend/snd/sys/windows.rs
5394 views
1
// Copyright 2023 The ChromiumOS Authors
2
// Use of this source code is governed by a BSD-style license that can be
3
// found in the LICENSE file.
4
5
use anyhow::bail;
6
use anyhow::Context;
7
use argh::FromArgs;
8
use base::info;
9
use base::warn;
10
use base::Event;
11
use base::RawDescriptor;
12
use base::Tube;
13
use cros_async::Executor;
14
use proc_init::common_child_setup;
15
use proc_init::CommonChildStartupArgs;
16
use serde::Deserialize;
17
use serde::Serialize;
18
use tube_transporter::TubeToken;
19
20
use crate::virtio::snd::parameters::Parameters;
21
use crate::virtio::snd::sys::set_audio_thread_priority;
22
use crate::virtio::vhost_user_backend::handler::sys::windows::read_from_tube_transporter;
23
use crate::virtio::vhost_user_backend::handler::sys::windows::run_handler;
24
use crate::virtio::vhost_user_backend::snd::SndBackend;
25
use crate::virtio::vhost_user_backend::VhostUserDeviceBuilder;
26
27
pub mod generic;
28
pub use generic as product;
29
30
#[derive(FromArgs, Debug)]
31
#[argh(subcommand, name = "snd", description = "")]
32
pub struct Options {
33
#[argh(
34
option,
35
description = "pipe handle end for Tube Transporter",
36
arg_name = "HANDLE"
37
)]
38
bootstrap: usize,
39
}
40
41
/// Main process end for a sound device.
42
#[derive(Deserialize, Serialize)]
43
pub struct SndVmmConfig {
44
// Tube for setting up the vhost-user connection. May not exist if not using vhost-user.
45
pub main_vhost_user_tube: Option<Tube>,
46
// GUID that will be passed into `IAudioClient::Initialize`.
47
pub audio_client_guid: String,
48
// Used to identify the device backend.
49
pub card_index: usize,
50
// Product related configuration.
51
pub product_config: product::SndVmmConfig,
52
}
53
54
/// Config arguments passed through the bootstrap Tube from the broker to the Snd backend
55
/// process.
56
#[derive(Deserialize, Serialize)]
57
pub struct SndBackendConfig {
58
// Tube for setting up the vhost-user connection. May not exist if not using vhost-user.
59
pub device_vhost_user_tube: Option<Tube>,
60
// An event for an incoming exit request.
61
pub exit_event: Event,
62
// Sound device parameters.
63
pub parameters: Parameters,
64
// This field is used to pass this GUID to `IAudioClient::Initialize`.
65
pub audio_client_guid: String,
66
// Used to append to logs in the vhost user device backends.
67
pub card_index: usize,
68
// Product related configuration.
69
pub product_config: product::SndBackendConfig,
70
}
71
72
/// Configuration for running a Snd device, split by a part sent to the main VMM and a part sent to
73
/// where the Snd worker will be running (either main process or a vhost-user process).
74
#[derive(Deserialize, Serialize)]
75
pub struct SndSplitConfig {
76
// Config sent to the backend.
77
pub backend_config: Option<SndBackendConfig>,
78
// Config sent to the main process.
79
pub vmm_config: Option<SndVmmConfig>,
80
}
81
82
/// Starts a vhost-user snd device.
83
/// Returns an error if the given `args` is invalid or the device fails to run.
84
pub fn run_snd_device(opts: Options) -> anyhow::Result<()> {
85
let raw_transport_tube = opts.bootstrap as RawDescriptor;
86
87
let mut tubes = read_from_tube_transporter(raw_transport_tube)?;
88
89
let bootstrap_tube = tubes.get_tube(TubeToken::Bootstrap)?;
90
91
let startup_args: CommonChildStartupArgs = bootstrap_tube.recv::<CommonChildStartupArgs>()?;
92
let _child_cleanup = common_child_setup(startup_args)?;
93
94
let mut config: SndBackendConfig = bootstrap_tube
95
.recv()
96
.context("failed to parse Snd backend config from bootstrap tube")?;
97
98
// TODO(b/213170185): Uncomment once sandbox is upstreamed.
99
// if sandbox::is_sandbox_target() {
100
// sandbox::TargetServices::get()
101
// .expect("failed to get target services")
102
// .unwrap()
103
// .lower_token();
104
// }
105
106
run_snd_device_worker(config)
107
}
108
109
/// Run the SND device worker.
110
pub fn run_snd_device_worker(config: SndBackendConfig) -> anyhow::Result<()> {
111
let card_index = config.card_index;
112
let vhost_user_tube = config
113
.device_vhost_user_tube
114
.unwrap_or_else(|| panic!("[Card {card_index}] vhost-user Snd tube must be set"));
115
116
let ex = Executor::new()
117
.with_context(|| format!("[Card {card_index}] Failed to create executor"))?;
118
119
let snd_device = Box::new(SndBackend::new(
120
&ex,
121
config.parameters,
122
Some(config.audio_client_guid),
123
config.card_index,
124
)?);
125
126
// Set the audio thread priority here. This assumes our executor is running on a single thread.
127
let _thread_priority_handle = set_audio_thread_priority();
128
if let Err(e) = _thread_priority_handle {
129
warn!(
130
"[Card {}] Failed to set audio thread to real time: {}",
131
card_index, e
132
);
133
};
134
135
let handler = snd_device.build(&ex)?;
136
137
info!(
138
"[Card {}] vhost-user snd device ready, starting run loop...",
139
card_index
140
);
141
ex.run_until(run_handler(
142
handler,
143
vhost_user_tube,
144
config.exit_event,
145
&ex,
146
))
147
.context("run_until error")?
148
.context("run_handler error")
149
}
150
151