summarylogtreecommitdiffstats
diff options
context:
space:
mode:
authorhorstderheld2021-07-14 15:05:05 +0200
committerhorstderheld2021-07-14 15:05:05 +0200
commite2bab472c039a17f9782273391ebcd3b66e1eab8 (patch)
tree5eac1eaf0920a2b794669d8095dd5cea0c7503f2
parentc3fd7e8c90b3a7226af99715ce177102816c63c3 (diff)
downloadaur-e2bab472c039a17f9782273391ebcd3b66e1eab8.tar.gz
add media control by t-8ch
-rw-r--r--.SRCINFO7
-rw-r--r--01-Add-PipeWire-audio-backend-by-Oschowa.patch354
-rw-r--r--02-ao_pipewire-fixes-and-media-control-by-t-8ch.patch209
-rw-r--r--PKGBUILD14
4 files changed, 577 insertions, 7 deletions
diff --git a/.SRCINFO b/.SRCINFO
index 0bbb08e6784c..ae8f7374b2c8 100644
--- a/.SRCINFO
+++ b/.SRCINFO
@@ -1,7 +1,7 @@
pkgbase = mpv-pipewire
pkgdesc = a free, open source, and cross-platform media player including an experimental PipeWire audio backend
pkgver = 0.33.1
- pkgrel = 4
+ pkgrel = 5
url = https://mpv.io/
arch = x86_64
license = GPL3
@@ -83,10 +83,11 @@ pkgbase = mpv-pipewire
conflicts = mpv
options = !emptydirs
source = git+https://github.com/mpv-player/mpv.git#tag=4c9d3669a0f672e6754ac456acd324db570964d3?signed
- source = pipewire.patch::https://github.com/Oschowa/mpv/commit/fddb143282fa74425a8a6f29c9566e51777759d0.patch
+ source = 01-Add-PipeWire-audio-backend-by-Oschowa.patch
+ source = 02-ao_pipewire-fixes-and-media-control-by-t-8ch.patch
validpgpkeys = 145077D82501AA20152CACCE8D769208D5E31419
sha256sums = SKIP
sha256sums = d72a5863bceb5ac542c656ff85a9cb23d27d30c1609022e1b1735744f2777aaf
+ sha256sums = 1b1e69f06225b1f6c9a6ffdc7d3acccfcee3d25c350e4d1a0ab66f5dcb0d3bf3
pkgname = mpv-pipewire
-
diff --git a/01-Add-PipeWire-audio-backend-by-Oschowa.patch b/01-Add-PipeWire-audio-backend-by-Oschowa.patch
new file mode 100644
index 000000000000..3b4d1ea005cb
--- /dev/null
+++ b/01-Add-PipeWire-audio-backend-by-Oschowa.patch
@@ -0,0 +1,354 @@
+From fddb143282fa74425a8a6f29c9566e51777759d0 Mon Sep 17 00:00:00 2001
+From: Oschowa <oschowa@web.de>
+Date: Tue, 3 Nov 2020 11:46:45 +0100
+Subject: [PATCH] Add PipeWire audio backend
+
+based on this original pull request
+https://github.com/mpv-player/mpv/pull/7902 by andreaskem
+---
+ audio/out/ao.c | 4 +
+ audio/out/ao_pipewire.c | 284 ++++++++++++++++++++++++++++++++++++++++
+ wscript | 4 +
+ wscript_build.py | 1 +
+ 4 files changed, 293 insertions(+)
+ create mode 100644 audio/out/ao_pipewire.c
+
+diff --git a/audio/out/ao.c b/audio/out/ao.c
+index 52a38b63be2..74b290c9d9a 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_pipewire;
+ extern const struct ao_driver audio_out_pulse;
+ extern const struct ao_driver audio_out_jack;
+ extern const struct ao_driver audio_out_openal;
+@@ -62,6 +63,9 @@ static const struct ao_driver * const audio_out_drivers[] = {
+ #if HAVE_COREAUDIO
+ &audio_out_coreaudio,
+ #endif
++#if HAVE_PIPEWIRE
++ &audio_out_pipewire,
++#endif
+ #if HAVE_PULSE
+ &audio_out_pulse,
+ #endif
+diff --git a/audio/out/ao_pipewire.c b/audio/out/ao_pipewire.c
+new file mode 100644
+index 00000000000..79965cdc68b
+--- /dev/null
++++ b/audio/out/ao_pipewire.c
+@@ -0,0 +1,284 @@
++
++#include <pipewire/pipewire.h>
++#include <spa/param/audio/format-utils.h>
++
++#include "common/msg.h"
++#include "options/m_config.h"
++#include "options/m_option.h"
++#include "ao.h"
++#include "audio/format.h"
++#include "config.h"
++#include "internal.h"
++#include "osdep/timer.h"
++
++struct ao_pipewire_opts {
++ int buffer_samples;
++};
++
++#define OPT_BASE_STRUCT struct ao_pipewire_opts
++static const struct m_sub_options ao_pipewire_conf = {
++ .opts = (const struct m_option[]) {
++ {"pipewire-buffer-samples", OPT_INT(buffer_samples)},
++ {0}
++ },
++ .defaults = &(const struct ao_pipewire_opts) {
++ .buffer_samples = 2048,
++ },
++ .size = sizeof(struct ao_pipewire_opts),
++};
++
++struct priv {
++ struct pw_thread_loop *loop;
++ struct pw_stream *stream;
++
++ struct ao_pipewire_opts *opts;
++};
++
++static enum spa_audio_format af_fmt_to_pw(enum af_format format)
++{
++ switch (format) {
++ case AF_FORMAT_U8: return SPA_AUDIO_FORMAT_U8;
++ case AF_FORMAT_S16: return SPA_AUDIO_FORMAT_S16;
++ case AF_FORMAT_S32: return SPA_AUDIO_FORMAT_S32;
++ case AF_FORMAT_FLOAT: return SPA_AUDIO_FORMAT_F32;
++ case AF_FORMAT_DOUBLE: return SPA_AUDIO_FORMAT_F64;
++ case AF_FORMAT_U8P: return SPA_AUDIO_FORMAT_U8P;
++ case AF_FORMAT_S16P: return SPA_AUDIO_FORMAT_S16P;
++ case AF_FORMAT_S32P: return SPA_AUDIO_FORMAT_S32P;
++ case AF_FORMAT_FLOATP: return SPA_AUDIO_FORMAT_F32P;
++ case AF_FORMAT_DOUBLEP: return SPA_AUDIO_FORMAT_F64P;
++ default: return SPA_AUDIO_FORMAT_UNKNOWN;
++ }
++}
++
++static const enum spa_audio_channel mp_speaker_id_to_spa[] = {
++ [MP_SPEAKER_ID_FL] = SPA_AUDIO_CHANNEL_FL,
++ [MP_SPEAKER_ID_FR] = SPA_AUDIO_CHANNEL_FR,
++ [MP_SPEAKER_ID_FC] = SPA_AUDIO_CHANNEL_FC,
++ [MP_SPEAKER_ID_LFE] = SPA_AUDIO_CHANNEL_LFE,
++ [MP_SPEAKER_ID_BL] = SPA_AUDIO_CHANNEL_RL,
++ [MP_SPEAKER_ID_BR] = SPA_AUDIO_CHANNEL_RR,
++ [MP_SPEAKER_ID_FLC] = SPA_AUDIO_CHANNEL_FLC,
++ [MP_SPEAKER_ID_FRC] = SPA_AUDIO_CHANNEL_FRC,
++ [MP_SPEAKER_ID_BC] = SPA_AUDIO_CHANNEL_RC,
++ [MP_SPEAKER_ID_SL] = SPA_AUDIO_CHANNEL_SL,
++ [MP_SPEAKER_ID_SR] = SPA_AUDIO_CHANNEL_SR,
++ [MP_SPEAKER_ID_TC] = SPA_AUDIO_CHANNEL_TC,
++ [MP_SPEAKER_ID_TFL] = SPA_AUDIO_CHANNEL_TFL,
++ [MP_SPEAKER_ID_TFC] = SPA_AUDIO_CHANNEL_TFC,
++ [MP_SPEAKER_ID_TFR] = SPA_AUDIO_CHANNEL_TFR,
++ [MP_SPEAKER_ID_TBL] = SPA_AUDIO_CHANNEL_TRL,
++ [MP_SPEAKER_ID_TBC] = SPA_AUDIO_CHANNEL_TRC,
++ [MP_SPEAKER_ID_TBR] = SPA_AUDIO_CHANNEL_TRR,
++ [MP_SPEAKER_ID_DL] = SPA_AUDIO_CHANNEL_FL,
++ [MP_SPEAKER_ID_DR] = SPA_AUDIO_CHANNEL_FR,
++ [MP_SPEAKER_ID_WL] = SPA_AUDIO_CHANNEL_FL,
++ [MP_SPEAKER_ID_WR] = SPA_AUDIO_CHANNEL_FR,
++ [MP_SPEAKER_ID_SDL] = SPA_AUDIO_CHANNEL_SL,
++ [MP_SPEAKER_ID_SDR] = SPA_AUDIO_CHANNEL_SL,
++ [MP_SPEAKER_ID_LFE2] = SPA_AUDIO_CHANNEL_LFE2,
++ [MP_SPEAKER_ID_NA] = SPA_AUDIO_CHANNEL_NA,
++};
++
++static void on_process(void *userdata)
++{
++ struct ao *ao = userdata;
++ struct priv *p = ao->priv;
++ struct pw_time time;
++ struct pw_buffer *b;
++ void *data[MP_NUM_CHANNELS];
++
++ if ((b = pw_stream_dequeue_buffer(p->stream)) == NULL) {
++ pw_log_warn("out of buffers: %m");
++ return;
++ }
++
++ struct spa_buffer *buf = b->buffer;
++
++ int bytes_per_channel = buf->datas[0].maxsize / ao->channels.num;
++ int nframes = bytes_per_channel / ao->sstride;
++
++ for (int i = 0; i < buf->n_datas; i++) {
++ data[i] = buf->datas[i].data;
++ buf->datas[i].chunk->size = bytes_per_channel;
++ buf->datas[i].chunk->offset = 0;
++ }
++
++ pw_stream_get_time(p->stream, &time);
++ if (time.rate.denom == 0)
++ time.rate.denom = ao->samplerate;
++
++ int64_t end_time = mp_time_us();
++ /* time.queued is always going to be 0, so we don't need to care */
++ end_time += (nframes + time.delay) * SPA_USEC_PER_SEC / time.rate.denom;
++
++ ao_read_data(ao, data, nframes, end_time);
++
++ pw_stream_queue_buffer(p->stream, b);
++}
++
++static void on_param_changed(void *userdata, uint32_t id, const struct spa_pod *param)
++{
++ struct ao *ao = userdata;
++ struct priv *p = ao->priv;
++ const struct spa_pod *params[1];
++ uint8_t buffer[1024];
++ struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
++
++ if (param == NULL || id != SPA_PARAM_Format)
++ return;
++
++ int buffer_size = ao->device_buffer * af_fmt_to_bytes(ao->format) * ao->channels.num;
++
++ params[0] = spa_pod_builder_add_object(&b,
++ SPA_TYPE_OBJECT_ParamBuffers, SPA_PARAM_Buffers,
++ SPA_PARAM_BUFFERS_blocks, SPA_POD_Int(ao->num_planes),
++ SPA_PARAM_BUFFERS_size, SPA_POD_Int(buffer_size),
++ SPA_PARAM_BUFFERS_stride, SPA_POD_Int(ao->sstride));
++
++ pw_stream_update_params(p->stream, params, 1);
++}
++
++static void on_state_changed(void *userdata, enum pw_stream_state old, enum pw_stream_state state, const char *error)
++{
++ struct ao *ao = userdata;
++ MP_DBG(ao, "Stream state changed: old_state=%d state=%d error=%s\n", old, state, error);
++
++ if (state == PW_STREAM_STATE_ERROR) {
++ MP_WARN(ao, "Stream in error state, trying to reload...\n");
++ ao_request_reload(ao);
++ }
++}
++
++static const struct pw_stream_events stream_events = {
++ .version = PW_VERSION_STREAM_EVENTS,
++ .param_changed = on_param_changed,
++ .process = on_process,
++ .state_changed = on_state_changed,
++};
++
++static void uninit(struct ao *ao)
++{
++ struct priv *p = ao->priv;
++ if (p->loop)
++ pw_thread_loop_stop(p->loop);
++ if (p->stream)
++ pw_stream_destroy(p->stream);
++ p->stream = NULL;
++ if (p->loop)
++ pw_thread_loop_destroy(p->loop);
++ p->loop = NULL;
++ pw_deinit();
++}
++
++static int init(struct ao *ao)
++{
++ struct priv *p = ao->priv;
++ uint8_t buffer[1024];
++ struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
++ const struct spa_pod *params[1];
++ char latency_str[64];
++
++ p->opts = mp_get_config_group(ao, ao->global, &ao_pipewire_conf);
++
++ enum spa_audio_format spa_format = af_fmt_to_pw(ao->format);
++ if (spa_format == SPA_AUDIO_FORMAT_UNKNOWN) {
++ ao->format = AF_FORMAT_FLOATP;
++ spa_format = SPA_AUDIO_FORMAT_F32P;
++ }
++
++ struct spa_audio_info_raw audio_info = {
++ .format = spa_format,
++ .rate = ao->samplerate,
++ .channels = ao->channels.num,
++ };
++
++ for (int i = 0; i < ao->channels.num; i++)
++ audio_info.position[i] = mp_speaker_id_to_spa[ao->channels.speaker[i]];
++
++ params[0] = spa_format_audio_raw_build(&b, SPA_PARAM_EnumFormat, &audio_info);
++
++ if (af_fmt_is_planar(ao->format)) {
++ ao->num_planes = ao->channels.num;
++ ao->sstride = af_fmt_to_bytes(ao->format);
++ } else {
++ ao->num_planes = 1;
++ ao->sstride = ao->channels.num * af_fmt_to_bytes(ao->format);
++ }
++
++ ao->device_buffer = p->opts->buffer_samples;
++ snprintf(latency_str, sizeof(latency_str), "%d/%d", ao->device_buffer, ao->samplerate);
++
++ pw_init(NULL, NULL);
++
++ p->loop = pw_thread_loop_new("ao-pipewire", NULL);
++ if (p->loop == NULL)
++ goto error;
++
++ p->stream = pw_stream_new_simple(
++ pw_thread_loop_get_loop(p->loop),
++ "audio-src",
++ pw_properties_new(
++ PW_KEY_MEDIA_TYPE, "Audio",
++ PW_KEY_MEDIA_CATEGORY, "Playback",
++ PW_KEY_MEDIA_ROLE, "Music",
++ PW_KEY_NODE_NAME, "mpv",
++ PW_KEY_NODE_LATENCY, latency_str,
++ NULL),
++ &stream_events,
++ ao);
++ if (p->stream == NULL)
++ goto error;
++
++ if (pw_stream_connect(p->stream,
++ PW_DIRECTION_OUTPUT,
++ PW_ID_ANY,
++ PW_STREAM_FLAG_AUTOCONNECT |
++ PW_STREAM_FLAG_MAP_BUFFERS |
++ PW_STREAM_FLAG_RT_PROCESS,
++ params, 1) < 0)
++ goto error;
++
++ if (pw_thread_loop_start(p->loop) < 0)
++ goto error;
++
++ return 0;
++
++error:
++ uninit(ao);
++ return -1;
++}
++
++static void reset(struct ao *ao)
++{
++ struct priv *p = ao->priv;
++ pw_thread_loop_lock(p->loop);
++ pw_stream_set_active(p->stream, false);
++ pw_thread_loop_unlock(p->loop);
++}
++
++static void start(struct ao *ao)
++{
++ struct priv *p = ao->priv;
++ pw_thread_loop_lock(p->loop);
++ pw_stream_set_active(p->stream, true);
++ pw_thread_loop_unlock(p->loop);
++}
++
++const struct ao_driver audio_out_pipewire = {
++ .description = "PipeWire audio output",
++ .name = "pipewire",
++
++ .init = init,
++ .uninit = uninit,
++ .reset = reset,
++ .start = start,
++
++ .priv_size = sizeof(struct priv),
++ .priv_defaults = &(const struct priv)
++ {
++ .loop = NULL,
++ .stream = NULL,
++ },
++ .global_opts = &ao_pipewire_conf,
++};
+diff --git a/wscript b/wscript
+index 86231b79b1b..61e07281053 100644
+--- a/wscript
++++ b/wscript
+@@ -421,6 +421,10 @@ audio_output_features = [
+ 'desc': 'SDL2 audio output',
+ 'deps': 'sdl2',
+ 'func': check_true,
++ }, {
++ 'name': '--pipewire',
++ 'desc': 'PipeWire audio output',
++ 'func': check_pkg_config('libpipewire-0.3', '>= 0.3.0')
+ }, {
+ 'name': '--pulse',
+ 'desc': 'PulseAudio audio output',
+diff --git a/wscript_build.py b/wscript_build.py
+index 14c254e1ec9..4613fabe70f 100644
+--- a/wscript_build.py
++++ b/wscript_build.py
+@@ -245,6 +245,7 @@ def swift(task):
+ ( "audio/out/ao_openal.c", "openal" ),
+ ( "audio/out/ao_opensles.c", "opensles" ),
+ ( "audio/out/ao_pcm.c" ),
++ ( "audio/out/ao_pipewire.c", "pipewire" ),
+ ( "audio/out/ao_pulse.c", "pulse" ),
+ ( "audio/out/ao_sdl.c", "sdl2-audio" ),
+ ( "audio/out/ao_wasapi.c", "wasapi" ),
diff --git a/02-ao_pipewire-fixes-and-media-control-by-t-8ch.patch b/02-ao_pipewire-fixes-and-media-control-by-t-8ch.patch
new file mode 100644
index 000000000000..fd7313e863ba
--- /dev/null
+++ b/02-ao_pipewire-fixes-and-media-control-by-t-8ch.patch
@@ -0,0 +1,209 @@
+From 464391e216400874a46679b6f978e0c36a040e5c Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= <thomas@t-8ch.de>
+Date: Tue, 8 Jun 2021 00:24:00 +0200
+Subject: [PATCH 1/3] ao_pipewire: whitespace fixes
+
+---
+ audio/out/ao_pipewire.c | 6 +++---
+ 1 file changed, 3 insertions(+), 3 deletions(-)
+
+diff --git a/audio/out/ao_pipewire.c b/audio/out/ao_pipewire.c
+index 79965cdc68b..b0102bee8ea 100644
+--- a/audio/out/ao_pipewire.c
++++ b/audio/out/ao_pipewire.c
+@@ -121,9 +121,9 @@ static void on_param_changed(void *userdata, uint32_t id, const struct spa_pod *
+ {
+ struct ao *ao = userdata;
+ struct priv *p = ao->priv;
+- const struct spa_pod *params[1];
+- uint8_t buffer[1024];
+- struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
++ const struct spa_pod *params[1];
++ uint8_t buffer[1024];
++ struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buffer, sizeof(buffer));
+
+ if (param == NULL || id != SPA_PARAM_Format)
+ return;
+
+From af10f39b030a0d5c985c8f7d04bf7f7ea2904d5e Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= <thomas@t-8ch.de>
+Date: Tue, 8 Jun 2021 00:24:06 +0200
+Subject: [PATCH 2/3] ao_pipewire: add more application properties
+
+---
+ audio/out/ao_pipewire.c | 6 +++++-
+ 1 file changed, 5 insertions(+), 1 deletion(-)
+
+diff --git a/audio/out/ao_pipewire.c b/audio/out/ao_pipewire.c
+index b0102bee8ea..9f2a66ad845 100644
+--- a/audio/out/ao_pipewire.c
++++ b/audio/out/ao_pipewire.c
+@@ -8,6 +8,7 @@
+ #include "ao.h"
+ #include "audio/format.h"
+ #include "config.h"
++#include "generated/version.h"
+ #include "internal.h"
+ #include "osdep/timer.h"
+
+@@ -222,7 +223,10 @@ static int init(struct ao *ao)
+ PW_KEY_MEDIA_TYPE, "Audio",
+ PW_KEY_MEDIA_CATEGORY, "Playback",
+ PW_KEY_MEDIA_ROLE, "Music",
+- PW_KEY_NODE_NAME, "mpv",
++ PW_KEY_NODE_NAME, ao->client_name,
++ PW_KEY_APP_NAME, ao->client_name,
++ PW_KEY_APP_ID, ao->client_name,
++ PW_KEY_APP_ICON_NAME, ao->client_name,
+ PW_KEY_NODE_LATENCY, latency_str,
+ NULL),
+ &stream_events,
+
+From 3df9d344f0c05df90b421bbde3616be8f84d9f35 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?Thomas=20Wei=C3=9Fschuh?= <thomas@t-8ch.de>
+Date: Tue, 8 Jun 2021 00:24:11 +0200
+Subject: [PATCH 3/3] ap_pipewire: implement audio controls
+
+---
+ audio/out/ao_pipewire.c | 95 +++++++++++++++++++++++++++++++++++++++++
+ 1 file changed, 95 insertions(+)
+
+diff --git a/audio/out/ao_pipewire.c b/audio/out/ao_pipewire.c
+index 9f2a66ad845..a5c4322eebe 100644
+--- a/audio/out/ao_pipewire.c
++++ b/audio/out/ao_pipewire.c
+@@ -1,6 +1,8 @@
+
+ #include <pipewire/pipewire.h>
+ #include <spa/param/audio/format-utils.h>
++#include <spa/param/props.h>
++#include <math.h>
+
+ #include "common/msg.h"
+ #include "options/m_config.h"
+@@ -33,6 +35,8 @@ struct priv {
+ struct pw_stream *stream;
+
+ struct ao_pipewire_opts *opts;
++ bool muted;
++ float volume[2];
+ };
+
+ static enum spa_audio_format af_fmt_to_pw(enum af_format format)
+@@ -151,11 +155,44 @@ static void on_state_changed(void *userdata, enum pw_stream_state old, enum pw_s
+ }
+ }
+
++static float spa_volume_to_mp_volume(float vol)
++{
++ return cbrt(vol) * 100;
++}
++
++static float mp_volume_to_spa_volume(float vol)
++{
++ vol /= 100;
++ return vol * vol * vol;
++}
++
++static void on_control_info(void *userdata, uint32_t id,
++ const struct pw_stream_control *control)
++{
++ struct ao *ao = userdata;
++ struct priv *p = ao->priv;
++
++ switch (id) {
++ case SPA_PROP_mute:
++ if (control->n_values == 1)
++ p->muted = control->values[0] >= 0.5;
++ break;
++ case SPA_PROP_channelVolumes:
++ if (control->n_values == 2) {
++ p->volume[0] = control->values[0];
++ p->volume[1] = control->values[1];
++ }
++ break;
++ }
++}
++
++
+ static const struct pw_stream_events stream_events = {
+ .version = PW_VERSION_STREAM_EVENTS,
+ .param_changed = on_param_changed,
+ .process = on_process,
+ .state_changed = on_state_changed,
++ .control_info = on_control_info,
+ };
+
+ static void uninit(struct ao *ao)
+@@ -269,6 +306,62 @@ static void start(struct ao *ao)
+ pw_thread_loop_unlock(p->loop);
+ }
+
++#define CONTROL_RET(r) (!r ? CONTROL_OK : CONTROL_ERROR)
++
++static int control(struct ao *ao, enum aocontrol cmd, void *arg)
++{
++ struct priv *p = ao->priv;
++
++ switch (cmd) {
++ case AOCONTROL_GET_VOLUME: {
++ struct ao_control_vol *vol = arg;
++ vol->left = spa_volume_to_mp_volume(p->volume[0]);
++ vol->right = spa_volume_to_mp_volume(p->volume[1]);
++ return CONTROL_OK;
++ }
++ case AOCONTROL_GET_MUTE: {
++ bool *muted = arg;
++ *muted = p->muted;
++ return CONTROL_OK;
++ }
++ case AOCONTROL_SET_VOLUME:
++ case AOCONTROL_SET_MUTE:
++ case AOCONTROL_UPDATE_STREAM_TITLE: {
++ int ret;
++
++ pw_thread_loop_lock(p->loop);
++ switch (cmd) {
++ case AOCONTROL_SET_VOLUME: {
++ struct ao_control_vol *vol = arg;
++ float left = mp_volume_to_spa_volume(vol->left), right = mp_volume_to_spa_volume(vol->right);
++ ret = CONTROL_RET(pw_stream_set_control(p->stream, SPA_PROP_channelVolumes, 2, &left, &right));
++ break;
++ }
++ case AOCONTROL_SET_MUTE: {
++ bool *muted = arg;
++ float value = *muted ? 1.f : 0.f;
++ ret = CONTROL_RET(pw_stream_set_control(p->stream, SPA_PROP_mute, 1, &value));
++ break;
++ }
++ case AOCONTROL_UPDATE_STREAM_TITLE: {
++ char *title = arg;
++ struct spa_dict_item items[1];
++ items[0] = SPA_DICT_ITEM_INIT(PW_KEY_MEDIA_NAME, title);
++ ret = CONTROL_RET(pw_stream_update_properties(p->stream, &SPA_DICT_INIT(items, MP_ARRAY_SIZE(items))));
++ break;
++ }
++ default:
++ ret = CONTROL_NA;
++ }
++ pw_thread_loop_unlock(p->loop);
++ return ret;
++ }
++ default:
++ return CONTROL_UNKNOWN;
++ }
++}
++
++
+ const struct ao_driver audio_out_pipewire = {
+ .description = "PipeWire audio output",
+ .name = "pipewire",
+@@ -278,6 +371,8 @@ const struct ao_driver audio_out_pipewire = {
+ .reset = reset,
+ .start = start,
+
++ .control = control,
++
+ .priv_size = sizeof(struct priv),
+ .priv_defaults = &(const struct priv)
+ {
diff --git a/PKGBUILD b/PKGBUILD
index 9b55c30dc480..684de47f893f 100644
--- a/PKGBUILD
+++ b/PKGBUILD
@@ -7,7 +7,7 @@ _pkgname=mpv
pkgname=${_pkgname}-pipewire
_tag='4c9d3669a0f672e6754ac456acd324db570964d3' # git rev-parse v${pkgver}
pkgver=0.33.1
-pkgrel=4
+pkgrel=5
pkgdesc='a free, open source, and cross-platform media player including an experimental PipeWire audio backend'
arch=('x86_64')
# We link against libraries that are licensed GPLv3 explicitly, so our
@@ -33,9 +33,11 @@ conflicts=('mpv')
options=('!emptydirs')
validpgpkeys=('145077D82501AA20152CACCE8D769208D5E31419') # sfan5 <sfan5@live.de>
source=("git+https://github.com/mpv-player/mpv.git#tag=${_tag}?signed"
- "pipewire.patch::https://github.com/Oschowa/mpv/commit/fddb143282fa74425a8a6f29c9566e51777759d0.patch")
+ "01-Add-PipeWire-audio-backend-by-Oschowa.patch"
+ "02-ao_pipewire-fixes-and-media-control-by-t-8ch.patch")
sha256sums=('SKIP'
- 'd72a5863bceb5ac542c656ff85a9cb23d27d30c1609022e1b1735744f2777aaf')
+ 'd72a5863bceb5ac542c656ff85a9cb23d27d30c1609022e1b1735744f2777aaf'
+ '1b1e69f06225b1f6c9a6ffdc7d3acccfcee3d25c350e4d1a0ab66f5dcb0d3bf3')
prepare() {
cd ${_pkgname}
@@ -44,7 +46,11 @@ prepare() {
git cherry-pick -n 7c4465cefb27d4e0d07535d368febdf77b579566
# patch mpv with the PipeWire audio backend
- patch -Np1 -i ../pipewire.patch
+ #https://github.com/Oschowa/mpv/commit/fddb143282fa74425a8a6f29c9566e51777759d0
+ patch -Np1 -i ../01-Add-PipeWire-audio-backend-by-Oschowa.patch
+ # add ao_pipewire fixes and media control
+ # https://github.com/Oschowa/mpv/pull/1
+ patch -Np1 -i ../02-ao_pipewire-fixes-and-media-control-by-t-8ch.patch
}
build() {