0
0
mirror of https://github.com/mpv-player/mpv.git synced 2024-09-19 19:42:24 +02:00

client API: add API function that ensures total destruction

mpv_destroy() should perhaps better be called mpv_detach(), because it
destroys only the handle, not necessarily the player. The player is only
terminated if a quit command is sent.

This function quits automatically, and additionally waits until the
player is completely destroyed. It removes the possibility that the
player core is still uninitializing, while all client handles are
already destroyed. (Although in practice, the difference is usually not
important.)
This commit is contained in:
wm4 2014-06-07 15:08:45 +02:00
parent d64bd9efa1
commit 500ce69a06
4 changed files with 55 additions and 3 deletions

View File

@ -316,10 +316,27 @@ int mpv_initialize(mpv_handle *ctx);
* Disconnect and destroy the client context. ctx will be deallocated with this
* API call. This leaves the player running. If you want to be sure that the
* player is terminated, send a "quit" command, and wait until the
* MPV_EVENT_SHUTDOWN event is received.
* MPV_EVENT_SHUTDOWN event is received, or use mpv_terminate_destroy().
*/
void mpv_destroy(mpv_handle *ctx);
/**
* Similar to mpv_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 mpv_destroy() is that while mpv_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_handles are detached),
* and also waits for the final termination of the player.
*
* Since mpv_destroy() is called somewhere on the way, it's not safe to call
* other functions concurrently on the same context.
*
* If this is called on a mpv_handle that was not created with mpv_create(),
* this function will merely send a quit command and then call mpv_destroy(),
* without waiting for the actual shutdown.
*/
void mpv_terminate_destroy(mpv_handle *ctx);
/**
* Load a config file. This loads and parses the file, and sets every entry in
* the config file's default section as if mpv_set_option_string() is called.

View File

@ -77,6 +77,7 @@ struct observe_property {
struct mpv_handle {
// -- immmutable
char *name;
bool owner;
struct mp_log *log;
struct MPContext *mpctx;
struct mp_client_api *clients;
@ -299,11 +300,41 @@ void mpv_destroy(mpv_handle *ctx)
assert(!ctx);
}
static void get_thread(void *ptr)
{
*(pthread_t *)ptr = pthread_self();
}
void mpv_terminate_destroy(mpv_handle *ctx)
{
mpv_command(ctx, (const char*[]){"quit", NULL});
if (!ctx->owner) {
mpv_destroy(ctx);
return;
}
mp_dispatch_lock(ctx->mpctx->dispatch);
assert(ctx->mpctx->autodetach);
ctx->mpctx->autodetach = false;
mp_dispatch_unlock(ctx->mpctx->dispatch);
pthread_t playthread;
mp_dispatch_run(ctx->mpctx->dispatch, get_thread, &playthread);
mpv_destroy(ctx);
// And this is also the reason why we only allow 1 thread (the owner) to
// call this function.
pthread_join(playthread, NULL);
}
mpv_handle *mpv_create(void)
{
struct MPContext *mpctx = mp_create();
mpv_handle *ctx = mp_new_client(mpctx->clients, "main");
if (ctx) {
ctx->owner = true;
// Set some defaults.
mpv_set_option_string(ctx, "config", "no");
mpv_set_option_string(ctx, "idle", "yes");
@ -319,8 +350,7 @@ mpv_handle *mpv_create(void)
static void *playback_thread(void *p)
{
struct MPContext *mpctx = p;
pthread_detach(pthread_self());
mpctx->autodetach = true;
mp_play_files(mpctx);

View File

@ -144,6 +144,7 @@ enum {
typedef struct MPContext {
bool initialized;
bool is_cplayer;
bool autodetach;
struct mpv_global *global;
struct MPOpts *opts;
struct mp_log *log;

View File

@ -23,6 +23,7 @@
#include <assert.h>
#include <ctype.h>
#include <string.h>
#include <pthread.h>
#include "config.h"
#include "talloc.h"
@ -148,6 +149,9 @@ void mp_destroy(struct MPContext *mpctx)
}
uninit_libav(mpctx->global);
if (mpctx->autodetach)
pthread_detach(pthread_self());
mp_msg_uninit(mpctx->global);
talloc_free(mpctx);
}