Use smart pointer using g_autoptr
[platform/core/api/wav-player.git] / src / wav_player_private.c
old mode 100755 (executable)
new mode 100644 (file)
index ee918db..f06b8f8
 
 #define LOG_TAG "TIZEN_N_WAV_PLAYER"
 
-#include <mm_sound.h>
-#include <mm_sound_private.h>
 #include <stdio.h>
 #include <limits.h>
 #include <string.h>
 #include <unistd.h>
+#include <errno.h>
 #include <dlog.h>
 #include <stdlib.h>
+#include <gio/gio.h>
+#include <glib.h>
 #include "wav_player_private.h"
 
-int _convert_wav_player_error_code(const char *func, int code)
+#define PA_BUS_NAME "org.pulseaudio.Server"
+#define PA_SOUND_PLAYER_OBJECT_PATH "/org/pulseaudio/SoundPlayer"
+#define PA_SOUND_PLAYER_INTERFACE "org.pulseaudio.SoundPlayer"
+
+#define PA_SOUND_PLAYER_METHOD_NAME_SOUND_PLAY         "SoundPlay"
+#define PA_SOUND_PLAYER_METHOD_NAME_SOUND_STOP         "SoundStop"
+#define PA_SOUND_PLAYER_SIGNAL_EOS                     "EOS"
+
+typedef struct dbus_cb_data {
+       int handle;
+       guint subs_id;
+       wav_player_playback_completed_cb cb;
+       void *user_data;
+} dbus_cb_data_s;
+
+static int __convert_dbus_error(const char *error_msg)
+{
+       if (error_msg) {
+               if (strstr(error_msg, "UnsupportedMediaType"))
+                       return WAV_PLAYER_ERROR_FORMAT_NOT_SUPPORTED;
+               else if (strstr(error_msg, "InvalidArgument"))
+                       return WAV_PLAYER_ERROR_INVALID_PARAMETER;
+       }
+
+       return WAV_PLAYER_ERROR_INVALID_OPERATION;
+}
+
+static void __weak_notify_cb(gpointer data, GObject *where_the_object_was)
 {
-       int ret = WAV_PLAYER_ERROR_INVALID_OPERATION;
-       char *errorstr = NULL;
-       switch (code) {
-       case MM_ERROR_NONE:
-               ret = WAV_PLAYER_ERROR_NONE;
-               errorstr = "ERROR_NONE";
-               break;
-       case MM_ERROR_INVALID_ARGUMENT:
-       case MM_ERROR_SOUND_INVALID_POINTER:
-       case WAV_PLAYER_ERROR_INVALID_PARAMETER:
-               ret = WAV_PLAYER_ERROR_INVALID_PARAMETER;
-               errorstr = "INVALID_PARAMETER";
-               break;
-       case MM_ERROR_SOUND_INTERNAL:
-               ret = WAV_PLAYER_ERROR_INVALID_OPERATION;
-               errorstr = "INVALID_OPERATION";
-               break;
-       case MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE:
-               ret = WAV_PLAYER_ERROR_FORMAT_NOT_SUPPORTED;
-               errorstr = "FORMAT_NOT_SUPPORTED";
-               break;
-       case WAV_PLAYER_ERROR_NOT_SUPPORTED_TYPE:
-               ret = WAV_PLAYER_ERROR_NOT_SUPPORTED_TYPE;
-               errorstr = "NOT_SUPPORTED_TYPE";
-               break;
-       default:
-               ret = WAV_PLAYER_ERROR_INVALID_OPERATION;
-               errorstr = "INVALID_OPERATION";
-               break;
+       LOGD("object(%p) destroyed, data(%p)", where_the_object_was, data);
+}
+
+static GDBusConnection *__get_dbus_connection(void)
+{
+       GDBusConnection *conn = NULL;
+       g_autoptr(GError) err = NULL;
+
+       conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
+       if (!conn) {
+               LOGE("g_bus_get_sync() error (%s)", err->message);
+               return NULL;
        }
-       LOGE("[%s] %s(0x%08x)", func, errorstr, ret);
-       return ret;
+
+       /* For Debugging Purpose */
+       g_object_weak_ref(G_OBJECT(conn), __weak_notify_cb, NULL);
+
+       return conn;
 }
 
-void _internal_complete_cb(void *user_data, int id)
+static void __internal_complete_cb(GDBusConnection *connection,
+                                       const gchar *sender_name,
+                                       const gchar *object_path,
+                                       const gchar *interface_name,
+                                       const gchar *signal_name,
+                                       GVariant *params,
+                                       gpointer userdata)
 {
-       _cb_data *cb_data = (_cb_data*)user_data;
-       if (!cb_data)
+       gint handle = -1;
+       gboolean stopped_by_user = FALSE;
+       dbus_cb_data_s *dbus_data = (dbus_cb_data_s *)userdata;
+
+       if (!dbus_data) {
+               LOGE("dbus data is null");
                return;
+       }
 
-       if (cb_data->cb) {
-               LOGD("user callback for handle %d call %p", id, cb_data->cb);
-               cb_data->cb(id, cb_data->user_data);
+       g_variant_get(params, "(ib)", &handle, &stopped_by_user);
+       LOGI("Incoming/expected handle(%d/%d), id(%u), callback(%p), stopped_by_user(%d)",
+               handle, dbus_data->handle, dbus_data->subs_id, dbus_data->cb, stopped_by_user);
+
+       if (handle != dbus_data->handle)
+               return;
+
+       if (!stopped_by_user) {
+               LOGI("Invoking user callback(%p) for handle(%d)", dbus_data->cb, handle);
+               dbus_data->cb(handle, dbus_data->user_data);
        }
-       free(cb_data);
+
+       LOGI("user callback returned");
+
+       g_dbus_connection_signal_unsubscribe(connection, dbus_data->subs_id);
+       g_object_unref(connection);
+
+       g_free(dbus_data);
 }
 
-int _start_with_stream_info(const char *path, sound_stream_info_h stream_info, unsigned loop_count, wav_player_playback_completed_cb callback, void *user_data, int *id)
+int _wav_play_sound(const char *path, sound_stream_info_h stream_info, unsigned loop_count,
+                       wav_player_playback_completed_cb callback, void *user_data, bool stop_others, int *id)
 {
-       int ret = MM_ERROR_NONE;
-       int player = -1;
+       int ret = WAV_PLAYER_ERROR_NONE;
        char m_path[PATH_MAX];
-       void (*_completed_cb)(void *, int);
-       _completed_cb = NULL;
-       _cb_data *cb_data = NULL;
        char *stream_type = NULL;
        int stream_id;
        bool result = false;
 
-       if (path == NULL || stream_info == NULL)
-               return _convert_wav_player_error_code(__func__, WAV_PLAYER_ERROR_INVALID_PARAMETER);
+       int handle;
+       g_autoptr(GDBusConnection) conn = NULL;
+       g_autoptr(GError) err = NULL;
+       g_autoptr(GVariant) reply = NULL;
+       dbus_cb_data_s *dbus_cb_data = NULL;
+
+       if (path == NULL || stream_info == NULL) {
+               LOGE("invalid params");
+               return WAV_PLAYER_ERROR_INVALID_PARAMETER;
+       }
+
+       LOGI("path(%s), loop(%u), cb(%p) user_data(%p)", path, loop_count, callback, user_data);
+
+       m_path[0] = '\0';
+       if (path[0] != '/' && getcwd(m_path, PATH_MAX) != NULL)
+               strncat(m_path, "/", PATH_MAX - strlen(m_path) - 1);
+
+       strncat(m_path, path, PATH_MAX - strlen(m_path) - 1);
+       if (access(m_path, R_OK) != 0) {
+               char str_error[256];
+               strerror_r(errno, str_error, sizeof(str_error));
+               LOGE("file [%s] doesn't exists : [%s][%d]", m_path, str_error, errno);
+               return WAV_PLAYER_ERROR_INVALID_OPERATION;
+       }
 
        ret = sound_manager_is_available_stream_information(stream_info, NATIVE_API_WAV_PLAYER, &result);
-       if (!result)
-               return _convert_wav_player_error_code(__func__, WAV_PLAYER_ERROR_NOT_SUPPORTED_TYPE);
+       if (!result || ret) {
+               LOGE("stream info is not available. ret(0x%x), result(%d)", ret, result);
+               return WAV_PLAYER_ERROR_NOT_SUPPORTED_TYPE;
+       }
 
        ret = sound_manager_get_type_from_stream_information(stream_info, &stream_type);
-       if (ret)
-               return _convert_wav_player_error_code(__func__, ret);
+       if (ret) {
+               LOGE("can't get stream type. ret(0x%x)", ret);
+               return WAV_PLAYER_ERROR_INVALID_OPERATION;
+       }
+
        ret = sound_manager_get_index_from_stream_information(stream_info, &stream_id);
-       if (ret)
-               return _convert_wav_player_error_code(__func__, ret);
+       if (ret) {
+               LOGE("can't get stream index. ret(0x%x)", ret);
+               return WAV_PLAYER_ERROR_INVALID_OPERATION;
+       }
 
-       m_path[0] = '\0';
-       if (path[0] != '/') {
+       if (!(conn = __get_dbus_connection()))
+               return WAV_PLAYER_ERROR_INVALID_OPERATION;
 
-               if (getcwd(m_path, PATH_MAX) != NULL)
-                       strncat(m_path, "/", PATH_MAX - strlen(m_path) - 1);
+       reply = g_dbus_connection_call_sync(conn, PA_BUS_NAME,
+                       PA_SOUND_PLAYER_OBJECT_PATH,
+                       PA_SOUND_PLAYER_INTERFACE,
+                       PA_SOUND_PLAYER_METHOD_NAME_SOUND_PLAY,
+                       g_variant_new("(siisib)", m_path, loop_count == 0 ? -1 : loop_count,
+                                       getpid(), stream_type, stream_id, (gboolean)stop_others),
+                       NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+       if (!reply) {
+               LOGE("g_dbus_connection_call_sync error (%s)", err->message);
+               ret = __convert_dbus_error(err->message);
+               return ret;
        }
-       strncat(m_path, path, PATH_MAX - strlen(m_path) - 1);
+
+       g_variant_get(reply, "(i)", &handle);
+       if (id)
+               *id = handle;
+
+       LOGI("handle : %d", handle);
 
        if (callback) {
-               _completed_cb = _internal_complete_cb;
-               cb_data = (_cb_data *)malloc(sizeof(_cb_data));
-               if (cb_data == NULL)
-                       return _convert_wav_player_error_code(__func__, WAV_PLAYER_ERROR_INVALID_OPERATION);
-               cb_data->cb = callback;
-               cb_data->user_data = user_data;
+               dbus_cb_data = g_new0(dbus_cb_data_s, 1);
+               dbus_cb_data->handle = handle;
+               dbus_cb_data->cb = callback;
+               dbus_cb_data->user_data = user_data;
+               dbus_cb_data->subs_id = g_dbus_connection_signal_subscribe(
+                               g_object_ref(conn), NULL,
+                               PA_SOUND_PLAYER_INTERFACE,
+                               PA_SOUND_PLAYER_SIGNAL_EOS,
+                               PA_SOUND_PLAYER_OBJECT_PATH,
+                               NULL, G_DBUS_SIGNAL_FLAGS_NONE,
+                               __internal_complete_cb, dbus_cb_data, NULL);
+               if (dbus_cb_data->subs_id == 0) {
+                       g_object_unref(conn);
+                       g_free(dbus_cb_data);
+                       LOGE("g_dbus_connection_signal_subscribe() failed");
+                       return WAV_PLAYER_ERROR_INVALID_OPERATION;
+               }
+       }
+
+       return WAV_PLAYER_ERROR_NONE;
+}
+
+//LCOV_EXCL_START
+int _wav_play_sound_simple(const char *path, const char *stream_role)
+{
+       char m_path[PATH_MAX];
+       int handle;
+       g_autoptr(GDBusConnection) conn = NULL;
+       g_autoptr(GError) err = NULL;
+       g_autoptr(GVariant) reply = NULL;
+
+       if (!path || !stream_role) {
+               LOGE("invalid params path(%p), stream_role(%p)", path, stream_role);
+               return WAV_PLAYER_ERROR_INVALID_PARAMETER;
        }
 
-       ret = mm_sound_play_sound_with_stream_info(m_path, stream_type, stream_id, loop_count, _completed_cb , cb_data, &player);
+       LOGI("path(%s), stream_role(%s)", path, stream_role);
+
+       /* FIXME : need extraction of duplicated path validation code */
+       m_path[0] = '\0';
+       if (path[0] != '/' && getcwd(m_path, PATH_MAX) != NULL)
+               strncat(m_path, "/", PATH_MAX - strlen(m_path) - 1);
 
-       if (ret == 0 && id != NULL)
-               *id = player;
+       strncat(m_path, path, PATH_MAX - strlen(m_path) - 1);
+       if (access(m_path, R_OK) != 0) {
+               char str_error[256];
+               strerror_r(errno, str_error, sizeof(str_error));
+               LOGE("file [%s] doesn't exists : [%s][%d]", m_path, str_error, errno);
+               return WAV_PLAYER_ERROR_INVALID_OPERATION;
+       }
+
+       if (!(conn = __get_dbus_connection()))
+               return WAV_PLAYER_ERROR_INVALID_OPERATION;
+
+       reply = g_dbus_connection_call_sync(conn, PA_BUS_NAME,
+                                                                               PA_SOUND_PLAYER_OBJECT_PATH,
+                                                                               PA_SOUND_PLAYER_INTERFACE,
+                                                                               PA_SOUND_PLAYER_METHOD_NAME_SOUND_PLAY,
+                                                                               g_variant_new("(siisib)", m_path, 1,
+                                                                                                         getpid(), stream_role, -1, FALSE),
+                                                                               NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+       if (!reply) {
+               if (err) {
+                       LOGE("g_dbus_connection_call_sync error (%s)", err->message);
+                       return __convert_dbus_error(err->message);
+               }
+               return WAV_PLAYER_ERROR_INVALID_OPERATION;
+       }
+
+       g_variant_get(reply, "(i)", &handle);
+
+       LOGI("handle : %d", handle);
+
+       return WAV_PLAYER_ERROR_NONE;
+}
+//LCOV_EXCL_STOP
+
+int _wav_stop_sound(int id)
+{
+       g_autoptr(GDBusConnection) conn = NULL;
+       g_autoptr(GError) err = NULL;
+       g_autoptr(GVariant) reply = NULL;
+
+       LOGI("handle(%d)", id);
+
+       if (!(conn = __get_dbus_connection()))
+               return WAV_PLAYER_ERROR_INVALID_OPERATION;
+
+       reply = g_dbus_connection_call_sync(conn,
+                               PA_BUS_NAME,
+                               PA_SOUND_PLAYER_OBJECT_PATH,
+                               PA_SOUND_PLAYER_INTERFACE,
+                               PA_SOUND_PLAYER_METHOD_NAME_SOUND_STOP,
+                               g_variant_new("(i)", id),
+                               NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
+       if (!reply) {
+               LOGE("g_dbus_connection_call_sync error (%s)", err->message);
+               return __convert_dbus_error(err->message);
+       }
 
-       if (ret != 0 && cb_data != NULL)
-               free(cb_data);
+       LOGI("stop sound. handle(%d)", id);
 
-       return _convert_wav_player_error_code(__func__, ret);
+       return WAV_PLAYER_ERROR_NONE;
 }