1extern crate jack;
6
7use crate::{traits::HostTrait, Error, ErrorKind, SampleFormat};
8
9mod device;
10mod stream;
11
12#[allow(unused_imports)] pub use self::{
14 device::{Device, SupportedInputConfigs, SupportedOutputConfigs},
15 stream::Stream,
16};
17
18const JACK_SAMPLE_FORMAT: SampleFormat = SampleFormat::F32;
19
20pub type Devices = std::vec::IntoIter<Device>;
21
22#[derive(Debug)]
30pub struct Host {
31 name: String,
35 connect_ports_automatically: bool,
37 start_server_automatically: bool,
39 devices_created: Vec<Device>,
41}
42
43impl Host {
44 pub fn new() -> Result<Self, Error> {
45 let mut host = Host {
46 name: format!("cpal_client_{}", std::process::id()),
47 connect_ports_automatically: true,
48 start_server_automatically: false,
49 devices_created: vec![],
50 };
51 host.initialize_default_devices();
53 Ok(host)
54 }
55 pub fn set_connect_automatically(&mut self, do_connect: bool) {
64 self.connect_ports_automatically = do_connect;
65 }
66
67 pub fn set_start_server_automatically(&mut self, do_start_server: bool) {
74 self.start_server_automatically = do_start_server;
75 }
76
77 pub fn input_device_with_name(&mut self, name: &str) -> Option<Device> {
78 self.name = name.to_owned();
79 self.default_input_device()
80 }
81
82 pub fn output_device_with_name(&mut self, name: &str) -> Option<Device> {
83 self.name = name.to_owned();
84 self.default_output_device()
85 }
86
87 fn initialize_default_devices(&mut self) {
88 let in_device_res = Device::default_input_device(
89 &self.name,
90 self.connect_ports_automatically,
91 self.start_server_automatically,
92 );
93
94 if let Ok(device) = in_device_res {
95 self.devices_created.push(device);
96 }
97
98 let out_device_res = Device::default_output_device(
99 &self.name,
100 self.connect_ports_automatically,
101 self.start_server_automatically,
102 );
103 if let Ok(device) = out_device_res {
104 self.devices_created.push(device);
105 }
106 }
107}
108
109impl HostTrait for Host {
110 type Devices = Devices;
111 type Device = Device;
112
113 fn is_available() -> bool {
125 true
126 }
127
128 fn devices(&self) -> Result<Self::Devices, Error> {
129 Ok(self.devices_created.clone().into_iter())
130 }
131
132 fn default_input_device(&self) -> Option<Self::Device> {
133 for device in &self.devices_created {
134 if device.is_input() {
135 return Some(device.clone());
136 }
137 }
138 None
139 }
140
141 fn default_output_device(&self) -> Option<Self::Device> {
142 for device in &self.devices_created {
143 if device.is_output() {
144 return Some(device.clone());
145 }
146 }
147 None
148 }
149}
150
151fn get_client_options(start_server_automatically: bool) -> jack::ClientOptions {
152 let mut client_options = jack::ClientOptions::empty();
153 client_options.set(
154 jack::ClientOptions::NO_START_SERVER,
155 !start_server_automatically,
156 );
157 client_options
158}
159
160impl From<jack::Error> for Error {
161 fn from(err: jack::Error) -> Self {
162 let msg = format!("{err}");
163 match err {
164 jack::Error::ClientError(_)
165 | jack::Error::ClientActivationError
166 | jack::Error::ClientDeactivationError
167 | jack::Error::LibraryError(_)
168 | jack::Error::WeakFunctionNotFound(_)
169 | jack::Error::RingbufferCreateFailed => {
170 Error::with_message(ErrorKind::DeviceNotAvailable, msg)
171 }
172
173 jack::Error::ClientIsNoLongerAlive | jack::Error::ClientPanicked => {
174 Error::with_message(ErrorKind::StreamInvalidated, msg)
175 }
176
177 jack::Error::SetBufferSizeError | jack::Error::NotEnoughSpace => {
178 Error::with_message(ErrorKind::UnsupportedConfig, msg)
179 }
180
181 jack::Error::InvalidDeactivation | jack::Error::FreewheelError => {
182 Error::with_message(ErrorKind::UnsupportedOperation, msg)
183 }
184
185 jack::Error::PortNamingError | jack::Error::PortAliasError => {
186 Error::with_message(ErrorKind::InvalidInput, msg)
187 }
188
189 _ => Error::with_message(ErrorKind::BackendError, msg),
190 }
191 }
192}
193
194fn get_client(name: &str, client_options: jack::ClientOptions) -> Result<jack::Client, Error> {
195 let (client, status) = jack::Client::new(name, client_options)?;
196 if status.intersects(jack::ClientStatus::VERSION_ERROR) {
197 Err(Error::with_message(
198 ErrorKind::UnsupportedOperation,
199 "Client protocol version does not match the JACK server",
200 ))
201 } else if status.intersects(jack::ClientStatus::INVALID_OPTION) {
202 Err(Error::with_message(
203 ErrorKind::UnsupportedOperation,
204 "JACK client operation contained an invalid or unsupported option",
205 ))
206 } else if status.intersects(jack::ClientStatus::SERVER_ERROR) {
207 Err(Error::with_message(
208 ErrorKind::DeviceNotAvailable,
209 "Error communicating with the JACK server",
210 ))
211 } else if status.intersects(jack::ClientStatus::SERVER_FAILED) {
212 Err(Error::with_message(
213 ErrorKind::DeviceNotAvailable,
214 "Could not connect to the JACK server",
215 ))
216 } else if status.intersects(jack::ClientStatus::INIT_FAILURE) {
217 Err(Error::with_message(
218 ErrorKind::DeviceNotAvailable,
219 "Unable to initialize JACK client",
220 ))
221 } else if status.intersects(jack::ClientStatus::SHM_FAILURE) {
222 Err(Error::with_message(
223 ErrorKind::DeviceNotAvailable,
224 "Unable to access JACK shared memory",
225 ))
226 } else if status.intersects(jack::ClientStatus::NO_SUCH_CLIENT) {
227 Err(Error::with_message(
228 ErrorKind::DeviceNotAvailable,
229 "Requested JACK client does not exist",
230 ))
231 } else {
232 Ok(client)
233 }
234}