Skip to content

Commit 11f4737

Browse files
committed
add enumeration
1 parent f3eb57a commit 11f4737

File tree

7 files changed

+148
-43
lines changed

7 files changed

+148
-43
lines changed

Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ alsa = "0.6"
3636
nix = "0.23"
3737
libc = "0.2.65"
3838
parking_lot = "0.12"
39+
intmap = "2.0"
3940
jack = { version = "0.9", optional = true }
4041
# pipewire = { version = "0.4", optional = true }
4142
pipewire = { git = "https://gitlab.freedesktop.org/pipewire/pipewire-rs", optional = true }

src/host/mod.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,14 +11,14 @@ pub(crate) mod emscripten;
1111
feature = "jack"
1212
))]
1313
pub(crate) mod jack;
14+
pub(crate) mod null;
15+
#[cfg(target_os = "android")]
16+
pub(crate) mod oboe;
1417
#[cfg(all(
1518
any(target_os = "linux", target_os = "dragonfly", target_os = "freebsd"),
1619
feature = "pipewire"
1720
))]
1821
pub(crate) mod pipewire;
19-
pub(crate) mod null;
20-
#[cfg(target_os = "android")]
21-
pub(crate) mod oboe;
2222
#[cfg(windows)]
2323
pub(crate) mod wasapi;
2424
#[cfg(all(target_arch = "wasm32", feature = "wasm-bindgen"))]

src/host/pipewire/conn.rs

Lines changed: 82 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
extern crate pipewire;
22

3+
use intmap::IntMap;
4+
5+
use super::Device;
6+
37
use self::pipewire::{
48
metadata::{Metadata, MetadataListener},
59
node::{Node, NodeListener},
@@ -32,6 +36,7 @@ enum Message {
3236
device_type: DeviceType,
3337
autoconnect: bool,
3438
},
39+
EnumerateDevices,
3540
}
3641

