@@ -22,6 +22,8 @@ use super::utils::{
22
22
} ;
23
23
use super :: * ;
24
24
use std:: sync:: { LockResult , WaitTimeoutResult } ;
25
+ use std:: thread;
26
+ use std:: time;
25
27
26
28
// Switch default devices used by the active streams, to test stream reinitialization
27
29
// ================================================================================================
@@ -73,6 +75,88 @@ fn test_switch_device_in_scope(scope: Scope) {
73
75
} ) ;
74
76
}
75
77
78
+ #[ ignore]
79
+ #[ test]
80
+ fn test_switch_device_while_paused ( ) {
81
+ test_switch_device_in_scope_while_paused ( Scope :: Input ) ;
82
+ test_switch_device_in_scope_while_paused ( Scope :: Output ) ;
83
+ }
84
+
85
+ fn test_switch_device_in_scope_while_paused ( scope : Scope ) {
86
+ println ! (
87
+ "Switch default device for {:?} while the stream is paused." ,
88
+ scope
89
+ ) ;
90
+
91
+ // Do nothing if there is no 2 available devices at least.
92
+ let devices = test_get_devices_in_scope ( scope. clone ( ) ) ;
93
+ if devices. len ( ) < 2 {
94
+ println ! ( "Need 2 devices for {:?} at least. Skip." , scope) ;
95
+ return ;
96
+ }
97
+
98
+ let mut device_switcher = TestDeviceSwitcher :: new ( scope. clone ( ) ) ;
99
+
100
+ let notifier = Arc :: new ( Notifier :: new ( 0 ) ) ;
101
+ let also_notifier = notifier. clone ( ) ;
102
+ let listener = run_serially ( || {
103
+ test_create_device_change_listener ( scope. clone ( ) , move |_addresses| {
104
+ let mut cnt = notifier. lock ( ) . unwrap ( ) ;
105
+ * cnt += 1 ;
106
+ notifier. notify ( cnt) ;
107
+ NO_ERR
108
+ } )
109
+ } ) ;
110
+ run_serially ( || listener. start ( ) ) ;
111
+
112
+ let changed_watcher = Watcher :: new ( & also_notifier) ;
113
+ test_get_started_stream_in_scope ( scope. clone ( ) , move |stream| loop {
114
+ // pause the stream, change device, start the stream
115
+ // peek under the hood to the find the device in use currently
116
+ let stm = unsafe { & mut * ( stream as * mut AudioUnitStream ) } ;
117
+ let before = if scope == Scope :: Output {
118
+ stm. core_stream_data . output_unit
119
+ } else {
120
+ stm. core_stream_data . input_unit
121
+ } ;
122
+
123
+ // Pause the stream, and change the default device
124
+ assert_eq ! ( unsafe { OPS . stream_stop. unwrap( ) ( stream) } , ffi:: CUBEB_OK ) ;
125
+
126
+ let start_cnt = changed_watcher. lock ( ) . unwrap ( ) . clone ( ) ;
127
+ device_switcher. next ( ) ;
128
+ let mut guard = changed_watcher. lock ( ) . unwrap ( ) ;
129
+ guard = changed_watcher
130
+ . wait_while ( guard, |cnt| * cnt == start_cnt)
131
+ . unwrap ( ) ;
132
+ if * guard >= devices. len ( ) {
133
+ break ;
134
+ }
135
+
136
+ // Wait until the switch is effective and the stream has been marked for delayed
137
+ // reinitialization. delayed_reinit can only be access from the queue thread. Depending on
138
+ // the setup this can take some time so we sleep a bit to not hammer the main thread.
139
+ let mut switched = false ;
140
+ while !switched {
141
+ switched = stm. queue . run_sync ( || stm. delayed_reinit ) . unwrap ( ) ;
142
+ if !switched {
143
+ let ten_millis = time:: Duration :: from_millis ( 10 ) ;
144
+ thread:: sleep ( ten_millis) ;
145
+ }
146
+ }
147
+
148
+ // Start the stream, and check that the device in use isn't the same as before pausing
149
+ assert_eq ! ( unsafe { OPS . stream_start. unwrap( ) ( stream) } , ffi:: CUBEB_OK ) ;
150
+
151
+ let after = if scope == Scope :: Output {
152
+ stm. core_stream_data . output_unit
153
+ } else {
154
+ stm. core_stream_data . input_unit
155
+ } ;
156
+ assert_ne ! ( before, after) ;
157
+ } ) ;
158
+ }
159
+
76
160
fn test_get_started_stream_in_scope < F > ( scope : Scope , operation : F )
77
161
where
78
162
F : FnOnce ( * mut ffi:: cubeb_stream ) ,
0 commit comments