f06b8f8ba2c06edc7d7422598fe7e1375d5f137d
[platform/core/api/wav-player.git] / src / wav_player_private.c
1 /*
2 * Copyright (c) 2011-2016 Samsung Electronics Co., Ltd All Rights Reserved
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #define LOG_TAG "TIZEN_N_WAV_PLAYER"
18
19 #include <stdio.h>
20 #include <limits.h>
21 #include <string.h>
22 #include <unistd.h>
23 #include <errno.h>
24 #include <dlog.h>
25 #include <stdlib.h>
26 #include <gio/gio.h>
27 #include <glib.h>
28 #include "wav_player_private.h"
29
30 #define PA_BUS_NAME "org.pulseaudio.Server"
31 #define PA_SOUND_PLAYER_OBJECT_PATH "/org/pulseaudio/SoundPlayer"
32 #define PA_SOUND_PLAYER_INTERFACE "org.pulseaudio.SoundPlayer"
33
34 #define PA_SOUND_PLAYER_METHOD_NAME_SOUND_PLAY          "SoundPlay"
35 #define PA_SOUND_PLAYER_METHOD_NAME_SOUND_STOP          "SoundStop"
36 #define PA_SOUND_PLAYER_SIGNAL_EOS                      "EOS"
37
38 typedef struct dbus_cb_data {
39         int handle;
40         guint subs_id;
41         wav_player_playback_completed_cb cb;
42         void *user_data;
43 } dbus_cb_data_s;
44
45 static int __convert_dbus_error(const char *error_msg)
46 {
47         if (error_msg) {
48                 if (strstr(error_msg, "UnsupportedMediaType"))
49                         return WAV_PLAYER_ERROR_FORMAT_NOT_SUPPORTED;
50                 else if (strstr(error_msg, "InvalidArgument"))
51                         return WAV_PLAYER_ERROR_INVALID_PARAMETER;
52         }
53
54         return WAV_PLAYER_ERROR_INVALID_OPERATION;
55 }
56
57 static void __weak_notify_cb(gpointer data, GObject *where_the_object_was)
58 {
59         LOGD("object(%p) destroyed, data(%p)", where_the_object_was, data);
60 }
61
62 static GDBusConnection *__get_dbus_connection(void)
63 {
64         GDBusConnection *conn = NULL;
65         g_autoptr(GError) err = NULL;
66
67         conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, NULL, &err);
68         if (!conn) {
69                 LOGE("g_bus_get_sync() error (%s)", err->message);
70                 return NULL;
71         }
72
73         /* For Debugging Purpose */
74         g_object_weak_ref(G_OBJECT(conn), __weak_notify_cb, NULL);
75
76         return conn;
77 }
78
79 static void __internal_complete_cb(GDBusConnection *connection,
80                                         const gchar *sender_name,
81                                         const gchar *object_path,
82                                         const gchar *interface_name,
83                                         const gchar *signal_name,
84                                         GVariant *params,
85                                         gpointer userdata)
86 {
87         gint handle = -1;
88         gboolean stopped_by_user = FALSE;
89         dbus_cb_data_s *dbus_data = (dbus_cb_data_s *)userdata;
90
91         if (!dbus_data) {
92                 LOGE("dbus data is null");
93                 return;
94         }
95
96         g_variant_get(params, "(ib)", &handle, &stopped_by_user);
97         LOGI("Incoming/expected handle(%d/%d), id(%u), callback(%p), stopped_by_user(%d)",
98                 handle, dbus_data->handle, dbus_data->subs_id, dbus_data->cb, stopped_by_user);
99
100         if (handle != dbus_data->handle)
101                 return;
102
103         if (!stopped_by_user) {
104                 LOGI("Invoking user callback(%p) for handle(%d)", dbus_data->cb, handle);
105                 dbus_data->cb(handle, dbus_data->user_data);
106         }
107
108         LOGI("user callback returned");
109
110         g_dbus_connection_signal_unsubscribe(connection, dbus_data->subs_id);
111         g_object_unref(connection);
112
113         g_free(dbus_data);
114 }
115
116 int _wav_play_sound(const char *path, sound_stream_info_h stream_info, unsigned loop_count,
117                         wav_player_playback_completed_cb callback, void *user_data, bool stop_others, int *id)
118 {
119         int ret = WAV_PLAYER_ERROR_NONE;
120         char m_path[PATH_MAX];
121         char *stream_type = NULL;
122         int stream_id;
123         bool result = false;
124
125         int handle;
126         g_autoptr(GDBusConnection) conn = NULL;
127         g_autoptr(GError) err = NULL;
128         g_autoptr(GVariant) reply = NULL;
129         dbus_cb_data_s *dbus_cb_data = NULL;
130
131         if (path == NULL || stream_info == NULL) {
132                 LOGE("invalid params");
133                 return WAV_PLAYER_ERROR_INVALID_PARAMETER;
134         }
135
136         LOGI("path(%s), loop(%u), cb(%p) user_data(%p)", path, loop_count, callback, user_data);
137
138         m_path[0] = '\0';
139         if (path[0] != '/' && getcwd(m_path, PATH_MAX) != NULL)
140                 strncat(m_path, "/", PATH_MAX - strlen(m_path) - 1);
141
142         strncat(m_path, path, PATH_MAX - strlen(m_path) - 1);
143         if (access(m_path, R_OK) != 0) {
144                 char str_error[256];
145                 strerror_r(errno, str_error, sizeof(str_error));
146                 LOGE("file [%s] doesn't exists : [%s][%d]", m_path, str_error, errno);
147                 return WAV_PLAYER_ERROR_INVALID_OPERATION;
148         }
149
150         ret = sound_manager_is_available_stream_information(stream_info, NATIVE_API_WAV_PLAYER, &result);
151         if (!result || ret) {
152                 LOGE("stream info is not available. ret(0x%x), result(%d)", ret, result);
153                 return WAV_PLAYER_ERROR_NOT_SUPPORTED_TYPE;
154         }
155
156         ret = sound_manager_get_type_from_stream_information(stream_info, &stream_type);
157         if (ret) {
158                 LOGE("can't get stream type. ret(0x%x)", ret);
159                 return WAV_PLAYER_ERROR_INVALID_OPERATION;
160         }
161
162         ret = sound_manager_get_index_from_stream_information(stream_info, &stream_id);
163         if (ret) {
164                 LOGE("can't get stream index. ret(0x%x)", ret);
165                 return WAV_PLAYER_ERROR_INVALID_OPERATION;
166         }
167
168         if (!(conn = __get_dbus_connection()))
169                 return WAV_PLAYER_ERROR_INVALID_OPERATION;
170
171         reply = g_dbus_connection_call_sync(conn, PA_BUS_NAME,
172                         PA_SOUND_PLAYER_OBJECT_PATH,
173                         PA_SOUND_PLAYER_INTERFACE,
174                         PA_SOUND_PLAYER_METHOD_NAME_SOUND_PLAY,
175                         g_variant_new("(siisib)", m_path, loop_count == 0 ? -1 : loop_count,
176                                         getpid(), stream_type, stream_id, (gboolean)stop_others),
177                         NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
178         if (!reply) {
179                 LOGE("g_dbus_connection_call_sync error (%s)", err->message);
180                 ret = __convert_dbus_error(err->message);
181                 return ret;
182         }
183
184         g_variant_get(reply, "(i)", &handle);
185         if (id)
186                 *id = handle;
187
188         LOGI("handle : %d", handle);
189
190         if (callback) {
191                 dbus_cb_data = g_new0(dbus_cb_data_s, 1);
192                 dbus_cb_data->handle = handle;
193                 dbus_cb_data->cb = callback;
194                 dbus_cb_data->user_data = user_data;
195                 dbus_cb_data->subs_id = g_dbus_connection_signal_subscribe(
196                                 g_object_ref(conn), NULL,
197                                 PA_SOUND_PLAYER_INTERFACE,
198                                 PA_SOUND_PLAYER_SIGNAL_EOS,
199                                 PA_SOUND_PLAYER_OBJECT_PATH,
200                                 NULL, G_DBUS_SIGNAL_FLAGS_NONE,
201                                 __internal_complete_cb, dbus_cb_data, NULL);
202                 if (dbus_cb_data->subs_id == 0) {
203                         g_object_unref(conn);
204                         g_free(dbus_cb_data);
205                         LOGE("g_dbus_connection_signal_subscribe() failed");
206                         return WAV_PLAYER_ERROR_INVALID_OPERATION;
207                 }
208         }
209
210         return WAV_PLAYER_ERROR_NONE;
211 }
212
213 //LCOV_EXCL_START
214 int _wav_play_sound_simple(const char *path, const char *stream_role)
215 {
216         char m_path[PATH_MAX];
217         int handle;
218         g_autoptr(GDBusConnection) conn = NULL;
219         g_autoptr(GError) err = NULL;
220         g_autoptr(GVariant) reply = NULL;
221
222         if (!path || !stream_role) {
223                 LOGE("invalid params path(%p), stream_role(%p)", path, stream_role);
224                 return WAV_PLAYER_ERROR_INVALID_PARAMETER;
225         }
226
227         LOGI("path(%s), stream_role(%s)", path, stream_role);
228
229         /* FIXME : need extraction of duplicated path validation code */
230         m_path[0] = '\0';
231         if (path[0] != '/' && getcwd(m_path, PATH_MAX) != NULL)
232                 strncat(m_path, "/", PATH_MAX - strlen(m_path) - 1);
233
234         strncat(m_path, path, PATH_MAX - strlen(m_path) - 1);
235         if (access(m_path, R_OK) != 0) {
236                 char str_error[256];
237                 strerror_r(errno, str_error, sizeof(str_error));
238                 LOGE("file [%s] doesn't exists : [%s][%d]", m_path, str_error, errno);
239                 return WAV_PLAYER_ERROR_INVALID_OPERATION;
240         }
241
242         if (!(conn = __get_dbus_connection()))
243                 return WAV_PLAYER_ERROR_INVALID_OPERATION;
244
245         reply = g_dbus_connection_call_sync(conn, PA_BUS_NAME,
246                                                                                 PA_SOUND_PLAYER_OBJECT_PATH,
247                                                                                 PA_SOUND_PLAYER_INTERFACE,
248                                                                                 PA_SOUND_PLAYER_METHOD_NAME_SOUND_PLAY,
249                                                                                 g_variant_new("(siisib)", m_path, 1,
250                                                                                                           getpid(), stream_role, -1, FALSE),
251                                                                                 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
252         if (!reply) {
253                 if (err) {
254                         LOGE("g_dbus_connection_call_sync error (%s)", err->message);
255                         return __convert_dbus_error(err->message);
256                 }
257                 return WAV_PLAYER_ERROR_INVALID_OPERATION;
258         }
259
260         g_variant_get(reply, "(i)", &handle);
261
262         LOGI("handle : %d", handle);
263
264         return WAV_PLAYER_ERROR_NONE;
265 }
266 //LCOV_EXCL_STOP
267
268 int _wav_stop_sound(int id)
269 {
270         g_autoptr(GDBusConnection) conn = NULL;
271         g_autoptr(GError) err = NULL;
272         g_autoptr(GVariant) reply = NULL;
273
274         LOGI("handle(%d)", id);
275
276         if (!(conn = __get_dbus_connection()))
277                 return WAV_PLAYER_ERROR_INVALID_OPERATION;
278
279         reply = g_dbus_connection_call_sync(conn,
280                                 PA_BUS_NAME,
281                                 PA_SOUND_PLAYER_OBJECT_PATH,
282                                 PA_SOUND_PLAYER_INTERFACE,
283                                 PA_SOUND_PLAYER_METHOD_NAME_SOUND_STOP,
284                                 g_variant_new("(i)", id),
285                                 NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, &err);
286         if (!reply) {
287                 LOGE("g_dbus_connection_call_sync error (%s)", err->message);
288                 return __convert_dbus_error(err->message);
289         }
290
291         LOGI("stop sound. handle(%d)", id);
292
293         return WAV_PLAYER_ERROR_NONE;
294 }