libcras/
libcras.rs

1// Copyright 2022 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// Minimal implementation of interfaces in libcras for external builds.
6//
7// These just exist to allow us to build and clippy check the audio feature
8// when building outside of ChromeOS. When building for ChromeOS, this stub
9// will be replaced by the actual libcras implementation:
10// https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/third_party/adhd/cras/client/libcras/
11//
12// Any changes to the libcras API used in crosvm needs to be reflected in this
13// stub as well so as to have a successful crosvm build outside of ChromeOS.
14//
15// Instantiating a CrasClient using this will always panic!
16
17use std::error;
18use std::fmt;
19use std::str::FromStr;
20
21use audio_streams::shm_streams::SharedMemory;
22use audio_streams::shm_streams::ShmStream;
23use audio_streams::shm_streams::ShmStreamSource;
24use audio_streams::BoxError;
25use audio_streams::SampleFormat;
26use audio_streams::StreamDirection;
27use audio_streams::StreamEffect;
28use audio_streams::StreamSource;
29use audio_streams::StreamSourceGenerator;
30use serde::Deserialize;
31use serde::Deserializer;
32use serde::Serialize;
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
35#[allow(non_camel_case_types)]
36pub enum CRAS_CLIENT_TYPE {
37    #[serde(rename = "arcvm")]
38    CRAS_CLIENT_TYPE_ARCVM,
39    #[serde(rename = "crosvm")]
40    CRAS_CLIENT_TYPE_CROSVM,
41}
42
43pub type CrasClientType = CRAS_CLIENT_TYPE;
44
45#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
46#[allow(non_camel_case_types)]
47pub enum CRAS_STREAM_TYPE {
48    #[serde(rename = "default")]
49    CRAS_STREAM_TYPE_DEFAULT,
50    #[serde(rename = "pro_audio")]
51    CRAS_STREAM_TYPE_PRO_AUDIO,
52}
53
54pub type CrasStreamType = CRAS_STREAM_TYPE;
55
56#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)]
57#[serde(rename_all = "lowercase")]
58pub enum CrasSocketType {
59    Legacy,
60    Unified,
61}
62
63#[derive(Debug)]
64pub enum Error {
65    InvalidClientType,
66    InvalidSocketType,
67}
68impl fmt::Display for Error {
69    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70        write!(f, "")
71    }
72}
73
74impl error::Error for Error {}
75
76pub type CrasSysError = Error;
77
78impl FromStr for CrasClientType {
79    type Err = CrasSysError;
80    fn from_str(cras_type: &str) -> std::result::Result<Self, Self::Err> {
81        match cras_type {
82            "crosvm" => Ok(CrasClientType::CRAS_CLIENT_TYPE_CROSVM),
83            "arcvm" => Ok(CrasClientType::CRAS_CLIENT_TYPE_ARCVM),
84            _ => Err(Error::InvalidClientType),
85        }
86    }
87}
88
89impl FromStr for CrasSocketType {
90    type Err = Error;
91    fn from_str(sock_type: &str) -> std::result::Result<Self, Self::Err> {
92        match sock_type {
93            "legacy" => Ok(CrasSocketType::Legacy),
94            "unified" => Ok(CrasSocketType::Unified),
95            _ => Err(Error::InvalidSocketType),
96        }
97    }
98}
99
100pub struct CrasStreamSourceGenerator {}
101
102impl CrasStreamSourceGenerator {
103    pub fn new(_capture: bool, _client_type: CrasClientType, _socket_type: CrasSocketType) -> Self {
104        panic!("Cannot create cras audio device on non-chromeos crosvm builds.")
105    }
106
107    pub fn with_stream_type(
108        _capture: bool,
109        _client_type: CrasClientType,
110        _socket_type: CrasSocketType,
111        _stream_type: CrasStreamType,
112    ) -> Self {
113        panic!("Cannot create cras audio device on non-chromeos crosvm builds.")
114    }
115}
116
117impl StreamSourceGenerator for CrasStreamSourceGenerator {
118    fn generate(&self) -> std::result::Result<Box<dyn StreamSource>, BoxError> {
119        panic!("Cannot create cras audio device on non-chromeos crosvm builds.")
120    }
121}
122
123pub fn deserialize_cras_client_type<'de, D: Deserializer<'de>>(
124    deserializer: D,
125) -> std::result::Result<CRAS_CLIENT_TYPE, D::Error> {
126    let s = String::deserialize(deserializer)?;
127
128    match s.parse() {
129        Ok(client_type) => Ok(client_type),
130        Err(e) => Err(serde::de::Error::custom(e.to_string())),
131    }
132}
133
134type Result<T> = std::result::Result<T, Error>;
135
136pub struct CrasClient {}
137impl CrasClient {
138    pub fn with_type(_: CrasSocketType) -> Result<Self> {
139        panic!("Cannot create cras audio device on non-chromeos crosvm builds.")
140    }
141    pub fn set_client_type(&mut self, _: CrasClientType) {}
142    pub fn enable_cras_capture(&mut self) {}
143}
144
145impl<E: std::error::Error> ShmStreamSource<E> for CrasClient {
146    fn new_stream(
147        &mut self,
148        _direction: StreamDirection,
149        _num_channels: usize,
150        _format: SampleFormat,
151        _frame_rate: u32,
152        _buffer_size: usize,
153        _effects: &[StreamEffect],
154        _client_shm: &dyn SharedMemory<Error = E>,
155        _buffer_offsets: [u64; 2],
156    ) -> std::result::Result<Box<dyn ShmStream>, BoxError> {
157        panic!("Cannot create cras audio device on non-chromeos crosvm builds.")
158    }
159}