]> code.delx.au - pulseaudio/blobdiff - src/modules/dbus/iface-stream.c
sink-input, source-output: Remove redundant get_mute() functions
[pulseaudio] / src / modules / dbus / iface-stream.c
index 0255be4bb44fb181d879c68052ffc403719fadc1..4cbcd74f8599f2f7fef88aef4057a92f8ca132b9 100644 (file)
@@ -56,6 +56,8 @@ struct pa_dbusiface_stream {
     dbus_bool_t mute;
     pa_proplist *proplist;
 
+    bool has_volume;
+
     pa_dbus_protocol *dbus_protocol;
     pa_subscription *subscription;
     pa_hook_slot *send_event_slot;
@@ -189,6 +191,14 @@ static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userd
     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
 }
 
+/* The returned string has to be freed with pa_xfree() by the caller. */
+static char *stream_to_string(pa_dbusiface_stream *s) {
+    if (s->type == STREAM_TYPE_PLAYBACK)
+        return pa_sprintf_malloc("Playback stream %u", (unsigned) s->sink_input->index);
+    else
+        return pa_sprintf_malloc("Record stream %u", (unsigned) s->source_output->index);
+}
+
 static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) {
     pa_dbusiface_stream *s = userdata;
     const char *driver = NULL;
@@ -200,12 +210,11 @@ static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *user
     driver = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->driver : s->source_output->driver;
 
     if (!driver) {
-        if (s->type == STREAM_TYPE_PLAYBACK)
-            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
-                               "Playback stream %u doesn't have a driver.", s->sink_input->index);
-        else
-            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
-                               "Record stream %u doesn't have a driver.", s->source_output->index);
+        char *str = stream_to_string(s);
+
+        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have a driver.", str);
+        pa_xfree(str);
+
         return;
     }
 
@@ -224,12 +233,11 @@ static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void
     owner_module = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->module : s->source_output->module;
 
     if (!owner_module) {
-        if (s->type == STREAM_TYPE_PLAYBACK)
-            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
-                               "Playback stream %u doesn't have an owner module.", s->sink_input->index);
-        else
-            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
-                               "Record stream %u doesn't have an owner module.", s->source_output->index);
+        char *str = stream_to_string(s);
+
+        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have an owner module.", str);
+        pa_xfree(str);
+
         return;
     }
 
@@ -250,12 +258,11 @@ static void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *user
     client = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->client : s->source_output->client;
 
     if (!client) {
-        if (s->type == STREAM_TYPE_PLAYBACK)
-            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
-                               "Playback stream %u isn't associated to any client.", s->sink_input->index);
-        else
-            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY,
-                               "Record stream %u isn't associated to any client.", s->source_output->index);
+        char *str = stream_to_string(s);
+
+        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s isn't associated to any client.", str);
+        pa_xfree(str);
+
         return;
     }
 
@@ -332,8 +339,12 @@ static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *user
     pa_assert(msg);
     pa_assert(s);
 
-    if (s->type == STREAM_TYPE_RECORD) {
-        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have volume.");
+    if (!s->has_volume) {
+        char *str = stream_to_string(s);
+
+        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have volume.", str);
+        pa_xfree(str);
+
         return;
     }
 
@@ -345,6 +356,7 @@ static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *user
 
 static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessageIter *iter, void *userdata) {
     pa_dbusiface_stream *s = userdata;
+    bool volume_writable = true;
     DBusMessageIter array_iter;
     int stream_channels = 0;
     dbus_uint32_t *volume = NULL;
@@ -357,35 +369,43 @@ static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, DBusMessag
     pa_assert(iter);
     pa_assert(s);
 
-    if (s->type == STREAM_TYPE_RECORD) {
-        pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "Record streams don't have volume.");
+    volume_writable = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->volume_writable : false;
+
+    if (!s->has_volume || !volume_writable) {
+        char *str = stream_to_string(s);
+
+        if (!s->has_volume)
+            pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NO_SUCH_PROPERTY, "%s doesn't have volume.", str);
+        else if (!volume_writable)
+            pa_dbus_send_error(conn, msg, DBUS_ERROR_ACCESS_DENIED, "%s has read-only volume.", str);
+        pa_xfree(str);
+
         return;
     }
 
