xref: /aosp_15_r20/external/crosvm/devices/src/virtio/snd/parameters.rs (revision bb4ee6a4ae7042d18b07a98463b9c8b875e44b39)
1*bb4ee6a4SAndroid Build Coastguard Worker // Copyright 2022 The ChromiumOS Authors
2*bb4ee6a4SAndroid Build Coastguard Worker // Use of this source code is governed by a BSD-style license that can be
3*bb4ee6a4SAndroid Build Coastguard Worker // found in the LICENSE file.
4*bb4ee6a4SAndroid Build Coastguard Worker 
5*bb4ee6a4SAndroid Build Coastguard Worker use std::num::ParseIntError;
6*bb4ee6a4SAndroid Build Coastguard Worker use std::str::ParseBoolError;
7*bb4ee6a4SAndroid Build Coastguard Worker 
8*bb4ee6a4SAndroid Build Coastguard Worker use audio_streams::StreamEffect;
9*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(all(unix, feature = "audio_cras"))]
10*bb4ee6a4SAndroid Build Coastguard Worker use libcras::CrasClientType;
11*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(all(unix, feature = "audio_cras"))]
12*bb4ee6a4SAndroid Build Coastguard Worker use libcras::CrasSocketType;
13*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(all(unix, feature = "audio_cras"))]
14*bb4ee6a4SAndroid Build Coastguard Worker use libcras::CrasStreamType;
15*bb4ee6a4SAndroid Build Coastguard Worker use serde::Deserialize;
16*bb4ee6a4SAndroid Build Coastguard Worker use serde::Serialize;
17*bb4ee6a4SAndroid Build Coastguard Worker use serde_keyvalue::FromKeyValues;
18*bb4ee6a4SAndroid Build Coastguard Worker use thiserror::Error as ThisError;
19*bb4ee6a4SAndroid Build Coastguard Worker 
20*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::snd::constants::*;
21*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::snd::layout::*;
22*bb4ee6a4SAndroid Build Coastguard Worker use crate::virtio::snd::sys::StreamSourceBackend as SysStreamSourceBackend;
23*bb4ee6a4SAndroid Build Coastguard Worker 
24*bb4ee6a4SAndroid Build Coastguard Worker #[derive(ThisError, Debug, PartialEq, Eq)]
25*bb4ee6a4SAndroid Build Coastguard Worker pub enum Error {
26*bb4ee6a4SAndroid Build Coastguard Worker     /// Unknown snd parameter value.
27*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Invalid snd parameter value ({0}): {1}")]
28*bb4ee6a4SAndroid Build Coastguard Worker     InvalidParameterValue(String, String),
29*bb4ee6a4SAndroid Build Coastguard Worker     /// Failed to parse bool value.
30*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Invalid bool value: {0}")]
31*bb4ee6a4SAndroid Build Coastguard Worker     InvalidBoolValue(ParseBoolError),
32*bb4ee6a4SAndroid Build Coastguard Worker     /// Failed to parse int value.
33*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Invalid int value: {0}")]
34*bb4ee6a4SAndroid Build Coastguard Worker     InvalidIntValue(ParseIntError),
35*bb4ee6a4SAndroid Build Coastguard Worker     // Invalid backend.
36*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Backend is not implemented")]
37*bb4ee6a4SAndroid Build Coastguard Worker     InvalidBackend,
38*bb4ee6a4SAndroid Build Coastguard Worker     /// Failed to parse parameters.
39*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Invalid snd parameter: {0}")]
40*bb4ee6a4SAndroid Build Coastguard Worker     UnknownParameter(String),
41*bb4ee6a4SAndroid Build Coastguard Worker     /// Invalid PCM device config index. Happens when the length of PCM device config is less than
42*bb4ee6a4SAndroid Build Coastguard Worker     /// the number of PCM devices.
43*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Invalid PCM device config index: {0}")]
44*bb4ee6a4SAndroid Build Coastguard Worker     InvalidPCMDeviceConfigIndex(usize),
45*bb4ee6a4SAndroid Build Coastguard Worker     /// Invalid PCM info direction (VIRTIO_SND_D_OUTPUT = 0, VIRTIO_SND_D_INPUT = 1)
46*bb4ee6a4SAndroid Build Coastguard Worker     #[error("Invalid PCM Info direction: {0}")]
47*bb4ee6a4SAndroid Build Coastguard Worker     InvalidPCMInfoDirection(u8),
48*bb4ee6a4SAndroid Build Coastguard Worker }
49*bb4ee6a4SAndroid Build Coastguard Worker 
50*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
51*bb4ee6a4SAndroid Build Coastguard Worker #[serde(into = "String", try_from = "&str")]
52*bb4ee6a4SAndroid Build Coastguard Worker pub enum StreamSourceBackend {
53*bb4ee6a4SAndroid Build Coastguard Worker     NULL,
54*bb4ee6a4SAndroid Build Coastguard Worker     FILE,
55*bb4ee6a4SAndroid Build Coastguard Worker     Sys(SysStreamSourceBackend),
56*bb4ee6a4SAndroid Build Coastguard Worker }
57*bb4ee6a4SAndroid Build Coastguard Worker 
58*bb4ee6a4SAndroid Build Coastguard Worker // Implemented to make backend serialization possible, since we deserialize from str.
59*bb4ee6a4SAndroid Build Coastguard Worker impl From<StreamSourceBackend> for String {
from(backend: StreamSourceBackend) -> Self60*bb4ee6a4SAndroid Build Coastguard Worker     fn from(backend: StreamSourceBackend) -> Self {
61*bb4ee6a4SAndroid Build Coastguard Worker         match backend {
62*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::NULL => "null".to_owned(),
63*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::FILE => "file".to_owned(),
64*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::Sys(sys_backend) => sys_backend.into(),
65*bb4ee6a4SAndroid Build Coastguard Worker         }
66*bb4ee6a4SAndroid Build Coastguard Worker     }
67*bb4ee6a4SAndroid Build Coastguard Worker }
68*bb4ee6a4SAndroid Build Coastguard Worker 
69*bb4ee6a4SAndroid Build Coastguard Worker impl TryFrom<&str> for StreamSourceBackend {
70*bb4ee6a4SAndroid Build Coastguard Worker     type Error = Error;
71*bb4ee6a4SAndroid Build Coastguard Worker 
try_from(s: &str) -> Result<Self, Self::Error>72*bb4ee6a4SAndroid Build Coastguard Worker     fn try_from(s: &str) -> Result<Self, Self::Error> {
73*bb4ee6a4SAndroid Build Coastguard Worker         match s {
74*bb4ee6a4SAndroid Build Coastguard Worker             "null" => Ok(StreamSourceBackend::NULL),
75*bb4ee6a4SAndroid Build Coastguard Worker             "file" => Ok(StreamSourceBackend::FILE),
76*bb4ee6a4SAndroid Build Coastguard Worker             _ => SysStreamSourceBackend::try_from(s).map(StreamSourceBackend::Sys),
77*bb4ee6a4SAndroid Build Coastguard Worker         }
78*bb4ee6a4SAndroid Build Coastguard Worker     }
79*bb4ee6a4SAndroid Build Coastguard Worker }
80*bb4ee6a4SAndroid Build Coastguard Worker 
81*bb4ee6a4SAndroid Build Coastguard Worker /// Holds the parameters for each PCM device
82*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Default, Deserialize, Serialize, FromKeyValues, PartialEq, Eq)]
83*bb4ee6a4SAndroid Build Coastguard Worker #[serde(deny_unknown_fields, default)]
84*bb4ee6a4SAndroid Build Coastguard Worker pub struct PCMDeviceParameters {
85*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(all(unix, feature = "audio_cras"))]
86*bb4ee6a4SAndroid Build Coastguard Worker     pub client_type: Option<CrasClientType>,
87*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(all(unix, feature = "audio_cras"))]
88*bb4ee6a4SAndroid Build Coastguard Worker     pub stream_type: Option<CrasStreamType>,
89*bb4ee6a4SAndroid Build Coastguard Worker     pub effects: Option<Vec<StreamEffect>>,
90*bb4ee6a4SAndroid Build Coastguard Worker }
91*bb4ee6a4SAndroid Build Coastguard Worker 
92*bb4ee6a4SAndroid Build Coastguard Worker /// Holds the parameters for a cras sound device
93*bb4ee6a4SAndroid Build Coastguard Worker #[derive(Debug, Clone, Deserialize, Serialize, FromKeyValues)]
94*bb4ee6a4SAndroid Build Coastguard Worker #[serde(deny_unknown_fields, default)]
95*bb4ee6a4SAndroid Build Coastguard Worker pub struct Parameters {
96*bb4ee6a4SAndroid Build Coastguard Worker     pub capture: bool,
97*bb4ee6a4SAndroid Build Coastguard Worker     pub num_output_devices: u32,
98*bb4ee6a4SAndroid Build Coastguard Worker     pub num_input_devices: u32,
99*bb4ee6a4SAndroid Build Coastguard Worker     pub backend: StreamSourceBackend,
100*bb4ee6a4SAndroid Build Coastguard Worker     pub num_output_streams: u32,
101*bb4ee6a4SAndroid Build Coastguard Worker     pub num_input_streams: u32,
102*bb4ee6a4SAndroid Build Coastguard Worker     pub playback_path: String,
103*bb4ee6a4SAndroid Build Coastguard Worker     pub playback_size: usize,
104*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(all(unix, feature = "audio_cras"))]
105*bb4ee6a4SAndroid Build Coastguard Worker     #[serde(deserialize_with = "libcras::deserialize_cras_client_type")]
106*bb4ee6a4SAndroid Build Coastguard Worker     pub client_type: CrasClientType,
107*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(all(unix, feature = "audio_cras"))]
108*bb4ee6a4SAndroid Build Coastguard Worker     pub socket_type: CrasSocketType,
109*bb4ee6a4SAndroid Build Coastguard Worker     pub output_device_config: Vec<PCMDeviceParameters>,
110*bb4ee6a4SAndroid Build Coastguard Worker     pub input_device_config: Vec<PCMDeviceParameters>,
111*bb4ee6a4SAndroid Build Coastguard Worker     pub card_index: usize,
112*bb4ee6a4SAndroid Build Coastguard Worker }
113*bb4ee6a4SAndroid Build Coastguard Worker 
114*bb4ee6a4SAndroid Build Coastguard Worker impl Default for Parameters {
default() -> Self115*bb4ee6a4SAndroid Build Coastguard Worker     fn default() -> Self {
116*bb4ee6a4SAndroid Build Coastguard Worker         Parameters {
117*bb4ee6a4SAndroid Build Coastguard Worker             capture: false,
118*bb4ee6a4SAndroid Build Coastguard Worker             num_output_devices: 1,
119*bb4ee6a4SAndroid Build Coastguard Worker             num_input_devices: 1,
120*bb4ee6a4SAndroid Build Coastguard Worker             backend: StreamSourceBackend::NULL,
121*bb4ee6a4SAndroid Build Coastguard Worker             num_output_streams: 1,
122*bb4ee6a4SAndroid Build Coastguard Worker             num_input_streams: 1,
123*bb4ee6a4SAndroid Build Coastguard Worker             playback_path: "".to_string(),
124*bb4ee6a4SAndroid Build Coastguard Worker             playback_size: 0,
125*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(all(unix, feature = "audio_cras"))]
126*bb4ee6a4SAndroid Build Coastguard Worker             client_type: CrasClientType::CRAS_CLIENT_TYPE_CROSVM,
127*bb4ee6a4SAndroid Build Coastguard Worker             #[cfg(all(unix, feature = "audio_cras"))]
128*bb4ee6a4SAndroid Build Coastguard Worker             socket_type: CrasSocketType::Unified,
129*bb4ee6a4SAndroid Build Coastguard Worker             output_device_config: vec![],
130*bb4ee6a4SAndroid Build Coastguard Worker             input_device_config: vec![],
131*bb4ee6a4SAndroid Build Coastguard Worker             card_index: 0,
132*bb4ee6a4SAndroid Build Coastguard Worker         }
133*bb4ee6a4SAndroid Build Coastguard Worker     }
134*bb4ee6a4SAndroid Build Coastguard Worker }
135*bb4ee6a4SAndroid Build Coastguard Worker 
136*bb4ee6a4SAndroid Build Coastguard Worker impl Parameters {
get_total_output_streams(&self) -> u32137*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) fn get_total_output_streams(&self) -> u32 {
138*bb4ee6a4SAndroid Build Coastguard Worker         self.num_output_devices * self.num_output_streams
139*bb4ee6a4SAndroid Build Coastguard Worker     }
140*bb4ee6a4SAndroid Build Coastguard Worker 
get_total_input_streams(&self) -> u32141*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) fn get_total_input_streams(&self) -> u32 {
142*bb4ee6a4SAndroid Build Coastguard Worker         self.num_input_devices * self.num_input_streams
143*bb4ee6a4SAndroid Build Coastguard Worker     }
144*bb4ee6a4SAndroid Build Coastguard Worker 
get_total_streams(&self) -> u32145*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) fn get_total_streams(&self) -> u32 {
146*bb4ee6a4SAndroid Build Coastguard Worker         self.get_total_output_streams() + self.get_total_input_streams()
147*bb4ee6a4SAndroid Build Coastguard Worker     }
148*bb4ee6a4SAndroid Build Coastguard Worker 
149*bb4ee6a4SAndroid Build Coastguard Worker     #[allow(dead_code)]
get_device_params( &self, pcm_info: &virtio_snd_pcm_info, ) -> Result<PCMDeviceParameters, Error>150*bb4ee6a4SAndroid Build Coastguard Worker     pub(crate) fn get_device_params(
151*bb4ee6a4SAndroid Build Coastguard Worker         &self,
152*bb4ee6a4SAndroid Build Coastguard Worker         pcm_info: &virtio_snd_pcm_info,
153*bb4ee6a4SAndroid Build Coastguard Worker     ) -> Result<PCMDeviceParameters, Error> {
154*bb4ee6a4SAndroid Build Coastguard Worker         let device_config = match pcm_info.direction {
155*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_SND_D_OUTPUT => &self.output_device_config,
156*bb4ee6a4SAndroid Build Coastguard Worker             VIRTIO_SND_D_INPUT => &self.input_device_config,
157*bb4ee6a4SAndroid Build Coastguard Worker             _ => return Err(Error::InvalidPCMInfoDirection(pcm_info.direction)),
158*bb4ee6a4SAndroid Build Coastguard Worker         };
159*bb4ee6a4SAndroid Build Coastguard Worker         let device_idx = u32::from(pcm_info.hdr.hda_fn_nid) as usize;
160*bb4ee6a4SAndroid Build Coastguard Worker         device_config
161*bb4ee6a4SAndroid Build Coastguard Worker             .get(device_idx)
162*bb4ee6a4SAndroid Build Coastguard Worker             .cloned()
163*bb4ee6a4SAndroid Build Coastguard Worker             .ok_or(Error::InvalidPCMDeviceConfigIndex(device_idx))
164*bb4ee6a4SAndroid Build Coastguard Worker     }
165*bb4ee6a4SAndroid Build Coastguard Worker }
166*bb4ee6a4SAndroid Build Coastguard Worker 
167*bb4ee6a4SAndroid Build Coastguard Worker #[cfg(test)]
168*bb4ee6a4SAndroid Build Coastguard Worker #[allow(clippy::needless_update)]
169*bb4ee6a4SAndroid Build Coastguard Worker mod tests {
170*bb4ee6a4SAndroid Build Coastguard Worker     use super::*;
171*bb4ee6a4SAndroid Build Coastguard Worker 
check_failure(s: &str)172*bb4ee6a4SAndroid Build Coastguard Worker     fn check_failure(s: &str) {
173*bb4ee6a4SAndroid Build Coastguard Worker         serde_keyvalue::from_key_values::<Parameters>(s).expect_err("parse should have failed");
174*bb4ee6a4SAndroid Build Coastguard Worker     }
175*bb4ee6a4SAndroid Build Coastguard Worker 
check_success( s: &str, capture: bool, backend: StreamSourceBackend, num_output_devices: u32, num_input_devices: u32, num_output_streams: u32, num_input_streams: u32, output_device_config: Vec<PCMDeviceParameters>, input_device_config: Vec<PCMDeviceParameters>, )176*bb4ee6a4SAndroid Build Coastguard Worker     fn check_success(
177*bb4ee6a4SAndroid Build Coastguard Worker         s: &str,
178*bb4ee6a4SAndroid Build Coastguard Worker         capture: bool,
179*bb4ee6a4SAndroid Build Coastguard Worker         backend: StreamSourceBackend,
180*bb4ee6a4SAndroid Build Coastguard Worker         num_output_devices: u32,
181*bb4ee6a4SAndroid Build Coastguard Worker         num_input_devices: u32,
182*bb4ee6a4SAndroid Build Coastguard Worker         num_output_streams: u32,
183*bb4ee6a4SAndroid Build Coastguard Worker         num_input_streams: u32,
184*bb4ee6a4SAndroid Build Coastguard Worker         output_device_config: Vec<PCMDeviceParameters>,
185*bb4ee6a4SAndroid Build Coastguard Worker         input_device_config: Vec<PCMDeviceParameters>,
186*bb4ee6a4SAndroid Build Coastguard Worker     ) {
187*bb4ee6a4SAndroid Build Coastguard Worker         let params: Parameters =
188*bb4ee6a4SAndroid Build Coastguard Worker             serde_keyvalue::from_key_values(s).expect("parse should have succeded");
189*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(params.capture, capture);
190*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(params.backend, backend);
191*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(params.num_output_devices, num_output_devices);
192*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(params.num_input_devices, num_input_devices);
193*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(params.num_output_streams, num_output_streams);
194*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(params.num_input_streams, num_input_streams);
195*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(params.output_device_config, output_device_config);
196*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(params.input_device_config, input_device_config);
197*bb4ee6a4SAndroid Build Coastguard Worker     }
198*bb4ee6a4SAndroid Build Coastguard Worker 
199*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
parameters_fromstr()200*bb4ee6a4SAndroid Build Coastguard Worker     fn parameters_fromstr() {
201*bb4ee6a4SAndroid Build Coastguard Worker         check_failure("capture=none");
202*bb4ee6a4SAndroid Build Coastguard Worker         check_success(
203*bb4ee6a4SAndroid Build Coastguard Worker             "capture=false",
204*bb4ee6a4SAndroid Build Coastguard Worker             false,
205*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::NULL,
206*bb4ee6a4SAndroid Build Coastguard Worker             1,
207*bb4ee6a4SAndroid Build Coastguard Worker             1,
208*bb4ee6a4SAndroid Build Coastguard Worker             1,
209*bb4ee6a4SAndroid Build Coastguard Worker             1,
210*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
211*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
212*bb4ee6a4SAndroid Build Coastguard Worker         );
213*bb4ee6a4SAndroid Build Coastguard Worker         check_success(
214*bb4ee6a4SAndroid Build Coastguard Worker             "capture=true,num_output_streams=2,num_input_streams=3",
215*bb4ee6a4SAndroid Build Coastguard Worker             true,
216*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::NULL,
217*bb4ee6a4SAndroid Build Coastguard Worker             1,
218*bb4ee6a4SAndroid Build Coastguard Worker             1,
219*bb4ee6a4SAndroid Build Coastguard Worker             2,
220*bb4ee6a4SAndroid Build Coastguard Worker             3,
221*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
222*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
223*bb4ee6a4SAndroid Build Coastguard Worker         );
224*bb4ee6a4SAndroid Build Coastguard Worker         check_success(
225*bb4ee6a4SAndroid Build Coastguard Worker             "capture=true,num_output_devices=3,num_input_devices=2",
226*bb4ee6a4SAndroid Build Coastguard Worker             true,
227*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::NULL,
228*bb4ee6a4SAndroid Build Coastguard Worker             3,
229*bb4ee6a4SAndroid Build Coastguard Worker             2,
230*bb4ee6a4SAndroid Build Coastguard Worker             1,
231*bb4ee6a4SAndroid Build Coastguard Worker             1,
232*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
233*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
234*bb4ee6a4SAndroid Build Coastguard Worker         );
235*bb4ee6a4SAndroid Build Coastguard Worker         check_success(
236*bb4ee6a4SAndroid Build Coastguard Worker             "capture=true,num_output_devices=2,num_input_devices=3,\
237*bb4ee6a4SAndroid Build Coastguard Worker             num_output_streams=3,num_input_streams=2",
238*bb4ee6a4SAndroid Build Coastguard Worker             true,
239*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::NULL,
240*bb4ee6a4SAndroid Build Coastguard Worker             2,
241*bb4ee6a4SAndroid Build Coastguard Worker             3,
242*bb4ee6a4SAndroid Build Coastguard Worker             3,
243*bb4ee6a4SAndroid Build Coastguard Worker             2,
244*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
245*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
246*bb4ee6a4SAndroid Build Coastguard Worker         );
247*bb4ee6a4SAndroid Build Coastguard Worker         check_success(
248*bb4ee6a4SAndroid Build Coastguard Worker             "capture=true,backend=null,num_output_devices=2,num_input_devices=3,\
249*bb4ee6a4SAndroid Build Coastguard Worker             num_output_streams=3,num_input_streams=2",
250*bb4ee6a4SAndroid Build Coastguard Worker             true,
251*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::NULL,
252*bb4ee6a4SAndroid Build Coastguard Worker             2,
253*bb4ee6a4SAndroid Build Coastguard Worker             3,
254*bb4ee6a4SAndroid Build Coastguard Worker             3,
255*bb4ee6a4SAndroid Build Coastguard Worker             2,
256*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
257*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
258*bb4ee6a4SAndroid Build Coastguard Worker         );
259*bb4ee6a4SAndroid Build Coastguard Worker         check_success(
260*bb4ee6a4SAndroid Build Coastguard Worker             "output_device_config=[[effects=[aec]],[]]",
261*bb4ee6a4SAndroid Build Coastguard Worker             false,
262*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::NULL,
263*bb4ee6a4SAndroid Build Coastguard Worker             1,
264*bb4ee6a4SAndroid Build Coastguard Worker             1,
265*bb4ee6a4SAndroid Build Coastguard Worker             1,
266*bb4ee6a4SAndroid Build Coastguard Worker             1,
267*bb4ee6a4SAndroid Build Coastguard Worker             vec![
268*bb4ee6a4SAndroid Build Coastguard Worker                 PCMDeviceParameters {
269*bb4ee6a4SAndroid Build Coastguard Worker                     effects: Some(vec![StreamEffect::EchoCancellation]),
270*bb4ee6a4SAndroid Build Coastguard Worker                     ..Default::default()
271*bb4ee6a4SAndroid Build Coastguard Worker                 },
272*bb4ee6a4SAndroid Build Coastguard Worker                 Default::default(),
273*bb4ee6a4SAndroid Build Coastguard Worker             ],
274*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
275*bb4ee6a4SAndroid Build Coastguard Worker         );
276*bb4ee6a4SAndroid Build Coastguard Worker         check_success(
277*bb4ee6a4SAndroid Build Coastguard Worker             "input_device_config=[[effects=[aec]],[]]",
278*bb4ee6a4SAndroid Build Coastguard Worker             false,
279*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::NULL,
280*bb4ee6a4SAndroid Build Coastguard Worker             1,
281*bb4ee6a4SAndroid Build Coastguard Worker             1,
282*bb4ee6a4SAndroid Build Coastguard Worker             1,
283*bb4ee6a4SAndroid Build Coastguard Worker             1,
284*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
285*bb4ee6a4SAndroid Build Coastguard Worker             vec![
286*bb4ee6a4SAndroid Build Coastguard Worker                 PCMDeviceParameters {
287*bb4ee6a4SAndroid Build Coastguard Worker                     effects: Some(vec![StreamEffect::EchoCancellation]),
288*bb4ee6a4SAndroid Build Coastguard Worker                     ..Default::default()
289*bb4ee6a4SAndroid Build Coastguard Worker                 },
290*bb4ee6a4SAndroid Build Coastguard Worker                 Default::default(),
291*bb4ee6a4SAndroid Build Coastguard Worker             ],
292*bb4ee6a4SAndroid Build Coastguard Worker         );
293*bb4ee6a4SAndroid Build Coastguard Worker 
294*bb4ee6a4SAndroid Build Coastguard Worker         // Invalid effect in device config
295*bb4ee6a4SAndroid Build Coastguard Worker         check_failure("output_device_config=[[effects=[none]]]");
296*bb4ee6a4SAndroid Build Coastguard Worker     }
297*bb4ee6a4SAndroid Build Coastguard Worker 
298*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
299*bb4ee6a4SAndroid Build Coastguard Worker     #[cfg(all(unix, feature = "audio_cras"))]
cras_parameters_fromstr()300*bb4ee6a4SAndroid Build Coastguard Worker     fn cras_parameters_fromstr() {
301*bb4ee6a4SAndroid Build Coastguard Worker         fn cras_check_success(
302*bb4ee6a4SAndroid Build Coastguard Worker             s: &str,
303*bb4ee6a4SAndroid Build Coastguard Worker             backend: StreamSourceBackend,
304*bb4ee6a4SAndroid Build Coastguard Worker             client_type: CrasClientType,
305*bb4ee6a4SAndroid Build Coastguard Worker             socket_type: CrasSocketType,
306*bb4ee6a4SAndroid Build Coastguard Worker             output_device_config: Vec<PCMDeviceParameters>,
307*bb4ee6a4SAndroid Build Coastguard Worker             input_device_config: Vec<PCMDeviceParameters>,
308*bb4ee6a4SAndroid Build Coastguard Worker         ) {
309*bb4ee6a4SAndroid Build Coastguard Worker             let params: Parameters =
310*bb4ee6a4SAndroid Build Coastguard Worker                 serde_keyvalue::from_key_values(s).expect("parse should have succeded");
311*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(params.backend, backend);
312*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(params.client_type, client_type);
313*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(params.socket_type, socket_type);
314*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(params.output_device_config, output_device_config);
315*bb4ee6a4SAndroid Build Coastguard Worker             assert_eq!(params.input_device_config, input_device_config);
316*bb4ee6a4SAndroid Build Coastguard Worker         }
317*bb4ee6a4SAndroid Build Coastguard Worker 
318*bb4ee6a4SAndroid Build Coastguard Worker         cras_check_success(
319*bb4ee6a4SAndroid Build Coastguard Worker             "backend=cras",
320*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::Sys(SysStreamSourceBackend::CRAS),
321*bb4ee6a4SAndroid Build Coastguard Worker             CrasClientType::CRAS_CLIENT_TYPE_CROSVM,
322*bb4ee6a4SAndroid Build Coastguard Worker             CrasSocketType::Unified,
323*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
324*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
325*bb4ee6a4SAndroid Build Coastguard Worker         );
326*bb4ee6a4SAndroid Build Coastguard Worker         cras_check_success(
327*bb4ee6a4SAndroid Build Coastguard Worker             "backend=cras,client_type=crosvm",
328*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::Sys(SysStreamSourceBackend::CRAS),
329*bb4ee6a4SAndroid Build Coastguard Worker             CrasClientType::CRAS_CLIENT_TYPE_CROSVM,
330*bb4ee6a4SAndroid Build Coastguard Worker             CrasSocketType::Unified,
331*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
332*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
333*bb4ee6a4SAndroid Build Coastguard Worker         );
334*bb4ee6a4SAndroid Build Coastguard Worker         cras_check_success(
335*bb4ee6a4SAndroid Build Coastguard Worker             "backend=cras,client_type=arcvm",
336*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::Sys(SysStreamSourceBackend::CRAS),
337*bb4ee6a4SAndroid Build Coastguard Worker             CrasClientType::CRAS_CLIENT_TYPE_ARCVM,
338*bb4ee6a4SAndroid Build Coastguard Worker             CrasSocketType::Unified,
339*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
340*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
341*bb4ee6a4SAndroid Build Coastguard Worker         );
342*bb4ee6a4SAndroid Build Coastguard Worker         check_failure("backend=cras,client_type=none");
343*bb4ee6a4SAndroid Build Coastguard Worker         cras_check_success(
344*bb4ee6a4SAndroid Build Coastguard Worker             "backend=cras,socket_type=legacy",
345*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::Sys(SysStreamSourceBackend::CRAS),
346*bb4ee6a4SAndroid Build Coastguard Worker             CrasClientType::CRAS_CLIENT_TYPE_CROSVM,
347*bb4ee6a4SAndroid Build Coastguard Worker             CrasSocketType::Legacy,
348*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
349*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
350*bb4ee6a4SAndroid Build Coastguard Worker         );
351*bb4ee6a4SAndroid Build Coastguard Worker         cras_check_success(
352*bb4ee6a4SAndroid Build Coastguard Worker             "backend=cras,socket_type=unified",
353*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::Sys(SysStreamSourceBackend::CRAS),
354*bb4ee6a4SAndroid Build Coastguard Worker             CrasClientType::CRAS_CLIENT_TYPE_CROSVM,
355*bb4ee6a4SAndroid Build Coastguard Worker             CrasSocketType::Unified,
356*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
357*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
358*bb4ee6a4SAndroid Build Coastguard Worker         );
359*bb4ee6a4SAndroid Build Coastguard Worker         cras_check_success(
360*bb4ee6a4SAndroid Build Coastguard Worker             "output_device_config=[[client_type=crosvm],[client_type=arcvm,stream_type=pro_audio],[]]",
361*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::NULL,
362*bb4ee6a4SAndroid Build Coastguard Worker             CrasClientType::CRAS_CLIENT_TYPE_CROSVM,
363*bb4ee6a4SAndroid Build Coastguard Worker             CrasSocketType::Unified,
364*bb4ee6a4SAndroid Build Coastguard Worker             vec![
365*bb4ee6a4SAndroid Build Coastguard Worker                 PCMDeviceParameters{
366*bb4ee6a4SAndroid Build Coastguard Worker                     client_type: Some(CrasClientType::CRAS_CLIENT_TYPE_CROSVM),
367*bb4ee6a4SAndroid Build Coastguard Worker                     stream_type: None,
368*bb4ee6a4SAndroid Build Coastguard Worker                     effects: None,
369*bb4ee6a4SAndroid Build Coastguard Worker                 },
370*bb4ee6a4SAndroid Build Coastguard Worker                 PCMDeviceParameters{
371*bb4ee6a4SAndroid Build Coastguard Worker                     client_type: Some(CrasClientType::CRAS_CLIENT_TYPE_ARCVM),
372*bb4ee6a4SAndroid Build Coastguard Worker                     stream_type: Some(CrasStreamType::CRAS_STREAM_TYPE_PRO_AUDIO),
373*bb4ee6a4SAndroid Build Coastguard Worker                     effects: None,
374*bb4ee6a4SAndroid Build Coastguard Worker                 },
375*bb4ee6a4SAndroid Build Coastguard Worker                 Default::default(),
376*bb4ee6a4SAndroid Build Coastguard Worker                 ],
377*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
378*bb4ee6a4SAndroid Build Coastguard Worker         );
379*bb4ee6a4SAndroid Build Coastguard Worker         cras_check_success(
380*bb4ee6a4SAndroid Build Coastguard Worker             "input_device_config=[[client_type=crosvm],[client_type=arcvm,effects=[aec],stream_type=pro_audio],[effects=[EchoCancellation]],[]]",
381*bb4ee6a4SAndroid Build Coastguard Worker             StreamSourceBackend::NULL,
382*bb4ee6a4SAndroid Build Coastguard Worker             CrasClientType::CRAS_CLIENT_TYPE_CROSVM,
383*bb4ee6a4SAndroid Build Coastguard Worker             CrasSocketType::Unified,
384*bb4ee6a4SAndroid Build Coastguard Worker             vec![],
385*bb4ee6a4SAndroid Build Coastguard Worker             vec![
386*bb4ee6a4SAndroid Build Coastguard Worker                 PCMDeviceParameters{
387*bb4ee6a4SAndroid Build Coastguard Worker                     client_type: Some(CrasClientType::CRAS_CLIENT_TYPE_CROSVM),
388*bb4ee6a4SAndroid Build Coastguard Worker                     stream_type: None,
389*bb4ee6a4SAndroid Build Coastguard Worker                     effects: None,
390*bb4ee6a4SAndroid Build Coastguard Worker                 },
391*bb4ee6a4SAndroid Build Coastguard Worker                 PCMDeviceParameters{
392*bb4ee6a4SAndroid Build Coastguard Worker                     client_type: Some(CrasClientType::CRAS_CLIENT_TYPE_ARCVM),
393*bb4ee6a4SAndroid Build Coastguard Worker                     stream_type: Some(CrasStreamType::CRAS_STREAM_TYPE_PRO_AUDIO),
394*bb4ee6a4SAndroid Build Coastguard Worker                     effects: Some(vec![StreamEffect::EchoCancellation]),
395*bb4ee6a4SAndroid Build Coastguard Worker                 },
396*bb4ee6a4SAndroid Build Coastguard Worker                 PCMDeviceParameters{
397*bb4ee6a4SAndroid Build Coastguard Worker                     client_type: None,
398*bb4ee6a4SAndroid Build Coastguard Worker                     stream_type: None,
399*bb4ee6a4SAndroid Build Coastguard Worker                     effects: Some(vec![StreamEffect::EchoCancellation]),
400*bb4ee6a4SAndroid Build Coastguard Worker                 },
401*bb4ee6a4SAndroid Build Coastguard Worker                 Default::default(),
402*bb4ee6a4SAndroid Build Coastguard Worker                 ],
403*bb4ee6a4SAndroid Build Coastguard Worker         );
404*bb4ee6a4SAndroid Build Coastguard Worker 
405*bb4ee6a4SAndroid Build Coastguard Worker         // Invalid client_type in device config
406*bb4ee6a4SAndroid Build Coastguard Worker         check_failure("output_device_config=[[client_type=none]]");
407*bb4ee6a4SAndroid Build Coastguard Worker 
408*bb4ee6a4SAndroid Build Coastguard Worker         // Invalid stream type in device config
409*bb4ee6a4SAndroid Build Coastguard Worker         check_failure("output_device_config=[[stream_type=none]]");
410*bb4ee6a4SAndroid Build Coastguard Worker     }
411*bb4ee6a4SAndroid Build Coastguard Worker 
412*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
get_device_params_output()413*bb4ee6a4SAndroid Build Coastguard Worker     fn get_device_params_output() {
414*bb4ee6a4SAndroid Build Coastguard Worker         let params = Parameters {
415*bb4ee6a4SAndroid Build Coastguard Worker             output_device_config: vec![
416*bb4ee6a4SAndroid Build Coastguard Worker                 PCMDeviceParameters {
417*bb4ee6a4SAndroid Build Coastguard Worker                     effects: Some(vec![StreamEffect::EchoCancellation]),
418*bb4ee6a4SAndroid Build Coastguard Worker                     ..Default::default()
419*bb4ee6a4SAndroid Build Coastguard Worker                 },
420*bb4ee6a4SAndroid Build Coastguard Worker                 PCMDeviceParameters {
421*bb4ee6a4SAndroid Build Coastguard Worker                     effects: Some(vec![
422*bb4ee6a4SAndroid Build Coastguard Worker                         StreamEffect::EchoCancellation,
423*bb4ee6a4SAndroid Build Coastguard Worker                         StreamEffect::EchoCancellation,
424*bb4ee6a4SAndroid Build Coastguard Worker                     ]),
425*bb4ee6a4SAndroid Build Coastguard Worker                     ..Default::default()
426*bb4ee6a4SAndroid Build Coastguard Worker                 },
427*bb4ee6a4SAndroid Build Coastguard Worker             ],
428*bb4ee6a4SAndroid Build Coastguard Worker             ..Default::default()
429*bb4ee6a4SAndroid Build Coastguard Worker         };
430*bb4ee6a4SAndroid Build Coastguard Worker 
431*bb4ee6a4SAndroid Build Coastguard Worker         let default_pcm_info = virtio_snd_pcm_info {
432*bb4ee6a4SAndroid Build Coastguard Worker             hdr: virtio_snd_info {
433*bb4ee6a4SAndroid Build Coastguard Worker                 hda_fn_nid: 0.into(),
434*bb4ee6a4SAndroid Build Coastguard Worker             },
435*bb4ee6a4SAndroid Build Coastguard Worker             features: 0.into(),
436*bb4ee6a4SAndroid Build Coastguard Worker             formats: 0.into(),
437*bb4ee6a4SAndroid Build Coastguard Worker             rates: 0.into(),
438*bb4ee6a4SAndroid Build Coastguard Worker             direction: VIRTIO_SND_D_OUTPUT, // Direction is OUTPUT
439*bb4ee6a4SAndroid Build Coastguard Worker             channels_min: 1,
440*bb4ee6a4SAndroid Build Coastguard Worker             channels_max: 6,
441*bb4ee6a4SAndroid Build Coastguard Worker             padding: [0; 5],
442*bb4ee6a4SAndroid Build Coastguard Worker         };
443*bb4ee6a4SAndroid Build Coastguard Worker 
444*bb4ee6a4SAndroid Build Coastguard Worker         let mut pcm_info = default_pcm_info;
445*bb4ee6a4SAndroid Build Coastguard Worker         pcm_info.hdr.hda_fn_nid = 0.into();
446*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
447*bb4ee6a4SAndroid Build Coastguard Worker             params.get_device_params(&pcm_info),
448*bb4ee6a4SAndroid Build Coastguard Worker             Ok(params.output_device_config[0].clone())
449*bb4ee6a4SAndroid Build Coastguard Worker         );
450*bb4ee6a4SAndroid Build Coastguard Worker 
451*bb4ee6a4SAndroid Build Coastguard Worker         let mut pcm_info = default_pcm_info;
452*bb4ee6a4SAndroid Build Coastguard Worker         pcm_info.hdr.hda_fn_nid = 1.into();
453*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
454*bb4ee6a4SAndroid Build Coastguard Worker             params.get_device_params(&pcm_info),
455*bb4ee6a4SAndroid Build Coastguard Worker             Ok(params.output_device_config[1].clone())
456*bb4ee6a4SAndroid Build Coastguard Worker         );
457*bb4ee6a4SAndroid Build Coastguard Worker 
458*bb4ee6a4SAndroid Build Coastguard Worker         let mut pcm_info = default_pcm_info;
459*bb4ee6a4SAndroid Build Coastguard Worker         pcm_info.hdr.hda_fn_nid = 2.into();
460*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
461*bb4ee6a4SAndroid Build Coastguard Worker             params.get_device_params(&pcm_info),
462*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::InvalidPCMDeviceConfigIndex(2))
463*bb4ee6a4SAndroid Build Coastguard Worker         );
464*bb4ee6a4SAndroid Build Coastguard Worker     }
465*bb4ee6a4SAndroid Build Coastguard Worker 
466*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
get_device_params_input()467*bb4ee6a4SAndroid Build Coastguard Worker     fn get_device_params_input() {
468*bb4ee6a4SAndroid Build Coastguard Worker         let params = Parameters {
469*bb4ee6a4SAndroid Build Coastguard Worker             input_device_config: vec![
470*bb4ee6a4SAndroid Build Coastguard Worker                 PCMDeviceParameters {
471*bb4ee6a4SAndroid Build Coastguard Worker                     effects: Some(vec![
472*bb4ee6a4SAndroid Build Coastguard Worker                         StreamEffect::EchoCancellation,
473*bb4ee6a4SAndroid Build Coastguard Worker                         StreamEffect::EchoCancellation,
474*bb4ee6a4SAndroid Build Coastguard Worker                     ]),
475*bb4ee6a4SAndroid Build Coastguard Worker                     ..Default::default()
476*bb4ee6a4SAndroid Build Coastguard Worker                 },
477*bb4ee6a4SAndroid Build Coastguard Worker                 PCMDeviceParameters {
478*bb4ee6a4SAndroid Build Coastguard Worker                     effects: Some(vec![StreamEffect::EchoCancellation]),
479*bb4ee6a4SAndroid Build Coastguard Worker                     ..Default::default()
480*bb4ee6a4SAndroid Build Coastguard Worker                 },
481*bb4ee6a4SAndroid Build Coastguard Worker             ],
482*bb4ee6a4SAndroid Build Coastguard Worker             ..Default::default()
483*bb4ee6a4SAndroid Build Coastguard Worker         };
484*bb4ee6a4SAndroid Build Coastguard Worker 
485*bb4ee6a4SAndroid Build Coastguard Worker         let default_pcm_info = virtio_snd_pcm_info {
486*bb4ee6a4SAndroid Build Coastguard Worker             hdr: virtio_snd_info {
487*bb4ee6a4SAndroid Build Coastguard Worker                 hda_fn_nid: 0.into(),
488*bb4ee6a4SAndroid Build Coastguard Worker             },
489*bb4ee6a4SAndroid Build Coastguard Worker             features: 0.into(),
490*bb4ee6a4SAndroid Build Coastguard Worker             formats: 0.into(),
491*bb4ee6a4SAndroid Build Coastguard Worker             rates: 0.into(),
492*bb4ee6a4SAndroid Build Coastguard Worker             direction: VIRTIO_SND_D_INPUT, // Direction is INPUT
493*bb4ee6a4SAndroid Build Coastguard Worker             channels_min: 1,
494*bb4ee6a4SAndroid Build Coastguard Worker             channels_max: 6,
495*bb4ee6a4SAndroid Build Coastguard Worker             padding: [0; 5],
496*bb4ee6a4SAndroid Build Coastguard Worker         };
497*bb4ee6a4SAndroid Build Coastguard Worker 
498*bb4ee6a4SAndroid Build Coastguard Worker         let mut pcm_info = default_pcm_info;
499*bb4ee6a4SAndroid Build Coastguard Worker         pcm_info.hdr.hda_fn_nid = 0.into();
500*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
501*bb4ee6a4SAndroid Build Coastguard Worker             params.get_device_params(&pcm_info),
502*bb4ee6a4SAndroid Build Coastguard Worker             Ok(params.input_device_config[0].clone())
503*bb4ee6a4SAndroid Build Coastguard Worker         );
504*bb4ee6a4SAndroid Build Coastguard Worker 
505*bb4ee6a4SAndroid Build Coastguard Worker         let mut pcm_info = default_pcm_info;
506*bb4ee6a4SAndroid Build Coastguard Worker         pcm_info.hdr.hda_fn_nid = 1.into();
507*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
508*bb4ee6a4SAndroid Build Coastguard Worker             params.get_device_params(&pcm_info),
509*bb4ee6a4SAndroid Build Coastguard Worker             Ok(params.input_device_config[1].clone())
510*bb4ee6a4SAndroid Build Coastguard Worker         );
511*bb4ee6a4SAndroid Build Coastguard Worker 
512*bb4ee6a4SAndroid Build Coastguard Worker         let mut pcm_info = default_pcm_info;
513*bb4ee6a4SAndroid Build Coastguard Worker         pcm_info.hdr.hda_fn_nid = 2.into();
514*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
515*bb4ee6a4SAndroid Build Coastguard Worker             params.get_device_params(&pcm_info),
516*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::InvalidPCMDeviceConfigIndex(2))
517*bb4ee6a4SAndroid Build Coastguard Worker         );
518*bb4ee6a4SAndroid Build Coastguard Worker     }
519*bb4ee6a4SAndroid Build Coastguard Worker 
520*bb4ee6a4SAndroid Build Coastguard Worker     #[test]
get_device_params_invalid_direction()521*bb4ee6a4SAndroid Build Coastguard Worker     fn get_device_params_invalid_direction() {
522*bb4ee6a4SAndroid Build Coastguard Worker         let params = Parameters::default();
523*bb4ee6a4SAndroid Build Coastguard Worker 
524*bb4ee6a4SAndroid Build Coastguard Worker         let pcm_info = virtio_snd_pcm_info {
525*bb4ee6a4SAndroid Build Coastguard Worker             hdr: virtio_snd_info {
526*bb4ee6a4SAndroid Build Coastguard Worker                 hda_fn_nid: 0.into(),
527*bb4ee6a4SAndroid Build Coastguard Worker             },
528*bb4ee6a4SAndroid Build Coastguard Worker             features: 0.into(),
529*bb4ee6a4SAndroid Build Coastguard Worker             formats: 0.into(),
530*bb4ee6a4SAndroid Build Coastguard Worker             rates: 0.into(),
531*bb4ee6a4SAndroid Build Coastguard Worker             direction: 2, // Invalid direction
532*bb4ee6a4SAndroid Build Coastguard Worker             channels_min: 1,
533*bb4ee6a4SAndroid Build Coastguard Worker             channels_max: 6,
534*bb4ee6a4SAndroid Build Coastguard Worker             padding: [0; 5],
535*bb4ee6a4SAndroid Build Coastguard Worker         };
536*bb4ee6a4SAndroid Build Coastguard Worker 
537*bb4ee6a4SAndroid Build Coastguard Worker         assert_eq!(
538*bb4ee6a4SAndroid Build Coastguard Worker             params.get_device_params(&pcm_info),
539*bb4ee6a4SAndroid Build Coastguard Worker             Err(Error::InvalidPCMInfoDirection(2))
540*bb4ee6a4SAndroid Build Coastguard Worker         );
541*bb4ee6a4SAndroid Build Coastguard Worker     }
542*bb4ee6a4SAndroid Build Coastguard Worker }
543