Browse Source

Add simple playback example.

Paul Lietar 8 years ago
parent
commit
294a7821d6
8 changed files with 81 additions and 11 deletions
  1. 10 0
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 40 0
      examples/play.rs
  4. 2 2
      src/audio_backend/mod.rs
  5. 1 0
      src/lib.rs
  6. 11 6
      src/main.rs
  7. 15 1
      src/session.rs
  8. 1 2
      src/spirc.rs

+ 10 - 0
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"

+ 1 - 0
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"

+ 40 - 0
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");
+}

+ 2 - 2
src/audio_backend/mod.rs

@@ -85,8 +85,8 @@ declare_backends! {
     ];
 }
 
-pub fn find<T: AsRef<str>>(name: Option<T>) -> Option<fn(Option<String>) -> Box<Sink>> {
-    if let Some(name) = name.as_ref().map(AsRef::as_ref) {
+pub fn find(name: Option<String>) -> Option<fn(Option<String>) -> Box<Sink>> {
+    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)

+ 1 - 0
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;
 

+ 11 - 6
src/main.rs

@@ -73,6 +73,7 @@ struct Setup {
 
     mixer: fn() -> Box<Mixer>,
 
+    name: String,
     cache: Option<Cache>,
     config: Config,
     credentials: Option<Credentials>,
@@ -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<Cache>,
     config: Config,
     backend: fn(Option<String>) -> Box<Sink>,
@@ -184,6 +186,7 @@ struct Main {
 
 impl Main {
     fn new(handle: Handle,
+           name: String,
            config: Config,
            cache: Option<Cache>,
            backend: fn(Option<String>) -> Box<Sink>,
@@ -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<String> = 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();
     }

+ 15 - 1
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<String>,
     pub onstop: Option<String>,
 }
 
+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,

+ 1 - 2
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<Mixer>)
+    pub fn new(name: String, session: Session, player: Player, mixer: Box<Mixer>)
         -> (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());