mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-07-06 00:06:33 -04:00
Merge branch 'spa-device-external-vol-control' into 'master'
spa: alsa: Add option to send external volume control events See merge request pipewire/pipewire!2836
This commit is contained in:
commit
bc2af75d24
24 changed files with 1275 additions and 98 deletions
|
|
@ -8,6 +8,7 @@
|
|||
#include <regex.h>
|
||||
#include <malloc.h>
|
||||
|
||||
#include <spa/monitor/device.h>
|
||||
#include <spa/param/props.h>
|
||||
#include <spa/pod/builder.h>
|
||||
#include <spa/pod/pod.h>
|
||||
|
|
@ -23,8 +24,62 @@
|
|||
#include "log.h"
|
||||
#include "manager.h"
|
||||
#include "module.h"
|
||||
#include "pipewire/properties.h"
|
||||
#include "message-handler.h"
|
||||
|
||||
static int sink_object_message_handler(struct client *client, struct pw_manager_object *o, const char *message, const char *params, FILE *response)
|
||||
{
|
||||
struct device_info dev_info;
|
||||
struct pw_manager_object *card = NULL;
|
||||
char buf[1024];
|
||||
struct spa_pod_builder b = SPA_POD_BUILDER_INIT(buf, sizeof(buf));
|
||||
struct spa_pod_frame f[1];
|
||||
struct spa_command *command;
|
||||
uint32_t card_id, command_id;
|
||||
|
||||
pw_log_debug(": sink %p object message:'%s' params:'%s'", o, message, params);
|
||||
|
||||
get_device_info(o, &dev_info, PW_DIRECTION_OUTPUT, false);
|
||||
|
||||
if (spa_streq(message, "volume-up"))
|
||||
command_id = SPA_COMMAND_DEVICE_volumeUp;
|
||||
else if (spa_streq(message, "volume-down"))
|
||||
command_id = SPA_COMMAND_DEVICE_volumeDown;
|
||||
else if (spa_streq(message, "mute-toggle"))
|
||||
command_id = SPA_COMMAND_DEVICE_muteToggle;
|
||||
else {
|
||||
fprintf(response, "Unknown message %s (must be volume-up, volume-down or mute-toggle)", message);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
card_id = pw_properties_get_uint32(o->props, PW_KEY_DEVICE_ID, SPA_ID_INVALID);
|
||||
|
||||
spa_list_for_each(o, &client->manager->object_list, link) {
|
||||
if (o->id == card_id) {
|
||||
card = o;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!card) {
|
||||
pw_log_error("Could not find card");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
spa_pod_builder_push_object(&b, &f[0],
|
||||
SPA_TYPE_COMMAND_Device, SPA_DEVICE_COMMAND_VolumeControl);
|
||||
spa_pod_builder_add(&b,
|
||||
command_id, SPA_POD_Id(dev_info.active_port), 0);
|
||||
|
||||
command = (struct spa_command *)spa_pod_builder_pop(&b, &f[0]);
|
||||
|
||||
pw_device_send_command((struct pw_device *)card->proxy, command);
|
||||
|
||||
fprintf(response, "true");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bluez_card_object_message_handler(struct client *client, struct pw_manager_object *o, const char *message, const char *params, FILE *response)
|
||||
{
|
||||
struct transport_codec_info codecs[64];
|
||||
|
|
@ -289,4 +344,14 @@ void register_object_message_handlers(struct pw_manager_object *o)
|
|||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (pw_manager_object_is_sink(o)) {
|
||||
str = pw_properties_get(o->props, PW_KEY_NODE_NAME);
|
||||
if (str) {
|
||||
free(o->message_object_path);
|
||||
o->message_object_path = spa_aprintf("/sink/%s/volume-control", str);
|
||||
o->message_handler = sink_object_message_handler;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3746,7 +3746,7 @@ static int fill_card_info(struct client *client, struct message *m,
|
|||
}
|
||||
|
||||
static int fill_sink_info_proplist(struct message *m, const struct spa_dict *sink_props,
|
||||
const struct pw_manager_object *card)
|
||||
const struct device_info *dev_info, const struct pw_manager_object *card)
|
||||
{
|
||||
struct pw_device_info *card_info = card ? card->info : NULL;
|
||||
spa_autoptr(pw_properties) props = NULL;
|
||||
|
|
@ -3760,6 +3760,26 @@ static int fill_sink_info_proplist(struct message *m, const struct spa_dict *sin
|
|||
sink_props = &props->dict;
|
||||
}
|
||||
|
||||
if (dev_info->volume_info.flags & VOLUME_CONTROL_MASK) {
|
||||
props = pw_properties_new_dict(sink_props);
|
||||
if (props == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
#define SET_PROP(k, f) pw_properties_set(props, k, dev_info->volume_info.flags & (f) ? "true" : "false")
|
||||
|
||||
SET_PROP("device.volume.read-volume", VOLUME_READ);
|
||||
SET_PROP("device.volume.write-volume-value", VOLUME_WRITE);
|
||||
SET_PROP("device.volume.write-volume-updown", VOLUME_UPDOWN);
|
||||
SET_PROP("device.volume.read-mute", VOLUME_READ_MUTE);
|
||||
SET_PROP("device.volume.write-mute-value", VOLUME_WRITE_MUTE);
|
||||
SET_PROP("device.volume.write-mute-toggle", VOLUME_TOGGLE_MUTE);
|
||||
SET_PROP("device.volume.read-balance", VOLUME_READ_BALANCE);
|
||||
SET_PROP("device.volume.write-balance", VOLUME_WRITE_BALANCE);
|
||||
|
||||
pw_properties_add(props, card_info->props);
|
||||
sink_props = &props->dict;
|
||||
}
|
||||
|
||||
message_put(m, TAG_PROPLIST, sink_props, TAG_INVALID);
|
||||
|
||||
return 0;
|
||||
|
|
@ -3858,7 +3878,7 @@ static int fill_sink_info(struct client *client, struct message *m,
|
|||
|
||||
if (client->version >= 13) {
|
||||
int res;
|
||||
if ((res = fill_sink_info_proplist(m, info->props, card)) < 0)
|
||||
if ((res = fill_sink_info_proplist(m, info->props, &dev_info, card)) < 0)
|
||||
return res;
|
||||
message_put(m,
|
||||
TAG_USEC, 0LL, /* requested latency */
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <spa/param/props.h>
|
||||
#include <spa/param/audio/raw.h>
|
||||
#include <spa/param/audio/volume.h>
|
||||
#include <spa/pod/iter.h>
|
||||
#include <spa/utils/defs.h>
|
||||
#include <pipewire/log.h>
|
||||
|
|
@ -89,6 +90,29 @@ int volume_parse_param(const struct spa_pod *param, struct volume_info *info, bo
|
|||
info->map.channels = spa_pod_copy_array(&prop->value, SPA_TYPE_Id,
|
||||
info->map.map, SPA_N_ELEMENTS(info->map.map));
|
||||
break;
|
||||
case SPA_PROP_volumeControlFlags:
|
||||
{
|
||||
uint32_t flags;
|
||||
if (spa_pod_get_id(&prop->value, &flags) >= 0) {
|
||||
SPA_FLAG_UPDATE(info->flags, VOLUME_READ,
|
||||
flags & SPA_AUDIO_VOLUME_CONTROL_READ_VOLUME);
|
||||
SPA_FLAG_UPDATE(info->flags, VOLUME_WRITE,
|
||||
flags & SPA_AUDIO_VOLUME_CONTROL_WRITE_VOLUME_VALUE);
|
||||
SPA_FLAG_UPDATE(info->flags, VOLUME_UPDOWN,
|
||||
flags & SPA_AUDIO_VOLUME_CONTROL_WRITE_VOLUME_UPDOWN);
|
||||
SPA_FLAG_UPDATE(info->flags, VOLUME_READ_MUTE,
|
||||
flags & SPA_AUDIO_VOLUME_CONTROL_READ_MUTE);
|
||||
SPA_FLAG_UPDATE(info->flags, VOLUME_WRITE_MUTE,
|
||||
flags & SPA_AUDIO_VOLUME_CONTROL_WRITE_MUTE_VALUE);
|
||||
SPA_FLAG_UPDATE(info->flags, VOLUME_TOGGLE_MUTE,
|
||||
flags & SPA_AUDIO_VOLUME_CONTROL_WRITE_MUTE_TOGGLE);
|
||||
SPA_FLAG_UPDATE(info->flags, VOLUME_READ_BALANCE,
|
||||
flags & SPA_AUDIO_VOLUME_CONTROL_READ_BALANCE);
|
||||
SPA_FLAG_UPDATE(info->flags, VOLUME_WRITE_BALANCE,
|
||||
flags & SPA_AUDIO_VOLUME_CONTROL_WRITE_BALANCE);
|
||||
}
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,6 +32,15 @@ struct volume_info {
|
|||
uint32_t steps;
|
||||
#define VOLUME_HW_VOLUME (1<<0)
|
||||
#define VOLUME_HW_MUTE (1<<1)
|
||||
#define VOLUME_READ (1<<2)
|
||||
#define VOLUME_WRITE (1<<3)
|
||||
#define VOLUME_UPDOWN (1<<4)
|
||||
#define VOLUME_READ_MUTE (1<<5)
|
||||
#define VOLUME_WRITE_MUTE (1<<6)
|
||||
#define VOLUME_TOGGLE_MUTE (1<<7)
|
||||
#define VOLUME_READ_BALANCE (1<<8)
|
||||
#define VOLUME_WRITE_BALANCE (1<<9)
|
||||
#define VOLUME_CONTROL_MASK (0x01FC)
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue