Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions DOCS/client-api-changes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ API changes

::

--- mpv 0.41.0 ---
2.6 - add mpv_set_audio_callback()
--- mpv 0.40.0 ---
2.5 - Deprecate MPV_RENDER_PARAM_AMBIENT_LIGHT. no replacement.
--- mpv 0.39.0 ---
Expand Down
2 changes: 2 additions & 0 deletions audio/out/ao.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ extern const struct ao_driver audio_out_opensles;
extern const struct ao_driver audio_out_null;
extern const struct ao_driver audio_out_alsa;
extern const struct ao_driver audio_out_wasapi;
extern const struct ao_driver audio_out_libmpv;
extern const struct ao_driver audio_out_pcm;
extern const struct ao_driver audio_out_lavc;
extern const struct ao_driver audio_out_sdl;
Expand Down Expand Up @@ -104,6 +105,7 @@ static const struct ao_driver * const audio_out_drivers[] = {
#if HAVE_COREAUDIO
&audio_out_coreaudio_exclusive,
#endif
&audio_out_libmpv,
&audio_out_pcm,
&audio_out_lavc,
};
Expand Down
107 changes: 107 additions & 0 deletions audio/out/ao_libmpv.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/*
* libmpv audio output driver
*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/

#include "ao.h"
#include "audio/format.h"
#include "ao_libmpv.h"
#include "internal.h"
#include "common/msg.h"

struct priv {
void (*write_cb)(void *userdata, const void *data, int bytes);
void *userdata;
};

void ao_libmpv_set_cb(struct ao *ao, void (*cb)(void *userdata, const void *data, int bytes), void *userdata)
{
struct priv *p = ao->priv;
p->write_cb = cb;
p->userdata = userdata;
}

static int init(struct ao *ao)
{
ao->format = af_fmt_from_planar(ao->format);

struct mp_chmap_sel sel = {0};
mp_chmap_sel_add_waveext(&sel);
if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
return -1;

ao->bps = ao->channels.num * (int64_t)ao->samplerate * af_fmt_to_bytes(ao->format);

MP_INFO(ao, "libmpv: Samplerate: %d Hz Channels: %d Format: %s\n",
ao->samplerate, ao->channels.num, af_fmt_to_str(ao->format));
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does the client find out which format the blob of data he gets is, anyway?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the audio current audio format can be grabbed as a property, though I suppose I could just pass that in the callback as well

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's also async, so won't work reliably.

I think it would be more practical if sample rate and channels were set ahead of time and then the driver would only support s16.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Correct me if I'm wrong, but it's already possible to set the format with this option before mpv initializes, so I think that should cover it. I might just add a note about it in the docs.

{"audio-format", OPT_AUDIOFORMAT(audio_output_format), .flags = UPDATE_AUDIO},

If that's not enough I could also add an option specific to this ao, I'd prefer to keep it configurable since I personally would like the samples as floats, it saves me an extra conversion step.


ao->untimed = true;
ao->device_buffer = 1 << 16;

return 0;
}

static void uninit(struct ao *ao)
{
}

static bool audio_write(struct ao *ao, void **data, int samples)
{
struct priv *priv = ao->priv;
const int len = samples * ao->sstride;

if (priv->write_cb)
priv->write_cb(priv->userdata, data[0], len);

return true;
}

static void get_state(struct ao *ao, struct mp_pcm_state *state)
{
state->free_samples = ao->device_buffer;
state->queued_samples = 0;
state->delay = 0;
}

static bool set_pause(struct ao *ao, bool paused)
{
return true; // signal support so common code doesn't write silence
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so the client is not informed of a pause situation?


static void start(struct ao *ao)
{
// we use data immediately
}

static void reset(struct ao *ao)
{
}

#define OPT_BASE_STRUCT struct priv

const struct ao_driver audio_out_libmpv = {
.description = "libmpv audio output with a callback",
.name = "libmpv",
.init = init,
.uninit = uninit,
.get_state = get_state,
.set_pause = set_pause,
.write = audio_write,
.start = start,
.reset = reset,
.priv_size = sizeof(struct priv),
};
24 changes: 24 additions & 0 deletions audio/out/ao_libmpv.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/*
* libmpv audio output driver
*
* This file is part of mpv.
*
* mpv is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* mpv is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with mpv. If not, see <http://www.gnu.org/licenses/>.
*/