3742
enum MessageRepl {
@@ -41,6 +46,7 @@ enum MessageRepl {
4146

4247
pub struct NodeInfo {
4348
pub name: String,
49+
pub id: u32,
4450
}
4551

4652
pub struct PWClient {
@@ -97,11 +103,12 @@ impl PWClient {
97103
struct State {
98104
settings: Settings,
99105
nodes: Vec<ProxyItem>,
106+
devices: IntMap<NodeInfo>,
100107
}
101108

102109
#[derive(Default, Clone, Debug)]
103110
pub struct Settings {
104-
pub sample_rate: u32,
111+
pub allowed_sample_rates: Vec<u32>,
105112
pub min_buffer_size: u32,
106113
pub max_buffer_size: u32,
107114
pub default_buffer_size: u32,
@@ -148,7 +155,9 @@ fn pw_thread(
148155
Message::Terminate => mainloop.quit(),
149156
Message::GetSettings => {
150157
let settings = state.borrow().settings.clone();
151-
main_sender.send(MessageRepl::Settings(settings));
158+
main_sender
159+
.send(MessageRepl::Settings(settings))
160+
.expect("Failed to send settings");
152161
}
153162
Message::CreateDeviceNode {
154163
name,
@@ -176,25 +185,32 @@ fn pw_thread(
176185
)
177186
.expect("Failed to create object");
178187

188+
let id = Rc::new(Cell::new(0));
189+
let id_clone = id.clone();
179190
let _listener = node
180191
.add_listener_local()
181-
.info(|info| {
182-
// println!("{:?}", info);
192+
.info(move |info| {
193+
id_clone.set(info.id());
183194
})
184195
.param(|a, b, c, d| {
185196
println!("{}, {}, {}, {}", a, b, c, d);
186197
})
187198
.register();
188-
189199
println!("{:?}", node);
200+
while id.get() == 0 {
201+
mainloop.run();
202+
}
190203

191204
state.as_ref().borrow_mut().nodes.push(ProxyItem::Node {
192205
_proxy: node,
193206
_listener,
194207
});
195208

196-
main_sender.send(MessageRepl::NodeInfo(NodeInfo { name }));
209+
main_sender
210+
.send(MessageRepl::NodeInfo(NodeInfo { name, id: id.get() }))
211+
.expect("Failed to send node info");
197212
}
213+
Message::EnumerateDevices => {}
198214
}
199215
});
200216

@@ -207,6 +223,47 @@ fn pw_thread(
207223

208224
move |global| match global.type_ {
209225
ObjectType::Metadata => handle_metadata(global, &state, &registry, &proxies),
226+
ObjectType::Node => {
227+
if let Some(ref props) = global.props {
228+
let mut state = state.as_ref().borrow_mut();
229+
let name = props
230+
.get("node.nick")
231+
.or(props.get("node.description"))
232+
.unwrap_or("Unknown device");
233+
match props.get("media.class") {
234+
Some("Audio/Source") => {
235+
state.devices.insert(
236+
global.id.into(),
237+
NodeInfo {
238+
name: name.to_string(),
239+
id: global.id,
240+
},
241+
);
242+
}
243+
Some("Audio/Sink") => {
244+
state.devices.insert(
245+
global.id.into(),
246+
NodeInfo {
247+
name: name.to_string(),
248+
id: global.id,
249+
},
250+
);
251+
}
252+
_ => {}
253+
}
254+
if props.get("media.class") == Some("Audio/Source")
255+
&& global.type_ == ObjectType::Node
256+
{
257+
println!(
258+
"object: id:{} type:{}/{} nick:{}",
259+
global.id,
260+
global.type_,
261+
global.version,
262+
props.get("node.nick").unwrap_or("failed to get name")
263+
);
264+
}
265+
}
266+
}
210267
_ => {}
211268
}
212269
})
@@ -248,11 +305,12 @@ fn handle_metadata(
248305
.property({
249306
let state = state.clone();
250307
move |_, key, _, value| {
308+
let mut sample_rate = 0;
251309
let mut state = state.as_ref().borrow_mut();
252310
if let Some(value) = value {
253311
if let Ok(value) = value.parse::<u32>() {
254312
match key {
255-
Some("clock.rate") => state.settings.sample_rate = value,
313+
Some("clock.rate") => sample_rate = value,
256314
Some("clock.quantum") => {
257315
state.settings.default_buffer_size = value
258316
}
@@ -264,8 +322,25 @@ fn handle_metadata(
264322
}
265323
_ => {}
266324
};
325+
} else {
326+
match key {
327+
Some("clock.allowed-rates") => {
328+
let rates: Result<Vec<u32>, _> = value[2..value.len() - 2]
329+
.split_whitespace()
330+
.map(|x| x.parse::<u32>())
331+
.collect();
332+
state.settings.allowed_sample_rates =
333+
rates.expect("Couldn't parse allowed rates");
334+
}
335+
_ => {}
336+
}
267337
}
268338
}
339+
// Not sure if allowed-rates can be empty,
340+
// but if it is just push the currently used one.
341+
if state.settings.allowed_sample_rates.is_empty() {
342+
state.settings.allowed_sample_rates.push(sample_rate);
343+
}
269344
0
270345
}
271346
})

src/host/pipewire/device.rs

Lines changed: 52 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use crate::traits::DeviceTrait;
12
use crate::{
23
BackendSpecificError, BuildStreamError, Data, DefaultStreamConfigError, DeviceNameError,
34
InputCallbackInfo, OutputCallbackInfo, SampleFormat, SampleRate, StreamConfig, StreamError,
@@ -6,7 +7,6 @@ use crate::{
67
};
78
use std::hash::{Hash, Hasher};
89
use std::rc::Rc;
9-
use crate::traits::DeviceTrait;
1010

1111
use super::stream::Stream;
1212
use super::PIPEWIRE_SAMPLE_FORMAT;
@@ -26,12 +26,10 @@ pub enum DeviceType {
2626
}
2727
#[derive(Clone)]
2828
pub struct Device {
29-
name: String,
30-
sample_rate: SampleRate,
31-
buffer_size: SupportedBufferSize,
32-
device_type: DeviceType,
33-
connect_ports_automatically: bool,
34-
client: Rc<super::conn::PWClient>
29+
pub(crate) name: String,
30+
pub(crate) device_type: DeviceType,
31+
pub(crate) connect_ports_automatically: bool,
32+
pub(crate) client: Rc<super::conn::PWClient>,
3533
}
3634

3735
impl Device {
@@ -41,22 +39,29 @@ impl Device {
4139
device_type: DeviceType,
4240
client: Rc<super::conn::PWClient>,
4341
) -> Result<Self, String> {
44-
while client.get_settings().and_then(|s| if s.sample_rate == 0 {Err(String::new())} else {Ok(true)} ).is_err() {}
42+
while client
43+
.get_settings()
44+
.and_then(|s| {
45+
if s.allowed_sample_rates.is_empty() {
46+
Err(String::new())
47+
} else {
48+
Ok(true)
49+
}
50+
})
51+
.is_err()
52+
{}
4553

4654
let settings = client.get_settings().unwrap();
4755

48-
let info = client.create_device_node(name, device_type.clone(), connect_ports_automatically).expect("Error creating device");
56+
let info = client
57+
.create_device_node(name, device_type.clone(), connect_ports_automatically)
58+
.expect("Error creating device");
4959

5060
Ok(Device {
5161
name: info.name,
52-
sample_rate: SampleRate(settings.sample_rate),
53-
buffer_size: SupportedBufferSize::Range {
54-
min: settings.min_buffer_size,
55-
max: settings.max_buffer_size,
56-
},
5762
device_type,
5863
connect_ports_automatically,
59-
client
64+
client,
6065
})
6166
}
6267

@@ -89,9 +94,14 @@ impl Device {
8994
}
9095

9196
pub fn default_config(&self) -> Result<SupportedStreamConfig, DefaultStreamConfigError> {
97+
let settings = self.client.get_settings().unwrap();
9298
let channels = DEFAULT_NUM_CHANNELS;
93-
let sample_rate = self.sample_rate;
94-
let buffer_size = self.buffer_size.clone();
99+
// Default is highest sample rate possible
100+
let sample_rate = SampleRate(*settings.allowed_sample_rates.last().unwrap());
101+
let buffer_size = SupportedBufferSize::Range {
102+
min: settings.min_buffer_size,
103+
max: settings.max_buffer_size,
104+
};
95105
// The sample format for JACK audio ports is always "32-bit float mono audio" in the current implementation.
96106
// Custom formats are allowed within JACK, but this is of niche interest.
97107
// The format can be found programmatically by calling jack::PortSpec::port_type() on a created port.
@@ -105,6 +115,7 @@ impl Device {
105115
}
106116

107117
pub fn supported_configs(&self) -> Vec<SupportedStreamConfigRange> {
118+
let settings = self.client.get_settings().unwrap();
108119
let f = match self.default_config() {
109120
Err(_) => return vec![],
110121
Ok(f) => f,
@@ -115,7 +126,8 @@ impl Device {
115126
for &channels in DEFAULT_SUPPORTED_CHANNELS.iter() {
116127
supported_configs.push(SupportedStreamConfigRange {
117128
channels,
118-
min_sample_rate: f.sample_rate,
129+
min_sample_rate: SampleRate(*settings.allowed_sample_rates.first().unwrap()),
130+
// Default is maximum possible, so just use that
119131
max_sample_rate: f.sample_rate,
120132
buffer_size: f.buffer_size.clone(),
121133
sample_format: f.sample_format,
@@ -179,15 +191,25 @@ impl DeviceTrait for Device {
179191
D: FnMut(&Data, &InputCallbackInfo) + Send + 'static,
180192
E: FnMut(StreamError) + Send + 'static,
181193
{
194+
let settings = self.client.get_settings().unwrap();
182195
if let DeviceType::OutputDevice = &self.device_type {
183196
// Trying to create an input stream from an output device
184197
return Err(BuildStreamError::StreamConfigNotSupported);
185198
}
186-
if conf.sample_rate != self.sample_rate || sample_format != PIPEWIRE_SAMPLE_FORMAT {
199+
// FIXME: Not sure if we should go to the nearest neighbour sample rate
200+
// This issue also happens on build_output_stream_raw()
201+
if settings.allowed_sample_rates.contains(&conf.sample_rate.0)
202+
|| sample_format != PIPEWIRE_SAMPLE_FORMAT
203+
{
187204
return Err(BuildStreamError::StreamConfigNotSupported);
188205
}
189206

190-
let mut stream = Stream::new_input(self.client.clone(), conf.channels, data_callback, error_callback);
207+
let mut stream = Stream::new_input(
208+
self.client.clone(),
209+
conf.channels,
210+
data_callback,
211+
error_callback,
212+
);
191213

192214
if self.connect_ports_automatically {
193215
stream.connect_to_system_inputs();
@@ -207,15 +229,23 @@ impl DeviceTrait for Device {
207229
D: FnMut(&mut Data, &OutputCallbackInfo) + Send + 'static,
208230
E: FnMut(StreamError) + Send + 'static,
209231
{
232+
let settings = self.client.get_settings().unwrap();
210233
if let DeviceType::InputDevice = &self.device_type {
211234
// Trying to create an output stream from an input device
212235
return Err(BuildStreamError::StreamConfigNotSupported);
213236
}
214-
if conf.sample_rate != self.sample_rate || sample_format != PIPEWIRE_SAMPLE_FORMAT {
237+
if settings.allowed_sample_rates.contains(&conf.sample_rate.0)
238+
|| sample_format != PIPEWIRE_SAMPLE_FORMAT
239+
{
215240
return Err(BuildStreamError::StreamConfigNotSupported);
216241
}
217242

218-
let mut stream = Stream::new_output(self.client.clone(), conf.channels, data_callback, error_callback);
243+
let mut stream = Stream::new_output(
244+
self.client.clone(),
245+
conf.channels,
246+
data_callback,
247+
error_callback,
248+
);
219249

220250
if self.connect_ports_automatically {
221251
stream.connect_to_system_outputs();

0 commit comments

Comments
 (0)