use std::io; use super::{Open, Sink}; use jack::prelude::{AudioOutPort, AudioOutSpec, Client, JackControl, ProcessScope, AsyncClient, client_options, ProcessHandler, Port }; use std::sync::mpsc::{sync_channel, SyncSender, Receiver}; #[allow(dead_code)] pub struct JackSink { send: SyncSender, active_client: AsyncClient<(),JackData>, } pub struct JackData { rec: Receiver, port_l: Port, port_r: Port, } fn pcm_to_f32(sample: i16) -> f32 { let mut f: f32 = sample as f32 / 32768.0; if f > 1.0 { f = 1.0; } if f < -1.0 { f = -1.0; } f } impl ProcessHandler for JackData { fn process(&mut self, _: &Client, ps: &ProcessScope) -> JackControl { // get output port buffers let mut out_r = AudioOutPort::new(&mut self.port_r, ps); let mut out_l = AudioOutPort::new(&mut self.port_l, ps); let buf_r: &mut [f32] = &mut out_r; let buf_l: &mut [f32] = &mut out_l; // get queue iterator let mut queue_iter = self.rec.try_iter(); let buf_size = buf_r.len(); for i in 0..buf_size { buf_r[i] = pcm_to_f32(queue_iter.next().unwrap_or(0)); buf_l[i] = pcm_to_f32(queue_iter.next().unwrap_or(0)); } JackControl::Continue } } impl Open for JackSink { fn open(client_name: Option) -> JackSink { info!("Using jack sink!"); let client_name = client_name.unwrap_or("librespot".to_string()); let (client, _status) = Client::new(&client_name[..], client_options::NO_START_SERVER).unwrap(); let ch_r = client.register_port("out_0", AudioOutSpec::default()).unwrap(); let ch_l = client.register_port("out_1", AudioOutSpec::default()).unwrap(); // buffer for samples from librespot (~10ms) let (tx, rx) = sync_channel(2*1024*4); let jack_data = JackData { rec: rx, port_l: ch_l, port_r: ch_r }; let active_client = AsyncClient::new(client, (), jack_data).unwrap(); JackSink { send: tx, active_client: active_client } } } impl Sink for JackSink { fn start(&mut self) -> io::Result<()> { Ok(()) } fn stop(&mut self) -> io::Result<()> { Ok(()) } fn write(&mut self, data: &[i16]) -> io::Result<()> { for s in data.iter() { let res = self.send.send(*s); if res.is_err() { error!("jackaudio: cannot write to channel"); } } Ok(()) } }