+static DBusHandlerResult filter_cb(DBusConnection *bus, DBusMessage *msg, void *userdata) {
+ DBusMessageIter arg_i;
+ DBusError err;
+ const char *value;
+ struct userdata *u;
+
+ pa_assert(bus);
+ pa_assert(msg);
+ pa_assert(userdata);
+ u = userdata;
+
+ pa_log_debug("dbus: interface=%s, path=%s, member=%s\n",
+ dbus_message_get_interface(msg),
+ dbus_message_get_path(msg),
+ dbus_message_get_member(msg));
+
+ dbus_error_init(&err);
+
+ if (dbus_message_is_signal(msg, "org.bluez.Headset", "PropertyChanged") ||
+ dbus_message_is_signal(msg, "org.bluez.AudioSink", "PropertyChanged")) {
+
+ struct device *d;
+ const char *profile;
+ DBusMessageIter variant_i;
+ dbus_uint16_t gain;
+
+ if (!dbus_message_iter_init(msg, &arg_i)) {
+ pa_log("dbus: message has no parameters");
+ goto done;
+ }
+
+ if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_STRING) {
+ pa_log("Property name not a string.");
+ goto done;
+ }
+
+ dbus_message_iter_get_basic(&arg_i, &value);
+
+ if (!dbus_message_iter_next(&arg_i)) {
+ pa_log("Property value missing");
+ goto done;
+ }
+
+ if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_VARIANT) {
+ pa_log("Property value not a variant.");
+ goto done;
+ }
+
+ dbus_message_iter_recurse(&arg_i, &variant_i);
+
+ if (dbus_message_iter_get_arg_type(&variant_i) != DBUS_TYPE_UINT16) {
+ dbus_message_iter_get_basic(&variant_i, &gain);
+
+ if (pa_streq(value, "SpeakerGain")) {
+ pa_log("spk gain: %d", gain);
+ pa_cvolume_set(&u->sink->volume, 1, (pa_volume_t) (gain * PA_VOLUME_NORM / 15));
+ u->sink->virtual_volume = u->sink->volume;
+ pa_subscription_post(u->sink->core, PA_SUBSCRIPTION_EVENT_SINK|PA_SUBSCRIPTION_EVENT_CHANGE, u->sink->index);
+ } else {
+ pa_log("mic gain: %d", gain);
+ if (!u->source)
+ goto done;
+
+ pa_cvolume_set(&u->source->volume, 1, (pa_volume_t) (gain * PA_VOLUME_NORM / 15));
+ pa_subscription_post(u->source->core, PA_SUBSCRIPTION_EVENT_SOURCE|PA_SUBSCRIPTION_EVENT_CHANGE, u->source->index);
+ }
+ }
+ }
+
+done:
+ dbus_error_free(&err);
+ return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static int sink_get_volume_cb(pa_sink *s) {
+ struct userdata *u = s->userdata;
+ pa_assert(u);
+
+ /* refresh? */
+
+ return 0;
+}
+
+static int source_get_volume_cb(pa_source *s) {
+ struct userdata *u = s->userdata;
+ pa_assert(u);
+
+ /* refresh? */
+
+ return 0;
+}
+
+static int sink_set_volume_cb(pa_sink *s) {
+ DBusError e;
+ DBusMessage *m, *r;
+ DBusMessageIter it, itvar;
+ dbus_uint16_t vol;
+ const char *spkgain = "SpeakerGain";
+ struct userdata *u = s->userdata;
+ pa_assert(u);
+
+ dbus_error_init(&e);
+
+ vol = ((float)pa_cvolume_max(&s->volume) / PA_VOLUME_NORM) * 15;
+ pa_log_debug("set headset volume: %d", vol);
+
+ pa_assert_se(m = dbus_message_new_method_call("org.bluez", u->path, "org.bluez.Headset", "SetProperty"));
+ dbus_message_iter_init_append(m, &it);
+ dbus_message_iter_append_basic(&it, DBUS_TYPE_STRING, &spkgain);
+ dbus_message_iter_open_container(&it, DBUS_TYPE_VARIANT, DBUS_TYPE_UINT16_AS_STRING, &itvar);
+ dbus_message_iter_append_basic(&itvar, DBUS_TYPE_UINT16, &vol);
+ dbus_message_iter_close_container(&it, &itvar);
+
+ r = dbus_connection_send_with_reply_and_block(pa_dbus_connection_get(u->conn), m, -1, &e);
+
+finish:
+ if (m)
+ dbus_message_unref(m);
+ if (r)
+ dbus_message_unref(r);
+
+ dbus_error_free(&e);
+
+ return 0;
+}
+
+static int source_set_volume_cb(pa_source *s) {
+ dbus_uint16_t vol;
+ struct userdata *u = s->userdata;
+ pa_assert(u);
+
+ vol = ((float)pa_cvolume_max(&s->volume) / PA_VOLUME_NORM) * 15;
+
+ pa_log_debug("set headset mic volume: %d (not implemented yet)", vol);
+
+ return 0;
+}
+