From 294a7821d682d9f694d26feabc67048f343c7a56 Mon Sep 17 00:00:00 2001 From: Paul Lietar Date: Fri, 28 Apr 2017 23:24:55 +0100 Subject: [PATCH] Add simple playback example. --- Cargo.lock | 10 ++++++++++ Cargo.toml | 1 + examples/play.rs | 40 ++++++++++++++++++++++++++++++++++++++++ src/audio_backend/mod.rs | 4 ++-- src/lib.rs | 1 + src/main.rs | 17 +++++++++++------ src/session.rs | 16 +++++++++++++++- src/spirc.rs | 3 +-- 8 files changed, 81 insertions(+), 11 deletions(-) create mode 100644 examples/play.rs diff --git a/Cargo.lock b/Cargo.lock index 4341e82c..dee7016a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -36,6 +36,7 @@ dependencies = [ "tokio-signal 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "tremor 0.1.0 (git+https://github.com/plietar/rust-tremor)", "url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "vorbis 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -851,6 +852,14 @@ name = "utf8-ranges" version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "uuid" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "vergen" version = "0.1.1" @@ -1033,6 +1042,7 @@ dependencies = [ "checksum unreachable 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1f2ae5ddb18e1c92664717616dd9549dde73f539f01bd7b77c2edb2446bdff91" "checksum url 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f5ba8a749fb4479b043733416c244fa9d1d3af3d7c23804944651c8a448cb87e" "checksum utf8-ranges 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "662fab6525a98beff2921d7f61a39e7d59e0b425ebc7d0d9e66d316e55124122" +"checksum uuid 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7cfec50b0842181ba6e713151b72f4ec84a6a7e2c9c8a8a3ffc37bb1cd16b231" "checksum vergen 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "8c3365f36c57e5df714a34be40902b27a992eeddb9996eca52d0584611cf885d" "checksum void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" "checksum vorbis 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "760993e54524128b88d4d7aff09c773c2f16a9f18db3c8ae1ccca5afd1287656" diff --git a/Cargo.toml b/Cargo.toml index a9bb7da5..f47dd5c1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -59,6 +59,7 @@ futures = "0.1.8" tokio-core = "0.1.2" tokio-proto = "0.1.0" tokio-signal = "0.1" +uuid = { version = "0.4", features = ["v4"] } [build-dependencies] vergen = "0.1.0" diff --git a/examples/play.rs b/examples/play.rs new file mode 100644 index 00000000..0fccc1ff --- /dev/null +++ b/examples/play.rs @@ -0,0 +1,40 @@ +extern crate librespot; +extern crate tokio_core; + +use std::env; +use tokio_core::reactor::Core; + +use librespot::audio_backend; +use librespot::authentication::Credentials; +use librespot::player::Player; +use librespot::session::{Config, Session}; +use librespot::util::SpotifyId; + +fn main() { + let mut core = Core::new().unwrap(); + let handle = core.handle(); + + let config = Config::default(); + + let args : Vec<_> = env::args().collect(); + if args.len() != 4 { + println!("Usage: {} USERNAME PASSWORD TRACK", args[0]); + } + let username = args[1].to_owned(); + let password = args[2].to_owned(); + let credentials = Credentials::with_password(username, password); + + let track = SpotifyId::from_base62(&args[3]); + + let backend = audio_backend::find(None).unwrap(); + + println!("Connecting .."); + let session = core.run(Session::connect(config, credentials, None, handle)).unwrap(); + + let player = Player::new(session.clone(), None, move || (backend)(None)); + + println!("Playing..."); + core.run(player.load(track, true, 0)).unwrap(); + + println!("Done"); +} diff --git a/src/audio_backend/mod.rs b/src/audio_backend/mod.rs index 689379cf..c1e54a1b 100644 --- a/src/audio_backend/mod.rs +++ b/src/audio_backend/mod.rs @@ -85,8 +85,8 @@ declare_backends! { ]; } -pub fn find>(name: Option) -> Option) -> Box> { - if let Some(name) = name.as_ref().map(AsRef::as_ref) { +pub fn find(name: Option) -> Option) -> Box> { + if let Some(name) = name { BACKENDS.iter().find(|backend| name == backend.0).map(|backend| backend.1) } else { Some(BACKENDS.first().expect("No backends were enabled at build time").1) diff --git a/src/lib.rs b/src/lib.rs index 58e49322..8c4ead58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ extern crate tempfile; extern crate tokio_core; extern crate tokio_proto; extern crate url; +extern crate uuid; pub extern crate librespot_protocol as protocol; diff --git a/src/main.rs b/src/main.rs index ab446b7e..7f00d5e7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -73,6 +73,7 @@ struct Setup { mixer: fn() -> Box, + name: String, cache: Option, config: Config, credentials: Option, @@ -116,7 +117,7 @@ fn setup(args: &[String]) -> Setup { exit(0); } - let backend = audio_backend::find(backend_name.as_ref()) + let backend = audio_backend::find(backend_name) .expect("Invalid backend"); let mixer_name = matches.opt_str("mixer"); @@ -144,7 +145,6 @@ fn setup(args: &[String]) -> Setup { let config = Config { user_agent: version::version_string(), - name: name, device_id: device_id, bitrate: bitrate, onstart: matches.opt_str("onstart"), @@ -154,6 +154,7 @@ fn setup(args: &[String]) -> Setup { let device = matches.opt_str("device"); Setup { + name: name, backend: backend, cache: cache, config: config, @@ -165,6 +166,7 @@ fn setup(args: &[String]) -> Setup { } struct Main { + name: String, cache: Option, config: Config, backend: fn(Option) -> Box, @@ -184,6 +186,7 @@ struct Main { impl Main { fn new(handle: Handle, + name: String, config: Config, cache: Option, backend: fn(Option) -> Box, @@ -192,6 +195,7 @@ impl Main { { Main { handle: handle.clone(), + name: name, cache: cache, config: config, backend: backend, @@ -208,8 +212,9 @@ impl Main { } fn discovery(&mut self) { - let name = self.config.name.clone(); let device_id = self.config.device_id.clone(); + let name = self.name.clone(); + self.discovery = Some(discovery(&self.handle, name, device_id).unwrap()); } @@ -256,7 +261,7 @@ impl Future for Main { (backend)(device) }); - let (spirc, spirc_task) = Spirc::new(session, player, mixer); + let (spirc, spirc_task) = Spirc::new(self.name.clone(), session, player, mixer); self.spirc = Some(spirc); self.spirc_task = Some(spirc_task); @@ -298,9 +303,9 @@ fn main() { let handle = core.handle(); let args: Vec = std::env::args().collect(); - let Setup { backend, config, device, cache, enable_discovery, credentials, mixer } = setup(&args); + let Setup { name, backend, config, device, cache, enable_discovery, credentials, mixer } = setup(&args); - let mut task = Main::new(handle, config.clone(), cache, backend, device, mixer); + let mut task = Main::new(handle, name, config, cache, backend, device, mixer); if enable_discovery { task.discovery(); } diff --git a/src/session.rs b/src/session.rs index 452ef12d..028f041d 100644 --- a/src/session.rs +++ b/src/session.rs @@ -9,12 +9,14 @@ use std::sync::{RwLock, Arc, Weak}; use tokio_core::io::EasyBuf; use tokio_core::reactor::{Handle, Remote}; use std::sync::atomic::{AtomicUsize, ATOMIC_USIZE_INIT, Ordering}; +use uuid::Uuid; use apresolve::apresolve_or_fallback; use authentication::Credentials; use cache::Cache; use component::Lazy; use connection; +use version; use audio_key::AudioKeyManager; use channel::ChannelManager; @@ -43,13 +45,25 @@ impl FromStr for Bitrate { #[derive(Clone)] pub struct Config { pub user_agent: String, - pub name: String, pub device_id: String, pub bitrate: Bitrate, pub onstart: Option, pub onstop: Option, } +impl Default for Config { + fn default() -> Config { + let device_id = Uuid::new_v4().hyphenated().to_string(); + Config { + user_agent: version::version_string(), + device_id: device_id, + bitrate: Bitrate::Bitrate160, + onstart: None, + onstop: None, + } + } +} + pub struct SessionData { country: String, canonical_username: String, diff --git a/src/spirc.rs b/src/spirc.rs index 2e47c002..efbe6aec 100644 --- a/src/spirc.rs +++ b/src/spirc.rs @@ -118,13 +118,12 @@ fn initial_device_state(name: String, volume: u16) -> DeviceState { } impl Spirc { - pub fn new(session: Session, player: Player, mixer: Box) + pub fn new(name: String, session: Session, player: Player, mixer: Box) -> (Spirc, SpircTask) { debug!("new Spirc[{}]", session.session_id()); let ident = session.device_id().to_owned(); - let name = session.config().name.clone(); let uri = format!("hm://remote/user/{}", session.username());