From 891298171c5afb13c7be169918915679b6102912 Mon Sep 17 00:00:00 2001 From: Will Stott Date: Thu, 15 Nov 2018 19:34:13 +0000 Subject: [PATCH 01/11] Initial untested VecDeque concept. --- Cargo.toml | 1 + playback/Cargo.toml | 2 + playback/src/audio_backend/cpal.rs | 92 ++++++++++++++++++++++++++++++ playback/src/audio_backend/mod.rs | 7 +++ 4 files changed, 102 insertions(+) create mode 100644 playback/src/audio_backend/cpal.rs diff --git a/Cargo.toml b/Cargo.toml index 8231759a2..5b6765a27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,6 +63,7 @@ alsa-backend = ["librespot-playback/alsa-backend"] portaudio-backend = ["librespot-playback/portaudio-backend"] pulseaudio-backend = ["librespot-playback/pulseaudio-backend"] jackaudio-backend = ["librespot-playback/jackaudio-backend"] +cpal-backend = ["librespot-playback/cpal-backend"] with-tremor = ["librespot-audio/with-tremor"] with-vorbis = ["librespot-audio/with-vorbis"] diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 653cbe6c5..32be6d1fd 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -20,9 +20,11 @@ portaudio-rs = { version = "0.3.0", optional = true } libpulse-sys = { version = "0.0.0", optional = true } jack = { version = "0.5.3", optional = true } libc = { version = "0.2", optional = true } +cpal = { version = "0.8.2", optional = true } [features] alsa-backend = ["alsa"] portaudio-backend = ["portaudio-rs"] pulseaudio-backend = ["libpulse-sys", "libc"] jackaudio-backend = ["jack"] +cpal-backend = ["cpal"] diff --git a/playback/src/audio_backend/cpal.rs b/playback/src/audio_backend/cpal.rs new file mode 100644 index 000000000..e493c8ac4 --- /dev/null +++ b/playback/src/audio_backend/cpal.rs @@ -0,0 +1,92 @@ +use super::{Open, Sink}; +extern crate cpal; +use std::io; +use std::thread; +use std::collections::VecDeque; + +pub struct CpalSink { + event_loop: cpal::EventLoop, + buffer: mut VecDeque, + stream_id: Option, +} + +impl Open for CpalSink { + fn open(device: Option) -> CpalSink { + info!("Using cpal sink"); + + if device.is_some() { + // N.B. This is perfectly possible to support. + // TODO: First need to enable listing of devices. + // Remember to filter to those which support Stereo 16bit 44100Hz + // TODO: Choose cpal sink by name. + panic!("cpal sink does not support specifying a device name"); + } + + let event_loop = cpal::EventLoop::new(); + + CpalSink { + // Allow an (arbitrary) 2 second buffer before resizing. + buffer: VecDeque::with_capacity(44100 * 2 * 2), + event_loop: event_loop, + } + } +} + +impl Sink for CpalSink { + fn start(&mut self) -> io::Result<()> { + + if self.stream_id.is_none() { + + let device = cpal::default_output_device().expect("no output device available"); + // TODO: Support more formats. + let format = cpal::Format(2, 44100, cpal::SampleFormat::I16); + + self.stream_id = self.event_loop.build_output_stream(&device, &format)?; + + self.event_loop.play_stream(self.stream_id.clone()); + } + + if self.thread.is_none() { + let event_loop = self.event_loop; + let source = self.buffer; + thread::spawn(move |event_loop, source| { + event_loop.run(move |_stream_id, mut stream_data| { + match data { + cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::I16(mut buffer) } => { + let sl = source.len(); + if (sl > buffer.len()) { + sl = buffer.len(); + } + // let u: Vec<_> = source.drain(..sl).collect(); + // buffer[..s1].copy_from_slice(u[..s1]); + + for (sample, data) in buffer.iter_mut().zip(source.drain(..sl)) { + *sample = data; + } + }, + _ => (), + } + }); + }) + } + + Ok(()) + } + + fn stop(&mut self) -> io::Result<()> { + if !self.stream_id.is_none() { + self.event_loop.destroy_stream(self.stream_id); + self.stream_id = None; + self.buffer.clear(); + } + Ok(()) + } + + fn write(&mut self, data: &[i16]) -> io::Result<()> { + // self.0.as_mut().unwrap().write_interleaved(&data).unwrap(); + // self.buffer.reserve(data.len()); // Unneccessary? + // self.buffer.extend_from_slice(data); + self.buffer.extend(data); + Ok(()) + } +} diff --git a/playback/src/audio_backend/mod.rs b/playback/src/audio_backend/mod.rs index 895b0100a..077cdf3ad 100644 --- a/playback/src/audio_backend/mod.rs +++ b/playback/src/audio_backend/mod.rs @@ -34,6 +34,11 @@ mod jackaudio; #[cfg(feature = "jackaudio-backend")] use self::jackaudio::JackSink; +#[cfg(feature = "cpal-backend")] +mod cpal; +#[cfg(feature = "cpal-backend")] +use self::cpal::CpalSink; + mod pipe; use self::pipe::StdoutSink; @@ -46,6 +51,8 @@ pub const BACKENDS: &'static [(&'static str, fn(Option) -> Box)] = ("pulseaudio", mk_sink::), #[cfg(feature = "jackaudio-backend")] ("jackaudio", mk_sink::), + #[cfg(feature = "cpal-backend")] + ("cpal", mk_sink::), ("pipe", mk_sink::), ]; From ac9423d9d99eaf4fcf665e17bd55fe9073b479eb Mon Sep 17 00:00:00 2001 From: Will Stott Date: Thu, 15 Nov 2018 20:55:52 +0000 Subject: [PATCH 02/11] cpal backend builds. Panics building output stream on my system. --- playback/src/audio_backend/cpal.rs | 86 ++++++++++++------------------ 1 file changed, 33 insertions(+), 53 deletions(-) diff --git a/playback/src/audio_backend/cpal.rs b/playback/src/audio_backend/cpal.rs index e493c8ac4..693ee88d6 100644 --- a/playback/src/audio_backend/cpal.rs +++ b/playback/src/audio_backend/cpal.rs @@ -2,18 +2,21 @@ use super::{Open, Sink}; extern crate cpal; use std::io; use std::thread; -use std::collections::VecDeque; +use std::sync::mpsc::{sync_channel, SyncSender}; pub struct CpalSink { - event_loop: cpal::EventLoop, - buffer: mut VecDeque, - stream_id: Option, + // event_loop: cpal::EventLoop, + send: SyncSender, } impl Open for CpalSink { fn open(device: Option) -> CpalSink { info!("Using cpal sink"); + // buffer for samples from librespot (~10ms) + let (tx, rx) = sync_channel::(2 * 1024 * 4); + let event_loop = cpal::EventLoop::new(); + if device.is_some() { // N.B. This is perfectly possible to support. // TODO: First need to enable listing of devices. @@ -21,72 +24,49 @@ impl Open for CpalSink { // TODO: Choose cpal sink by name. panic!("cpal sink does not support specifying a device name"); } + let cpal_device = cpal::default_output_device().expect("no output device available"); + // TODO: Support more formats? Surely cpal will handle that. + let format = cpal::Format{channels: 2, sample_rate: cpal::SampleRate(44100), data_type: cpal::SampleFormat::I16}; - let event_loop = cpal::EventLoop::new(); + let stream_id = event_loop.build_output_stream(&cpal_device, &format).expect("could not build output stream"); + event_loop.play_stream(stream_id); + + thread::spawn(move |/*event_loop, rx*/| { + event_loop.run(move |_stream_id, stream_data| { + match stream_data { + cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::I16(mut buffer) } => { + for (sample, recv) in buffer.iter_mut().zip(rx.try_iter()) { + *sample = recv; + } + }, + _ => (), + } + }); + }); CpalSink { - // Allow an (arbitrary) 2 second buffer before resizing. - buffer: VecDeque::with_capacity(44100 * 2 * 2), - event_loop: event_loop, + send: tx, + // event_loop: event_loop, } } } impl Sink for CpalSink { fn start(&mut self) -> io::Result<()> { - - if self.stream_id.is_none() { - - let device = cpal::default_output_device().expect("no output device available"); - // TODO: Support more formats. - let format = cpal::Format(2, 44100, cpal::SampleFormat::I16); - - self.stream_id = self.event_loop.build_output_stream(&device, &format)?; - - self.event_loop.play_stream(self.stream_id.clone()); - } - - if self.thread.is_none() { - let event_loop = self.event_loop; - let source = self.buffer; - thread::spawn(move |event_loop, source| { - event_loop.run(move |_stream_id, mut stream_data| { - match data { - cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::I16(mut buffer) } => { - let sl = source.len(); - if (sl > buffer.len()) { - sl = buffer.len(); - } - // let u: Vec<_> = source.drain(..sl).collect(); - // buffer[..s1].copy_from_slice(u[..s1]); - - for (sample, data) in buffer.iter_mut().zip(source.drain(..sl)) { - *sample = data; - } - }, - _ => (), - } - }); - }) - } - Ok(()) } fn stop(&mut self) -> io::Result<()> { - if !self.stream_id.is_none() { - self.event_loop.destroy_stream(self.stream_id); - self.stream_id = None; - self.buffer.clear(); - } Ok(()) } fn write(&mut self, data: &[i16]) -> io::Result<()> { - // self.0.as_mut().unwrap().write_interleaved(&data).unwrap(); - // self.buffer.reserve(data.len()); // Unneccessary? - // self.buffer.extend_from_slice(data); - self.buffer.extend(data); + for s in data.iter() { + let res = self.send.send(*s); + if res.is_err() { + error!("jackaudio: cannot write to channel"); + } + } Ok(()) } } From b81bdca707ce4a563a201f8971c603a1d3496f37 Mon Sep 17 00:00:00 2001 From: Will Stott Date: Thu, 15 Nov 2018 21:46:26 +0000 Subject: [PATCH 03/11] QDH: Instantiate audio backend immediately when using "--device ?". --- src/main.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main.rs b/src/main.rs index 2e2d56a38..61290fb16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -200,6 +200,10 @@ fn setup(args: &[String]) -> Setup { let backend = audio_backend::find(backend_name).expect("Invalid backend"); let device = matches.opt_str("device"); + if device == Some("?".into()) { + backend(device); + exit(0); + } let mixer_name = matches.opt_str("mixer"); let mixer = mixer::find(mixer_name.as_ref()).expect("Invalid mixer"); From 1eb5b7d127a2356c511065640519b6cb543b65a2 Mon Sep 17 00:00:00 2001 From: Will Stott Date: Thu, 15 Nov 2018 22:15:57 +0000 Subject: [PATCH 04/11] Turns out I don't have an appropriate output device. --- playback/src/audio_backend/cpal.rs | 31 ++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/playback/src/audio_backend/cpal.rs b/playback/src/audio_backend/cpal.rs index 693ee88d6..8a71b9e4b 100644 --- a/playback/src/audio_backend/cpal.rs +++ b/playback/src/audio_backend/cpal.rs @@ -3,12 +3,39 @@ extern crate cpal; use std::io; use std::thread; use std::sync::mpsc::{sync_channel, SyncSender}; +use std::process::exit; pub struct CpalSink { // event_loop: cpal::EventLoop, send: SyncSender, } +fn list_outputs() { + println!("Default Audio Device:\n {:?}", cpal::default_output_device().map(|e| e.name())); + + println!("Available Audio Devices:"); + for device in cpal::output_devices() { + println!("- {}", device.name()); + // Output formats + if let Ok(fmt) = device.default_output_format() { + println!(" Default format:\n {:?}", fmt); + } + let mut output_formats = match device.supported_output_formats() { + Ok(f) => f.peekable(), + Err(e) => { + println!("Error: {:?}", e); + continue; + }, + }; + if output_formats.peek().is_some() { + println!(" All formats:"); + for format in output_formats { + println!(" {:?}", format); + } + } + } +} + impl Open for CpalSink { fn open(device: Option) -> CpalSink { info!("Using cpal sink"); @@ -18,6 +45,10 @@ impl Open for CpalSink { let event_loop = cpal::EventLoop::new(); if device.is_some() { + if device == Some("?".to_string()) { + list_outputs(); + exit(0) + } // N.B. This is perfectly possible to support. // TODO: First need to enable listing of devices. // Remember to filter to those which support Stereo 16bit 44100Hz From 2c2bfc52acd8d24af04870f4a657d32a5a12eb9f Mon Sep 17 00:00:00 2001 From: Will Stott Date: Wed, 20 Mar 2019 13:24:03 +0000 Subject: [PATCH 05/11] Cpal -> Rodio Doesn't work that well. --- Cargo.toml | 2 +- playback/Cargo.toml | 4 +- playback/src/audio_backend/cpal.rs | 103 ---------------------------- playback/src/audio_backend/mod.rs | 12 ++-- playback/src/audio_backend/rodio.rs | 85 +++++++++++++++++++++++ 5 files changed, 94 insertions(+), 112 deletions(-) delete mode 100644 playback/src/audio_backend/cpal.rs create mode 100644 playback/src/audio_backend/rodio.rs diff --git a/Cargo.toml b/Cargo.toml index 5b6765a27..761b23d49 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -63,7 +63,7 @@ alsa-backend = ["librespot-playback/alsa-backend"] portaudio-backend = ["librespot-playback/portaudio-backend"] pulseaudio-backend = ["librespot-playback/pulseaudio-backend"] jackaudio-backend = ["librespot-playback/jackaudio-backend"] -cpal-backend = ["librespot-playback/cpal-backend"] +rodio-backend = ["librespot-playback/rodio-backend"] with-tremor = ["librespot-audio/with-tremor"] with-vorbis = ["librespot-audio/with-vorbis"] diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 32be6d1fd..6b4e7756e 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -20,11 +20,11 @@ portaudio-rs = { version = "0.3.0", optional = true } libpulse-sys = { version = "0.0.0", optional = true } jack = { version = "0.5.3", optional = true } libc = { version = "0.2", optional = true } -cpal = { version = "0.8.2", optional = true } +rodio = { version = "0.8.1", optional = true, default-features = false } [features] alsa-backend = ["alsa"] portaudio-backend = ["portaudio-rs"] pulseaudio-backend = ["libpulse-sys", "libc"] jackaudio-backend = ["jack"] -cpal-backend = ["cpal"] +rodio-backend = ["rodio"] diff --git a/playback/src/audio_backend/cpal.rs b/playback/src/audio_backend/cpal.rs deleted file mode 100644 index 8a71b9e4b..000000000 --- a/playback/src/audio_backend/cpal.rs +++ /dev/null @@ -1,103 +0,0 @@ -use super::{Open, Sink}; -extern crate cpal; -use std::io; -use std::thread; -use std::sync::mpsc::{sync_channel, SyncSender}; -use std::process::exit; - -pub struct CpalSink { - // event_loop: cpal::EventLoop, - send: SyncSender, -} - -fn list_outputs() { - println!("Default Audio Device:\n {:?}", cpal::default_output_device().map(|e| e.name())); - - println!("Available Audio Devices:"); - for device in cpal::output_devices() { - println!("- {}", device.name()); - // Output formats - if let Ok(fmt) = device.default_output_format() { - println!(" Default format:\n {:?}", fmt); - } - let mut output_formats = match device.supported_output_formats() { - Ok(f) => f.peekable(), - Err(e) => { - println!("Error: {:?}", e); - continue; - }, - }; - if output_formats.peek().is_some() { - println!(" All formats:"); - for format in output_formats { - println!(" {:?}", format); - } - } - } -} - -impl Open for CpalSink { - fn open(device: Option) -> CpalSink { - info!("Using cpal sink"); - - // buffer for samples from librespot (~10ms) - let (tx, rx) = sync_channel::(2 * 1024 * 4); - let event_loop = cpal::EventLoop::new(); - - if device.is_some() { - if device == Some("?".to_string()) { - list_outputs(); - exit(0) - } - // N.B. This is perfectly possible to support. - // TODO: First need to enable listing of devices. - // Remember to filter to those which support Stereo 16bit 44100Hz - // TODO: Choose cpal sink by name. - panic!("cpal sink does not support specifying a device name"); - } - let cpal_device = cpal::default_output_device().expect("no output device available"); - // TODO: Support more formats? Surely cpal will handle that. - let format = cpal::Format{channels: 2, sample_rate: cpal::SampleRate(44100), data_type: cpal::SampleFormat::I16}; - - let stream_id = event_loop.build_output_stream(&cpal_device, &format).expect("could not build output stream"); - event_loop.play_stream(stream_id); - - thread::spawn(move |/*event_loop, rx*/| { - event_loop.run(move |_stream_id, stream_data| { - match stream_data { - cpal::StreamData::Output { buffer: cpal::UnknownTypeOutputBuffer::I16(mut buffer) } => { - for (sample, recv) in buffer.iter_mut().zip(rx.try_iter()) { - *sample = recv; - } - }, - _ => (), - } - }); - }); - - CpalSink { - send: tx, - // event_loop: event_loop, - } - } -} - -impl Sink for CpalSink { - 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(()) - } -} diff --git a/playback/src/audio_backend/mod.rs b/playback/src/audio_backend/mod.rs index 077cdf3ad..85e05d558 100644 --- a/playback/src/audio_backend/mod.rs +++ b/playback/src/audio_backend/mod.rs @@ -34,10 +34,10 @@ mod jackaudio; #[cfg(feature = "jackaudio-backend")] use self::jackaudio::JackSink; -#[cfg(feature = "cpal-backend")] -mod cpal; -#[cfg(feature = "cpal-backend")] -use self::cpal::CpalSink; +#[cfg(feature = "rodio-backend")] +mod rodio; +#[cfg(feature = "rodio-backend")] +use self::rodio::RodioSink; mod pipe; use self::pipe::StdoutSink; @@ -51,8 +51,8 @@ pub const BACKENDS: &'static [(&'static str, fn(Option) -> Box)] = ("pulseaudio", mk_sink::), #[cfg(feature = "jackaudio-backend")] ("jackaudio", mk_sink::), - #[cfg(feature = "cpal-backend")] - ("cpal", mk_sink::), + #[cfg(feature = "rodio-backend")] + ("rodio", mk_sink::), ("pipe", mk_sink::), ]; diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs new file mode 100644 index 000000000..1e6fbb04a --- /dev/null +++ b/playback/src/audio_backend/rodio.rs @@ -0,0 +1,85 @@ +use super::{Open, Sink}; +extern crate rodio; +use std::io; +use std::process::exit; + +pub struct RodioSink { + rodio_sink: rodio::Sink, +} + +fn list_outputs() { + println!("Default Audio Device:\n {:?}", rodio::default_output_device().map(|e| e.name())); + + println!("Available Audio Devices:"); + for device in rodio::output_devices() { + println!("- {}", device.name()); + // Output formats + if let Ok(fmt) = device.default_output_format() { + println!(" Default format:\n {:?}", fmt); + } + let mut output_formats = match device.supported_output_formats() { + Ok(f) => f.peekable(), + Err(e) => { + println!("Error: {:?}", e); + continue; + }, + }; + if output_formats.peek().is_some() { + println!(" All formats:"); + for format in output_formats { + println!(" {:?}", format); + } + } + } +} + +impl Open for RodioSink { + fn open(device: Option) -> RodioSink { + info!("Using rodio sink"); + + let mut rodio_device = rodio::default_output_device().expect("no output device available"); + if device.is_some() { + let device_name = device.unwrap(); + + if device_name == "?".to_string() { + list_outputs(); + exit(0) + } + let mut found = false; + for d in rodio::output_devices() { + if d.name() == device_name { + rodio_device = d; + found = true; + break; + } + } + if !found { + println!("No output sink matching '{}' found.", device_name); + exit(0) + } + } + let sink = rodio::Sink::new(&rodio_device); + + RodioSink { + rodio_sink: sink, + } + } +} + +impl Sink for RodioSink { + fn start(&mut self) -> io::Result<()> { + self.rodio_sink.play(); + Ok(()) + } + + fn stop(&mut self) -> io::Result<()> { + self.rodio_sink.stop(); + Ok(()) + } + + fn write(&mut self, data: &[i16]) -> io::Result<()> { + let source = rodio::buffer::SamplesBuffer::new(2, 44100, data); + self.rodio_sink.append(source); + Ok(()) + } +} From 49fd48b42a671667966352947a352a4b06bd87ef Mon Sep 17 00:00:00 2001 From: Will Stott Date: Fri, 1 Mar 2019 15:43:16 +0000 Subject: [PATCH 06/11] Sink.play is not the opposite of Sink.stop in Rodio --- playback/src/audio_backend/rodio.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs index 1e6fbb04a..6269a7846 100644 --- a/playback/src/audio_backend/rodio.rs +++ b/playback/src/audio_backend/rodio.rs @@ -68,12 +68,15 @@ impl Open for RodioSink { impl Sink for RodioSink { fn start(&mut self) -> io::Result<()> { - self.rodio_sink.play(); + // More similar to an "unpause" than "play". Doesn't undo "stop". + // self.rodio_sink.play(); Ok(()) } fn stop(&mut self) -> io::Result<()> { - self.rodio_sink.stop(); + // This will immediately stop playback, but the sink is then unusable. + // We just have to let the current buffer play till the end. + // self.rodio_sink.stop(); Ok(()) } From 587aa9c711f761f5ce4e30d7c2624397983204a3 Mon Sep 17 00:00:00 2001 From: Will Stott Date: Wed, 20 Mar 2019 13:23:20 +0000 Subject: [PATCH 07/11] Simple block of playback thread based on buffer size. --- playback/Cargo.toml | 2 +- playback/src/audio_backend/rodio.rs | 10 +++++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/playback/Cargo.toml b/playback/Cargo.toml index 6b4e7756e..cf07d65e8 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -20,7 +20,7 @@ portaudio-rs = { version = "0.3.0", optional = true } libpulse-sys = { version = "0.0.0", optional = true } jack = { version = "0.5.3", optional = true } libc = { version = "0.2", optional = true } -rodio = { version = "0.8.1", optional = true, default-features = false } +rodio = { git = "https://github.com/tomaka/rodio", optional = true, default-features = false} [features] alsa-backend = ["alsa"] diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs index 6269a7846..b00a3be61 100644 --- a/playback/src/audio_backend/rodio.rs +++ b/playback/src/audio_backend/rodio.rs @@ -1,6 +1,6 @@ use super::{Open, Sink}; extern crate rodio; -use std::io; +use std::{io, thread, time}; use std::process::exit; pub struct RodioSink { @@ -83,6 +83,14 @@ impl Sink for RodioSink { fn write(&mut self, data: &[i16]) -> io::Result<()> { let source = rodio::buffer::SamplesBuffer::new(2, 44100, data); self.rodio_sink.append(source); + + // Chunk sizes seem to be about 256 to 3000 ish items long. + // Assuming they're on average 1628 then a half second buffer is: + // 44100 elements --> about 27 chunks + while self.rodio_sink.len() > 26 { + // sleep and wait for rodio to drain a bit + thread::sleep(time::Duration::from_millis(10)); + } Ok(()) } } From f1be5085ad5a183146059f6609fb0b50ff7fc9cb Mon Sep 17 00:00:00 2001 From: Will Stott Date: Sun, 10 Mar 2019 18:31:27 +0000 Subject: [PATCH 08/11] Make rodio backend the default --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 761b23d49..d0e962d44 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ with-vorbis = ["librespot-audio/with-vorbis"] with-dns-sd = ["librespot-connect/with-dns-sd"] -default = ["librespot-playback/portaudio-backend"] +default = ["librespot-playback/rodio-backend"] [package.metadata.deb] maintainer = "librespot-org" From 5ceb4db9b805d1f5319e4f53e3edeffa5d21bdaa Mon Sep 17 00:00:00 2001 From: Will Stott Date: Wed, 20 Mar 2019 13:21:50 +0000 Subject: [PATCH 09/11] Improve formatting and macro usage in devices list. --- playback/Cargo.toml | 5 ++- playback/src/audio_backend/rodio.rs | 59 +++++++++++++++++++---------- 2 files changed, 42 insertions(+), 22 deletions(-) diff --git a/playback/Cargo.toml b/playback/Cargo.toml index cf07d65e8..2efd6ca64 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -20,11 +20,12 @@ portaudio-rs = { version = "0.3.0", optional = true } libpulse-sys = { version = "0.0.0", optional = true } jack = { version = "0.5.3", optional = true } libc = { version = "0.2", optional = true } -rodio = { git = "https://github.com/tomaka/rodio", optional = true, default-features = false} +rodio = { git = "https://github.com/tomaka/rodio", optional = true, default-features = false } +cpal = { version = "*", optional = true } [features] alsa-backend = ["alsa"] portaudio-backend = ["portaudio-rs"] pulseaudio-backend = ["libpulse-sys", "libc"] jackaudio-backend = ["jack"] -rodio-backend = ["rodio"] +rodio-backend = ["rodio", "cpal"] diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs index b00a3be61..674a6f7f6 100644 --- a/playback/src/audio_backend/rodio.rs +++ b/playback/src/audio_backend/rodio.rs @@ -1,5 +1,6 @@ use super::{Open, Sink}; extern crate rodio; +extern crate cpal; use std::{io, thread, time}; use std::process::exit; @@ -7,35 +8,53 @@ pub struct RodioSink { rodio_sink: rodio::Sink, } +fn list_formats(ref device: &rodio::Device) { + let default_fmt = match device.default_output_format() { + Ok(fmt) => cpal::SupportedFormat::from(fmt), + Err(e) => { + info!("Error getting default rodio::Sink format: {:?}", e); + return; + }, + }; + + let mut output_formats = match device.supported_output_formats() { + Ok(f) => f.peekable(), + Err(e) => { + info!("Error getting supported rodio::Sink formats: {:?}", e); + return; + }, + }; + + if output_formats.peek().is_some() { + debug!(" Available formats:"); + for format in output_formats { + let s = format!("{}ch, {:?}, min {:?}, max {:?}", format.channels, format.data_type, format.min_sample_rate, format.max_sample_rate); + if format == default_fmt { + debug!(" (default) {}", s); + } else { + debug!(" {:?}", format); + } + } + } +} + fn list_outputs() { - println!("Default Audio Device:\n {:?}", rodio::default_output_device().map(|e| e.name())); + let default_device = rodio::default_output_device().unwrap(); + println!("Default Audio Device:\n {}", default_device.name()); + list_formats(&default_device); - println!("Available Audio Devices:"); + println!("Other Available Audio Devices:"); for device in rodio::output_devices() { - println!("- {}", device.name()); - // Output formats - if let Ok(fmt) = device.default_output_format() { - println!(" Default format:\n {:?}", fmt); - } - let mut output_formats = match device.supported_output_formats() { - Ok(f) => f.peekable(), - Err(e) => { - println!("Error: {:?}", e); - continue; - }, - }; - if output_formats.peek().is_some() { - println!(" All formats:"); - for format in output_formats { - println!(" {:?}", format); - } + if device.name() != default_device.name() { + println!(" {}", device.name()); + list_formats(&device); } } } impl Open for RodioSink { fn open(device: Option) -> RodioSink { - info!("Using rodio sink"); + debug!("Using rodio sink"); let mut rodio_device = rodio::default_output_device().expect("no output device available"); if device.is_some() { From 99703a268ff409755b1ec3004fcb1352863a2f40 Mon Sep 17 00:00:00 2001 From: Will Stott Date: Sun, 17 Mar 2019 15:30:32 +0000 Subject: [PATCH 10/11] Warn when there's a Rodio failure accessing a default device formats. --- playback/src/audio_backend/rodio.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/playback/src/audio_backend/rodio.rs b/playback/src/audio_backend/rodio.rs index 674a6f7f6..c4b9c927e 100644 --- a/playback/src/audio_backend/rodio.rs +++ b/playback/src/audio_backend/rodio.rs @@ -12,7 +12,7 @@ fn list_formats(ref device: &rodio::Device) { let default_fmt = match device.default_output_format() { Ok(fmt) => cpal::SupportedFormat::from(fmt), Err(e) => { - info!("Error getting default rodio::Sink format: {:?}", e); + warn!("Error getting default rodio::Sink format: {:?}", e); return; }, }; @@ -20,7 +20,7 @@ fn list_formats(ref device: &rodio::Device) { let mut output_formats = match device.supported_output_formats() { Ok(f) => f.peekable(), Err(e) => { - info!("Error getting supported rodio::Sink formats: {:?}", e); + warn!("Error getting supported rodio::Sink formats: {:?}", e); return; }, }; From 3548917914bc4c7694758326aa7019c1c205e490 Mon Sep 17 00:00:00 2001 From: Will Stott Date: Wed, 20 Mar 2019 13:30:10 +0000 Subject: [PATCH 11/11] Update Cargo.lock with successful windows build. --- Cargo.lock | 262 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 262 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 27ce7e846..59b6ee228 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -57,6 +57,28 @@ dependencies = [ "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "alsa-sys" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "approx" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "arc-swap" version = "0.3.7" @@ -70,6 +92,16 @@ dependencies = [ "nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "atty" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "autocfg" version = "0.1.2" @@ -92,6 +124,25 @@ dependencies = [ "safemem 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "bindgen" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "clang-sys 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)", + "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "bit-set" version = "0.4.0" @@ -190,11 +241,53 @@ name = "cc" version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cexpr" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cfg-if" version = "0.1.7" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "cgmath" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "clang-sys" +version = "0.21.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "clap" +version = "2.32.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "cloudabi" version = "0.0.3" @@ -203,6 +296,45 @@ dependencies = [ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "core-foundation-sys" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "coreaudio-rs" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "coreaudio-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "coreaudio-sys" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bindgen 0.32.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cpal" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "alsa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "coreaudio-rs 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "stdweb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.7.1" @@ -402,6 +534,11 @@ dependencies = [ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "glob" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "hex" version = "0.3.2" @@ -699,6 +836,7 @@ version = "0.1.0" dependencies = [ "alsa 0.0.1 (git+https://github.com/plietar/rust-alsa)", "byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cpal 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", "jack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)", "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", @@ -708,6 +846,7 @@ dependencies = [ "librespot-metadata 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "portaudio-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rodio 0.8.1 (git+https://github.com/tomaka/rodio)", ] [[package]] @@ -774,6 +913,14 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "memchr" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "memchr" version = "2.2.0" @@ -886,6 +1033,14 @@ name = "nodrop" version = "0.1.13" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "nom" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "num-bigint" version = "0.1.44" @@ -992,6 +1147,11 @@ dependencies = [ "subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "peeking_take_while" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "percent-encoding" version = "1.0.1" @@ -1021,6 +1181,14 @@ dependencies = [ "pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "proc-macro2" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "proc-macro2" version = "0.4.27" @@ -1066,6 +1234,14 @@ name = "quote" version = "0.3.15" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "quote" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "quote" version = "0.6.11" @@ -1216,6 +1392,14 @@ name = "redox_syscall" version = "0.1.51" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "redox_termios" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "regex" version = "0.2.11" @@ -1244,6 +1428,16 @@ dependencies = [ "futures 0.1.25 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rodio" +version = "0.8.1" +source = "git+https://github.com/tomaka/rodio#8dd11878ff907b6feecafa8f842a8220ba5841d6" +dependencies = [ + "cgmath 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", + "cpal 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "rpassword" version = "0.3.1" @@ -1435,6 +1629,11 @@ name = "stable_deref_trait" version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "stdweb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "stream-cipher" version = "0.3.0" @@ -1443,6 +1642,11 @@ dependencies = [ "generic-array 0.12.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "strsim" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "subtle" version = "1.0.0" @@ -1493,6 +1697,16 @@ dependencies = [ "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "termion" +version = "1.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)", + "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "termios" version = "0.2.2" @@ -1501,6 +1715,14 @@ dependencies = [ "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "textwrap" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "thread_local" version = "0.3.6" @@ -1882,6 +2104,11 @@ dependencies = [ "rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "vec_map" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "vergen" version = "0.1.1" @@ -1959,6 +2186,14 @@ dependencies = [ "try-lock 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "which" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.50 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "winapi" version = "0.2.8" @@ -2004,11 +2239,16 @@ dependencies = [ "checksum aesni 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2f70a6b5f971e473091ab7cfb5ffac6cde81666c4556751d8d5620ead8abf100" "checksum aho-corasick 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "81ce3d38065e618af2d7b77e10c5ad9a069859b4be3c2250f674af3840d9c8a5" "checksum alsa 0.0.1 (git+https://github.com/plietar/rust-alsa)" = "" +"checksum alsa-sys 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b0edcbbf9ef68f15ae1b620f722180b82a98b6f0628d30baa6b8d2a5abc87d58" +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum approx 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "08abcc3b4e9339e33a3d0a5ed15d84a687350c05689d825e0f6655eef9e76a94" "checksum arc-swap 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1025aeae2b664ca0ea726a89d574fe8f4e77dd712d443236ad1de00379450cf6" "checksum arrayvec 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "92c7fb76bc8826a8b33b4ee5bb07a247a81e76764ab4d55e8f73e3a4d8808c71" +"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652" "checksum autocfg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a6d640bee2da49f60a4068a7fae53acde8982514ab7bae8b8cea9e88cbcfd799" "checksum base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "30e93c03064e7590d0466209155251b90c22e37fab1daf2771582598b5827557" "checksum base64 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "489d6c0ed21b11d038c31b6ceccca973e65d73ba3bd8ecb9a2babf5546164643" +"checksum bindgen 0.32.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8b242e11a8f446f5fc7b76b37e81d737cabca562a927bd33766dac55b5f1177f" "checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c" "checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f" "checksum bitflags 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "32866f4d103c4e438b1db1158aa1b1a80ee078e5d77a59a2f906fd62a577389c" @@ -2024,8 +2264,16 @@ dependencies = [ "checksum bytes 0.4.12 (registry+https://github.com/rust-lang/crates.io-index)" = "206fdffcfa2df7cbe15601ef46c813fce0965eb3286db6b56c583b814b51c81c" "checksum c_linked_list 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4964518bd3b4a8190e832886cdc0da9794f12e8e6c1613a9e90ff331c4c8724b" "checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d" +"checksum cexpr 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "42aac45e9567d97474a834efdee3081b3c942b2205be932092f53354ce503d6c" "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" +"checksum cgmath 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "87f025a17ad3f30d49015c787903976d5f9cd6115ece1eb7f4d6ffe06b8c4080" +"checksum clang-sys 0.21.2 (registry+https://github.com/rust-lang/crates.io-index)" = "e414af9726e1d11660801e73ccc7fb81803fb5f49e5903a25b348b2b3b480d2e" +"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e" "checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +"checksum core-foundation-sys 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "716c271e8613ace48344f723b60b900a93150271e5be206212d052bbc0883efa" +"checksum coreaudio-rs 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f229761965dad3e9b11081668a6ea00f1def7aa46062321b5ec245b834f6e491" +"checksum coreaudio-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "78fdbabf58d5b1f461e31b94a571c109284f384cec619a3d96e66ec55b4de82b" +"checksum cpal 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d58ae1ed6536b1b233f5e3aeb6997a046ddb4d05e3f61701b58a92eb254a829e" "checksum crossbeam-deque 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b18cd2e169ad86297e6bc0ad9aa679aee9daa4f19e8163860faf7c164e4f5a71" "checksum crossbeam-epoch 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "04c9e3102cc2d69cd681412141b390abd55a362afc1540965dad0ad4d34280b4" "checksum crossbeam-queue 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7c979cd6cfe72335896575c6b5688da489e420d36a27a0b9eb0c73db574b4a4b" @@ -2051,6 +2299,7 @@ dependencies = [ "checksum get_if_addrs 0.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "abddb55a898d32925f3148bd281174a68eeb68bbfd9a5938a57b18f506ee4ef7" "checksum get_if_addrs-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0d04f9fb746cf36b191c00f3ede8bde9c8e64f9f4b05ae2694a9ccf5e3f5ab48" "checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" +"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb" "checksum hex 0.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "805026a5d0141ffc30abb3be3173848ad46a1b1664fe632428479619a3644d77" "checksum hmac 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f127a908633569f208325f86f71255d3363c79721d7f9fe31cd5569908819771" "checksum httparse 1.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e8734b0cfd3bc3e101ec59100e101c2eecd19282202e87808b3037b442777a83" @@ -2076,6 +2325,7 @@ dependencies = [ "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum matches 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" "checksum mdns 0.2.0 (git+https://github.com/plietar/rust-mdns)" = "" +"checksum memchr 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "148fab2e51b4f1cfc66da2a7c32981d1d3c083a803978268bb11fe4b86925e7a" "checksum memchr 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2efc7bc57c883d4a4d6e3246905283d8dae951bb3bd32f49d6ef297f546e1c39" "checksum memoffset 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0f9dc261e2b62d7a622bf416ea3c5245cdd5d9a7fcc428c0d06804dfce1775b3" "checksum mime 0.3.13 (registry+https://github.com/rust-lang/crates.io-index)" = "3e27ca21f40a310bd06d9031785f4801710d566c184a6e15bad4f1d9b65f9425" @@ -2088,6 +2338,7 @@ dependencies = [ "checksum net2 0.2.33 (registry+https://github.com/rust-lang/crates.io-index)" = "42550d9fb7b6684a6d404d9fa7250c2eb2646df731d1c06afc06dcee9e1bcf88" "checksum nix 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d37e713a259ff641624b6cb20e3b12b2952313ba36b6823c0f16e6cfd9e5de17" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" +"checksum nom 3.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05aec50c70fd288702bcd93284a8444607f3292dbdf2a30de5ea5dcdbe72287b" "checksum num-bigint 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "e63899ad0da84ce718c14936262a41cee2c79c981fc0a0e7c7beb47d5a07e8c1" "checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea" "checksum num-traits 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" @@ -2100,10 +2351,12 @@ dependencies = [ "checksum parking_lot 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ab41b4aed082705d1056416ae4468b6ea99d52599ecf3169b00088d43113e337" "checksum parking_lot_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "94c8c7923936b28d546dfd14d4472eaf34c99b14e1c973a32b3e6d4eb04298c9" "checksum pbkdf2 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "006c038a43a45995a9670da19e67600114740e8511d4333bf97a56e66a7542d9" +"checksum peeking_take_while 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" "checksum percent-encoding 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "31010dd2e1ac33d5b46a5b413495239882813e0369f8ed8a5e266f173602f831" "checksum pkg-config 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)" = "676e8eb2b1b4c9043511a9b7bea0915320d7e502b0a079fb03f9635a5252b18c" "checksum portaudio-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "029e0ab393b44b2d825efbc755cae51c36be7a99d91356b2052be0ed05836636" "checksum portaudio-sys 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "5194a4fa953b4ffd851c320ef6f0484cd7278cb7169ea9d6c433e49b23f7b7f5" +"checksum proc-macro2 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "cd07deb3c6d1d9ff827999c7f9b04cdfd66b1b17ae508e14fe47b620f2282ae0" "checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915" "checksum protobuf 1.7.4 (registry+https://github.com/rust-lang/crates.io-index)" = "52fbc45bf6709565e44ef31847eb7407b3c3c80af811ee884a04da071dcca12b" "checksum protobuf 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "24d5d73d2b88fddb8b8141f2730d950d88772c940ac4f8f3e93230b9a99d92df" @@ -2111,6 +2364,7 @@ dependencies = [ "checksum protobuf-codegen-pure 2.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "48b7a5dbe7e07265974a3897320af02372c63562ecf6514a0f0bce50812003bb" "checksum quick-error 1.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9274b940887ce9addde99c4eee6b5c44cc494b182b97e73dc8ffdcb3397fd3f0" "checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a" +"checksum quote 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1eca14c727ad12702eb4b6bfb5a232287dcf8385cb8ca83a3eeaf6519c44c408" "checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1" "checksum rand 0.3.23 (registry+https://github.com/rust-lang/crates.io-index)" = "64ac302d8f83c0c1974bf758f6b041c6c8ada916fbb44a609158ca8b064cc76c" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" @@ -2127,9 +2381,11 @@ dependencies = [ "checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" "checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" "checksum redox_syscall 0.1.51 (registry+https://github.com/rust-lang/crates.io-index)" = "423e376fffca3dfa06c9e9790a9ccd282fafb3cc6e6397d01dbf64f9bacc6b85" +"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76" "checksum regex 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9329abc99e39129fcceabd24cf5d85b4671ef7c29c50e972bc5afe32438ec384" "checksum regex-syntax 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "7d707a4fa2637f2dca2ef9fd02225ec7661fe01a53623c1e6515b6916511f7a7" "checksum relay 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1576e382688d7e9deecea24417e350d3062d97e32e45d70b1cde65994ff1489a" +"checksum rodio 0.8.1 (git+https://github.com/tomaka/rodio)" = "" "checksum rpassword 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ec4bdede957362ec6fdd550f7e79c6d14cad2bc26b2d062786234c6ee0cb27bb" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" @@ -2155,14 +2411,18 @@ dependencies = [ "checksum socket2 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "36b4896961171cd3317c7e9603d88f379f8c6e45342212235d356496680c68fd" "checksum socket2 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "c4d11a52082057d87cb5caa31ad812f4504b97ab44732cd8359df2e9ff9f48e7" "checksum stable_deref_trait 1.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "dba1a27d3efae4351c8051072d619e3ade2820635c3958d826bfea39d59b54c8" +"checksum stdweb 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ef5430c8e36b713e13b48a9f709cc21e046723fe44ce34587b73a830203b533e" "checksum stream-cipher 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8861bc80f649f5b4c9bd38b696ae9af74499d479dbfb327f0607de6b326a36bc" +"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550" "checksum subtle 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2d67a5a62ba6e01cb2192ff309324cb4875d0c451d55fe2319433abe7a05a8ee" "checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad" "checksum syn 0.15.29 (registry+https://github.com/rust-lang/crates.io-index)" = "1825685f977249735d510a242a6727b46efe914bb67e38d30c071b1b72b1d5c2" "checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6" "checksum take 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b157868d8ac1f56b64604539990685fa7611d8fa9e5476cf0c02cf34d32917c5" "checksum tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "11ce2fe9db64b842314052e2421ac61a73ce41b898dc8e3750398b219c5fc1e0" +"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096" "checksum termios 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d5d9cf598a6d7ce700a4e6a9199da127e6819a61e64b68609683cc9a01b5683a" +"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6" "checksum thread_local 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c6b53e329000edc2b34dbe8545fd20e55a333362d0a321909685a19bd28c3f1b" "checksum time 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "db8dcfca086c1143c9270ac42a2bbd8a7ee477b78ac8e45b19abfb0cbede4b6f" "checksum tokio 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)" = "1021bb1f4150435ab8f222eb7ed37c60b2d57037def63ba43085a79f387512d7" @@ -2199,6 +2459,7 @@ dependencies = [ "checksum url 1.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "dd4e7c0d531266369519a4aa4f399d748bd37043b00bde1e4ff1f60a120b355a" "checksum utf8-ranges 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "796f7e48bef87609f7ade7e06495a87d5cd06c7866e6a5cbfceffc558a243737" "checksum uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7cfec50b0842181ba6e713151b72f4ec84a6a7e2c9c8a8a3ffc37bb1cd16b231" +"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a" "checksum vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c3365f36c57e5df714a34be40902b27a992eeddb9996eca52d0584611cf885d" "checksum version_check 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "914b1a6776c4c929a602fafd8bc742e06365d4bcbe48c30f9cca5824f70dc9dd" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" @@ -2207,6 +2468,7 @@ dependencies = [ "checksum vorbis-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "729e1f15395850b4e6d19ca0cd1d42ef44707503a53b69d40ff49182b3c5589d" "checksum vorbisfile-sys 0.0.8 (registry+https://github.com/rust-lang/crates.io-index)" = "4f4306d7e1ac4699b55e20de9483750b90c250913188efd7484db6bfbe9042d1" "checksum want 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a05d9d966753fa4b5c8db73fcab5eed4549cfe0e1e4e66911e5564a0085c35d1" +"checksum which 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e84a603e7e0b1ce1aa1ee2b109c7be00155ce52df5081590d1ffb93f4f515cb2" "checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"