mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-12-20 04:30:04 +01:00
pulse-server: Add a message to enable/disable mono mixdown
WirePlumber recently added a mechanism to force mono mixdown on audio outputs, which is a useful feature for accessibility. Let's also expose that setting via libpulse for existing audio settings UIs to be able to use.
This commit is contained in:
parent
8c7890eb52
commit
385161b12a
4 changed files with 73 additions and 7 deletions
|
|
@ -60,6 +60,11 @@ struct client {
|
||||||
struct pw_manager_object *metadata_routes;
|
struct pw_manager_object *metadata_routes;
|
||||||
struct pw_properties *routes;
|
struct pw_properties *routes;
|
||||||
|
|
||||||
|
struct pw_manager_object *metadata_schema_sm_settings;
|
||||||
|
bool have_force_mono_audio;
|
||||||
|
struct pw_manager_object *metadata_sm_settings;
|
||||||
|
bool force_mono_audio;
|
||||||
|
|
||||||
uint32_t connect_tag;
|
uint32_t connect_tag;
|
||||||
|
|
||||||
uint32_t in_index;
|
uint32_t in_index;
|
||||||
|
|
|
||||||
|
|
@ -323,5 +323,6 @@ static inline uint32_t port_type_value(const char *port_type)
|
||||||
#define METADATA_CONFIG_DEFAULT_SOURCE "default.configured.audio.source"
|
#define METADATA_CONFIG_DEFAULT_SOURCE "default.configured.audio.source"
|
||||||
#define METADATA_TARGET_NODE "target.node"
|
#define METADATA_TARGET_NODE "target.node"
|
||||||
#define METADATA_TARGET_OBJECT "target.object"
|
#define METADATA_TARGET_OBJECT "target.object"
|
||||||
|
#define METADATA_FEATURES_AUDIO_MONO "node.features.audio.mono"
|
||||||
|
|
||||||
#endif /* PULSE_SERVER_DEFS_H */
|
#endif /* PULSE_SERVER_DEFS_H */
|
||||||
|
|
|
||||||
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include "client.h"
|
#include "client.h"
|
||||||
#include "collect.h"
|
#include "collect.h"
|
||||||
|
#include "defs.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "manager.h"
|
#include "manager.h"
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
|
@ -89,6 +90,46 @@ static int bluez_card_object_message_handler(struct client *client, struct pw_ma
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int core_object_force_mono_output(struct client *client, const char *params, FILE *response)
|
||||||
|
{
|
||||||
|
if (!client->have_force_mono_audio) {
|
||||||
|
/* Not supported, return a null value to indicate that */
|
||||||
|
fprintf(response, "null");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!params || params[0] == '\0') {
|
||||||
|
/* No parameter => query the current value */
|
||||||
|
fprintf(response, "%s", client->force_mono_audio ? "true" : "false");
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
/* The caller is trying to set a value or clear with a null */
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (spa_streq(params, "true")) {
|
||||||
|
ret = pw_manager_set_metadata(client->manager, client->metadata_sm_settings, PW_ID_CORE,
|
||||||
|
METADATA_FEATURES_AUDIO_MONO, "Spa:String:JSON", "true");
|
||||||
|
} else if (spa_streq(params, "false")) {
|
||||||
|
ret = pw_manager_set_metadata(client->manager, client->metadata_sm_settings, PW_ID_CORE,
|
||||||
|
METADATA_FEATURES_AUDIO_MONO, "Spa:String:JSON", "false");
|
||||||
|
} else if (spa_streq(params, "null")) {
|
||||||
|
ret = pw_manager_set_metadata(client->manager, client->metadata_sm_settings, PW_ID_CORE,
|
||||||
|
METADATA_FEATURES_AUDIO_MONO, NULL, NULL);
|
||||||
|
} else {
|
||||||
|
fprintf(response, "Value must be true, false, or clear");
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
fprintf(response, "Could not set metadata: %s", spa_strerror(ret));
|
||||||
|
else
|
||||||
|
fprintf(response, "%s", params);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static int core_object_message_handler(struct client *client, struct pw_manager_object *o, const char *message, const char *params, FILE *response)
|
static int core_object_message_handler(struct client *client, struct pw_manager_object *o, const char *message, const char *params, FILE *response)
|
||||||
{
|
{
|
||||||
pw_log_debug(": core %p object message:'%s' params:'%s'", o, message, params);
|
pw_log_debug(": core %p object message:'%s' params:'%s'", o, message, params);
|
||||||
|
|
@ -97,13 +138,14 @@ static int core_object_message_handler(struct client *client, struct pw_manager_
|
||||||
fprintf(response,
|
fprintf(response,
|
||||||
"/core <command> [<params>]\n"
|
"/core <command> [<params>]\n"
|
||||||
"available commands:\n"
|
"available commands:\n"
|
||||||
" help this help\n"
|
" help this help\n"
|
||||||
" list-handlers show available object handlers\n"
|
" list-handlers show available object handlers\n"
|
||||||
" pipewire-pulse:malloc-info show malloc_info\n"
|
" pipewire-pulse:malloc-info show malloc_info\n"
|
||||||
" pipewire-pulse:malloc-trim run malloc_trim\n"
|
" pipewire-pulse:malloc-trim run malloc_trim\n"
|
||||||
" pipewire-pulse:log-level update log level with <params>\n"
|
" pipewire-pulse:log-level update log level with <params>\n"
|
||||||
" pipewire-pulse:list-modules list all module names\n"
|
" pipewire-pulse:list-modules list all module names\n"
|
||||||
" pipewire-pulse:describe-module describe module info for <params>"
|
" pipewire-pulse:describe-module describe module info for <params>\n"
|
||||||
|
" pipewire-pulse:force-mono-output force mono mixdown on all hardware outputs"
|
||||||
);
|
);
|
||||||
} else if (spa_streq(message, "list-handlers")) {
|
} else if (spa_streq(message, "list-handlers")) {
|
||||||
bool first = true;
|
bool first = true;
|
||||||
|
|
@ -164,6 +206,8 @@ static int core_object_message_handler(struct client *client, struct pw_manager_
|
||||||
} else {
|
} else {
|
||||||
fprintf(response, "Failed to open module.\n");
|
fprintf(response, "Failed to open module.\n");
|
||||||
}
|
}
|
||||||
|
} else if (spa_streq(message, "pipewire-pulse:force-mono-output")) {
|
||||||
|
return core_object_force_mono_output(client, params, response);
|
||||||
} else {
|
} else {
|
||||||
return -ENOSYS;
|
return -ENOSYS;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -404,6 +404,14 @@ static void handle_metadata(struct client *client, struct pw_manager_object *old
|
||||||
if (client->metadata_routes == old)
|
if (client->metadata_routes == old)
|
||||||
client->metadata_routes = new;
|
client->metadata_routes = new;
|
||||||
}
|
}
|
||||||
|
else if (spa_streq(name, "sm-settings")) {
|
||||||
|
if (client->metadata_sm_settings == old)
|
||||||
|
client->metadata_sm_settings = new;
|
||||||
|
}
|
||||||
|
else if (spa_streq(name, "schema-sm-settings")) {
|
||||||
|
if (client->metadata_schema_sm_settings == old)
|
||||||
|
client->metadata_schema_sm_settings = new;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t frac_to_bytes_round_up(struct spa_fraction val, const struct sample_spec *ss)
|
static uint32_t frac_to_bytes_round_up(struct spa_fraction val, const struct sample_spec *ss)
|
||||||
|
|
@ -964,6 +972,14 @@ static void manager_metadata(void *data, struct pw_manager_object *o,
|
||||||
}
|
}
|
||||||
if (subject == PW_ID_CORE && o == client->metadata_routes)
|
if (subject == PW_ID_CORE && o == client->metadata_routes)
|
||||||
client_update_routes(client, key, value);
|
client_update_routes(client, key, value);
|
||||||
|
if (subject == PW_ID_CORE && o == client->metadata_schema_sm_settings) {
|
||||||
|
if (spa_streq(key, METADATA_FEATURES_AUDIO_MONO))
|
||||||
|
client->have_force_mono_audio = true;
|
||||||
|
}
|
||||||
|
if (subject == PW_ID_CORE && o == client->metadata_sm_settings) {
|
||||||
|
if (spa_streq(key, METADATA_FEATURES_AUDIO_MONO))
|
||||||
|
client->force_mono_audio = spa_streq(value, "true");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue