1use std::ffi::{c_void, CStr};
4use libmpv_client_sys::{mpv_event, mpv_event_client_message, mpv_event_command, mpv_event_end_file, mpv_event_hook, mpv_event_id, mpv_event_id_MPV_EVENT_AUDIO_RECONFIG, mpv_event_id_MPV_EVENT_CLIENT_MESSAGE, mpv_event_id_MPV_EVENT_COMMAND_REPLY, mpv_event_id_MPV_EVENT_END_FILE, mpv_event_id_MPV_EVENT_FILE_LOADED, mpv_event_id_MPV_EVENT_GET_PROPERTY_REPLY, mpv_event_id_MPV_EVENT_HOOK, mpv_event_id_MPV_EVENT_IDLE, mpv_event_id_MPV_EVENT_LOG_MESSAGE, mpv_event_id_MPV_EVENT_PLAYBACK_RESTART, mpv_event_id_MPV_EVENT_PROPERTY_CHANGE, mpv_event_id_MPV_EVENT_QUEUE_OVERFLOW, mpv_event_id_MPV_EVENT_SEEK, mpv_event_id_MPV_EVENT_SET_PROPERTY_REPLY, mpv_event_id_MPV_EVENT_SHUTDOWN, mpv_event_id_MPV_EVENT_START_FILE, mpv_event_id_MPV_EVENT_TICK, mpv_event_id_MPV_EVENT_VIDEO_RECONFIG, mpv_event_log_message, mpv_event_property, mpv_event_start_file, mpv_format};
5use crate::*;
6use crate::error::error_to_result_code;
7use crate::types::traits::MpvRecvInternal;
8
9pub struct EventId(pub(crate) mpv_event_id);
11
12impl EventId {
13 pub const SHUTDOWN: EventId = EventId(mpv_event_id_MPV_EVENT_SHUTDOWN);
15 pub const LOG_MESSAGE: EventId = EventId(mpv_event_id_MPV_EVENT_LOG_MESSAGE);
17 pub const GET_PROPERTY_REPLY: EventId = EventId(mpv_event_id_MPV_EVENT_GET_PROPERTY_REPLY);
19 pub const SET_PROPERTY_REPLY: EventId = EventId(mpv_event_id_MPV_EVENT_SET_PROPERTY_REPLY);
21 pub const COMMAND_REPLY: EventId = EventId(mpv_event_id_MPV_EVENT_COMMAND_REPLY);
23 pub const START_FILE: EventId = EventId(mpv_event_id_MPV_EVENT_START_FILE);
25 pub const END_FILE: EventId = EventId(mpv_event_id_MPV_EVENT_END_FILE);
27 pub const FILE_LOADED: EventId = EventId(mpv_event_id_MPV_EVENT_FILE_LOADED);
29 pub const IDLE: EventId = EventId(mpv_event_id_MPV_EVENT_IDLE);
31 pub const TICK: EventId = EventId(mpv_event_id_MPV_EVENT_TICK);
33 pub const CLIENT_MESSAGE: EventId = EventId(mpv_event_id_MPV_EVENT_CLIENT_MESSAGE);
35 pub const VIDEO_RECONFIG: EventId = EventId(mpv_event_id_MPV_EVENT_VIDEO_RECONFIG);
37 pub const AUDIO_RECONFIG: EventId = EventId(mpv_event_id_MPV_EVENT_AUDIO_RECONFIG);
39 pub const SEEK: EventId = EventId(mpv_event_id_MPV_EVENT_SEEK);
41 pub const PLAYBACK_RESTART: EventId = EventId(mpv_event_id_MPV_EVENT_PLAYBACK_RESTART);
43 pub const PROPERTY_CHANGE: EventId = EventId(mpv_event_id_MPV_EVENT_PROPERTY_CHANGE);
45 pub const QUEUE_OVERFLOW: EventId = EventId(mpv_event_id_MPV_EVENT_QUEUE_OVERFLOW);
47 pub const HOOK: EventId = EventId(mpv_event_id_MPV_EVENT_HOOK);
49}
50
51#[derive(Debug)]
53pub enum LogLevel {
54 None,
56 Fatal,
58 Error,
60 Warn,
62 Info,
64 Verbose,
66 Debug,
68 Trace,
70}
71
72const LOG_LEVEL_NONE: &CStr = c"no";
73const LOG_LEVEL_FATAL: &CStr = c"fatal";
74const LOG_LEVEL_ERROR: &CStr = c"error";
75const LOG_LEVEL_WARN: &CStr = c"warn";
76const LOG_LEVEL_INFO: &CStr = c"info";
77const LOG_LEVEL_VERBOSE: &CStr = c"v";
78const LOG_LEVEL_DEBUG: &CStr = c"debug";
79const LOG_LEVEL_TRACE: &CStr = c"trace";
80
81impl LogLevel {
82 pub(crate) fn to_cstr(&self) -> &CStr {
83 match self {
84 LogLevel::None => LOG_LEVEL_NONE,
85 LogLevel::Fatal => LOG_LEVEL_FATAL,
86 LogLevel::Error => LOG_LEVEL_ERROR,
87 LogLevel::Warn => LOG_LEVEL_WARN,
88 LogLevel::Info => LOG_LEVEL_INFO,
89 LogLevel::Verbose => LOG_LEVEL_VERBOSE,
90 LogLevel::Debug => LOG_LEVEL_DEBUG,
91 LogLevel::Trace => LOG_LEVEL_TRACE,
92 }
93 }
94}
95
96#[derive(Debug)]
98pub enum EndFileReason {
99 Eof,
104 Stop,
106 Quit,
108 Error(Error),
112 Redirect,
117}
118
119#[derive(Debug)]
123pub enum Event {
124 None,
126 Shutdown,
132 LogMessage(LogMessage),
134 GetPropertyReply(GetPropertyReply),
136 SetPropertyReply(SetPropertyReply),
138 CommandReply(CommandReply),
140 StartFile(StartFile),
142 EndFile(EndFile),
144 FileLoaded,
146 #[deprecated = "This is equivalent to using mpv_observe_property() on the `idle-active` property. The event is redundant, and might be removed in the far future. As a further warning, this event is not necessarily sent at the right point anymore (at the start of the program), while the property behaves correctly."]
152 Idle,
153 #[deprecated = "Use `Handle::observe_property()` with relevant properties instead (such as `playback-time`)."]
157 Tick,
158 ClientMessage(ClientMessage),
162 VideoReconfig,
166 AudioReconfig,
170 Seek,
174 PlaybackRestart,
178 PropertyChange(PropertyChange),
180 QueueOverflow,
186 Hook(Hook),
190}
191
192#[derive(Debug)]
194pub struct LogMessage {
195 pub level: LogLevel,
197 pub prefix: String,
201 pub text: String,
203}
204
205#[derive(Debug)]
207pub struct GetPropertyReply {
208 pub value: Result<PropertyValue>,
210 pub name: String,
212 pub userdata: u64,
215}
216
217#[derive(Debug)]
219pub struct SetPropertyReply {
220 pub error: Result<i32>,
222 pub userdata: u64,
225}
226
227#[derive(Debug)]
229pub struct CommandReply {
230 pub result: Result<Node>,
232 pub userdata: u64,
235}
236
237#[derive(Debug)]
239pub struct StartFile {
240 pub playlist_entry_id: i64,
242}
243
244#[derive(Debug)]
246pub struct EndFile {
247 pub reason: EndFileReason,
249 pub playlist_entry_id: i64,
253 pub playlist_insert_id: i64,
263 pub playlist_insert_num_entries: i32,
267}
268
269#[derive(Debug)]
273pub struct ClientMessage(pub Vec<String>);
274
275#[derive(Debug)]
277pub struct PropertyChange {
278 pub name: String,
280 pub value: Result<PropertyValue>,
285 pub userdata: u64,
288}
289
290#[derive(Debug)]
292pub struct Hook {
293 pub name: String,
295 pub id: u64,
297 pub userdata: u64,
300}
301
302impl Event {
303 pub(crate) fn from_ptr(ptr: *const mpv_event) -> Result<Event> {
304 check_null!(ptr);
305 let event = unsafe { *ptr };
306
307 match event.event_id {
308 libmpv_client_sys::mpv_event_id_MPV_EVENT_NONE => Ok(Event::None),
309 libmpv_client_sys::mpv_event_id_MPV_EVENT_SHUTDOWN => Ok(Event::Shutdown),
310 libmpv_client_sys::mpv_event_id_MPV_EVENT_LOG_MESSAGE => Ok(Event::LogMessage(LogMessage::from_event(event)?)),
311 libmpv_client_sys::mpv_event_id_MPV_EVENT_GET_PROPERTY_REPLY => Ok(Event::GetPropertyReply(GetPropertyReply::from_event(event)?)),
312 libmpv_client_sys::mpv_event_id_MPV_EVENT_SET_PROPERTY_REPLY => Ok(Event::SetPropertyReply(SetPropertyReply::from_event(event)?)),
313 libmpv_client_sys::mpv_event_id_MPV_EVENT_COMMAND_REPLY => Ok(Event::CommandReply(CommandReply::from_event(event)?)),
314 libmpv_client_sys::mpv_event_id_MPV_EVENT_START_FILE => Ok(Event::StartFile(StartFile::from_event(event)?)),
315 libmpv_client_sys::mpv_event_id_MPV_EVENT_END_FILE => Ok(Event::EndFile(EndFile::from_event(event)?)),
316 libmpv_client_sys::mpv_event_id_MPV_EVENT_FILE_LOADED => Ok(Event::FileLoaded),
317 #[allow(deprecated)]
318 libmpv_client_sys::mpv_event_id_MPV_EVENT_IDLE => Ok(Event::Idle),
319 #[allow(deprecated)]
320 libmpv_client_sys::mpv_event_id_MPV_EVENT_TICK => Ok(Event::Tick),
321 libmpv_client_sys::mpv_event_id_MPV_EVENT_CLIENT_MESSAGE => Ok(Event::ClientMessage(ClientMessage::from_event(event)?)),
322 libmpv_client_sys::mpv_event_id_MPV_EVENT_VIDEO_RECONFIG => Ok(Event::VideoReconfig),
323 libmpv_client_sys::mpv_event_id_MPV_EVENT_AUDIO_RECONFIG => Ok(Event::AudioReconfig),
324 libmpv_client_sys::mpv_event_id_MPV_EVENT_SEEK => Ok(Event::Seek),
325 libmpv_client_sys::mpv_event_id_MPV_EVENT_PLAYBACK_RESTART => Ok(Event::PlaybackRestart),
326 libmpv_client_sys::mpv_event_id_MPV_EVENT_PROPERTY_CHANGE => Ok(Event::PropertyChange(PropertyChange::from_event(event)?)),
327 libmpv_client_sys::mpv_event_id_MPV_EVENT_QUEUE_OVERFLOW => Ok(Event::QueueOverflow),
328 libmpv_client_sys::mpv_event_id_MPV_EVENT_HOOK => Ok(Event::Hook(Hook::from_event(event)?)),
329 _ => unimplemented!(),
330 }
331 }
332}
333
334impl LogMessage {
335 fn from_event(event: mpv_event) -> Result<Self> {
336 check_null!(event.data);
337 let event_log_message = unsafe { *(event.data as *const mpv_event_log_message) };
338
339 let level = match event_log_message.log_level {
340 libmpv_client_sys::mpv_log_level_MPV_LOG_LEVEL_FATAL => LogLevel::Fatal,
341 libmpv_client_sys::mpv_log_level_MPV_LOG_LEVEL_ERROR => LogLevel::Error,
342 libmpv_client_sys::mpv_log_level_MPV_LOG_LEVEL_WARN => LogLevel::Warn,
343 libmpv_client_sys::mpv_log_level_MPV_LOG_LEVEL_INFO => LogLevel::Info,
344 libmpv_client_sys::mpv_log_level_MPV_LOG_LEVEL_V => LogLevel::Verbose,
345 libmpv_client_sys::mpv_log_level_MPV_LOG_LEVEL_DEBUG => LogLevel::Debug,
346 libmpv_client_sys::mpv_log_level_MPV_LOG_LEVEL_TRACE => LogLevel::Trace,
347 _ => unimplemented!()
348 };
349
350 check_null!(event_log_message.prefix);
351 let prefix = unsafe { CStr::from_ptr(event_log_message.prefix) }.to_str()?.to_string();
352
353 check_null!(event_log_message.text);
354 let text = unsafe { CStr::from_ptr(event_log_message.text) }.to_str()?.to_string();
355
356 Ok(Self { level, prefix, text })
357 }
358}
359
360impl GetPropertyReply {
361 fn from_event(event: mpv_event) -> Result<Self> {
362 check_null!(event.data);
363 let event_prop = unsafe { *(event.data as *const mpv_event_property) };
364
365 check_null!(event_prop.name);
366 let name = unsafe { CStr::from_ptr(event_prop.name).to_str()?.to_string() };
367
368 let value = error_to_result_code(event.error)
369 .and_then(|_| {
370 unsafe { PropertyValue::from_mpv(event_prop.format, event_prop.data) }
371 });
372
373 let userdata = event.reply_userdata;
374
375 Ok(Self { value, name, userdata })
376 }
377}
378
379impl SetPropertyReply {
380 fn from_event(event: mpv_event) -> Result<Self> {
381 let error = error_to_result_code(event.error);
382
383 let userdata = event.reply_userdata;
384
385 Ok(Self { error, userdata })
386 }
387}
388
389impl CommandReply {
390 fn from_event(event: mpv_event) -> Result<Self> {
391 check_null!(event.data);
392 let event_command = unsafe { *(event.data as *const mpv_event_command) };
393
394 let result = error_to_result_code(event.error)
395 .and_then(|_| {
396 unsafe { Node::from_node_ptr(&event_command.result) }
397 });
398
399 let userdata = event.reply_userdata;
400
401 Ok(Self { result, userdata })
402 }
403}
404
405impl ClientMessage {
406 fn from_event(event: mpv_event) -> Result<Self> {
407 check_null!(event.data);
408 let event_client_message = unsafe { *(event.data as *const mpv_event_client_message) };
409
410 let mut args = Vec::with_capacity(event_client_message.num_args as usize);
411
412 check_null!(event_client_message.args);
413 let event_args = unsafe { std::slice::from_raw_parts(event_client_message.args, event_client_message.num_args as usize) };
414
415 for event_arg in event_args {
416 check_null!(event_arg);
417 args.push(unsafe { CStr::from_ptr(*event_arg).to_str()?.to_string() });
418 }
419
420 Ok(Self(args))
421 }
422}
423
424impl StartFile {
425 fn from_event(event: mpv_event) -> Result<Self> {
426 check_null!(event.data);
427 let event_start_file = unsafe { *(event.data as *const mpv_event_start_file) };
428
429 Ok(Self { playlist_entry_id: event_start_file.playlist_entry_id })
430 }
431}
432
433impl EndFile {
434 fn from_event(event: mpv_event) -> Result<Self> {
435 check_null!(event.data);
436 let event_end_file = unsafe { *(event.data as *const mpv_event_end_file) };
437
438 let reason = match event_end_file.reason {
439 libmpv_client_sys::mpv_end_file_reason_MPV_END_FILE_REASON_EOF => EndFileReason::Eof,
440 libmpv_client_sys::mpv_end_file_reason_MPV_END_FILE_REASON_STOP => EndFileReason::Stop,
441 libmpv_client_sys::mpv_end_file_reason_MPV_END_FILE_REASON_QUIT => EndFileReason::Quit,
442 libmpv_client_sys::mpv_end_file_reason_MPV_END_FILE_REASON_ERROR => EndFileReason::Error(Error::from(event_end_file.error)),
443 libmpv_client_sys::mpv_end_file_reason_MPV_END_FILE_REASON_REDIRECT => EndFileReason::Redirect,
444 _ => unimplemented!(),
445 };
446
447 Ok(Self {
448 reason,
449 playlist_entry_id: event_end_file.playlist_entry_id,
450 playlist_insert_id: event_end_file.playlist_insert_id,
451 playlist_insert_num_entries: event_end_file.playlist_insert_num_entries,
452 })
453 }
454}
455
456impl PropertyChange {
457 fn from_event(event: mpv_event) -> Result<Self> {
458 check_null!(event.data);
459 let event_prop = unsafe { *(event.data as *const mpv_event_property) };
460
461 check_null!(event_prop.name);
462 let name = unsafe { CStr::from_ptr(event_prop.name).to_str()?.to_string() };
463
464 let value = unsafe { PropertyValue::from_mpv(event_prop.format, event_prop.data) };
465
466 let userdata = event.reply_userdata;
467
468 Ok(Self { value, name, userdata })
469 }
470}
471
472impl Hook {
473 fn from_event(event: mpv_event) -> Result<Self> {
474 check_null!(event.data);
475 let event_hook = unsafe { *(event.data as *const mpv_event_hook) };
476
477 check_null!(event_hook.name);
478 let name = unsafe { CStr::from_ptr(event_hook.name) }.to_str()?.to_string();
479
480 let id = event_hook.id;
481
482 let userdata = event.reply_userdata;
483
484 Ok(Self { name, id, userdata })
485 }
486}
487
488#[derive(Debug)]
489pub enum PropertyValue {
491 None,
493 String(String),
495 OsdString(OsdString),
497 Flag(bool),
499 Int64(i64),
501 Double(f64),
503 Node(Node),
505 NodeArray(NodeArray),
507 NodeMap(NodeMap),
509 ByteArray(ByteArray),
511}
512
513impl PropertyValue {
514 pub(crate) unsafe fn from_mpv(format: mpv_format, data: *mut c_void) -> Result<Self> {
515 match format {
516 libmpv_client_sys::mpv_format_MPV_FORMAT_NONE => Ok(Self::None),
517 libmpv_client_sys::mpv_format_MPV_FORMAT_STRING => Ok(Self::String(unsafe { String::from_ptr(data)? })),
518 libmpv_client_sys::mpv_format_MPV_FORMAT_OSD_STRING => Ok(Self::OsdString(unsafe { OsdString::from_ptr(data)? })),
519 libmpv_client_sys::mpv_format_MPV_FORMAT_FLAG => Ok(Self::Flag(unsafe { bool::from_ptr(data)? })),
520 libmpv_client_sys::mpv_format_MPV_FORMAT_INT64 => Ok(Self::Int64(unsafe { i64::from_ptr(data)? })),
521 libmpv_client_sys::mpv_format_MPV_FORMAT_DOUBLE => Ok(Self::Double(unsafe { f64::from_ptr(data)? })),
522 libmpv_client_sys::mpv_format_MPV_FORMAT_NODE => Ok(Self::Node(unsafe { Node::from_ptr(data)? })),
523 libmpv_client_sys::mpv_format_MPV_FORMAT_NODE_ARRAY => Ok(Self::NodeArray(unsafe { NodeArray::from_ptr(data)? })),
524 libmpv_client_sys::mpv_format_MPV_FORMAT_NODE_MAP => Ok(Self::NodeMap(unsafe { NodeMap::from_ptr(data)? })),
525 libmpv_client_sys::mpv_format_MPV_FORMAT_BYTE_ARRAY => Ok(Self::ByteArray(unsafe { ByteArray::from_ptr(data)? })),
526 _ => unimplemented!()
527 }
528 }
529}