~alpine/aports

community/mpv: add sndio output support (ported from an openbsd patch) v1 REJECTED

james palmer: 2
 community/mpv: add sndio output support (ported from an openbsd patch)
 community/mpv: add sndio output support (ported from an openbsd patch)
mailinglist-bot: 1
 community/mpv: add sndio output support (ported from an openbsd patch)

 6 files changed, 1152 insertions(+), 9 deletions(-)
Export patchset (mbox)
How do I use this?

Copy & paste the following snippet into your terminal to import this patchset into git:

curl -s https://lists.alpinelinux.org/~alpine/aports/patches/3912/mbox | git am -3
Learn more about email & git

[PATCH] community/mpv: add sndio output support (ported from an openbsd patch) Export this patch

---
 community/mpv/APKBUILD    |  10 +-
 community/mpv/sndio.patch | 377 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 384 insertions(+), 3 deletions(-)
 create mode 100644 community/mpv/sndio.patch

diff --git a/community/mpv/APKBUILD b/community/mpv/APKBUILD
index d644626250..7ef545a519 100644
--- a/community/mpv/APKBUILD
+++ b/community/mpv/APKBUILD
@@ -5,7 +5,7 @@
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
pkgname=mpv
pkgver=0.34.1
pkgrel=1
pkgrel=2
pkgdesc="Video player based on MPlayer/mplayer2"
url="https://mpv.io/"
license="GPL-2.0-or-later"
@@ -53,6 +53,7 @@ makedepends="
	x264-dev
	xvidcore-dev
	zlib-dev
	sndio-dev
	"
subpackages="
	$pkgname-doc
@@ -61,7 +62,8 @@ subpackages="
	$pkgname-bash-completion
	$pkgname-zsh-completion
	"
source="https://github.com/mpv-player/mpv/archive/v$pkgver/mpv-$pkgver.tar.gz"
source="https://github.com/mpv-player/mpv/archive/v$pkgver/mpv-$pkgver.tar.gz
	sndio.patch"

# secfixes:
#   0.27.0-r3:
@@ -91,7 +93,8 @@ build() {
		--enable-vulkan \
		--enable-uchardet \
		--enable-cdda \
		--enable-dvdnav
		--enable-dvdnav \
		--enable-sndio
	python3 waf build
}

@@ -114,4 +117,5 @@ package() {

sha512sums="
77ea349d6999f8cce9b5cce4cebd3506a224fc18ab08d22dd16bd34c34d012bb170879b268ddd62db40d116b4cc0b2d9d651b8097f387ed9115c426834cac77e  mpv-0.34.1.tar.gz
84bed23d81115efa82f4fd97259e4b0bc9a9d727c8354d79de85d2f74622cefa0d0e34d84fe6ddce110bcf783ef587564009eacb0697ef243cb0180b45d7392e  sndio.patch
"
diff --git a/community/mpv/sndio.patch b/community/mpv/sndio.patch
new file mode 100644
index 0000000000..71d0b53d7e
--- /dev/null
+++ b/community/mpv/sndio.patch
@@ -0,0 +1,377 @@
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -51,6 +51,7 @@
 extern const struct ao_driver audio_out_pcm;
 extern const struct ao_driver audio_out_lavc;
 extern const struct ao_driver audio_out_sdl;
+extern const struct ao_driver audio_out_sndio;
 
 static const struct ao_driver * const audio_out_drivers[] = {
 // native:
@@ -87,6 +88,9 @@
 #endif
 #if HAVE_SDL2_AUDIO
     &audio_out_sdl,
+#endif
+#if HAVE_SNDIO
+    &audio_out_sndio,
 #endif
     &audio_out_null,
 #if HAVE_COREAUDIO
--- 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.
--- /dev/null
+++ b/audio/out/ao_sndio.c
@@ -0,0 +1,317 @@
+/*
+ * 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[MP_NUM_CHANNELS + 1] = {
+    {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;
+    
+    if (!p->playing)
+        return;
+    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);
+    for (i = 0, ap = af_to_par;; i++, ap++) {
+        if (i == MP_ARRAY_SIZE(af_to_par)) {
+            MP_VERBOSE(ao, "unsupported format\n");
+            p->par.bits = 16;
+            p->par.sig = 1;
+            p->par.le = SIO_LE_NATIVE;
+            break;
+        }
+        if (ap->format == ao->format) {
+            p->par.bits = ap->bits;
+            p->par.sig = ap->sig;
+            if (ap->bits > 8)
+                p->par.le = SIO_LE_NATIVE;
+            if (ap->bits != SIO_BPS(ap->bits))
+                p->par.bps = ap->bits / 8;
+            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 = calloc(sio_nfds(p->hdl), sizeof(struct pollfd));
+    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;
+    }
+    free(p->pfd);
+    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;
+
+    process_events(ao);
+    p->delay = 0;
+    p->playing = false;
+
+    /* XXX: some times may block here then sndiod used. */
+    if (!sio_stop(p->hdl)) {
+        MP_ERR(ao, "reset: couldn't sio_stop()\n");
+reinit:
+        /* Without this device will never work again. */
+        MP_WARN(ao, "Force reinitialize audio device.\n");
+        uninit(ao);
+        init(ao);
+        return;
+    }
+    if (!sio_start(p->hdl)) {
+        MP_ERR(ao, "reset: sio_start() fail.\n");
+        goto reinit;
+    }
+}
+
+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;
+    process_events(ao);
+
+    return true;
+}
+
+static void get_state(struct ao *ao, struct mp_pcm_state *state)
+{
+    struct priv *p = ao->priv;
+
+    process_events(ao);
+
+    state->free_samples = (ao->device_buffer - p->delay);
+    state->queued_samples = p->delay;
+    state->delay = (p->delay / (double)p->par.rate);
+    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),
+};
--- a/wscript
+++ b/wscript
@@ -473,6 +473,10 @@
         'desc': 'WASAPI audio output',
         'deps': 'os-win32 || os-cygwin',
         'func': check_cc(fragment=load_fragment('wasapi.c')),