#pragma once

#include "ao.h"

void ao_libmpv_set_cb(struct ao *ao, void (*cb)(void *userdata, const void *data, int bytes), void *userdata);
14 changes: 13 additions & 1 deletion include/mpv/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ extern "C" {
* relational operators (<, >, <=, >=).
*/
#define MPV_MAKE_VERSION(major, minor) (((major) << 16) | (minor) | 0UL)
#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(2, 5)
#define MPV_CLIENT_API_VERSION MPV_MAKE_VERSION(2, 6)

/**
* The API user is allowed to "#define MPV_ENABLE_DEPRECATED 0" before
Expand Down Expand Up @@ -1768,6 +1768,18 @@ MPV_EXPORT void mpv_wakeup(mpv_handle *ctx);
*/
MPV_EXPORT void mpv_set_wakeup_callback(mpv_handle *ctx, void (*cb)(void *d), void *d);

/**
* Set a custom function that should be called on new audio data.
* Raw PCM is passed in as an argument to the callback, the format should be set before init using appropriate options.
*
* This can only be used with ao_libmpv and must be called before the ao is initialized (so before playback starts).
* Only one audio callback can be set per instance.
*
* @param cb function that should be called on audio data
* @param d arbitrary userdata passed to cb
*/
MPV_EXPORT void mpv_set_audio_callback(mpv_handle *ctx, void (*cb)(void *d, const void *data, int bytes), void *d);

/**
* Block until all asynchronous requests are done. This affects functions like
* mpv_command_async(), which return immediately and return their result as
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ sources = files(
'audio/out/ao.c',
'audio/out/ao_lavc.c',
'audio/out/ao_null.c',
'audio/out/ao_libmpv.c',
'audio/out/ao_pcm.c',
'audio/out/buffer.c',

Expand Down
5 changes: 5 additions & 0 deletions player/audio.c
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
#include <limits.h>
#include <math.h>
#include <assert.h>
#include <audio/out/ao_libmpv.h>
#include <audio/out/internal.h>

#include "mpv_talloc.h"

Expand Down Expand Up @@ -447,6 +449,9 @@
mpctx, mpctx->encode_lavc_ctx, out_rate,
out_format, out_channels);

if (strcmp(mpctx->ao->driver->name, "libmpv") == 0)

Check failure

Code scanning / ClusterFuzzLite/CIFuzz

Don't crash Error

Null-dereference
ao_libmpv_set_cb(mpctx->ao, mpctx->ao_libmpv_cb, mpctx->ao_libmpv_userdata);

int ao_rate = 0;
int ao_format = 0;
struct mp_chmap ao_channels = {0};
Expand Down
13 changes: 13 additions & 0 deletions player/client.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@
#include "core.h"
#include "client.h"

#include <audio/out/internal.h>
#include <audio/out/ao_libmpv.h>

/*
* Locking hierarchy:
*
Expand Down Expand Up @@ -2245,3 +2248,13 @@ bool mp_streamcb_lookup(struct mpv_global *g, const char *protocol,
mp_mutex_unlock(&clients->lock);
return found;
}

void mpv_set_audio_callback(mpv_handle *ctx, void (*cb)(void *userdata, const void *data, int bytes), void *userdata)
{
lock_core(ctx);

ctx->mpctx->ao_libmpv_cb = cb;
ctx->mpctx->ao_libmpv_userdata = userdata;

unlock_core(ctx);
}
4 changes: 4 additions & 0 deletions player/core.h
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,10 @@ typedef struct MPContext {
struct mp_aframe *ao_filter_fmt; // for weak gapless audio check
struct ao_chain *ao_chain;

// Callback that will be set for ao_libmpv
void (*ao_libmpv_cb)(void *userdata, const void *data, int bytes);
void *ao_libmpv_userdata;

struct vo_chain *vo_chain;

struct vo *video_out;
Expand Down
Loading