sound-player: add stop / stop_all operation for simple playbacks 22/227322/12 accepted/tizen/unified/20200323.172915 submit/tizen/20200323.095035
authorSeungbae Shin <seungbae.shin@samsung.com>
Wed, 11 Mar 2020 07:36:57 +0000 (16:36 +0900)
committerSeungbae Shin <seungbae.shin@samsung.com>
Mon, 23 Mar 2020 03:53:13 +0000 (12:53 +0900)
[Version] 13.0.7
[Issue Type] Add

Change-Id: I9b9e1653496f77d24c0aab0d7b3e093b547e080f

packaging/pulseaudio-modules-tizen.spec
src/module-sound-player.c

index f6646fb..df7fb6b 100644 (file)
@@ -1,6 +1,6 @@
 Name:             pulseaudio-modules-tizen
 Summary:          Pulseaudio modules for Tizen
-Version:          13.0.6
+Version:          13.0.7
 Release:          0
 Group:            Multimedia/Audio
 License:          LGPL-2.1+
index 310b631..639383b 100644 (file)
@@ -57,11 +57,14 @@ PA_MODULE_DESCRIPTION("Sound Player module");
 PA_MODULE_VERSION(PACKAGE_VERSION);
 PA_MODULE_LOAD_ONCE(true);
 
+#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"
+
 #ifdef HAVE_DBUS
 #define ARR_ARG_MAX  32
 #define SOUND_PLAYER_OBJECT_PATH "/org/pulseaudio/SoundPlayer"
 #define SOUND_PLAYER_INTERFACE   "org.pulseaudio.SoundPlayer"
-#define SOUND_PLAYER_METHOD_NAME_SIMPLE_PLAY      "SimplePlay"
 #define SOUND_PLAYER_METHOD_NAME_SAMPLE_PLAY      "SamplePlay"
 #define SOUND_PLAYER_SIGNAL_EOS                   "EOS"
 
@@ -69,22 +72,26 @@ static DBusHandlerResult method_handler_for_vt(DBusConnection *c, DBusMessage *m
 static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *msg, void *userdata);
 static DBusHandlerResult handle_methods(DBusConnection *conn, DBusMessage *msg, void *userdata);
 static void handle_simple_play(DBusConnection *conn, DBusMessage *msg, 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);
 
 enum method_handler_index {
     METHOD_HANDLER_SIMPLE_PLAY,
+    METHOD_HANDLER_SIMPLE_STOP,
+    METHOD_HANDLER_SIMPLE_STOP_ALL,
     METHOD_HANDLER_SAMPLE_PLAY,
     METHOD_HANDLER_MAX
 };
 
