pub struct Client(/* private fields */);
Expand description
An owned client created from a Handle
.
Unlike a Handle
, it is safe to call mpv_destroy
and mpv_terminate_destroy
on an owned Client
; thus the Client::destroy()
and Client::terminate_destroy()
methods are provided here.
Additionally, since mpv_initialize
should only be called on uninitialized instances
of mpv, it only makes sense to call it on a created Client
, so that is exposed here as Client::initialize()
.
All other usage is the same as Handle
.
§Example
#[unsafe(no_mangle)]
extern "C" fn mpv_open_cplugin(ptr: *mut mpv_handle) -> std::os::raw::c_int {
let handle = Handle::from_ptr(ptr);
let second_client = handle.create_client("second client").unwrap();
// Note: in the case of a cplugin, the passed Handle MUST call wait_event
// or else mpv will block the entire program waiting for a sign of life.
let _ = handle.wait_event(-1.0);
loop {
match second_client.wait_event(0.0) {
Err(e) => {
println!("Second client got error: {e:?}");
}
Ok(event) => {
match event {
Event::Shutdown => {
println!("Goodbye from Rust!");
// Clients must be destroyed in a timely manner!
// (though in this case it would get Drop'd anyway...)
second_client.destroy();
// Handles require no additional cleanup!
return 0;
},
Event::None => {},
event => {
println!("Second client got event: {event:?}");
},
}
}
}
}
}
Implementations§
Source§impl Client
impl Client
Sourcepub fn initialize(&self) -> Result<()>
pub fn initialize(&self) -> Result<()>
Initialize an uninitialized mpv instance. If the mpv instance is already running, an Error
is returned.
This function needs to be called to make full use of the client API if the client API handle was created with Handle::create()
.
Only the following options are required to be set before Client::initialize()
:
- options which are only read at initialization time:
config
config-dir
input-conf
load-scripts
script
player-operation-mode
input-app-events
(macOS)
- all encoding mode options
Sourcepub fn destroy(self)
pub fn destroy(self)
Disconnect and destroy the Client
and its underlying Handle
. The underlying mpv_handle
will be deallocated with this API call.
If the last mpv_handle
is detached, the core player is destroyed.
In addition, if there are only weak handles (such as created by Handle::create_weak_client()
or internal scripts), these handles will be sent Event::Shutdown
.
This function may block until these clients have responded to the shutdown event, and the core is finally destroyed.
§Concurrency
Since the underlying mpv_handle
is destroyed somewhere on the way, it’s not safe to call other functions concurrently on the same handle.
§Handles
Note that mpv_destroy()
cannot be called from a cplugin client. The correct way to terminate (given a Handle
) is to return from
the execution environment in which you were provided a mpv_handle
. In the case of a cplugin, this means returning from mpv_open_cplugin()
.
mpv will handle cleaning up the underlying client upon return.
If a Handle
wishes to terminate mpv, send client.command(&["quit"])
before returning from mpv_open_cplugin()
.
Sourcepub fn terminate_destroy(self)
pub fn terminate_destroy(self)
Similar to Client::destroy()
, but brings the player and all clients down as well and waits until all of them are destroyed. This function blocks.
The advantage over Client::destroy()
is that while Client::destroy()
merely detaches the client handle from the player,
this function quits the player, waits until all other clients are destroyed (i.e., all mpv_handle
s are detached), and also waits for the final termination of the player.
§Concurrency
Since the underlying mpv_handle
is destroyed somewhere on the way, it’s not safe to call other functions concurrently on the same handle.
§Handles
Note that mpv_destroy()
cannot be called from a cplugin client. The correct way to terminate (given a Handle
) is to return from
the execution environment in which you were provided a mpv_handle
. In the case of a cplugin, this means returning from mpv_open_cplugin()
.
mpv will handle cleaning up the underlying client upon return.
If a Handle
wishes to terminate mpv, send client.command(&["quit"])
before returning from mpv_open_cplugin()
.
Methods from Deref<Target = Handle>§
Sourcepub fn client_name(&self) -> Result<String>
pub fn client_name(&self) -> Result<String>
Return the name of this client Handle
.
Every client has its own unique name, which is mostly used for user interface purposes.
Sourcepub fn client_id(&self) -> i64
pub fn client_id(&self) -> i64
Return the ID of this client Handle
.
Every client has its own unique ID. This ID is never reused by the core, even if the Handle
at hand gets destroyed and new handles get allocated.
Some mpv APIs (not necessarily all) accept a name in the form @id
in addition to the proper Handle::client_name()
, where id
is the ID in decimal form (e.g. @123
).
For example, the script-message-to
command takes the client name as the first argument but also accepts the client ID formatted in this manner.
Sourcepub fn create_client(&self, name: &str) -> Result<Client>
pub fn create_client(&self, name: &str) -> Result<Client>
Create a new Client
connected to the same player core as self
.
This context has its own event queue, its own Handle::request_event()
state, its own Handle::request_log_messages()
state,
its own set of observed properties, and its own state for asynchronous operations. Otherwise, everything is shared.
This client should be destroyed with Client::destroy()
if no longer needed.
The core will live as long as there is at least 1 handle referencing it.
Any handle can make the core quit, which will result in every handle receiving Event::Shutdown
.
Sourcepub fn create_weak_client(&self, name: &str) -> Result<Client>
pub fn create_weak_client(&self, name: &str) -> Result<Client>
This is the same as Handle::create_client()
, but the created mpv_handle
is treated as a weak reference.
If all handles referencing a core are weak references, the core is automatically destroyed. (This still goes through normal shutdown, of course.
Effectively, if the last non-weak handle is destroyed, then the weak handles receive Event::Shutdown
and are asked to terminate as well.)
Note if you want to use this like refcounting: you have to be aware that Client::terminate_destroy()
and Client::destroy()
for the last non-weak mpv_handle
will block until all weak handles are destroyed.
Sourcepub fn load_config_file(&self, filename: &str) -> Result<()>
pub fn load_config_file(&self, filename: &str) -> Result<()>
Load a config file. This parses the file and sets every entry in the config file’s default section as if Handle::set_option()
is called.
The filename should be an absolute path. If it isn’t, the actual path used is unspecified. (Note: an absolute path starts with ‘/
’ on UNIX.)
If the file wasn’t found, Error::InvalidParameter
is returned.
If a fatal error happens when parsing a config file, Error::OptionError
is returned.
Errors when setting options as well as other types or errors are ignored (even if options do not exist).
You can still try to capture the resulting error messages with Handle::request_log_messages()
.
Note that it’s possible that some options were successfully set even if any of these errors happen.
Sourcepub fn get_time_ns(&self) -> i64
pub fn get_time_ns(&self) -> i64
Return the internal time in nanoseconds. This has an arbitrary start offset but will never wrap or go backwards.
Note that this is always the real time and doesn’t necessarily have to do with playback time.
For example, playback could go faster or slower due to playback speed, or due to playback being paused.
Use the time-pos
property instead to get the playback status.
Unlike other libmpv APIs, this can be called at absolutely any time (even within wakeup callbacks), as long as the Handle
is valid.
Safe to be called from mpv render API threads.
Sourcepub fn get_time_us(&self) -> i64
pub fn get_time_us(&self) -> i64
Same as Handle::get_time_ns
but in microseconds.
Sourcepub fn set_option<T: MpvSend>(&self, name: &str, data: T) -> Result<()>
👎Deprecated: For most purposes, this is not needed anymore.Starting with mpv version 0.21.0 (version 1.23) most options can be set with Handle::set_property()
(and related functions), and even before Handle::initialize()
.In some obscure corner cases, using this function to set options might still be required (see “Inconsistencies between options and properties” in the manpage).Once these are resolved, the option setting functions might be fully deprecated.
pub fn set_option<T: MpvSend>(&self, name: &str, data: T) -> Result<()>
Handle::set_property()
(and related functions), and even before Handle::initialize()
.In some obscure corner cases, using this function to set options might still be required (see “Inconsistencies between options and properties” in the manpage).Once these are resolved, the option setting functions might be fully deprecated.Set an option. Note that you can’t normally set options during runtime. It works in an uninitialized state (see Handle::create()
), and in some cases in at runtime.
Using a format other than Node
is equivalent to constructing a Node
with the given format and data and passing it to this function.
§Example
handle.set_option("idle", "yes")?;
Sourcepub fn command(&self, command: &[impl AsRef<str>]) -> Result<()>
pub fn command(&self, command: &[impl AsRef<str>]) -> Result<()>
Send a command to the player. Commands are the same as those used in input.conf
, except that this function takes parameters in a pre-split form.
The commands and their parameters are documented in input.rst.
Does not use OSD and string expansion by default (unlike Handle::command_string()
and input.conf).
§Params
command
- Usually, the first item is the command, and the following items are arguments.
§Example
handle.command(&["script-message-to", "commands", "type", "seek absolute-percent", "6"])?;
Sourcepub fn command_node(&self, command: Node) -> Result<Node>
pub fn command_node(&self, command: Node) -> Result<Node>
Same as Handle::command_ret()
, but allows passing structured data in any format.
In particular, calling Handle::command()
is exactly like calling Handle::command_node()
with the format set to NodeArray
,
and every arg passed in order as String
.
Does not use OSD and string expansion by default.
§Params
The command
Node
can be one of the following formats:
Node::Array
: Positional arguments. Each entry is an argument using an arbitrary format (the format must be compatible with the used command). Usually, the first item is the command name (as aNode::String
). The order of arguments is as documented in each command description.Node::Map
: Named arguments. This requires at least an entry with the key “name” to be present, which must be a string and contain the command name. The special entry “_flags” is optional, and if present, must be an array of strings, each being a command prefix to apply. All other entries are interpreted as arguments. They must use the argument names as documented in each command description. Some commands do not support named arguments at all and must useNode::Array
.
§Return
If the function succeeds, Result<Node>
is command-specific return data. Few commands actually use this.
§Example
// For convenience, you use node_array!(), which accepts any arbitrary types
// implementing Into<Node> and produces a Node::Array...
handle.command_node(node_array!("frame-step", 20, "mute"))?;
// ...or node_map!(), which is similar but takes (Into<String>, Into<Node>) tuples
// and produces a Node::Map.
handle.command_node(node_map! {
("name", "show-text"),
("text", "peekaboo!"),
("duration", 500),
})?;
Sourcepub fn command_ret(&self, command: &[impl AsRef<str>]) -> Result<Node>
pub fn command_ret(&self, command: &[impl AsRef<str>]) -> Result<Node>
This is essentially identical to Handle::command()
, but it also returns a result.
Does not use OSD and string expansion by default.
§Params
command
- Usually, the first item is the command, and the following items are arguments.
§Return
If the function succeeds, Result<Node>
is command-specific return data. Few commands actually use this.
Sourcepub fn command_string(&self, command: &str) -> Result<()>
pub fn command_string(&self, command: &str) -> Result<()>
Same as Handle::command()
, but use input.conf parsing for splitting arguments.
This is slightly simpler, but also more error-prone, since arguments may need quoting/escaping.
This also has OSD and string expansion enabled by default.
Sourcepub fn set_property<T: MpvSend>(&self, name: &str, value: T) -> Result<()>
pub fn set_property<T: MpvSend>(&self, name: &str, value: T) -> Result<()>
Set a property to a given value.
Properties are essentially variables that can be queried or set at runtime. For example, writing to the pause property will actually pause or unpause playback.
§Params
If the MpvFormat::MPV_FORMAT
of value
doesn’t match with the internal mpv_format
format of the property,
access usually will fail with Error::PropertyFormat
.
In some cases, the data is automatically converted and access succeeds. For example, mpv converts i64
to f64
,
and access using String
usually invokes a string parser.
The same happens when calling this function with Node
: the underlying format may be converted to another type if possible.
Using a format other than Node
is equivalent to constructing a Node
with the given format and data and passing it to this function.
§Example
handle.set_property("chapter", 3)?;
Sourcepub fn del_property(&self, name: &str) -> Result<()>
pub fn del_property(&self, name: &str) -> Result<()>
Convenience function to delete a property.
This is equivalent to running the command del [name]
.
Sourcepub fn get_property<T: MpvRecv>(&self, name: &str) -> Result<T>
pub fn get_property<T: MpvRecv>(&self, name: &str) -> Result<T>
Read the value of the given property.
If the MpvFormat::MPV_FORMAT
of the requested type doesn’t match with the internal mpv_format
format of the property,
access usually will fail with Error::PropertyFormat
.
In some cases, the data is automatically converted and access succeeds. For example, i64
is always converted to f64
,
and access using String
usually invokes a string formatter.
§Example
// use turbofish...
let duration = handle.get_property::<f64>("duration")?;
// or explicitly type the assignment...
let node: Node = handle.get_property("metadata")?;
Sourcepub fn observe_property(
&self,
name: &str,
format: Format,
userdata: u64,
) -> Result<()>
pub fn observe_property( &self, name: &str, format: Format, userdata: u64, ) -> Result<()>
Get a notification whenever the given property changes.
You will receive updates as Event::PropertyChange
. Note that this is not very precise: for some properties, it may not send updates even if the property changed.
This depends on the property, and it’s a valid feature request to ask for better update handling of a specific property.
(For some properties, like clock
, which shows the wall clock, this mechanism doesn’t make too much sense anyway.)
Property changes are coalesced: the change events are returned only once the event queue becomes empty
(e.g., Handle::wait_event()
would block or return Event::None
), and then only one event per changed property is returned.
You always get an initial change notification. This is meant to initialize the user’s state to the current value of the property.
Normally, change events are sent only if the property value changes within the requested format.
PropertyChange.value
will contain the PropertyValue
.
If the property is observed with the format parameter set to PropertyValue::None
, you get low-level notifications whether the property may have changed.
With this mode, you will have to determine yourself whether the property really changed. On the other hand, this mechanism can be faster and use fewer resources.
Observing a property that doesn’t exist is allowed. (Although it may still cause some sporadic change events.)
Keep in mind that you will get Event::PropertyChange
even if you change a property yourself.
Try to avoid endless feedback loops, which could happen if you react to the change notifications triggered by your own change.
Only the Handle
on which this was called will receive Event::PropertyChange
events or can unobserve them.
§Warning
If a property is unavailable or retrieving it caused an error, Event::PropertyChange
’s PropertyChange.value
will be PropertyValue::None
,
even if the format parameter was set to a different value.
§Params
-
userdata
: This will be used for thePropertyChange.userdata
field for the receivedEvent::PropertyChange
events.If you have no use for this, pass 0.
Also see Handle::unobserve_property()
.
§Example
// you can set userdata = 0 if you don't plan un unobserving the value later
handle.observe_property("playtime-remaining", Format::DOUBLE, 0)?;
Sourcepub fn unobserve_property(&self, userdata: u64) -> Result<i32>
pub fn unobserve_property(&self, userdata: u64) -> Result<i32>
Undo Handle::observe_property
.
This will remove all observed properties for which the given number was passed as userdata
to Handle::observe_property()
.
§Params
userdata
:userdata
that was passed toHandle::observe_property()
§Returns
Result<i32>
contains the number of properties removed on success.
§Example
// if you want to later unobserve a property, you must provide a userdata
let media_title_userdata: u64 = 12345; // arbitrary, user-defined value
handle.observe_property("media-title", Format::STRING, media_title_userdata)?;
// later...
handle.unobserve_property(media_title_userdata)?;
Sourcepub fn request_event(&self, event_id: EventId, enable: bool) -> Result<()>
pub fn request_event(&self, event_id: EventId, enable: bool) -> Result<()>
Enable or disable an Event
given its EventId
.
Some events are enabled by default. Some events can’t be disabled.
(Informational note: currently, all events are enabled by default, except Event::Tick
.)
Sourcepub fn request_log_messages(&self, max_level: LogLevel) -> Result<()>
pub fn request_log_messages(&self, max_level: LogLevel) -> Result<()>
Enable or disable receiving of log messages.
These are the messages the command line player prints to the terminal.
This call sets the maximum log level for a message to be received with Event::LogMessage
.
§Params
max_level
: Maximum log level to subscribe to.
The value LogLevel::None
disables all messages. This is the default.
Sourcepub fn wait_event(&self, timeout: f64) -> Result<Event>
pub fn wait_event(&self, timeout: f64) -> Result<Event>
Wait for the next event, or until the timeout expires, or if another thread makes a call to Handle::wakeup()
.
See Event
for the possible events.
§Params
timeout
: Timeout in seconds, after which the function returns even if no event was received. AnEvent::None
is returned on timeout.- A value of 0 will disable waiting and is suitable for polling.
- Negative values will wait with an infinite timeout.
§Warning
The internal event queue has a limited size (per client handle). If you don’t empty the event queue quickly enough with Handle::wait_event()
,
it will overflow and silently discard further events. If this happens, making asynchronous requests will fail as well (with Error::EventQueueFull
).
§Concurrency
Only one thread is allowed to call this on the same Handle
at a time. The API won’t complain if more than one thread calls this,
but it will cause race conditions in the client when accessing the shared mpv_event
struct.
Note that most other API functions are not restricted by this, and no API function internally calls Handle::wait_event()
.
Additionally, concurrent calls to different Handle
s are always safe.
§Example
match handle.wait_event(0.0)? {
Event::None => println!("No event was ready yet!"),
Event::Shutdown => {
println!("Shutting down!");
// You must cleanly exit after receiving Event::Shutdown, or else you'll hang mpv.
return Ok(());
}
Event::LogMessage(log_message) => println!("Got a log message: {log_message:?}"),
event => println!("Got an other event: {event:?}"),
}
§Warning
cplugins must call Handle::wait_event()
at least once after initialization;
mpv will block awaiting a sign of life:.
#[unsafe(no_mangle)]
extern "C" fn mpv_open_cplugin(ptr: *mut mpv_handle) -> std::os::raw::c_int {
let handle = Handle::from_ptr(ptr);
println!("Sleeping 5 seconds pre-wait_event...");
// mpv will be completely hung during this sleep...
sleep(Duration::from_secs(5));
// Let mpv know we're alive!
let _ = handle.wait_event(-1.0);
println!("Sleeping 15 seconds post-wait_event...");
// mpv will operate normally during this sleep.
sleep(Duration::from_secs(15));
return 0;
}
Sourcepub fn wakeup(&self)
pub fn wakeup(&self)
Interrupt the current Handle::wait_event()
call.
This will wake up the thread currently waiting in Handle::wait_event()
. If no thread is waiting, the next Handle::wait_event()
call will return immediately (this is to avoid lost wakeups).
Handle::wait_event()
will receive an Event::None
if it’s woken up due to this call. But note that this dummy event might be
skipped if there are already other events queued. All that counts is that the waiting thread is woken up.
Sourcepub fn hook_add(&self, userdata: u64, name: &str, priority: i32) -> Result<()>
pub fn hook_add(&self, userdata: u64, name: &str, priority: i32) -> Result<()>
A hook is like a synchronous event that blocks the player. You register a hook handler with this function. You will get an event,
which you need to handle, and once things are ready, you can let the player continue with Handle::hook_continue()
.
Currently, hooks can’t be removed explicitly. But they will be implicitly removed if the Handle
it was registered with is destroyed.
This also continues the hook if it was being handled by the destroyed handle (but this should be avoided, as it might mess up the order of hook execution).
See the “Hooks” section in the manpage to see which hooks are currently defined.
Some hooks might be reentrant (so you get multiple Event::Hook
for the same hook). If this can happen for a specific hook type,
it will be explicitly documented in the manpage.
Only the Handle
on which this was called will receive the hook events or can “continue” them.
§Priority
Hook handlers are ordered globally by priority and order of registration. Handlers for the same hook with the same priority are invoked in order of registration (the handler registered first is run first). Handlers with lower priority are run first (which seems backward).
§Params
userdata
: This will be used for theEvent::Hook.userdata
field for the receivedEvent::Hook
events. If you have no use for this, pass 0.name
: The hook name. This should be one of the documented names. But if the name is unknown, the hook event will simply never be raised.priority
: See remarks above. Use 0 as a neutral default.
Sourcepub fn hook_continue(&self, id: u64) -> Result<()>
pub fn hook_continue(&self, id: u64) -> Result<()>
Respond to an Event::Hook
event. You must call this after you have handled the event.
There is no way to “cancel” or “stop” the hook.
Calling this will typically unblock the player for whatever the hook is responsible for (e.g., for the on_load
hook it lets it continue playback).
§Params
id
: This must be the value of theHook.id
field for the correspondingEvent::Hook
.
§Warning
It is explicitly undefined behavior to call this more than once for each Event::Hook
, to pass an incorrect ID,
or to call this on a Handle
different from the one that registered the handler and received the event.
§Example
match handle.wait_event(0.0)? {
Event::Hook(hook) => {
do_something_during_hook();
// You MUST call hook_continue() on the provided Hook.id,
// or else you'll hang mpv.
handle.hook_continue(hook.id)?;
}
// ...
event => {}
}