+    }, {
+        'name': '--sndio',
+        'desc': 'sndio audio output',
+        'func': check_pkg_config('sndio')
     }
 ]
 
--- a/wscript_build.py
+++ b/wscript_build.py
@@ -248,6 +248,7 @@
         ( "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.35.0

[PATCH v2] community/mpv: add sndio output support (ported from an openbsd patch) Export this patch

---
 community/mpv/APKBUILD    |  10 +-
 community/mpv/sndio.patch | 377 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 384 insertions(+), 3 deletions(-)
 create mode 100644 community/mpv/sndio.patch

diff --git a/community/mpv/APKBUILD b/community/mpv/APKBUILD
index d644626250..c2d3346a22 100644
--- a/community/mpv/APKBUILD
+++ b/community/mpv/APKBUILD
@@ -5,7 +5,7 @@
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
pkgname=mpv
pkgver=0.34.1
pkgrel=1
pkgrel=2
pkgdesc="Video player based on MPlayer/mplayer2"
url="https://mpv.io/"
license="GPL-2.0-or-later"
@@ -43,6 +43,7 @@ makedepends="
	py3-docutils
	python3
	shaderc-dev
	sndio-dev
	ttf-dejavu
	uchardet-dev
	vulkan-headers
@@ -61,7 +62,8 @@ subpackages="
	$pkgname-bash-completion
	$pkgname-zsh-completion
	"
source="https://github.com/mpv-player/mpv/archive/v$pkgver/mpv-$pkgver.tar.gz"
source="https://github.com/mpv-player/mpv/archive/v$pkgver/mpv-$pkgver.tar.gz
	sndio.patch"

# secfixes:
#   0.27.0-r3:
@@ -91,7 +93,8 @@ build() {
		--enable-vulkan \
		--enable-uchardet \
		--enable-cdda \
		--enable-dvdnav
		--enable-dvdnav \
		--enable-sndio
	python3 waf build
}

@@ -114,4 +117,5 @@ package() {

sha512sums="
77ea349d6999f8cce9b5cce4cebd3506a224fc18ab08d22dd16bd34c34d012bb170879b268ddd62db40d116b4cc0b2d9d651b8097f387ed9115c426834cac77e  mpv-0.34.1.tar.gz
84bed23d81115efa82f4fd97259e4b0bc9a9d727c8354d79de85d2f74622cefa0d0e34d84fe6ddce110bcf783ef587564009eacb0697ef243cb0180b45d7392e  sndio.patch
"
diff --git a/community/mpv/sndio.patch b/community/mpv/sndio.patch
new file mode 100644
index 0000000000..71d0b53d7e
--- /dev/null
+++ b/community/mpv/sndio.patch
@@ -0,0 +1,377 @@
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -51,6 +51,7 @@
 extern const struct ao_driver audio_out_pcm;
 extern const struct ao_driver audio_out_lavc;
 extern const struct ao_driver audio_out_sdl;
+extern const struct ao_driver audio_out_sndio;
 
 static const struct ao_driver * const audio_out_drivers[] = {
 // native:
@@ -87,6 +88,9 @@
 #endif
 #if HAVE_SDL2_AUDIO
     &audio_out_sdl,
+#endif
+#if HAVE_SNDIO
+    &audio_out_sndio,
 #endif
     &audio_out_null,
 #if HAVE_COREAUDIO
--- 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.
--- /dev/null
+++ b/audio/out/ao_sndio.c
@@ -0,0 +1,317 @@
+/*
+ * 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[MP_NUM_CHANNELS + 1] = {
+    {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;
+    
+    if (!p->playing)
+        return;
+    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);
+    for (i = 0, ap = af_to_par;; i++, ap++) {
+        if (i == MP_ARRAY_SIZE(af_to_par)) {
+            MP_VERBOSE(ao, "unsupported format\n");
+            p->par.bits = 16;
+            p->par.sig = 1;
+            p->par.le = SIO_LE_NATIVE;
+            break;
+        }
+        if (ap->format == ao->format) {
+            p->par.bits = ap->bits;
+            p->par.sig = ap->sig;
+            if (ap->bits > 8)
+                p->par.le = SIO_LE_NATIVE;
+            if (ap->bits != SIO_BPS(ap->bits))
+                p->par.bps = ap->bits / 8;
+            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 = calloc(sio_nfds(p->hdl), sizeof(struct pollfd));
+    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;
+    }
+    free(p->pfd);
+    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;
+
+    process_events(ao);
+    p->delay = 0;
+    p->playing = false;
+
+    /* XXX: some times may block here then sndiod used. */
+    if (!sio_stop(p->hdl)) {
+        MP_ERR(ao, "reset: couldn't sio_stop()\n");
+reinit:
+        /* Without this device will never work again. */
+        MP_WARN(ao, "Force reinitialize audio device.\n");
+        uninit(ao);
+        init(ao);
+        return;
+    }
+    if (!sio_start(p->hdl)) {
+        MP_ERR(ao, "reset: sio_start() fail.\n");
+        goto reinit;
+    }
+}
+
+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;
+    process_events(ao);
+
+    return true;
+}
+
+static void get_state(struct ao *ao, struct mp_pcm_state *state)
+{
+    struct priv *p = ao->priv;
+
+    process_events(ao);
+
+    state->free_samples = (ao->device_buffer - p->delay);
+    state->queued_samples = p->delay;
+    state->delay = (p->delay / (double)p->par.rate);
+    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),
+};
--- a/wscript
+++ b/wscript
@@ -473,6 +473,10 @@
         'desc': 'WASAPI audio output',
         'deps': 'os-win32 || os-cygwin',
         'func': check_cc(fragment=load_fragment('wasapi.c')),
