Skip to content

Commit 6c63609

Browse files
Merge pull request librespot-org#116 from librespot-org/jackaudio
Jackaudio Support. Closes librespot-org#93.
2 parents d893d3e + 797ae82 commit 6c63609

File tree

4 files changed

+87
-0
lines changed

4 files changed

+87
-0
lines changed

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ url = "1.3"
5353
alsa = { git = "https://github.com/plietar/rust-alsa", optional = true }
5454
portaudio-rs = { version = "0.3.0", optional = true }
5555
libpulse-sys = { version = "0.0.0", optional = true }
56+
jack = { version = "0.5.3", optional = true }
5657
libc = { version = "0.2", optional = true }
5758
dns-sd = { version = "0.1.3", optional = true }
5859

@@ -65,6 +66,7 @@ protobuf_macros = { git = "https://github.com/plietar/rust-protobuf-macros", fea
6566
alsa-backend = ["alsa"]
6667
portaudio-backend = ["portaudio-rs"]
6768
pulseaudio-backend = ["libpulse-sys", "libc"]
69+
jackaudio-backend = ["jack"]
6870

6971
with-tremor = ["librespot-audio/with-tremor"]
7072
with-lewton = ["librespot-audio/with-lewton"]

src/audio_backend/jackaudio.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
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+
}

src/audio_backend/mod.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,11 @@ mod pulseaudio;
2929
#[cfg(feature = "pulseaudio-backend")]
3030
use self::pulseaudio::PulseAudioSink;
3131

32+
#[cfg(feature = "jackaudio-backend")]
33+
mod jackaudio;
34+
#[cfg(feature = "jackaudio-backend")]
35+
use self::jackaudio::JackSink;
36+
3237
mod pipe;
3338
use self::pipe::StdoutSink;
3439

@@ -41,6 +46,8 @@ pub const BACKENDS : &'static [
4146
("portaudio", mk_sink::<PortAudioSink>),
4247
#[cfg(feature = "pulseaudio-backend")]
4348
("pulseaudio", mk_sink::<PulseAudioSink>),
49+
#[cfg(feature = "jackaudio-backend")]
50+
("jackaudio", mk_sink::<JackSink>),
4451
("pipe", mk_sink::<StdoutSink>),
4552
];
4653

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ extern crate portaudio_rs;
3030
#[cfg(feature = "libpulse-sys")]
3131
extern crate libpulse_sys;
3232

33+
#[cfg(feature = "jackaudio-backend")]
34+
extern crate jack;
35+
3336
#[cfg(feature = "libc")]
3437
extern crate libc;
3538

0 commit comments

Comments
 (0)