-    pa_cvolume_init(&new_vol);
-
     stream_channels = s->sink_input->channel_map.channels;
 
-    new_vol.channels = stream_channels;
-
     dbus_message_iter_recurse(iter, &array_iter);
     dbus_message_iter_get_fixed_array(&array_iter, &volume, &n_volume_entries);
 
-    if (n_volume_entries != stream_channels) {
+    if (n_volume_entries != stream_channels && n_volume_entries != 1) {
         pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
                            "Expected %u volume entries, got %u.", stream_channels, n_volume_entries);
         return;
     }
 
+    pa_cvolume_init(&new_vol);
+    new_vol.channels = n_volume_entries;
+
     for (i = 0; i < n_volume_entries; ++i) {
-        if (volume[i] > PA_VOLUME_MAX) {
-            pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Too large volume value: %u", volume[i]);
+        if (!PA_VOLUME_IS_VALID(volume[i])) {
+            pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Invalid volume: %u", volume[i]);
             return;
         }
         new_vol.values[i] = volume[i];
     }
 
-    pa_sink_input_set_volume(s->sink_input, &new_vol, TRUE, TRUE);
+    pa_sink_input_set_volume(s->sink_input, &new_vol, true, true);
 
     pa_dbus_send_empty_reply(conn, msg);
 }
@@ -421,10 +441,10 @@ static void handle_set_mute(DBusConnection *conn, DBusMessage *msg, DBusMessageI
         return;
     }
 
-    pa_sink_input_set_mute(s->sink_input, mute, TRUE);
+    pa_sink_input_set_mute(s->sink_input, mute, true);
 
     pa_dbus_send_empty_reply(conn, msg);
-};
+}
 
 static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
     pa_dbusiface_stream *s = userdata;
@@ -471,6 +491,9 @@ static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, v
     else
         resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
 
+    if (!resample_method)
+        resample_method = "";
+
     pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &resample_method);
 }
 
@@ -509,6 +532,11 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
     pa_assert(msg);
     pa_assert(s);
 
+    if (s->has_volume) {
+        for (i = 0; i < s->volume.channels; ++i)
+            volume[i] = s->volume.values[i];
+    }
+
     if (s->type == STREAM_TYPE_PLAYBACK) {
         idx = s->sink_input->index;
         driver = s->sink_input->driver;
@@ -517,8 +545,6 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
         device = pa_dbusiface_core_get_sink_path(s->core, s->sink);
         sample_format = s->sink_input->sample_spec.format;
         channel_map = &s->sink_input->channel_map;
-        for (i = 0; i < s->volume.channels; ++i)
-            volume[i] = s->volume.values[i];
         buffer_latency = pa_sink_input_get_latency(s->sink_input, &device_latency);
         resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
     } else {
@@ -538,6 +564,8 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
         client_path = pa_dbusiface_core_get_client_path(s->core, client);
     for (i = 0; i < channel_map->channels; ++i)
         channels[i] = channel_map->map[i];
+    if (!resample_method)
+        resample_method = "";
 
     pa_assert_se((reply = dbus_message_new_method_return(msg)));
 
@@ -555,11 +583,12 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
     if (client)
         pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CLIENT].property_name, DBUS_TYPE_OBJECT_PATH, &client_path);
 
+    pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE].property_name, DBUS_TYPE_OBJECT_PATH, &device);
     pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_FORMAT].property_name, DBUS_TYPE_UINT32, &sample_format);
     pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_SAMPLE_RATE].property_name, DBUS_TYPE_UINT32, &s->sample_rate);
     pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_CHANNELS].property_name, DBUS_TYPE_UINT32, channels, channel_map->channels);
 
-    if (s->type == STREAM_TYPE_PLAYBACK) {
+    if (s->has_volume) {
         pa_dbus_append_basic_array_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_VOLUME].property_name, DBUS_TYPE_UINT32, volume, s->volume.channels);
         pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_MUTE].property_name, DBUS_TYPE_BOOLEAN, &s->mute);
     }
