default_device_sink/
lib.rs1use cpal::traits::{DeviceTrait, HostTrait};
10use once_cell::sync::Lazy;
11use rodio::{OutputStream, Sink, Source};
12use std::collections::VecDeque;
13use std::sync::{
14 atomic::{AtomicUsize, Ordering},
15 Arc, Mutex,
16};
17
18pub static SELECTED_OUTPUT_DEVICE: Lazy<Mutex<Option<String>>> = Lazy::new(|| Mutex::new(None));
20
21struct AudioBuffer {
22 channels: u16,
23 sample_rate: u32,
24 data: Arc<Vec<f32>>,
25 pos: Arc<AtomicUsize>,
26}
27
28#[derive(Clone)]
29struct ResumableSource {
30 channels: u16,
31 sample_rate: u32,
32 data: Arc<Vec<f32>>,
33 pos: Arc<AtomicUsize>,
34}
35
36impl Iterator for ResumableSource {
37 type Item = f32;
38 fn next(&mut self) -> Option<Self::Item> {
39 let idx = self.pos.fetch_add(1, Ordering::Relaxed);
40 self.data.get(idx).copied()
41 }
42}
43
44impl Source for ResumableSource {
45 fn current_frame_len(&self) -> Option<usize> {
46 None
47 }
48 fn channels(&self) -> u16 {
49 self.channels
50 }
51 fn sample_rate(&self) -> u32 {
52 self.sample_rate
53 }
54 fn total_duration(&self) -> Option<std::time::Duration> {
55 let len = self.data.len() as f32 / self.channels as f32 / self.sample_rate as f32;
56 Some(std::time::Duration::from_secs_f32(len))
57 }
58}
59
60pub fn default_device_name() -> Option<String> {
62 cpal::default_host()
63 .default_output_device()
64 .and_then(|d| d.name().ok())
65}
66
67pub fn list_output_devices() -> Vec<String> {
69 let host = cpal::default_host();
70 match host.output_devices() {
71 Ok(devices) => devices.filter_map(|d| d.name().ok()).collect::<Vec<_>>(),
72 Err(_) => Vec::new(),
73 }
74}
75
76pub fn set_output_device(device: Option<String>) {
78 *SELECTED_OUTPUT_DEVICE.lock().unwrap() = device;
79}
80
81pub fn get_output_device() -> Option<String> {
83 SELECTED_OUTPUT_DEVICE.lock().unwrap().clone()
84}
85
86struct Inner {
87 _stream: OutputStream,
88 sink: Sink,
89 device_name: Option<String>,
90 queue: VecDeque<AudioBuffer>,
91}
92
93#[derive(Clone)]
96pub struct DefaultDeviceSink {
97 inner: Arc<Mutex<Inner>>,
98}
99
100impl DefaultDeviceSink {
101 fn with_inner<R>(&self, f: impl FnOnce(&mut Inner) -> R) -> R {
102 let mut inner = self.inner.lock().unwrap();
103 Self::ensure_device(&mut inner);
104 f(&mut inner)
105 }
106
107 fn create_stream() -> (OutputStream, Sink, Option<String>) {
108 if let Some(selected) = get_output_device() {
109 let host = cpal::default_host();
110 if let Ok(devices) = host.output_devices() {
111 for device in devices {
112 if let Ok(device_name) = device.name() {
113 if device_name == selected {
114 if let Ok((stream, handle)) = OutputStream::try_from_device(&device) {
115 let sink = Sink::try_new(&handle).expect("Failed to create Sink");
116 return (stream, sink, Some(device_name));
117 }
118 }
119 }
120 }
121 }
122 }
123
124 let (stream, handle) =
125 OutputStream::try_default().expect("Failed to open default output stream");
126 let sink = Sink::try_new(&handle).expect("Failed to create Sink");
127 let name = default_device_name();
128 (stream, sink, name)
129 }
130
131 pub fn new() -> Self {
133 let (stream, sink, name) = Self::create_stream();
134 DefaultDeviceSink {
135 inner: Arc::new(Mutex::new(Inner {
136 _stream: stream,
137 sink,
138 device_name: name,
139 queue: VecDeque::new(),
140 })),
141 }
142 }
143
144 fn sync_queue(inner: &mut Inner) {
147 while inner.queue.len() > inner.sink.len() {
148 inner.queue.pop_front();
149 }
150 }
151
152 fn ensure_device(inner: &mut Inner) {
153 Self::sync_queue(inner);
154
155 let desired = match get_output_device() {
156 Some(name) => Some(name),
157 None => default_device_name(),
158 };
159
160 if desired != inner.device_name {
161 let volume = inner.sink.volume();
162 let speed = inner.sink.speed();
163 let paused = inner.sink.is_paused();
164
165 let (stream, new_sink, name) = Self::create_stream();
166 new_sink.set_volume(volume);
167 new_sink.set_speed(speed);
168
169 for buf in &inner.queue {
171 let source = ResumableSource {
172 channels: buf.channels,
173 sample_rate: buf.sample_rate,
174 data: buf.data.clone(),
175 pos: buf.pos.clone(),
176 };
177 new_sink.append(source);
178 }
179
180 if paused {
181 new_sink.pause();
182 }
183
184 inner.sink.stop();
185 inner._stream = stream;
186 inner.sink = new_sink;
187 inner.device_name = name;
188 }
189 }
190
191 pub fn append<T>(&self, input: T)
193 where
194 T: Source + Send + 'static,
195 T::Item: rodio::Sample + Send,
196 f32: cpal::FromSample<T::Item>,
197 {
198 self.with_inner(|inner| {
199 let channels = input.channels();
200 let sample_rate = input.sample_rate();
201 let samples: Vec<f32> = input.convert_samples().collect();
202 let arc = Arc::new(samples);
203 let pos = Arc::new(AtomicUsize::new(0));
204 let buf = AudioBuffer {
205 channels,
206 sample_rate,
207 data: arc.clone(),
208 pos: pos.clone(),
209 };
210 let source = ResumableSource {
211 channels,
212 sample_rate,
213 data: arc,
214 pos,
215 };
216 inner.queue.push_back(buf);
217 inner.sink.append::<ResumableSource>(source);
218 });
219 }
220
221 pub fn stop(&self) {
223 let mut inner = self.inner.lock().unwrap();
224 inner.sink.stop();
225 inner.queue.clear();
226 }
227
228 pub fn play(&self) {
229 let inner = self.inner.lock().unwrap();
230 inner.sink.play();
231 }
232
233 pub fn pause(&self) {
234 let inner = self.inner.lock().unwrap();
235 inner.sink.pause();
236 }
237
238 pub fn is_paused(&self) -> bool {
239 let inner = self.inner.lock().unwrap();
240 inner.sink.is_paused()
241 }
242
243 pub fn clear(&self) {
244 let mut inner = self.inner.lock().unwrap();
245 inner.sink.clear();
246 inner.queue.clear();
247 }
248
249 pub fn skip_one(&self) {
250 let mut inner = self.inner.lock().unwrap();
251 inner.sink.skip_one();
252 if !inner.queue.is_empty() {
253 inner.queue.pop_front();
254 }
255 }
256
257 pub fn sleep_until_end(&self) {
258 self.with_inner(|inner| inner.sink.sleep_until_end());
259 }
260
261 pub fn empty(&self) -> bool {
262 self.with_inner(|inner| inner.sink.empty())
263 }
264
265 pub fn len(&self) -> usize {
266 self.with_inner(|inner| inner.sink.len())
267 }
268
269 pub fn volume(&self) -> f32 {
270 self.with_inner(|inner| inner.sink.volume())
271 }
272
273 pub fn set_volume(&self, value: f32) {
274 self.with_inner(|inner| inner.sink.set_volume(value));
275 }
276
277 pub fn speed(&self) -> f32 {
278 self.with_inner(|inner| inner.sink.speed())
279 }
280
281 pub fn set_speed(&self, value: f32) {
282 self.with_inner(|inner| inner.sink.set_speed(value));
283 }
284}
285