diff options
Diffstat (limited to 'binding')
-rw-r--r-- | binding/CMakeLists.txt | 19 | ||||
-rw-r--r-- | binding/audiomixer-binding.c | 402 | ||||
-rw-r--r-- | binding/audiomixer.c | 463 | ||||
-rw-r--r-- | binding/audiomixer.h | 59 |
4 files changed, 0 insertions, 943 deletions
diff --git a/binding/CMakeLists.txt b/binding/CMakeLists.txt deleted file mode 100644 index c199ad2..0000000 --- a/binding/CMakeLists.txt +++ /dev/null @@ -1,19 +0,0 @@ -PROJECT_TARGET_ADD(audiomixer-binding) - - add_definitions(-DAFB_BINDING_VERSION=3) - - set(audiomixer_SOURCES - audiomixer-binding.c - audiomixer.c - ) - - add_library(${TARGET_NAME} MODULE ${audiomixer_SOURCES}) - - SET_TARGET_PROPERTIES(${TARGET_NAME} PROPERTIES - PREFIX "libafm-" - LABELS "BINDING" - LINK_FLAGS ${BINDINGS_LINK_FLAG} - OUTPUT_NAME ${TARGET_NAME} - ) - - TARGET_LINK_LIBRARIES(${TARGET_NAME} ${link_libraries}) diff --git a/binding/audiomixer-binding.c b/binding/audiomixer-binding.c deleted file mode 100644 index 2c8981a..0000000 --- a/binding/audiomixer-binding.c +++ /dev/null @@ -1,402 +0,0 @@ -/* - * Copyright © 2019 Collabora Ltd. - * Copyright © 2019 Konsulko Group - * @author George Kiagiadakis <george.kiagiadakis@collabora.com> - * - * SPDX-License-Identifier: MIT - */ - -#include <string.h> -#include <json-c/json.h> -#include <afb/afb-binding.h> -#include <systemd/sd-event.h> -#include "audiomixer.h" - -static struct audiomixer *audiomixer; -static afb_event_t controls_changed; -static afb_event_t volume_changed; -static afb_event_t mute_changed; - -static const char *signalcomposer_events[] = { - "event.volume.up", - "event.volume.down", - "event.volume.mute", - NULL, -}; - -static void -audiomixer_controls_changed_deferred(int signum, void *arg) -{ - AFB_DEBUG("controls changed"); - afb_event_push(controls_changed, NULL); -} - -struct value_changed_data -{ - unsigned int change_mask; - struct mixer_control control; -}; - -static void -audiomixer_value_changed_deferred(int signum, void *data) -{ - struct value_changed_data *d = data; - json_object *json; - - AFB_DEBUG("value changed"); - - json = json_object_new_object(); - json_object_object_add(json, "control", - json_object_new_string(d->control.name)); - - if (d->change_mask & MIXER_CONTROL_CHANGE_FLAG_VOLUME) { - json_object_object_add(json, "value", - json_object_new_double(d->control.volume)); - afb_event_push(volume_changed, json); - } else if (d->change_mask & MIXER_CONTROL_CHANGE_FLAG_MUTE) { - json_object_object_add(json, "value", - json_object_new_int(d->control.mute)); - afb_event_push(mute_changed, json); - } - - free(d); -} - -/* called in audiomixer's thread */ -static void -audiomixer_controls_changed(void *data) -{ - afb_api_t api = data; - afb_api_queue_job (api, audiomixer_controls_changed_deferred, NULL, - (void *) 0x1, 0); -} - - -/* called in audiomixer's thread */ -static void -audiomixer_value_changed(void *data, - unsigned int change_mask, - const struct mixer_control *control) -{ - afb_api_t api = data; - struct value_changed_data *d = calloc(1, sizeof(*d)); - - d->change_mask = change_mask; - d->control = *control; - - afb_api_queue_job (api, audiomixer_value_changed_deferred, d, - (void *) 0x1, 0); -} - -static const struct audiomixer_events audiomixer_events = { - .controls_changed = audiomixer_controls_changed, - .value_changed = audiomixer_value_changed, -}; - -static int -cleanup(sd_event_source *s, void *data) -{ - audiomixer_free(audiomixer); - audiomixer = NULL; - return 0; -} - -static int -init(afb_api_t api) -{ - int ret; - - ret = afb_daemon_require_api("signal-composer", 1); - if (ret) { - AFB_WARNING("unable to initialize signal-composer binding"); - } else { - const char **tmp = signalcomposer_events; - json_object *args = json_object_new_object(); - json_object *signals = json_object_new_array(); - - while (*tmp) { - json_object_array_add(signals, json_object_new_string(*tmp++)); - } - json_object_object_add(args, "signal", signals); - if(json_object_array_length(signals)) { - afb_api_call_sync(api, "signal-composer", "subscribe", - args, NULL, NULL, NULL); - } else { - json_object_put(args); - } - } - - sd_event *e = afb_daemon_get_event_loop(); - - controls_changed = afb_api_make_event(api, "controls_changed"); - volume_changed = afb_api_make_event(api, "volume_changed"); - mute_changed = afb_api_make_event(api, "mute_changed"); - - audiomixer = audiomixer_new(); - sd_event_add_exit(e, NULL, cleanup, NULL); - - audiomixer_add_event_listener(audiomixer, &audiomixer_events, api); - - return 0; -} - -static void -list_controls_cb(afb_req_t request) -{ - json_object *ret_json, *nest_json; - const struct mixer_control **ctls; - unsigned int n_controls, i; - - audiomixer_lock(audiomixer); - - if (audiomixer_ensure_controls(audiomixer, 3) < 0) { - AFB_REQ_NOTICE(request, "No mixer controls were exposed " - "in PipeWire after 3 seconds"); - } - - ctls = audiomixer_get_active_controls(audiomixer, &n_controls); - - ret_json = json_object_new_array(); - for (i = 0; i < n_controls; i++) { - nest_json = json_object_new_object(); - json_object_object_add(nest_json, "control", - json_object_new_string(ctls[i]->name)); - json_object_object_add(nest_json, "volume", - json_object_new_double(ctls[i]->volume)); - json_object_object_add(nest_json, "mute", - json_object_new_int(ctls[i]->mute)); - json_object_array_add(ret_json, nest_json); - } - afb_req_success(request, ret_json, NULL); - - audiomixer_unlock(audiomixer); -} - -static void -volume_cb(afb_req_t request) -{ - json_object *ret_json; - const char *control = afb_req_value(request, "control"); - const char *value = afb_req_value(request, "value"); - const struct mixer_control *ctl; - double volume; - - audiomixer_lock(audiomixer); - - if (!control) { - afb_req_fail(request, "failed", - "Invalid arguments: missing 'control'"); - goto unlock; - } - - if (audiomixer_ensure_controls(audiomixer, 3) < 0) { - AFB_REQ_NOTICE(request, "No mixer controls were exposed " - "in PipeWire after 3 seconds"); - } - - ctl = audiomixer_find_control(audiomixer, control); - if (!ctl) { - afb_req_fail(request, "failed", "Could not find control"); - goto unlock; - } - - if(value) { - char *endptr; - volume = strtod(value, &endptr); - if (endptr == value || volume < -0.00001 || volume > 1.00001) { - afb_req_fail(request, "failed", - "Invalid volume value (must be between 0.0 and 1.0)"); - goto unlock; - } - - audiomixer_change_volume(audiomixer, ctl, volume); - } else { - volume = ctl->volume; - } - - ret_json = json_object_new_object(); - json_object_object_add(ret_json, "volume", json_object_new_double(volume)); - afb_req_success(request, ret_json, NULL); - -unlock: - audiomixer_unlock(audiomixer); -} - -static void -mute_cb(afb_req_t request) -{ - json_object *ret_json; - const char *control = afb_req_value(request, "control"); - const char *value = afb_req_value(request, "value"); - const struct mixer_control *ctl; - int mute; - - audiomixer_lock(audiomixer); - - if (!control) { - afb_req_fail(request, "failed", - "Invalid arguments: missing 'control'"); - goto unlock; - } - - if (audiomixer_ensure_controls(audiomixer, 3) < 0) { - AFB_REQ_NOTICE(request, "No mixer controls were exposed " - "in PipeWire after 3 seconds"); - } - - ctl = audiomixer_find_control(audiomixer, control); - if (!ctl) { - afb_req_fail(request, "failed", "Could not find control"); - goto unlock; - } - - if(value) { - char *endptr; - mute = (int) strtol(value, &endptr, 10); - if (endptr == value || mute < 0 || mute > 1) { - afb_req_fail(request, "failed", - "Invalid mute value (must be integer 0 or 1)"); - goto unlock; - } - - audiomixer_change_mute(audiomixer, ctl, mute); - } else { - mute = ctl->mute; - } - - ret_json = json_object_new_object(); - json_object_object_add(ret_json, "mute", json_object_new_int(mute)); - afb_req_success(request, ret_json, NULL); - -unlock: - audiomixer_unlock(audiomixer); -} - -static void -subscribe_cb(afb_req_t request) -{ - const char *eventstr = afb_req_value(request, "event"); - afb_event_t event; - - if (!eventstr) { - afb_req_fail(request, "failed", - "Invalid arguments: missing 'event'"); - return; - } - - if (!strcmp(eventstr, "controls_changed")) - event = controls_changed; - else if (!strcmp(eventstr, "volume_changed")) - event = volume_changed; - else if (!strcmp(eventstr, "mute_changed")) - event = mute_changed; - else { - afb_req_fail(request, "failed", "Invalid event name"); - return; - } - - if (afb_req_subscribe(request, event) != 0) - afb_req_fail(request, "failed", "Failed to subscribe to event"); - else - afb_req_success(request, NULL, "Subscribed"); -} - -static void -unsubscribe_cb(afb_req_t request) -{ - const char *eventstr = afb_req_value(request, "event"); - afb_event_t event; - - if (!eventstr) { - afb_req_fail(request, "failed", - "Invalid arguments: missing 'event'"); - return; - } - - if (!strcmp(eventstr, "controls_changed")) - event = controls_changed; - else if (!strcmp(eventstr, "volume_changed")) - event = volume_changed; - else if (!strcmp(eventstr, "mute_changed")) - event = mute_changed; - else { - afb_req_fail(request, "failed", "Invalid event name"); - return; - } - - if (afb_req_unsubscribe(request, event) != 0) - afb_req_fail(request, "failed", "Failed to unsubscribe from event"); - else - afb_req_success(request, NULL, "Unsubscribed"); -} - -static void -onevent(afb_api_t api, const char *event, struct json_object *object) -{ - const struct mixer_control *ctl; - json_object *tmp = NULL; - const char *uid; - const char *value; - - json_object_object_get_ex(object, "uid", &tmp); - if (tmp == NULL) - return; - - uid = json_object_get_string(tmp); - if (strncmp(uid, "event.volume.", 13)) - return; - - json_object_object_get_ex(object, "value", &tmp); - if (tmp == NULL) - return; - - value = json_object_get_string(tmp); - if (strncmp(value, "true", 4)) - return; - - audiomixer_lock(audiomixer); - - ctl = audiomixer_find_control(audiomixer, "Master Playback"); - if (!ctl) - goto unlock; - - if (!strcmp(uid, "event.volume.mute")) { - audiomixer_change_mute(audiomixer, ctl, !ctl->mute); - } else { - double volume = ctl->volume; - - if (!strcmp(uid, "event.volume.up")) { - volume += 0.05; // up 5% - if (volume > 1.0) - volume = 1.0; // clamp to 100% - } else if (!strcmp(uid, "event.volume.down")) { - volume -= 0.05; // down 5% - if (volume < 0.0) - volume = 0.0; // clamp to 0% - } else { - AFB_WARNING("Unhandled signal-composer uid '%s'", uid); - goto unlock; - } - audiomixer_change_volume(audiomixer, ctl, volume); - } - -unlock: - audiomixer_unlock(audiomixer); -} - -static const afb_verb_t verbs[]= { - { .verb = "list_controls", .callback = list_controls_cb, .info = "List the available controls" }, - { .verb = "volume", .callback = volume_cb, .info = "Get/Set volume" }, - { .verb = "mute", .callback = mute_cb, .info = "Get/Set mute" }, - { .verb = "subscribe", .callback = subscribe_cb, .info = "Subscribe to mixer events" }, - { .verb = "unsubscribe", .callback = unsubscribe_cb, .info = "Unsubscribe from mixer events" }, - { } -}; - -const afb_binding_t afbBindingV3 = { - .api = "audiomixer", - .specification = "AudioMixer API", - .verbs = verbs, - .onevent = onevent, - .init = init, -}; diff --git a/binding/audiomixer.c b/binding/audiomixer.c deleted file mode 100644 index 97ad622..0000000 --- a/binding/audiomixer.c +++ /dev/null @@ -1,463 +0,0 @@ -/* - * Copyright © 2019 Collabora Ltd. - * @author George Kiagiadakis <george.kiagiadakis@collabora.com> - * - * SPDX-License-Identifier: MIT - */ - -#include "audiomixer.h" -#include <wp/wp.h> -#include <pipewire/pipewire.h> - -struct audiomixer -{ - WpCore *core; - GMainLoop *loop; - GMainContext *context; - GThread *thread; - GMutex lock; - GCond cond; - - GPtrArray *mixer_controls; - - gint initialized; - WpObjectManager *om; - WpPlugin *default_nodes_api; - WpPlugin *mixer_api; - - const struct audiomixer_events *events; - void *events_data; -}; - -struct mixer_control_impl -{ - struct mixer_control pub; - guint32 node_id; -}; - -struct action -{ - struct audiomixer *audiomixer; - union { - struct { - guint32 id; - gfloat volume; - } change_volume; - struct { - guint32 id; - gboolean mute; - } change_mute; - }; -}; - -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) && - g_variant_lookup (v, "mute", "b", mute); -} - -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 -volume_changed (struct audiomixer * self, guint32 node_id) -{ - 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->node_id != node_id) - continue; - - if (!get_mixer_controls (self, node_id, &vol, &mute)) { - g_warning ("failed to get object controls when volume changed"); - return; - } - - if ((ctl->pub.volume - 0.01f) > vol || (ctl->pub.volume + 0.01f) < vol) { - ctl->pub.volume = vol; - change_mask |= MIXER_CONTROL_CHANGE_FLAG_VOLUME; - } - if (ctl->pub.mute != mute) { - ctl->pub.mute = mute; - change_mask |= MIXER_CONTROL_CHANGE_FLAG_MUTE; - } - - if (self->events && self->events->value_changed) - self->events->value_changed (self->events_data, change_mask, &ctl->pub); - break; - } -} - -static void -rescan_controls (struct audiomixer * self) -{ - 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); - } - - /* notify subscribers */ - if (self->events && self->events->controls_changed) - self->events->controls_changed (self->events_data); - g_cond_broadcast (&self->cond); -} - -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); - } - - if (wp_object_get_active_features (WP_OBJECT (self->mixer_api)) - & WP_PLUGIN_FEATURE_ENABLED) - wp_core_install_object_manager (self->core, self->om); - - g_signal_connect_swapped (self->default_nodes_api, "changed", - (GCallback) rescan_controls, self); -} - -static void -on_mixer_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); - } - - 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 -on_core_connected (struct audiomixer * 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 -on_core_disconnected (struct audiomixer * 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 -audiomixer_init_in_thread (struct audiomixer * self) -{ - g_autoptr (GMutexLocker) locker = g_mutex_locker_new (&self->lock); - g_autoptr (GError) error = NULL; - - 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) -{ - audiomixer_init_in_thread (self); - - /* main loop for the thread; quits only when audiomixer_free() is called */ - g_main_loop_run (self->loop); - - 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_context_pop_thread_default (self->context); - g_main_loop_unref (self->loop); - g_main_context_unref (self->context); - - return NULL; -} - -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->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; -} - -void -audiomixer_free(struct audiomixer *self) -{ - g_main_loop_quit (self->loop); - g_thread_join (self->thread); - - g_ptr_array_unref (self->mixer_controls); - g_cond_clear (&self->cond); - g_mutex_clear (&self->lock); - - free (self); -} - -void -audiomixer_lock(struct audiomixer *self) -{ - g_mutex_lock (&self->lock); -} - -void -audiomixer_unlock(struct audiomixer *self) -{ - g_mutex_unlock (&self->lock); -} - -static gboolean -do_connect (WpCore * core) -{ - 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; - } - return 0; -} - -const struct mixer_control ** -audiomixer_get_active_controls(struct audiomixer *self, - unsigned int *n_controls) -{ - *n_controls = self->mixer_controls->len; - return (const struct mixer_control **) self->mixer_controls->pdata; -} - -const struct mixer_control * -audiomixer_find_control(struct audiomixer *self, const char *name) -{ - struct mixer_control *ctl; - - for (guint i = 0; i < self->mixer_controls->len; i++) { - ctl = g_ptr_array_index (self->mixer_controls, i); - if (!strcmp(ctl->name, name)) { - return ctl; - } - } - return NULL; -} - -void -audiomixer_add_event_listener(struct audiomixer *self, - const struct audiomixer_events *events, - void *data) -{ - self->events = events; - self->events_data = data; -} - -static gboolean -do_change_volume (struct action * action) -{ - 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"); - - return G_SOURCE_REMOVE; -} - -void -audiomixer_change_volume(struct audiomixer *self, - const struct mixer_control *control, - double volume) -{ - const struct mixer_control_impl *impl = - (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->node_id; - action->change_volume.volume = (gfloat) volume; - wp_core_idle_add (self->core, NULL, (GSourceFunc) do_change_volume, action, - g_free); -} - -static gboolean -do_change_mute (struct action * action) -{ - 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"); - - return G_SOURCE_REMOVE; -} - -void -audiomixer_change_mute(struct audiomixer *self, - const struct mixer_control *control, - bool mute) -{ - const struct mixer_control_impl *impl = - (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->node_id; - action->change_mute.mute = mute; - wp_core_idle_add (self->core, NULL, (GSourceFunc) do_change_mute, action, - g_free); -} diff --git a/binding/audiomixer.h b/binding/audiomixer.h deleted file mode 100644 index 47bd703..0000000 --- a/binding/audiomixer.h +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Copyright © 2019 Collabora Ltd. - * @author George Kiagiadakis <george.kiagiadakis@collabora.com> - * - * SPDX-License-Identifier: MIT - */ - -#include <stdbool.h> - -struct audiomixer; - -struct mixer_control -{ - char name[32]; - double volume; - bool mute; -}; - -struct audiomixer_events -{ - void (*controls_changed) (void *data); - - void (*value_changed) (void *data, -#define MIXER_CONTROL_CHANGE_FLAG_VOLUME (1<<0) -#define MIXER_CONTROL_CHANGE_FLAG_MUTE (1<<1) - unsigned int change_mask, - const struct mixer_control *control); -}; - -struct audiomixer * audiomixer_new(void); -void audiomixer_free(struct audiomixer *self); - -/* locking is required to call any of the methods below - * and to access any structure maintained by audiomixer */ -void audiomixer_lock(struct audiomixer *self); -void audiomixer_unlock(struct audiomixer *self); - -int audiomixer_ensure_controls(struct audiomixer *self, int timeout_sec); - -const struct mixer_control ** audiomixer_get_active_controls( - struct audiomixer *self, - unsigned int *n_controls); - -const struct mixer_control * audiomixer_find_control( - struct audiomixer *self, - const char *name); - -void audiomixer_add_event_listener(struct audiomixer *self, - const struct audiomixer_events *events, - void *data); - -void audiomixer_change_volume(struct audiomixer *self, - const struct mixer_control *control, - double volume); - -void audiomixer_change_mute(struct audiomixer *self, - const struct mixer_control *control, - bool mute); - |