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:
Julian Bouzas 2026-05-28 13:25:08 +00:00
commit eed1094fbd
24 changed files with 1311 additions and 99 deletions

View file

@ -8,6 +8,7 @@
#include <spa/utils/defs.h>
#include <spa/utils/hook.h>
#include <spa/utils/dict.h>
#include <spa/pod/command.h>
#include <spa/pod/event.h>
#ifdef __cplusplus
@ -126,7 +127,35 @@ struct spa_device_events {
#define SPA_DEVICE_METHOD_SYNC 1
#define SPA_DEVICE_METHOD_ENUM_PARAMS 2
#define SPA_DEVICE_METHOD_SET_PARAM 3
#define SPA_DEVICE_METHOD_NUM 4
#define SPA_DEVICE_METHOD_SEND_COMMAND 4
#define SPA_DEVICE_METHOD_NUM 5
/* object id of SPA_TYPE_COMMAND_Device */
enum spa_device_commands {
SPA_DEVICE_COMMAND_User,
SPA_DEVICE_COMMAND_VolumeControl, /**< Volume control for devices which do not
* support standard volume control via route
* props */
};
#define SPA_DEVICE_COMMAND_ID(cmd) SPA_COMMAND_ID(cmd, SPA_TYPE_COMMAND_Device)
#define SPA_DEVICE_COMMAND_INIT(id) SPA_COMMAND_INIT(SPA_TYPE_COMMAND_Device, id)
/* properties for SPA_TYPE_COMMAND_Device */
enum spa_command_device {
SPA_COMMAND_DEVICE_START,
SPA_COMMAND_DEVICE_START_User = 0x1000,
SPA_COMMAND_DEVICE_extra, /** extra info (String) */
SPA_COMMAND_DEVICE_START_VolumeControl = 0x2000,
SPA_COMMAND_DEVICE_volumeUp, /** Send a volume up command. route id (Id) */
SPA_COMMAND_DEVICE_volumeDown, /** Send a volume down command. route id (Id) */
SPA_COMMAND_DEVICE_muteToggle, /** Send a mute toggle command. route id (Id) */
SPA_COMMAND_DEVICE_START_CUSTOM = 0x1000000,
};
/**
* spa_device_methods:
@ -134,7 +163,7 @@ struct spa_device_events {
struct spa_device_methods {
/* the version of the methods. This can be used to expand this
* structure in the future */
#define SPA_VERSION_DEVICE_METHODS 0
#define SPA_VERSION_DEVICE_METHODS 1
uint32_t version;
/**
@ -226,6 +255,23 @@ struct spa_device_methods {
int (*set_param) (void *object,
uint32_t id, uint32_t flags,
const struct spa_pod *param);
/**
* Send a command to a device.
*
* This function must be called from the main thread.
*
* \param object a \ref spa_device
* \param command a \ref spa_command of type \ref spa_command_device
* \return 0 on success
* -EINVAL when node or command is NULL
* -ENOTSUP when this node can't process commands
* -EINVAL \a command is an invalid command
*
* \since 1
*/
int (*send_command) (void *object, const struct spa_command *command);
};
SPA_API_DEVICE int spa_device_add_listener(struct spa_device *object,
@ -256,6 +302,12 @@ SPA_API_DEVICE int spa_device_set_param(struct spa_device *object,
return spa_api_method_r(int, -ENOTSUP, spa_device, &object->iface, set_param, 0,
id, flags, param);
}
SPA_API_DEVICE int spa_device_send_command(struct spa_device *object,
const struct spa_command *command)
{
return spa_api_method_r(int, -ENOTSUP, spa_device, &object->iface, send_command, 1,
command);
}
#define SPA_KEY_DEVICE_ENUM_API "device.enum.api" /**< the api used to discover this
* device */

View file

@ -19,6 +19,7 @@ extern "C" {
/* object id of SPA_TYPE_EVENT_Device */
enum spa_device_event {
SPA_DEVICE_EVENT_ObjectConfig,
SPA_DEVICE_EVENT_ExtVolumeControl,
};
#define SPA_DEVICE_EVENT_ID(ev) SPA_EVENT_ID(ev, SPA_TYPE_EVENT_Device)

View file

@ -5,8 +5,9 @@
#ifndef SPA_DEVICE_TYPE_INFO_H
#define SPA_DEVICE_TYPE_INFO_H
#include <spa/utils/type-info.h>
#include <spa/utils/type.h>
#include <spa/monitor/device.h>
#include <spa/monitor/event.h>
#ifdef __cplusplus
@ -26,6 +27,7 @@ extern "C" {
static const struct spa_type_info spa_type_device_event_id[] = {
{ SPA_DEVICE_EVENT_ObjectConfig, SPA_TYPE_EVENT_Device, SPA_TYPE_INFO_DEVICE_EVENT_ID_BASE "ObjectConfig", NULL },
{ SPA_DEVICE_EVENT_ExtVolumeControl, SPA_TYPE_EVENT_Device, SPA_TYPE_INFO_DEVICE_EVENT_ID_BASE "ExtVolumeControl", NULL },
{ 0, 0, NULL, NULL },
};
@ -36,6 +38,27 @@ static const struct spa_type_info spa_type_device_event[] = {
{ 0, 0, NULL, NULL },
};
#define SPA_TYPE_INFO_DeviceCommand SPA_TYPE_INFO_COMMAND_BASE "Device"
#define SPA_TYPE_INFO_DEVICE_COMMAND_BASE SPA_TYPE_INFO_DeviceCommand ":"
static const struct spa_type_info spa_type_device_command_id[] = {
{ SPA_DEVICE_COMMAND_User, SPA_TYPE_COMMAND_Device, SPA_TYPE_INFO_DEVICE_COMMAND_BASE "User", NULL },
{ SPA_DEVICE_COMMAND_VolumeControl, SPA_TYPE_COMMAND_Device, SPA_TYPE_INFO_DEVICE_COMMAND_BASE "VolumeControl", NULL },
{ 0, 0, NULL, NULL },
};
static const struct spa_type_info spa_type_device_command[] = {
{ SPA_COMMAND_DEVICE_START, SPA_TYPE_Id, SPA_TYPE_INFO_DEVICE_COMMAND_BASE, spa_type_device_command_id },
{ SPA_COMMAND_DEVICE_extra, SPA_TYPE_String, SPA_TYPE_INFO_DEVICE_COMMAND_BASE "extra", NULL },
{ SPA_COMMAND_DEVICE_volumeUp, SPA_TYPE_Id, SPA_TYPE_INFO_DEVICE_COMMAND_BASE "volumeUp", NULL },
{ SPA_COMMAND_DEVICE_volumeDown, SPA_TYPE_Id, SPA_TYPE_INFO_DEVICE_COMMAND_BASE "volumeDown", NULL },
{ SPA_COMMAND_DEVICE_muteToggle, SPA_TYPE_Id, SPA_TYPE_INFO_DEVICE_COMMAND_BASE "muteToggle", NULL },
{ 0, 0, NULL, NULL },
};
/**
* \}
*/

View file

@ -0,0 +1,29 @@
/* Simple Plugin API */
/* SPDX-FileCopyrightText: Copyright © 2026 Arun Raghavan */
/* SPDX-License-Identifier: MIT */
#ifndef SPA_AUDIO_VOLUME_H
#define SPA_AUDIO_VOLUME_H
#ifdef __cplusplus
extern "C" {
#endif
/** Flags for volume control capabilities */
enum spa_audio_volume_control_flags {
SPA_AUDIO_VOLUME_CONTROL_NONE = 0, /**<< No flags */
SPA_AUDIO_VOLUME_CONTROL_READ_VOLUME = (1 << 0), /**<< Volume value can be read */
SPA_AUDIO_VOLUME_CONTROL_WRITE_VOLUME_VALUE = (1 << 1), /**<< Volume value can be set */
SPA_AUDIO_VOLUME_CONTROL_WRITE_VOLUME_UPDOWN = (1 << 2), /**<< Volume value can incremented/decremented */
SPA_AUDIO_VOLUME_CONTROL_READ_MUTE = (1 << 3), /**<< Mute state can be read */
SPA_AUDIO_VOLUME_CONTROL_WRITE_MUTE_VALUE = (1 << 4), /**<< Mute state can be set */
SPA_AUDIO_VOLUME_CONTROL_WRITE_MUTE_TOGGLE = (1 << 5), /**<< Mute state can be toggled */
SPA_AUDIO_VOLUME_CONTROL_READ_BALANCE = (1 << 6), /**<< Per-channel volumes can be read */
SPA_AUDIO_VOLUME_CONTROL_WRITE_BALANCE = (1 << 7), /**<< Per-channel volumes can be set */
};
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* SPA_AUDIO_VOLUME_H */

View file

@ -66,6 +66,7 @@ static const struct spa_type_info spa_type_props[] = {
{ SPA_PROP_volumeRampTime, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "volumeRampTime", NULL },
{ SPA_PROP_volumeRampStepTime, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "volumeRampStepTime", NULL },
{ SPA_PROP_volumeRampScale, SPA_TYPE_Id, SPA_TYPE_INFO_PROPS_BASE "volumeRampScale", spa_type_audio_volume_ramp_scale },
{ SPA_PROP_volumeControlFlags, SPA_TYPE_Int, SPA_TYPE_INFO_PROPS_BASE "volumeControlFlags", NULL },
{ SPA_PROP_brightness, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "brightness", NULL },
{ SPA_PROP_contrast, SPA_TYPE_Float, SPA_TYPE_INFO_PROPS_BASE "contrast", NULL },

View file

@ -98,6 +98,8 @@ enum spa_prop {
* to ramp the */
SPA_PROP_volumeRampScale, /**< the scale or graph to used to ramp the
* volume */
SPA_PROP_volumeControlFlags, /**< Available volume control features
* (Id enum spa_audio_volume_control_flags) */
SPA_PROP_START_Video = 0x20000, /**< video related properties */
SPA_PROP_brightness,

View file

@ -62,7 +62,7 @@ static const struct spa_type_info spa_types[] = {
{ SPA_TYPE_EVENT_Node, SPA_TYPE_Object, SPA_TYPE_INFO_EVENT_BASE "Node", spa_type_node_event },
{ SPA_TYPE_COMMAND_START, SPA_TYPE_Object, SPA_TYPE_INFO_Command, NULL },
{ SPA_TYPE_COMMAND_Device, SPA_TYPE_Object, SPA_TYPE_INFO_COMMAND_BASE "Device", NULL },
{ SPA_TYPE_COMMAND_Device, SPA_TYPE_Object, SPA_TYPE_INFO_COMMAND_BASE "Device", spa_type_device_command },
{ SPA_TYPE_COMMAND_Node, SPA_TYPE_Object, SPA_TYPE_INFO_COMMAND_BASE "Node", spa_type_node_command },
{ SPA_TYPE_OBJECT_START, SPA_TYPE_Object, SPA_TYPE_INFO_Object, NULL },