mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-03-27 07:58:16 -04:00
Merge branch 'alsa-ext-vol' into 'master'
Add an external volume control mechanism See merge request pipewire/pipewire!2722
This commit is contained in:
commit
cc53257729
33 changed files with 2361 additions and 103 deletions
|
|
@ -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 */
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
@ -36,6 +37,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 },
|
||||
};
|
||||
|
||||
/**
|
||||
* \}
|
||||
*/
|
||||
|
|
|
|||
29
spa/include/spa/param/audio/volume.h
Normal file
29
spa/include/spa/param/audio/volume.h
Normal 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 */
|
||||
|
|
@ -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 },
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -122,10 +122,9 @@ struct spa_dbus_methods {
|
|||
*
|
||||
* \param dbus the dbus manager
|
||||
* \param type the bus type to wrap
|
||||
* \param error location for the DBusError
|
||||
* \return a new dbus connection wrapper or NULL on error
|
||||
*/
|
||||
struct spa_dbus_connection * (*get_connection) (void *object,
|
||||
struct spa_dbus_connection * (*get_connection) (void *dbus,
|
||||
enum spa_dbus_type type);
|
||||
};
|
||||
|
||||
|
|
|
|||
163
spa/include/spa/support/varlink.h
Normal file
163
spa/include/spa/support/varlink.h
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
/* Simple Plugin API */
|
||||
/* SPDX-FileCopyrightText: Copyright © 2026 Arun Raghavan */
|
||||
/* SPDX-License-Identifier: MIT */
|
||||
|
||||
#ifndef SPA_VARLINK_H
|
||||
#define SPA_VARLINK_H
|
||||
|
||||
#include <spa/utils/hook.h>
|
||||
#include <spa/utils/json.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef SPA_API_VARLINK
|
||||
#ifdef SPA_API_IMPL
|
||||
#define SPA_API_VARLINK SPA_API_IMPL
|
||||
#else
|
||||
#define SPA_API_VARLINK static inline
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/** \defgroup spa_varlink Varlink
|
||||
* Varlink communication
|
||||
*/
|
||||
|
||||
/**
|
||||
* \addtogroup spa_varlink
|
||||
* \{
|
||||
*/
|
||||
|
||||
#define SPA_TYPE_INTERFACE_Varlink SPA_TYPE_INFO_INTERFACE_BASE "Varlink"
|
||||
|
||||
typedef void (*spa_varlink_reply_func_t) (void *data, const char *params,
|
||||
const char *error, size_t len, bool continues);
|
||||
|
||||
struct spa_varlink_client_events {
|
||||
#define SPA_VERSION_VARLINK_CLIENT_EVENTS 0
|
||||
uint32_t version;
|
||||
|
||||
/** The client was destroyed. */
|
||||
void (*destroy) (void *data);
|
||||
|
||||
/** The client was disconnected. */
|
||||
void (*disconnect) (void *data);
|
||||
};
|
||||
|
||||
struct spa_varlink_client {
|
||||
#define SPA_VERSION_VARLINK_CLIENT 0
|
||||
uint32_t version;
|
||||
|
||||
/** Add a listener fo events */
|
||||
void (*add_listener) (void *object, struct spa_hook *listener,
|
||||
const struct spa_varlink_client_events *events,
|
||||
void *data);
|
||||
|
||||
/** Call a single- or no-reply method on a varlink client.
|
||||
*
|
||||
* \param method Fully qualified (`interface.Method`) method name to
|
||||
* call.
|
||||
* \param params Method parameters as a string (must be a valid JSON
|
||||
* object).
|
||||
* \param oneway Signal that the server should not send a reply.
|
||||
* \param more Expect multiple replies from the server for this method
|
||||
* call.
|
||||
* \param cb Callback to invok when a reply to this call arrives.
|
||||
* \param userdata Userdata to supply to the callback.
|
||||
* \return 0 on success, or a negative error code on failure.
|
||||
*/
|
||||
int (*call) (void *object, const char *method, const char *params,
|
||||
bool oneway, bool more, spa_varlink_reply_func_t cb,
|
||||
void *userdata);
|
||||
|
||||
/** Call a single-reply method and block until a reply is received.
|
||||
*
|
||||
* \param method Fully qualified (`interface.Method`) method name to
|
||||
* call.
|
||||
* \param params Method parameters as a string (must be a valid JSON
|
||||
* object).
|
||||
* \param reply The reply string. The caller is responsible for freeing
|
||||
* this data with `free()`
|
||||
* \return 0 on success, or a negative error code on failure.
|
||||
*/
|
||||
int (*call_sync) (void *object, const char *method, const char *params,
|
||||
char **reply);
|
||||
|
||||
/** Destroy a varlink client.
|
||||
*
|
||||
* \param client The client to destroy
|
||||
*/
|
||||
void (*destroy) (void *object);
|
||||
};
|
||||
|
||||
/** \copydoc spa_varlink_client_methods.add_listener
|
||||
* \sa spa_varlink_client_methods.add_listener */
|
||||
SPA_API_VARLINK void
|
||||
spa_varlink_client_add_listener(struct spa_varlink_client *client,
|
||||
struct spa_hook *listener,
|
||||
const struct spa_varlink_client_events *events,
|
||||
void *data)
|
||||
{
|
||||
spa_api_func_v(client, add_listener, 0, listener, events, data);
|
||||
}
|
||||
|
||||
/** \copydoc spa_varlink_client_methods.call
|
||||
* \sa spa_varlink_client_methods.call */
|
||||
SPA_API_VARLINK int
|
||||
spa_varlink_client_call(struct spa_varlink_client *client, const char *method,
|
||||
const char *params, bool oneway, bool more,
|
||||
spa_varlink_reply_func_t cb, void *userdata)
|
||||
{
|
||||
return spa_api_func_r(int, -EINVAL, client, call, 0, method, params,
|
||||
oneway, more, cb, userdata);
|
||||
}
|
||||
|
||||
/** \copydoc spa_varlink_client_methods.call_sync
|
||||
* \sa spa_varlink_client_methods.call_sync */
|
||||
SPA_API_VARLINK int
|
||||
spa_varlink_client_call_sync(struct spa_varlink_client *client, const char *method,
|
||||
const char *params, char **reply)
|
||||
{
|
||||
return spa_api_func_r(int, -EINVAL, client, call_sync, 0, method,
|
||||
params, reply);
|
||||
}
|
||||
|
||||
/** \copydoc spa_varlink_client_methods.destroy
|
||||
* \sa spa_varlink_client_methods.destroy */
|
||||
SPA_API_VARLINK void
|
||||
spa_varlink_client_destroy(struct spa_varlink_client *client)
|
||||
{
|
||||
spa_api_func_v(client, destroy, 0);
|
||||
}
|
||||
|
||||
#define SPA_VERSION_VARLINK 0
|
||||
struct spa_varlink { struct spa_interface iface; };
|
||||
|
||||
struct spa_varlink_methods {
|
||||
#define SPA_VERSION_VARLINK_METHODS 0
|
||||
uint32_t version;
|
||||
|
||||
/**
|
||||
* Connect to a varlink service.
|
||||
*
|
||||
* \param path Path to connect to, for example `unix:/path/to/socket`
|
||||
* \return A `spa_varlink_client` on success, NULL on failure.
|
||||
*/
|
||||
struct spa_varlink_client * (*connect) (void *object, const char *path);
|
||||
};
|
||||
|
||||
/** \copydoc spa_varlink_methods.connect
|
||||
* \sa spa_varlink_methods.connect */
|
||||
SPA_API_VARLINK void *
|
||||
spa_varlink_connect(struct spa_varlink *varlink, const char *path)
|
||||
{
|
||||
return spa_api_method_r(struct spa_varlink_client *, NULL, spa_varlink,
|
||||
&varlink->iface, connect, 0, path);
|
||||
}
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
#endif /* SPA_VARLINK_H */
|
||||
|
|
@ -25,6 +25,7 @@ extern "C" {
|
|||
#define SPA_NAME_SUPPORT_LOOP "support.loop" /**< A Loop/LoopControl/LoopUtils
|
||||
* interface */
|
||||
#define SPA_NAME_SUPPORT_SYSTEM "support.system" /**< A System interface */
|
||||
#define SPA_NAME_SUPPORT_VARLINK "support.varlink" /**< A Varlink interface */
|
||||
|
||||
#define SPA_NAME_SUPPORT_NODE_DRIVER "support.node.driver" /**< A dummy driver node */
|
||||
|
||||
|
|
|
|||
|
|
@ -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 },
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue