Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ target
.cargo
spotify_appkey.key
.vagrant/
.settings/
.project
12 changes: 12 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -31,12 +31,14 @@ path = "protocol"

[dependencies]
base64 = "0.5.0"
cfg-if = "0.1.2"
dns-sd = { version = "~0.1.3", optional = true }
env_logger = "0.4.0"
futures = "0.1.8"
getopts = "0.2.14"
hyper = "0.11.2"
log = "0.3.5"
mdns = { git = "https://github.com/plietar/rust-mdns" }
mdns = { git = "https://github.com/plietar/rust-mdns", optional = true }
num-bigint = "0.1.35"
protobuf = "1.1"
rand = "0.3.13"
Expand Down Expand Up @@ -66,7 +68,10 @@ pulseaudio-backend = ["libpulse-sys"]
with-tremor = ["librespot-audio/with-tremor"]
with-lewton = ["librespot-audio/with-lewton"]

default = ["portaudio-backend"]
with-internal-mdns = ["mdns"]
with-external-mdns = ["dns-sd"]

default = ["portaudio-backend", "with-internal-mdns"]

[package.metadata.deb]
maintainer = "nobody"
Expand Down
5 changes: 5 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,11 @@ The following backends are currently available :
- PortAudio
- PulseAudio

## mdns - Internal or External
*librespot* allows for the use of external avahi mdns. Internal or External mdns can be specified at compile time using
`--feature "with-internal-mdns"` or `--feature "with-external-mdns"` respectively. The internal mdns is used by default if none is specified. Currently, it is not possible to build without mdns.
`libavahi-compat-libdnssd-dev` must be installed to compile with-external-mdns.

## Cross-compiling
A cross compilation environment is provided as a docker image.
Build the image from the root of the project with the following command :
Expand Down
3 changes: 3 additions & 0 deletions contrib/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#
# The resulting image can be used to build librespot for linux x86_64, armhf and armel.
# $ docker run -v /tmp/librespot-build:/build librespot-cross
# To build librespot with avahi support
# $ docker run -v /tmp/librespot-build:/build librespot-cross /src/contrib/docker-build-avahi.sh
#
# The compiled binaries will be located in /tmp/librespot-build
#
Expand All @@ -23,6 +25,7 @@ RUN apt-get update

RUN apt-get install -y curl git build-essential crossbuild-essential-arm64 crossbuild-essential-armel crossbuild-essential-armhf crossbuild-essential-mipsel
RUN apt-get install -y libasound2-dev libasound2-dev:arm64 libasound2-dev:armel libasound2-dev:armhf libasound2-dev:mipsel
RUN apt-get install -y libavahi-compat-libdnssd-dev libavahi-compat-libdnssd-dev:arm64 libavahi-compat-libdnssd-dev:armel libavahi-compat-libdnssd-dev:armhf libavahi-compat-libdnssd-dev:mipsel

RUN curl https://sh.rustup.rs -sSf | sh -s -- -y
ENV PATH="/root/.cargo/bin/:${PATH}"
Expand Down
24 changes: 24 additions & 0 deletions contrib/docker-build-avahi.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#!/usr/bin/env bash
set -eux

cargo build --release --no-default-features --features "alsa-backend with-external-mdns"
cp /usr/lib/x86_64-linux-gnu/libdns_sd.so.1 /build/release

export PKG_CONFIG_ALLOW_CROSS=0

export PKG_CONFIG_PATH=/usr/lib/aarch64-unknown-linux-gnu/pkgconfig
cargo build --release --target aarch64-unknown-linux-gnu --no-default-features --features "alsa-backend with-external-mdns"
cp /usr/lib/aarch64-linux-gnu/libdns_sd.so.1 /build/aarch64-unknown-linux-gnu/release

export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabi/pkgconfig
cargo build --release --target arm-unknown-linux-gnueabi --no-default-features --features "alsa-backend with-external-mdns"
cp /usr/lib/arm-linux-gnueabi/libdns_sd.so.1 /build/arm-unknown-linux-gnueabi/release

export PKG_CONFIG_PATH=/usr/lib/arm-linux-gnueabihf/pkgconfig
cargo build --release --target arm-unknown-linux-gnueabihf --no-default-features --features "alsa-backend with-external-mdns"
cp /usr/lib/arm-linux-gnueabihf/libdns_sd.so.1 /build/arm-unknown-linux-gnueabihf/release

export PKG_CONFIG_PATH=/usr/lib/mipsel-linux-gnu/pkgconfig
cargo build --release --target mipsel-unknown-linux-gnu --no-default-features --features "alsa-backend with-external-mdns"
cp /usr/libmipsel-linux-gnu/libdns_sd.so.1 /build/mipsel-unknown-linux-gnu/release

153 changes: 120 additions & 33 deletions src/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@ use futures::sync::mpsc;
use futures::{Future, Stream, BoxFuture, Poll, Async};
use hyper::server::{Service, NewService, Request, Response, Http};
use hyper::{self, Get, Post, StatusCode};
use mdns;
use num_bigint::BigUint;
use rand;
use std::collections::BTreeMap;
Expand All @@ -21,6 +20,16 @@ use core::authentication::Credentials;
use core::util;
use core::config::ConnectConfig;

cfg_if! {
if #[cfg(feature = "with-internal-mdns")] {
use mdns;
} else if #[cfg(feature = "with-external-mdns")] {
use dns_sd::DNSService;
} else {
use mdns;
}
}

