Add simple playback example.

This commit is contained in:
Paul Lietar 2017-04-28 23:24:55 +01:00
parent d95c0b3fcd
commit 294a7821d6
8 changed files with 81 additions and 11 deletions

10
Cargo.lock generated
View file

@ -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"

View file

@ -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
examples/play.rs Normal file
View file

@ -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");
}

View file

@ -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)

View file

@ -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;

View file

@ -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();
}

View file

@ -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,

View file

@ -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());