@@ -582,7 +611,7 @@ static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata)
     pa_assert(msg);
     pa_assert(s);
 
-    pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &device, DBUS_TYPE_INVALID));
+    pa_assert_se(dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device, DBUS_TYPE_INVALID));
 
     if (s->type == STREAM_TYPE_PLAYBACK) {
         pa_sink *sink = pa_dbusiface_core_get_sink(s->core, device);
@@ -592,7 +621,7 @@ static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata)
             return;
         }
 
-        if (pa_sink_input_move_to(s->sink_input, sink, TRUE) < 0) {
+        if (pa_sink_input_move_to(s->sink_input, sink, true) < 0) {
             pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
                                "Moving playback stream %u to sink %s failed.", s->sink_input->index, sink->name);
             return;
@@ -605,7 +634,7 @@ static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata)
             return;
         }
 
-        if (pa_source_output_move_to(s->source_output, source, TRUE) < 0) {
+        if (pa_source_output_move_to(s->source_output, source, true) < 0) {
             pa_dbus_send_error(conn, msg, DBUS_ERROR_FAILED,
                                "Moving record stream %u to source %s failed.", s->source_output->index, source->name);
             return;
@@ -663,8 +692,8 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
             new_device_path = pa_dbusiface_core_get_sink_path(s->core, new_sink);
 
             pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
-                                                             PA_DBUSIFACE_STREAM_INTERFACE,
-                                                             signals[SIGNAL_DEVICE_UPDATED].name));
+                                                              PA_DBUSIFACE_STREAM_INTERFACE,
+                                                              signals[SIGNAL_DEVICE_UPDATED].name));
             pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
 
             pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
@@ -681,8 +710,8 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
             new_device_path = pa_dbusiface_core_get_source_path(s->core, new_source);
 
             pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
-                                                             PA_DBUSIFACE_STREAM_INTERFACE,
-                                                             signals[SIGNAL_DEVICE_UPDATED].name));
+                                                              PA_DBUSIFACE_STREAM_INTERFACE,
+                                                              signals[SIGNAL_DEVICE_UPDATED].name));
             pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
 
             pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
@@ -697,8 +726,8 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
         s->sample_rate = new_sample_rate;
 
         pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
-                                                         PA_DBUSIFACE_STREAM_INTERFACE,
-                                                         signals[SIGNAL_SAMPLE_RATE_UPDATED].name));
+                                                          PA_DBUSIFACE_STREAM_INTERFACE,
+                                                          signals[SIGNAL_SAMPLE_RATE_UPDATED].name));
         pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_UINT32, &s->sample_rate, DBUS_TYPE_INVALID));
 
         pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
@@ -707,40 +736,43 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
     }
 
     if (s->type == STREAM_TYPE_PLAYBACK) {
-        pa_cvolume new_volume;
-        pa_bool_t new_mute = FALSE;
+        bool new_mute = false;
 
-        pa_sink_input_get_volume(s->sink_input, &new_volume, TRUE);
+        if (s->has_volume) {
+            pa_cvolume new_volume;
 
-        if (!pa_cvolume_equal(&s->volume, &new_volume)) {
-            dbus_uint32_t volume[PA_CHANNELS_MAX];
-            dbus_uint32_t *volume_ptr = volume;
+            pa_sink_input_get_volume(s->sink_input, &new_volume, true);
 
-            s->volume = new_volume;
+            if (!pa_cvolume_equal(&s->volume, &new_volume)) {
+                dbus_uint32_t volume[PA_CHANNELS_MAX];
+                dbus_uint32_t *volume_ptr = volume;
 
-            for (i = 0; i < s->volume.channels; ++i)
-                volume[i] = s->volume.values[i];
+                s->volume = new_volume;
 
-            pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
-                                                             PA_DBUSIFACE_STREAM_INTERFACE,
-                                                             signals[SIGNAL_VOLUME_UPDATED].name));
-            pa_assert_se(dbus_message_append_args(signal_msg,
-                                                  DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
-                                                  DBUS_TYPE_INVALID));
+                for (i = 0; i < s->volume.channels; ++i)
+                    volume[i] = s->volume.values[i];
 
-            pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
-            dbus_message_unref(signal_msg);
-            signal_msg = NULL;
+                pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
+                                                                  PA_DBUSIFACE_STREAM_INTERFACE,
+                                                                  signals[SIGNAL_VOLUME_UPDATED].name));
+                pa_assert_se(dbus_message_append_args(signal_msg,
+                                                      DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
+                                                      DBUS_TYPE_INVALID));
+
+                pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
+                dbus_message_unref(signal_msg);
+                signal_msg = NULL;
+            }
         }
 
