1 use super::{Open, Sink};
2 use jack::prelude::{
3     client_options, AsyncClient, AudioOutPort, AudioOutSpec, Client, JackControl, Port,
4     ProcessHandler, ProcessScope,
5 };
6 use std::io;
7 use std::sync::mpsc::{sync_channel, Receiver, SyncSender};
8 
9 pub struct JackSink {
10     send: SyncSender<i16>,
11     active_client: AsyncClient<(), JackData>,
12 }
13 
14 pub struct JackData {
15     rec: Receiver<i16>,
16     port_l: Port<AudioOutSpec>,
17     port_r: Port<AudioOutSpec>,
18 }
19 
pcm_to_f32(sample: i16) -> f3220 fn pcm_to_f32(sample: i16) -> f32 {
21     sample as f32 / 32768.0
22 }
23 
24 impl ProcessHandler for JackData {
process(&mut self, _: &Client, ps: &ProcessScope) -> JackControl25     fn process(&mut self, _: &Client, ps: &ProcessScope) -> JackControl {
26         // get output port buffers
27         let mut out_r = AudioOutPort::new(&mut self.port_r, ps);
28         let mut out_l = AudioOutPort::new(&mut self.port_l, ps);
29         let buf_r: &mut [f32] = &mut out_r;
30         let buf_l: &mut [f32] = &mut out_l;
31         // get queue iterator
32         let mut queue_iter = self.rec.try_iter();
33 
34         let buf_size = buf_r.len();
35         for i in 0..buf_size {
36             buf_r[i] = pcm_to_f32(queue_iter.next().unwrap_or(0));
37             buf_l[i] = pcm_to_f32(queue_iter.next().unwrap_or(0));
38         }
39         JackControl::Continue
40     }
41 }
42 
43 impl Open for JackSink {
open(client_name: Option<String>) -> JackSink44     fn open(client_name: Option<String>) -> JackSink {
45         info!("Using jack sink!");
46 
47         let client_name = client_name.unwrap_or("librespot".to_string());
48         let (client, _status) =
49             Client::new(&client_name[..], client_options::NO_START_SERVER).unwrap();
50         let ch_r = client
51             .register_port("out_0", AudioOutSpec::default())
52             .unwrap();
53         let ch_l = client
54             .register_port("out_1", AudioOutSpec::default())
55             .unwrap();
56         // buffer for samples from librespot (~10ms)
57         let (tx, rx) = sync_channel(2 * 1024 * 4);
58         let jack_data = JackData {
59             rec: rx,
60             port_l: ch_l,
61             port_r: ch_r,
62         };
63         let active_client = AsyncClient::new(client, (), jack_data).unwrap();
64 
65         JackSink {
66             send: tx,
67             active_client: active_client,
68         }
69     }
70 }
71 
72 impl Sink for JackSink {
start(&mut self) -> io::Result<()>73     fn start(&mut self) -> io::Result<()> {
74         Ok(())
75     }
76 
stop(&mut self) -> io::Result<()>77     fn stop(&mut self) -> io::Result<()> {
78         Ok(())
79     }
80 
write(&mut self, data: &[i16]) -> io::Result<()>81     fn write(&mut self, data: &[i16]) -> io::Result<()> {
82         for s in data.iter() {
83             let res = self.send.send(*s);
84             if res.is_err() {
85                 error!("jackaudio: cannot write to channel");
86             }
87         }
88         Ok(())
89     }
90 }
91