mpv-0.33.1-sndio_pr9298.patch (11999B)
- From d41e8d39dd1de81aa5f56bb1aa4d9fffc1a2ef3d Mon Sep 17 00:00:00 2001
- From: rim <rozhuk.im@gmail.com>
- Date: Mon, 18 Oct 2021 23:55:49 +0200
- Subject: [PATCH] ao_sndio: add this audio output again
- Changes:
- - rewrite to use new internal MPV API;
- - code refactoring;
- - fix buffers size calculations;
- - buffer set to auto;
- - reset() - clean/reinit device only after errors;
- ---
- DOCS/man/ao.rst | 6 +
- audio/out/ao.c | 4 +
- audio/out/ao_sndio.c | 311 +++++++++++++++++++++++++++++++++++++++++++
- wscript | 6 +
- wscript_build.py | 1 +
- 5 files changed, 328 insertions(+)
- create mode 100644 audio/out/ao_sndio.c
- diff --git a/DOCS/man/ao.rst b/DOCS/man/ao.rst
- index cc42ec23a6..1f9bf915b3 100644
- --- a/DOCS/man/ao.rst
- +++ b/DOCS/man/ao.rst
- @@ -216,5 +216,11 @@ Available audio output drivers are:
- ``no-waveheader`` option - with ``waveheader`` it's broken, because
- it will write a WAVE header every time the file is opened.
- +``sndio``
- + Audio output to the OpenBSD sndio sound system
- +
- + (Note: only supports mono, stereo, 4.0, 5.1 and 7.1 channel
- + layouts.)
- +
- ``wasapi``
- Audio output to the Windows Audio Session API.
- diff --git a/audio/out/ao.c b/audio/out/ao.c
- index 52a38b63be..00893c0eb3 100644
- --- a/audio/out/ao.c
- +++ b/audio/out/ao.c
- @@ -40,6 +40,7 @@ extern const struct ao_driver audio_out_audiounit;
- extern const struct ao_driver audio_out_coreaudio;
- extern const struct ao_driver audio_out_coreaudio_exclusive;
- extern const struct ao_driver audio_out_rsound;
- +extern const struct ao_driver audio_out_sndio;
- extern const struct ao_driver audio_out_pulse;
- extern const struct ao_driver audio_out_jack;
- extern const struct ao_driver audio_out_openal;
- @@ -83,6 +84,9 @@ static const struct ao_driver * const audio_out_drivers[] = {
- #endif
- #if HAVE_SDL2_AUDIO
- &audio_out_sdl,
- +#endif
- +#if HAVE_SNDIO
- + &audio_out_sndio,
- #endif
- &audio_out_null,
- #if HAVE_COREAUDIO
- diff --git a/audio/out/ao_sndio.c b/audio/out/ao_sndio.c
- new file mode 100644
- index 0000000000..ec2fb3bcb6
- --- /dev/null
- +++ b/audio/out/ao_sndio.c
- @@ -0,0 +1,311 @@
- +/*
- + * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- + * Copyright (c) 2013 Christian Neukirchen <chneukirchen@gmail.com>
- + * Copyright (c) 2020 Rozhuk Ivan <rozhuk.im@gmail.com>
- + *
- + * Permission to use, copy, modify, and distribute this software for any
- + * purpose with or without fee is hereby granted, provided that the above
- + * copyright notice and this permission notice appear in all copies.
- + *
- + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- + */
- +
- +#include "config.h"
- +
- +#include <sys/types.h>
- +#include <poll.h>
- +#include <errno.h>
- +#include <sndio.h>
- +
- +#include "options/m_option.h"
- +#include "common/msg.h"
- +
- +#include "audio/format.h"
- +#include "ao.h"
- +#include "internal.h"
- +
- +struct priv {
- + struct sio_hdl *hdl;
- + struct sio_par par;
- + int delay;
- + bool playing;
- + int vol;
- + int havevol;
- + struct pollfd *pfd;
- +};
- +
- +
- +static const struct mp_chmap sndio_layouts[] = {
- + {0}, /* empty */
- + {1, {MP_SPEAKER_ID_FL}}, /* mono */
- + MP_CHMAP2(FL, FR), /* stereo */
- + {0}, /* 2.1 */
- + MP_CHMAP4(FL, FR, BL, BR), /* 4.0 */
- + {0}, /* 5.0 */
- + MP_CHMAP6(FL, FR, BL, BR, FC, LFE), /* 5.1 */
- + {0}, /* 6.1 */
- + MP_CHMAP8(FL, FR, BL, BR, FC, LFE, SL, SR), /* 7.1 */
- + /* Above is the fixed channel assignment for sndio, since we need to
- + * fill all channels and cannot insert silence, not all layouts are
- + * supported.
- + * NOTE: MP_SPEAKER_ID_NA could be used to add padding channels. */
- +};
- +
- +static void uninit(struct ao *ao);
- +
- +
- +/* Make libsndio call movecb(). */
- +static void process_events(struct ao *ao)
- +{
- + struct priv *p = ao->priv;
- +
- + int n = sio_pollfd(p->hdl, p->pfd, POLLOUT);
- + while (poll(p->pfd, n, 0) < 0 && errno == EINTR);
- +
- + sio_revents(p->hdl, p->pfd);
- +}
- +
- +/* Call-back invoked to notify of the hardware position. */
- +static void movecb(void *addr, int delta)
- +{
- + struct ao *ao = addr;
- + struct priv *p = ao->priv;
- +
- + p->delay -= delta;
- +}
- +
- +/* Call-back invoked to notify about volume changes. */
- +static void volcb(void *addr, unsigned newvol)
- +{
- + struct ao *ao = addr;
- + struct priv *p = ao->priv;
- +
- + p->vol = newvol;
- +}
- +
- +static int init(struct ao *ao)
- +{
- + struct priv *p = ao->priv;
- + struct mp_chmap_sel sel = {0};
- + size_t i;
- + struct af_to_par {
- + int format, bits, sig;
- + };
- + static const struct af_to_par af_to_par[] = {
- + {AF_FORMAT_U8, 8, 0},
- + {AF_FORMAT_S16, 16, 1},
- + {AF_FORMAT_S32, 32, 1},
- + };
- + const struct af_to_par *ap;
- + const char *device = ((ao->device) ? ao->device : SIO_DEVANY);
- +
- + /* Opening device. */
- + MP_VERBOSE(ao, "Using '%s' audio device.\n", device);
- + p->hdl = sio_open(device, SIO_PLAY, 0);
- + if (p->hdl == NULL) {
- + MP_ERR(ao, "Can't open audio device %s.\n", device);
- + goto err_out;
- + }
- +
- + sio_initpar(&p->par);
- +
- + /* Selecting sound format. */
- + ao->format = af_fmt_from_planar(ao->format);
- +
- + p->par.bits = 16;
- + p->par.sig = 1;
- + p->par.le = SIO_LE_NATIVE;
- + for (i = 0; i < MP_ARRAY_SIZE(af_to_par); i++) {
- + ap = &af_to_par[i];
- + if (ap->format == ao->format) {
- + p->par.bits = ap->bits;
- + p->par.sig = ap->sig;
- + break;
- + }
- + }
- +
- + p->par.rate = ao->samplerate;
- +
- + /* Channels count. */
- + for (i = 0; i < MP_ARRAY_SIZE(sndio_layouts); i++) {
- + mp_chmap_sel_add_map(&sel, &sndio_layouts[i]);
- + }
- + if (!ao_chmap_sel_adjust(ao, &sel, &ao->channels))
- + goto err_out;
- +
- + p->par.pchan = ao->channels.num;
- +#ifdef __FreeBSD__
- + /* OSS wrapper have bad defaults, overwrite it. */
- + p->par.appbufsz = ((p->par.rate * 25) / 1000); /* 25 ms. */
- +#endif
- + if (!sio_setpar(p->hdl, &p->par)) {
- + MP_ERR(ao, "couldn't set params\n");
- + goto err_out;
- + }
- +
- + /* Get current sound params. */
- + if (!sio_getpar(p->hdl, &p->par)) {
- + MP_ERR(ao, "couldn't get params\n");
- + goto err_out;
- + }
- + if (p->par.bps > 1 && p->par.le != SIO_LE_NATIVE) {
- + MP_ERR(ao, "swapped endian output not supported\n");
- + goto err_out;
- + }
- +
- + /* Update sound params. */
- + if (p->par.bits == 8 && p->par.bps == 1 && !p->par.sig) {
- + ao->format = AF_FORMAT_U8;
- + } else if (p->par.bits == 16 && p->par.bps == 2 && p->par.sig) {
- + ao->format = AF_FORMAT_S16;
- + } else if ((p->par.bits == 32 || p->par.msb) && p->par.bps == 4 && p->par.sig) {
- + ao->format = AF_FORMAT_S32;
- + } else {
- + MP_ERR(ao, "couldn't set format\n");
- + goto err_out;
- + }
- +
- + p->havevol = sio_onvol(p->hdl, volcb, ao);
- + sio_onmove(p->hdl, movecb, ao);
- +
- + p->pfd = talloc_array_ptrtype(p, p->pfd, sio_nfds(p->hdl));
- + if (!p->pfd)
- + goto err_out;
- +
- + ao->device_buffer = p->par.bufsz;
- + MP_VERBOSE(ao, "bufsz = %i, appbufsz = %i, round = %i\n",
- + p->par.bufsz, p->par.appbufsz, p->par.round);
- +
- + p->delay = 0;
- + p->playing = false;
- + if (!sio_start(p->hdl)) {
- + MP_ERR(ao, "start: sio_start() fail.\n");
- + goto err_out;
- + }
- +
- + return 0;
- +
- +err_out:
- + uninit(ao);
- + return -1;
- +}
- +
- +static void uninit(struct ao *ao)
- +{
- + struct priv *p = ao->priv;
- +
- + if (p->hdl) {
- + sio_close(p->hdl);
- + p->hdl = NULL;
- + }
- + p->pfd = NULL;
- + p->playing = false;
- +}
- +
- +static int control(struct ao *ao, enum aocontrol cmd, void *arg)
- +{
- + struct priv *p = ao->priv;
- + ao_control_vol_t *vol = arg;
- +
- + switch (cmd) {
- + case AOCONTROL_GET_VOLUME:
- + if (!p->havevol)
- + return CONTROL_FALSE;
- + vol->left = vol->right = p->vol * 100 / SIO_MAXVOL;
- + break;
- + case AOCONTROL_SET_VOLUME:
- + if (!p->havevol)
- + return CONTROL_FALSE;
- + sio_setvol(p->hdl, vol->left * SIO_MAXVOL / 100);
- + break;
- + default:
- + return CONTROL_UNKNOWN;
- + }
- + return CONTROL_OK;
- +}
- +
- +static void reset(struct ao *ao)
- +{
- + struct priv *p = ao->priv;
- +
- + if (p->playing) {
- + p->playing = false;
- +
- + if (!sio_stop(p->hdl)) {
- + MP_ERR(ao, "reset: couldn't sio_stop()\n");
- + }
- + p->delay = 0;
- + if (!sio_start(p->hdl)) {
- + MP_ERR(ao, "reset: sio_start() fail.\n");
- + }
- + }
- +}
- +
- +static void start(struct ao *ao)
- +{
- + struct priv *p = ao->priv;
- +
- + p->playing = true;
- + process_events(ao);
- +}
- +
- +static bool audio_write(struct ao *ao, void **data, int samples)
- +{
- + struct priv *p = ao->priv;
- + const size_t size = (samples * ao->sstride);
- + size_t rc;
- +
- + rc = sio_write(p->hdl, data[0], size);
- + if (rc != size) {
- + MP_WARN(ao, "audio_write: unexpected partial write: required: %zu, written: %zu.\n",
- + size, rc);
- + reset(ao);
- + p->playing = false;
- + return false;
- + }
- + p->delay += samples;
- +
- + return true;
- +}
- +
- +static void get_state(struct ao *ao, struct mp_pcm_state *state)
- +{
- + struct priv *p = ao->priv;
- +
- + process_events(ao);
- +
- + /* how many samples we can play without blocking */
- + state->free_samples = ao->device_buffer - p->delay;
- + /* how many samples are already in the buffer to be played */
- + state->queued_samples = p->delay;
- + /* delay in seconds between first and last sample in buffer */
- + state->delay = p->delay / (double)p->par.rate;
- +
- + /* reset on unexpected EOF / underrun */
- + if (state->queued_samples && state->queued_samples &&
- + state->queued_samples < state->free_samples &&
- + p->playing)
- + {
- + reset(ao);
- + }
- + state->playing = p->playing;
- +}
- +
- +const struct ao_driver audio_out_sndio = {
- + .name = "sndio",
- + .description = "sndio audio output",
- + .init = init,
- + .uninit = uninit,
- + .control = control,
- + .reset = reset,
- + .start = start,
- + .write = audio_write,
- + .get_state = get_state,
- + .priv_size = sizeof(struct priv),
- +};
- diff --git a/wscript b/wscript
- index b81f1202ec..e9af544b0c 100644
- --- a/wscript
- +++ b/wscript
- @@ -421,6 +421,12 @@ audio_output_features = [
- 'desc': 'SDL2 audio output',
- 'deps': 'sdl2',
- 'func': check_true,
- + }, {
- + 'name': '--sndio',
- + 'desc': 'sndio audio input/output',
- + 'func': check_statement('sndio.h',
- + 'struct sio_par par; sio_initpar(&par); const char *s = SIO_DEVANY', lib='sndio'),
- + 'default': 'disable'
- }, {
- 'name': '--pulse',
- 'desc': 'PulseAudio audio output',
- diff --git a/wscript_build.py b/wscript_build.py
- index 14c254e1ec..7943f850b0 100644
- --- a/wscript_build.py
- +++ b/wscript_build.py
- @@ -247,6 +247,7 @@ def build(ctx):
- ( "audio/out/ao_pcm.c" ),
- ( "audio/out/ao_pulse.c", "pulse" ),
- ( "audio/out/ao_sdl.c", "sdl2-audio" ),
- + ( "audio/out/ao_sndio.c", "sndio" ),
- ( "audio/out/ao_wasapi.c", "wasapi" ),
- ( "audio/out/ao_wasapi_changenotify.c", "wasapi" ),
- ( "audio/out/ao_wasapi_utils.c", "wasapi" ),
- --
- 2.32.0