diff --git a/capi/Cargo.toml b/capi/Cargo.toml deleted file mode 100644 index ad8385c..0000000 --- a/capi/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -name = "librespot_capi" -version = "0.1.0" -authors = ["Paul LiƩtar "] - -[lib] -name = "librespot_capi" -crate-type = ["staticlib"] - -[dependencies] -libc = "0.2" -eventual = "~0.1.5" - -[dependencies.librespot] -path = "../" diff --git a/capi/src/artist.rs b/capi/src/artist.rs deleted file mode 100644 index c5a458c..0000000 --- a/capi/src/artist.rs +++ /dev/null @@ -1,25 +0,0 @@ -use libc::c_char; - -use librespot::metadata::Artist; - -use metadata::SpMetadata; - -#[allow(non_camel_case_types)] -pub type sp_artist = SpMetadata; - -#[no_mangle] -pub unsafe extern "C" fn sp_artist_is_loaded(c_artist: *mut sp_artist) -> bool { - let artist = &*c_artist; - artist.is_loaded() -} - -#[no_mangle] -pub unsafe extern "C" fn sp_artist_name(c_artist: *mut sp_artist) -> *const c_char { - let artist = &mut *c_artist; - - let name = artist.get() - .map(|metadata| &metadata.name as &str) - .unwrap_or(""); - - artist.intern(name).as_ptr() -} diff --git a/capi/src/cstring_cache.rs b/capi/src/cstring_cache.rs deleted file mode 100644 index 4999c0c..0000000 --- a/capi/src/cstring_cache.rs +++ /dev/null @@ -1,21 +0,0 @@ -use std::collections::HashMap; -use std::ffi::{CString, CStr}; - -pub struct CStringCache { - cache: HashMap -} - -impl CStringCache { - pub fn new() -> CStringCache { - CStringCache { - cache: HashMap::new() - } - } - - pub fn intern(&mut self, string: &str) -> &CStr { - self.cache.entry(string.to_owned()).or_insert_with(|| { - CString::new(string).unwrap() - }) - } -} - diff --git a/capi/src/lib.rs b/capi/src/lib.rs deleted file mode 100644 index e31176d..0000000 --- a/capi/src/lib.rs +++ /dev/null @@ -1,14 +0,0 @@ -#![feature(fnbox)] - -extern crate librespot; -extern crate libc; -extern crate eventual; - -pub mod artist; -pub mod link; -pub mod metadata; -pub mod session; -pub mod track; -mod types; -mod cstring_cache; - diff --git a/capi/src/link.rs b/capi/src/link.rs deleted file mode 100644 index 57a3904..0000000 --- a/capi/src/link.rs +++ /dev/null @@ -1,36 +0,0 @@ -use metadata::SpMetadata; -use session::SpSession; -use track::sp_track; -use types::sp_error; -use types::sp_error::*; -use std::ffi::CStr; -use std::rc::Rc; -use libc::c_char; -use librespot::link::Link; - -#[allow(non_camel_case_types)] -pub type sp_link = Rc; - -#[no_mangle] -pub unsafe extern "C" fn sp_link_create_from_string(uri: *const c_char) -> *mut sp_link { - let uri = CStr::from_ptr(uri).to_string_lossy(); - let link = Link::from_str(&uri).unwrap(); - - Box::into_raw(Box::new(Rc::new(link))) -} - -#[no_mangle] -pub unsafe extern "C" fn sp_link_release(c_link: *mut sp_link) -> sp_error { - drop(Box::from_raw(c_link)); - - SP_ERROR_OK -} - -#[no_mangle] -pub unsafe extern "C" fn sp_link_as_track(c_link: *mut sp_link) -> *mut sp_track { - let link = &*c_link; - let session = SpSession::global(); - - let track = SpMetadata::from_future(link.as_track(&session.session).unwrap()); - Box::into_raw(Box::new(track)) -} diff --git a/capi/src/metadata.rs b/capi/src/metadata.rs deleted file mode 100644 index ef5a0c6..0000000 --- a/capi/src/metadata.rs +++ /dev/null @@ -1,87 +0,0 @@ -use eventual::Async; -use std::sync::Arc; -use std::ffi::CStr; -use std::cell::UnsafeCell; - -use librespot::metadata::{MetadataTrait, MetadataRef}; - -use cstring_cache::CStringCache; - -use session::SpSession; - -pub struct UnsafeSyncCell { - cell: UnsafeCell -} - -impl UnsafeSyncCell { - fn new(value: T) -> UnsafeSyncCell { - UnsafeSyncCell { cell: UnsafeCell::new(value) } - } - - fn get(&self) -> *mut T { - self.cell.get() - } -} - -unsafe impl Sync for UnsafeSyncCell {} - -pub enum SpMetadataState { - Loading, - Error, - Loaded(T), -} - -pub struct SpMetadata { - state: Arc>>, - cache: CStringCache, -} - -impl SpMetadata { - pub fn from_future(future: MetadataRef) -> SpMetadata { - let state = Arc::new(UnsafeSyncCell::new(SpMetadataState::Loading)); - - { - let state = state.clone(); - SpSession::receive(future, move |session, result| { - let state = unsafe { - &mut *state.get() - }; - - *state = match result { - Ok(data) => SpMetadataState::Loaded(data), - Err(_) => SpMetadataState::Error, - }; - - unsafe { - if let Some(f) = session.callbacks.metadata_updated { - f(session as *mut _) - } - } - }); - } - - SpMetadata { - state: state, - cache: CStringCache::new(), - } - } - - pub fn is_loaded(&self) -> bool { - unsafe { - self.get().is_some() - } - } - - pub unsafe fn get(&self) -> Option<&'static T> { - let state = &*self.state.get(); - - match *state { - SpMetadataState::Loaded(ref metadata) => Some(metadata), - _ => None, - } - } - - pub fn intern(&mut self, string: &str) -> &CStr { - self.cache.intern(string) - } -} diff --git a/capi/src/session.rs b/capi/src/session.rs deleted file mode 100644 index 35731a1..0000000 --- a/capi/src/session.rs +++ /dev/null @@ -1,168 +0,0 @@ -use libc::{c_int, c_char}; -use std::ffi::CStr; -use std::slice::from_raw_parts; -use std::sync::mpsc; -use std::boxed::FnBox; -use std::sync::Mutex; - -use librespot::session::{Session, Config, Bitrate}; -use eventual::{Async, AsyncResult, Future}; - -use cstring_cache::CStringCache; -use types::sp_error; -use types::sp_error::*; -use types::sp_session_config; -use types::sp_session_callbacks; - -static mut global_session: Option<(*const sp_session, *const Mutex>)> = None; - -pub type SpSessionEvent = Box ()>; - -pub struct SpSession { - pub session: Session, - cache: CStringCache, - rx: mpsc::Receiver, - - pub callbacks: &'static sp_session_callbacks, -} - -impl SpSession { - pub unsafe fn global() -> &'static SpSession { - &*global_session.unwrap().0 - } - - pub fn run () + 'static>(event: F) { - let tx = unsafe { - &*global_session.unwrap().1 - }; - - tx.lock().unwrap().send(Box::new(event)).unwrap(); - } - - pub fn receive(future: Future, handler: F) - where T : Send, E: Send, - F : FnOnce(&mut SpSession, AsyncResult) -> () + Send + 'static { - - future.receive(move |result| { - SpSession::run(move |session| { - handler(session, result); - }) - }) - } -} - -#[allow(non_camel_case_types)] -pub type sp_session = SpSession; - -#[no_mangle] -pub unsafe extern "C" fn sp_session_create(c_config: *const sp_session_config, - c_session: *mut *mut sp_session) -> sp_error { - assert!(global_session.is_none()); - - let c_config = &*c_config; - - let application_key = from_raw_parts::(c_config.application_key as *const u8, - c_config.application_key_size); - - let user_agent = CStr::from_ptr(c_config.user_agent).to_string_lossy().into_owned(); - let device_name = CStr::from_ptr(c_config.device_id).to_string_lossy().into_owned(); - let cache_location = CStr::from_ptr(c_config.cache_location).to_string_lossy().into_owned(); - - let config = Config { - application_key: application_key.to_owned(), - user_agent: user_agent, - device_name: device_name, - cache_location: cache_location.into(), - bitrate: Bitrate::Bitrate160, - }; - - let (tx, rx) = mpsc::channel(); - - let session = SpSession { - session: Session::new(config), - cache: CStringCache::new(), - rx: rx, - callbacks: &*c_config.callbacks, - }; - - let session = Box::into_raw(Box::new(session)); - let tx = Box::into_raw(Box::new(Mutex::new(tx))); - - global_session = Some((session, tx)); - - *c_session = session; - - SP_ERROR_OK -} - -#[no_mangle] -pub unsafe extern "C" fn sp_session_release(c_session: *mut sp_session) -> sp_error { - global_session = None; - drop(Box::from_raw(c_session)); - - SP_ERROR_OK -} - -#[no_mangle] -pub unsafe extern "C" fn sp_session_login(c_session: *mut sp_session, - c_username: *const c_char, - c_password: *const c_char, - _remember_me: bool, - _blob: *const c_char) -> sp_error { - let session = &*c_session; - - let username = CStr::from_ptr(c_username).to_string_lossy().into_owned(); - let password = CStr::from_ptr(c_password).to_string_lossy().into_owned(); - - { - let session = session.session.clone(); - SpSession::receive(Future::spawn(move || { - session.login_password(username, password) - }), |session, result| { - result.unwrap(); - - { - let session = session.session.clone(); - ::std::thread::spawn(move || { - loop { - session.poll(); - } - }); - } - }); - } - - SP_ERROR_OK -} - -#[no_mangle] -pub unsafe extern "C" fn sp_session_user_name(c_session: *mut sp_session) -> *const c_char { - let session = &mut *c_session; - - let username = session.session.username(); - session.cache.intern(&username).as_ptr() -} - -#[no_mangle] -pub unsafe extern "C" fn sp_session_user_country(c_session: *mut sp_session) -> c_int { - let session = &*c_session; - - let country = session.session.country(); - country.chars().fold(0, |acc, x| { - acc << 8 | (x as u32) - }) as c_int -} - -#[no_mangle] -pub unsafe extern "C" fn sp_session_process_events(c_session: *mut sp_session, next_timeout: *mut c_int) -> sp_error { - let session = &mut *c_session; - - if !next_timeout.is_null() { - *next_timeout = 10; - } - - let event = session.rx.recv().unwrap(); - event.call_box((session,)); - - SP_ERROR_OK -} diff --git a/capi/src/track.rs b/capi/src/track.rs deleted file mode 100644 index b5280d2..0000000 --- a/capi/src/track.rs +++ /dev/null @@ -1,50 +0,0 @@ -use libc::{c_int, c_char}; -use std::ptr::null_mut; - -use artist::sp_artist; -use metadata::SpMetadata; -use session::SpSession; - -use librespot::metadata::{Track, Artist}; - -#[allow(non_camel_case_types)] -pub type sp_track = SpMetadata; - -#[no_mangle] -pub unsafe extern "C" fn sp_track_is_loaded(c_track: *mut sp_track) -> bool { - let track = &*c_track; - track.is_loaded() -} - -#[no_mangle] -pub unsafe extern "C" fn sp_track_name(c_track: *mut sp_track) -> *const c_char { - let track = &mut *c_track; - - let name = track.get() - .map(|metadata| &metadata.name as &str) - .unwrap_or(""); - - track.intern(name).as_ptr() -} - -#[no_mangle] -pub unsafe extern "C" fn sp_track_num_artists(c_track: *mut sp_track) -> c_int { - let track = &*c_track; - - track.get() - .map(|metadata| metadata.artists.len() as c_int) - .unwrap_or(0) -} - -#[no_mangle] -pub unsafe extern "C" fn sp_track_artist(c_track: *mut sp_track, index: c_int) -> *mut sp_artist { - let track = &*c_track; - let session = SpSession::global(); - - track.get() - .and_then(|metadata| metadata.artists.get(index as usize).map(|x| *x)) - .map(|artist_id| session.session.metadata::(artist_id)) - .map(|artist| Box::into_raw(Box::new(SpMetadata::from_future(artist)))) - .unwrap_or(null_mut()) -} - diff --git a/capi/src/types.rs b/capi/src/types.rs deleted file mode 100644 index c392677..0000000 --- a/capi/src/types.rs +++ /dev/null @@ -1,148 +0,0 @@ -#![allow(non_camel_case_types, dead_code)] - -use libc::{size_t, c_int, c_char, c_void}; -use session::sp_session; - -#[derive(Clone, Copy)] -#[repr(u32)] -pub enum sp_error { - SP_ERROR_OK = 0, - SP_ERROR_BAD_API_VERSION = 1, - SP_ERROR_API_INITIALIZATION_FAILED = 2, - SP_ERROR_TRACK_NOT_PLAYABLE = 3, - SP_ERROR_BAD_APPLICATION_KEY = 5, - SP_ERROR_BAD_USERNAME_OR_PASSWORD = 6, - SP_ERROR_USER_BANNED = 7, - SP_ERROR_UNABLE_TO_CONTACT_SERVER = 8, - SP_ERROR_CLIENT_TOO_OLD = 9, - SP_ERROR_OTHER_PERMANENT = 10, - SP_ERROR_BAD_USER_AGENT = 11, - SP_ERROR_MISSING_CALLBACK = 12, - SP_ERROR_INVALID_INDATA = 13, - SP_ERROR_INDEX_OUT_OF_RANGE = 14, - SP_ERROR_USER_NEEDS_PREMIUM = 15, - SP_ERROR_OTHER_TRANSIENT = 16, - SP_ERROR_IS_LOADING = 17, - SP_ERROR_NO_STREAM_AVAILABLE = 18, - SP_ERROR_PERMISSION_DENIED = 19, - SP_ERROR_INBOX_IS_FULL = 20, - SP_ERROR_NO_CACHE = 21, - SP_ERROR_NO_SUCH_USER = 22, - SP_ERROR_NO_CREDENTIALS = 23, - SP_ERROR_NETWORK_DISABLED = 24, - SP_ERROR_INVALID_DEVICE_ID = 25, - SP_ERROR_CANT_OPEN_TRACE_FILE = 26, - SP_ERROR_APPLICATION_BANNED = 27, - SP_ERROR_OFFLINE_TOO_MANY_TRACKS = 31, - SP_ERROR_OFFLINE_DISK_CACHE = 32, - SP_ERROR_OFFLINE_EXPIRED = 33, - SP_ERROR_OFFLINE_NOT_ALLOWED = 34, - SP_ERROR_OFFLINE_LICENSE_LOST = 35, - SP_ERROR_OFFLINE_LICENSE_ERROR = 36, - SP_ERROR_LASTFM_AUTH_ERROR = 39, - SP_ERROR_INVALID_ARGUMENT = 40, - SP_ERROR_SYSTEM_FAILURE = 41, -} - -#[repr(C)] -#[derive(Copy,Clone)] -pub struct sp_session_config { - pub api_version: c_int, - pub cache_location: *const c_char, - pub settings_location: *const c_char, - pub application_key: *const c_void, - pub application_key_size: size_t, - pub user_agent: *const c_char, - pub callbacks: *const sp_session_callbacks, - pub userdata: *mut c_void, - pub compress_playlists: bool, - pub dont_save_metadata_for_playlists: bool, - pub initially_unload_playlists: bool, - pub device_id: *const c_char, - pub proxy: *const c_char, - pub proxy_username: *const c_char, - pub proxy_password: *const c_char, - pub tracefile: *const c_char, -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct sp_session_callbacks { - pub logged_in: Option, - - pub logged_out: Option, - - pub metadata_updated: Option, - - pub connection_error: Option, - - pub message_to_user: Option, - - pub notify_main_thread: Option, - - pub music_delivery: Option c_int>, - - pub play_token_lost: Option, - - pub log_message: Option, - - pub end_of_track: Option, - - pub streaming_error: Option, - - pub userinfo_updated: Option, - - pub start_playback: Option, - - pub stop_playback: Option, - - pub get_audio_buffer_stats: Option, - - pub offline_status_updated: Option, - - pub offline_error: Option, - - pub credentials_blob_updated: Option, - - pub connectionstate_updated: Option, - - pub scrobble_error: Option, - - pub private_session_mode_changed: Option, -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct sp_audioformat { - pub sample_type: sp_sampletype, - pub sample_rate: c_int, - pub channels: c_int, -} - -#[derive(Clone, Copy)] -#[repr(u32)] -pub enum sp_sampletype { - SP_SAMPLETYPE_INT16_NATIVE_ENDIAN = 0, - _Dummy // rust #10292 -} - -#[repr(C)] -#[derive(Clone, Copy)] -pub struct sp_audio_buffer_stats { - pub samples: c_int, - pub stutter: c_int, -}