diff --git a/src/mpv/event.rs b/src/mpv/event.rs index 788d352..6c22463 100644 --- a/src/mpv/event.rs +++ b/src/mpv/event.rs @@ -1,10 +1,9 @@ use super::Error; -use std::borrow::Cow; #[derive(Clone, Debug)] -pub enum Event<'a> { +pub enum Event { Shutdown, - LogMessage(LogMessageEvent<'a>), + LogMessage(LogMessageEvent), //GetPropertyReply(PropertyEvent), TODO //SetPropertyReply(PropertyEvent), TODO //CommandReply(CommandEvent), TODO @@ -16,7 +15,7 @@ pub enum Event<'a> { AudioReconfig, //Seek, PlaybackRestart, - PropertyChange(PropertyEvent<'a>), + PropertyChange(PropertyEvent), //QueueOverflow, //Hook, Unknown(u32), @@ -45,25 +44,25 @@ pub struct EndFileEvent { } #[derive(Clone, Debug)] -pub struct LogMessageEvent<'a> { - pub prefix: &'a str, - pub level: &'a str, - pub text: &'a str, +pub struct LogMessageEvent { + pub prefix: String, + pub level: String, + pub text: String, //log_level: i32, } #[derive(Clone, Debug)] -pub struct PropertyEvent<'a> { +pub struct PropertyEvent { pub reply_userdata: u64, - pub name: &'a str, - pub value: PropertyEventValue<'a>, + pub name: String, + pub value: PropertyEventValue, } #[derive(Clone, Debug)] -pub enum PropertyEventValue<'a> { +pub enum PropertyEventValue { None, - String(Cow<'a, str>), - OsdString(&'a str), + String(String), + OsdString(String), Flag(bool), Int64(i64), Double(f64), diff --git a/src/mpv/handle.rs b/src/mpv/handle.rs index 731b99a..8f32851 100644 --- a/src/mpv/handle.rs +++ b/src/mpv/handle.rs @@ -3,6 +3,7 @@ use event::{ EndFileEvent, EndFileReason, LogMessageEvent, PropertyEvent, PropertyEventValue, StartFileEvent, }; use event_listener::{Event, EventListener, IntoNotification}; +use std::cell::{RefCell, RefMut}; use std::ffi::{c_char, c_void, CStr, CString}; use std::fmt; use std::pin::Pin; @@ -11,6 +12,7 @@ use std::ptr::NonNull; pub struct Handle { inner: NonNull, wakeup: Pin>, // the wakeup callback holds a pointer to this + wait_event_cell: RefCell<()>, } // The client API is generally fully thread-safe, unless otherwise noted. @@ -61,7 +63,11 @@ impl Handle { Error::from_return_code(unsafe { ffi::mpv_initialize(inner.as_ptr()) }) .expect("could not initialize mpv handle"); - Self { inner, wakeup } + Self { + inner, + wakeup, + wait_event_cell: RefCell::new(()), + } } pub fn client_name(&self) -> &str { @@ -122,8 +128,11 @@ impl Handle { self.wakeup.listen() } - pub fn wait_event(&mut self, timeout: f64) -> Option> { - let event = unsafe { &*ffi::mpv_wait_event(self.inner.as_ptr(), timeout) }; + pub fn wait_event(&self, timeout: f64) -> Option { + // use refcell to ensure exclusive access + let event = RefMut::map(self.wait_event_cell.borrow_mut(), |()| unsafe { + &mut *ffi::mpv_wait_event(self.inner.as_ptr(), timeout) + }); match event.event_id { ffi::mpv_event_id_MPV_EVENT_NONE => None, @@ -134,9 +143,15 @@ impl Handle { let data = unsafe { &*(event.data as *mut ffi::mpv_event_log_message) }; // TODO: actual logging? Some(MpvEvent::LogMessage(LogMessageEvent { - prefix: unsafe { CStr::from_ptr(data.prefix) }.to_str().unwrap(), - level: unsafe { CStr::from_ptr(data.level) }.to_str().unwrap(), - text: unsafe { CStr::from_ptr(data.text) }.to_str().unwrap(), + prefix: unsafe { CStr::from_ptr(data.prefix) } + .to_string_lossy() + .into(), + level: unsafe { CStr::from_ptr(data.level) } + .to_string_lossy() + .into(), + text: unsafe { CStr::from_ptr(data.text) } + .to_string_lossy() + .into(), })) } @@ -178,7 +193,9 @@ impl Handle { let data = unsafe { &*(event.data as *mut ffi::mpv_event_property) }; Some(MpvEvent::PropertyChange(PropertyEvent { reply_userdata: event.reply_userdata, - name: unsafe { CStr::from_ptr(data.name) }.to_str().unwrap(), + name: unsafe { CStr::from_ptr(data.name) } + .to_string_lossy() + .into(), value: match data.format { ffi::mpv_format_MPV_FORMAT_NONE => PropertyEventValue::None, ffi::mpv_format_MPV_FORMAT_INT64 => { diff --git a/src/playbin2.rs b/src/playbin2.rs index 6876140..40f310f 100644 --- a/src/playbin2.rs +++ b/src/playbin2.rs @@ -1 +1,43 @@ -mod imp {} +use crate::mpv; +use event_listener::EventListener; + +pub struct Playbin { + mpv: mpv::Handle, +} + +impl Default for Playbin { + fn default() -> Self { + let mpv = mpv::Handle::new(); + mpv.set_property("audio-client-name", "audrey").unwrap(); + mpv.set_property("user-agent", crate::USER_AGENT).unwrap(); + mpv.set_property("video", false).unwrap(); + mpv.set_property("prefetch-playlist", true).unwrap(); + mpv.set_property("gapless-audio", true).unwrap(); + + mpv.command(["loadfile", "https://www.youtube.com/watch?v=19y8YTbvri8"]) + .unwrap(); + + Self { mpv } + } +} + +impl Playbin { + pub fn tick(&self) -> EventListener { + let listener = self.mpv.wakeup_listener(); + while let Some(event) = self.mpv.wait_event(0.0) { + self.handle_event(event); + } + listener + } + + fn handle_event(&self, event: mpv::Event) { + println!("mpv event {:?}", event); + } +} + +impl Drop for Playbin { + fn drop(&mut self) { + println!("dropping Playbin2"); + self.mpv.command(["quit"]).unwrap(); + } +} diff --git a/src/ui/window.rs b/src/ui/window.rs index d862380..b27bf4a 100644 --- a/src/ui/window.rs +++ b/src/ui/window.rs @@ -1,5 +1,4 @@ mod imp { - use crate::mpv; use adw::prelude::*; use adw::subclass::prelude::*; use glib::subclass::InitializingObject; @@ -28,7 +27,8 @@ mod imp { pub(super) setup: crate::ui::Setup, pub(super) api: RefCell>, - pub(super) mpv: Rc>, + + playbin2: Rc, } #[glib::object_subclass] @@ -52,36 +52,19 @@ mod imp { fn constructed(&self) { self.parent_constructed(); - // set up mpv - let mpv = self.mpv.borrow(); - mpv.set_property("audio-client-name", "audrey").unwrap(); - mpv.set_property("user-agent", crate::USER_AGENT).unwrap(); - mpv.set_property("video", false).unwrap(); - mpv.set_property("prefetch-playlist", true).unwrap(); - mpv.set_property("gapless-audio", true).unwrap(); - mpv.observe_property_i64(0, "duration").unwrap(); - - mpv.command(["loadfile", "https://www.youtube.com/watch?v=19y8YTbvri8"]) - .unwrap(); - - let mpv_weak = Rc::downgrade(&self.mpv); - glib::spawn_future_local(async move { + let playbin = Rc::downgrade(&self.playbin2); + glib::spawn_future_local(glib::clone!(async move { loop { - let mpv = match mpv_weak.upgrade() { - Some(mpv) => mpv, + match playbin.upgrade() { None => break, - }; - { - let mut mpv_ref = mpv.borrow_mut(); - let listener = mpv_ref.wakeup_listener(); - while let Some(event) = mpv_ref.wait_event(0.0) { - println!("mpv event {:?}", event); + Some(playbin) => { + let listener = playbin.tick(); + drop(playbin); + listener.await; } - listener } - .await } - }); + })); // set up mpris let window = self.obj().clone(); @@ -194,7 +177,6 @@ mod imp { impl Drop for Window { fn drop(&mut self) { println!("dropping AudreyUiWindow"); - self.mpv.borrow().command(["quit"]).unwrap(); } } }