dbusiface-stream: Finish the Stream D-Bus interface.

This commit is contained in:
Tanu Kaskinen 2009-08-17 16:56:12 +03:00
parent 70ff96b8ab
commit 36dc61a2bf

View file

@ -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,22 +572,145 @@ 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;
if ((s->type == STREAM_TYPE_PLAYBACK && idx != s->sink_input->index)
|| (s->type == STREAM_TYPE_RECORD && idx != s->source_output->index))
return;
if ((t & PA_SUBSCRIPTION_EVENT_TYPE_MASK) != PA_SUBSCRIPTION_EVENT_CHANGE)
return;
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) {
pa_sink *new_sink = s->sink_input->sink;
if (s->sink != new_sink) {
pa_sink_unref(s->sink);
s->sink = pa_sink_ref(new_sink);
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_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;
}
} else {
pa_source *new_source = s->source_output->source;
if (s->source != new_source) {
pa_source_unref(s->source);
s->source = pa_source_ref(new_source);
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_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;
}
}
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;
@ -405,7 +771,41 @@ static void subscription_cb(pa_core *c, pa_subscription_event_type_t t, uint32_t
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);