about summary refs log tree commit diff stats
path: root/libmpv2/src/mpv/events.rs
diff options
context:
space:
mode:
authorBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-08-23 12:57:19 +0200
committerBenedikt Peetz <benedikt.peetz@b-peetz.de>2024-08-23 12:58:02 +0200
commit0ae5018c33cc4bfe27583c9902472b499f4bd269 (patch)
treeafc2fbfcb126215f47afbc32e555d203d4d6d88c /libmpv2/src/mpv/events.rs
parentchore(yt_dlp/progress_hook): Also consider the `total_bytes_estimate` field (diff)
downloadyt-0ae5018c33cc4bfe27583c9902472b499f4bd269.tar.gz
yt-0ae5018c33cc4bfe27583c9902472b499f4bd269.zip
refactor(libmpv2): Move to the `crates` directory
Diffstat (limited to 'libmpv2/src/mpv/events.rs')
-rw-r--r--libmpv2/src/mpv/events.rs383
1 files changed, 0 insertions, 383 deletions
diff --git a/libmpv2/src/mpv/events.rs b/libmpv2/src/mpv/events.rs
deleted file mode 100644
index cbe1ef3..0000000
--- a/libmpv2/src/mpv/events.rs
+++ /dev/null
@@ -1,383 +0,0 @@
-// yt - A fully featured command line YouTube client
-//
-// Copyright (C) 2024 Benedikt Peetz <benedikt.peetz@b-peetz.de>
-// SPDX-License-Identifier: GPL-3.0-or-later
-//
-// This file is part of Yt.
-//
-// You should have received a copy of the License along with this program.
-// If not, see <https://www.gnu.org/licenses/gpl-3.0.txt>.
-
-use crate::mpv_node::sys_node::SysMpvNode;
-use crate::{mpv::mpv_err, *};
-
-use std::ffi::{c_void, CString};
-use std::os::raw as ctype;
-use std::ptr::NonNull;
-use std::slice;
-
-/// An `Event`'s ID.
-pub use libmpv2_sys::mpv_event_id as EventId;
-
-use self::mpv_node::MpvNode;
-pub mod mpv_event_id {
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_AUDIO_RECONFIG as AudioReconfig;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_CLIENT_MESSAGE as ClientMessage;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_COMMAND_REPLY as CommandReply;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_END_FILE as EndFile;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_FILE_LOADED as FileLoaded;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_GET_PROPERTY_REPLY as GetPropertyReply;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_HOOK as Hook;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_LOG_MESSAGE as LogMessage;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_NONE as None;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_PLAYBACK_RESTART as PlaybackRestart;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_PROPERTY_CHANGE as PropertyChange;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_QUEUE_OVERFLOW as QueueOverflow;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_SEEK as Seek;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_SET_PROPERTY_REPLY as SetPropertyReply;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_SHUTDOWN as Shutdown;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_START_FILE as StartFile;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_TICK as Tick;
-    pub use libmpv2_sys::mpv_event_id_MPV_EVENT_VIDEO_RECONFIG as VideoReconfig;
-}
-
-#[derive(Debug)]
-/// Data that is returned by both `GetPropertyReply` and `PropertyChange` events.
-pub enum PropertyData<'a> {
-    Str(&'a str),
-    OsdStr(&'a str),
-    Flag(bool),
-    Int64(i64),
-    Double(ctype::c_double),
-    Node(MpvNode),
-}
-
-impl<'a> PropertyData<'a> {
-    // SAFETY: meant to extract the data from an event property. See `mpv_event_property` in
-    // `client.h`
-    unsafe fn from_raw(format: MpvFormat, ptr: *mut ctype::c_void) -> Result<PropertyData<'a>> {
-        assert!(!ptr.is_null());
-        match format {
-            mpv_format::Flag => Ok(PropertyData::Flag(*(ptr as *mut bool))),
-            mpv_format::String => {
-                let char_ptr = *(ptr as *mut *mut ctype::c_char);
-                Ok(PropertyData::Str(mpv_cstr_to_str!(char_ptr)?))
-            }
-            mpv_format::OsdString => {
-                let char_ptr = *(ptr as *mut *mut ctype::c_char);
-                Ok(PropertyData::OsdStr(mpv_cstr_to_str!(char_ptr)?))
-            }
-            mpv_format::Double => Ok(PropertyData::Double(*(ptr as *mut f64))),
-            mpv_format::Int64 => Ok(PropertyData::Int64(*(ptr as *mut i64))),
-            mpv_format::Node => {
-                let sys_node = *(ptr as *mut libmpv2_sys::mpv_node);
-                let node = SysMpvNode::new(sys_node, false);
-                return Ok(PropertyData::Node(node.value().unwrap()));
-            }
-            mpv_format::None => unreachable!(),
-            _ => unimplemented!(),
-        }
-    }
-}
-
-pub type PlaylistEntryId = i64;
-
-#[derive(Debug)]
-pub enum Event<'a> {
-    /// Received when the player is shutting down
-    Shutdown,
-    /// *Has not been tested*, received when explicitly asked to MPV
-    LogMessage {
-        prefix: &'a str,
-        level: &'a str,
-        text: &'a str,
-        log_level: LogLevel,
-    },
-    /// Received when using get_property_async
-    GetPropertyReply {
-        name: &'a str,
-        result: PropertyData<'a>,
-        reply_userdata: u64,
-    },
-    /// Received when using set_property_async
-    SetPropertyReply(u64),
-    /// Received when using command_async
-    CommandReply(u64),
-    /// Event received when a new file is playing
-    StartFile(PlaylistEntryId),
-    /// Event received when the file being played currently has stopped, for an error or not
-    EndFile(EndFileReason),
-    /// Event received when a file has been *loaded*, but has not been started
-    FileLoaded,
-    ClientMessage(Vec<&'a str>),
-    VideoReconfig,
-    AudioReconfig,
-    /// The player changed current position
-    Seek,
-    PlaybackRestart,
-    /// Received when used with observe_property
-    PropertyChange {
-        name: &'a str,
-        change: PropertyData<'a>,
-        reply_userdata: u64,
-    },
-    /// Received when the Event Queue is full
-    QueueOverflow,
-    /// A deprecated event
-    Deprecated(libmpv2_sys::mpv_event),
-}
-
-unsafe extern "C" fn wu_wrapper<F: Fn() + Send + 'static>(ctx: *mut c_void) {
-    if ctx.is_null() {
-        panic!("ctx for wakeup wrapper is NULL");
-    }
-
-    (*(ctx as *mut F))();
-}
-
-/// Context to listen to events.
-pub struct EventContext {
-    ctx: NonNull<libmpv2_sys::mpv_handle>,
-    wakeup_callback_cleanup: Option<Box<dyn FnOnce()>>,
-}
-
-unsafe impl Send for EventContext {}
-
-impl EventContext {
-    pub fn new(ctx: NonNull<libmpv2_sys::mpv_handle>) -> Self {
-        EventContext {
-            ctx,
-            wakeup_callback_cleanup: None,
-        }
-    }
-
-    /// Enable an event.
-    pub fn enable_event(&self, ev: events::EventId) -> Result<()> {
-        mpv_err((), unsafe {
-            libmpv2_sys::mpv_request_event(self.ctx.as_ptr(), ev, 1)
-        })
-    }
-
-    /// Enable all, except deprecated, events.
-    pub fn enable_all_events(&self) -> Result<()> {
-        for i in (2..9).chain(16..19).chain(20..23).chain(24..26) {
-            self.enable_event(i)?;
-        }
-        Ok(())
-    }
-
-    /// Disable an event.
-    pub fn disable_event(&self, ev: events::EventId) -> Result<()> {
-        mpv_err((), unsafe {
-            libmpv2_sys::mpv_request_event(self.ctx.as_ptr(), ev, 0)
-        })
-    }
-
-    /// Diable all deprecated events.
-    pub fn disable_deprecated_events(&self) -> Result<()> {
-        self.disable_event(libmpv2_sys::mpv_event_id_MPV_EVENT_IDLE)?;
-        Ok(())
-    }
-
-    /// Diable all events.
-    pub fn disable_all_events(&self) -> Result<()> {
-        for i in 2..26 {
-            self.disable_event(i as _)?;
-        }
-        Ok(())
-    }
-
-    /// Observe `name` property for changes. `id` can be used to unobserve this (or many) properties
-    /// again.
-    pub fn observe_property(&self, name: &str, format: Format, id: u64) -> Result<()> {
-        let name = CString::new(name)?;
-        mpv_err((), unsafe {
-            libmpv2_sys::mpv_observe_property(
-                self.ctx.as_ptr(),
-                id,
-                name.as_ptr(),
-                format.as_mpv_format() as _,
-            )
-        })
-    }
-
-    /// Unobserve any property associated with `id`.
-    pub fn unobserve_property(&self, id: u64) -> Result<()> {
-        mpv_err((), unsafe {
-            libmpv2_sys::mpv_unobserve_property(self.ctx.as_ptr(), id)
-        })
-    }
-
-    /// Wait for `timeout` seconds for an `Event`. Passing `0` as `timeout` will poll.
-    /// For more information, as always, see the mpv-sys docs of `mpv_wait_event`.
-    ///
-    /// This function is intended to be called repeatedly in a wait-event loop.
-    ///
-    /// Returns `Some(Err(...))` if there was invalid utf-8, or if either an
-    /// `MPV_EVENT_GET_PROPERTY_REPLY`, `MPV_EVENT_SET_PROPERTY_REPLY`, `MPV_EVENT_COMMAND_REPLY`,
-    /// or `MPV_EVENT_PROPERTY_CHANGE` event failed, or if `MPV_EVENT_END_FILE` reported an error.
-    pub fn wait_event(&mut self, timeout: f64) -> Option<Result<Event>> {
-        let event = unsafe { *libmpv2_sys::mpv_wait_event(self.ctx.as_ptr(), timeout) };
-
-        // debug!("Got an event from mpv: {:#?}", event);
-
-        if event.event_id != mpv_event_id::None {
-            if let Err(e) = mpv_err((), event.error) {
-                return Some(Err(e));
-            }
-        }
-
-        match event.event_id {
-            mpv_event_id::None => None,
-            mpv_event_id::Shutdown => Some(Ok(Event::Shutdown)),
-            mpv_event_id::LogMessage => {
-                let log_message =
-                    unsafe { *(event.data as *mut libmpv2_sys::mpv_event_log_message) };
-
-                let prefix = unsafe { mpv_cstr_to_str!(log_message.prefix) };
-                Some(prefix.and_then(|prefix| {
-                    Ok(Event::LogMessage {
-                        prefix,
-                        level: unsafe { mpv_cstr_to_str!(log_message.level)? },
-                        text: unsafe { mpv_cstr_to_str!(log_message.text)? },
-                        log_level: log_message.log_level,
-                    })
-                }))
-            }
-            mpv_event_id::GetPropertyReply => {
-                let property = unsafe { *(event.data as *mut libmpv2_sys::mpv_event_property) };
-
-                let name = unsafe { mpv_cstr_to_str!(property.name) };
-                Some(name.and_then(|name| {
-                    // SAFETY: safe because we are passing format + data from an mpv_event_property
-                    let result = unsafe { PropertyData::from_raw(property.format, property.data) }?;
-
-                    Ok(Event::GetPropertyReply {
-                        name,
-                        result,
-                        reply_userdata: event.reply_userdata,
-                    })
-                }))
-            }
-            mpv_event_id::SetPropertyReply => Some(mpv_err(
-                Event::SetPropertyReply(event.reply_userdata),
-                event.error,
-            )),
-            mpv_event_id::CommandReply => Some(mpv_err(
-                Event::CommandReply(event.reply_userdata),
-                event.error,
-            )),
-            mpv_event_id::StartFile => {
-                let playlist_id = unsafe { *(event.data as *mut i64) };
-
-                Some(Ok(Event::StartFile(playlist_id)))
-            }
-            mpv_event_id::EndFile => {
-                let end_file = unsafe { *(event.data as *mut libmpv2_sys::mpv_event_end_file) };
-
-                // debug!("Got an end file event, with error code '{:#?}'", end_file);
-
-                if let Err(e) = mpv_err((), end_file.error) {
-                    Some(Err(e))
-                } else {
-                    Some(Ok(Event::EndFile(end_file.reason.into())))
-                }
-            }
-            mpv_event_id::FileLoaded => Some(Ok(Event::FileLoaded)),
-            mpv_event_id::ClientMessage => {
-                let client_message =
-                    unsafe { *(event.data as *mut libmpv2_sys::mpv_event_client_message) };
-                let messages = unsafe {
-                    slice::from_raw_parts_mut(client_message.args, client_message.num_args as _)
-                };
-                Some(Ok(Event::ClientMessage(
-                    messages
-                        .iter()
-                        .map(|msg| unsafe { mpv_cstr_to_str!(*msg) })
-                        .collect::<Result<Vec<_>>>()
-                        .unwrap(),
-                )))
-            }
-            mpv_event_id::VideoReconfig => Some(Ok(Event::VideoReconfig)),
-            mpv_event_id::AudioReconfig => Some(Ok(Event::AudioReconfig)),
-            mpv_event_id::Seek => Some(Ok(Event::Seek)),
-            mpv_event_id::PlaybackRestart => Some(Ok(Event::PlaybackRestart)),
-            mpv_event_id::PropertyChange => {
-                let property = unsafe { *(event.data as *mut libmpv2_sys::mpv_event_property) };
-
-                // This happens if the property is not available. For example,
-                // if you reached EndFile while observing a property.
-                if property.format == mpv_format::None {
-                    None
-                } else {
-                    let name = unsafe { mpv_cstr_to_str!(property.name) };
-                    Some(name.and_then(|name| {
-                        // SAFETY: safe because we are passing format + data from an mpv_event_property
-                        let change =
-                            unsafe { PropertyData::from_raw(property.format, property.data) }?;
-
-                        Ok(Event::PropertyChange {
-                            name,
-                            change,
-                            reply_userdata: event.reply_userdata,
-                        })
-                    }))
-                }
-            }
-            mpv_event_id::QueueOverflow => Some(Ok(Event::QueueOverflow)),
-            _ => Some(Ok(Event::Deprecated(event))),
-        }
-    }
-
-    /// Set a custom function that should be called when there are new events. Use this if
-    /// blocking in [wait_event](#method.wait_event) to wait for new events is not feasible.
-    ///
-    /// Keep in mind that the callback will be called from foreign threads. You must not make
-    /// any assumptions of the environment, and you must return as soon as possible (i.e. no
-    /// long blocking waits). Exiting the callback through any other means than a normal return
-    /// is forbidden (no throwing exceptions, no `longjmp()` calls). You must not change any
-    /// local thread state (such as the C floating point environment).
-    ///
-    /// You are not allowed to call any client API functions inside of the callback. In
-    /// particular, you should not do any processing in the callback, but wake up another
-    /// thread that does all the work. The callback is meant strictly for notification only,
-    /// and is called from arbitrary core parts of the player, that make no considerations for
-    /// reentrant API use or allowing the callee to spend a lot of time doing other things.
-    /// Keep in mind that it’s also possible that the callback is called from a thread while a
-    /// mpv API function is called (i.e. it can be reentrant).
-    ///
-    /// In general, the client API expects you to call [wait_event](#method.wait_event) to receive
-    /// notifications, and the wakeup callback is merely a helper utility to make this easier in
-    /// certain situations. Note that it’s possible that there’s only one wakeup callback
-    /// invocation for multiple events. You should call [wait_event](#method.wait_event) with no timeout until
-    /// `None` is returned, at which point the event queue is empty.
-    ///
-    /// If you actually want to do processing in a callback, spawn a thread that does nothing but
-    /// call [wait_event](#method.wait_event) in a loop and dispatches the result to a callback.
-    ///
-    /// Only one wakeup callback can be set.
-    pub fn set_wakeup_callback<F: Fn() + Send + 'static>(&mut self, callback: F) {
-        if let Some(wakeup_callback_cleanup) = self.wakeup_callback_cleanup.take() {
-            wakeup_callback_cleanup();
-        }
-        let raw_callback = Box::into_raw(Box::new(callback));
-        self.wakeup_callback_cleanup = Some(Box::new(move || unsafe {
-            drop(Box::from_raw(raw_callback));
-        }) as Box<dyn FnOnce()>);
-        unsafe {
-            libmpv2_sys::mpv_set_wakeup_callback(
-                self.ctx.as_ptr(),
-                Some(wu_wrapper::<F>),
-                raw_callback as *mut c_void,
-            );
-        }
-    }
-}
-
-impl Drop for EventContext {
-    fn drop(&mut self) {
-        if let Some(wakeup_callback_cleanup) = self.wakeup_callback_cleanup.take() {
-            wakeup_callback_cleanup();
-        }
-    }
-}