summaryrefslogtreecommitdiffstats
path: root/src/modules/dbus/iface-stream.c
diff options
context:
space:
mode:
authorTanu Kaskinen <tanuk@iki.fi>2009-08-17 16:56:12 +0300
committerTanu Kaskinen <tanuk@iki.fi>2009-08-17 16:56:12 +0300
commit36dc61a2bff7ee93ca289c33c24b76cb82068cac (patch)
treea828047801514c5de34aaf3eea0748f907389273 /src/modules/dbus/iface-stream.c
parent70ff96b8ab100abb4969b882f66518ce739ae655 (diff)
dbusiface-stream: Finish the Stream D-Bus interface.
Diffstat (limited to 'src/modules/dbus/iface-stream.c')
-rw-r--r--src/modules/dbus/iface-stream.c578
1 files changed, 498 insertions, 80 deletions
diff --git a/src/modules/dbus/iface-stream.c b/src/modules/dbus/iface-stream.c
index 4333c16f..354ca6eb 100644
--- a/src/modules/dbus/iface-stream.c
+++ b/src/modules/dbus/iface-stream.c
@@ -39,78 +39,86 @@ enum stream_type {
};
struct pa_dbusiface_stream {
+ pa_dbusiface_core *core;
+
union {
pa_sink_input *sink_input;
pa_source_output *source_output;
};
enum stream_type type;
char *path;
+ union {
+ pa_sink *sink;
+ pa_source *source;
+ };
+ uint32_t sample_rate;
pa_cvolume volume;
pa_bool_t is_muted;
pa_proplist *proplist;
pa_dbus_protocol *dbus_protocol;
pa_subscription *subscription;
+ pa_hook_slot *send_event_slot;
};
static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userdata);
-/*static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata);
-static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata);*/
+static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_is_muted(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_set_is_muted(DBusConnection *conn, DBusMessage *msg, void *userdata);
-/*static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata);
-static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata);*/
+static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
-/*static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata);
-static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata);*/
+static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata);
enum property_handler_index {
PROPERTY_HANDLER_INDEX,
-/* PROPERTY_HANDLER_DRIVER,
+ PROPERTY_HANDLER_DRIVER,
PROPERTY_HANDLER_OWNER_MODULE,
PROPERTY_HANDLER_CLIENT,
PROPERTY_HANDLER_DEVICE,
PROPERTY_HANDLER_SAMPLE_FORMAT,
PROPERTY_HANDLER_SAMPLE_RATE,
- PROPERTY_HANDLER_CHANNELS,*/
+ PROPERTY_HANDLER_CHANNELS,
PROPERTY_HANDLER_VOLUME,
PROPERTY_HANDLER_IS_MUTED,
-/* PROPERTY_HANDLER_BUFFER_LATENCY,
+ PROPERTY_HANDLER_BUFFER_LATENCY,
PROPERTY_HANDLER_DEVICE_LATENCY,
- PROPERTY_HANDLER_RESAMPLE_METHOD,*/
+ PROPERTY_HANDLER_RESAMPLE_METHOD,
PROPERTY_HANDLER_PROPERTY_LIST,
PROPERTY_HANDLER_MAX
};
static pa_dbus_property_handler property_handlers[PROPERTY_HANDLER_MAX] = {
[PROPERTY_HANDLER_INDEX] = { .property_name = "Index", .type = "u", .get_cb = handle_get_index, .set_cb = NULL },
-/* [PROPERTY_HANDLER_DRIVER] = { .property_name = "Driver", .type = "s", .get_cb = handle_get_driver, .set_cb = NULL },
+ [PROPERTY_HANDLER_DRIVER] = { .property_name = "Driver", .type = "s", .get_cb = handle_get_driver, .set_cb = NULL },
[PROPERTY_HANDLER_OWNER_MODULE] = { .property_name = "OwnerModule", .type = "o", .get_cb = handle_get_owner_module, .set_cb = NULL },
[PROPERTY_HANDLER_CLIENT] = { .property_name = "Client", .type = "o", .get_cb = handle_get_client, .set_cb = NULL },
[PROPERTY_HANDLER_DEVICE] = { .property_name = "Device", .type = "o", .get_cb = handle_get_device, .set_cb = NULL },
[PROPERTY_HANDLER_SAMPLE_FORMAT] = { .property_name = "SampleFormat", .type = "u", .get_cb = handle_get_sample_format, .set_cb = NULL },
[PROPERTY_HANDLER_SAMPLE_RATE] = { .property_name = "SampleRate", .type = "u", .get_cb = handle_get_sample_rate, .set_cb = NULL },
- [PROPERTY_HANDLER_CHANNELS] = { .property_name = "Channels", .type = "au", .get_cb = handle_get_channels, .set_cb = NULL },*/
+ [PROPERTY_HANDLER_CHANNELS] = { .property_name = "Channels", .type = "au", .get_cb = handle_get_channels, .set_cb = NULL },
[PROPERTY_HANDLER_VOLUME] = { .property_name = "Volume", .type = "au", .get_cb = handle_get_volume, .set_cb = handle_set_volume },
[PROPERTY_HANDLER_IS_MUTED] = { .property_name = "IsMuted", .type = "b", .get_cb = handle_get_is_muted, .set_cb = handle_set_is_muted },
-/* [PROPERTY_HANDLER_BUFFER_LATENCY] = { .property_name = "BufferLatency", .type = "t", .get_cb = handle_get_buffer_latency, .set_cb = NULL },
+ [PROPERTY_HANDLER_BUFFER_LATENCY] = { .property_name = "BufferLatency", .type = "t", .get_cb = handle_get_buffer_latency, .set_cb = NULL },
[PROPERTY_HANDLER_DEVICE_LATENCY] = { .property_name = "DeviceLatency", .type = "t", .get_cb = handle_get_device_latency, .set_cb = NULL },
- [PROPERTY_HANDLER_RESAMPLE_METHOD] = { .property_name = "ResampleMethod", .type = "s", .get_cb = handle_get_resample_method, .set_cb = NULL },*/
+ [PROPERTY_HANDLER_RESAMPLE_METHOD] = { .property_name = "ResampleMethod", .type = "s", .get_cb = handle_get_resample_method, .set_cb = NULL },
[PROPERTY_HANDLER_PROPERTY_LIST] = { .property_name = "PropertyList", .type = "a{say}", .get_cb = handle_get_property_list, .set_cb = NULL }
};
-/*enum method_handler_index {
+enum method_handler_index {
METHOD_HANDLER_MOVE,
METHOD_HANDLER_KILL,
METHOD_HANDLER_MAX
@@ -129,38 +137,38 @@ static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
.arguments = NULL,
.n_arguments = 0,
.receive_cb = handle_kill }
-};*/
+};
enum signal_index {
-/* SIGNAL_DEVICE_UPDATED,
- SIGNAL_SAMPLE_RATE_UPDATED,*/
+ SIGNAL_DEVICE_UPDATED,
+ SIGNAL_SAMPLE_RATE_UPDATED,
SIGNAL_VOLUME_UPDATED,
SIGNAL_MUTE_UPDATED,
SIGNAL_PROPERTY_LIST_UPDATED,
-/* SIGNAL_STREAM_EVENT,*/
+ SIGNAL_STREAM_EVENT,
SIGNAL_MAX
};
-/*static pa_dbus_arg_info device_updated_args[] = { { "device", "o", NULL } };
-static pa_dbus_arg_info sample_rate_updated_args[] = { { "sample_rate", "u", NULL } };*/
+static pa_dbus_arg_info device_updated_args[] = { { "device", "o", NULL } };
+static pa_dbus_arg_info sample_rate_updated_args[] = { { "sample_rate", "u", NULL } };
static pa_dbus_arg_info volume_updated_args[] = { { "volume", "au", NULL } };
static pa_dbus_arg_info mute_updated_args[] = { { "muted", "b", NULL } };
static pa_dbus_arg_info property_list_updated_args[] = { { "property_list", "a{say}", NULL } };
-/*static pa_dbus_arg_info stream_event_args[] = { { "name", "s", NULL }, { "property_list", "a{say}", NULL } };*/
+static pa_dbus_arg_info stream_event_args[] = { { "name", "s", NULL }, { "property_list", "a{say}", NULL } };
static pa_dbus_signal_info signals[SIGNAL_MAX] = {
-/* [SIGNAL_DEVICE_UPDATED] = { .name = "DeviceUpdated", .arguments = device_updated_args, .n_arguments = 1 },
- [SIGNAL_SAMPLE_RATE_UPDATED] = { .name = "SampleRateUpdated", .arguments = sample_rate_updated_args, .n_arguments = 1 },*/
+ [SIGNAL_DEVICE_UPDATED] = { .name = "DeviceUpdated", .arguments = device_updated_args, .n_arguments = 1 },
+ [SIGNAL_SAMPLE_RATE_UPDATED] = { .name = "SampleRateUpdated", .arguments = sample_rate_updated_args, .n_arguments = 1 },
[SIGNAL_VOLUME_UPDATED] = { .name = "VolumeUpdated", .arguments = volume_updated_args, .n_arguments = 1 },
[SIGNAL_MUTE_UPDATED] = { .name = "MuteUpdated", .arguments = mute_updated_args, .n_arguments = 1 },
- [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 }/*,
- [SIGNAL_STREAM_EVENT] = { .name = "StreamEvent", .arguments = stream_event_args, .n_arguments = sizeof(stream_event_args) / sizeof(pa_dbus_arg_info) }*/
+ [SIGNAL_PROPERTY_LIST_UPDATED] = { .name = "PropertyListUpdated", .arguments = property_list_updated_args, .n_arguments = 1 },
+ [SIGNAL_STREAM_EVENT] = { .name = "StreamEvent", .arguments = stream_event_args, .n_arguments = sizeof(stream_event_args) / sizeof(pa_dbus_arg_info) }
};
static pa_dbus_interface_info stream_interface_info = {
.name = PA_DBUSIFACE_STREAM_INTERFACE,
- .method_handlers = /*method_handlers*/ NULL,
- .n_method_handlers = /*METHOD_HANDLER_MAX*/ 0,
+ .method_handlers = method_handlers,
+ .n_method_handlers = METHOD_HANDLER_MAX,
.property_handlers = property_handlers,
.n_property_handlers = PROPERTY_HANDLER_MAX,
.get_all_properties_cb = handle_get_all,
@@ -181,6 +189,140 @@ static void handle_get_index(DBusConnection *conn, DBusMessage *msg, void *userd
pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &idx);
}
+static void handle_get_driver(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_dbusiface_stream *s = userdata;
+ const char *driver = NULL;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(s);
+
+ 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);
+ return;
+ }
+
+ pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &driver);
+}
+
+static void handle_get_owner_module(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_dbusiface_stream *s = userdata;
+ pa_module *owner_module = NULL;
+ const char *object_path = NULL;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(s);
+
+ 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);
+ return;
+ }
+
+ object_path = pa_dbusiface_core_get_module_path(s->core, owner_module);
+
+ pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
+}
+
+static void handle_get_client(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_dbusiface_stream *s = userdata;
+ pa_client *client = NULL;
+ const char *object_path = NULL;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(s);
+
+ 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);
+ return;
+ }
+
+ object_path = pa_dbusiface_core_get_client_path(s->core, client);
+
+ pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &object_path);
+}
+
+static void handle_get_device(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_dbusiface_stream *s = userdata;
+ const char *device = NULL;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(s);
+
+ if (s->type == STREAM_TYPE_PLAYBACK)
+ device = pa_dbusiface_core_get_sink_path(s->core, s->sink);
+ else
+ device = pa_dbusiface_core_get_source_path(s->core, s->source);
+
+ pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_OBJECT_PATH, &device);
+}
+
+static void handle_get_sample_format(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_dbusiface_stream *s = userdata;
+ dbus_uint32_t sample_format = 0;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(s);
+
+ sample_format = (s->type == STREAM_TYPE_PLAYBACK)
+ ? s->sink_input->sample_spec.format
+ : s->source_output->sample_spec.format;
+
+ pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &sample_format);
+}
+
+static void handle_get_sample_rate(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_dbusiface_stream *s = userdata;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(s);
+
+ pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT32, &s->sample_rate);
+}
+
+static void handle_get_channels(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_dbusiface_stream *s = userdata;
+ pa_channel_map *channel_map = NULL;
+ dbus_uint32_t channels[PA_CHANNELS_MAX];
+ unsigned i = 0;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(s);
+
+ channel_map = (s->type == STREAM_TYPE_PLAYBACK) ? &s->sink_input->channel_map : &s->source_output->channel_map;
+
+ for (i = 0; i < channel_map->channels; ++i)
+ channels[i] = channel_map->map[i];
+
+ pa_dbus_send_basic_array_variant_reply(conn, msg, DBUS_TYPE_UINT32, channels, channel_map->channels);
+}
+
static void handle_get_volume(DBusConnection *conn, DBusMessage *msg, void *userdata) {
pa_dbusiface_stream *s = userdata;
dbus_uint32_t volume[PA_CHANNELS_MAX];
@@ -228,7 +370,8 @@ static void handle_set_volume(DBusConnection *conn, DBusMessage *msg, void *user
return;
if (n_volume_entries != stream_channels) {
- pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "Expected %u volume entries, got %u.", stream_channels, n_volume_entries);
+ pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS,
+ "Expected %u volume entries, got %u.", stream_channels, n_volume_entries);
return;
}
@@ -281,6 +424,54 @@ static void handle_set_is_muted(DBusConnection *conn, DBusMessage *msg, void *us
pa_dbus_send_empty_reply(conn, msg);
};
+static void handle_get_buffer_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_dbusiface_stream *s = userdata;
+ dbus_uint64_t buffer_latency = 0;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(s);
+
+ if (s->type == STREAM_TYPE_PLAYBACK)
+ buffer_latency = pa_sink_input_get_latency(s->sink_input, NULL);
+ else
+ buffer_latency = pa_source_output_get_latency(s->source_output, NULL);
+
+ pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &buffer_latency);
+}
+
+static void handle_get_device_latency(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_dbusiface_stream *s = userdata;
+ dbus_uint64_t device_latency = 0;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(s);
+
+ if (s->type == STREAM_TYPE_PLAYBACK)
+ pa_sink_input_get_latency(s->sink_input, &device_latency);
+ else
+ pa_source_output_get_latency(s->source_output, &device_latency);
+
+ pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_UINT64, &device_latency);
+}
+
+static void handle_get_resample_method(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_dbusiface_stream *s = userdata;
+ const char *resample_method = NULL;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(s);
+
+ if (s->type == STREAM_TYPE_PLAYBACK)
+ resample_method = pa_resample_method_to_string(s->sink_input->actual_resample_method);
+ else
+ resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
+
+ pa_dbus_send_basic_variant_reply(conn, msg, DBUS_TYPE_STRING, &resample_method);
+}
+
static void handle_get_property_list(DBusConnection *conn, DBusMessage *msg, void *userdata) {
pa_dbusiface_stream *s = userdata;
@@ -296,19 +487,55 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
DBusMessage *reply = NULL;
DBusMessageIter msg_iter;
DBusMessageIter dict_iter;
- dbus_uint32_t idx;
+ dbus_uint32_t idx = 0;
+ const char *driver = NULL;
+ pa_module *owner_module = NULL;
+ const char *owner_module_path = NULL;
+ pa_client *client = NULL;
+ const char *client_path = NULL;
+ const char *device = NULL;
+ dbus_uint32_t sample_format = 0;
+ pa_channel_map *channel_map = NULL;
+ dbus_uint32_t channels[PA_CHANNELS_MAX];
dbus_uint32_t volume[PA_CHANNELS_MAX];
+ dbus_uint64_t buffer_latency = 0;
+ dbus_uint64_t device_latency = 0;
+ const char *resample_method = NULL;
unsigned i = 0;
pa_assert(conn);
pa_assert(msg);
pa_assert(s);
- idx = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->index : s->source_output->index;
if (s->type == STREAM_TYPE_PLAYBACK) {
+ idx = s->sink_input->index;
+ driver = s->sink_input->driver;
+ owner_module = s->sink_input->module;
+ client = s->sink_input->client;
+ 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 {
+ idx = s->source_output->index;
+ driver = s->source_output->driver;
+ owner_module = s->source_output->module;
+ client = s->source_output->client;
+ device = pa_dbusiface_core_get_source_path(s->core, s->source);
+ sample_format = s->source_output->sample_spec.format;
+ channel_map = &s->source_output->channel_map;
+ buffer_latency = pa_source_output_get_latency(s->source_output, &device_latency);
+ resample_method = pa_resample_method_to_string(s->source_output->actual_resample_method);
}
+ if (owner_module)
+ owner_module_path = pa_dbusiface_core_get_module_path(s->core, owner_module);
+ if (client)
+ 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];
pa_assert_se((reply = dbus_message_new_method_return(msg)));
@@ -317,11 +544,27 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_INDEX].property_name, DBUS_TYPE_UINT32, &idx);
+ if (driver)
+ pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DRIVER].property_name, DBUS_TYPE_STRING, &driver);
+
+ if (owner_module)
+ pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_OWNER_MODULE].property_name, DBUS_TYPE_OBJECT_PATH, &owner_module_path);
+
+ 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_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) {
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_IS_MUTED].property_name, DBUS_TYPE_BOOLEAN, &s->is_muted);
}
+ pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_BUFFER_LATENCY].property_name, DBUS_TYPE_UINT64, &buffer_latency);
+ pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_DEVICE_LATENCY].property_name, DBUS_TYPE_UINT64, &device_latency);
+ pa_dbus_append_basic_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_RESAMPLE_METHOD].property_name, DBUS_TYPE_STRING, &resample_method);
pa_dbus_append_proplist_variant_dict_entry(&dict_iter, property_handlers[PROPERTY_HANDLER_PROPERTY_LIST].property_name, s->proplist);
pa_assert_se(dbus_message_iter_close_container(&msg_iter, &dict_iter));
@@ -329,83 +572,240 @@ static void handle_get_all(DBusConnection *conn, DBusMessage *msg, void *userdat
dbus_message_unref(reply);
}
+static void handle_move(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_dbusiface_stream *s = userdata;
+ const char *device = NULL;
+ DBusError error;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(s);
+
+ dbus_error_init(&error);
+
+ if (!dbus_message_get_args(msg, &error, DBUS_TYPE_STRING, &device, DBUS_TYPE_INVALID)) {
+ pa_dbus_send_error(conn, msg, DBUS_ERROR_INVALID_ARGS, "%s", error.message);
+ dbus_error_free(&error);
+ return;
+ }
+
+ if (s->type == STREAM_TYPE_PLAYBACK) {
+ pa_sink *sink = pa_dbusiface_core_get_sink(s->core, device);
+
+ if (!sink) {
+ pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such sink.", device);
+ return;
+ }
+
+ 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;
+ }
+ } else {
+ pa_source *source = pa_dbusiface_core_get_source(s->core, device);
+
+ if (!source) {
+ pa_dbus_send_error(conn, msg, PA_DBUS_ERROR_NOT_FOUND, "%s: No such source.", device);
+ return;
+ }
+
+ 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;
+ }
+ }
+
+ pa_dbus_send_empty_reply(conn, msg);
+}
+
+static void handle_kill(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_dbusiface_stream *s = userdata;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(s);
+
+ if (s->type == STREAM_TYPE_PLAYBACK)
+ pa_sink_input_kill(s->sink_input);
+ else
+ pa_source_output_kill(s->source_output);
+
+ pa_dbus_send_empty_reply(conn, msg);
+}
+
static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t idx, void *userdata) {
pa_dbusiface_stream *s = userdata;
+ DBusMessage *signal = NULL;
+ const char *new_device_path = NULL;
+ uint32_t new_sample_rate = 0;
+ pa_proplist *new_proplist = NULL;
+ unsigned i = 0;
pa_assert(c);
pa_assert(s);
- if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) == PA_SUBSCRIPTION_EVENT_CHANGE) {
- DBusMessage *signal = NULL;
- pa_proplist *new_proplist = NULL;
- unsigned i = 0;
-
- pa_assert(((s->type == STREAM_TYPE_PLAYBACK)
- && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT))
- || ((s->type == STREAM_TYPE_RECORD)
- && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT)));
+ if ((s->type == STREAM_TYPE_PLAYBACK && idx != s->sink_input->index)
+ || (s->type == STREAM_TYPE_RECORD && idx != s->source_output->index))
+ return;
- if (s->type == STREAM_TYPE_PLAYBACK) {
- pa_cvolume new_volume;
- pa_bool_t new_muted = FALSE;
+ if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
+ return;
- pa_sink_input_get_volume(s->sink_input, &new_volume, TRUE);
+ pa_assert(((s->type == STREAM_TYPE_PLAYBACK)
+ && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SINK_INPUT))
+ || ((s->type == STREAM_TYPE_RECORD)
+ && ((t & PA_SUBSCRIPTION_EVENT_FACILITY_MASK) == PA_SUBSCRIPTION_EVENT_SOURCE_OUTPUT)));
- if (!pa_cvolume_equal(&s->volume, &new_volume)) {
- dbus_uint32_t volume[PA_CHANNELS_MAX];
- dbus_uint32_t *volume_ptr = volume;
+ if (s->type == STREAM_TYPE_PLAYBACK) {
+ pa_sink *new_sink = s->sink_input->sink;
- s->volume = new_volume;
+ if (s->sink != new_sink) {
+ pa_sink_unref(s->sink);
+ s->sink = pa_sink_ref(new_sink);
- for (i = 0; i < s->volume.channels; ++i)
- volume[i] = s->volume.values[i];
+ new_device_path = pa_dbusiface_core_get_sink_path(s->core, new_sink);
- pa_assert_se(signal = dbus_message_new_signal(s->path,
- PA_DBUSIFACE_STREAM_INTERFACE,
- signals[SIGNAL_VOLUME_UPDATED].name));
- pa_assert_se(dbus_message_append_args(signal,
- DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
- DBUS_TYPE_INVALID));
+ pa_assert_se(signal = dbus_message_new_signal(s->path,
+ PA_DBUSIFACE_STREAM_INTERFACE,
+ signals[SIGNAL_DEVICE_UPDATED].name));
+ pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
- pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
- dbus_message_unref(signal);
- signal = NULL;
- }
+ pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
+ dbus_message_unref(signal);
+ signal = NULL;
+ }
+ } else {
+ pa_source *new_source = s->source_output->source;
- new_muted = pa_sink_input_get_mute(s->sink_input);
+ if (s->source != new_source) {
+ pa_source_unref(s->source);
+ s->source = pa_source_ref(new_source);
- if (s->is_muted != new_muted) {
- s->is_muted = new_muted;
+ new_device_path = pa_dbusiface_core_get_source_path(s->core, new_source);
- pa_assert_se(signal = dbus_message_new_signal(s->path,
- PA_DBUSIFACE_STREAM_INTERFACE,
- signals[SIGNAL_MUTE_UPDATED].name));
- pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_BOOLEAN, &s->is_muted, DBUS_TYPE_INVALID));
+ pa_assert_se(signal = dbus_message_new_signal(s->path,
+ PA_DBUSIFACE_STREAM_INTERFACE,
+ signals[SIGNAL_DEVICE_UPDATED].name));
+ pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_OBJECT_PATH, &new_device_path, DBUS_TYPE_INVALID));
- pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
- dbus_message_unref(signal);
- signal = NULL;
- }
+ pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
+ dbus_message_unref(signal);
+ signal = NULL;
}
+ }
+
+ new_sample_rate = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->sample_spec.rate : s->source_output->sample_spec.rate;
+
+ if (s->sample_rate != new_sample_rate) {
+ s->sample_rate = new_sample_rate;
+
+ pa_assert_se(signal = dbus_message_new_signal(s->path,
+ PA_DBUSIFACE_STREAM_INTERFACE,
+ signals[SIGNAL_SAMPLE_RATE_UPDATED].name));
+ pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_UINT32, &s->sample_rate, DBUS_TYPE_INVALID));
+
+ pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
+ dbus_message_unref(signal);
+ signal = NULL;
+ }
+
+ if (s->type == STREAM_TYPE_PLAYBACK) {
+ pa_cvolume new_volume;
+ pa_bool_t new_muted = FALSE;
+
+ pa_sink_input_get_volume(s->sink_input, &new_volume, TRUE);
+
+ if (!pa_cvolume_equal(&s->volume, &new_volume)) {
+ dbus_uint32_t volume[PA_CHANNELS_MAX];
+ dbus_uint32_t *volume_ptr = volume;
+
+ s->volume = new_volume;
+
+ for (i = 0; i < s->volume.channels; ++i)
+ volume[i] = s->volume.values[i];
+
+ pa_assert_se(signal = dbus_message_new_signal(s->path,
+ PA_DBUSIFACE_STREAM_INTERFACE,
+ signals[SIGNAL_VOLUME_UPDATED].name));
+ pa_assert_se(dbus_message_append_args(signal,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_UINT32, &volume_ptr, s->volume.channels,
+ DBUS_TYPE_INVALID));
- new_proplist = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->proplist : s->source_output->proplist;
+ pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
+ dbus_message_unref(signal);
+ signal = NULL;
+ }
- if (!pa_proplist_equal(s->proplist, new_proplist)) {
- DBusMessageIter msg_iter;
+ new_muted = pa_sink_input_get_mute(s->sink_input);
- pa_proplist_update(s->proplist, PA_UPDATE_SET, new_proplist);
+ if (s->is_muted != new_muted) {
+ s->is_muted = new_muted;
pa_assert_se(signal = dbus_message_new_signal(s->path,
PA_DBUSIFACE_STREAM_INTERFACE,
- signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
- dbus_message_iter_init_append(signal, &msg_iter);
- pa_dbus_append_proplist(&msg_iter, s->proplist);
+ signals[SIGNAL_MUTE_UPDATED].name));
+ pa_assert_se(dbus_message_append_args(signal, DBUS_TYPE_BOOLEAN, &s->is_muted, DBUS_TYPE_INVALID));
pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
dbus_message_unref(signal);
signal = NULL;
}
}
+
+ new_proplist = (s->type == STREAM_TYPE_PLAYBACK) ? s->sink_input->proplist : s->source_output->proplist;
+
+ if (!pa_proplist_equal(s->proplist, new_proplist)) {
+ DBusMessageIter msg_iter;
+
+ pa_proplist_update(s->proplist, PA_UPDATE_SET, new_proplist);
+
+ pa_assert_se(signal = dbus_message_new_signal(s->path,
+ PA_DBUSIFACE_STREAM_INTERFACE,
+ signals[SIGNAL_PROPERTY_LIST_UPDATED].name));
+ dbus_message_iter_init_append(signal, &msg_iter);
+ pa_dbus_append_proplist(&msg_iter, s->proplist);
+
+ pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
+ dbus_message_unref(signal);
+ signal = NULL;
+ }
+}
+
+static pa_hook_result_t send_event_cb(void *hook_data, void *call_data, void *slot_data) {
+ pa_dbusiface_stream *s = slot_data;
+ DBusMessage *signal = NULL;
+ DBusMessageIter msg_iter;
+ const char *name = NULL;
+ pa_proplist *property_list = NULL;
+
+ pa_assert(call_data);
+ pa_assert(s);
+
+ if (s->type == STREAM_TYPE_PLAYBACK) {
+ pa_sink_input_send_event_hook_data *data = call_data;
+
+ name = data->event;
+ property_list = data->data;
+ } else {
+ pa_source_output_send_event_hook_data *data = call_data;
+
+ name = data->event;
+ property_list = data->data;
+ }
+
+ pa_assert_se(signal = dbus_message_new_signal(s->path,
+ PA_DBUSIFACE_STREAM_INTERFACE,
+ signals[SIGNAL_STREAM_EVENT].name));
+ dbus_message_iter_init_append(signal, &msg_iter);
+ pa_assert_se(dbus_message_iter_append_basic(&msg_iter, DBUS_TYPE_STRING, &name));
+ pa_dbus_append_proplist(&msg_iter, property_list);
+
+ pa_dbus_protocol_send_signal(s->dbus_protocol, signal);
+ dbus_message_unref(signal);
+
+ return PA_HOOK_OK;
}
pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, pa_sink_input *sink_input) {
@@ -415,14 +815,21 @@ pa_dbusiface_stream *pa_dbusiface_stream_new_playback(pa_dbusiface_core *core, p
pa_assert(sink_input);
s = pa_xnew(pa_dbusiface_stream, 1);
+ s->core = core;
s->sink_input = pa_sink_input_ref(sink_input);
s->type = STREAM_TYPE_PLAYBACK;
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->is_muted = pa_sink_input_get_mute(sink_input);
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);
+ s->send_event_slot = pa_hook_connect(&sink_input->core->hooks[PA_CORE_HOOK_SINK_INPUT_SEND_EVENT],
+ PA_HOOK_NORMAL,
+ send_event_cb,
+ s);
pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
@@ -436,14 +843,21 @@ pa_dbusiface_stream *pa_dbusiface_stream_new_record(pa_dbusiface_core *core, pa_
pa_assert(source_output);
s = pa_xnew(pa_dbusiface_stream, 1);
+ s->core = core;
s->source_output = pa_source_output_ref(source_output);
s->type = STREAM_TYPE_RECORD;
s->path = pa_sprintf_malloc("%s/%s%u", PA_DBUS_CORE_OBJECT_PATH, RECORD_OBJECT_NAME, source_output->index);
+ s->source = pa_source_ref(source_output->source);
+ s->sample_rate = source_output->sample_spec.rate;
pa_cvolume_init(&s->volume);
s->is_muted = FALSE;
s->proplist = pa_proplist_copy(source_output->proplist);
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],
+ PA_HOOK_NORMAL,
+ send_event_cb,
+ s);
pa_assert_se(pa_dbus_protocol_add_interface(s->dbus_protocol, s->path, &stream_interface_info, s) >= 0);
@@ -455,14 +869,18 @@ void pa_dbusiface_stream_free(pa_dbusiface_stream *s) {
pa_assert_se(pa_dbus_protocol_remove_interface(s->dbus_protocol, s->path, stream_interface_info.name) >= 0);
- if (s->type == STREAM_TYPE_PLAYBACK)
+ if (s->type == STREAM_TYPE_PLAYBACK) {
pa_sink_input_unref(s->sink_input);
- else
+ pa_sink_unref(s->sink);
+ } else {
pa_source_output_unref(s->source_output);
+ pa_source_unref(s->source);
+ }
pa_proplist_free(s->proplist);
pa_dbus_protocol_unref(s->dbus_protocol);
pa_subscription_free(s->subscription);
+ pa_hook_slot_free(s->send_event_slot);
pa_xfree(s->path);
pa_xfree(s);