#[derive(Clone)]
struct Discovery(Arc<DiscoveryInner>);
struct DiscoveryInner {
Expand Down Expand Up @@ -201,39 +210,117 @@ impl NewService for Discovery {
}
}

pub struct DiscoveryStream {
credentials: mpsc::UnboundedReceiver<Credentials>,
_svc: mdns::Service,
task: Box<Future<Item=(), Error=io::Error>>,
cfg_if! {
if #[cfg(feature = "with-internal-mdns")] {
pub struct DiscoveryStream {
credentials: mpsc::UnboundedReceiver<Credentials>,
_svc: mdns::Service,
task: Box<Future<Item=(), Error=io::Error>>,
}
} else if #[cfg(feature = "with-external-mdns")] {
pub struct DiscoveryStream {
credentials: mpsc::UnboundedReceiver<Credentials>,
_svc: DNSService,
task: Box<Future<Item=(), Error=io::Error>>,
}
} else {
pub struct DiscoveryStream {
credentials: mpsc::UnboundedReceiver<Credentials>,
_svc: mdns::Service,
task: Box<Future<Item=(), Error=io::Error>>,
}
}
}

pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String)
-> io::Result<DiscoveryStream>
{
let (discovery, creds_rx) = Discovery::new(config.clone(), device_id);

let listener = TcpListener::bind(&"0.0.0.0:0".parse().unwrap(), handle)?;
let addr = listener.local_addr()?;

let http = Http::new();
let handle_ = handle.clone();
let task = Box::new(listener.incoming().for_each(move |(socket, addr)| {
http.bind_connection(&handle_, socket, addr, discovery.clone());
Ok(())
}));

let responder = mdns::Responder::spawn(&handle)?;
let svc = responder.register(
"_spotify-connect._tcp".to_owned(),
config.name,
addr.port(),
&["VERSION=1.0", "CPath=/"]);

Ok(DiscoveryStream {
credentials: creds_rx,
_svc: svc,
task: task,
})
cfg_if! {
if #[cfg(feature = "with-internal-mdns")] {
pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String)
-> io::Result<DiscoveryStream>
{
let (discovery, creds_rx) = Discovery::new(config.clone(), device_id);

let listener = TcpListener::bind(&"0.0.0.0:0".parse().unwrap(), handle)?;
let addr = listener.local_addr()?;

let http = Http::new();
let handle_ = handle.clone();
let task = Box::new(listener.incoming().for_each(move |(socket, addr)| {
http.bind_connection(&handle_, socket, addr, discovery.clone());
Ok(())
}));

let responder = mdns::Responder::spawn(&handle)?;
let svc = responder.register(
"_spotify-connect._tcp".to_owned(),
config.name,
addr.port(),
&["VERSION=1.0", "CPath=/"]);

Ok(DiscoveryStream {
credentials: creds_rx,
_svc: svc,
task: task,
})
}
} else if #[cfg(feature = "with-external-mdns")] {
pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String)
-> io::Result<DiscoveryStream>
{
let (discovery, creds_rx) = Discovery::new(config.clone(), device_id);

let listener = TcpListener::bind(&"0.0.0.0:0".parse().unwrap(), handle)?;
let port = listener.local_addr().unwrap().port();

let http = Http::new();
let handle_ = handle.clone();
let task = Box::new(listener.incoming().for_each(move |(socket, addr)| {
http.bind_connection(&handle_, socket, addr, discovery.clone());
Ok(())
}));

let svc = DNSService::register(Some(&*config.name),
"_spotify-connect._tcp",
None,
None,
port,
&["VERSION=1.0", "CPath=/"]).unwrap();

Ok(DiscoveryStream {
credentials: creds_rx,
_svc: svc,
task: task,
})
}
} else {
pub fn discovery(handle: &Handle, config: ConnectConfig, device_id: String)
-> io::Result<DiscoveryStream>
{
let (discovery, creds_rx) = Discovery::new(config.clone(), device_id);

let listener = TcpListener::bind(&"0.0.0.0:0".parse().unwrap(), handle)?;
let addr = listener.local_addr()?;

let http = Http::new();
let handle_ = handle.clone();
let task = Box::new(listener.incoming().for_each(move |(socket, addr)| {
http.bind_connection(&handle_, socket, addr, discovery.clone());
Ok(())
}));

let responder = mdns::Responder::spawn(&handle)?;
let svc = responder.register(
"_spotify-connect._tcp".to_owned(),
config.name,
addr.port(),
&["VERSION=1.0", "CPath=/"]);

Ok(DiscoveryStream {
credentials: creds_rx,
_svc: svc,
task: task,
})
}
}
}

impl Stream for DiscoveryStream {
Expand All @@ -248,4 +335,4 @@ impl Stream for DiscoveryStream {

Ok(self.credentials.poll().unwrap())
}
}
}
12 changes: 11 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// TODO: many items from tokio-core::io have been deprecated in favour of tokio-io
#![allow(deprecated)]

#[macro_use] extern crate cfg_if;
#[macro_use] extern crate log;
#[macro_use] extern crate serde_json;
#[macro_use] extern crate serde_derive;
Expand All @@ -13,7 +14,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;
Expand All @@ -34,6 +34,16 @@ extern crate portaudio_rs;
#[cfg(feature = "libpulse-sys")]
extern crate libpulse_sys;

cfg_if! {
if #[cfg(feature = "with-internal-mdns")] {
extern crate mdns;
} else if #[cfg(feature = "with-external-mdns")] {
extern crate dns_sd;
} else {
extern crate mdns;
}
}

pub mod audio_backend;
pub mod discovery;
pub mod keymaster;
Expand Down