-static pa_dbus_arg_info simple_play_args[]    = { { "uri", "s", "in" },
-                                                 { "role", "s", "in" },
-                                         { "volume_gain", "s", "in" } };
-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", "sss" };
+static pa_dbus_arg_info simple_play_args[] = { { "uri", "s", "in" },
+                                               { "role", "s", "in" },
+                                               { "volume_gain", "s", "in" } };
+static pa_dbus_arg_info simple_stop_args[] = { { "uri", "s", "in" } };
+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_method_handler method_handlers[METHOD_HANDLER_MAX] = {
     [METHOD_HANDLER_SIMPLE_PLAY] = {
@@ -92,6 +99,16 @@ static pa_dbus_method_handler method_handlers[METHOD_HANDLER_MAX] = {
         .arguments = simple_play_args,
         .n_arguments = sizeof(simple_play_args) / sizeof(pa_dbus_arg_info),
         .receive_cb = handle_simple_play },
+    [METHOD_HANDLER_SIMPLE_STOP] = {
+        .method_name = SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP,
+        .arguments = simple_stop_args,
+        .n_arguments = sizeof(simple_stop_args) / sizeof(pa_dbus_arg_info),
+        .receive_cb = handle_simple_stop },
+    [METHOD_HANDLER_SIMPLE_STOP_ALL] = {
+        .method_name = SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP_ALL,
+        .arguments = NULL,
+        .n_arguments = 0,
+        .receive_cb = handle_simple_stop_all },
     [METHOD_HANDLER_SAMPLE_PLAY] = {
         .method_name = SOUND_PLAYER_METHOD_NAME_SAMPLE_PLAY,
         .arguments = sample_play_args,
@@ -123,6 +140,10 @@ static pa_dbus_interface_info sound_player_interface_info = {
     "   <arg name=\"role\" direction=\"in\" type=\"s\"/>"               \
     "   <arg name=\"volume_gain\" direction=\"in\" type=\"s\"/>"        \
     "  </method>"                                                       \
+    "  <method name=\"SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP\">"          \
+    "   <arg name=\"uri\" direction=\"in\" type=\"s\"/>"                \
+    "  </method>"                                                       \
+    "  <method name=\"SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP_ALL\" />"    \
     "  <method name=\"SOUND_PLAYER_METHOD_NAME_SAMPLE_PLAY\">"          \
     "   <arg name=\"sample_name\" direction=\"in\" type=\"s\"/>"        \
     "   <arg name=\"role\" direction=\"in\" type=\"s\"/>"               \
@@ -156,62 +177,61 @@ struct userdata {
 #endif
 };
 
-#define FILE_FULL_PATH 1024        /* File path length */
-#define ROLE_NAME_LEN 64                /* Role name length */
-#define VOLUME_GAIN_TYPE_LEN 64    /* Volume gain type length */
+#define FILE_FULL_PATH 1024
+#define ROLE_NAME_LEN 64
+#define VOLUME_GAIN_TYPE_LEN 32
+#define METHOD_LEN 32
+
 #define RETRY_NUM 100
 
 struct ipc_data {
     char filename[FILE_FULL_PATH];
     char role[ROLE_NAME_LEN];
     char volume_gain_type[VOLUME_GAIN_TYPE_LEN];
+    char method[METHOD_LEN];
 };
 
+#define KEYTONE_PREFIX      "SIMPLE_PLAY"
 #define KEYTONE_PATH        "/tmp/keytone"  /* Keytone pipe path */
 #define KEYTONE_GROUP       6526            /* Keytone group : assigned by security */
 #define DEFAULT_IPC_TYPE    IPC_TYPE_PIPE
 
-#define MAX_NAME_LEN 256
 static int _simple_play(struct userdata *u, const char *file_path, const char *role, const char *vol_gain_type) {
     int ret = 0;
-    pa_sink *sink = NULL;
     pa_proplist *p;
-    const char *name_prefix = "SIMPLE_PLAY";
 
-    char name[MAX_NAME_LEN] = {0};
+    char *scache_name = NULL;
 
     uint32_t stream_idx = 0;
     uint32_t scache_idx = 0;
 
+    /* Set role & volume gain type of stream to proplist */
     p = pa_proplist_new();
-
-    /* Set role type of stream */
     if (role)
         pa_proplist_sets(p, PA_PROP_MEDIA_ROLE, role);
-
-    /* Set volume gain type of stream */
     if (vol_gain_type)
         pa_proplist_sets(p, PA_PROP_MEDIA_TIZEN_VOLUME_GAIN_TYPE, vol_gain_type);
-
-    sink = pa_namereg_get(u->module->core, NULL, PA_NAMEREG_SINK);
-
     pa_log_debug("role[%s], volume_gain_type[%s]", role, vol_gain_type);
-    snprintf(name, sizeof(name)-1, "%s_%s", name_prefix, file_path);
-    scache_idx = pa_scache_get_id_by_name(u->module->core, name);
+
+    /* prepare scache */
+    scache_name = pa_sprintf_malloc("%s_%s", KEYTONE_PREFIX, file_path);
+    scache_idx = pa_scache_get_id_by_name(u->module->core, scache_name);
     if (scache_idx != PA_IDXSET_INVALID) {
         pa_log_debug("found cached index [%u] for name [%s]", scache_idx, file_path);
     } else {
         /* for more precision, need to update volume value here */
-        if ((ret = pa_scache_add_file_lazy(u->module->core, name, file_path, &scache_idx)) != 0) {
+        if ((ret = pa_scache_add_file_lazy(u->module->core, scache_name, file_path, &scache_idx)) != 0) {
             pa_log_error("failed to add file [%s]", file_path);
             goto exit;
-        } else {
-            pa_log_debug("success to add file [%s], index [%u]", file_path, scache_idx);
         }
+        pa_log_debug("success to add file [%s], index [%u]", file_path, scache_idx);
     }
 
+    /* play scache */
     pa_log_debug("pa_scache_play_item() start");
-    ret = pa_scache_play_item(u->module->core, name, sink, PA_VOLUME_NORM, p, &stream_idx);
+    ret = pa_scache_play_item(u->module->core, scache_name,
+            pa_namereg_get(u->module->core, NULL, PA_NAMEREG_SINK),
+            PA_VOLUME_NORM, p, &stream_idx);
     if (ret < 0) {
         pa_log_error("pa_scache_play_item fail, ret[%d]", ret);
         goto exit;
@@ -221,10 +241,47 @@ static int _simple_play(struct userdata *u, const char *file_path, const char *r
     if (!ret)
         ret = (int32_t)stream_idx;
 exit:
+    pa_xfree(scache_name);
     pa_proplist_free(p);
     return ret;
 }
 
+static void _simple_stop(struct userdata *u, const char *file_path) {
+    pa_sink_input *si;
+    uint32_t idx;
+    char *name_to_search = NULL;
+
+    pa_assert(u);
+
+    name_to_search = pa_sprintf_malloc("%s_%s", KEYTONE_PREFIX, file_path);
+
+    PA_IDXSET_FOREACH(si, u->module->core->sink_inputs, idx) {
+        if (pa_safe_streq(pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME), name_to_search)) {
+            pa_log_info("unlink sink-input : %u", si->index);
+            pa_sink_input_unlink(si);
+        }
+    }
+
+    pa_xfree(name_to_search);
+}
+
+static void _simple_stop_all(struct userdata *u) {
+    pa_sink_input *si;
+    uint32_t idx;
+    const char *media_name = NULL;
+
+    pa_assert(u);
+
+    PA_IDXSET_FOREACH(si, u->module->core->sink_inputs, idx) {
+        media_name = pa_proplist_gets(si->proplist, PA_PROP_MEDIA_NAME);
+
+        if (media_name && pa_strneq(media_name, KEYTONE_PREFIX, strlen(KEYTONE_PREFIX))) {
+            pa_log_info("unlink sink-input : %u", si->index);
+            pa_sink_input_unlink(si);
+        }
+    }
+}
+
 static int _sample_play(struct userdata *u, const char *sample_name, const char *role, const char *vol_gain_type) {
     int ret = 0;
     pa_sink *sink = NULL;
@@ -287,11 +344,12 @@ static DBusHandlerResult handle_introspect(DBusConnection *conn, DBusMessage *ms
 }
 
 static void handle_simple_play(DBusConnection *conn, DBusMessage *msg, void *userdata) {
-    char *uri = NULL;
-    char *role = NULL;
-    char *volume_gain = NULL;
-    dbus_int32_t result = 0;
-    struct userdata *u =  (struct userdata*)userdata;
+    const char *uri = NULL;
+    const char *role = NULL;
+    const char *volume_gain = NULL;
+    dbus_int32_t result = -1;
+    struct userdata *u = (struct userdata *)userdata;
+
     pa_assert(conn);
     pa_assert(msg);
     pa_assert(u);
@@ -302,27 +360,53 @@ static void handle_simple_play(DBusConnection *conn, DBusMessage *msg, void *use
                                        DBUS_TYPE_STRING, &volume_gain,
                                        DBUS_TYPE_INVALID));
     pa_log_info("uri[%s], role[%s], volume_gain[%s]", uri, role, volume_gain);
-    if (uri)
+    if (uri) {
         result = _simple_play(u, uri, role, volume_gain);
-    else
-        result = -1;
-
-    if (result != -1) {
-        uint32_t idx = 0;
-        int32_t *stream_idx = NULL;
-        stream_idx = pa_xmalloc0(sizeof(int32_t));
-        *stream_idx = result;
-        pa_idxset_put(u->stream_idxs, stream_idx, &idx);
+        if (result != -1) {
+            int32_t *stream_idx = pa_xmalloc0(sizeof(int32_t));
+            *stream_idx = result;
+            pa_idxset_put(u->stream_idxs, stream_idx, NULL);
+        }
     }
+
     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_INT32, &result);
 }
 
+static void handle_simple_stop(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+    const char *uri = NULL;
+    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_STRING, &uri,
+                                       DBUS_TYPE_INVALID));
+    if (uri)
+        _simple_stop(u, uri);
+
+    pa_dbus_send_empty_reply(conn, msg);
+}
+
+static void handle_simple_stop_all(DBusConnection *conn, DBusMessage *msg, void *userdata) {
+    struct userdata *u = (struct userdata *)userdata;
+
+    pa_assert(conn);
+    pa_assert(msg);
+    pa_assert(u);
+
+    _simple_stop_all(u);
+
+    pa_dbus_send_empty_reply(conn, msg);
+}
+
 static void handle_sample_play(DBusConnection *conn, DBusMessage *msg, void *userdata) {
-    char *sample_name = NULL;
-    char *role = NULL;
-    char *volume_gain = NULL;
-    dbus_int32_t result = 0;
-    struct userdata *u =  (struct userdata*)userdata;
+    const char *sample_name = NULL;
+    const char *role = NULL;
+    const char *volume_gain = NULL;
+    dbus_int32_t result = -1;
+    struct userdata *u = (struct userdata *)userdata;
     pa_assert(conn);
     pa_assert(msg);
     pa_assert(u);
@@ -335,15 +419,11 @@ static void handle_sample_play(DBusConnection *conn, DBusMessage *msg, void *use
     pa_log_info("sample_name[%s], role[%s], volume_gain[%s]", sample_name, role, volume_gain);
     if (sample_name)
         result = _sample_play(u, sample_name, role, volume_gain);
-    else
-        result = -1;
 
     if (result != -1) {
-        uint32_t idx = 0;
-        int32_t *stream_idx = NULL;
-        stream_idx = pa_xmalloc0(sizeof(int32_t));
+        int32_t *stream_idx = pa_xmalloc0(sizeof(int32_t));
         *stream_idx = result;
-        pa_idxset_put(u->stream_idxs, stream_idx, &idx);
+        pa_idxset_put(u->stream_idxs, stream_idx, NULL);
     }
 
     pa_dbus_send_basic_value_reply(conn, msg, DBUS_TYPE_INT32, &result);
@@ -538,8 +618,17 @@ static void io_event_callback(pa_mainloop_api *io, pa_io_event *e, int fd, pa_io
                 read_sum += ret;
         }
         if (read_sum == data_size) {
-            pa_log_info("name(%s), role(%s), volume_gain_type(%s)", data.filename, data.role, data.volume_gain_type);
-            _simple_play(u, data.filename, data.role, data.volume_gain_type);
+            pa_log_info("name(%s), role(%s), volume_gain_type(%s), method(%s)",
+                    data.filename, data.role, data.volume_gain_type, data.method);
+
+            if (pa_streq(data.method, SOUND_PLAYER_METHOD_NAME_SIMPLE_PLAY))
+                _simple_play(u, data.filename, data.role, data.volume_gain_type);
+            else if (pa_streq(data.method, SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP))
+                _simple_stop(u, data.filename);
+            else if (pa_streq(data.method, SOUND_PLAYER_METHOD_NAME_SIMPLE_STOP_ALL))
+                _simple_stop_all(u);
+            else
+                pa_log_error("Invalid method!!!");
         } else {
             pa_log_warn("Fail to read, retry_count(%d), read sum(%d), err(%s)", retry_count, read_sum, pa_cstrerror(errno));
         }