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