#include "module-sound-player-symdef.h"
#include <pulsecore/core-scache.h>
+#include <pulsecore/sound-file-stream.h>
PA_MODULE_AUTHOR("Sangchul Lee");
PA_MODULE_DESCRIPTION("Sound Player module");
PA_MODULE_VERSION(PACKAGE_VERSION);
PA_MODULE_LOAD_ONCE(true);
+/* Todo: need to change simple/sample play names more clearly */
#define SOUND_PLAYER_METHOD_NAME_SIMPLE_PLAY "SimplePlay"
#define SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP "SimpleStop"
#define SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP_ALL "SimpleStopAll"
#define SOUND_PLAYER_OBJECT_PATH "/org/pulseaudio/SoundPlayer"
#define SOUND_PLAYER_INTERFACE "org.pulseaudio.SoundPlayer"
#define SOUND_PLAYER_METHOD_NAME_SAMPLE_PLAY "SamplePlay"
+
+#define SOUND_PLAYER_METHOD_NAME_SOUND_PLAY "SoundPlay"
+#define SOUND_PLAYER_METHOD_NAME_SOUND_STOP "SoundStop"
#define SOUND_PLAYER_SIGNAL_EOS "EOS"
static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m, void *userdata);
static void handle_simple_stop(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_simple_stop_all(DBusConnection *conn, DBusMessage *msg, void *userdata);
static void handle_sample_play(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_sound_play(DBusConnection *conn, DBusMessage *msg, void *userdata);
+static void handle_sound_stop(DBusConnection *conn, DBusMessage *msg, void *userdata);
enum method_handler_index {
METHOD_HANDLER_SIMPLE_PLAY,
METHOD_HANDLER_SIMPLE_STOP,
METHOD_HANDLER_SIMPLE_STOP_ALL,
METHOD_HANDLER_SAMPLE_PLAY,
+ METHOD_HANDLER_SOUND_PLAY,
+ METHOD_HANDLER_SOUND_STOP,
METHOD_HANDLER_MAX
};
static pa_dbus_arg_info sample_play_args[] = { { "sample_name", "s", "in" },
{ "role", "s", "in" },
{ "volume_gain", "s", "in" } };
-static const char* signature_args_for_in[] = { "sss", "s", NULL, "sss" };
+static pa_dbus_arg_info sound_play_args[] = { { "filename", "s", "in" },
+ { "repeat", "i", "in" },
+ { "client_pid", "i", "in" },
+ { "role", "s", "in" },
+ { "parent_id", "i", "in" } };
+static pa_dbus_arg_info sound_stop_args[] = { { "stream_idx", "i", "in" } };
+static const char* signature_args_for_in[] = { "sss", "s", NULL, "sss", "siisi", "i" };
static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
[METHOD_HANDLER_SIMPLE_PLAY] = {
.method_name = SOUND_PLAYER_METHOD_NAME_SAMPLE_PLAY,
.arguments = sample_play_args,
.n_arguments = sizeof(sample_play_args) / sizeof(pa_dbus_arg_info),
- .receive_cb = handle_sample_play }
+ .receive_cb = handle_sample_play },
+ [METHOD_HANDLER_SOUND_PLAY] = {
+ .method_name = SOUND_PLAYER_METHOD_NAME_SOUND_PLAY,
+ .arguments = sound_play_args,
+ .n_arguments = sizeof(sound_play_args) / sizeof(pa_dbus_arg_info),
+ .receive_cb = handle_sound_play },
+ [METHOD_HANDLER_SOUND_STOP] = {
+ .method_name = SOUND_PLAYER_METHOD_NAME_SOUND_STOP,
+ .arguments = sound_stop_args,
+ .n_arguments = sizeof(sound_stop_args) / sizeof(pa_dbus_arg_info),
+ .receive_cb = handle_sound_stop }
};
#ifdef USE_DBUS_PROTOCOL
" <arg name=\"role\" direction=\"in\" type=\"s\"/>" \
" <arg name=\"volume_gain\" direction=\"in\" type=\"s\"/>" \
" </method>" \
+ " <method name=\"SOUND_PLAYER_METHOD_NAME_SOUND_PLAY\">" \
+ " <arg name=\"filename\" direction=\"in\" type=\"s\"/>" \
+ " <arg name=\"repeat\" direction=\"in\" type=\"i\"/>" \
+ " <arg name=\"client_pid\" direction=\"in\" type=\"i\"/>" \
+ " <arg name=\"role\" direction=\"in\" type=\"s\"/>" \
+ " <arg name=\"parent_id\" direction=\"in\" type=\"i\"/>" \
+ " </method>" \
+ " <method name=\"SOUND_PLAYER_METHOD_NAME_SOUND_STOP\">" \
+ " <arg name=\"stream_idx\" direction=\"in\" type=\"i\"/>" \
+ " </method>" \
" </interface>" \
" <interface name=\"org.freedesktop.DBus.Introspectable\">" \
" <method name=\"Introspect\">" \
pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_INT32, &result);
}
+static void handle_sound_play(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ int ret;
+ dbus_int32_t result = -1;
+ struct userdata *u = (struct userdata *)userdata;
+
+ const char *filename = NULL;
+ uint32_t repeat = 0;
+ uint32_t client_pid;
+ const char *role;
+ uint32_t parent_id;
+ uint32_t stream_idx;
+ pa_proplist *p;
+
+ pa_assert_se(dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_STRING, &filename,
+ DBUS_TYPE_INT32, &repeat,
+ DBUS_TYPE_INT32, &client_pid,
+ DBUS_TYPE_STRING, &role,
+ DBUS_TYPE_INT32, &parent_id,
+ DBUS_TYPE_INVALID));
+
+ p = pa_proplist_new();
+ pa_proplist_sets(p, PA_PROP_MEDIA_ROLE, role);
+ pa_proplist_setf(p, PA_PROP_APPLICATION_PROCESS_ID_ORIGIN, "%d", client_pid);
+ pa_proplist_setf(p, PA_PROP_MEDIA_PARENT_ID, "%d", parent_id);
+
+ ret = pa_play_file_repeat(pa_namereg_get(u->module->core, NULL, PA_NAMEREG_SINK),
+ filename, NULL, p, repeat, &stream_idx);
+ if (ret != 0) {
+ pa_log_error("pa_play_file_repeat failed.\n");
+ goto exit;
+ }
+
+ pa_idxset_put(u->stream_idxs, pa_xmemdup(&stream_idx, sizeof(stream_idx)), NULL);
+ result = (dbus_int32_t)stream_idx;
+
+exit:
+ pa_proplist_free(p);
+ pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_INT32, &result);
+}
+
+static void handle_sound_stop(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+ pa_sink_input *si;
+ uint32_t stream_idx;
+ struct userdata *u = (struct userdata *)userdata;
+
+ pa_assert(conn);
+ pa_assert(msg);
+ pa_assert(u);
+
+ pa_assert_se(dbus_message_get_args(msg, NULL,
+ DBUS_TYPE_INT32, &stream_idx,
+ DBUS_TYPE_INVALID));
+
+ si = pa_idxset_get_by_index(u->module->core->sink_inputs, stream_idx);
+ if (si != NULL) {
+ int32_t *i = NULL;
+ uint32_t idx = 0;
+
+ PA_IDXSET_FOREACH(i, u->stream_idxs, idx) {
+ if (*i == stream_idx) {
+ pa_idxset_remove_by_data(u->stream_idxs, i, NULL);
+ pa_xfree(i);
+ }
+ }
+ pa_sink_input_unlink(si);
+ }
+
+ pa_dbus_send_empty_reply(conn, msg);
+}
+
static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata) {
int idx = 0;