+    }, {
+        'name': '--sndio',
+        'desc': 'sndio audio output',
+        'func': check_pkg_config('sndio')
     }
 ]
 
--- a/wscript_build.py
+++ b/wscript_build.py
@@ -248,6 +248,7 @@
         ( "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.35.0

Re: [PATCH] community/mpv: add sndio output support (ported from an openbsd patch) Export this patch

On Thu, 27 Jan 2022 18:49:37 +0000, james palmer wrote:
>  	xvidcore-dev
>  	zlib-dev
> +	sndio-dev
james palmer <james@biobuf.link> replied via email:

```
---
 community/mpv/APKBUILD    |  10 +-
 community/mpv/sndio.patch | 377 ++++++++++++++++++++++++++++++++++++++
 2 files changed, 384 insertions(+), 3 deletions(-)
 create mode 100644 community/mpv/sndio.patch

diff --git a/community/mpv/APKBUILD b/community/mpv/APKBUILD
index d644626250..c2d3346a22 100644
--- a/community/mpv/APKBUILD
+++ b/community/mpv/APKBUILD
@@ -5,7 +5,7 @@
# Maintainer: Natanael Copa <ncopa@alpinelinux.org>
pkgname=mpv
pkgver=0.34.1
pkgrel=1
pkgrel=2
pkgdesc="Video player based on MPlayer/mplayer2"
url="https://mpv.io/"
license="GPL-2.0-or-later"
@@ -43,6 +43,7 @@ makedepends="
	py3-docutils
	python3
	shaderc-dev
	sndio-dev
	ttf-dejavu
	uchardet-dev
	vulkan-headers
@@ -61,7 +62,8 @@ subpackages="
	$pkgname-bash-completion
	$pkgname-zsh-completion
	"
source="https://github.com/mpv-player/mpv/archive/v$pkgver/mpv-$pkgver.tar.gz"
source="https://github.com/mpv-player/mpv/archive/v$pkgver/mpv-$pkgver.tar.gz
	sndio.patch"

# secfixes:
#   0.27.0-r3:
@@ -91,7 +93,8 @@ build() {
		--enable-vulkan \
		--enable-uchardet \
		--enable-cdda \
		--enable-dvdnav
		--enable-dvdnav \
		--enable-sndio
	python3 waf build
}

@@ -114,4 +117,5 @@ package() {

sha512sums="
77ea349d6999f8cce9b5cce4cebd3506a224fc18ab08d22dd16bd34c34d012bb170879b268ddd62db40d116b4cc0b2d9d651b8097f387ed9115c426834cac77e  mpv-0.34.1.tar.gz
84bed23d81115efa82f4fd97259e4b0bc9a9d727c8354d79de85d2f74622cefa0d0e34d84fe6ddce110bcf783ef587564009eacb0697ef243cb0180b45d7392e  sndio.patch
"
diff --git a/community/mpv/sndio.patch b/community/mpv/sndio.patch
new file mode 100644
index 0000000000..71d0b53d7e
--- /dev/null
+++ b/community/mpv/sndio.patch
@@ -0,0 +1,377 @@
--- a/audio/out/ao.c
+++ b/audio/out/ao.c
@@ -51,6 +51,7 @@
 extern const struct ao_driver audio_out_pcm;
 extern const struct ao_driver audio_out_lavc;
 extern const struct ao_driver audio_out_sdl;
+extern const struct ao_driver audio_out_sndio;
 
 static const struct ao_driver * const audio_out_drivers[] = {
 // native:
@@ -87,6 +88,9 @@
 #endif
 #if HAVE_SDL2_AUDIO
     &audio_out_sdl,
+#endif
+#if HAVE_SNDIO
+    &audio_out_sndio,
 #endif
     &audio_out_null,
 #if HAVE_COREAUDIO
--- 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.
--- /dev/null
+++ b/audio/out/ao_sndio.c
@@ -0,0 +1,317 @@
+/*
+ * 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[MP_NUM_CHANNELS + 1] = {
+    {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;
+    
+    if (!p->playing)
+        return;
+    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);
+    for (i = 0, ap = af_to_par;; i++, ap++) {
+        if (i == MP_ARRAY_SIZE(af_to_par)) {
+            MP_VERBOSE(ao, "unsupported format\n");
+            p->par.bits = 16;
+            p->par.sig = 1;
+            p->par.le = SIO_LE_NATIVE;
+            break;
+        }
+        if (ap->format == ao->format) {
+            p->par.bits = ap->bits;
+            p->par.sig = ap->sig;
+            if (ap->bits > 8)
+                p->par.le = SIO_LE_NATIVE;
+            if (ap->bits != SIO_BPS(ap->bits))
+                p->par.bps = ap->bits / 8;
+            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 = calloc(sio_nfds(p->hdl), sizeof(struct pollfd));
+    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;
+    }
+    free(p->pfd);
+    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;
+
+    process_events(ao);
+    p->delay = 0;
+    p->playing = false;
+
+    /* XXX: some times may block here then sndiod used. */
+    if (!sio_stop(p->hdl)) {
+        MP_ERR(ao, "reset: couldn't sio_stop()\n");
+reinit:
+        /* Without this device will never work again. */
+        MP_WARN(ao, "Force reinitialize audio device.\n");
+        uninit(ao);
+        init(ao);
+        return;
+    }
+    if (!sio_start(p->hdl)) {
+        MP_ERR(ao, "reset: sio_start() fail.\n");
+        goto reinit;
+    }
+}
+
+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;
+    process_events(ao);
+
+    return true;
+}
+
+static void get_state(struct ao *ao, struct mp_pcm_state *state)
+{
+    struct priv *p = ao->priv;
+
+    process_events(ao);
+
+    state->free_samples = (ao->device_buffer - p->delay);
+    state->queued_samples = p->delay;
+    state->delay = (p->delay / (double)p->par.rate);
+    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),
+};
--- a/wscript
+++ b/wscript
@@ -473,6 +473,10 @@
         'desc': 'WASAPI audio output',
         'deps': 'os-win32 || os-cygwin',
         'func': check_cc(fragment=load_fragment('wasapi.c')),
+    }, {
+        'name': '--sndio',
+        'desc': 'sndio audio output',
+        'func': check_pkg_config('sndio')
     }
 ]
 
--- a/wscript_build.py
+++ b/wscript_build.py
@@ -248,6 +248,7 @@
         ( "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.35.0


```

-- 
via https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/30064#note_210009