-        new_mute = pa_sink_input_get_mute(s->sink_input);
+        new_mute = s->sink_input->muted;
 
         if (s->mute != new_mute) {
             s->mute = new_mute;
 
             pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
-                                                             PA_DBUSIFACE_STREAM_INTERFACE,
-                                                             signals[SIGNAL_MUTE_UPDATED].name));
+                                                              PA_DBUSIFACE_STREAM_INTERFACE,
+                                                              signals[SIGNAL_MUTE_UPDATED].name));
             pa_assert_se(dbus_message_append_args(signal_msg, DBUS_TYPE_BOOLEAN, &s->mute, DBUS_TYPE_INVALID));
 
             pa_dbus_protocol_send_signal(s->dbus_protocol, signal_msg);
@@ -757,8 +789,8 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
         pa_proplist_update(s->proplist, PA_UPDATE_SET, new_proplist);
 
         pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
-                                                         PA_DBUSIFACE_STREAM_INTERFACE,
-                                                         signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
+                                                          PA_DBUSIFACE_STREAM_INTERFACE,
+                                                          signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
         dbus_message_iter_init_append(signal_msg, &msg_iter);
         pa_dbus_append_proplist(&msg_iter, s->proplist);
 
@@ -797,8 +829,8 @@ static pa_hook_result_t send_event_cb(void *hook_data, void *call_data, void *sl
     }
 
     pa_assert_se(signal_msg = dbus_message_new_signal(s->path,
-                                                     PA_DBUSIFACE_STREAM_INTERFACE,
-                                                     signals[SIGNAL_STREAM_EVENT].name));
+                                                      PA_DBUSIFACE_STREAM_INTERFACE,
+                                                      signals[SIGNAL_STREAM_EVENT].name));
     dbus_message_iter_init_append(signal_msg, &msg_iter);
     pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name));
     pa_dbus_append_proplist(&msg_iter, property_list);
@@ -822,8 +854,14 @@ pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, p
     s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, PLAYBACK_OBJECT_NAME, sink_input->index);
     s->sink = pa_sink_ref(sink_input->sink);
     s->sample_rate = sink_input->sample_spec.rate;
-    pa_sink_input_get_volume(sink_input, &s->volume, TRUE);
-    s->mute = pa_sink_input_get_mute(sink_input);
+    s->has_volume = pa_sink_input_is_volume_readable(sink_input);
+
+    if (s->has_volume)
+        pa_sink_input_get_volume(sink_input, &s->volume, true);
+    else
+        pa_cvolume_init(&s->volume);
+
+    s->mute = sink_input->muted;
     s->proplist = pa_proplist_copy(sink_input->proplist);
     s->dbus_protocol = pa_dbus_protocol_get(sink_input->core);
     s->subscription = pa_subscription_new(sink_input->core, PA_SUBSCRIPTION_MASK_SINK_INPUT, subscription_cb, s);
@@ -851,8 +889,9 @@ pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_
     s->source = pa_source_ref(source_output->source);
     s->sample_rate = source_output->sample_spec.rate;
     pa_cvolume_init(&s->volume);
-    s->mute = FALSE;
+    s->mute = false;
     s->proplist = pa_proplist_copy(source_output->proplist);
+    s->has_volume = false;
     s->dbus_protocol = pa_dbus_protocol_get(source_output->core);
     s->subscription = pa_subscription_new(source_output->core, PA_SUBSCRIPTION_MASK_SOURCE_OUTPUT, subscription_cb, s);
     s->send_event_slot = pa_hook_connect(&source_output->core->hooks[PA_CORE_HOOK_SOURCE_OUTPUT_SEND_EVENT],