@@ -5,42 +5,79 @@ use std::sync::{Arc, Mutex};
5
5
6
6
/// ALSA's implementation for `Devices`.
7
7
pub struct Devices {
8
- hint_iter : alsa:: device_name:: HintIter ,
8
+ builtin_pos : usize ,
9
+ card_iter : alsa:: card:: Iter ,
9
10
}
10
11
11
12
impl Devices {
12
13
pub fn new ( ) -> Result < Self , DevicesError > {
13
14
Ok ( Devices {
14
- hint_iter : alsa:: device_name:: HintIter :: new_str ( None , "pcm" ) ?,
15
+ builtin_pos : 0 ,
16
+ card_iter : alsa:: card:: Iter :: new ( ) ,
15
17
} )
16
18
}
17
19
}
18
20
19
21
unsafe impl Send for Devices { }
20
22
unsafe impl Sync for Devices { }
21
23
24
+ const BUILTINS : [ & ' static str ; 5 ] = [ "default" , "pipewire" , "pulse" , "jack" , "oss" ] ;
25
+
22
26
impl Iterator for Devices {
23
27
type Item = Device ;
24
28
25
29
fn next ( & mut self ) -> Option < Device > {
30
+ while self . builtin_pos < BUILTINS . len ( ) {
31
+ let pos = self . builtin_pos ;
32
+ self . builtin_pos += 1 ;
33
+ let name = BUILTINS [ pos] ;
34
+
35
+ if let Ok ( handles) = DeviceHandles :: open ( & name) {
36
+ return Some ( Device {
37
+ name : name. to_string ( ) ,
38
+ pcm_id : name. to_string ( ) ,
39
+ handles : Arc :: new ( Mutex :: new ( handles) ) ,
40
+ } ) ;
41
+ }
42
+ }
43
+
26
44
loop {
27
- match self . hint_iter . next ( ) {
28
- None => return None ,
29
- Some ( hint) => {
30
- let name = match hint. name {
31
- None => continue ,
32
- // Ignoring the `null` device.
33
- Some ( name) if name == "null" => continue ,
34
- Some ( name) => name,
35
- } ;
45
+ let Some ( res) = self . card_iter . next ( ) else {
46
+ return None ;
47
+ } ;
48
+ let Ok ( card) = res else { continue } ;
49
+
50
+ let ctl_id = format ! ( "hw:{}" , card. get_index( ) ) ;
51
+ let Ok ( ctl) = alsa:: Ctl :: new ( & ctl_id, false ) else {
52
+ continue ;
53
+ } ;
54
+ let Ok ( cardinfo) = ctl. card_info ( ) else {
55
+ continue ;
56
+ } ;
57
+ let Ok ( card_name) = cardinfo. get_name ( ) else {
58
+ continue ;
59
+ } ;
36
60
37
- if let Ok ( handles) = DeviceHandles :: open ( & name) {
38
- return Some ( Device {
39
- name,
40
- handles : Arc :: new ( Mutex :: new ( handles) ) ,
41
- } ) ;
42
- }
43
- }
61
+ // Using plughw adds the ALSA plug layer, which can do sample type conversion,
62
+ // sample rate convertion, ...
63
+ // It is convenient, but at the same time not suitable for pro-audio as it hides
64
+ // the actual device capabilities and perform audio manipulation under your feet,
65
+ // for example sample rate conversion, sample format conversion, adds dummy channels,
66
+ // ...
67
+ // For now, many hardware only support 24bit / 3 bytes, which isn't yet supported by
68
+ // cpal. So we have to enable plughw (unfortunately) for maximum compatibility.
69
+ const USE_PLUGHW : bool = true ;
70
+ let pcm_id = if USE_PLUGHW {
71
+ format ! ( "plughw:{}" , card. get_index( ) )
72
+ } else {
73
+ ctl_id
74
+ } ;
75
+ if let Ok ( handles) = DeviceHandles :: open ( & pcm_id) {
76
+ return Some ( Device {
77
+ name : card_name. to_string ( ) ,
78
+ pcm_id : pcm_id. to_string ( ) ,
79
+ handles : Arc :: new ( Mutex :: new ( handles) ) ,
80
+ } ) ;
44
81
}
45
82
}
46
83
}
@@ -50,6 +87,7 @@ impl Iterator for Devices {
50
87
pub fn default_input_device ( ) -> Option < Device > {
51
88
Some ( Device {
52
89
name : "default" . to_owned ( ) ,
90
+ pcm_id : "default" . to_owned ( ) ,
53
91
handles : Arc :: new ( Mutex :: new ( Default :: default ( ) ) ) ,
54
92
} )
55
93
}
@@ -58,6 +96,7 @@ pub fn default_input_device() -> Option<Device> {
58
96
pub fn default_output_device ( ) -> Option < Device > {
59
97
Some ( Device {
60
98
name : "default" . to_owned ( ) ,
99
+ pcm_id : "default" . to_owned ( ) ,
61
100
handles : Arc :: new ( Mutex :: new ( Default :: default ( ) ) ) ,
62
101
} )
63
102
}
0 commit comments