From adeb22b2f31e904568b92c1d103b7681ed08dda7 Mon Sep 17 00:00:00 2001 From: loblik Date: Thu, 5 Oct 2017 20:41:02 +0200 Subject: [PATCH 01/70] add support for jack audio connection kit This is initial support for JACK. It creates ports at startup and keeps it connected while librespot is running. So when librespot playback is stoped it writes silence (zeroes). It uses jack crate (rust-jack) which needs libjack. To compile in jack support use --features jackaudio-backend. And run librespot with --backend jackaudio. --- Cargo.toml | 2 + src/audio_backend/jackaudio.rs | 79 ++++++++++++++++++++++++++++++++++ src/audio_backend/mod.rs | 7 +++ src/lib.rs | 3 ++ 4 files changed, 91 insertions(+) create mode 100644 src/audio_backend/jackaudio.rs diff --git a/Cargo.toml b/Cargo.toml index f4e63498..c2a8d87f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -52,6 +52,7 @@ url = "1.3" alsa = { git = "https://github.com/plietar/rust-alsa", optional = true } portaudio-rs = { version = "0.3.0", optional = true } libpulse-sys = { version = "0.0.0", optional = true } +jack = { version = "0.5.3", optional = true } [build-dependencies] rand = "0.3.13" @@ -62,6 +63,7 @@ protobuf_macros = { git = "https://github.com/plietar/rust-protobuf-macros", fea alsa-backend = ["alsa"] portaudio-backend = ["portaudio-rs"] pulseaudio-backend = ["libpulse-sys"] +jackaudio-backend = ["jack"] with-tremor = ["librespot-audio/with-tremor"] with-lewton = ["librespot-audio/with-lewton"] diff --git a/src/audio_backend/jackaudio.rs b/src/audio_backend/jackaudio.rs new file mode 100644 index 00000000..e1a67aec --- /dev/null +++ b/src/audio_backend/jackaudio.rs @@ -0,0 +1,79 @@ +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(()) + } +} diff --git a/src/audio_backend/mod.rs b/src/audio_backend/mod.rs index 1effc05a..be73bf6c 100644 --- a/src/audio_backend/mod.rs +++ b/src/audio_backend/mod.rs @@ -29,6 +29,11 @@ mod pulseaudio; #[cfg(feature = "pulseaudio-backend")] use self::pulseaudio::PulseAudioSink; +#[cfg(feature = "jackaudio-backend")] +mod jackaudio; +#[cfg(feature = "jackaudio-backend")] +use self::jackaudio::JackSink; + mod pipe; use self::pipe::StdoutSink; @@ -41,6 +46,8 @@ pub const BACKENDS : &'static [ ("portaudio", mk_sink::), #[cfg(feature = "pulseaudio-backend")] ("pulseaudio", mk_sink::), + #[cfg(feature = "jackaudio-backend")] + ("jackaudio", mk_sink::), ("pipe", mk_sink::), ]; diff --git a/src/lib.rs b/src/lib.rs index b9c920ec..5a9274b9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -34,6 +34,9 @@ extern crate portaudio_rs; #[cfg(feature = "libpulse-sys")] extern crate libpulse_sys; +#[cfg(feature = "jackaudio-backend")] +extern crate jack; + pub mod audio_backend; pub mod discovery; pub mod keymaster; From 4870acd572c8de86b9c71d308363485111c3725a Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 25 Jan 2018 23:37:28 +0100 Subject: [PATCH 02/70] Add --progressive-volume option. Increase volume slowly at low level, faster at higher level --- core/src/config.rs | 1 + src/main.rs | 11 ++++++++--- src/spirc.rs | 49 ++++++++++++++++++++++++++++++++++++---------- 3 files changed, 48 insertions(+), 13 deletions(-) diff --git a/core/src/config.rs b/core/src/config.rs index 46b22e41..aab65e69 100644 --- a/core/src/config.rs +++ b/core/src/config.rs @@ -122,4 +122,5 @@ pub struct ConnectConfig { pub name: String, pub device_type: DeviceType, pub volume: i32, + pub progressive_volume: bool, } diff --git a/src/main.rs b/src/main.rs index c6208f2b..27d91d21 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,7 +101,8 @@ fn setup(args: &[String]) -> Setup { .optopt("", "backend", "Audio backend to use. Use '?' to list options", "BACKEND") .optopt("", "device", "Audio device to use. Use '?' to list options", "DEVICE") .optopt("", "mixer", "Mixer to use", "MIXER") - .optopt("", "initial-volume", "Initial volume in %, once connected (must be from 0 to 100)", "VOLUME"); + .optopt("", "initial-volume", "Initial volume in %, once connected (must be from 0 to 100)", "VOLUME") + .optflag("", "progressive-volume", "Increase volume slowly at low level, faster at high level"); let matches = match opts.parse(&args[1..]) { Ok(m) => m, @@ -159,8 +160,11 @@ fn setup(args: &[String]) -> Setup { // if argument not present use default values (50%) else{ initial_volume = 0x8000 as i32; - } - debug!("Volume \"{}\" !", initial_volume); + } + + let progressive_volume = matches.opt_present("progressive-volume"); + info!("Volume:{}, progressive_volume: {}.", initial_volume, progressive_volume); + let name = matches.opt_str("name").unwrap(); let use_audio_cache = !matches.opt_present("disable-audio-cache"); @@ -209,6 +213,7 @@ fn setup(args: &[String]) -> Setup { name: name, device_type: device_type, volume: initial_volume, + progressive_volume, } }; diff --git a/src/spirc.rs b/src/spirc.rs index 795ba68f..f60d7ac0 100644 --- a/src/spirc.rs +++ b/src/spirc.rs @@ -17,12 +17,14 @@ use protocol::spirc::{PlayStatus, State, MessageType, Frame, DeviceState}; use mixer::Mixer; use player::Player; +use std; use rand; use rand::Rng; pub struct SpircTask { player: Player, mixer: Box, + progressive_volume:bool, sequence: SeqGenerator, @@ -122,6 +124,33 @@ fn initial_device_state(config: ConnectConfig, volume: u16) -> DeviceState { }) } +fn volume_to_mixer(volume: u16, progressive: bool) -> u16 { + if progressive { + // Some by trail determined volume calculation algorithm. Start increasing slowly, + // then after 50% increase in bigger steps. + let d = volume / (std::u16::MAX / 100); + let mut v:u32 = 0; + let mut incr:u32 = 0; + for i in 0..d { + v += incr; + incr +=3; + if i > 50 { + // Increase faster to reach max volume + incr += 42; + } + } + + // Clip the vulume to the max + if v > std::u16::MAX as u32 {v = std::u16::MAX as u32;} + debug!("volume_to_mixer {} {}", volume, v); + return v as u16; + } else { + debug!("volume_to_mixer {}", volume); + return volume; + } +} + + impl Spirc { pub fn new(config: ConnectConfig, session: Session, player: Player, mixer: Box) -> (Spirc, SpircTask) @@ -144,15 +173,15 @@ impl Spirc { })); let (cmd_tx, cmd_rx) = mpsc::unbounded(); - + let progressive_volume = config.progressive_volume; let volume = config.volume as u16; let device = initial_device_state(config, volume); - mixer.set_volume(volume as u16); + mixer.set_volume(volume_to_mixer(volume as u16, progressive_volume)); let mut task = SpircTask { player: player, mixer: mixer, - + progressive_volume, sequence: SeqGenerator::new(1), ident: ident, @@ -439,9 +468,9 @@ impl SpircTask { } MessageType::kMessageTypeVolume => { - let volume = frame.get_volume(); - self.device.set_volume(volume); - self.mixer.set_volume(frame.get_volume() as u16); + self.device.set_volume(frame.get_volume()); + self.mixer.set_volume( + volume_to_mixer(frame.get_volume() as u16, self.progressive_volume)); self.notify(None); } @@ -536,21 +565,21 @@ impl SpircTask { } fn handle_volume_up(&mut self) { - let mut volume: u32 = self.mixer.volume() as u32 + 4096; + let mut volume: u32 = self.device.get_volume() as u32 + 4096; if volume > 0xFFFF { volume = 0xFFFF; } self.device.set_volume(volume); - self.mixer.set_volume(volume as u16); + self.mixer.set_volume(volume_to_mixer(volume as u16, self.progressive_volume)); } fn handle_volume_down(&mut self) { - let mut volume: i32 = self.mixer.volume() as i32 - 4096; + let mut volume: i32 = self.device.get_volume() as i32 - 4096; if volume < 0 { volume = 0; } self.device.set_volume(volume as u32); - self.mixer.set_volume(volume as u16); + self.mixer.set_volume(volume_to_mixer(volume as u16, self.progressive_volume)); } fn handle_end_of_track(&mut self) { From 67adb06859d951755369ecd887e152e48f34fea4 Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 26 Jan 2018 01:10:52 +0100 Subject: [PATCH 03/70] update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index bd8bf64c..f1d648b9 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ target/release/librespot --username USERNAME --cache CACHEDIR --name DEVICENAME | Option | | device | Audio device to use. Use '?' to list options | DEVICE | | Option | | mixer | Mixer to use | MIXER | | Option | | initial-volume | Initial volume in %, once connected [0-100] | VOLUME | +| Flag | | progressive-volume | Increase volume slowly at low level | | Taken from here: https://github.com/ComlOnline/librespot/blob/master/src/main.rs#L88 From f5b70c4cb6fd09e49e3f4851819853fb0c46005e Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 26 Jan 2018 01:10:52 +0100 Subject: [PATCH 04/70] update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index bd8bf64c..f1d648b9 100644 --- a/README.md +++ b/README.md @@ -73,6 +73,7 @@ target/release/librespot --username USERNAME --cache CACHEDIR --name DEVICENAME | Option | | device | Audio device to use. Use '?' to list options | DEVICE | | Option | | mixer | Mixer to use | MIXER | | Option | | initial-volume | Initial volume in %, once connected [0-100] | VOLUME | +| Flag | | progressive-volume | Increase volume slowly at low level | | Taken from here: https://github.com/ComlOnline/librespot/blob/master/src/main.rs#L88 From de7d341faa3505b1ff4160f4819196ad9be32b88 Mon Sep 17 00:00:00 2001 From: thekr1s Date: Fri, 26 Jan 2018 01:17:31 +0100 Subject: [PATCH 05/70] update README.md --- README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 README.md diff --git a/README.md b/README.md old mode 100644 new mode 100755 From 752a6b1df444cae138f946ed13eca80e498b1e7b Mon Sep 17 00:00:00 2001 From: Robert Date: Fri, 26 Jan 2018 01:42:24 +0100 Subject: [PATCH 06/70] Prevent crash in audio_backend/alsa.rs when switching from Kodi audio to librespot --- src/audio_backend/alsa.rs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/audio_backend/alsa.rs b/src/audio_backend/alsa.rs index ce459380..42f590bf 100644 --- a/src/audio_backend/alsa.rs +++ b/src/audio_backend/alsa.rs @@ -18,10 +18,17 @@ impl Sink for AlsaSink { fn start(&mut self) -> io::Result<()> { if self.0.is_some() { } else { - self.0 = Some(PCM::open(&*self.1, + match PCM::open(&*self.1, Stream::Playback, Mode::Blocking, Format::Signed16, Access::Interleaved, - 2, 44100).ok().unwrap()); + 2, 44100) { + Ok(f) => self.0 = Some(f), + Err(e) => { + self.0 = None; + error!("Alsa error PCM open {}", e); + return Err(io::Error::new(io::ErrorKind::Other, "Alsa error: PCM open failed")); + } + } } Ok(()) } From bec6b8c512ff2d2e7c4aa3d7819e02dd8fca73f8 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 29 Jan 2018 23:37:30 +0100 Subject: [PATCH 07/70] Changed volume control after discussion: https://github.com/librespot-org/librespot/pull/10 implement exponential volume control only --- README.md | 1 - core/src/config.rs | 1 - src/main.rs | 11 +++------ src/spirc.rs | 56 +++++++++++++++++++++------------------------- 4 files changed, 28 insertions(+), 41 deletions(-) mode change 100755 => 100644 README.md diff --git a/README.md b/README.md old mode 100755 new mode 100644 index f1d648b9..bd8bf64c --- a/README.md +++ b/README.md @@ -73,7 +73,6 @@ target/release/librespot --username USERNAME --cache CACHEDIR --name DEVICENAME | Option | | device | Audio device to use. Use '?' to list options | DEVICE | | Option | | mixer | Mixer to use | MIXER | | Option | | initial-volume | Initial volume in %, once connected [0-100] | VOLUME | -| Flag | | progressive-volume | Increase volume slowly at low level | | Taken from here: https://github.com/ComlOnline/librespot/blob/master/src/main.rs#L88 diff --git a/core/src/config.rs b/core/src/config.rs index aab65e69..46b22e41 100644 --- a/core/src/config.rs +++ b/core/src/config.rs @@ -122,5 +122,4 @@ pub struct ConnectConfig { pub name: String, pub device_type: DeviceType, pub volume: i32, - pub progressive_volume: bool, } diff --git a/src/main.rs b/src/main.rs index 27d91d21..c6208f2b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,8 +101,7 @@ fn setup(args: &[String]) -> Setup { .optopt("", "backend", "Audio backend to use. Use '?' to list options", "BACKEND") .optopt("", "device", "Audio device to use. Use '?' to list options", "DEVICE") .optopt("", "mixer", "Mixer to use", "MIXER") - .optopt("", "initial-volume", "Initial volume in %, once connected (must be from 0 to 100)", "VOLUME") - .optflag("", "progressive-volume", "Increase volume slowly at low level, faster at high level"); + .optopt("", "initial-volume", "Initial volume in %, once connected (must be from 0 to 100)", "VOLUME"); let matches = match opts.parse(&args[1..]) { Ok(m) => m, @@ -160,11 +159,8 @@ fn setup(args: &[String]) -> Setup { // if argument not present use default values (50%) else{ initial_volume = 0x8000 as i32; - } - - let progressive_volume = matches.opt_present("progressive-volume"); - info!("Volume:{}, progressive_volume: {}.", initial_volume, progressive_volume); - + } + debug!("Volume \"{}\" !", initial_volume); let name = matches.opt_str("name").unwrap(); let use_audio_cache = !matches.opt_present("disable-audio-cache"); @@ -213,7 +209,6 @@ fn setup(args: &[String]) -> Setup { name: name, device_type: device_type, volume: initial_volume, - progressive_volume, } }; diff --git a/src/spirc.rs b/src/spirc.rs index f60d7ac0..422340ae 100644 --- a/src/spirc.rs +++ b/src/spirc.rs @@ -24,7 +24,6 @@ use rand::Rng; pub struct SpircTask { player: Player, mixer: Box, - progressive_volume:bool, sequence: SeqGenerator, @@ -124,30 +123,26 @@ fn initial_device_state(config: ConnectConfig, volume: u16) -> DeviceState { }) } -fn volume_to_mixer(volume: u16, progressive: bool) -> u16 { - if progressive { - // Some by trail determined volume calculation algorithm. Start increasing slowly, - // then after 50% increase in bigger steps. - let d = volume / (std::u16::MAX / 100); - let mut v:u32 = 0; - let mut incr:u32 = 0; - for i in 0..d { - v += incr; - incr +=3; - if i > 50 { - // Increase faster to reach max volume - incr += 42; - } - } - - // Clip the vulume to the max - if v > std::u16::MAX as u32 {v = std::u16::MAX as u32;} - debug!("volume_to_mixer {} {}", volume, v); - return v as u16; - } else { - debug!("volume_to_mixer {}", volume); - return volume; +fn volume_to_mixer(volume: u16) -> u16 { + // Volume conversion taken from https://www.dr-lex.be/info-stuff/volumecontrols.html#ideal2 + // Convert the given volume [0..0xffff] to a dB gain + // We assume a dB range of 60dB. + // Use the equatation: a * exp(b * x) + // in which a = IDEAL_FACTOR, b = 1/1000 + const IDEAL_FACTOR: f64 = 6.908; + let normalized_volume = volume as f64 / std::u16::MAX as f64; // To get a value between 0 and 1 + + let mut val = std::u16::MAX; + // Prevent val > std::u16::MAX due to rounding errors + if normalized_volume < 0.999 { + let new_volume = (normalized_volume * IDEAL_FACTOR).exp() / 1000.0; + val = (new_volume * std::u16::MAX as f64) as u16; } + + debug!("input volume:{} to mixer: {}", volume, val); + + // return the scale factor (0..0xffff) (equivalent to a voltage multiplier). + val } @@ -173,15 +168,15 @@ impl Spirc { })); let (cmd_tx, cmd_rx) = mpsc::unbounded(); - let progressive_volume = config.progressive_volume; + let volume = config.volume as u16; let device = initial_device_state(config, volume); - mixer.set_volume(volume_to_mixer(volume as u16, progressive_volume)); + mixer.set_volume(volume_to_mixer(volume as u16)); let mut task = SpircTask { player: player, mixer: mixer, - progressive_volume, + sequence: SeqGenerator::new(1), ident: ident, @@ -469,8 +464,7 @@ impl SpircTask { MessageType::kMessageTypeVolume => { self.device.set_volume(frame.get_volume()); - self.mixer.set_volume( - volume_to_mixer(frame.get_volume() as u16, self.progressive_volume)); + self.mixer.set_volume(volume_to_mixer(frame.get_volume() as u16)); self.notify(None); } @@ -570,7 +564,7 @@ impl SpircTask { volume = 0xFFFF; } self.device.set_volume(volume); - self.mixer.set_volume(volume_to_mixer(volume as u16, self.progressive_volume)); + self.mixer.set_volume(volume_to_mixer(volume as u16)); } fn handle_volume_down(&mut self) { @@ -579,7 +573,7 @@ impl SpircTask { volume = 0; } self.device.set_volume(volume as u32); - self.mixer.set_volume(volume_to_mixer(volume as u16, self.progressive_volume)); + self.mixer.set_volume(volume_to_mixer(volume as u16)); } fn handle_end_of_track(&mut self) { From bc7ceb3f65107f68ed7d2ee1db4e66e981a855b6 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Tue, 30 Jan 2018 17:42:32 +0100 Subject: [PATCH 08/70] Update To-Do --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 623a56f9..a56ed869 100644 --- a/README.md +++ b/README.md @@ -56,9 +56,11 @@ https://gitter.im/sashahilton00/spotify-connect-resources ## To-Do/Feature Requests If there is a feature request that is being considered, or has been widely requested, it should be listed below. Please do not use this for bug reports or special use case feature requests. +- [ ] Add support for contexts (used by dynamic playlists, Spotify Radio, green now-playing bar, etc.) ([#57](https://github.com/librespot-org/librespot/issues/57)) - [ ] Document the Spotify Protocol and provide reference example. - [ ] Implement API to allow wrappers to be written for librespot. -- [ ] Logarithmic volume scaling ([#10](https://github.com/librespot-org/librespot/issues/10)) +- [x] Logarithmic volume scaling ([#10](https://github.com/librespot-org/librespot/issues/10)) +- [ ] Fix Shuffle & Repeat functionality - [ ] Provide automatic release binaries for download - [ ] Provide an adequate method for exporting metadata ([#7](https://github.com/librespot-org/librespot/issues/7)) - [ ] Provide API Documentation From 8e8bab03d5eb787b4efd564a5ebdbe1a7eeaec6d Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Tue, 30 Jan 2018 21:38:54 +0100 Subject: [PATCH 09/70] Add zeroconf-port option --- src/discovery.rs | 5 +++-- src/main.rs | 18 ++++++++++++++++-- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/src/discovery.rs b/src/discovery.rs index fc168d5c..e39c1738 100644 --- a/src/discovery.rs +++ b/src/discovery.rs @@ -194,14 +194,15 @@ pub struct DiscoveryStream { _svc: mdns::Service, } -pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String) +pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String, port: u16) -> io::Result { let (discovery, creds_rx) = Discovery::new(config.clone(), device_id); let serve = { let http = Http::new(); - http.serve_addr_handle(&"0.0.0.0:0".parse().unwrap(), &handle, move || Ok(discovery.clone())).unwrap() + debug!("Zeroconf server listening on 0.0.0.0:{}", port); + http.serve_addr_handle(&format!("0.0.0.0:{}", port).parse().unwrap(), &handle, move || Ok(discovery.clone())).unwrap() }; let addr = serve.incoming_ref().local_addr(); let server_future = { diff --git a/src/main.rs b/src/main.rs index 85131ee9..fd3f1c2c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -81,6 +81,7 @@ struct Setup { connect_config: ConnectConfig, credentials: Option, enable_discovery: bool, + zeroconf_port: u16, } fn setup(args: &[String]) -> Setup { @@ -99,7 +100,8 @@ fn setup(args: &[String]) -> Setup { .optopt("", "backend", "Audio backend to use. Use '?' to list options", "BACKEND") .optopt("", "device", "Audio device to use. Use '?' to list options", "DEVICE") .optopt("", "mixer", "Mixer to use", "MIXER") - .optopt("", "initial-volume", "Initial volume in %, once connected (must be from 0 to 100)", "VOLUME"); + .optopt("", "initial-volume", "Initial volume in %, once connected (must be from 0 to 100)", "VOLUME") + .optopt("z", "zeroconf-port", "The port the internal server advertised over zeroconf uses.", "ZEROCONF_PORT"); let matches = match opts.parse(&args[1..]) { Ok(m) => m, @@ -160,6 +162,17 @@ fn setup(args: &[String]) -> Setup { } debug!("Volume \"{}\" !", initial_volume); + let zeroconf_port: u16; + if matches.opt_present("zeroconf-port") && matches.opt_str("zeroconf-port").unwrap().parse::().is_ok() { + let z = matches.opt_str("zeroconf-port").unwrap().parse::().unwrap(); + match z { + z if z >= 1024 => { zeroconf_port = z } + _ => { zeroconf_port = 0 } + } + } else { + zeroconf_port = 0 + } + let name = matches.opt_str("name").unwrap(); let use_audio_cache = !matches.opt_present("disable-audio-cache"); @@ -221,6 +234,7 @@ fn setup(args: &[String]) -> Setup { credentials: credentials, device: device, enable_discovery: enable_discovery, + zeroconf_port: zeroconf_port, mixer: mixer, } } @@ -269,7 +283,7 @@ impl Main { let config = task.connect_config.clone(); let device_id = task.session_config.device_id.clone(); - task.discovery = Some(discovery(&handle, config, device_id).unwrap()); + task.discovery = Some(discovery(&handle, config, device_id, setup.zeroconf_port).unwrap()); } if let Some(credentials) = setup.credentials { From 863ea9c976235f28c086fb50baf99b3f08099f13 Mon Sep 17 00:00:00 2001 From: ComlOnline Date: Tue, 30 Jan 2018 20:52:25 +0000 Subject: [PATCH 10/70] removed and optimised --- src/main.rs | 32 +++++++++----------------------- 1 file changed, 9 insertions(+), 23 deletions(-) diff --git a/src/main.rs b/src/main.rs index 85131ee9..cccfb268 100644 --- a/src/main.rs +++ b/src/main.rs @@ -132,33 +132,19 @@ fn setup(args: &[String]) -> Setup { let mixer_name = matches.opt_str("mixer"); let mixer = mixer::find(mixer_name.as_ref()) .expect("Invalid mixer"); + let initial_volume; - // check if initial-volume argument is present - if matches.opt_present("initial-volume"){ - // check if value is a number - if matches.opt_str("initial-volume").unwrap().parse::().is_ok(){ - // check if value is in [0-100] range, otherwise put the bound values - if matches.opt_str("initial-volume").unwrap().parse::().unwrap() < 0 { - initial_volume = 0 as i32; + if matches.opt_present("initial-volume") && matches.opt_str("initial-volume").unwrap().parse::().is_ok() { + let iv = matches.opt_str("zeroconf-port").unwrap().parse::().unwrap(); + if iv => 0 && iv <= 100 { + initial_volume = iv * 0xFFFF as i32 / 100 ; + } else { + debug!("Volume needs to be a value from 0-100; set as 50%"); + initial_volume = 0x8000 as i32; } - else if matches.opt_str("initial-volume").unwrap().parse::().unwrap() > 100{ - initial_volume = 0xFFFF as i32; - } - // checks ok - else{ - initial_volume = matches.opt_str("initial-volume").unwrap().parse::().unwrap()* 0xFFFF as i32 / 100 ; - } - } - // if value is not a number use default value (50%) - else { + } else { initial_volume = 0x8000 as i32; } - } - // if argument not present use default values (50%) - else{ - initial_volume = 0x8000 as i32; - } - debug!("Volume \"{}\" !", initial_volume); let name = matches.opt_str("name").unwrap(); let use_audio_cache = !matches.opt_present("disable-audio-cache"); From 46de5a704b08d42a8d57b62ef103f0529c0195af Mon Sep 17 00:00:00 2001 From: ComlOnline Date: Tue, 30 Jan 2018 21:30:37 +0000 Subject: [PATCH 11/70] Thats what I get for copypasta --- src/main.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index cccfb268..45c5ec87 100644 --- a/src/main.rs +++ b/src/main.rs @@ -135,8 +135,8 @@ fn setup(args: &[String]) -> Setup { let initial_volume; if matches.opt_present("initial-volume") && matches.opt_str("initial-volume").unwrap().parse::().is_ok() { - let iv = matches.opt_str("zeroconf-port").unwrap().parse::().unwrap(); - if iv => 0 && iv <= 100 { + let matches.opt_str("initial-volume").unwrap().parse::().unwrap(); + if 0 <= iv && iv <= 100 { initial_volume = iv * 0xFFFF as i32 / 100 ; } else { debug!("Volume needs to be a value from 0-100; set as 50%"); From 618eceb740113d25d58977f941e4a8ef2ce81481 Mon Sep 17 00:00:00 2001 From: ComlOnline Date: Tue, 30 Jan 2018 21:46:57 +0000 Subject: [PATCH 12/70] lost `iv -` due to previous --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 45c5ec87..499bb613 100644 --- a/src/main.rs +++ b/src/main.rs @@ -135,7 +135,7 @@ fn setup(args: &[String]) -> Setup { let initial_volume; if matches.opt_present("initial-volume") && matches.opt_str("initial-volume").unwrap().parse::().is_ok() { - let matches.opt_str("initial-volume").unwrap().parse::().unwrap(); + let iv = matches.opt_str("initial-volume").unwrap().parse::().unwrap(); if 0 <= iv && iv <= 100 { initial_volume = iv * 0xFFFF as i32 / 100 ; } else { From fddcbbcd8261563009436e9444275913317c0711 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 31 Jan 2018 00:05:54 +0100 Subject: [PATCH 13/70] Tidied up Syntax --- src/main.rs | 23 ++++++++++++----------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/main.rs b/src/main.rs index 499bb613..1ca16165 100644 --- a/src/main.rs +++ b/src/main.rs @@ -132,19 +132,20 @@ fn setup(args: &[String]) -> Setup { let mixer_name = matches.opt_str("mixer"); let mixer = mixer::find(mixer_name.as_ref()) .expect("Invalid mixer"); - - let initial_volume; - if matches.opt_present("initial-volume") && matches.opt_str("initial-volume").unwrap().parse::().is_ok() { - let iv = matches.opt_str("initial-volume").unwrap().parse::().unwrap(); - if 0 <= iv && iv <= 100 { - initial_volume = iv * 0xFFFF as i32 / 100 ; - } else { - debug!("Volume needs to be a value from 0-100; set as 50%"); - initial_volume = 0x8000 as i32; + + let initial_volume: i32; + if matches.opt_present("initial-volume") && matches.opt_str("initial-volume").unwrap().parse::().is_ok() { + let iv = matches.opt_str("initial-volume").unwrap().parse::().unwrap(); + match iv { + iv if iv >= 0 && iv <= 100 => { initial_volume = iv * 0xFFFF / 100 } + _ => { + debug!("Volume needs to be a value from 0-100; set volume level to 50%"); + initial_volume = 0x8000; } - } else { - initial_volume = 0x8000 as i32; } + } else { + initial_volume = 0x8000; + } let name = matches.opt_str("name").unwrap(); let use_audio_cache = !matches.opt_present("disable-audio-cache"); From d923f3bad377fc17add533e8de294fdf8bfcee3d Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 31 Jan 2018 12:00:53 +0100 Subject: [PATCH 14/70] Add with-dns-sd feature flag --- Cargo.lock | 11 +++++++++++ Cargo.toml | 7 +++++-- src/discovery.rs | 30 +++++++++++++++++++++++++++++- src/lib.rs | 7 ++++++- 4 files changed, 51 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1bee8116..d01def63 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -106,6 +106,15 @@ dependencies = [ "quick-error 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "dns-sd" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "pkg-config 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "dtoa" version = "0.4.2" @@ -272,6 +281,7 @@ version = "0.1.0" dependencies = [ "alsa 0.0.1 (git+https://github.com/plietar/rust-alsa)", "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dns-sd 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1108,6 +1118,7 @@ dependencies = [ "checksum bytes 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "1b7db437d718977f6dc9b2e3fd6fc343c02ac6b899b73fdd2179163447bd9ce9" "checksum cfg-if 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4c819a1287eb618df47cc647173c5c4c66ba19d888a6e50d605672aed3140de" "checksum dns-parser 0.3.2 (git+https://github.com/plietar/dns-parser)" = "" +"checksum dns-sd 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "d748509dea20228f63ba519bf142ce2593396386125b01f5b0d6412dab972087" "checksum dtoa 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "09c3753c3db574d215cba4ea76018483895d7bff25a31b49ba45db21c48e50ab" "checksum env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3ddf21e73e016298f5cb37d6ef8e8da8e39f91f9ec8b0df44b7deb16a9f8cd5b" "checksum error-chain 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e92ecf0a508c8e074c0e6fa8fe0fa38414848ad4dfc4db6f74c5e9753330b248" diff --git a/Cargo.toml b/Cargo.toml index 277e149f..dfe27524 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -54,6 +54,7 @@ alsa = { git = "https://github.com/plietar/rust-alsa", optional = tru portaudio-rs = { version = "0.3.0", optional = true } libpulse-sys = { version = "0.0.0", optional = true } libc = { version = "0.2", optional = true } +dns-sd = { version = "0.1.3", optional = true } [build-dependencies] rand = "0.3.13" @@ -68,11 +69,13 @@ pulseaudio-backend = ["libpulse-sys", "libc"] with-tremor = ["librespot-audio/with-tremor"] with-lewton = ["librespot-audio/with-lewton"] +with-dns-sd = ["dns-sd"] + default = ["portaudio-backend"] [package.metadata.deb] -maintainer = "nobody" -copyright = "2016 Paul Liétar" +maintainer = "librespot-org" +copyright = "2018 Paul Liétar" license_file = ["LICENSE", "4"] depends = "$auto" extended_description = """\ diff --git a/src/discovery.rs b/src/discovery.rs index fc168d5c..1f4617b4 100644 --- a/src/discovery.rs +++ b/src/discovery.rs @@ -6,7 +6,13 @@ use futures::sync::mpsc; use futures::{Future, Stream, Poll}; use hyper::server::{Service, Request, Response, Http}; use hyper::{self, Get, Post, StatusCode}; + +#[cfg(feature = "with-dns-sd")] +use dns_sd::DNSService; + +#[cfg(not(feature = "with-dns-sd"))] use mdns; + use num_bigint::BigUint; use rand; use std::collections::BTreeMap; @@ -189,6 +195,13 @@ impl Service for Discovery { } } +#[cfg(feature = "with-dns-sd")] +pub struct DiscoveryStream { + credentials: mpsc::UnboundedReceiver, + _svc: DNSService, +} + +#[cfg(not(feature = "with-dns-sd"))] pub struct DiscoveryStream { credentials: mpsc::UnboundedReceiver, _svc: mdns::Service, @@ -203,7 +216,10 @@ pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String) let http = Http::new(); http.serve_addr_handle(&"0.0.0.0:0".parse().unwrap(), &handle, move || Ok(discovery.clone())).unwrap() }; - let addr = serve.incoming_ref().local_addr(); + + #[cfg(feature = "with-dns-sd")] + let port = serve.incoming_ref().local_addr().port(); + let server_future = { let handle = handle.clone(); serve.for_each(move |connection| { @@ -214,7 +230,19 @@ pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String) }; handle.spawn(server_future); + #[cfg(feature = "with-dns-sd")] + let svc = DNSService::register(Some(&*config.name), + "_spotify-connect._tcp", + None, + None, + port, + &["VERSION=1.0", "CPath=/"]).unwrap(); + + #[cfg(not(feature = "with-dns-sd"))] + let addr = serve.incoming_ref().local_addr(); + #[cfg(not(feature = "with-dns-sd"))] let responder = mdns::Responder::spawn(&handle)?; + #[cfg(not(feature = "with-dns-sd"))] let svc = responder.register( "_spotify-connect._tcp".to_owned(), config.name, diff --git a/src/lib.rs b/src/lib.rs index 53257a8a..a08f2f5c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -10,7 +10,6 @@ extern crate base64; extern crate crypto; extern crate futures; extern crate hyper; -extern crate mdns; extern crate num_bigint; extern crate protobuf; extern crate rand; @@ -34,6 +33,12 @@ extern crate libpulse_sys; #[cfg(feature = "libc")] extern crate libc; +#[cfg(feature = "with-dns-sd")] +extern crate dns_sd; + +#[cfg(not(feature = "with-dns-sd"))] +extern crate mdns; + pub mod audio_backend; pub mod discovery; pub mod keymaster; From 7a58e6d561d91aa5d41d2da3ab641074aea68147 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 31 Jan 2018 12:08:23 +0100 Subject: [PATCH 15/70] fix addr in wrong place --- src/discovery.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/discovery.rs b/src/discovery.rs index 1f4617b4..0a621339 100644 --- a/src/discovery.rs +++ b/src/discovery.rs @@ -220,6 +220,9 @@ pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String) #[cfg(feature = "with-dns-sd")] let port = serve.incoming_ref().local_addr().port(); + #[cfg(not(feature = "with-dns-sd"))] + let addr = serve.incoming_ref().local_addr(); + let server_future = { let handle = handle.clone(); serve.for_each(move |connection| { @@ -238,10 +241,9 @@ pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String) port, &["VERSION=1.0", "CPath=/"]).unwrap(); - #[cfg(not(feature = "with-dns-sd"))] - let addr = serve.incoming_ref().local_addr(); #[cfg(not(feature = "with-dns-sd"))] let responder = mdns::Responder::spawn(&handle)?; + #[cfg(not(feature = "with-dns-sd"))] let svc = responder.register( "_spotify-connect._tcp".to_owned(), From f35f52cbf94548e11b0ad059d3cb754af18c5ec8 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Fri, 2 Feb 2018 05:03:59 +0100 Subject: [PATCH 16/70] Remove redundant code --- src/audio_backend/jackaudio.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/audio_backend/jackaudio.rs b/src/audio_backend/jackaudio.rs index e1a67aec..9b389ea6 100644 --- a/src/audio_backend/jackaudio.rs +++ b/src/audio_backend/jackaudio.rs @@ -3,7 +3,6 @@ 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>, @@ -16,10 +15,7 @@ pub struct JackData { } 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 + sample as f32 / 32768.0; } impl ProcessHandler for JackData { From b22f252abd7ff0782cea62eaf91c81f4e38e0a3e Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Fri, 2 Feb 2018 05:14:00 +0100 Subject: [PATCH 17/70] Add missing " --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 1796bc43..6e3a798d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -65,7 +65,7 @@ protobuf_macros = { git = "https://github.com/plietar/rust-protobuf-macros", fea [features] alsa-backend = ["alsa"] portaudio-backend = ["portaudio-rs"] -pulseaudio-backend = ["libpulse-sys, "libc"] +pulseaudio-backend = ["libpulse-sys", "libc"] jackaudio-backend = ["jack"] with-tremor = ["librespot-audio/with-tremor"] From 2ae1f1399f57922b5a179588603ee51ddf4b2544 Mon Sep 17 00:00:00 2001 From: awiouy Date: Fri, 2 Feb 2018 19:37:15 +0100 Subject: [PATCH 18/70] simplify dns-sd/mdns code --- src/discovery.rs | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/discovery.rs b/src/discovery.rs index 99f56763..e29a798a 100644 --- a/src/discovery.rs +++ b/src/discovery.rs @@ -218,11 +218,7 @@ pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String, port http.serve_addr_handle(&format!("0.0.0.0:{}", port).parse().unwrap(), &handle, move || Ok(discovery.clone())).unwrap() }; - #[cfg(feature = "with-dns-sd")] - let port = serve.incoming_ref().local_addr().port(); - - #[cfg(not(feature = "with-dns-sd"))] - let addr = serve.incoming_ref().local_addr(); + let s_port = serve.incoming_ref().local_addr().port(); let server_future = { let handle = handle.clone(); @@ -239,7 +235,7 @@ pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String, port "_spotify-connect._tcp", None, None, - port, + s_port, &["VERSION=1.0", "CPath=/"]).unwrap(); #[cfg(not(feature = "with-dns-sd"))] @@ -249,7 +245,7 @@ pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String, port let svc = responder.register( "_spotify-connect._tcp".to_owned(), config.name, - addr.port(), + s_port, &["VERSION=1.0", "CPath=/"]); Ok(DiscoveryStream { From b03430a0575653b6d84d7abe8bc3bd34c7cc76e5 Mon Sep 17 00:00:00 2001 From: Robert Date: Mon, 5 Feb 2018 00:33:17 +0100 Subject: [PATCH 19/70] minor code cleanup --- src/audio_backend/alsa.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/audio_backend/alsa.rs b/src/audio_backend/alsa.rs index 42f590bf..517c8f0a 100644 --- a/src/audio_backend/alsa.rs +++ b/src/audio_backend/alsa.rs @@ -16,15 +16,13 @@ impl Open for AlsaSink { impl Sink for AlsaSink { fn start(&mut self) -> io::Result<()> { - if self.0.is_some() { - } else { + if self.0.is_none() { match PCM::open(&*self.1, Stream::Playback, Mode::Blocking, Format::Signed16, Access::Interleaved, 2, 44100) { Ok(f) => self.0 = Some(f), Err(e) => { - self.0 = None; error!("Alsa error PCM open {}", e); return Err(io::Error::new(io::ErrorKind::Other, "Alsa error: PCM open failed")); } From 41647174527f553460f3aa4dbd357dbb7b7a37c2 Mon Sep 17 00:00:00 2001 From: ashthespy Date: Tue, 6 Feb 2018 03:20:21 +0100 Subject: [PATCH 20/70] Add track duration to `Track` metadata --- metadata/src/lib.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index f76cd224..2439ded6 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -75,6 +75,7 @@ pub trait Metadata : Send + Sized + 'static { pub struct Track { pub id: SpotifyId, pub name: String, + pub duration: i32, pub album: SpotifyId, pub artists: Vec, pub files: LinearMap, @@ -127,6 +128,7 @@ impl Metadata for Track { Track { id: SpotifyId::from_raw(msg.get_gid()), name: msg.get_name().to_owned(), + duration: msg.get_duration(), album: SpotifyId::from_raw(msg.get_album().get_gid()), artists: artists, files: files, @@ -215,4 +217,3 @@ impl Metadata for Artist { } } } - From 6a442a457088030e074dfa6c355b9ee5ffbf89ed Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Tue, 6 Feb 2018 19:54:28 +0100 Subject: [PATCH 21/70] Move keymaster to core --- Cargo.lock | 36 +++++++++++++++++++++++++++++++++- Cargo.toml | 1 - {src => core/src}/keymaster.rs | 4 ++-- core/src/lib.rs | 1 + src/lib.rs | 2 -- 5 files changed, 38 insertions(+), 6 deletions(-) rename {src => core/src}/keymaster.rs (92%) diff --git a/Cargo.lock b/Cargo.lock index d01def63..1defbc62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -224,6 +224,27 @@ name = "itoa" version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "jack" +version = "0.5.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", + "jack-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "jack-sys" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "kernel32-sys" version = "0.2.2" @@ -267,6 +288,16 @@ name = "libc" version = "0.2.36" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "libloading" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "libpulse-sys" version = "0.0.0" @@ -286,6 +317,7 @@ dependencies = [ "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.14 (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.36 (registry+https://github.com/rust-lang/crates.io-index)", "libpulse-sys 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "librespot-audio 0.1.0", @@ -302,7 +334,6 @@ dependencies = [ "rpassword 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1133,6 +1164,8 @@ dependencies = [ "checksum idna 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "014b298351066f1512874135335d62a789ffe78a9974f94b43ed5621951eaf7d" "checksum iovec 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "b6e8b9c2247fcf6c6a1151f1156932be5606c9fd6f55a2d7f9fc1cb29386b2f7" "checksum itoa 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8324a32baf01e2ae060e9de58ed0bc2320c9a2833491ee36cd3b4c414de4db8c" +"checksum jack 0.5.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1e15fc592e2e5a74a105ff507083c04db1aa20ba1b90d425362ba000e57422df" +"checksum jack-sys 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c0d4ca501477fd3cd93a36df581046e5d6338ed826cf7e9b8d302603521e6cc3" "checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d" "checksum language-tags 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a91d884b6667cd606bb5a69aa0c99ba811a115fc68915e7056ec08a46e93199a" "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" @@ -1140,6 +1173,7 @@ dependencies = [ "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" "checksum lewton 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0de1cca3399919efa65ae7e01ed6696c961bd0fc9e844c05c80f90b638300bbf" "checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121" +"checksum libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9" "checksum libpulse-sys 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9bb11b06faf883500c1b625cf4453e6c7737e9df9c7ba01df3f84b22b083e4ac" "checksum linear-map 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bfae20f6b19ad527b550c223fddc3077a547fc70cda94b9b566575423fd303ee" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" diff --git a/Cargo.toml b/Cargo.toml index 6e3a798d..f0734494 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,6 @@ rand = "0.3.13" rpassword = "0.3.0" rust-crypto = { git = "https://github.com/awmath/rust-crypto.git", branch = "avx2" } serde = "0.9.6" -serde_derive = "0.9.6" serde_json = "0.9.5" tokio-core = "0.1.2" tokio-io = "0.1" diff --git a/src/keymaster.rs b/core/src/keymaster.rs similarity index 92% rename from src/keymaster.rs rename to core/src/keymaster.rs index e803a959..a4e0c169 100644 --- a/src/keymaster.rs +++ b/core/src/keymaster.rs @@ -1,8 +1,8 @@ use futures::Future; use serde_json; -use core::mercury::MercuryError; -use core::session::Session; +use mercury::MercuryError; +use session::Session; #[derive(Deserialize, Debug, Clone)] #[serde(rename_all = "camelCase")] diff --git a/core/src/lib.rs b/core/src/lib.rs index 17515a49..2f00ad39 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -34,6 +34,7 @@ pub mod cache; pub mod channel; pub mod config; pub mod diffie_hellman; +pub mod keymaster; pub mod mercury; pub mod session; pub mod util; diff --git a/src/lib.rs b/src/lib.rs index 09398162..80dad1bc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,7 +4,6 @@ #[macro_use] extern crate log; #[macro_use] extern crate serde_json; -#[macro_use] extern crate serde_derive; extern crate base64; extern crate crypto; @@ -44,7 +43,6 @@ extern crate mdns; pub mod audio_backend; pub mod discovery; -pub mod keymaster; pub mod mixer; pub mod player; From ccbaff267eee66cab7d878c998100c38a092969b Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Tue, 6 Feb 2018 20:26:37 +0100 Subject: [PATCH 22/70] Re-add serde_derive --- Cargo.lock | 1 + Cargo.toml | 1 + 2 files changed, 2 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 1defbc62..d3b3a568 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -334,6 +334,7 @@ dependencies = [ "rpassword 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", "tokio-io 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index f0734494..6e3a798d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ rand = "0.3.13" rpassword = "0.3.0" rust-crypto = { git = "https://github.com/awmath/rust-crypto.git", branch = "avx2" } serde = "0.9.6" +serde_derive = "0.9.6" serde_json = "0.9.5" tokio-core = "0.1.2" tokio-io = "0.1" From cfa7a62dfcadd426e754dc845f01ed9af881742f Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Wed, 7 Feb 2018 15:07:01 +0100 Subject: [PATCH 23/70] Re-add serde_derive to lib.rs --- src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lib.rs b/src/lib.rs index 80dad1bc..753827c6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -4,6 +4,7 @@ #[macro_use] extern crate log; #[macro_use] extern crate serde_json; +#[macro_use] extern crate serde_derive; extern crate base64; extern crate crypto; From 99e7da562d454b1eac548c44be63030560115242 Mon Sep 17 00:00:00 2001 From: awiouy Date: Tue, 6 Feb 2018 17:39:52 +0100 Subject: [PATCH 24/70] lewton: handle OggError(NoCapturePatternFound) --- Cargo.lock | 6 +++--- audio/Cargo.toml | 2 +- audio/src/lewton_decoder.rs | 3 +++ 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d3b3a568..f73a91ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -276,7 +276,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "lewton" -version = "0.6.2" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -350,7 +350,7 @@ dependencies = [ "bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "byteorder 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", - "lewton 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lewton 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "librespot-core 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1172,7 +1172,7 @@ dependencies = [ "checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73" "checksum lazy_static 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c8f31047daa365f19be14b47c29df4f7c3b581832407daabe6ae77397619237d" "checksum lazycell 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a6f08839bc70ef4a3fe1d566d5350f519c5912ea86be0df1740a7d247c7fc0ef" -"checksum lewton 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)" = "0de1cca3399919efa65ae7e01ed6696c961bd0fc9e844c05c80f90b638300bbf" +"checksum lewton 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3d170da25c0b3541e3260f84aa8f9d323468083bd1ed6c4c15aec7ff33e2a1c4" "checksum libc 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "1e5d97d6708edaa407429faa671b942dc0f2727222fb6b6539bf1db936e4b121" "checksum libloading 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fd38073de8f7965d0c17d30546d4bb6da311ab428d1c7a3fc71dff7f9d4979b9" "checksum libpulse-sys 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9bb11b06faf883500c1b625cf4453e6c7737e9df9c7ba01df3f84b22b083e4ac" diff --git a/audio/Cargo.toml b/audio/Cargo.toml index b9e4af81..66b5432e 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -18,7 +18,7 @@ tempfile = "2.1" vorbis = "0.1.0" tremor = { git = "https://github.com/plietar/rust-tremor", optional = true } -lewton = { version = "0.6.2", optional = true } +lewton = { version = "0.8.0", optional = true } [features] with-tremor = ["tremor"] diff --git a/audio/src/lewton_decoder.rs b/audio/src/lewton_decoder.rs index cff734f9..5bedda9d 100644 --- a/audio/src/lewton_decoder.rs +++ b/audio/src/lewton_decoder.rs @@ -24,7 +24,9 @@ impl VorbisDecoder } pub fn next_packet(&mut self) -> Result, VorbisError> { + use self::lewton::OggReadError::NoCapturePatternFound; use self::lewton::VorbisError::BadAudio; + use self::lewton::VorbisError::OggError; use self::lewton::audio::AudioReadError::AudioIsHeader; loop { match self.0.read_dec_packet_itl() { @@ -32,6 +34,7 @@ impl VorbisDecoder Ok(None) => return Ok(None), Err(BadAudio(AudioIsHeader)) => (), + Err(OggError(NoCapturePatternFound)) => (), Err(err) => return Err(err.into()), } } From 97bc429e081504498b9129e023c0db8a926a89f6 Mon Sep 17 00:00:00 2001 From: awiouy Date: Wed, 7 Feb 2018 18:57:19 +0100 Subject: [PATCH 25/70] Update Rust requirement to 1.20.0 --- .travis.yml | 2 +- README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 402b32ae..72722c43 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,6 @@ language: rust rust: - - 1.18.0 + - 1.20.0 - stable - beta - nightly diff --git a/README.md b/README.md index a56ed869..f9f3c106 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ As the origin by [plietar](https://github.com/plietar/) is no longer actively ma More information can be found in the [wiki](https://github.com/librespot-org/librespot/wiki) # Building -Rust 1.18.0 or later is required to build librespot. +Rust 1.20.0 or later is required to build librespot. **If you are building librespot on macOS, the homebrew provided rust may fail due to the way in which homebrew installs rust. In this case, uninstall the homebrew version of rust and use [rustup](https://www.rustup.rs/), and librespot should then build. This should have been fixed in more recent versions of Homebrew, but we're leaving this notice here as a warning.** From f400a894bc4fc1b45d0266df44e964990f34c99e Mon Sep 17 00:00:00 2001 From: awiouy Date: Tue, 6 Feb 2018 22:50:00 +0100 Subject: [PATCH 26/70] lewton_decoder becomes default, libvorbis_decoder optional --- .travis.yml | 2 +- Cargo.toml | 2 +- audio/Cargo.toml | 6 +++--- audio/src/lib.rs | 12 ++++++------ 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 72722c43..34bf2dfb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -24,7 +24,7 @@ before_script: script: - cargo build --no-default-features - cargo build --no-default-features --features "with-tremor" - - cargo build --no-default-features --features "with-lewton"; + - cargo build --no-default-features --features "with-vorbis" - cargo build --no-default-features --features "portaudio-backend" - cargo build --no-default-features --features "pulseaudio-backend" - cargo build --no-default-features --features "alsa-backend" diff --git a/Cargo.toml b/Cargo.toml index 6e3a798d..4ac75eb4 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -69,7 +69,7 @@ pulseaudio-backend = ["libpulse-sys", "libc"] jackaudio-backend = ["jack"] with-tremor = ["librespot-audio/with-tremor"] -with-lewton = ["librespot-audio/with-lewton"] +with-vorbis = ["librespot-audio/with-vorbis"] with-dns-sd = ["dns-sd"] diff --git a/audio/Cargo.toml b/audio/Cargo.toml index 66b5432e..48605669 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -10,16 +10,16 @@ path = "../core" bit-set = "0.4.0" byteorder = "1.0" futures = "0.1.8" +lewton = "0.8.0" log = "0.3.5" num-bigint = "0.1.35" num-traits = "0.1.36" rust-crypto = { git = "https://github.com/awmath/rust-crypto.git", branch = "avx2" } tempfile = "2.1" -vorbis = "0.1.0" tremor = { git = "https://github.com/plietar/rust-tremor", optional = true } -lewton = { version = "0.8.0", optional = true } +vorbis = { version ="0.1.0", optional = true } [features] with-tremor = ["tremor"] -with-lewton = ["lewton"] +with-vorbis = ["vorbis"] diff --git a/audio/src/lib.rs b/audio/src/lib.rs index d0afba62..37b62774 100644 --- a/audio/src/lib.rs +++ b/audio/src/lib.rs @@ -13,15 +13,15 @@ extern crate librespot_core as core; mod fetch; mod decrypt; -#[cfg(not(feature = "with-lewton"))] -mod libvorbis_decoder; -#[cfg(feature = "with-lewton")] +#[cfg(not(any(feature = "with-tremor", feature = "with-vorbis")))] mod lewton_decoder; +#[cfg(any(feature = "with-tremor", feature = "with-vorbis"))] +mod libvorbis_decoder; pub use fetch::{AudioFile, AudioFileOpen}; pub use decrypt::AudioDecrypt; -#[cfg(not(feature = "with-lewton"))] -pub use libvorbis_decoder::{VorbisDecoder, VorbisPacket, VorbisError}; -#[cfg(feature = "with-lewton")] +#[cfg(not(any(feature = "with-tremor", feature = "with-vorbis")))] pub use lewton_decoder::{VorbisDecoder, VorbisPacket, VorbisError}; +#[cfg(any(feature = "with-tremor", feature = "with-vorbis"))] +pub use libvorbis_decoder::{VorbisDecoder, VorbisPacket, VorbisError}; From e3516ebd9baaeb48740e4c6f50aca1bae7e07463 Mon Sep 17 00:00:00 2001 From: awiouy Date: Tue, 6 Feb 2018 01:00:00 +0100 Subject: [PATCH 27/70] Move discovery to its own module. --- Cargo.toml | 6 +++--- discovery/Cargo.toml | 29 +++++++++++++++++++++++++++++ {src => discovery/src}/discovery.rs | 0 discovery/src/lib.rs | 22 ++++++++++++++++++++++ src/lib.rs | 10 +--------- src/main.rs | 2 +- 6 files changed, 56 insertions(+), 13 deletions(-) create mode 100644 discovery/Cargo.toml rename {src => discovery/src}/discovery.rs (100%) create mode 100644 discovery/src/lib.rs diff --git a/Cargo.toml b/Cargo.toml index 6e3a798d..4623702e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -24,6 +24,8 @@ doc = false path = "audio" [dependencies.librespot-core] path = "core" +[dependencies.librespot-discovery] +path = "discovery" [dependencies.librespot-metadata] path = "metadata" [dependencies.librespot-protocol] @@ -36,7 +38,6 @@ futures = "0.1.8" getopts = "0.2.14" hyper = "0.11.2" log = "0.3.5" -mdns = { git = "https://github.com/plietar/rust-mdns" } num-bigint = "0.1.35" protobuf = "1.1" rand = "0.3.13" @@ -55,7 +56,6 @@ 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 } -dns-sd = { version = "0.1.3", optional = true } [build-dependencies] rand = "0.3.13" @@ -71,7 +71,7 @@ jackaudio-backend = ["jack"] with-tremor = ["librespot-audio/with-tremor"] with-lewton = ["librespot-audio/with-lewton"] -with-dns-sd = ["dns-sd"] +with-dns-sd = ["librespot-discovery/dns-sd"] default = ["portaudio-backend"] diff --git a/discovery/Cargo.toml b/discovery/Cargo.toml new file mode 100644 index 00000000..f69185a0 --- /dev/null +++ b/discovery/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "librespot-discovery" +version = "0.1.0" +authors = ["Paul Lietar "] + +[dependencies.librespot-core] +path = "../core" + +[dependencies] +base64 = "0.5.0" +futures = "0.1.8" +hyper = "0.11.2" +log = "0.3.5" +num-bigint = "0.1.35" +protobuf = "1.1" +rand = "0.3.13" +rust-crypto = { git = "https://github.com/awmath/rust-crypto.git", branch = "avx2" } +serde = "0.9.6" +serde_derive = "0.9.6" +serde_json = "0.9.5" +tokio-core = "0.1.2" +url = "1.3" + +dns-sd = { version = "0.1.3", optional = true } +mdns = { git = "https://github.com/plietar/rust-mdns", optional = true } + +[features] +default = ["mdns"] +with-dns-sd = ["dns-sd"] diff --git a/src/discovery.rs b/discovery/src/discovery.rs similarity index 100% rename from src/discovery.rs rename to discovery/src/discovery.rs diff --git a/discovery/src/lib.rs b/discovery/src/lib.rs new file mode 100644 index 00000000..d8775b8a --- /dev/null +++ b/discovery/src/lib.rs @@ -0,0 +1,22 @@ +#[macro_use] extern crate log; +#[macro_use] extern crate serde_json; + +extern crate base64; +extern crate crypto; +extern crate futures; +extern crate hyper; +extern crate num_bigint; +extern crate protobuf; +extern crate rand; +extern crate tokio_core; +extern crate url; + +#[cfg(feature = "with-dns-sd")] +extern crate dns_sd; + +#[cfg(not(feature = "with-dns-sd"))] +extern crate mdns; + +extern crate librespot_core as core; + +pub mod discovery; diff --git a/src/lib.rs b/src/lib.rs index 753827c6..2d9aad1b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,8 +3,6 @@ #![cfg_attr(feature = "cargo-clippy", allow(unused_io_amount))] #[macro_use] extern crate log; -#[macro_use] extern crate serde_json; -#[macro_use] extern crate serde_derive; extern crate base64; extern crate crypto; @@ -18,6 +16,7 @@ extern crate url; pub extern crate librespot_audio as audio; pub extern crate librespot_core as core; +pub extern crate librespot_discovery as discovery; pub extern crate librespot_protocol as protocol; pub extern crate librespot_metadata as metadata; @@ -36,14 +35,7 @@ extern crate jack; #[cfg(feature = "libc")] extern crate libc; -#[cfg(feature = "with-dns-sd")] -extern crate dns_sd; - -#[cfg(not(feature = "with-dns-sd"))] -extern crate mdns; - pub mod audio_backend; -pub mod discovery; pub mod mixer; pub mod player; diff --git a/src/main.rs b/src/main.rs index cbf495dc..4200fc16 100644 --- a/src/main.rs +++ b/src/main.rs @@ -25,7 +25,7 @@ use librespot::core::session::Session; use librespot::core::version; use librespot::audio_backend::{self, Sink, BACKENDS}; -use librespot::discovery::{discovery, DiscoveryStream}; +use librespot::discovery::discovery::{discovery, DiscoveryStream}; use librespot::mixer::{self, Mixer}; use librespot::player::Player; use librespot::spirc::{Spirc, SpircTask}; From 1fb65354b006cda3d1bfc71f16e4f41c0d832758 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Fri, 9 Feb 2018 02:05:50 +0100 Subject: [PATCH 28/70] Move audio backends into seperate crate --- Cargo.lock | 47 ++++++++++++++++--- Cargo.toml | 20 ++++---- playback/Cargo.toml | 29 ++++++++++++ {src => playback/src}/audio_backend/alsa.rs | 0 .../src}/audio_backend/jackaudio.rs | 0 {src => playback/src}/audio_backend/mod.rs | 0 {src => playback/src}/audio_backend/pipe.rs | 0 .../src}/audio_backend/portaudio.rs | 0 .../src}/audio_backend/pulseaudio.rs | 0 playback/src/lib.rs | 26 ++++++++++ {src => playback/src}/mixer/mod.rs | 0 {src => playback/src}/mixer/softmixer.rs | 0 {src => playback/src}/player.rs | 0 src/lib.rs | 19 +------- src/main.rs | 6 +-- src/spirc.rs | 10 ++-- 16 files changed, 112 insertions(+), 45 deletions(-) create mode 100644 playback/Cargo.toml rename {src => playback/src}/audio_backend/alsa.rs (100%) rename {src => playback/src}/audio_backend/jackaudio.rs (100%) rename {src => playback/src}/audio_backend/mod.rs (100%) rename {src => playback/src}/audio_backend/pipe.rs (100%) rename {src => playback/src}/audio_backend/portaudio.rs (100%) rename {src => playback/src}/audio_backend/pulseaudio.rs (100%) create mode 100644 playback/src/lib.rs rename {src => playback/src}/mixer/mod.rs (100%) rename {src => playback/src}/mixer/softmixer.rs (100%) rename {src => playback/src}/player.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index f73a91ad..0f21634d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -310,24 +310,19 @@ dependencies = [ name = "librespot" version = "0.1.0" dependencies = [ - "alsa 0.0.1 (git+https://github.com/plietar/rust-alsa)", "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", - "dns-sd 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "env_logger 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.14 (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.36 (registry+https://github.com/rust-lang/crates.io-index)", - "libpulse-sys 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", "librespot-audio 0.1.0", "librespot-core 0.1.0", + "librespot-discovery 0.1.0", "librespot-metadata 0.1.0", + "librespot-playback 0.1.0", "librespot-protocol 0.1.0", "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "mdns 0.2.0 (git+https://github.com/plietar/rust-mdns)", "num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "portaudio-rs 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf_macros 0.6.0 (git+https://github.com/plietar/rust-protobuf-macros)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", @@ -392,6 +387,28 @@ dependencies = [ "vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "librespot-discovery" +version = "0.1.0" +dependencies = [ + "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", + "dns-sd 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "futures 0.1.17 (registry+https://github.com/rust-lang/crates.io-index)", + "hyper 0.11.14 (registry+https://github.com/rust-lang/crates.io-index)", + "librespot-core 0.1.0", + "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "mdns 0.2.0 (git+https://github.com/plietar/rust-mdns)", + "num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", + "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", + "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", + "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", + "tokio-core 0.1.12 (registry+https://github.com/rust-lang/crates.io-index)", + "url 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "librespot-metadata" version = "0.1.0" @@ -404,6 +421,22 @@ dependencies = [ "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "librespot-playback" +version = "0.1.0" +dependencies = [ + "alsa 0.0.1 (git+https://github.com/plietar/rust-alsa)", + "futures 0.1.17 (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.36 (registry+https://github.com/rust-lang/crates.io-index)", + "libpulse-sys 0.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "librespot-audio 0.1.0", + "librespot-core 0.1.0", + "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)", +] + [[package]] name = "librespot-protocol" version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml index e627c1f9..617f89e5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,8 @@ path = "core" path = "discovery" [dependencies.librespot-metadata] path = "metadata" +[dependencies.librespot-playback] +path = "playback" [dependencies.librespot-protocol] path = "protocol" @@ -51,29 +53,23 @@ tokio-io = "0.1" tokio-signal = "0.1.2" url = "1.3" -alsa = { git = "https://github.com/plietar/rust-alsa", optional = true } -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 } - [build-dependencies] rand = "0.3.13" vergen = "0.1.0" protobuf_macros = { git = "https://github.com/plietar/rust-protobuf-macros", features = ["with-syntex"] } [features] -alsa-backend = ["alsa"] -portaudio-backend = ["portaudio-rs"] -pulseaudio-backend = ["libpulse-sys", "libc"] -jackaudio-backend = ["jack"] +alsa-backend = ["librespot-playback/alsa"] +portaudio-backend = ["librespot-playback/portaudio-rs"] +pulseaudio-backend = ["librespot-playback/libpulse-sys", "librespot-playback/libc"] +jackaudio-backend = ["librespot-playback/jack"] with-tremor = ["librespot-audio/with-tremor"] with-vorbis = ["librespot-audio/with-vorbis"] -with-dns-sd = ["librespot-discovery/dns-sd"] +with-dns-sd = ["librespot-discovery/with-dns-sd"] -default = ["portaudio-backend"] +default = ["librespot-playback/portaudio-backend"] [package.metadata.deb] maintainer = "librespot-org" diff --git a/playback/Cargo.toml b/playback/Cargo.toml new file mode 100644 index 00000000..b3e4fd55 --- /dev/null +++ b/playback/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "librespot-playback" +version = "0.1.0" +authors = ["Sasha Hilton "] + +[dependencies.librespot-audio] +path = "../audio" +[dependencies.librespot-core] +path = "../core" +[dependencies.librespot-metadata] +path = "../metadata" + +[dependencies] +futures = "0.1.8" +log = "0.3.5" + +alsa = { git = "https://github.com/plietar/rust-alsa", optional = true } +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 } + +[features] +alsa-backend = ["alsa"] +portaudio-backend = ["portaudio-rs"] +pulseaudio-backend = ["libpulse-sys", "libc"] +jackaudio-backend = ["jack"] + +default = ["portaudio-backend"] diff --git a/src/audio_backend/alsa.rs b/playback/src/audio_backend/alsa.rs similarity index 100% rename from src/audio_backend/alsa.rs rename to playback/src/audio_backend/alsa.rs diff --git a/src/audio_backend/jackaudio.rs b/playback/src/audio_backend/jackaudio.rs similarity index 100% rename from src/audio_backend/jackaudio.rs rename to playback/src/audio_backend/jackaudio.rs diff --git a/src/audio_backend/mod.rs b/playback/src/audio_backend/mod.rs similarity index 100% rename from src/audio_backend/mod.rs rename to playback/src/audio_backend/mod.rs diff --git a/src/audio_backend/pipe.rs b/playback/src/audio_backend/pipe.rs similarity index 100% rename from src/audio_backend/pipe.rs rename to playback/src/audio_backend/pipe.rs diff --git a/src/audio_backend/portaudio.rs b/playback/src/audio_backend/portaudio.rs similarity index 100% rename from src/audio_backend/portaudio.rs rename to playback/src/audio_backend/portaudio.rs diff --git a/src/audio_backend/pulseaudio.rs b/playback/src/audio_backend/pulseaudio.rs similarity index 100% rename from src/audio_backend/pulseaudio.rs rename to playback/src/audio_backend/pulseaudio.rs diff --git a/playback/src/lib.rs b/playback/src/lib.rs new file mode 100644 index 00000000..2633343b --- /dev/null +++ b/playback/src/lib.rs @@ -0,0 +1,26 @@ +#[macro_use] extern crate log; + +extern crate futures; + +#[cfg(feature = "alsa-backend")] +extern crate alsa; + +#[cfg(feature = "portaudio-rs")] +extern crate portaudio_rs; + +#[cfg(feature = "libpulse-sys")] +extern crate libpulse_sys; + +#[cfg(feature = "jackaudio-backend")] +extern crate jack; + +#[cfg(feature = "libc")] +extern crate libc; + +extern crate librespot_audio as audio; +extern crate librespot_core as core; +extern crate librespot_metadata as metadata; + +pub mod audio_backend; +pub mod mixer; +pub mod player; diff --git a/src/mixer/mod.rs b/playback/src/mixer/mod.rs similarity index 100% rename from src/mixer/mod.rs rename to playback/src/mixer/mod.rs diff --git a/src/mixer/softmixer.rs b/playback/src/mixer/softmixer.rs similarity index 100% rename from src/mixer/softmixer.rs rename to playback/src/mixer/softmixer.rs diff --git a/src/player.rs b/playback/src/player.rs similarity index 100% rename from src/player.rs rename to playback/src/player.rs diff --git a/src/lib.rs b/src/lib.rs index 2d9aad1b..1d0ee72d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -17,26 +17,9 @@ extern crate url; pub extern crate librespot_audio as audio; pub extern crate librespot_core as core; pub extern crate librespot_discovery as discovery; +pub extern crate librespot_playback as playback; pub extern crate librespot_protocol as protocol; pub extern crate librespot_metadata as metadata; -#[cfg(feature = "alsa-backend")] -extern crate alsa; - -#[cfg(feature = "portaudio-rs")] -extern crate portaudio_rs; - -#[cfg(feature = "libpulse-sys")] -extern crate libpulse_sys; - -#[cfg(feature = "jackaudio-backend")] -extern crate jack; - -#[cfg(feature = "libc")] -extern crate libc; - -pub mod audio_backend; -pub mod mixer; -pub mod player; include!(concat!(env!("OUT_DIR"), "/lib.rs")); diff --git a/src/main.rs b/src/main.rs index 4200fc16..2ecfb57c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -24,10 +24,10 @@ use librespot::core::config::{Bitrate, DeviceType, PlayerConfig, SessionConfig, use librespot::core::session::Session; use librespot::core::version; -use librespot::audio_backend::{self, Sink, BACKENDS}; +use librespot::playback::audio_backend::{self, Sink, BACKENDS}; use librespot::discovery::discovery::{discovery, DiscoveryStream}; -use librespot::mixer::{self, Mixer}; -use librespot::player::Player; +use librespot::playback::mixer::{self, Mixer}; +use librespot::playback::player::Player; use librespot::spirc::{Spirc, SpircTask}; fn usage(program: &str, opts: &getopts::Options) -> String { diff --git a/src/spirc.rs b/src/spirc.rs index f8bd53a8..59b6b841 100644 --- a/src/spirc.rs +++ b/src/spirc.rs @@ -12,8 +12,8 @@ use core::version; use protocol; use protocol::spirc::{PlayStatus, State, MessageType, Frame, DeviceState}; -use mixer::Mixer; -use player::Player; +use playback::mixer::Mixer; +use playback::player::Player; use std; use rand; @@ -132,12 +132,12 @@ fn volume_to_mixer(volume: u16) -> u16 { let mut val = std::u16::MAX; // Prevent val > std::u16::MAX due to rounding errors - if normalized_volume < 0.999 { + if normalized_volume < 0.999 { let new_volume = (normalized_volume * IDEAL_FACTOR).exp() / 1000.0; val = (new_volume * std::u16::MAX as f64) as u16; } - debug!("input volume:{} to mixer: {}", volume, val); + debug!("input volume:{} to mixer: {}", volume, val); // return the scale factor (0..0xffff) (equivalent to a voltage multiplier). val @@ -575,7 +575,7 @@ impl SpircTask { } fn handle_end_of_track(&mut self) { - self.handle_next(); + self.handle_next(); self.notify(None); } From 4f605dfd86052f81f935dc48b8929f3f3cf268a4 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Fri, 9 Feb 2018 02:14:11 +0100 Subject: [PATCH 29/70] Correct feature flags --- Cargo.toml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 617f89e5..15e1dda1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,10 +59,10 @@ vergen = "0.1.0" protobuf_macros = { git = "https://github.com/plietar/rust-protobuf-macros", features = ["with-syntex"] } [features] -alsa-backend = ["librespot-playback/alsa"] -portaudio-backend = ["librespot-playback/portaudio-rs"] -pulseaudio-backend = ["librespot-playback/libpulse-sys", "librespot-playback/libc"] -jackaudio-backend = ["librespot-playback/jack"] +alsa-backend = ["librespot-playback/alsa-backend"] +portaudio-backend = ["librespot-playback/portaudio-backend"] +pulseaudio-backend = ["librespot-playback/pulseaudio-backend"] +jackaudio-backend = ["librespot-playback/jackaudio-backend"] with-tremor = ["librespot-audio/with-tremor"] with-vorbis = ["librespot-audio/with-vorbis"] From d34068c5a75d344123d7f61a5a09af14c6c08110 Mon Sep 17 00:00:00 2001 From: awiouy Date: Fri, 9 Feb 2018 20:57:49 +0100 Subject: [PATCH 30/70] core API: apresolve --- core/src/apresolve.rs | 9 ++++----- core/src/lib.rs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index d137d874..bf3ba276 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -14,7 +14,7 @@ pub struct APResolveData { ap_list: Vec } -pub fn apresolve(handle: &Handle) -> Box> { +fn apresolve(handle: &Handle) -> Box> { let url = Uri::from_str(APRESOLVE_ENDPOINT).expect("invalid AP resolve URL"); let client = Client::new(handle); @@ -44,10 +44,9 @@ pub fn apresolve(handle: &Handle) -> Box> { Box::new(ap) } -pub fn apresolve_or_fallback(handle: &Handle) - -> Box> - where E: 'static -{ +pub(crate) fn apresolve_or_fallback(handle: &Handle) + -> Box> + where E: 'static { let ap = apresolve(handle).or_else(|e| { warn!("Failed to resolve Access Point: {}", e.description()); warn!("Using fallback \"{}\"", AP_FALLBACK); diff --git a/core/src/lib.rs b/core/src/lib.rs index 2f00ad39..ab7a556f 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -27,7 +27,7 @@ extern crate uuid; extern crate librespot_protocol as protocol; #[macro_use] mod component; -pub mod apresolve; +mod apresolve; pub mod audio_key; pub mod authentication; pub mod cache; From 434b824c6e7b2daf0bd255b5cedd4265fab68ef3 Mon Sep 17 00:00:00 2001 From: awiouy Date: Fri, 9 Feb 2018 21:06:16 +0100 Subject: [PATCH 31/70] core API: dispatch --- core/src/audio_key.rs | 2 +- core/src/channel.rs | 2 +- core/src/mercury/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/audio_key.rs b/core/src/audio_key.rs index 41424880..a7a85896 100644 --- a/core/src/audio_key.rs +++ b/core/src/audio_key.rs @@ -22,7 +22,7 @@ component! { } impl AudioKeyManager { - pub fn dispatch(&self, cmd: u8, mut data: Bytes) { + pub(crate) fn dispatch(&self, cmd: u8, mut data: Bytes) { let seq = BigEndian::read_u32(data.split_to(4).as_ref()); let sender = self.lock(|inner| inner.pending.remove(&seq)); diff --git a/core/src/channel.rs b/core/src/channel.rs index d7c74e50..19f880e7 100644 --- a/core/src/channel.rs +++ b/core/src/channel.rs @@ -54,7 +54,7 @@ impl ChannelManager { (seq, channel) } - pub fn dispatch(&self, cmd: u8, mut data: Bytes) { + pub(crate) fn dispatch(&self, cmd: u8, mut data: Bytes) { use std::collections::hash_map::Entry; let id: u16 = BigEndian::read_u16(data.split_to(2).as_ref()); diff --git a/core/src/mercury/mod.rs b/core/src/mercury/mod.rs index b37ed92b..6309d0f4 100644 --- a/core/src/mercury/mod.rs +++ b/core/src/mercury/mod.rs @@ -136,7 +136,7 @@ impl MercuryManager { })) } - pub fn dispatch(&self, cmd: u8, mut data: Bytes) { + pub(crate) fn dispatch(&self, cmd: u8, mut data: Bytes) { let seq_len = BigEndian::read_u16(data.split_to(2).as_ref()) as usize; let seq = data.split_to(seq_len).as_ref().to_owned(); From c86f7909861105d1b35e69c5d7bff953e87a41be Mon Sep 17 00:00:00 2001 From: awiouy Date: Fri, 9 Feb 2018 21:18:06 +0100 Subject: [PATCH 32/70] core API: from_file, from_reader --- core/src/authentication.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/authentication.rs b/core/src/authentication.rs index 0075fe0d..4e6cc262 100644 --- a/core/src/authentication.rs +++ b/core/src/authentication.rs @@ -121,14 +121,14 @@ impl Credentials { } } - pub fn from_reader(mut reader: R) -> Credentials { + fn from_reader(mut reader: R) -> Credentials { let mut contents = String::new(); reader.read_to_string(&mut contents).unwrap(); serde_json::from_str(&contents).unwrap() } - pub fn from_file>(path: P) -> Option { + pub(crate) fn from_file>(path: P) -> Option { File::open(path).ok().map(Credentials::from_reader) } From a105fd44c46d7c1e5f708fa42c383402617963da Mon Sep 17 00:00:00 2001 From: awiouy Date: Fri, 9 Feb 2018 21:24:58 +0100 Subject: [PATCH 33/70] core API: save_to_file, save_to_writer --- core/src/authentication.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/authentication.rs b/core/src/authentication.rs index 4e6cc262..f441a7fd 100644 --- a/core/src/authentication.rs +++ b/core/src/authentication.rs @@ -132,12 +132,12 @@ impl Credentials { File::open(path).ok().map(Credentials::from_reader) } - pub fn save_to_writer(&self, writer: &mut W) { + fn save_to_writer(&self, writer: &mut W) { let contents = serde_json::to_string(&self.clone()).unwrap(); writer.write_all(contents.as_bytes()).unwrap(); } - pub fn save_to_file>(&self, path: P) { + pub(crate) fn save_to_file>(&self, path: P) { let mut file = File::create(path).unwrap(); self.save_to_writer(&mut file) } From 4c23803c84fca4ff4bdd8536bb7c39fc2d6a8153 Mon Sep 17 00:00:00 2001 From: awiouy Date: Fri, 9 Feb 2018 21:29:29 +0100 Subject: [PATCH 34/70] core API: cache.rs --- core/src/{cache/mod.rs => cache.rs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename core/src/{cache/mod.rs => cache.rs} (100%) diff --git a/core/src/cache/mod.rs b/core/src/cache.rs similarity index 100% rename from core/src/cache/mod.rs rename to core/src/cache.rs From 762b75803b0523f6e296459ed887093227cd2f48 Mon Sep 17 00:00:00 2001 From: awiouy Date: Fri, 9 Feb 2018 21:36:18 +0100 Subject: [PATCH 35/70] core API: connection --- core/src/lib.in.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/lib.in.rs b/core/src/lib.in.rs index c534cec4..cd8fbdaf 100644 --- a/core/src/lib.in.rs +++ b/core/src/lib.in.rs @@ -1,2 +1,2 @@ #[allow(unused_mut)] -pub mod connection; +mod connection; From 930bc3f841d3fe4962325c68c1c13a7d528caad7 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Sat, 10 Feb 2018 01:44:26 +0100 Subject: [PATCH 36/70] Remove default option iin playback/Cargo.toml --- playback/Cargo.toml | 2 -- 1 file changed, 2 deletions(-) diff --git a/playback/Cargo.toml b/playback/Cargo.toml index b3e4fd55..96c44bec 100644 --- a/playback/Cargo.toml +++ b/playback/Cargo.toml @@ -25,5 +25,3 @@ alsa-backend = ["alsa"] portaudio-backend = ["portaudio-rs"] pulseaudio-backend = ["libpulse-sys", "libc"] jackaudio-backend = ["jack"] - -default = ["portaudio-backend"] From a8bb696be89476470d90cdc832c8a109b284afe6 Mon Sep 17 00:00:00 2001 From: awiouy Date: Sat, 10 Feb 2018 08:23:46 +0100 Subject: [PATCH 37/70] core API: MercurySender::new --- core/src/mercury/sender.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mercury/sender.rs b/core/src/mercury/sender.rs index 67b4dc08..359e6907 100644 --- a/core/src/mercury/sender.rs +++ b/core/src/mercury/sender.rs @@ -11,7 +11,7 @@ pub struct MercurySender { impl MercurySender { // TODO: pub(super) when stable - pub fn new(mercury: MercuryManager, uri: String) -> MercurySender { + pub(crate) fn new(mercury: MercuryManager, uri: String) -> MercurySender { MercurySender { mercury: mercury, uri: uri, From d05fa10067247af8543061145d1888c6c8bbe9d1 Mon Sep 17 00:00:00 2001 From: Nick Steel Date: Thu, 1 Feb 2018 00:02:12 +0000 Subject: [PATCH 38/70] Improved next/prev handling for queued tracks. 1) A queued track is removed once it has become the current track. Note that the track doesn't need to actually play i.e. it could have been immediately skipped over with 'next()'. This is implemented in 'consume_queued_track()'. 2) Queued tracks are always positioned immediately after the current track. 1) ensures this is true for 'next()' but 'prev()' requires all the queued tracks are actually moved for this to remain the case. Also fixed the case where 'prev()' on the first track would incorrectly wrap back around to the last track even when repeat was disabled. The correct behaviour is to remain on the first track and just seek to the start. For example, with the following tracks and repeat enabled: TrackA, TrackB, TrackC-Q, TrackD-Q, TrackE ^^^^^^ Here, the result of 'prev' changes the current track from TrackB to TrackA and the queued tracks (TrackC, TrackD) move to the position immediately after TrackA: TrackA, TrackC-Q, TrackD-Q, TrackB, TrackE ^^^^^^ Calling 'prev' again results in the current track wrapping back around to TrackE and the queued tracks moving after that same track: TrackA, TrackB, TrackE, TrackC-Q, TrackD-Q ^^^^^^ --- src/spirc.rs | 54 ++++++++++++++++++++++++++++++++++++++-------------- 1 file changed, 40 insertions(+), 14 deletions(-) diff --git a/src/spirc.rs b/src/spirc.rs index 59b6b841..5c3d2afe 100644 --- a/src/spirc.rs +++ b/src/spirc.rs @@ -514,35 +514,61 @@ impl SpircTask { } } - fn handle_next(&mut self) { - let current_index = self.state.get_playing_track_index(); - let num_tracks = self.state.get_track().len() as u32; - let new_index = (current_index + 1) % num_tracks; - - let mut was_last_track = (current_index + 1) >= num_tracks; - if self.state.get_repeat() { - was_last_track = false; + fn consume_queued_track(&mut self) -> usize { + // Removes current track if it is queued + // Returns the index of the next track + let current_index = self.state.get_playing_track_index() as usize; + if self.state.get_track()[current_index].get_queued() { + self.state.mut_track().remove(current_index); + return current_index; } + current_index + 1 + } + fn handle_next(&mut self) { + let mut new_index = self.consume_queued_track() as u32; + let mut continue_playing = true; + if new_index >= self.state.get_track().len() as u32 { + new_index = 0; // Loop around back to start + continue_playing = self.state.get_repeat(); + } self.state.set_playing_track_index(new_index); self.state.set_position_ms(0); self.state.set_position_measured_at(now_ms() as u64); - self.load_track(!was_last_track); + self.load_track(continue_playing); } fn handle_prev(&mut self) { // Previous behaves differently based on the position - // Under 3s it goes to the previous song - // Over 3s it seeks to zero + // Under 3s it goes to the previous song (starts playing) + // Over 3s it seeks to zero (retains previous play status) if self.position() < 3000 { + // Queued tracks always follow the currently playing track. + // They should not be considered when calculating the previous + // track so extract them beforehand and reinsert them after it. + let mut queue_tracks = Vec::new(); + { + let queue_index = self.consume_queued_track(); + let tracks = self.state.mut_track(); + while queue_index < tracks.len() && tracks[queue_index].get_queued() { + queue_tracks.push(tracks.remove(queue_index)); + } + } let current_index = self.state.get_playing_track_index(); - - let new_index = if current_index == 0 { + let new_index = if current_index > 0 { + current_index - 1 + } else if self.state.get_repeat() { self.state.get_track().len() as u32 - 1 } else { - current_index - 1 + 0 }; + // Reinsert queued tracks after the new playing track. + let mut pos = (new_index + 1) as usize; + for track in queue_tracks.into_iter() { + self.state.mut_track().insert(pos, track); + pos += 1; + } self.state.set_playing_track_index(new_index); self.state.set_position_ms(0); From 72cef9a10c331f4abbcfa0f9fa951276619deaae Mon Sep 17 00:00:00 2001 From: awiouy Date: Sat, 10 Feb 2018 09:52:30 +0100 Subject: [PATCH 39/70] core API: Session.config() --- core/src/session.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/session.rs b/core/src/session.rs index e3b474bf..37a4aba0 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -184,7 +184,7 @@ impl Session { self.0.cache.as_ref() } - pub fn config(&self) -> &SessionConfig { + fn config(&self) -> &SessionConfig { &self.0.config } From ae85e69aca4ab5eedd3ebbf63164ad30c3202ec9 Mon Sep 17 00:00:00 2001 From: awiouy Date: Sat, 10 Feb 2018 10:10:26 +0100 Subject: [PATCH 40/70] core API: Session.weak() --- core/src/session.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/session.rs b/core/src/session.rs index 37a4aba0..4eecbe95 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -200,7 +200,7 @@ impl Session { &self.config().device_id } - pub fn weak(&self) -> SessionWeak { + fn weak(&self) -> SessionWeak { SessionWeak(Arc::downgrade(&self.0)) } From 55f27a9e0a26256e725d1c93805c2359ba027fa0 Mon Sep 17 00:00:00 2001 From: awiouy Date: Sat, 10 Feb 2018 10:22:03 +0100 Subject: [PATCH 41/70] core API: SessionWeak.try_upgrade(), SessionWeak.upgrade() --- core/src/session.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/core/src/session.rs b/core/src/session.rs index 4eecbe95..9fe785ed 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -213,11 +213,11 @@ impl Session { pub struct SessionWeak(pub Weak); impl SessionWeak { - pub fn try_upgrade(&self) -> Option { + fn try_upgrade(&self) -> Option { self.0.upgrade().map(Session) } - pub fn upgrade(&self) -> Session { + pub(crate) fn upgrade(&self) -> Session { self.try_upgrade().expect("Session died") } } From 77882836ce32bd475f8fec7d11c476153e551f9d Mon Sep 17 00:00:00 2001 From: awiouy Date: Sat, 10 Feb 2018 11:01:19 +0100 Subject: [PATCH 42/70] core API: move now_ms to spirc.rs --- core/src/util/mod.rs | 9 --------- src/spirc.rs | 11 ++++++++++- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/core/src/util/mod.rs b/core/src/util/mod.rs index 01a3a506..f9304f0b 100644 --- a/core/src/util/mod.rs +++ b/core/src/util/mod.rs @@ -8,7 +8,6 @@ use std::ops::{Mul, Rem, Shr}; use std::fs; use std::path::Path; use std::process::Command; -use std::time::{UNIX_EPOCH, SystemTime}; mod int128; mod spotify_id; @@ -22,14 +21,6 @@ pub fn rand_vec(rng: &mut G, size: usize) -> Vec { rng.gen_iter().take(size).collect() } -pub fn now_ms() -> i64 { - let dur = match SystemTime::now().duration_since(UNIX_EPOCH) { - Ok(dur) => dur, - Err(err) => err.duration(), - }; - (dur.as_secs() * 1000 + (dur.subsec_nanos() / 1000_000) as u64) as i64 -} - pub fn mkdir_existing(path: &Path) -> io::Result<()> { fs::create_dir(path).or_else(|err| { if err.kind() == io::ErrorKind::AlreadyExists { diff --git a/src/spirc.rs b/src/spirc.rs index 59b6b841..4e9e2991 100644 --- a/src/spirc.rs +++ b/src/spirc.rs @@ -6,7 +6,7 @@ use protobuf::{self, Message}; use core::config::ConnectConfig; use core::mercury::MercuryError; use core::session::Session; -use core::util::{now_ms, SpotifyId, SeqGenerator}; +use core::util::{SpotifyId, SeqGenerator}; use core::version; use protocol; @@ -18,6 +18,7 @@ use playback::player::Player; use std; use rand; use rand::Rng; +use std::time::{UNIX_EPOCH, SystemTime}; pub struct SpircTask { player: Player, @@ -53,6 +54,14 @@ pub struct Spirc { commands: mpsc::UnboundedSender, } +fn now_ms() -> i64 { + let dur = match SystemTime::now().duration_since(UNIX_EPOCH) { + Ok(dur) => dur, + Err(err) => err.duration(), + }; + (dur.as_secs() * 1000 + (dur.subsec_nanos() / 1000_000) as u64) as i64 +} + fn initial_state() -> State { protobuf_init!(protocol::spirc::State::new(), { repeat: false, From d7fa1464ffd3fc0dc4cabb1442f27be2d5adf17c Mon Sep 17 00:00:00 2001 From: awiouy Date: Sat, 10 Feb 2018 11:26:26 +0100 Subject: [PATCH 43/70] core API: move mkdir_existing to cache.rs --- core/src/cache.rs | 19 ++++++++++++++++--- core/src/util/mod.rs | 13 ------------- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/core/src/cache.rs b/core/src/cache.rs index 28b787ff..1a58bdc0 100644 --- a/core/src/cache.rs +++ b/core/src/cache.rs @@ -1,8 +1,11 @@ -use std::path::PathBuf; -use std::io::Read; +use std::fs; use std::fs::File; +use std::io; +use std::io::Read; +use std::path::Path; +use std::path::PathBuf; -use util::{FileId, mkdir_existing}; +use util::FileId; use authentication::Credentials; #[derive(Clone)] @@ -11,6 +14,16 @@ pub struct Cache { use_audio_cache: bool, } +fn mkdir_existing(path: &Path) -> io::Result<()> { + fs::create_dir(path).or_else(|err| { + if err.kind() == io::ErrorKind::AlreadyExists { + Ok(()) + } else { + Err(err) + } + }) +} + impl Cache { pub fn new(location: PathBuf, use_audio_cache: bool) -> Cache { mkdir_existing(&location).unwrap(); diff --git a/core/src/util/mod.rs b/core/src/util/mod.rs index f9304f0b..f96a5431 100644 --- a/core/src/util/mod.rs +++ b/core/src/util/mod.rs @@ -2,11 +2,8 @@ use num_bigint::BigUint; use num_traits::{Zero, One}; use num_integer::Integer; use rand::{Rng, Rand}; -use std::io; use std::mem; use std::ops::{Mul, Rem, Shr}; -use std::fs; -use std::path::Path; use std::process::Command; mod int128; @@ -21,16 +18,6 @@ pub fn rand_vec(rng: &mut G, size: usize) -> Vec { rng.gen_iter().take(size).collect() } -pub fn mkdir_existing(path: &Path) -> io::Result<()> { - fs::create_dir(path).or_else(|err| { - if err.kind() == io::ErrorKind::AlreadyExists { - Ok(()) - } else { - Err(err) - } - }) -} - pub fn run_program(program: &str) { info!("Running {}", program); let mut v: Vec<&str> = program.split_whitespace().collect(); From 496a802248af48c1c3ba88e68f9f5bf81a0846ed Mon Sep 17 00:00:00 2001 From: awiouy Date: Sat, 10 Feb 2018 16:26:08 +0100 Subject: [PATCH 44/70] core API: move subfile.rs to player.rs --- core/src/util/mod.rs | 2 -- core/src/util/subfile.rs | 38 ------------------------------------ playback/src/player.rs | 42 ++++++++++++++++++++++++++++++++++++++-- 3 files changed, 40 insertions(+), 42 deletions(-) delete mode 100644 core/src/util/subfile.rs diff --git a/core/src/util/mod.rs b/core/src/util/mod.rs index f96a5431..d6cbdd68 100644 --- a/core/src/util/mod.rs +++ b/core/src/util/mod.rs @@ -8,11 +8,9 @@ use std::process::Command; mod int128; mod spotify_id; -mod subfile; pub use util::int128::u128; pub use util::spotify_id::{SpotifyId, FileId}; -pub use util::subfile::Subfile; pub fn rand_vec(rng: &mut G, size: usize) -> Vec { rng.gen_iter().take(size).collect() diff --git a/core/src/util/subfile.rs b/core/src/util/subfile.rs deleted file mode 100644 index 81d5d916..00000000 --- a/core/src/util/subfile.rs +++ /dev/null @@ -1,38 +0,0 @@ -use std::io::{Read, Seek, SeekFrom, Result}; - -pub struct Subfile { - stream: T, - offset: u64, -} - -impl Subfile { - pub fn new(mut stream: T, offset: u64) -> Subfile { - stream.seek(SeekFrom::Start(offset)).unwrap(); - Subfile { - stream: stream, - offset: offset, - } - } -} - -impl Read for Subfile { - fn read(&mut self, buf: &mut [u8]) -> Result { - self.stream.read(buf) - } -} - -impl Seek for Subfile { - fn seek(&mut self, mut pos: SeekFrom) -> Result { - pos = match pos { - SeekFrom::Start(offset) => SeekFrom::Start(offset + self.offset), - x => x, - }; - - let newpos = try!(self.stream.seek(pos)); - if newpos > self.offset { - Ok(newpos - self.offset) - } else { - Ok(0) - } - } -} diff --git a/playback/src/player.rs b/playback/src/player.rs index ffffa130..3958ab8a 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -1,15 +1,16 @@ use futures::sync::oneshot; use futures::{future, Future}; +use std; use std::borrow::Cow; +use std::io::{Read, Seek, SeekFrom, Result}; use std::mem; use std::sync::mpsc::{RecvError, TryRecvError, RecvTimeoutError}; use std::thread; use std::time::Duration; -use std; use core::config::{Bitrate, PlayerConfig}; use core::session::Session; -use core::util::{self, SpotifyId, Subfile}; +use core::util::{self, SpotifyId}; use audio_backend::Sink; use audio::{AudioFile, AudioDecrypt}; @@ -478,3 +479,40 @@ impl ::std::fmt::Debug for PlayerCommand { } } } + +struct Subfile { + stream: T, + offset: u64, +} + +impl Subfile { + pub fn new(mut stream: T, offset: u64) -> Subfile { + stream.seek(SeekFrom::Start(offset)).unwrap(); + Subfile { + stream: stream, + offset: offset, + } + } +} + +impl Read for Subfile { + fn read(&mut self, buf: &mut [u8]) -> Result { + self.stream.read(buf) + } +} + +impl Seek for Subfile { + fn seek(&mut self, mut pos: SeekFrom) -> Result { + pos = match pos { + SeekFrom::Start(offset) => SeekFrom::Start(offset + self.offset), + x => x, + }; + + let newpos = try!(self.stream.seek(pos)); + if newpos > self.offset { + Ok(newpos - self.offset) + } else { + Ok(0) + } + } +} From a35edc6af46a558d1f3325c9d056209713b5ce58 Mon Sep 17 00:00:00 2001 From: awiouy Date: Sat, 10 Feb 2018 17:18:54 +0100 Subject: [PATCH 45/70] core API: move run_program to player.rs --- core/src/util/mod.rs | 11 ----------- playback/src/player.rs | 17 ++++++++++++++--- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/core/src/util/mod.rs b/core/src/util/mod.rs index d6cbdd68..6e21a0f2 100644 --- a/core/src/util/mod.rs +++ b/core/src/util/mod.rs @@ -4,7 +4,6 @@ use num_integer::Integer; use rand::{Rng, Rand}; use std::mem; use std::ops::{Mul, Rem, Shr}; -use std::process::Command; mod int128; mod spotify_id; @@ -16,16 +15,6 @@ pub fn rand_vec(rng: &mut G, size: usize) -> Vec { rng.gen_iter().take(size).collect() } -pub fn run_program(program: &str) { - info!("Running {}", program); - let mut v: Vec<&str> = program.split_whitespace().collect(); - let status = Command::new(&v.remove(0)) - .args(&v) - .status() - .expect("program failed to start"); - info!("Exit status: {}", status); -} - pub fn powm(base: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint { let mut base = base.clone(); let mut exp = exp.clone(); diff --git a/playback/src/player.rs b/playback/src/player.rs index 3958ab8a..f0ee5d22 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -4,13 +4,14 @@ use std; use std::borrow::Cow; use std::io::{Read, Seek, SeekFrom, Result}; use std::mem; +use std::process::Command; use std::sync::mpsc::{RecvError, TryRecvError, RecvTimeoutError}; use std::thread; use std::time::Duration; use core::config::{Bitrate, PlayerConfig}; use core::session::Session; -use core::util::{self, SpotifyId}; +use core::util::SpotifyId; use audio_backend::Sink; use audio::{AudioFile, AudioDecrypt}; @@ -376,13 +377,13 @@ impl PlayerInternal { fn run_onstart(&self) { if let Some(ref program) = self.config.onstart { - util::run_program(program) + run_program(program) } } fn run_onstop(&self) { if let Some(ref program) = self.config.onstop { - util::run_program(program) + run_program(program) } } @@ -516,3 +517,13 @@ impl Seek for Subfile { } } } + +fn run_program(program: &str) { + info!("Running {}", program); + let mut v: Vec<&str> = program.split_whitespace().collect(); + let status = Command::new(&v.remove(0)) + .args(&v) + .status() + .expect("program failed to start"); + info!("Exit status: {}", status); +} From 12487966b274aff7325a7cae6355f7692681ccf2 Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Wed, 31 Jan 2018 06:45:48 +0100 Subject: [PATCH 46/70] Somewhat uniform coding style might help myself to better understand Rust :-) --- .gitignore | 2 ++ src/main.rs | 35 +++++++++++++---------------------- 2 files changed, 15 insertions(+), 22 deletions(-) diff --git a/.gitignore b/.gitignore index 50242a6a..1ca8ef72 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,5 @@ target .cargo spotify_appkey.key .vagrant/ +.project +.history \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index 2ecfb57c..579f5bc9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -135,30 +135,21 @@ fn setup(args: &[String]) -> Setup { let mixer = mixer::find(mixer_name.as_ref()) .expect("Invalid mixer"); - let initial_volume: i32; - if matches.opt_present("initial-volume") && matches.opt_str("initial-volume").unwrap().parse::().is_ok() { - let iv = matches.opt_str("initial-volume").unwrap().parse::().unwrap(); - match iv { - iv if iv >= 0 && iv <= 100 => { initial_volume = iv * 0xFFFF / 100 } - _ => { - debug!("Volume needs to be a value from 0-100; set volume level to 50%"); - initial_volume = 0x8000; + let initial_volume = matches + .opt_str("initial-volume") + .map(|volume| { + let volume = volume.parse::().unwrap(); + if volume < 0 || volume > 100 { + panic!("Initial volume must be in the range 0-100"); } - } - } else { - initial_volume = 0x8000; - } + volume * 0xFFFF / 100 + }) + .unwrap_or(0x8000); - let zeroconf_port: u16; - if matches.opt_present("zeroconf-port") && matches.opt_str("zeroconf-port").unwrap().parse::().is_ok() { - let z = matches.opt_str("zeroconf-port").unwrap().parse::().unwrap(); - match z { - z if z >= 1024 => { zeroconf_port = z } - _ => { zeroconf_port = 0 } - } - } else { - zeroconf_port = 0 - } + let zeroconf_port = + matches.opt_str("zeroconf-port") + .map(|port| port.parse::().unwrap()) + .unwrap_or(0); let name = matches.opt_str("name").unwrap(); let use_audio_cache = !matches.opt_present("disable-audio-cache"); From 5ed4639cca9c13035b72ec58a2f1a56f1571cf63 Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Wed, 31 Jan 2018 16:15:20 +0100 Subject: [PATCH 47/70] Remove the -z as an alias for the --zeroconf-port parameter --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 579f5bc9..4c04ad1b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,7 +101,7 @@ fn setup(args: &[String]) -> Setup { .optopt("", "device", "Audio device to use. Use '?' to list options", "DEVICE") .optopt("", "mixer", "Mixer to use", "MIXER") .optopt("", "initial-volume", "Initial volume in %, once connected (must be from 0 to 100)", "VOLUME") - .optopt("z", "zeroconf-port", "The port the internal server advertised over zeroconf uses.", "ZEROCONF_PORT"); + .optopt("", "zeroconf-port", "The port the internal server advertised over zeroconf uses.", "ZEROCONF_PORT"); let matches = match opts.parse(&args[1..]) { Ok(m) => m, From 4636cb71b96785bc44004c77ec0034e7eca3b140 Mon Sep 17 00:00:00 2001 From: Michael Herger Date: Fri, 9 Feb 2018 21:51:56 +0100 Subject: [PATCH 48/70] Print more descriptive error message when we fail to bind zeroconf to the given port. --- discovery/src/discovery.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/discovery/src/discovery.rs b/discovery/src/discovery.rs index e29a798a..24bf0e57 100644 --- a/discovery/src/discovery.rs +++ b/discovery/src/discovery.rs @@ -215,7 +215,7 @@ pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String, port let serve = { let http = Http::new(); debug!("Zeroconf server listening on 0.0.0.0:{}", port); - http.serve_addr_handle(&format!("0.0.0.0:{}", port).parse().unwrap(), &handle, move || Ok(discovery.clone())).unwrap() + http.serve_addr_handle(&format!("0.0.0.0:{}", port).parse().unwrap(), &handle, move || Ok(discovery.clone())).expect("Unable to bind Zeroconf to port") }; let s_port = serve.incoming_ref().local_addr().port(); From 0d92ac74d1dbb63c6d876d0a00f63961565e4c00 Mon Sep 17 00:00:00 2001 From: awiouy Date: Sun, 11 Feb 2018 12:14:09 +0100 Subject: [PATCH 49/70] Add rustfmt.toml --- rustfmt.toml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 rustfmt.toml diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 00000000..627f7c40 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1,4 @@ +max_width = 105 +reorder_imports = true +reorder_imports_in_group = true +reorder_modules = true From c9ba73c9ef08002bc9ffd709a482841da0a5ee68 Mon Sep 17 00:00:00 2001 From: awiouy Date: Sun, 11 Feb 2018 12:37:08 +0100 Subject: [PATCH 50/70] rustfmt: core --- core/build.rs | 19 ++++--- core/src/apresolve.rs | 31 +++++------ core/src/audio_key.rs | 17 +++--- core/src/authentication.rs | 82 ++++++++++++++++------------- core/src/cache.rs | 4 +- core/src/channel.rs | 6 +-- core/src/component.rs | 8 +-- core/src/config.rs | 11 ++-- core/src/connection/codec.rs | 6 +-- core/src/connection/handshake.rs | 47 ++++++++++------- core/src/connection/mod.rs | 57 ++++++++++---------- core/src/diffie_hellman.rs | 8 +-- core/src/keymaster.rs | 14 +++-- core/src/lib.rs | 18 ++++--- core/src/mercury/mod.rs | 41 ++++++--------- core/src/mercury/sender.rs | 2 +- core/src/mercury/types.rs | 21 ++++---- core/src/session.rs | 89 +++++++++++++++++++------------- core/src/util/int128.rs | 37 ++++++------- core/src/util/mod.rs | 12 ++--- core/src/util/spotify_id.rs | 9 ++-- 21 files changed, 290 insertions(+), 249 deletions(-) diff --git a/core/build.rs b/core/build.rs index 5a2e5db8..d57d57a9 100644 --- a/core/build.rs +++ b/core/build.rs @@ -1,36 +1,35 @@ -extern crate vergen; extern crate protobuf_macros; extern crate rand; +extern crate vergen; use rand::Rng; use std::env; -use std::path::PathBuf; use std::fs::OpenOptions; use std::io::Write; +use std::path::PathBuf; fn main() { let out = PathBuf::from(env::var("OUT_DIR").unwrap()); vergen::vergen(vergen::OutputFns::all()).unwrap(); - let build_id: String = rand::thread_rng() - .gen_ascii_chars() - .take(8) - .collect(); + let build_id: String = rand::thread_rng().gen_ascii_chars().take(8).collect(); - let mut version_file = - OpenOptions::new() + let mut version_file = OpenOptions::new() .write(true) .append(true) .open(&out.join("version.rs")) .unwrap(); - let build_id_fn = format!(" + let build_id_fn = format!( + " /// Generate a random build id. pub fn build_id() -> &'static str {{ \"{}\" }} -", build_id); +", + build_id + ); if let Err(e) = version_file.write_all(build_id_fn.as_bytes()) { println!("{}", e); diff --git a/core/src/apresolve.rs b/core/src/apresolve.rs index bf3ba276..8db9a5ed 100644 --- a/core/src/apresolve.rs +++ b/core/src/apresolve.rs @@ -1,20 +1,20 @@ -const AP_FALLBACK : &'static str = "ap.spotify.com:80"; -const APRESOLVE_ENDPOINT : &'static str = "http://apresolve.spotify.com/"; +const AP_FALLBACK: &'static str = "ap.spotify.com:80"; +const APRESOLVE_ENDPOINT: &'static str = "http://apresolve.spotify.com/"; -use std::str::FromStr; use futures::{Future, Stream}; -use hyper::{self, Uri, Client}; +use hyper::{self, Client, Uri}; use serde_json; +use std::str::FromStr; use tokio_core::reactor::Handle; -error_chain! { } +error_chain!{} #[derive(Clone, Debug, Serialize, Deserialize)] pub struct APResolveData { - ap_list: Vec + ap_list: Vec, } -fn apresolve(handle: &Handle) -> Box> { +fn apresolve(handle: &Handle) -> Box> { let url = Uri::from_str(APRESOLVE_ENDPOINT).expect("invalid AP resolve URL"); let client = Client::new(handle); @@ -27,14 +27,10 @@ fn apresolve(handle: &Handle) -> Box> { }) }); let body = body.then(|result| result.chain_err(|| "HTTP error")); - let body = body.and_then(|body| { - String::from_utf8(body).chain_err(|| "invalid UTF8 in response") - }); + let body = body.and_then(|body| String::from_utf8(body).chain_err(|| "invalid UTF8 in response")); - let data = body.and_then(|body| { - serde_json::from_str::(&body) - .chain_err(|| "invalid JSON") - }); + let data = + body.and_then(|body| serde_json::from_str::(&body).chain_err(|| "invalid JSON")); let ap = data.and_then(|data| { let ap = data.ap_list.first().ok_or("empty AP List")?; @@ -44,9 +40,10 @@ fn apresolve(handle: &Handle) -> Box> { Box::new(ap) } -pub(crate) fn apresolve_or_fallback(handle: &Handle) - -> Box> - where E: 'static { +pub(crate) fn apresolve_or_fallback(handle: &Handle) -> Box> +where + E: 'static, +{ let ap = apresolve(handle).or_else(|e| { warn!("Failed to resolve Access Point: {}", e.description()); warn!("Using fallback \"{}\"", AP_FALLBACK); diff --git a/core/src/audio_key.rs b/core/src/audio_key.rs index a7a85896..2d4fb2ab 100644 --- a/core/src/audio_key.rs +++ b/core/src/audio_key.rs @@ -1,17 +1,17 @@ use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use bytes::Bytes; -use futures::sync::oneshot; use futures::{Async, Future, Poll}; +use futures::sync::oneshot; use std::collections::HashMap; use std::io::Write; +use util::{FileId, SpotifyId}; use util::SeqGenerator; -use util::{SpotifyId, FileId}; -#[derive(Debug,Hash,PartialEq,Eq,Copy,Clone)] +#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)] pub struct AudioKey(pub [u8; 16]); -#[derive(Debug,Hash,PartialEq,Eq,Copy,Clone)] +#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)] pub struct AudioKeyError; component! { @@ -35,7 +35,11 @@ impl AudioKeyManager { let _ = sender.send(Ok(AudioKey(key))); } 0xe => { - warn!("error audio key {:x} {:x}", data.as_ref()[0], data.as_ref()[1]); + warn!( + "error audio key {:x} {:x}", + data.as_ref()[0], + data.as_ref()[1] + ); let _ = sender.send(Err(AudioKeyError)); } _ => (), @@ -68,7 +72,7 @@ impl AudioKeyManager { } pub struct AudioKeyFuture(oneshot::Receiver>); -impl Future for AudioKeyFuture { +impl Future for AudioKeyFuture { type Item = T; type Error = AudioKeyError; @@ -81,4 +85,3 @@ impl Future for AudioKeyFuture { } } } - diff --git a/core/src/authentication.rs b/core/src/authentication.rs index f441a7fd..c079d543 100644 --- a/core/src/authentication.rs +++ b/core/src/authentication.rs @@ -10,23 +10,22 @@ use protobuf::ProtobufEnum; use rpassword; use serde; use serde_json; -use std::io::{self, stderr, Read, Write}; use std::fs::File; +use std::io::{self, stderr, Read, Write}; use std::path::Path; use protocol::authentication::AuthenticationType; -#[derive(Debug, Clone)] -#[derive(Serialize, Deserialize)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Credentials { pub username: String, - #[serde(serialize_with="serialize_protobuf_enum")] - #[serde(deserialize_with="deserialize_protobuf_enum")] + #[serde(serialize_with = "serialize_protobuf_enum")] + #[serde(deserialize_with = "deserialize_protobuf_enum")] pub auth_type: AuthenticationType, - #[serde(serialize_with="serialize_base64")] - #[serde(deserialize_with="deserialize_base64")] + #[serde(serialize_with = "serialize_base64")] + #[serde(deserialize_with = "deserialize_base64")] pub auth_data: Vec, } @@ -89,13 +88,18 @@ impl Credentials { let blob = { // Anyone know what this block mode is ? let mut data = vec![0u8; encrypted_blob.len()]; - let mut cipher = aes::ecb_decryptor(aes::KeySize::KeySize192, - &key, - crypto::blockmodes::NoPadding); - cipher.decrypt(&mut crypto::buffer::RefReadBuffer::new(&encrypted_blob), - &mut crypto::buffer::RefWriteBuffer::new(&mut data), - true) - .unwrap(); + let mut cipher = aes::ecb_decryptor( + aes::KeySize::KeySize192, + &key, + crypto::blockmodes::NoPadding, + ); + cipher + .decrypt( + &mut crypto::buffer::RefReadBuffer::new(&encrypted_blob), + &mut crypto::buffer::RefWriteBuffer::new(&mut data), + true, + ) + .unwrap(); let l = encrypted_blob.len(); for i in 0..l - 0x10 { @@ -112,7 +116,7 @@ impl Credentials { let auth_type = read_int(&mut cursor).unwrap(); let auth_type = AuthenticationType::from_i32(auth_type as i32).unwrap(); read_u8(&mut cursor).unwrap(); - let auth_data = read_bytes(&mut cursor).unwrap();; + let auth_data = read_bytes(&mut cursor).unwrap(); Credentials { username: username, @@ -144,42 +148,49 @@ impl Credentials { } fn serialize_protobuf_enum(v: &T, ser: S) -> Result - where T: ProtobufEnum, S: serde::Serializer { - +where + T: ProtobufEnum, + S: serde::Serializer, +{ serde::Serialize::serialize(&v.value(), ser) } fn deserialize_protobuf_enum(de: D) -> Result - where T: ProtobufEnum, D: serde::Deserializer { - - let v : i32 = try!(serde::Deserialize::deserialize(de)); +where + T: ProtobufEnum, + D: serde::Deserializer, +{ + let v: i32 = try!(serde::Deserialize::deserialize(de)); T::from_i32(v).ok_or_else(|| serde::de::Error::custom("Invalid enum value")) } fn serialize_base64(v: &T, ser: S) -> Result - where T: AsRef<[u8]>, S: serde::Serializer { - +where + T: AsRef<[u8]>, + S: serde::Serializer, +{ serde::Serialize::serialize(&base64::encode(v.as_ref()), ser) } fn deserialize_base64(de: D) -> Result, D::Error> - where D: serde::Deserializer { - - let v : String = try!(serde::Deserialize::deserialize(de)); +where + D: serde::Deserializer, +{ + let v: String = try!(serde::Deserialize::deserialize(de)); base64::decode(&v).map_err(|e| serde::de::Error::custom(e.to_string())) } -pub fn get_credentials(username: Option, password: Option, - cached_credentials: Option) - -> Option -{ +pub fn get_credentials( + username: Option, + password: Option, + cached_credentials: Option, +) -> Option { match (username, password, cached_credentials) { + (Some(username), Some(password), _) => Some(Credentials::with_password(username, password)), - (Some(username), Some(password), _) - => Some(Credentials::with_password(username, password)), - - (Some(ref username), _, Some(ref credentials)) - if *username == credentials.username => Some(credentials.clone()), + (Some(ref username), _, Some(ref credentials)) if *username == credentials.username => { + Some(credentials.clone()) + } (Some(username), None, _) => { write!(stderr(), "Password for {}: ", username).unwrap(); @@ -188,8 +199,7 @@ pub fn get_credentials(username: Option, password: Option, Some(Credentials::with_password(username.clone(), password)) } - (None, _, Some(credentials)) - => Some(credentials), + (None, _, Some(credentials)) => Some(credentials), (None, _, None) => None, } diff --git a/core/src/cache.rs b/core/src/cache.rs index 1a58bdc0..fb59c729 100644 --- a/core/src/cache.rs +++ b/core/src/cache.rs @@ -5,8 +5,8 @@ use std::io::Read; use std::path::Path; use std::path::PathBuf; -use util::FileId; use authentication::Credentials; +use util::FileId; #[derive(Clone)] pub struct Cache { @@ -31,7 +31,7 @@ impl Cache { Cache { root: location, - use_audio_cache: use_audio_cache + use_audio_cache: use_audio_cache, } } } diff --git a/core/src/channel.rs b/core/src/channel.rs index 19f880e7..112e6ad4 100644 --- a/core/src/channel.rs +++ b/core/src/channel.rs @@ -1,7 +1,7 @@ use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; -use futures::sync::{BiLock, mpsc}; -use futures::{Poll, Async, Stream}; +use futures::{Async, Poll, Stream}; +use futures::sync::{mpsc, BiLock}; use std::collections::HashMap; use util::SeqGenerator; @@ -13,7 +13,7 @@ component! { } } -#[derive(Debug,Hash,PartialEq,Eq,Copy,Clone)] +#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)] pub struct ChannelError; pub struct Channel { diff --git a/core/src/component.rs b/core/src/component.rs index 1a887e77..923e72ec 100644 --- a/core/src/component.rs +++ b/core/src/component.rs @@ -36,15 +36,15 @@ macro_rules! component { } } -use std::sync::Mutex; use std::cell::UnsafeCell; +use std::sync::Mutex; pub struct Lazy(Mutex, UnsafeCell>); -unsafe impl Sync for Lazy {} -unsafe impl Send for Lazy {} +unsafe impl Sync for Lazy {} +unsafe impl Send for Lazy {} #[cfg_attr(feature = "cargo-clippy", allow(mutex_atomic))] -impl Lazy { +impl Lazy { pub fn new() -> Lazy { Lazy(Mutex::new(false), UnsafeCell::new(None)) } diff --git a/core/src/config.rs b/core/src/config.rs index 46b22e41..297c04f4 100644 --- a/core/src/config.rs +++ b/core/src/config.rs @@ -1,10 +1,10 @@ -use uuid::Uuid; -use std::str::FromStr; use std::fmt; +use std::str::FromStr; +use uuid::Uuid; use version; -#[derive(Clone,Debug)] +#[derive(Clone, Debug)] pub struct SessionConfig { pub user_agent: String, pub device_id: String, @@ -20,7 +20,6 @@ impl Default for SessionConfig { } } - #[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] pub enum Bitrate { Bitrate96, @@ -100,7 +99,7 @@ impl Default for DeviceType { } } -#[derive(Clone,Debug)] +#[derive(Clone, Debug)] pub struct PlayerConfig { pub bitrate: Bitrate, pub onstart: Option, @@ -117,7 +116,7 @@ impl Default for PlayerConfig { } } -#[derive(Clone,Debug)] +#[derive(Clone, Debug)] pub struct ConnectConfig { pub name: String, pub device_type: DeviceType, diff --git a/core/src/connection/codec.rs b/core/src/connection/codec.rs index 6fbede13..4a8fd208 100644 --- a/core/src/connection/codec.rs +++ b/core/src/connection/codec.rs @@ -1,5 +1,5 @@ use byteorder::{BigEndian, ByteOrder}; -use bytes::{Bytes, BytesMut, BufMut}; +use bytes::{BufMut, Bytes, BytesMut}; use shannon::Shannon; use std::io; use tokio_io::codec::{Decoder, Encoder}; @@ -88,7 +88,8 @@ impl Decoder for APCodec { let mut payload = buf.split_to(size + MAC_SIZE); - self.decode_cipher.decrypt(&mut payload.get_mut(..size).unwrap()); + self.decode_cipher + .decrypt(&mut payload.get_mut(..size).unwrap()); let mac = payload.split_off(size); self.decode_cipher.check_mac(mac.as_ref())?; @@ -96,7 +97,6 @@ impl Decoder for APCodec { } } - Ok(None) } } diff --git a/core/src/connection/handshake.rs b/core/src/connection/handshake.rs index 5b94f709..c47364b4 100644 --- a/core/src/connection/handshake.rs +++ b/core/src/connection/handshake.rs @@ -1,20 +1,21 @@ -use crypto::sha1::Sha1; +use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; use crypto::hmac::Hmac; -use crypto::mac::Mac;use byteorder::{BigEndian, ByteOrder, WriteBytesExt}; +use crypto::mac::Mac; +use crypto::sha1::Sha1; +use futures::{Async, Future, Poll}; use protobuf::{self, Message, MessageStatic}; use rand::thread_rng; use std::io::{self, Read}; use std::marker::PhantomData; use tokio_io::{AsyncRead, AsyncWrite}; use tokio_io::codec::Framed; -use tokio_io::io::{write_all, WriteAll, read_exact, ReadExact, Window}; -use futures::{Poll, Async, Future}; +use tokio_io::io::{read_exact, write_all, ReadExact, Window, WriteAll}; +use super::codec::APCodec; use diffie_hellman::DHLocalKeys; use protocol; -use protocol::keyexchange::{ClientHello, APResponseMessage, ClientResponsePlaintext}; +use protocol::keyexchange::{APResponseMessage, ClientHello, ClientResponsePlaintext}; use util; -use super::codec::APCodec; pub struct Handshake { keys: DHLocalKeys, @@ -37,7 +38,7 @@ pub fn handshake(connection: T) -> Handshake { } } -impl Future for Handshake { +impl Future for Handshake { type Item = Framed; type Error = io::Error; @@ -47,22 +48,22 @@ impl Future for Handshake { self.state = match self.state { ClientHello(ref mut write) => { let (connection, accumulator) = try_ready!(write.poll()); - + let read = recv_packet(connection, accumulator); APResponse(read) } APResponse(ref mut read) => { let (connection, message, accumulator) = try_ready!(read.poll()); - let remote_key = message.get_challenge() + let remote_key = message + .get_challenge() .get_login_crypto_challenge() .get_diffie_hellman() .get_gs() .to_owned(); let shared_secret = self.keys.shared_secret(&remote_key); - let (challenge, send_key, recv_key) = compute_keys(&shared_secret, - &accumulator); + let (challenge, send_key, recv_key) = compute_keys(&shared_secret, &accumulator); let codec = APCodec::new(&send_key, &recv_key); let write = client_response(connection, challenge); @@ -129,15 +130,17 @@ enum RecvPacket { } fn recv_packet(connection: T, acc: Vec) -> RecvPacket - where T: Read, - M: MessageStatic +where + T: Read, + M: MessageStatic, { RecvPacket::Header(read_into_accumulator(connection, 4, acc), PhantomData) } -impl Future for RecvPacket - where T: Read, - M: MessageStatic +impl Future for RecvPacket +where + T: Read, + M: MessageStatic, { type Item = (T, M, Vec); type Error = io::Error; @@ -167,7 +170,11 @@ impl Future for RecvPacket } } -fn read_into_accumulator(connection: T, size: usize, mut acc: Vec) -> ReadExact>> { +fn read_into_accumulator( + connection: T, + size: usize, + mut acc: Vec, +) -> ReadExact>> { let offset = acc.len(); acc.resize(offset + size, 0); @@ -191,5 +198,9 @@ fn compute_keys(shared_secret: &[u8], packets: &[u8]) -> (Vec, Vec, Vec< mac = Hmac::new(Sha1::new(), &data[..0x14]); mac.input(packets); - (mac.result().code().to_vec(), data[0x14..0x34].to_vec(), data[0x34..0x54].to_vec()) + ( + mac.result().code().to_vec(), + data[0x14..0x34].to_vec(), + data[0x34..0x54].to_vec(), + ) } diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index 91c220b6..fae4092a 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -5,31 +5,34 @@ pub use self::codec::APCodec; pub use self::handshake::handshake; use futures::{Future, Sink, Stream}; +use protobuf::{self, Message}; use std::io; use std::net::ToSocketAddrs; use tokio_core::net::TcpStream; use tokio_core::reactor::Handle; use tokio_io::codec::Framed; -use protobuf::{self, Message}; use authentication::Credentials; use version; pub type Transport = Framed; -pub fn connect(addr: A, handle: &Handle) -> Box> { +pub fn connect( + addr: A, + handle: &Handle, +) -> Box> { let addr = addr.to_socket_addrs().unwrap().next().unwrap(); let socket = TcpStream::connect(&addr, handle); - let connection = socket.and_then(|socket| { - handshake(socket) - }); + let connection = socket.and_then(|socket| handshake(socket)); Box::new(connection) } -pub fn authenticate(transport: Transport, credentials: Credentials, device_id: String) - -> Box> -{ +pub fn authenticate( + transport: Transport, + credentials: Credentials, + device_id: String, +) -> Box> { use protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os}; let packet = protobuf_init!(ClientResponseEncrypted::new(), { @@ -50,26 +53,26 @@ pub fn authenticate(transport: Transport, credentials: Credentials, device_id: S let cmd = 0xab; let data = packet.write_to_bytes().unwrap(); - Box::new(transport.send((cmd, data)).and_then(|transport| { - transport.into_future().map_err(|(err, _stream)| err) - }).and_then(|(packet, transport)| { - match packet { - Some((0xac, data)) => { - let welcome_data: APWelcome = - protobuf::parse_from_bytes(data.as_ref()).unwrap(); + Box::new( + transport + .send((cmd, data)) + .and_then(|transport| transport.into_future().map_err(|(err, _stream)| err)) + .and_then(|(packet, transport)| match packet { + Some((0xac, data)) => { + let welcome_data: APWelcome = protobuf::parse_from_bytes(data.as_ref()).unwrap(); - let reusable_credentials = Credentials { - username: welcome_data.get_canonical_username().to_owned(), - auth_type: welcome_data.get_reusable_auth_credentials_type(), - auth_data: welcome_data.get_reusable_auth_credentials().to_owned(), - }; + let reusable_credentials = Credentials { + username: welcome_data.get_canonical_username().to_owned(), + auth_type: welcome_data.get_reusable_auth_credentials_type(), + auth_data: welcome_data.get_reusable_auth_credentials().to_owned(), + }; - Ok((transport, reusable_credentials)) - } + Ok((transport, reusable_credentials)) + } - Some((0xad, _)) => panic!("Authentication failed"), - Some((cmd, _)) => panic!("Unexpected packet {:?}", cmd), - None => panic!("EOF"), - } - })) + Some((0xad, _)) => panic!("Authentication failed"), + Some((cmd, _)) => panic!("Unexpected packet {:?}", cmd), + None => panic!("EOF"), + }), + ) } diff --git a/core/src/diffie_hellman.rs b/core/src/diffie_hellman.rs index 2f6572e1..2200399f 100644 --- a/core/src/diffie_hellman.rs +++ b/core/src/diffie_hellman.rs @@ -43,9 +43,11 @@ impl DHLocalKeys { } pub fn shared_secret(&self, remote_key: &[u8]) -> Vec { - let shared_key = util::powm(&BigUint::from_bytes_be(remote_key), - &self.private_key, - &DH_PRIME); + let shared_key = util::powm( + &BigUint::from_bytes_be(remote_key), + &self.private_key, + &DH_PRIME, + ); shared_key.to_bytes_be() } } diff --git a/core/src/keymaster.rs b/core/src/keymaster.rs index a4e0c169..4d82ae07 100644 --- a/core/src/keymaster.rs +++ b/core/src/keymaster.rs @@ -13,13 +13,19 @@ pub struct Token { pub scope: Vec, } -pub fn get_token(session: &Session, client_id: &str, scopes: &str) -> Box> { - let url = format!("hm://keymaster/token/authenticated?client_id={}&scope={}", - client_id, scopes); +pub fn get_token( + session: &Session, + client_id: &str, + scopes: &str, +) -> Box> { + let url = format!( + "hm://keymaster/token/authenticated?client_id={}&scope={}", + client_id, scopes + ); Box::new(session.mercury().get(url).map(move |response| { let data = response.payload.first().expect("Empty payload"); let data = String::from_utf8(data.clone()).unwrap(); - let token : Token = serde_json::from_str(&data).unwrap(); + let token: Token = serde_json::from_str(&data).unwrap(); token })) diff --git a/core/src/lib.rs b/core/src/lib.rs index ab7a556f..4cc44448 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -1,10 +1,15 @@ #![cfg_attr(feature = "cargo-clippy", allow(unused_io_amount))] -#[macro_use] extern crate error_chain; -#[macro_use] extern crate futures; -#[macro_use] extern crate lazy_static; -#[macro_use] extern crate log; -#[macro_use] extern crate serde_derive; +#[macro_use] +extern crate error_chain; +#[macro_use] +extern crate futures; +#[macro_use] +extern crate lazy_static; +#[macro_use] +extern crate log; +#[macro_use] +extern crate serde_derive; extern crate base64; extern crate byteorder; @@ -26,7 +31,8 @@ extern crate uuid; extern crate librespot_protocol as protocol; -#[macro_use] mod component; +#[macro_use] +mod component; mod apresolve; pub mod audio_key; pub mod authentication; diff --git a/core/src/mercury/mod.rs b/core/src/mercury/mod.rs index 6309d0f4..9a607061 100644 --- a/core/src/mercury/mod.rs +++ b/core/src/mercury/mod.rs @@ -1,7 +1,7 @@ use byteorder::{BigEndian, ByteOrder}; use bytes::Bytes; -use futures::sync::{oneshot, mpsc}; -use futures::{Async, Poll, Future}; +use futures::{Async, Future, Poll}; +use futures::sync::{mpsc, oneshot}; use protobuf; use protocol; use std::collections::HashMap; @@ -30,7 +30,7 @@ pub struct MercuryPending { } pub struct MercuryFuture(oneshot::Receiver>); -impl Future for MercuryFuture { +impl Future for MercuryFuture { type Item = T; type Error = MercuryError; @@ -51,9 +51,7 @@ impl MercuryManager { seq } - pub fn request(&self, req: MercuryRequest) - -> MercuryFuture - { + pub fn request(&self, req: MercuryRequest) -> MercuryFuture { let (tx, rx) = oneshot::channel(); let pending = MercuryPending { @@ -72,9 +70,7 @@ impl MercuryManager { MercuryFuture(rx) } - pub fn get>(&self, uri: T) - -> MercuryFuture - { + pub fn get>(&self, uri: T) -> MercuryFuture { self.request(MercuryRequest { method: MercuryMethod::GET, uri: uri.into(), @@ -83,9 +79,7 @@ impl MercuryManager { }) } - pub fn send>(&self, uri: T, data: Vec) - -> MercuryFuture - { + pub fn send>(&self, uri: T, data: Vec) -> MercuryFuture { self.request(MercuryRequest { method: MercuryMethod::SEND, uri: uri.into(), @@ -98,9 +92,10 @@ impl MercuryManager { MercurySender::new(self.clone(), uri.into()) } - pub fn subscribe>(&self, uri: T) - -> Box, Error = MercuryError>> - { + pub fn subscribe>( + &self, + uri: T, + ) -> Box, Error = MercuryError>> { let uri = uri.into(); let request = self.request(MercuryRequest { method: MercuryMethod::SUB, @@ -118,8 +113,8 @@ impl MercuryManager { if response.payload.len() > 0 { // Old subscription protocol, watch the provided list of URIs for sub in response.payload { - let mut sub : protocol::pubsub::Subscription - = protobuf::parse_from_bytes(&sub).unwrap(); + let mut sub: protocol::pubsub::Subscription = + protobuf::parse_from_bytes(&sub).unwrap(); let sub_uri = sub.take_uri(); debug!("subscribed sub_uri={}", sub_uri); @@ -147,13 +142,11 @@ impl MercuryManager { let mut pending = match pending { Some(pending) => pending, - None if cmd == 0xb5 => { - MercuryPending { - parts: Vec::new(), - partial: None, - callback: None, - } - } + None if cmd == 0xb5 => MercuryPending { + parts: Vec::new(), + partial: None, + callback: None, + }, None => { warn!("Ignore seq {:?} cmd {:x}", seq, cmd); return; diff --git a/core/src/mercury/sender.rs b/core/src/mercury/sender.rs index 359e6907..f00235ef 100644 --- a/core/src/mercury/sender.rs +++ b/core/src/mercury/sender.rs @@ -1,5 +1,5 @@ +use futures::{Async, AsyncSink, Future, Poll, Sink, StartSend}; use std::collections::VecDeque; -use futures::{Async, Poll, Future, Sink, StartSend, AsyncSink}; use super::*; diff --git a/core/src/mercury/types.rs b/core/src/mercury/types.rs index 9952b533..23f64c45 100644 --- a/core/src/mercury/types.rs +++ b/core/src/mercury/types.rs @@ -27,18 +27,17 @@ pub struct MercuryResponse { pub payload: Vec>, } -#[derive(Debug,Hash,PartialEq,Eq,Copy,Clone)] +#[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)] pub struct MercuryError; impl ToString for MercuryMethod { fn to_string(&self) -> String { match *self { - MercuryMethod::GET => "GET", - MercuryMethod::SUB => "SUB", - MercuryMethod::UNSUB => "UNSUB", - MercuryMethod::SEND => "SEND", - } - .to_owned() + MercuryMethod::GET => "GET", + MercuryMethod::SUB => "SUB", + MercuryMethod::UNSUB => "UNSUB", + MercuryMethod::SEND => "SEND", + }.to_owned() } } @@ -58,7 +57,9 @@ impl MercuryRequest { packet.write_u16::(seq.len() as u16).unwrap(); packet.write_all(seq).unwrap(); packet.write_u8(1).unwrap(); // Flags: FINAL - packet.write_u16::(1 + self.payload.len() as u16).unwrap(); // Part count + packet + .write_u16::(1 + self.payload.len() as u16) + .unwrap(); // Part count let mut header = protocol::mercury::Header::new(); header.set_uri(self.uri.clone()); @@ -68,7 +69,9 @@ impl MercuryRequest { header.set_content_type(content_type.clone()); } - packet.write_u16::(header.compute_size() as u16).unwrap(); + packet + .write_u16::(header.compute_size() as u16) + .unwrap(); header.write_to_writer(&mut packet).unwrap(); for p in &self.payload { diff --git a/core/src/session.rs b/core/src/session.rs index 9fe785ed..628e0377 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -1,19 +1,19 @@ use bytes::Bytes; use crypto::digest::Digest; use crypto::sha1::Sha1; +use futures::{Async, Future, IntoFuture, Poll, Stream}; use futures::sync::mpsc; -use futures::{Future, Stream, IntoFuture, Poll, Async}; use std::io; -use std::sync::{RwLock, Arc, Weak}; +use std::sync::{Arc, RwLock, Weak}; +use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT}; use tokio_core::reactor::{Handle, Remote}; -use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; use apresolve::apresolve_or_fallback; use authentication::Credentials; use cache::Cache; use component::Lazy; -use connection; use config::SessionConfig; +use connection; use audio_key::AudioKeyManager; use channel::ChannelManager; @@ -40,7 +40,7 @@ pub struct SessionInternal { session_id: usize, } -static SESSION_COUNTER : AtomicUsize = ATOMIC_USIZE_INIT; +static SESSION_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; #[derive(Clone)] pub struct Session(pub Arc); @@ -52,13 +52,14 @@ pub fn device_id(name: &str) -> String { } impl Session { - pub fn connect(config: SessionConfig, credentials: Credentials, - cache: Option, handle: Handle) - -> Box> - { + pub fn connect( + config: SessionConfig, + credentials: Credentials, + cache: Option, + handle: Handle, + ) -> Box> { let access_point = apresolve_or_fallback::(&handle); - let handle_ = handle.clone(); let connection = access_point.and_then(move |addr| { info!("Connecting to AP \"{}\"", addr); @@ -66,9 +67,8 @@ impl Session { }); let device_id = config.device_id.clone(); - let authentication = connection.and_then(move |connection| { - connection::authenticate(connection, credentials, device_id) - }); + let authentication = connection + .and_then(move |connection| connection::authenticate(connection, credentials, device_id)); let result = authentication.map(move |(transport, reusable_credentials)| { info!("Authenticated as \"{}\" !", reusable_credentials.username); @@ -77,21 +77,28 @@ impl Session { } let (session, task) = Session::create( - &handle, transport, config, cache, reusable_credentials.username.clone() + &handle, + transport, + config, + cache, + reusable_credentials.username.clone(), ); handle.spawn(task.map_err(|e| panic!(e))); session }); - + Box::new(result) } - fn create(handle: &Handle, transport: connection::Transport, - config: SessionConfig, cache: Option, username: String) - -> (Session, Box>) - { + fn create( + handle: &Handle, + transport: connection::Transport, + config: SessionConfig, + cache: Option, + username: String, + ) -> (Session, Box>) { let (sink, stream) = transport.split(); let (sender_tx, sender_rx) = mpsc::unbounded(); @@ -121,11 +128,15 @@ impl Session { let sender_task = sender_rx .map_err(|e| -> io::Error { panic!(e) }) - .forward(sink).map(|_| ()); + .forward(sink) + .map(|_| ()); let receiver_task = DispatchTask(stream, session.weak()); - let task = Box::new((receiver_task, sender_task).into_future() - .map(|((), ())| ())); + let task = Box::new( + (receiver_task, sender_task) + .into_future() + .map(|((), ())| ()), + ); (session, task) } @@ -143,16 +154,21 @@ impl Session { } pub fn spawn(&self, f: F) - where F: FnOnce(&Handle) -> R + Send + 'static, - R: IntoFuture, - R::Future: 'static + where + F: FnOnce(&Handle) -> R + Send + 'static, + R: IntoFuture, + R::Future: 'static, { self.0.handle.spawn(f) } fn debug_info(&self) { - debug!("Session[{}] strong={} weak={}", - self.0.session_id, Arc::strong_count(&self.0), Arc::weak_count(&self.0)); + debug!( + "Session[{}] strong={} weak={}", + self.0.session_id, + Arc::strong_count(&self.0), + Arc::weak_count(&self.0) + ); } #[cfg_attr(feature = "cargo-clippy", allow(match_same_arms))] @@ -161,7 +177,7 @@ impl Session { 0x4 => { self.debug_info(); self.send_packet(0x49, data.as_ref().to_owned()); - }, + } 0x4a => (), 0x1b => { let country = String::from_utf8(data.as_ref().to_owned()).unwrap(); @@ -229,10 +245,12 @@ impl Drop for SessionInternal { } struct DispatchTask(S, SessionWeak) - where S: Stream; +where + S: Stream; -impl Future for DispatchTask - where S: Stream +impl Future for DispatchTask +where + S: Stream, { type Item = (); type Error = S::Error; @@ -240,9 +258,7 @@ impl Future for DispatchTask fn poll(&mut self) -> Poll { let session = match self.1.try_upgrade() { Some(session) => session, - None => { - return Ok(Async::Ready(())) - }, + None => return Ok(Async::Ready(())), }; loop { @@ -252,8 +268,9 @@ impl Future for DispatchTask } } -impl Drop for DispatchTask - where S: Stream +impl Drop for DispatchTask +where + S: Stream, { fn drop(&mut self) { debug!("drop Dispatch"); diff --git a/core/src/util/int128.rs b/core/src/util/int128.rs index 9cfbaf3b..f79692ca 100644 --- a/core/src/util/int128.rs +++ b/core/src/util/int128.rs @@ -1,6 +1,6 @@ use std; -#[derive(Debug,Copy,Clone,PartialEq,Eq,Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[allow(non_camel_case_types)] pub struct u128 { high: u64, @@ -28,12 +28,7 @@ impl std::ops::Add for u128 { type Output = u128; fn add(self, rhs: u128) -> u128 { let low = self.low + rhs.low; - let high = self.high + rhs.high + - if low < self.low { - 1 - } else { - 0 - }; + let high = self.high + rhs.high + if low < self.low { 1 } else { 0 }; u128::from_parts(high, low) } @@ -43,12 +38,7 @@ impl<'a> std::ops::Add<&'a u128> for u128 { type Output = u128; fn add(self, rhs: &'a u128) -> u128 { let low = self.low + rhs.low; - let high = self.high + rhs.high + - if low < self.low { - 1 - } else { - 0 - }; + let high = self.high + rhs.high + if low < self.low { 1 } else { 0 }; u128::from_parts(high, low) } @@ -60,20 +50,23 @@ impl std::convert::From for u128 { } } - impl std::ops::Mul for u128 { type Output = u128; fn mul(self, rhs: u128) -> u128 { - let top: [u64; 4] = [self.high >> 32, - self.high & 0xFFFFFFFF, - self.low >> 32, - self.low & 0xFFFFFFFF]; + let top: [u64; 4] = [ + self.high >> 32, + self.high & 0xFFFFFFFF, + self.low >> 32, + self.low & 0xFFFFFFFF, + ]; - let bottom: [u64; 4] = [rhs.high >> 32, - rhs.high & 0xFFFFFFFF, - rhs.low >> 32, - rhs.low & 0xFFFFFFFF]; + let bottom: [u64; 4] = [ + rhs.high >> 32, + rhs.high & 0xFFFFFFFF, + rhs.low >> 32, + rhs.low & 0xFFFFFFFF, + ]; let mut rows = [u128::zero(); 16]; for i in 0..4 { diff --git a/core/src/util/mod.rs b/core/src/util/mod.rs index 6e21a0f2..66f2fe3f 100644 --- a/core/src/util/mod.rs +++ b/core/src/util/mod.rs @@ -1,7 +1,7 @@ use num_bigint::BigUint; -use num_traits::{Zero, One}; use num_integer::Integer; -use rand::{Rng, Rand}; +use num_traits::{One, Zero}; +use rand::{Rand, Rng}; use std::mem; use std::ops::{Mul, Rem, Shr}; @@ -9,7 +9,7 @@ mod int128; mod spotify_id; pub use util::int128::u128; -pub use util::spotify_id::{SpotifyId, FileId}; +pub use util::spotify_id::{FileId, SpotifyId}; pub fn rand_vec(rng: &mut G, size: usize) -> Vec { rng.gen_iter().take(size).collect() @@ -57,8 +57,8 @@ impl<'s> Iterator for StrChunks<'s> { } } -pub trait ReadSeek : ::std::io::Read + ::std::io::Seek { } -impl ReadSeek for T { } +pub trait ReadSeek: ::std::io::Read + ::std::io::Seek {} +impl ReadSeek for T {} pub trait Seq { fn next(&self) -> Self; @@ -77,7 +77,7 @@ impl_seq!(u8 u16 u32 u64 usize); #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord, Default)] pub struct SeqGenerator(T); -impl SeqGenerator { +impl SeqGenerator { pub fn new(value: T) -> Self { SeqGenerator(value) } diff --git a/core/src/util/spotify_id.rs b/core/src/util/spotify_id.rs index 8ebd5a84..5d99cb67 100644 --- a/core/src/util/spotify_id.rs +++ b/core/src/util/spotify_id.rs @@ -1,16 +1,15 @@ +use byteorder::{BigEndian, ByteOrder}; use std; use std::fmt; use util::u128; -use byteorder::{BigEndian, ByteOrder}; // Unneeded since 1.21 #[allow(unused_imports)] use std::ascii::AsciiExt; -#[derive(Debug,Copy,Clone,PartialEq,Eq,Hash)] +#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct SpotifyId(u128); -const BASE62_DIGITS: &'static [u8] = - b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; +const BASE62_DIGITS: &'static [u8] = b"0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; const BASE16_DIGITS: &'static [u8] = b"0123456789abcdef"; impl SpotifyId { @@ -79,7 +78,7 @@ impl SpotifyId { } } -#[derive(Copy,Clone,PartialEq,Eq,PartialOrd,Ord,Hash)] +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FileId(pub [u8; 20]); impl FileId { From 8658ad3a62617a2f63277aa9c55866768314fef4 Mon Sep 17 00:00:00 2001 From: awiouy Date: Sun, 11 Feb 2018 13:28:06 +0100 Subject: [PATCH 51/70] .travis.yml: add rustfmt --- .travis.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.travis.yml b/.travis.yml index 34bf2dfb..b1c30b25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -20,6 +20,10 @@ before_script: - echo '[target.armv7-unknown-linux-gnueabihf]' > ~/.cargo/config - echo 'linker = "arm-linux-gnueabihf-gcc"' >> ~/.cargo/config - rustup target add armv7-unknown-linux-gnueabihf + - if [[ $TRAVIS_RUST_VERSION == *"nightly"* ]]; then + rustup component add rustfmt-preview; + cargo fmt --package=librespot-core -- --write-mode=diff; + fi script: - cargo build --no-default-features From 191caca51831c1707f709033bb1d19f5b441c1f3 Mon Sep 17 00:00:00 2001 From: awiouy Date: Sun, 11 Feb 2018 16:13:42 +0100 Subject: [PATCH 52/70] core API: move Bitrate and PlayerConfig from core to playback --- core/src/config.rs | 42 ----------------------------------------- examples/play.rs | 2 +- playback/src/config.rs | 43 ++++++++++++++++++++++++++++++++++++++++++ playback/src/lib.rs | 1 + playback/src/player.rs | 2 +- src/main.rs | 3 ++- 6 files changed, 48 insertions(+), 45 deletions(-) create mode 100644 playback/src/config.rs diff --git a/core/src/config.rs b/core/src/config.rs index 297c04f4..7d3a5aea 100644 --- a/core/src/config.rs +++ b/core/src/config.rs @@ -20,31 +20,6 @@ impl Default for SessionConfig { } } -#[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] -pub enum Bitrate { - Bitrate96, - Bitrate160, - Bitrate320, -} - -impl FromStr for Bitrate { - type Err = (); - fn from_str(s: &str) -> Result { - match s { - "96" => Ok(Bitrate::Bitrate96), - "160" => Ok(Bitrate::Bitrate160), - "320" => Ok(Bitrate::Bitrate320), - _ => Err(()), - } - } -} - -impl Default for Bitrate { - fn default() -> Bitrate { - Bitrate::Bitrate160 - } -} - #[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] pub enum DeviceType { Unknown = 0, @@ -99,23 +74,6 @@ impl Default for DeviceType { } } -#[derive(Clone, Debug)] -pub struct PlayerConfig { - pub bitrate: Bitrate, - pub onstart: Option, - pub onstop: Option, -} - -impl Default for PlayerConfig { - fn default() -> PlayerConfig { - PlayerConfig { - bitrate: Bitrate::default(), - onstart: None, - onstop: None, - } - } -} - #[derive(Clone, Debug)] pub struct ConnectConfig { pub name: String, diff --git a/examples/play.rs b/examples/play.rs index d6092732..8c88ddbe 100644 --- a/examples/play.rs +++ b/examples/play.rs @@ -5,7 +5,7 @@ use std::env; use tokio_core::reactor::Core; use librespot::core::authentication::Credentials; -use librespot::core::config::{PlayerConfig, SessionConfig}; +use librespot::playback::config::{PlayerConfig, SessionConfig}; use librespot::core::session::Session; use librespot::core::util::SpotifyId; diff --git a/playback/src/config.rs b/playback/src/config.rs new file mode 100644 index 00000000..d44e937a --- /dev/null +++ b/playback/src/config.rs @@ -0,0 +1,43 @@ +use std::str::FromStr; + +#[derive(Clone, Copy, Debug, Hash, PartialOrd, Ord, PartialEq, Eq)] +pub enum Bitrate { + Bitrate96, + Bitrate160, + Bitrate320, +} + +impl FromStr for Bitrate { + type Err = (); + fn from_str(s: &str) -> Result { + match s { + "96" => Ok(Bitrate::Bitrate96), + "160" => Ok(Bitrate::Bitrate160), + "320" => Ok(Bitrate::Bitrate320), + _ => Err(()), + } + } +} + +impl Default for Bitrate { + fn default() -> Bitrate { + Bitrate::Bitrate160 + } +} + +#[derive(Clone, Debug)] +pub struct PlayerConfig { + pub bitrate: Bitrate, + pub onstart: Option, + pub onstop: Option, +} + +impl Default for PlayerConfig { + fn default() -> PlayerConfig { + PlayerConfig { + bitrate: Bitrate::default(), + onstart: None, + onstop: None, + } + } +} diff --git a/playback/src/lib.rs b/playback/src/lib.rs index 2633343b..014c7814 100644 --- a/playback/src/lib.rs +++ b/playback/src/lib.rs @@ -22,5 +22,6 @@ extern crate librespot_core as core; extern crate librespot_metadata as metadata; pub mod audio_backend; +pub mod config; pub mod mixer; pub mod player; diff --git a/playback/src/player.rs b/playback/src/player.rs index f0ee5d22..48f7f307 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -9,7 +9,7 @@ use std::sync::mpsc::{RecvError, TryRecvError, RecvTimeoutError}; use std::thread; use std::time::Duration; -use core::config::{Bitrate, PlayerConfig}; +use config::{Bitrate, PlayerConfig}; use core::session::Session; use core::util::SpotifyId; diff --git a/src/main.rs b/src/main.rs index 2ecfb57c..18f47a41 100644 --- a/src/main.rs +++ b/src/main.rs @@ -20,11 +20,12 @@ use std::mem; use librespot::core::authentication::{get_credentials, Credentials}; use librespot::core::cache::Cache; -use librespot::core::config::{Bitrate, DeviceType, PlayerConfig, SessionConfig, ConnectConfig}; +use librespot::core::config::{DeviceType, SessionConfig, ConnectConfig}; use librespot::core::session::Session; use librespot::core::version; use librespot::playback::audio_backend::{self, Sink, BACKENDS}; +use librespot::playback::config::{Bitrate, PlayerConfig}; use librespot::discovery::discovery::{discovery, DiscoveryStream}; use librespot::playback::mixer::{self, Mixer}; use librespot::playback::player::Player; From d900134114d9ab9f71645fecf07f806496770b91 Mon Sep 17 00:00:00 2001 From: awiouy Date: Sun, 11 Feb 2018 16:57:55 +0100 Subject: [PATCH 53/70] connect: discovery and spirc --- Cargo.lock | 4 ++-- Cargo.toml | 7 +++---- {discovery => connect}/Cargo.toml | 10 +++++++++- build.rs => connect/build.rs | 0 {discovery => connect}/src/discovery.rs | 0 {src => connect/src}/lib.in.rs | 0 {discovery => connect}/src/lib.rs | 4 ++++ {src => connect/src}/spirc.rs | 0 src/lib.rs | 7 +------ src/main.rs | 4 ++-- 10 files changed, 21 insertions(+), 15 deletions(-) rename {discovery => connect}/Cargo.toml (68%) rename build.rs => connect/build.rs (100%) rename {discovery => connect}/src/discovery.rs (100%) rename {src => connect/src}/lib.in.rs (100%) rename {discovery => connect}/src/lib.rs (75%) rename {src => connect/src}/spirc.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 0f21634d..e31c72fc 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -316,8 +316,8 @@ dependencies = [ "getopts 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", "hyper 0.11.14 (registry+https://github.com/rust-lang/crates.io-index)", "librespot-audio 0.1.0", + "librespot-connect 0.1.0", "librespot-core 0.1.0", - "librespot-discovery 0.1.0", "librespot-metadata 0.1.0", "librespot-playback 0.1.0", "librespot-protocol 0.1.0", @@ -388,7 +388,7 @@ dependencies = [ ] [[package]] -name = "librespot-discovery" +name = "librespot-connect" version = "0.1.0" dependencies = [ "base64 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index 15e1dda1..f3b88c3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -2,7 +2,6 @@ name = "librespot" version = "0.1.0" authors = ["Paul Liétar "] -build = "build.rs" license = "MIT" description = "Open Source Spotify client library" keywords = ["spotify"] @@ -22,10 +21,10 @@ doc = false [dependencies.librespot-audio] path = "audio" +[dependencies.librespot-connect] +path = "connect" [dependencies.librespot-core] path = "core" -[dependencies.librespot-discovery] -path = "discovery" [dependencies.librespot-metadata] path = "metadata" [dependencies.librespot-playback] @@ -67,7 +66,7 @@ jackaudio-backend = ["librespot-playback/jackaudio-backend"] with-tremor = ["librespot-audio/with-tremor"] with-vorbis = ["librespot-audio/with-vorbis"] -with-dns-sd = ["librespot-discovery/with-dns-sd"] +with-dns-sd = ["librespot-connect/with-dns-sd"] default = ["librespot-playback/portaudio-backend"] diff --git a/discovery/Cargo.toml b/connect/Cargo.toml similarity index 68% rename from discovery/Cargo.toml rename to connect/Cargo.toml index f69185a0..a345401d 100644 --- a/discovery/Cargo.toml +++ b/connect/Cargo.toml @@ -1,10 +1,15 @@ [package] -name = "librespot-discovery" +name = "librespot-connect" version = "0.1.0" authors = ["Paul Lietar "] +build = "build.rs" [dependencies.librespot-core] path = "../core" +[dependencies.librespot-playback] +path = "../playback" +[dependencies.librespot-protocol] +path = "../protocol" [dependencies] base64 = "0.5.0" @@ -24,6 +29,9 @@ url = "1.3" dns-sd = { version = "0.1.3", optional = true } mdns = { git = "https://github.com/plietar/rust-mdns", optional = true } +[build-dependencies] +protobuf_macros = { git = "https://github.com/plietar/rust-protobuf-macros", features = ["with-syntex"] } + [features] default = ["mdns"] with-dns-sd = ["dns-sd"] diff --git a/build.rs b/connect/build.rs similarity index 100% rename from build.rs rename to connect/build.rs diff --git a/discovery/src/discovery.rs b/connect/src/discovery.rs similarity index 100% rename from discovery/src/discovery.rs rename to connect/src/discovery.rs diff --git a/src/lib.in.rs b/connect/src/lib.in.rs similarity index 100% rename from src/lib.in.rs rename to connect/src/lib.in.rs diff --git a/discovery/src/lib.rs b/connect/src/lib.rs similarity index 75% rename from discovery/src/lib.rs rename to connect/src/lib.rs index d8775b8a..22c6885f 100644 --- a/discovery/src/lib.rs +++ b/connect/src/lib.rs @@ -18,5 +18,9 @@ extern crate dns_sd; extern crate mdns; extern crate librespot_core as core; +extern crate librespot_playback as playback; +extern crate librespot_protocol as protocol; pub mod discovery; + +include!(concat!(env!("OUT_DIR"), "/lib.rs")); diff --git a/src/spirc.rs b/connect/src/spirc.rs similarity index 100% rename from src/spirc.rs rename to connect/src/spirc.rs diff --git a/src/lib.rs b/src/lib.rs index 1d0ee72d..2ba4dac0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -2,8 +2,6 @@ #![cfg_attr(feature = "cargo-clippy", allow(unused_io_amount))] -#[macro_use] extern crate log; - extern crate base64; extern crate crypto; extern crate futures; @@ -15,11 +13,8 @@ extern crate tokio_core; extern crate url; pub extern crate librespot_audio as audio; +pub extern crate librespot_connect as connect; pub extern crate librespot_core as core; -pub extern crate librespot_discovery as discovery; pub extern crate librespot_playback as playback; pub extern crate librespot_protocol as protocol; pub extern crate librespot_metadata as metadata; - - -include!(concat!(env!("OUT_DIR"), "/lib.rs")); diff --git a/src/main.rs b/src/main.rs index 18f47a41..8168e844 100644 --- a/src/main.rs +++ b/src/main.rs @@ -26,10 +26,10 @@ use librespot::core::version; use librespot::playback::audio_backend::{self, Sink, BACKENDS}; use librespot::playback::config::{Bitrate, PlayerConfig}; -use librespot::discovery::discovery::{discovery, DiscoveryStream}; +use librespot::connect::discovery::{discovery, DiscoveryStream}; use librespot::playback::mixer::{self, Mixer}; use librespot::playback::player::Player; -use librespot::spirc::{Spirc, SpircTask}; +use librespot::connect::spirc::{Spirc, SpircTask}; fn usage(program: &str, opts: &getopts::Options) -> String { let brief = format!("Usage: {} [options]", program); From b7c32e9d6de7e20b8249b9f5aa98ac83cdbb9c94 Mon Sep 17 00:00:00 2001 From: awiouy Date: Sun, 11 Feb 2018 18:52:53 +0100 Subject: [PATCH 54/70] rustfmt: connect --- connect/build.rs | 1 - connect/src/discovery.rs | 105 ++++++++++++++++++++++----------------- connect/src/lib.rs | 6 ++- connect/src/spirc.rs | 77 ++++++++++++++-------------- 4 files changed, 105 insertions(+), 84 deletions(-) diff --git a/connect/build.rs b/connect/build.rs index 033187ec..e8df45d5 100644 --- a/connect/build.rs +++ b/connect/build.rs @@ -10,5 +10,4 @@ fn main() { println!("cargo:rerun-if-changed=src/lib.in.rs"); println!("cargo:rerun-if-changed=src/spirc.rs"); - } diff --git a/connect/src/discovery.rs b/connect/src/discovery.rs index e29a798a..fce47bca 100644 --- a/connect/src/discovery.rs +++ b/connect/src/discovery.rs @@ -1,11 +1,11 @@ use base64; +use crypto; use crypto::digest::Digest; use crypto::mac::Mac; -use crypto; +use futures::{Future, Poll, Stream}; use futures::sync::mpsc; -use futures::{Future, Stream, Poll}; -use hyper::server::{Service, Request, Response, Http}; use hyper::{self, Get, Post, StatusCode}; +use hyper::server::{Http, Request, Response, Service}; #[cfg(feature = "with-dns-sd")] use dns_sd::DNSService; @@ -21,10 +21,10 @@ use std::sync::Arc; use tokio_core::reactor::Handle; use url; -use core::diffie_hellman::{DH_GENERATOR, DH_PRIME}; use core::authentication::Credentials; -use core::util; use core::config::ConnectConfig; +use core::diffie_hellman::{DH_GENERATOR, DH_PRIME}; +use core::util; #[derive(Clone)] struct Discovery(Arc); @@ -37,9 +37,10 @@ struct DiscoveryInner { } impl Discovery { - fn new(config: ConnectConfig, device_id: String) - -> (Discovery, mpsc::UnboundedReceiver) - { + fn new( + config: ConnectConfig, + device_id: String, + ) -> (Discovery, mpsc::UnboundedReceiver) { let (tx, rx) = mpsc::unbounded(); let key_data = util::rand_vec(&mut rand::thread_rng(), 95); @@ -59,9 +60,10 @@ impl Discovery { } impl Discovery { - fn handle_get_info(&self, _params: &BTreeMap) - -> ::futures::Finished - { + fn handle_get_info( + &self, + _params: &BTreeMap, + ) -> ::futures::Finished { let public_key = self.0.public_key.to_bytes_be(); let public_key = base64::encode(&public_key); @@ -85,9 +87,10 @@ impl Discovery { ::futures::finished(Response::new().with_body(body)) } - fn handle_add_user(&self, params: &BTreeMap) - -> ::futures::Finished - { + fn handle_add_user( + &self, + params: &BTreeMap, + ) -> ::futures::Finished { let username = params.get("userName").unwrap(); let encrypted_blob = params.get("blob").unwrap(); let client_key = params.get("clientKey").unwrap(); @@ -133,8 +136,8 @@ impl Discovery { let decrypted = { let mut data = vec![0u8; encrypted.len()]; - let mut cipher = crypto::aes::ctr(crypto::aes::KeySize::KeySize128, - &encryption_key[0..16], iv); + let mut cipher = + crypto::aes::ctr(crypto::aes::KeySize::KeySize128, &encryption_key[0..16], iv); cipher.process(encrypted, &mut data); String::from_utf8(data).unwrap() }; @@ -153,9 +156,7 @@ impl Discovery { ::futures::finished(Response::new().with_body(body)) } - fn not_found(&self) - -> ::futures::Finished - { + fn not_found(&self) -> ::futures::Finished { ::futures::finished(Response::new().with_status(StatusCode::NotFound)) } } @@ -179,19 +180,22 @@ impl Service for Discovery { } let this = self.clone(); - Box::new(body.fold(Vec::new(), |mut acc, chunk| { - acc.extend_from_slice(chunk.as_ref()); - Ok::<_, hyper::Error>(acc) - }).map(move |body| { - params.extend(url::form_urlencoded::parse(&body).into_owned()); - params - }).and_then(move |params| { - match (method, params.get("action").map(AsRef::as_ref)) { - (Get, Some("getInfo")) => this.handle_get_info(¶ms), - (Post, Some("addUser")) => this.handle_add_user(¶ms), - _ => this.not_found(), - } - })) + Box::new( + body.fold(Vec::new(), |mut acc, chunk| { + acc.extend_from_slice(chunk.as_ref()); + Ok::<_, hyper::Error>(acc) + }).map(move |body| { + params.extend(url::form_urlencoded::parse(&body).into_owned()); + params + }) + .and_then( + move |params| match (method, params.get("action").map(AsRef::as_ref)) { + (Get, Some("getInfo")) => this.handle_get_info(¶ms), + (Post, Some("addUser")) => this.handle_add_user(¶ms), + _ => this.not_found(), + }, + ), + ) } } @@ -207,22 +211,30 @@ pub struct DiscoveryStream { _svc: mdns::Service, } -pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String, port: u16) - -> io::Result -{ +pub fn discovery( + handle: &Handle, + config: ConnectConfig, + device_id: String, + port: u16, +) -> io::Result { let (discovery, creds_rx) = Discovery::new(config.clone(), device_id); let serve = { let http = Http::new(); debug!("Zeroconf server listening on 0.0.0.0:{}", port); - http.serve_addr_handle(&format!("0.0.0.0:{}", port).parse().unwrap(), &handle, move || Ok(discovery.clone())).unwrap() + http.serve_addr_handle( + &format!("0.0.0.0:{}", port).parse().unwrap(), + &handle, + move || Ok(discovery.clone()), + ).unwrap() }; let s_port = serve.incoming_ref().local_addr().port(); let server_future = { let handle = handle.clone(); - serve.for_each(move |connection| { + serve + .for_each(move |connection| { handle.spawn(connection.then(|_| Ok(()))); Ok(()) }) @@ -231,22 +243,25 @@ pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String, port handle.spawn(server_future); #[cfg(feature = "with-dns-sd")] - let svc = DNSService::register(Some(&*config.name), - "_spotify-connect._tcp", - None, - None, - s_port, - &["VERSION=1.0", "CPath=/"]).unwrap(); + let svc = DNSService::register( + Some(&*config.name), + "_spotify-connect._tcp", + None, + None, + s_port, + &["VERSION=1.0", "CPath=/"], + ).unwrap(); #[cfg(not(feature = "with-dns-sd"))] let responder = mdns::Responder::spawn(&handle)?; - + #[cfg(not(feature = "with-dns-sd"))] let svc = responder.register( "_spotify-connect._tcp".to_owned(), config.name, s_port, - &["VERSION=1.0", "CPath=/"]); + &["VERSION=1.0", "CPath=/"], + ); Ok(DiscoveryStream { credentials: creds_rx, diff --git a/connect/src/lib.rs b/connect/src/lib.rs index 22c6885f..97fff8d8 100644 --- a/connect/src/lib.rs +++ b/connect/src/lib.rs @@ -1,5 +1,7 @@ -#[macro_use] extern crate log; -#[macro_use] extern crate serde_json; +#[macro_use] +extern crate log; +#[macro_use] +extern crate serde_json; extern crate base64; extern crate crypto; diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index a34be279..704472d7 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -1,24 +1,24 @@ +use futures::{Async, Future, Poll, Sink, Stream}; use futures::future; -use futures::sync::{oneshot, mpsc}; -use futures::{Future, Stream, Sink, Async, Poll}; +use futures::sync::{mpsc, oneshot}; use protobuf::{self, Message}; use core::config::ConnectConfig; use core::mercury::MercuryError; use core::session::Session; -use core::util::{SpotifyId, SeqGenerator}; +use core::util::{SeqGenerator, SpotifyId}; use core::version; use protocol; -use protocol::spirc::{PlayStatus, State, MessageType, Frame, DeviceState}; +use protocol::spirc::{DeviceState, Frame, MessageType, PlayStatus, State}; use playback::mixer::Mixer; use playback::player::Player; -use std; use rand; use rand::Rng; -use std::time::{UNIX_EPOCH, SystemTime}; +use std; +use std::time::{SystemTime, UNIX_EPOCH}; pub struct SpircTask { player: Player, @@ -47,7 +47,7 @@ pub enum SpircCommand { Next, VolumeUp, VolumeDown, - Shutdown + Shutdown, } pub struct Spirc { @@ -152,11 +152,13 @@ fn volume_to_mixer(volume: u16) -> u16 { val } - impl Spirc { - pub fn new(config: ConnectConfig, session: Session, player: Player, mixer: Box) - -> (Spirc, SpircTask) - { + pub fn new( + config: ConnectConfig, + session: Session, + player: Player, + mixer: Box, + ) -> (Spirc, SpircTask) { debug!("new Spirc[{}]", session.session_id()); let ident = session.device_id().to_owned(); @@ -164,15 +166,20 @@ impl Spirc { let uri = format!("hm://remote/3/user/{}/", session.username()); let subscription = session.mercury().subscribe(&uri as &str); - let subscription = subscription.map(|stream| stream.map_err(|_| MercuryError)).flatten_stream(); + let subscription = subscription + .map(|stream| stream.map_err(|_| MercuryError)) + .flatten_stream(); let subscription = Box::new(subscription.map(|response| -> Frame { let data = response.payload.first().unwrap(); protobuf::parse_from_bytes(data).unwrap() })); - let sender = Box::new(session.mercury().sender(uri).with(|frame: Frame| { - Ok(frame.write_to_bytes().unwrap()) - })); + let sender = Box::new( + session + .mercury() + .sender(uri) + .with(|frame: Frame| Ok(frame.write_to_bytes().unwrap())), + ); let (cmd_tx, cmd_rx) = mpsc::unbounded(); @@ -200,9 +207,7 @@ impl Spirc { session: session.clone(), }; - let spirc = Spirc { - commands: cmd_tx, - }; + let spirc = Spirc { commands: cmd_tx }; task.hello(); @@ -268,9 +273,7 @@ impl Future for SpircTask { self.handle_end_of_track(); } Ok(Async::NotReady) => (), - Err(oneshot::Canceled) => { - self.end_of_track = Box::new(future::empty()) - } + Err(oneshot::Canceled) => self.end_of_track = Box::new(future::empty()), } } @@ -357,15 +360,18 @@ impl SpircTask { } fn handle_frame(&mut self, frame: Frame) { - debug!("{:?} {:?} {} {} {}", - frame.get_typ(), - frame.get_device_state().get_name(), - frame.get_ident(), - frame.get_seq_nr(), - frame.get_state_update_id()); + debug!( + "{:?} {:?} {} {} {}", + frame.get_typ(), + frame.get_device_state().get_name(), + frame.get_ident(), + frame.get_seq_nr(), + frame.get_state_update_id() + ); - if frame.get_ident() == self.ident || - (frame.get_recipient().len() > 0 && !frame.get_recipient().contains(&self.ident)) { + if frame.get_ident() == self.ident + || (frame.get_recipient().len() > 0 && !frame.get_recipient().contains(&self.ident)) + { return; } @@ -383,7 +389,8 @@ impl SpircTask { self.update_tracks(&frame); if self.state.get_track().len() > 0 { - self.state.set_position_ms(frame.get_state().get_position_ms()); + self.state + .set_position_ms(frame.get_state().get_position_ms()); self.state.set_position_measured_at(now_ms() as u64); let play = frame.get_state().get_status() == PlayStatus::kPlayStatusPlay; @@ -437,8 +444,7 @@ impl SpircTask { MessageType::kMessageTypeShuffle => { self.state.set_shuffle(frame.get_state().get_shuffle()); - if self.state.get_shuffle() - { + if self.state.get_shuffle() { let current_index = self.state.get_playing_track_index(); { let tracks = self.state.mut_track(); @@ -471,14 +477,13 @@ impl SpircTask { MessageType::kMessageTypeVolume => { self.device.set_volume(frame.get_volume()); - self.mixer.set_volume(volume_to_mixer(frame.get_volume() as u16)); + self.mixer + .set_volume(volume_to_mixer(frame.get_volume() as u16)); self.notify(None); } MessageType::kMessageTypeNotify => { - if self.device.get_is_active() && - frame.get_device_state().get_is_active() - { + if self.device.get_is_active() && frame.get_device_state().get_is_active() { self.device.set_is_active(false); self.state.set_status(PlayStatus::kPlayStatusStop); self.player.stop(); From 234958672f4ae232eacdb42a10a6c519cb86a963 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Mon, 12 Feb 2018 14:48:39 +0100 Subject: [PATCH 55/70] Implement [replace] for rust-crypto --- Cargo.toml | 5 ++++- audio/Cargo.toml | 2 +- connect/Cargo.toml | 2 +- core/Cargo.toml | 2 +- 4 files changed, 7 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f3b88c3f..5d680896 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,7 +43,7 @@ num-bigint = "0.1.35" protobuf = "1.1" rand = "0.3.13" rpassword = "0.3.0" -rust-crypto = { git = "https://github.com/awmath/rust-crypto.git", branch = "avx2" } +rust-crypto = "0.2.36" serde = "0.9.6" serde_derive = "0.9.6" serde_json = "0.9.5" @@ -57,6 +57,9 @@ rand = "0.3.13" vergen = "0.1.0" protobuf_macros = { git = "https://github.com/plietar/rust-protobuf-macros", features = ["with-syntex"] } +[replace] +"rust-crypto:0.2.36" = { git = "https://github.com/awmath/rust-crypto.git", branch = "avx2" } + [features] alsa-backend = ["librespot-playback/alsa-backend"] portaudio-backend = ["librespot-playback/portaudio-backend"] diff --git a/audio/Cargo.toml b/audio/Cargo.toml index 48605669..2a9e134c 100644 --- a/audio/Cargo.toml +++ b/audio/Cargo.toml @@ -14,7 +14,7 @@ lewton = "0.8.0" log = "0.3.5" num-bigint = "0.1.35" num-traits = "0.1.36" -rust-crypto = { git = "https://github.com/awmath/rust-crypto.git", branch = "avx2" } +rust-crypto = "0.2.36" tempfile = "2.1" tremor = { git = "https://github.com/plietar/rust-tremor", optional = true } diff --git a/connect/Cargo.toml b/connect/Cargo.toml index a345401d..c529b616 100644 --- a/connect/Cargo.toml +++ b/connect/Cargo.toml @@ -19,7 +19,7 @@ log = "0.3.5" num-bigint = "0.1.35" protobuf = "1.1" rand = "0.3.13" -rust-crypto = { git = "https://github.com/awmath/rust-crypto.git", branch = "avx2" } +rust-crypto = "0.2.36" serde = "0.9.6" serde_derive = "0.9.6" serde_json = "0.9.5" diff --git a/core/Cargo.toml b/core/Cargo.toml index 86722f07..8bb36214 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -22,7 +22,7 @@ num-traits = "0.1.36" protobuf = "1.1" rand = "0.3.13" rpassword = "0.3.0" -rust-crypto = { git = "https://github.com/awmath/rust-crypto.git", branch = "avx2" } +rust-crypto = "0.2.36" serde = "0.9.6" serde_derive = "0.9.6" serde_json = "0.9.5" From e276d39704e15b49f80c34b23578b1a07c9563b6 Mon Sep 17 00:00:00 2001 From: Anton Voyl Date: Mon, 12 Feb 2018 15:58:09 +0100 Subject: [PATCH 56/70] core: remove protobuf_macros (#146) Fixes #129 --- Cargo.lock | 1 - core/Cargo.toml | 1 - core/build.rs | 8 ----- core/src/connection/handshake.rs | 51 ++++++++++++++++++-------------- core/src/connection/mod.rs | 37 ++++++++++++++--------- core/src/lib.in.rs | 2 -- core/src/lib.rs | 3 +- 7 files changed, 52 insertions(+), 51 deletions(-) delete mode 100644 core/src/lib.in.rs diff --git a/Cargo.lock b/Cargo.lock index 08433771..1441ac07 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -398,7 +398,6 @@ dependencies = [ "num-integer 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", - "protobuf_macros 0.6.0 (git+https://github.com/plietar/rust-protobuf-macros)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", diff --git a/core/Cargo.toml b/core/Cargo.toml index 8bb36214..f563f315 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -32,6 +32,5 @@ tokio-io = "0.1" uuid = { version = "0.4", features = ["v4"] } [build-dependencies] -protobuf_macros = { git = "https://github.com/plietar/rust-protobuf-macros", features = ["with-syntex"] } rand = "0.3.13" vergen = "0.1.0" diff --git a/core/build.rs b/core/build.rs index d57d57a9..0240a8fe 100644 --- a/core/build.rs +++ b/core/build.rs @@ -1,4 +1,3 @@ -extern crate protobuf_macros; extern crate rand; extern crate vergen; @@ -34,11 +33,4 @@ pub fn build_id() -> &'static str {{ if let Err(e) = version_file.write_all(build_id_fn.as_bytes()) { println!("{}", e); } - - protobuf_macros::expand("src/lib.in.rs", &out.join("lib.rs")).unwrap(); - - println!("cargo:rerun-if-changed=src/lib.in.rs"); - println!("cargo:rerun-if-changed=src/connection/mod.rs"); - println!("cargo:rerun-if-changed=src/connection/codec.rs"); - println!("cargo:rerun-if-changed=src/connection/handshake.rs"); } diff --git a/core/src/connection/handshake.rs b/core/src/connection/handshake.rs index c47364b4..db945162 100644 --- a/core/src/connection/handshake.rs +++ b/core/src/connection/handshake.rs @@ -82,22 +82,27 @@ impl Future for Handshake { } fn client_hello(connection: T, gc: Vec) -> WriteAll> { - let packet = protobuf_init!(ClientHello::new(), { - build_info => { - product: protocol::keyexchange::Product::PRODUCT_PARTNER, - platform: protocol::keyexchange::Platform::PLATFORM_LINUX_X86, - version: 0x10800000000, - }, - cryptosuites_supported => [ - protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON, - ], - login_crypto_hello.diffie_hellman => { - gc: gc, - server_keys_known: 1, - }, - client_nonce: util::rand_vec(&mut thread_rng(), 0x10), - padding: vec![0x1e], - }); + let mut packet = ClientHello::new(); + packet + .mut_build_info() + .set_product(protocol::keyexchange::Product::PRODUCT_PARTNER); + packet + .mut_build_info() + .set_platform(protocol::keyexchange::Platform::PLATFORM_LINUX_X86); + packet.mut_build_info().set_version(0x10800000000); + packet + .mut_cryptosuites_supported() + .push(protocol::keyexchange::Cryptosuite::CRYPTO_SUITE_SHANNON); + packet + .mut_login_crypto_hello() + .mut_diffie_hellman() + .set_gc(gc); + packet + .mut_login_crypto_hello() + .mut_diffie_hellman() + .set_server_keys_known(1); + packet.set_client_nonce(util::rand_vec(&mut thread_rng(), 0x10)); + packet.set_padding(vec![0x1e]); let mut buffer = vec![0, 4]; let size = 2 + 4 + packet.compute_size(); @@ -108,13 +113,13 @@ fn client_hello(connection: T, gc: Vec) -> WriteAll(connection: T, challenge: Vec) -> WriteAll> { - let packet = protobuf_init!(ClientResponsePlaintext::new(), { - login_crypto_response.diffie_hellman => { - hmac: challenge - }, - pow_response => {}, - crypto_response => {}, - }); + let mut packet = ClientResponsePlaintext::new(); + packet + .mut_login_crypto_response() + .mut_diffie_hellman() + .set_hmac(challenge); + packet.mut_pow_response(); + packet.mut_crypto_response(); let mut buffer = vec![]; let size = 4 + packet.compute_size(); diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index fae4092a..7d365f6e 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -35,20 +35,29 @@ pub fn authenticate( ) -> Box> { use protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os}; - let packet = protobuf_init!(ClientResponseEncrypted::new(), { - login_credentials => { - username: credentials.username, - typ: credentials.auth_type, - auth_data: credentials.auth_data, - }, - system_info => { - cpu_family: CpuFamily::CPU_UNKNOWN, - os: Os::OS_UNKNOWN, - system_information_string: format!("librespot_{}_{}", version::short_sha(), version::build_id()), - device_id: device_id, - }, - version_string: version::version_string(), - }); + let mut packet = ClientResponseEncrypted::new(); + packet + .mut_login_credentials() + .set_username(credentials.username); + packet + .mut_login_credentials() + .set_typ(credentials.auth_type); + packet + .mut_login_credentials() + .set_auth_data(credentials.auth_data); + packet + .mut_system_info() + .set_cpu_family(CpuFamily::CPU_UNKNOWN); + packet.mut_system_info().set_os(Os::OS_UNKNOWN); + packet + .mut_system_info() + .set_system_information_string(format!( + "librespot_{}_{}", + version::short_sha(), + version::build_id() + )); + packet.mut_system_info().set_device_id(device_id); + packet.set_version_string(version::version_string()); let cmd = 0xab; let data = packet.write_to_bytes().unwrap(); diff --git a/core/src/lib.in.rs b/core/src/lib.in.rs deleted file mode 100644 index cd8fbdaf..00000000 --- a/core/src/lib.in.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[allow(unused_mut)] -mod connection; diff --git a/core/src/lib.rs b/core/src/lib.rs index 4cc44448..207c7656 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -39,11 +39,10 @@ pub mod authentication; pub mod cache; pub mod channel; pub mod config; +mod connection; pub mod diffie_hellman; pub mod keymaster; pub mod mercury; pub mod session; pub mod util; pub mod version; - -include!(concat!(env!("OUT_DIR"), "/lib.rs")); From 13241496abaad09e9b9f1124c8d05cdb1fda6ef1 Mon Sep 17 00:00:00 2001 From: awiouy Date: Mon, 12 Feb 2018 20:09:59 +0100 Subject: [PATCH 57/70] Cargo.lock --- Cargo.lock | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1441ac07..54be236b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -327,7 +327,7 @@ dependencies = [ "protobuf_macros 0.6.0 (git+https://github.com/plietar/rust-protobuf-macros)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -350,7 +350,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tremor 0.1.0 (git+https://github.com/plietar/rust-tremor)", "vorbis 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -373,7 +373,7 @@ dependencies = [ "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf_macros 0.6.0 (git+https://github.com/plietar/rust-protobuf-macros)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -400,7 +400,7 @@ dependencies = [ "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -737,6 +737,12 @@ dependencies = [ "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +replace = "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)" + [[package]] name = "rustc-serialize" version = "0.3.24" @@ -1245,6 +1251,7 @@ dependencies = [ "checksum relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f301bafeb60867c85170031bdb2fcf24c8041f33aee09e7b116a58d4e9f781c5" "checksum rpassword 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ec4bdede957362ec6fdd550f7e79c6d14cad2bc26b2d062786234c6ee0cb27bb" "checksum rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)" = "" +"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" From 0fd398e34db561a96a64958e7561f2e0f4981d49 Mon Sep 17 00:00:00 2001 From: awiouy Date: Mon, 12 Feb 2018 20:10:36 +0100 Subject: [PATCH 58/70] core API: SessionData --- core/src/session.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/session.rs b/core/src/session.rs index 628e0377..a702f191 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -19,7 +19,7 @@ use audio_key::AudioKeyManager; use channel::ChannelManager; use mercury::MercuryManager; -pub struct SessionData { +struct SessionData { country: String, canonical_username: String, } From aed4fe32d855be0ac6f0d709d725d6ea08043f11 Mon Sep 17 00:00:00 2001 From: awiouy Date: Mon, 12 Feb 2018 20:13:37 +0100 Subject: [PATCH 59/70] core API: SessionInternal --- core/src/session.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/session.rs b/core/src/session.rs index a702f191..cb210a0f 100644 --- a/core/src/session.rs +++ b/core/src/session.rs @@ -24,7 +24,7 @@ struct SessionData { canonical_username: String, } -pub struct SessionInternal { +struct SessionInternal { config: SessionConfig, data: RwLock, @@ -43,7 +43,7 @@ pub struct SessionInternal { static SESSION_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT; #[derive(Clone)] -pub struct Session(pub Arc); +pub struct Session(Arc); pub fn device_id(name: &str) -> String { let mut h = Sha1::new(); @@ -226,7 +226,7 @@ impl Session { } #[derive(Clone)] -pub struct SessionWeak(pub Weak); +pub struct SessionWeak(Weak); impl SessionWeak { fn try_upgrade(&self) -> Option { From 6a9084b00c83268e6389a2359e10f1dbc05c620e Mon Sep 17 00:00:00 2001 From: awiouy Date: Mon, 12 Feb 2018 20:20:43 +0100 Subject: [PATCH 60/70] core API: Lazy --- core/src/component.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/component.rs b/core/src/component.rs index 923e72ec..29aef1bf 100644 --- a/core/src/component.rs +++ b/core/src/component.rs @@ -39,17 +39,17 @@ macro_rules! component { use std::cell::UnsafeCell; use std::sync::Mutex; -pub struct Lazy(Mutex, UnsafeCell>); +pub(crate) struct Lazy(Mutex, UnsafeCell>); unsafe impl Sync for Lazy {} unsafe impl Send for Lazy {} #[cfg_attr(feature = "cargo-clippy", allow(mutex_atomic))] impl Lazy { - pub fn new() -> Lazy { + pub(crate) fn new() -> Lazy { Lazy(Mutex::new(false), UnsafeCell::new(None)) } - pub fn get T>(&self, f: F) -> &T { + pub(crate) fn get T>(&self, f: F) -> &T { let mut inner = self.0.lock().unwrap(); if !*inner { unsafe { From 7dd5a40d21d3d1e2c0bf3b04da22f4b044594db0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Paul=20Li=C3=A9tar?= Date: Tue, 13 Feb 2018 02:07:28 +0100 Subject: [PATCH 61/70] travis: Use `cargo --locked` everywhere This will prevent `Cargo.lock` from getting out of sync --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index b1c30b25..474ff039 100644 --- a/.travis.yml +++ b/.travis.yml @@ -26,13 +26,13 @@ before_script: fi script: - - cargo build --no-default-features - - cargo build --no-default-features --features "with-tremor" - - cargo build --no-default-features --features "with-vorbis" - - cargo build --no-default-features --features "portaudio-backend" - - cargo build --no-default-features --features "pulseaudio-backend" - - cargo build --no-default-features --features "alsa-backend" - - cargo build --no-default-features --target armv7-unknown-linux-gnueabihf + - cargo build --locked --no-default-features + - cargo build --locked --no-default-features --features "with-tremor" + - cargo build --locked --no-default-features --features "with-vorbis" + - cargo build --locked --no-default-features --features "portaudio-backend" + - cargo build --locked --no-default-features --features "pulseaudio-backend" + - cargo build --locked --no-default-features --features "alsa-backend" + - cargo build --locked --no-default-features --target armv7-unknown-linux-gnueabihf notifications: email: false From 60996d108e0d33328174731ee5e710daeb9e1210 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Tue, 13 Feb 2018 02:35:59 +0100 Subject: [PATCH 62/70] Update device usage instructions --- src/main.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 944334d5..b1f68512 100644 --- a/src/main.rs +++ b/src/main.rs @@ -99,7 +99,7 @@ fn setup(args: &[String]) -> Setup { .optopt("p", "password", "Password", "PASSWORD") .optflag("", "disable-discovery", "Disable discovery mode") .optopt("", "backend", "Audio backend to use. Use '?' to list options", "BACKEND") - .optopt("", "device", "Audio device to use. Use '?' to list options", "DEVICE") + .optopt("", "device", "Audio device to use. Use '?' to list options if using portaudio", "DEVICE") .optopt("", "mixer", "Mixer to use", "MIXER") .optopt("", "initial-volume", "Initial volume in %, once connected (must be from 0 to 100)", "VOLUME") .optopt("", "zeroconf-port", "The port the internal server advertised over zeroconf uses.", "ZEROCONF_PORT"); From 4c2b641cadb4adcf1b15ac03e2d94f394c4f135a Mon Sep 17 00:00:00 2001 From: awiouy Date: Mon, 12 Feb 2018 21:02:27 +0100 Subject: [PATCH 63/70] core API: move spotify_id to lib.rs --- audio/src/fetch.rs | 4 +- connect/src/spirc.rs | 3 +- core/src/audio_key.rs | 2 +- core/src/cache.rs | 2 +- core/src/lib.rs | 1 + core/src/{util => }/spotify_id.rs | 0 core/src/util/mod.rs | 2 - examples/play.rs | 2 +- metadata/src/cover.rs | 2 +- metadata/src/lib.rs | 116 +++++++++++++++--------------- playback/src/player.rs | 2 +- 11 files changed, 67 insertions(+), 69 deletions(-) rename core/src/{util => }/spotify_id.rs (100%) diff --git a/audio/src/fetch.rs b/audio/src/fetch.rs index f9bd11a9..1455f21b 100644 --- a/audio/src/fetch.rs +++ b/audio/src/fetch.rs @@ -11,7 +11,7 @@ use tempfile::NamedTempFile; use core::channel::{Channel, ChannelData, ChannelError, ChannelHeaders}; use core::session::Session; -use core::util::FileId; +use core::spotify_id::FileId; const CHUNK_SIZE: usize = 0x20000; @@ -115,7 +115,7 @@ impl Future for AudioFileOpenStreaming { if id == 0x3 { let size = BigEndian::read_u32(&data) as usize * 4; let file = self.finish(size); - + return Ok(Async::Ready(file)); } } diff --git a/connect/src/spirc.rs b/connect/src/spirc.rs index 704472d7..2b88249c 100644 --- a/connect/src/spirc.rs +++ b/connect/src/spirc.rs @@ -6,7 +6,8 @@ use protobuf::{self, Message}; use core::config::ConnectConfig; use core::mercury::MercuryError; use core::session::Session; -use core::util::{SeqGenerator, SpotifyId}; +use core::spotify_id::SpotifyId; +use core::util::SeqGenerator; use core::version; use protocol; diff --git a/core/src/audio_key.rs b/core/src/audio_key.rs index 2d4fb2ab..021b1dc8 100644 --- a/core/src/audio_key.rs +++ b/core/src/audio_key.rs @@ -5,7 +5,7 @@ use futures::sync::oneshot; use std::collections::HashMap; use std::io::Write; -use util::{FileId, SpotifyId}; +use spotify_id::{FileId, SpotifyId}; use util::SeqGenerator; #[derive(Debug, Hash, PartialEq, Eq, Copy, Clone)] diff --git a/core/src/cache.rs b/core/src/cache.rs index fb59c729..a5f89d5e 100644 --- a/core/src/cache.rs +++ b/core/src/cache.rs @@ -6,7 +6,7 @@ use std::path::Path; use std::path::PathBuf; use authentication::Credentials; -use util::FileId; +use spotify_id::FileId; #[derive(Clone)] pub struct Cache { diff --git a/core/src/lib.rs b/core/src/lib.rs index 207c7656..3c9be131 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -44,5 +44,6 @@ pub mod diffie_hellman; pub mod keymaster; pub mod mercury; pub mod session; +pub mod spotify_id; pub mod util; pub mod version; diff --git a/core/src/util/spotify_id.rs b/core/src/spotify_id.rs similarity index 100% rename from core/src/util/spotify_id.rs rename to core/src/spotify_id.rs diff --git a/core/src/util/mod.rs b/core/src/util/mod.rs index 66f2fe3f..32b058ad 100644 --- a/core/src/util/mod.rs +++ b/core/src/util/mod.rs @@ -6,10 +6,8 @@ use std::mem; use std::ops::{Mul, Rem, Shr}; mod int128; -mod spotify_id; pub use util::int128::u128; -pub use util::spotify_id::{FileId, SpotifyId}; pub fn rand_vec(rng: &mut G, size: usize) -> Vec { rng.gen_iter().take(size).collect() diff --git a/examples/play.rs b/examples/play.rs index 8c88ddbe..2c0b3282 100644 --- a/examples/play.rs +++ b/examples/play.rs @@ -7,7 +7,7 @@ use tokio_core::reactor::Core; use librespot::core::authentication::Credentials; use librespot::playback::config::{PlayerConfig, SessionConfig}; use librespot::core::session::Session; -use librespot::core::util::SpotifyId; +use librespot::core::spotify_id::SpotifyId; use librespot::audio_backend; use librespot::player::Player; diff --git a/metadata/src/cover.rs b/metadata/src/cover.rs index ea3c197b..0ef186a0 100644 --- a/metadata/src/cover.rs +++ b/metadata/src/cover.rs @@ -3,7 +3,7 @@ use std::io::Write; use core::channel::ChannelData; use core::session::Session; -use core::util::FileId; +use core::spotify_id::FileId; pub fn get(session: &Session, file: FileId) -> ChannelData { let (channel_id, channel) = session.channel().allocate(); diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index 2439ded6..664d9a22 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -13,7 +13,8 @@ use linear_map::LinearMap; use core::mercury::MercuryError; use core::session::Session; -use core::util::{SpotifyId, FileId, StrChunksExt}; +use core::spotify_id::{FileId, SpotifyId}; +use core::util::StrChunksExt; pub use protocol::metadata::AudioFile_Format as FileFormat; @@ -22,7 +23,8 @@ fn countrylist_contains(list: &str, country: &str) -> bool { } fn parse_restrictions<'s, I>(restrictions: I, country: &str, catalogue: &str) -> bool - where I: IntoIterator +where + I: IntoIterator, { let mut forbidden = "".to_string(); let mut has_forbidden = false; @@ -30,9 +32,9 @@ fn parse_restrictions<'s, I>(restrictions: I, country: &str, catalogue: &str) -> let mut allowed = "".to_string(); let mut has_allowed = false; - let rs = restrictions.into_iter().filter(|r| - r.get_catalogue_str().contains(&catalogue.to_owned()) - ); + let rs = restrictions + .into_iter() + .filter(|r| r.get_catalogue_str().contains(&catalogue.to_owned())); for r in rs { if r.has_countries_forbidden() { @@ -46,12 +48,12 @@ fn parse_restrictions<'s, I>(restrictions: I, country: &str, catalogue: &str) -> } } - (has_forbidden || has_allowed) && - (!has_forbidden || !countrylist_contains(forbidden.as_str(), country)) && - (!has_allowed || countrylist_contains(allowed.as_str(), country)) + (has_forbidden || has_allowed) + && (!has_forbidden || !countrylist_contains(forbidden.as_str(), country)) + && (!has_allowed || countrylist_contains(allowed.as_str(), country)) } -pub trait Metadata : Send + Sized + 'static { +pub trait Metadata: Send + Sized + 'static { type Message: protobuf::MessageStatic; fn base_url() -> &'static str; @@ -110,20 +112,20 @@ impl Metadata for Track { let country = session.country(); let artists = msg.get_artist() - .iter() - .filter(|artist| artist.has_gid()) - .map(|artist| SpotifyId::from_raw(artist.get_gid())) - .collect::>(); + .iter() + .filter(|artist| artist.has_gid()) + .map(|artist| SpotifyId::from_raw(artist.get_gid())) + .collect::>(); let files = msg.get_file() - .iter() - .filter(|file| file.has_file_id()) - .map(|file| { - let mut dst = [0u8; 20]; - dst.clone_from_slice(file.get_file_id()); - (file.get_format(), FileId(dst)) - }) - .collect(); + .iter() + .filter(|file| file.has_file_id()) + .map(|file| { + let mut dst = [0u8; 20]; + dst.clone_from_slice(file.get_file_id()); + (file.get_format(), FileId(dst)) + }) + .collect(); Track { id: SpotifyId::from_raw(msg.get_gid()), @@ -133,12 +135,10 @@ impl Metadata for Track { artists: artists, files: files, alternatives: msg.get_alternative() - .iter() - .map(|alt| SpotifyId::from_raw(alt.get_gid())) - .collect(), - available: parse_restrictions(msg.get_restriction(), - &country, - "premium"), + .iter() + .map(|alt| SpotifyId::from_raw(alt.get_gid())) + .collect(), + available: parse_restrictions(msg.get_restriction(), &country, "premium"), } } } @@ -152,28 +152,28 @@ impl Metadata for Album { fn parse(msg: &Self::Message, _: &Session) -> Self { let artists = msg.get_artist() - .iter() - .filter(|artist| artist.has_gid()) - .map(|artist| SpotifyId::from_raw(artist.get_gid())) - .collect::>(); + .iter() + .filter(|artist| artist.has_gid()) + .map(|artist| SpotifyId::from_raw(artist.get_gid())) + .collect::>(); let tracks = msg.get_disc() - .iter() - .flat_map(|disc| disc.get_track()) - .filter(|track| track.has_gid()) - .map(|track| SpotifyId::from_raw(track.get_gid())) - .collect::>(); + .iter() + .flat_map(|disc| disc.get_track()) + .filter(|track| track.has_gid()) + .map(|track| SpotifyId::from_raw(track.get_gid())) + .collect::>(); let covers = msg.get_cover_group() - .get_image() - .iter() - .filter(|image| image.has_file_id()) - .map(|image| { - let mut dst = [0u8; 20]; - dst.clone_from_slice(image.get_file_id()); - FileId(dst) - }) - .collect::>(); + .get_image() + .iter() + .filter(|image| image.has_file_id()) + .map(|image| { + let mut dst = [0u8; 20]; + dst.clone_from_slice(image.get_file_id()); + FileId(dst) + }) + .collect::>(); Album { id: SpotifyId::from_raw(msg.get_gid()), @@ -185,7 +185,6 @@ impl Metadata for Album { } } - impl Metadata for Artist { type Message = protocol::metadata::Artist; @@ -197,23 +196,22 @@ impl Metadata for Artist { let country = session.country(); let top_tracks: Vec = match msg.get_top_track() - .iter() - .find(|tt| !tt.has_country() || countrylist_contains(tt.get_country(), &country)) { - Some(tracks) => { - tracks.get_track() - .iter() - .filter(|track| track.has_gid()) - .map(|track| SpotifyId::from_raw(track.get_gid())) - .collect::>() - }, - None => Vec::new() - }; - + .iter() + .find(|tt| !tt.has_country() || countrylist_contains(tt.get_country(), &country)) + { + Some(tracks) => tracks + .get_track() + .iter() + .filter(|track| track.has_gid()) + .map(|track| SpotifyId::from_raw(track.get_gid())) + .collect::>(), + None => Vec::new(), + }; Artist { id: SpotifyId::from_raw(msg.get_gid()), name: msg.get_name().to_owned(), - top_tracks: top_tracks + top_tracks: top_tracks, } } } diff --git a/playback/src/player.rs b/playback/src/player.rs index 48f7f307..e5497365 100644 --- a/playback/src/player.rs +++ b/playback/src/player.rs @@ -11,7 +11,7 @@ use std::time::Duration; use config::{Bitrate, PlayerConfig}; use core::session::Session; -use core::util::SpotifyId; +use core::spotify_id::SpotifyId; use audio_backend::Sink; use audio::{AudioFile, AudioDecrypt}; From ea597361ff4617a1bb2b7390574b447ccbf26c7b Mon Sep 17 00:00:00 2001 From: awiouy Date: Tue, 13 Feb 2018 08:18:49 +0100 Subject: [PATCH 64/70] core API: component.new() --- core/src/component.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/component.rs b/core/src/component.rs index 29aef1bf..50ab7b37 100644 --- a/core/src/component.rs +++ b/core/src/component.rs @@ -4,7 +4,7 @@ macro_rules! component { pub struct $name(::std::sync::Arc<($crate::session::SessionWeak, ::std::sync::Mutex<$inner>)>); impl $name { #[allow(dead_code)] - pub fn new(session: $crate::session::SessionWeak) -> $name { + pub(crate) fn new(session: $crate::session::SessionWeak) -> $name { debug!(target:"librespot::component", "new {}", stringify!($name)); $name(::std::sync::Arc::new((session, ::std::sync::Mutex::new($inner { From 0ed4fb1c68e1d682039b9899d6a4bd1e824c69b4 Mon Sep 17 00:00:00 2001 From: awiouy Date: Tue, 13 Feb 2018 08:24:59 +0100 Subject: [PATCH 65/70] core API: MercuryManager.request() --- core/src/mercury/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/src/mercury/mod.rs b/core/src/mercury/mod.rs index 9a607061..e79c281f 100644 --- a/core/src/mercury/mod.rs +++ b/core/src/mercury/mod.rs @@ -51,7 +51,7 @@ impl MercuryManager { seq } - pub fn request(&self, req: MercuryRequest) -> MercuryFuture { + fn request(&self, req: MercuryRequest) -> MercuryFuture { let (tx, rx) = oneshot::channel(); let pending = MercuryPending { From edbe00c62b610d4b84c811a8efce105c3d01422e Mon Sep 17 00:00:00 2001 From: awiouy Date: Tue, 13 Feb 2018 08:33:50 +0100 Subject: [PATCH 66/70] core API: move StrChunks* to metadata --- core/src/util/mod.rs | 26 -------------------------- metadata/src/lib.rs | 27 ++++++++++++++++++++++++++- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/core/src/util/mod.rs b/core/src/util/mod.rs index 32b058ad..9c373eaa 100644 --- a/core/src/util/mod.rs +++ b/core/src/util/mod.rs @@ -29,32 +29,6 @@ pub fn powm(base: &BigUint, exp: &BigUint, modulus: &BigUint) -> BigUint { result } -pub struct StrChunks<'s>(&'s str, usize); - -pub trait StrChunksExt { - fn chunks(&self, size: usize) -> StrChunks; -} - -impl StrChunksExt for str { - fn chunks(&self, size: usize) -> StrChunks { - StrChunks(self, size) - } -} - -impl<'s> Iterator for StrChunks<'s> { - type Item = &'s str; - fn next(&mut self) -> Option<&'s str> { - let &mut StrChunks(data, size) = self; - if data.is_empty() { - None - } else { - let ret = Some(&data[..size]); - self.0 = &data[size..]; - ret - } - } -} - pub trait ReadSeek: ::std::io::Read + ::std::io::Seek {} impl ReadSeek for T {} diff --git a/metadata/src/lib.rs b/metadata/src/lib.rs index 664d9a22..0103a3b0 100644 --- a/metadata/src/lib.rs +++ b/metadata/src/lib.rs @@ -14,7 +14,6 @@ use linear_map::LinearMap; use core::mercury::MercuryError; use core::session::Session; use core::spotify_id::{FileId, SpotifyId}; -use core::util::StrChunksExt; pub use protocol::metadata::AudioFile_Format as FileFormat; @@ -215,3 +214,29 @@ impl Metadata for Artist { } } } + +struct StrChunks<'s>(&'s str, usize); + +trait StrChunksExt { + fn chunks(&self, size: usize) -> StrChunks; +} + +impl StrChunksExt for str { + fn chunks(&self, size: usize) -> StrChunks { + StrChunks(self, size) + } +} + +impl<'s> Iterator for StrChunks<'s> { + type Item = &'s str; + fn next(&mut self) -> Option<&'s str> { + let &mut StrChunks(data, size) = self; + if data.is_empty() { + None + } else { + let ret = Some(&data[..size]); + self.0 = &data[size..]; + ret + } + } +} From a427c8316b39b806ea70ee795265de48e98dac68 Mon Sep 17 00:00:00 2001 From: awiouy Date: Tue, 13 Feb 2018 08:34:52 +0100 Subject: [PATCH 67/70] metadata.rs is empty --- metadata/src/metadata.rs | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 metadata/src/metadata.rs diff --git a/metadata/src/metadata.rs b/metadata/src/metadata.rs deleted file mode 100644 index e69de29b..00000000 From 67dabcdd8e1d63ed5de851ac8ae4022ae23df700 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Tue, 13 Feb 2018 14:02:37 +0100 Subject: [PATCH 68/70] Enable backtrace on all builds --- Cargo.lock | 15 +++++++++++---- src/main.rs | 1 + 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1441ac07..54be236b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -327,7 +327,7 @@ dependencies = [ "protobuf_macros 0.6.0 (git+https://github.com/plietar/rust-protobuf-macros)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -350,7 +350,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tremor 0.1.0 (git+https://github.com/plietar/rust-tremor)", "vorbis 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -373,7 +373,7 @@ dependencies = [ "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf_macros 0.6.0 (git+https://github.com/plietar/rust-protobuf-macros)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -400,7 +400,7 @@ dependencies = [ "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -737,6 +737,12 @@ dependencies = [ "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +replace = "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)" + [[package]] name = "rustc-serialize" version = "0.3.24" @@ -1245,6 +1251,7 @@ dependencies = [ "checksum relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f301bafeb60867c85170031bdb2fcf24c8041f33aee09e7b116a58d4e9f781c5" "checksum rpassword 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ec4bdede957362ec6fdd550f7e79c6d14cad2bc26b2d062786234c6ee0cb27bb" "checksum rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)" = "" +"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" diff --git a/src/main.rs b/src/main.rs index b1f68512..9c6e136a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -355,6 +355,7 @@ impl Future for Main { } fn main() { + env::set_var("RUST_BACKTRACE", "full"); let mut core = Core::new().unwrap(); let handle = core.handle(); From 6936825783a73a9f77ed8f2d046d34aa1b7ca63f Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Tue, 13 Feb 2018 15:29:01 +0100 Subject: [PATCH 69/70] [ci skip] Accidentally deleted commit --- Cargo.lock | 15 +++++++++++---- core/src/connection/mod.rs | 7 ++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 1441ac07..54be236b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -327,7 +327,7 @@ dependencies = [ "protobuf_macros 0.6.0 (git+https://github.com/plietar/rust-protobuf-macros)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -350,7 +350,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.1.41 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "tempfile 2.2.0 (registry+https://github.com/rust-lang/crates.io-index)", "tremor 0.1.0 (git+https://github.com/plietar/rust-tremor)", "vorbis 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -373,7 +373,7 @@ dependencies = [ "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "protobuf_macros 0.6.0 (git+https://github.com/plietar/rust-protobuf-macros)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -400,7 +400,7 @@ dependencies = [ "protobuf 1.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.3.20 (registry+https://github.com/rust-lang/crates.io-index)", "rpassword 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)", + "rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)", "serde 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_derive 0.9.15 (registry+https://github.com/rust-lang/crates.io-index)", "serde_json 0.9.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -737,6 +737,12 @@ dependencies = [ "time 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "rust-crypto" +version = "0.2.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +replace = "rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)" + [[package]] name = "rustc-serialize" version = "0.3.24" @@ -1245,6 +1251,7 @@ dependencies = [ "checksum relay 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f301bafeb60867c85170031bdb2fcf24c8041f33aee09e7b116a58d4e9f781c5" "checksum rpassword 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ec4bdede957362ec6fdd550f7e79c6d14cad2bc26b2d062786234c6ee0cb27bb" "checksum rust-crypto 0.2.36 (git+https://github.com/awmath/rust-crypto.git?branch=avx2)" = "" +"checksum rust-crypto 0.2.36 (registry+https://github.com/rust-lang/crates.io-index)" = "f76d05d3993fd5f4af9434e8e436db163a12a9d40e1a58a726f27a01dfd12a2a" "checksum rustc-serialize 0.3.24 (registry+https://github.com/rust-lang/crates.io-index)" = "dcf128d1287d2ea9d80910b5f1120d0b8eede3fbf1abe91c40d39ea7d51e6fda" "checksum safemem 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e27a8b19b835f7aea908818e871f5cc3a5a186550c30773be987e155e8163d8f" "checksum scoped-tls 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f417c22df063e9450888a7561788e9bd46d3bb3c1466435b4eccb903807f147d" diff --git a/core/src/connection/mod.rs b/core/src/connection/mod.rs index 7d365f6e..172339c3 100644 --- a/core/src/connection/mod.rs +++ b/core/src/connection/mod.rs @@ -34,6 +34,7 @@ pub fn authenticate( device_id: String, ) -> Box> { use protocol::authentication::{APWelcome, ClientResponseEncrypted, CpuFamily, Os}; + use protocol::keyexchange::APLoginFailed; let mut packet = ClientResponseEncrypted::new(); packet @@ -79,7 +80,11 @@ pub fn authenticate( Ok((transport, reusable_credentials)) } - Some((0xad, _)) => panic!("Authentication failed"), + Some((0xad, data)) => { + let error_data: APLoginFailed = protobuf::parse_from_bytes(data.as_ref()).unwrap(); + panic!("Authentication failed with reason: {:?}", error_data.get_error_code()) + } + Some((cmd, _)) => panic!("Unexpected packet {:?}", cmd), None => panic!("EOF"), }), From 17d39dffa902520165f919eb3bdd760f5ecb0b36 Mon Sep 17 00:00:00 2001 From: Sasha Hilton Date: Tue, 13 Feb 2018 16:46:10 +0100 Subject: [PATCH 70/70] Make backtrace var conditional --- src/main.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 9c6e136a..01c34421 100644 --- a/src/main.rs +++ b/src/main.rs @@ -355,7 +355,9 @@ impl Future for Main { } fn main() { - env::set_var("RUST_BACKTRACE", "full"); + if env::var("RUST_BACKTRACE").is_err() { + env::set_var("RUST_BACKTRACE", "full") + } let mut core = Core::new().unwrap(); let handle = core.handle();