// Copyright (c) 2015 T. Okubo // This file is part of vlc-rs. // Licensed under the MIT license, see the LICENSE file. use std::ptr::null; use std::borrow::Cow; use std::marker::PhantomData; use sys; use ::tools::{to_cstr, from_cstr, from_cstr_ref}; use ::libc::{c_void, c_char, c_int}; use ::enums::*; /// Retrieve libvlc version. pub fn version() -> Cow<'static, str> { unsafe{ from_cstr_ref(sys::libvlc_get_version()).unwrap() } } /// Retrieve libvlc compiler version. pub fn compiler() -> Cow<'static, str> { unsafe{ from_cstr_ref(sys::libvlc_get_compiler()).unwrap() } } pub struct Instance { pub ptr: *mut sys::libvlc_instance_t, } impl Instance { /// Create and initialize a libvlc instance. pub fn new() -> Option<Instance> { unsafe{ let p = sys::libvlc_new(0, null()); if p.is_null() { return None; } Some(Instance{ptr: p}) } } /// Try to start a user interface for the libvlc instance. pub fn add_intf(&self, name: &str) -> Result<(), ()> { let cstr = to_cstr(name); let result = unsafe{ sys::libvlc_add_intf(self.ptr, cstr.as_ptr()) }; if result == 0 { Ok(()) } else { Err(()) } } /// Sets the application name. /// LibVLC passes this as the user agent string when a protocol requires it. pub fn set_user_agent(&self, name: &str, http: &str) { unsafe{ sys::libvlc_set_user_agent( self.ptr, to_cstr(name).as_ptr(), to_cstr(http).as_ptr()); } } /// Waits until an interface causes the instance to exit. pub fn wait(&self) { unsafe{ sys::libvlc_wait(self.ptr) }; } /// Sets some meta-information about the application. pub fn set_app_id(&self, id: &str, version: &str, icon: &str) { unsafe{ sys::libvlc_set_app_id( self.ptr, to_cstr(id).as_ptr(), to_cstr(version).as_ptr(), to_cstr(icon).as_ptr()); } } /// Returns a list of audio filters that are available. pub fn audio_filter_list_get(&self) -> Option<ModuleDescriptionList> { unsafe{ let p = sys::libvlc_audio_filter_list_get(self.ptr); if p.is_null() { None } else { Some(ModuleDescriptionList{ptr: p}) } } } /// Returns a list of video filters that are available. pub fn video_filter_list_get(&self) -> Option<ModuleDescriptionList> { unsafe{ let p = sys::libvlc_video_filter_list_get(self.ptr); if p.is_null() { None } else { Some(ModuleDescriptionList{ptr: p}) } } } /// Set logging callback pub fn set_log<F: Fn(LogLevel, Log, Cow<str>) + Send + 'static>(&self, f: F) { let cb: Box<Box<Fn(LogLevel, Log, Cow<str>) + Send + 'static>> = Box::new(Box::new(f)); unsafe{ sys::libvlc_log_set(self.ptr, logging_cb, Box::into_raw(cb) as *mut _); } } } impl Drop for Instance { fn drop(&mut self) { unsafe{ sys::libvlc_release(self.ptr); } } } extern "C" { fn vsnprintf(s: *mut c_char, n: usize, fmt: *const c_char, arg: sys::va_list); } const BUF_SIZE: usize = 1024; // Write log message to the buffer by vsnprintf. unsafe extern "C" fn logging_cb( data: *mut c_void, level: c_int, ctx: *const sys::libvlc_log_t, fmt: *const c_char, args: sys::va_list) { let f: &Box<Fn(LogLevel, Log, Cow<str>) + Send + 'static> = ::std::mem::transmute(data); let mut buf: [c_char; BUF_SIZE] = [0; BUF_SIZE]; vsnprintf(buf.as_mut_ptr(), BUF_SIZE, fmt, args); f(::std::mem::transmute(level), Log{ptr: ctx}, from_cstr_ref(buf.as_ptr()).unwrap()); } /// List of module description. pub struct ModuleDescriptionList { ptr: *mut sys::libvlc_module_description_t, } impl Drop for ModuleDescriptionList { fn drop(&mut self) { unsafe{ sys::libvlc_module_description_list_release(self.ptr) }; } } impl<'a> IntoIterator for &'a ModuleDescriptionList { type Item = ModuleDescriptionRef<'a>; type IntoIter = ModuleDescriptionListIter<'a>; fn into_iter(self) -> Self::IntoIter { ModuleDescriptionListIter{ptr: self.ptr, _phantomdata: PhantomData} } } pub struct ModuleDescriptionListIter<'a> { ptr: *mut sys::libvlc_module_description_t, _phantomdata: PhantomData<&'a sys::libvlc_module_description_t>, } /// Description of a module. /// The strings are owned. #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct ModuleDescription { pub name: Option<String>, pub shortname: Option<String>, pub longname: Option<String>, pub help: Option<String>, } /// Description of a module. #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct ModuleDescriptionRef<'a> { pub name: Option<Cow<'a, str>>, pub shortname: Option<Cow<'a, str>>, pub longname: Option<Cow<'a, str>>, pub help: Option<Cow<'a, str>>, } impl<'a> Iterator for ModuleDescriptionListIter<'a> { type Item = ModuleDescriptionRef<'a>; fn next(&mut self) -> Option<Self::Item> { unsafe{ if self.ptr.is_null() { return None; } let p = self.ptr; self.ptr = (*p).p_next; Some(ModuleDescriptionRef{ name: from_cstr_ref((*p).psz_name), shortname: from_cstr_ref((*p).psz_shortname), longname: from_cstr_ref((*p).psz_longname), help: from_cstr_ref((*p).psz_help), }) } } } impl<'a> ModuleDescriptionRef<'a> { /// Convert to owned strings. pub fn into_owned(&'a self) -> ModuleDescription { ModuleDescription { name: self.name .as_ref().map(|s| s.clone().into_owned()), shortname: self.shortname.as_ref().map(|s| s.clone().into_owned()), longname: self.name .as_ref().map(|s| s.clone().into_owned()), help: self.shortname.as_ref().map(|s| s.clone().into_owned()), } } } pub fn errmsg() -> Option<String> { unsafe{ from_cstr(sys::libvlc_errmsg()) } } pub fn clearerr() { unsafe{ sys::libvlc_clearerr() }; } #[derive(Clone, Debug)] pub enum Event { MediaMetaChanged(Meta), MediaSubItemAdded, MediaDurationChanged(i64), MediaParsedChanged(i32), MediaFreed, MediaStateChanged(State), MediaSubItemTreeAdded, MediaPlayerMediaChanged, MediaPlayerNothingSpecial, MediaPlayerOpening, MediaPlayerBuffering(f32), MediaPlayerPlaying, MediaPlayerPaused, MediaPlayerStopped, MediaPlayerForward, MediaPlayerBackward, MediaPlayerEndReached, MediaPlayerEncounteredError, MediaPlayerTimeChanged, MediaPlayerPositionChanged(f32), MediaPlayerSeekableChanged, MediaPlayerPausableChanged, MediaPlayerTitleChanged, MediaPlayerSnapshotTaken, MediaPlayerLengthChanged, MediaPlayerVout, MediaPlayerScrambledChanged, MediaListItemAdded, MediaListWillAddItem, MediaListItemDeleted, MediaListWillDeleteItem, MediaListViewItemAdded, MediaListViewWillAddItem, MediaListViewItemDeleted, MediaListViewWillDeleteItem, MediaListPlayerPlayed, MediaListPlayerNextItemSet, MediaListPlayerStopped, MediaDiscovererStarted, MediaDiscovererEnded, VlmMediaAdded, VlmMediaRemoved, VlmMediaChanged, VlmMediaInstanceStarted, VlmMediaInstanceStopped, VlmMediaInstanceStatusInit, VlmMediaInstanceStatusOpening, VlmMediaInstanceStatusPlaying, VlmMediaInstanceStatusPause, VlmMediaInstanceStatusEnd, VlmMediaInstanceStatusError } pub struct EventManager<'a> { pub ptr: *mut sys::libvlc_event_manager_t, pub _phantomdata: ::std::marker::PhantomData<&'a sys::libvlc_event_manager_t>, } impl<'a> EventManager<'a> { pub fn attach<F>(&self, event_type: EventType, callback: F) -> Result<(), ()> where F: Fn(Event, VLCObject) + Send + 'static { // Explicit type annotation is needed let callback: Box<Box<Fn(Event, VLCObject) + Send + 'static>> = Box::new(Box::new(callback)); let result = unsafe{ sys::libvlc_event_attach( self.ptr, event_type as i32, event_manager_callback, Box::into_raw(callback) as *mut c_void) }; if result == 0 { Ok(()) }else{ Err(()) } } } unsafe extern "C" fn event_manager_callback(pe: *const sys::libvlc_event_t, data: *mut c_void) { let f: &Box<Fn(Event, VLCObject) + Send + 'static> = ::std::mem::transmute(data); f(conv_event(pe), VLCObject{_ptr: (*pe).p_obj}); } // Convert c-style libvlc_event_t to Event fn conv_event(pe: *const sys::libvlc_event_t) -> Event { let event_type: EventType = unsafe{ ::std::mem::transmute((*pe)._type) }; match event_type { EventType::MediaMetaChanged => { unsafe{ Event::MediaMetaChanged((*pe).u.media_meta_changed.meta_type) } }, EventType::MediaSubItemAdded => { Event::MediaSubItemAdded }, EventType::MediaDurationChanged => { unsafe{ Event::MediaDurationChanged((*pe).u.media_duration_changed.new_duration) } }, EventType::MediaParsedChanged => { unsafe{ Event::MediaParsedChanged((*pe).u.media_parsed_changed.new_status) } }, EventType::MediaFreed => { Event::MediaFreed }, EventType::MediaStateChanged => { unsafe{ Event::MediaStateChanged((*pe).u.media_state_changed.new_state) } }, EventType::MediaSubItemTreeAdded => { Event::MediaSubItemTreeAdded }, EventType::MediaPlayerMediaChanged => { Event::MediaPlayerMediaChanged }, EventType::MediaPlayerNothingSpecial => { Event::MediaPlayerNothingSpecial }, EventType::MediaPlayerOpening => { Event::MediaPlayerOpening }, EventType::MediaPlayerBuffering => { unsafe{ Event::MediaPlayerBuffering((*pe).u.media_player_buffering.new_cache) } }, EventType::MediaPlayerPlaying => { Event::MediaPlayerPlaying }, EventType::MediaPlayerPaused => { Event::MediaPlayerPaused }, EventType::MediaPlayerStopped => { Event::MediaPlayerStopped }, EventType::MediaPlayerForward => { Event::MediaPlayerForward }, EventType::MediaPlayerBackward => { Event::MediaPlayerBackward }, EventType::MediaPlayerEndReached => { Event::MediaPlayerEndReached }, EventType::MediaPlayerEncounteredError => { Event::MediaPlayerEncounteredError }, EventType::MediaPlayerTimeChanged => { Event::MediaPlayerTimeChanged }, EventType::MediaPlayerPositionChanged => { unsafe{ Event::MediaPlayerPositionChanged((*pe).u.media_player_position_changed.new_position) } }, EventType::MediaPlayerSeekableChanged => { Event::MediaPlayerSeekableChanged }, EventType::MediaPlayerPausableChanged => { Event::MediaPlayerPausableChanged }, EventType::MediaPlayerTitleChanged => { Event::MediaPlayerTitleChanged }, EventType::MediaPlayerSnapshotTaken => { Event::MediaPlayerSnapshotTaken }, EventType::MediaPlayerLengthChanged => { Event::MediaPlayerLengthChanged }, EventType::MediaPlayerVout => { Event::MediaPlayerVout }, EventType::MediaPlayerScrambledChanged => { Event::MediaPlayerScrambledChanged }, EventType::MediaListItemAdded => { Event::MediaListItemAdded }, EventType::MediaListWillAddItem => { Event::MediaListWillAddItem }, EventType::MediaListItemDeleted => { Event::MediaListItemDeleted }, EventType::MediaListWillDeleteItem => { Event::MediaListWillDeleteItem }, EventType::MediaListViewItemAdded => { Event::MediaListViewItemAdded }, EventType::MediaListViewWillAddItem => { Event::MediaListViewWillAddItem }, EventType::MediaListViewItemDeleted => { Event::MediaListViewItemDeleted }, EventType::MediaListViewWillDeleteItem => { Event::MediaListViewWillDeleteItem }, EventType::MediaListPlayerPlayed => { Event::MediaListPlayerPlayed }, EventType::MediaListPlayerNextItemSet => { Event::MediaListPlayerNextItemSet }, EventType::MediaListPlayerStopped => { Event::MediaListPlayerStopped }, EventType::MediaDiscovererStarted => { Event::MediaDiscovererStarted }, EventType::MediaDiscovererEnded => { Event::MediaDiscovererEnded }, EventType::VlmMediaAdded => { Event::VlmMediaAdded }, EventType::VlmMediaRemoved => { Event::VlmMediaRemoved }, EventType::VlmMediaChanged => { Event::VlmMediaChanged }, EventType::VlmMediaInstanceStarted => { Event::VlmMediaInstanceStarted }, EventType::VlmMediaInstanceStopped => { Event::VlmMediaInstanceStopped }, EventType::VlmMediaInstanceStatusInit => { Event::VlmMediaInstanceStatusInit }, EventType::VlmMediaInstanceStatusOpening => { Event::VlmMediaInstanceStatusOpening }, EventType::VlmMediaInstanceStatusPlaying => { Event::VlmMediaInstanceStatusPlaying }, EventType::VlmMediaInstanceStatusPause => { Event::VlmMediaInstanceStatusPause }, EventType::VlmMediaInstanceStatusEnd => { Event::VlmMediaInstanceStatusEnd }, EventType::VlmMediaInstanceStatusError => { Event::VlmMediaInstanceStatusError }, } } pub struct VLCObject { _ptr: *mut c_void, } pub struct Log { pub ptr: *const sys::libvlc_log_t }