aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGeorge Kiagiadakis <george.kiagiadakis@collabora.com>2021-02-25 14:55:58 -0500
committerGeorge Kiagiadakis <george.kiagiadakis@collabora.com>2021-04-20 11:37:52 +0300
commitf1908e302b8c7317dc922164c37c4c50884684c6 (patch)
tree2b38d70e4c8bc77ee643b0083cf1096eb98c80b7
parent54ea1cd48f13517773cc1395ca2e13e059f2525c (diff)
* use module-mixer-api and module-default-nodes-api * use endpoints without endpoint streams (new design) * improve thread safety a little bit Bug-AGL: SPEC-3844 Signed-off-by: George Kiagiadakis <george.kiagiadakis@collabora.com> Change-Id: Ia180d607698d7a8875c19cc48bd2b2c503772945
-rw-r--r--binding/audiomixer-binding.c21
-rw-r--r--binding/audiomixer.c482
-rw-r--r--binding/audiomixer.h1
-rw-r--r--conf.d/cmake/config.cmake2
4 files changed, 228 insertions, 278 deletions
diff --git a/binding/audiomixer-binding.c b/binding/audiomixer-binding.c
index 80c4482..2c8981a 100644
--- a/binding/audiomixer-binding.c
+++ b/binding/audiomixer-binding.c
@@ -149,12 +149,6 @@ list_controls_cb(afb_req_t request)
audiomixer_lock(audiomixer);
- if (audiomixer_ensure_connected(audiomixer, 3) < 0) {
- afb_req_fail(request, "failed",
- "Could not connect to the PipeWire daemon");
- goto unlock;
- }
-
if (audiomixer_ensure_controls(audiomixer, 3) < 0) {
AFB_REQ_NOTICE(request, "No mixer controls were exposed "
"in PipeWire after 3 seconds");
@@ -175,7 +169,6 @@ list_controls_cb(afb_req_t request)
}
afb_req_success(request, ret_json, NULL);
-unlock:
audiomixer_unlock(audiomixer);
}
@@ -196,12 +189,6 @@ volume_cb(afb_req_t request)
goto unlock;
}
- if (audiomixer_ensure_connected(audiomixer, 3) < 0) {
- afb_req_fail(request, "failed",
- "Could not connect to the PipeWire daemon");
- goto unlock;
- }
-
if (audiomixer_ensure_controls(audiomixer, 3) < 0) {
AFB_REQ_NOTICE(request, "No mixer controls were exposed "
"in PipeWire after 3 seconds");
@@ -252,12 +239,6 @@ mute_cb(afb_req_t request)
goto unlock;
}
- if (audiomixer_ensure_connected(audiomixer, 3) < 0) {
- afb_req_fail(request, "failed",
- "Could not connect to the PipeWire daemon");
- goto unlock;
- }
-
if (audiomixer_ensure_controls(audiomixer, 3) < 0) {
AFB_REQ_NOTICE(request, "No mixer controls were exposed "
"in PipeWire after 3 seconds");
@@ -375,7 +356,7 @@ onevent(afb_api_t api, const char *event, struct json_object *object)
audiomixer_lock(audiomixer);
- ctl = audiomixer_find_control(audiomixer, "Master");
+ ctl = audiomixer_find_control(audiomixer, "Master Playback");
if (!ctl)
goto unlock;
diff --git a/binding/audiomixer.c b/binding/audiomixer.c
index aceaefe..78dd347 100644
--- a/binding/audiomixer.c
+++ b/binding/audiomixer.c
@@ -18,13 +18,12 @@ struct audiomixer
GMutex lock;
GCond cond;
- WpRemoteState state;
GPtrArray *mixer_controls;
- GWeakRef session;
- /* ref held in the thread function */
- WpObjectManager *sessions_om;
- WpObjectManager *endpoints_om;
+ gint initialized;
+ WpObjectManager *om;
+ WpPlugin *default_nodes_api;
+ WpPlugin *mixer_api;
const struct audiomixer_events *events;
void *events_data;
@@ -33,9 +32,7 @@ struct audiomixer
struct mixer_control_impl
{
struct mixer_control pub;
- gboolean is_master;
- guint32 id;
- WpEndpoint *endpoint;
+ guint32 node_id;
};
struct action
@@ -53,35 +50,67 @@ struct action
};
};
+static gboolean
+get_mixer_controls (struct audiomixer * self, guint32 node_id, gdouble * vol, gboolean * mute)
+{
+ g_autoptr (GVariant) v = NULL;
+ g_signal_emit_by_name (self->mixer_api, "get-volume", node_id, &v);
+ return v &&
+ g_variant_lookup (v, "volume", "d", &vol, NULL) &&
+ g_variant_lookup (v, "mute", "b", &mute, NULL);
+}
+
+static void
+add_control (struct audiomixer *self, const char *name, guint32 node_id)
+{
+ struct mixer_control_impl *mixctl = NULL;
+ gdouble volume = 1.0;
+ gboolean mute = FALSE;
+
+ /* get current values */
+ if (!get_mixer_controls (self, node_id, &volume, &mute)) {
+ g_warning ("failed to get object controls when populating controls");
+ return;
+ }
+
+ /* create the control */
+ mixctl = g_new0 (struct mixer_control_impl, 1);
+ snprintf (mixctl->pub.name, sizeof (mixctl->pub.name), "%s", name);
+ mixctl->pub.volume = volume;
+ mixctl->pub.mute = mute;
+ mixctl->node_id = node_id;
+ g_ptr_array_add (self->mixer_controls, mixctl);
+
+ g_debug ("added control %s", mixctl->pub.name);
+}
+
static void
-control_changed (WpEndpoint * ep, guint32 control_id, struct audiomixer * self)
+volume_changed (struct audiomixer * self, guint32 node_id)
{
- struct mixer_control_impl *ctl;
+ g_autoptr (GMutexLocker) locker = g_mutex_locker_new (&self->lock);
+ gdouble vol = 1.0;
+ gboolean mute = FALSE;
for (guint i = 0; i < self->mixer_controls->len; i++) {
+ struct mixer_control_impl *ctl;
+ guint change_mask = 0;
+
ctl = g_ptr_array_index (self->mixer_controls, i);
- if (ctl->endpoint != ep)
+ if (ctl->node_id != node_id)
continue;
- guint change_mask = 0;
+ if (!get_mixer_controls (self, node_id, &vol, &mute)) {
+ g_warning ("failed to get object controls when volume changed");
+ return;
+ }
- switch (control_id) {
- case WP_ENDPOINT_CONTROL_VOLUME: {
- float vol;
- wp_endpoint_get_control_float (ep, control_id, &vol);
+ if ((ctl->pub.volume - 0.01f) > vol || (ctl->pub.volume + 0.01f) < vol) {
ctl->pub.volume = vol;
- change_mask = MIXER_CONTROL_CHANGE_FLAG_VOLUME;
- break;
+ change_mask |= MIXER_CONTROL_CHANGE_FLAG_VOLUME;
}
- case WP_ENDPOINT_CONTROL_MUTE: {
- gboolean mute;
- wp_endpoint_get_control_boolean (ep, control_id, &mute);
+ if (ctl->pub.mute != mute) {
ctl->pub.mute = mute;
- change_mask = MIXER_CONTROL_CHANGE_FLAG_MUTE;
- break;
- }
- default:
- break;
+ change_mask |= MIXER_CONTROL_CHANGE_FLAG_MUTE;
}
if (self->events && self->events->value_changed)
@@ -90,239 +119,190 @@ control_changed (WpEndpoint * ep, guint32 control_id, struct audiomixer * self)
}
}
-/* called with self->lock locked */
static void
-check_and_populate_controls (struct audiomixer * self)
+rescan_controls (struct audiomixer * self)
{
- g_autoptr (WpSession) session = NULL;
- g_autoptr (WpEndpoint) def_ep = NULL;
- guint32 def_id = 0;
- struct mixer_control_impl *master_ctl = NULL;
-
- /* find the session */
- session = g_weak_ref_get (&self->session);
-
- /* find the default audio sink endpoint */
- if (session) {
- g_autoptr (GPtrArray) arr =
- wp_object_manager_get_objects (self->endpoints_om, 0);
- def_id = wp_session_get_default_endpoint (session,
- WP_DEFAULT_ENDPOINT_TYPE_AUDIO_SINK);
-
- for (guint i = 0; i < arr->len; i++) {
- WpEndpoint *ep = g_ptr_array_index (arr, i);
- guint32 id = wp_proxy_get_global_id (WP_PROXY (ep));
- if (id != def_id)
- continue;
- def_ep = g_object_ref (ep);
- }
+ g_autoptr (GMutexLocker) locker = g_mutex_locker_new (&self->lock);
+ g_autoptr (WpIterator) it = NULL;
+ g_auto (GValue) val = G_VALUE_INIT;
+ guint32 id = -1;
+
+ g_debug ("rescan");
+
+ /* clear previous */
+ g_ptr_array_set_size (self->mixer_controls, 0);
+
+ /* add master controls */
+ g_signal_emit_by_name (self->default_nodes_api, "get-default-node",
+ "Audio/Sink", &id);
+ if (id != (guint32)-1)
+ add_control (self, "Master Playback", id);
+
+ g_signal_emit_by_name (self->default_nodes_api, "get-default-node",
+ "Audio/Source", &id);
+ if (id != (guint32)-1)
+ add_control (self, "Master Capture", id);
+
+ /* add endpoints */
+ it = wp_object_manager_new_iterator (self->om);
+ for (; wp_iterator_next (it, &val); g_value_unset (&val)) {
+ WpPipewireObject *ep = g_value_get_object (&val);
+ const gchar *name = wp_pipewire_object_get_property (ep, "endpoint.description");
+ const gchar *node = wp_pipewire_object_get_property (ep, "node.id");
+ id = node ? atoi(node) : 0;
+ if (name && id != 0 && id != (guint32)-1)
+ add_control (self, name, id);
}
- /* find the audio sink endpoint that was the default before */
- for (guint i = 0; i < self->mixer_controls->len; i++) {
- struct mixer_control_impl *ctl = (struct mixer_control_impl *)
- g_ptr_array_index (self->mixer_controls, i);
- if (ctl->is_master) {
- master_ctl = ctl;
- break;
- }
- }
+ /* notify subscribers */
+ if (self->events && self->events->controls_changed)
+ self->events->controls_changed (self->events_data);
+ g_cond_broadcast (&self->cond);
+}
- g_debug ("check_and_populate: session:%p, def_ep:%p, def_id:%u, "
- "master_ctl:%p, master_id:%u", session, def_ep, def_id,
- master_ctl, master_ctl ? master_ctl->id : 0);
-
- /* case 1: there is a default endpoint but it doesn't match
- what we currently expose -> clear and expose the new one */
- if (def_ep && (!master_ctl || master_ctl->id != def_id)) {
- struct mixer_control_impl *mixctl = NULL;
- gfloat volume;
- gboolean mute;
-
- /* clear previous */
- if (master_ctl)
- g_signal_handlers_disconnect_by_data (master_ctl->endpoint, self);
- g_ptr_array_set_size (self->mixer_controls, 0);
-
- /* get current master values */
- wp_endpoint_get_control_float (def_ep, WP_ENDPOINT_CONTROL_VOLUME, &volume);
- wp_endpoint_get_control_boolean (def_ep, WP_ENDPOINT_CONTROL_MUTE, &mute);
-
- /* create the Master control */
- mixctl = g_new0 (struct mixer_control_impl, 1);
- strncpy (mixctl->pub.name, "Master", sizeof (mixctl->pub.name));
- mixctl->pub.volume = volume;
- mixctl->pub.mute = mute;
- mixctl->is_master = TRUE;
- mixctl->id = def_id;
- mixctl->endpoint = g_object_ref (def_ep);
- g_ptr_array_add (self->mixer_controls, mixctl);
-
- /* track changes */
- g_signal_connect (def_ep, "control-changed", (GCallback) control_changed,
- self);
-
- /* wake up audiomixer_ensure_controls() */
- g_cond_broadcast (&self->cond);
-
- g_debug ("controls changed");
-
- /* notify subscribers */
- if (self->events && self->events->controls_changed)
- self->events->controls_changed (self->events_data);
+static void
+on_default_nodes_activated (WpObject * p, GAsyncResult * res, struct audiomixer * self)
+{
+ g_autoptr (GError) error = NULL;
+ if (!wp_object_activate_finish (p, res, &error)) {
+ g_warning ("%s", error->message);
}
- /* case 2: there is no default endpoint but something is exposed -> clear */
- else if (!def_ep && master_ctl) {
- g_signal_handlers_disconnect_by_data (master_ctl->endpoint, self);
- g_ptr_array_set_size (self->mixer_controls, 0);
- g_debug ("controls cleared");
+ if (wp_object_get_active_features (WP_OBJECT (self->mixer_api))
+ & WP_PLUGIN_FEATURE_ENABLED)
+ wp_core_install_object_manager (self->core, self->om);
- /* notify subscribers */
- if (self->events && self->events->controls_changed)
- self->events->controls_changed (self->events_data);
- }
+ g_signal_connect_swapped (self->default_nodes_api, "changed",
+ (GCallback) rescan_controls, self);
}
static void
-default_endpoint_changed (WpSession * session, WpDefaultEndpointType type,
- guint32 new_id, struct audiomixer * self)
+on_mixer_activated (WpObject * p, GAsyncResult * res, struct audiomixer * self)
{
- if (type != WP_DEFAULT_ENDPOINT_TYPE_AUDIO_SINK)
- return;
+ g_autoptr (GError) error = NULL;
+ if (!wp_object_activate_finish (p, res, &error)) {
+ g_warning ("%s", error->message);
+ }
- g_autoptr (GMutexLocker) locker = g_mutex_locker_new (&self->lock);
- check_and_populate_controls (self);
+ if (wp_object_get_active_features (WP_OBJECT (self->default_nodes_api))
+ & WP_PLUGIN_FEATURE_ENABLED)
+ wp_core_install_object_manager (self->core, self->om);
+
+ g_signal_connect_swapped (self->mixer_api, "changed",
+ (GCallback) volume_changed, self);
}
static void
-sessions_changed (WpObjectManager * sessions_om, struct audiomixer * self)
+on_core_connected (struct audiomixer * self)
{
- g_autoptr (GMutexLocker) locker = g_mutex_locker_new (&self->lock);
- g_autoptr (WpSession) old_session = NULL;
- g_autoptr (WpSession) session = NULL;
- g_autoptr (GPtrArray) arr = NULL;
-
- old_session = g_weak_ref_get (&self->session);
-
- /* normally there is only 1 session */
- arr = wp_object_manager_get_objects (sessions_om, 0);
- if (arr->len > 0)
- session = WP_SESSION (g_object_ref (g_ptr_array_index (arr, 0)));
-
- g_debug ("sessions changed, count:%d, session:%p, old_session:%p",
- arr->len, session, old_session);
-
- if (session != old_session) {
- if (old_session)
- g_signal_handlers_disconnect_by_data (old_session, self);
- if (session)
- g_signal_connect (session, "default-endpoint-changed",
- (GCallback) default_endpoint_changed, self);
-
- g_weak_ref_set (&self->session, session);
- }
-
- check_and_populate_controls (self);
+ self->om = wp_object_manager_new ();
+ wp_object_manager_add_interest (self->om, WP_TYPE_ENDPOINT,
+ WP_CONSTRAINT_TYPE_PW_GLOBAL_PROPERTY,
+ PW_KEY_MEDIA_CLASS, "#s", "Audio/*", NULL);
+ wp_object_manager_request_object_features (self->om,
+ WP_TYPE_ENDPOINT, WP_OBJECT_FEATURES_ALL);
+ g_signal_connect_swapped (self->om, "objects-changed",
+ (GCallback) rescan_controls, self);
+
+ wp_object_activate (WP_OBJECT (self->default_nodes_api),
+ WP_PLUGIN_FEATURE_ENABLED, NULL,
+ (GAsyncReadyCallback) on_default_nodes_activated, self);
+
+ wp_object_activate (WP_OBJECT (self->mixer_api),
+ WP_PLUGIN_FEATURE_ENABLED, NULL,
+ (GAsyncReadyCallback) on_mixer_activated, self);
}
static void
-endpoints_changed (WpObjectManager * endpoints_om, struct audiomixer * self)
+on_core_disconnected (struct audiomixer * self)
{
- g_autoptr (GMutexLocker) locker = g_mutex_locker_new (&self->lock);
- check_and_populate_controls (self);
+ g_ptr_array_set_size (self->mixer_controls, 0);
+ g_clear_object (&self->om);
+ g_signal_handlers_disconnect_by_data (self->default_nodes_api, self);
+ g_signal_handlers_disconnect_by_data (self->mixer_api, self);
+ wp_object_deactivate (WP_OBJECT (self->default_nodes_api), WP_PLUGIN_FEATURE_ENABLED);
+ wp_object_deactivate (WP_OBJECT (self->mixer_api), WP_PLUGIN_FEATURE_ENABLED);
}
static void
-remote_state_changed (WpCore *core, WpRemoteState state,
- struct audiomixer * self)
+audiomixer_init_in_thread (struct audiomixer * self)
{
g_autoptr (GMutexLocker) locker = g_mutex_locker_new (&self->lock);
- self->state = state;
- g_cond_broadcast (&self->cond);
-}
+ g_autoptr (GError) error = NULL;
-static gboolean
-connect_in_idle (struct audiomixer * self)
-{
- wp_core_connect (self->core);
- return G_SOURCE_REMOVE;
+ self->context = g_main_context_new ();
+ g_main_context_push_thread_default (self->context);
+
+ self->loop = g_main_loop_new (self->context, FALSE);
+ self->core = wp_core_new (self->context, NULL);
+
+ /* load required API modules */
+ if (!wp_core_load_component (self->core,
+ "libwireplumber-module-default-nodes-api", "module", NULL, &error)) {
+ g_warning ("%s", error->message);
+ self->initialized = -1;
+ goto out;
+ }
+ if (!wp_core_load_component (self->core,
+ "libwireplumber-module-mixer-api", "module", NULL, &error)) {
+ g_warning ("%s", error->message);
+ self->initialized = -1;
+ goto out;
+ }
+
+ self->default_nodes_api = wp_plugin_find (self->core, "default-nodes-api");
+ self->mixer_api = wp_plugin_find (self->core, "mixer-api");
+ g_object_set (G_OBJECT (self->mixer_api), "scale", 1 /* cubic */, NULL);
+
+ g_signal_connect_swapped (self->core, "connected",
+ G_CALLBACK (on_core_connected), self);
+ g_signal_connect_swapped (self->core, "disconnected",
+ G_CALLBACK (on_core_disconnected), self);
+
+ self->initialized = 1;
+
+out:
+ g_cond_broadcast (&self->cond);
}
static void *
audiomixer_thread (struct audiomixer * self)
{
- g_autoptr (WpObjectManager) sessions_om =
- self->sessions_om = wp_object_manager_new ();
- g_autoptr (WpObjectManager) endpoints_om =
- self->endpoints_om = wp_object_manager_new ();
- GVariantBuilder b;
+ audiomixer_init_in_thread (self);
- g_main_context_push_thread_default (self->context);
+ /* main loop for the thread; quits only when audiomixer_free() is called */
+ g_main_loop_run (self->loop);
- /* install object manager for sessions */
- wp_object_manager_add_proxy_interest (sessions_om, PW_TYPE_INTERFACE_Session,
- NULL, WP_PROXY_FEATURE_INFO | WP_PROXY_SESSION_FEATURE_DEFAULT_ENDPOINT);
- g_signal_connect (sessions_om, "objects-changed",
- (GCallback) sessions_changed, self);
- wp_core_install_object_manager (self->core, sessions_om);
-
- /* install object manager for Audio/Sink endpoints */
- g_variant_builder_init (&b, G_VARIANT_TYPE ("aa{sv}"));
- g_variant_builder_open (&b, G_VARIANT_TYPE_VARDICT);
- g_variant_builder_add (&b, "{sv}", "type",
- g_variant_new_int32 (WP_OBJECT_MANAGER_CONSTRAINT_PW_GLOBAL_PROPERTY));
- g_variant_builder_add (&b, "{sv}", "name",
- g_variant_new_string (PW_KEY_MEDIA_CLASS));
- g_variant_builder_add (&b, "{sv}", "value",
- g_variant_new_string ("Audio/Sink"));
- g_variant_builder_close (&b);
-
- wp_object_manager_add_proxy_interest (endpoints_om,
- PW_TYPE_INTERFACE_Endpoint,
- g_variant_builder_end (&b),
- WP_PROXY_FEATURE_INFO | WP_PROXY_ENDPOINT_FEATURE_CONTROLS);
- g_signal_connect (endpoints_om, "objects-changed",
- (GCallback) endpoints_changed, self);
- wp_core_install_object_manager (self->core, endpoints_om);
-
- g_signal_connect (self->core, "remote-state-changed",
- (GCallback) remote_state_changed, self);
+ wp_core_disconnect (self->core);
+ g_clear_object (&self->default_nodes_api);
+ g_clear_object (&self->mixer_api);
+ g_object_unref (self->core);
- g_main_loop_run (self->loop);
g_main_context_pop_thread_default (self->context);
+ g_main_loop_unref (self->loop);
+ g_main_context_unref (self->context);
return NULL;
}
-static void
-mixer_control_impl_free (struct mixer_control_impl * impl)
-{
- if (impl->endpoint)
- g_signal_handlers_disconnect_matched (impl->endpoint,
- G_SIGNAL_MATCH_FUNC, 0, 0, NULL, control_changed, NULL);
- g_clear_object (&impl->endpoint);
- g_free (impl);
-}
-
struct audiomixer *
audiomixer_new (void)
{
struct audiomixer *self = calloc(1, sizeof(struct audiomixer));
+ wp_init (WP_INIT_ALL);
+
g_mutex_init (&self->lock);
g_cond_init (&self->cond);
- self->context = g_main_context_new ();
- self->loop = g_main_loop_new (self->context, FALSE);
- self->core = wp_core_new (self->context, NULL);
-
- self->state = WP_REMOTE_STATE_UNCONNECTED;
- self->mixer_controls = g_ptr_array_new_with_free_func (
- (GDestroyNotify) mixer_control_impl_free);
- g_weak_ref_init (&self->session, NULL);
+ self->mixer_controls = g_ptr_array_new_with_free_func (g_free);
+ g_mutex_lock (&self->lock);
+ self->initialized = 0;
self->thread = g_thread_new ("audiomixer", (GThreadFunc) audiomixer_thread,
self);
+ while (self->initialized == 0)
+ g_cond_wait (&self->cond, &self->lock);
+ g_mutex_unlock (&self->lock);
return self;
}
@@ -333,11 +313,7 @@ audiomixer_free(struct audiomixer *self)
g_main_loop_quit (self->loop);
g_thread_join (self->thread);
- g_weak_ref_clear (&self->session);
g_ptr_array_unref (self->mixer_controls);
- g_object_unref (self->core);
- g_main_loop_unref (self->loop);
- g_main_context_unref (self->context);
g_cond_clear (&self->cond);
g_mutex_clear (&self->lock);
@@ -356,34 +332,24 @@ audiomixer_unlock(struct audiomixer *self)
g_mutex_unlock (&self->lock);
}
-int
-audiomixer_ensure_connected(struct audiomixer *self, int timeout_sec)
+static gboolean
+do_connect (WpCore * core)
{
- gint64 end_time = g_get_monotonic_time () + timeout_sec * G_TIME_SPAN_SECOND;
-
- /* already connected */
- if (self->state == WP_REMOTE_STATE_CONNECTED)
- return 0;
-
- /* if disconnected, for any reason, try to connect again */
- if (self->state != WP_REMOTE_STATE_CONNECTING)
- wp_core_idle_add (self->core, (GSourceFunc) connect_in_idle, self, NULL);
-
- while (true) {
- if (!g_cond_wait_until (&self->cond, &self->lock, end_time))
- return -ETIMEDOUT;
-
- if (self->state == WP_REMOTE_STATE_CONNECTED)
- return 0;
- else if (self->state == WP_REMOTE_STATE_ERROR)
- return -EIO;
- }
+ if (!wp_core_connect (core))
+ g_warning ("Failed to connect to PipeWire");
+ return G_SOURCE_REMOVE;
}
int
audiomixer_ensure_controls(struct audiomixer *self, int timeout_sec)
{
gint64 end_time = g_get_monotonic_time () + timeout_sec * G_TIME_SPAN_SECOND;
+
+ g_return_val_if_fail (self->initialized == 1, -EIO);
+
+ if (!wp_core_is_connected (self->core))
+ g_main_context_invoke (self->context, (GSourceFunc) do_connect, self->core);
+
while (self->mixer_controls->len == 0) {
if (!g_cond_wait_until (&self->cond, &self->lock, end_time))
return -ETIMEDOUT;
@@ -425,17 +391,17 @@ audiomixer_add_event_listener(struct audiomixer *self,
static gboolean
do_change_volume (struct action * action)
{
- struct mixer_control_impl *ctl;
struct audiomixer *self = action->audiomixer;
+ GVariantBuilder b = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
+ gboolean ret = FALSE;
+
+ g_variant_builder_add (&b, "{sv}", "volume",
+ g_variant_new_double (action->change_volume.volume));
+ g_signal_emit_by_name (self->mixer_api, "set-volume",
+ action->change_volume.id, g_variant_builder_end (&b), &ret);
+ if (!ret)
+ g_warning ("mixer api set-volume failed");
- for (guint i = 0; i < self->mixer_controls->len; i++) {
- ctl = g_ptr_array_index (self->mixer_controls, i);
- if (ctl->id != action->change_volume.id)
- continue;
- if (ctl->is_master)
- wp_endpoint_set_control_float (ctl->endpoint,
- WP_ENDPOINT_CONTROL_VOLUME, action->change_volume.volume);
- }
return G_SOURCE_REMOVE;
}
@@ -448,29 +414,31 @@ audiomixer_change_volume(struct audiomixer *self,
(const struct mixer_control_impl *) control;
struct action * action;
+ g_return_if_fail (self->initialized == 1);
+
/* schedule the action to run on the audiomixer thread */
action = g_new0 (struct action, 1);
action->audiomixer = self;
- action->change_volume.id = impl->id;
+ action->change_volume.id = impl->node_id;
action->change_volume.volume = (gfloat) volume;
- wp_core_idle_add (self->core, (GSourceFunc) do_change_volume, action,
+ wp_core_idle_add (self->core, NULL, (GSourceFunc) do_change_volume, action,
g_free);
}
static gboolean
do_change_mute (struct action * action)
{
- struct mixer_control_impl *ctl;
struct audiomixer *self = action->audiomixer;
+ GVariantBuilder b = G_VARIANT_BUILDER_INIT (G_VARIANT_TYPE_VARDICT);
+ gboolean ret = FALSE;
+
+ g_variant_builder_add (&b, "{sv}", "mute",
+ g_variant_new_double (action->change_mute.mute));
+ g_signal_emit_by_name (self->mixer_api, "set-volume",
+ action->change_mute.id, g_variant_builder_end (&b), &ret);
+ if (!ret)
+ g_warning ("mixer api set-volume failed");
- for (guint i = 0; i < self->mixer_controls->len; i++) {
- ctl = g_ptr_array_index (self->mixer_controls, i);
- if (ctl->id != action->change_mute.id)
- continue;
- if (ctl->is_master)
- wp_endpoint_set_control_boolean (ctl->endpoint,
- WP_ENDPOINT_CONTROL_MUTE, action->change_mute.mute);
- }
return G_SOURCE_REMOVE;
}
@@ -483,11 +451,13 @@ audiomixer_change_mute(struct audiomixer *self,
(const struct mixer_control_impl *) control;
struct action * action;
+ g_return_if_fail (self->initialized == 1);
+
/* schedule the action to run on the audiomixer thread */
action = g_new0 (struct action, 1);
action->audiomixer = self;
- action->change_mute.id = impl->id;
+ action->change_mute.id = impl->node_id;
action->change_mute.mute = mute;
- wp_core_idle_add (self->core, (GSourceFunc) do_change_mute, action,
+ wp_core_idle_add (self->core, NULL, (GSourceFunc) do_change_mute, action,
g_free);
}
diff --git a/binding/audiomixer.h b/binding/audiomixer.h
index f4e83c7..47bd703 100644
--- a/binding/audiomixer.h
+++ b/binding/audiomixer.h
@@ -35,7 +35,6 @@ void audiomixer_free(struct audiomixer *self);
void audiomixer_lock(struct audiomixer *self);
void audiomixer_unlock(struct audiomixer *self);
-int audiomixer_ensure_connected(struct audiomixer *self, int timeout_sec);
int audiomixer_ensure_controls(struct audiomixer *self, int timeout_sec);
const struct mixer_control ** audiomixer_get_active_controls(
diff --git a/conf.d/cmake/config.cmake b/conf.d/cmake/config.cmake
index 04501a8..09d91ae 100644
--- a/conf.d/cmake/config.cmake
+++ b/conf.d/cmake/config.cmake
@@ -72,7 +72,7 @@ set (PKG_REQUIRED_LIST
libsystemd>=222
afb-daemon
libpipewire-0.3
- wireplumber-0.1
+ wireplumber-0.4
)
# Static constante definition