ca46587abd202ebbe64f86606764799f641d6122
[apps/mediaplayer.git] / binding / mediaplayer-manager.c
1 /*
2  *  Copyright 2017 Konsulko Group
3  *
4  *  Based on bluetooth-manager.c
5  *   Copyright 2016 ALPS ELECTRIC CO., LTD.
6  *
7  *   Licensed under the Apache License, Version 2.0 (the "License");
8  *   you may not use this file except in compliance with the License.
9  *   You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  *   Unless required by applicable law or agreed to in writing, software
14  *   distributed under the License is distributed on an "AS IS" BASIS,
15  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  *   See the License for the specific language governing permissions and
17  *   limitations under the License.
18  */
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <unistd.h>
24 #include <sys/types.h>
25 #include <sys/stat.h>
26
27 #include <pthread.h>
28 #include <glib.h>
29 #include <gio/gio.h>
30 #include <glib-object.h>
31 #include <sqlite3.h>
32
33 #include "mediaplayer-manager.h"
34
35 static Binding_RegisterCallback_t g_RegisterCallback = { 0 };
36 static stMediaPlayerManage MediaPlayerManage = { 0 };
37
38 /* ------ LOCAL  FUNCTIONS --------- */
39 void ListLock() {
40     g_mutex_lock(&(MediaPlayerManage.m));
41 }
42
43 void ListUnlock() {
44     g_mutex_unlock(&(MediaPlayerManage.m));
45 }
46
47 void DebugTraceSendMsg(int level, gchar* message)
48 {
49 #ifdef LOCAL_PRINT_DEBUG
50     switch (level)
51     {
52             case DT_LEVEL_ERROR:
53                 g_print("[E]");
54                 break;
55
56             case DT_LEVEL_WARNING:
57                 g_print("[W]");
58                 break;
59
60             case DT_LEVEL_NOTICE:
61                 g_print("[N]");
62                 break;
63
64             case DT_LEVEL_INFO:
65                 g_print("[I]");
66                 break;
67
68             case DT_LEVEL_DEBUG:
69                 g_print("[D]");
70                 break;
71
72             default:
73                 g_print("[-]");
74                 break;
75     }
76
77     g_print("%s",message);
78 #endif
79
80     if (message) {
81         g_free(message);
82     }
83
84 }
85
86 GList* media_local_scan(GList *list)
87 {
88     gchar *path = g_strconcat(g_get_home_dir(), "/", "Music", NULL);
89     gchar *tmp = NULL;
90     GDir *dir;
91
92     dir = g_dir_open(path, 0, NULL);
93     if (dir == NULL)
94     {
95         LOGE("Cannot open media path %s\n", path);
96         return list;
97     }
98
99     while ((tmp = (gchar *) g_dir_read_name(dir)) != NULL)
100     {
101         list = g_list_append(list, g_strdup_printf("file://%s/%s", path, tmp));
102     }
103
104     g_free(path);
105     g_dir_close(dir);
106
107     return list;
108 }
109
110 GList* media_lightmediascanner_scan(void)
111 {
112     sqlite3 *conn;
113     sqlite3_stmt *res;
114     GList *list = NULL;
115     const char *tail;
116     const gchar *db_path;
117     int ret = 0;
118
119     db_path = scanner1_get_data_base_path(MediaPlayerManage.lms_proxy);
120
121     ret = sqlite3_open(db_path, &conn);
122     if (ret) {
123         LOGE("Cannot open SQLITE database: '%s'\n", db_path);
124         return NULL;
125     }
126
127     ret = sqlite3_prepare_v2(conn, SQL_QUERY, strlen(SQL_QUERY) + 1, &res, &tail);
128     if (ret) {
129         LOGE("Cannot execute query '%s'\n", SQL_QUERY);
130         return NULL;
131     }
132
133     while (sqlite3_step(res) == SQLITE_ROW) {
134         struct stat buf;
135         const char *path = (const char *) sqlite3_column_text(res, 0);
136
137         ret = stat(path, &buf);
138         if (ret)
139             continue;
140
141         list = g_list_append(list, g_strdup_printf("file://%s", path));
142     }
143
144     sqlite3_finalize(res);
145
146     return list;
147 }
148
149
150 static void
151 on_interface_proxy_properties_changed (GDBusProxy *proxy,
152                                     GVariant *changed_properties,
153                                     const gchar* const  *invalidated_properties)
154 {
155     GVariantIter iter;
156     const gchar *key;
157     GVariant *subValue;
158     const gchar *pInterface;
159     GList *list;
160
161     pInterface = g_dbus_proxy_get_interface_name (proxy);
162
163     if (0 != g_strcmp0(pInterface, LIGHTMEDIASCANNER_INTERFACE))
164         return;
165
166     g_variant_iter_init (&iter, changed_properties);
167     while (g_variant_iter_next (&iter, "{&sv}", &key, &subValue))
168     {
169         gboolean val;
170         if (0 == g_strcmp0(key,"IsScanning")) {
171             g_variant_get(subValue, "b", &val);
172             if (val == TRUE)
173                 return;
174         } else if (0 == g_strcmp0(key, "WriteLocked")) {
175             g_variant_get(subValue, "b", &val);
176             if (val == TRUE)
177                 return;
178         }
179     }
180
181     ListLock();
182
183     list = media_lightmediascanner_scan();
184
185     if (list != NULL && g_RegisterCallback.binding_device_added)
186         g_RegisterCallback.binding_device_added(list);
187
188     g_list_free_full(list, g_free);
189
190     ListUnlock();
191 }
192
193 static int MediaPlayerDBusInit(void)
194 {
195     GError *error = NULL;
196
197     MediaPlayerManage.lms_proxy = scanner1_proxy_new_for_bus_sync(
198         G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, LIGHTMEDIASCANNER_SERVICE,
199         LIGHTMEDIASCANNER_PATH, NULL, &error);
200
201     if (MediaPlayerManage.lms_proxy == NULL) {
202         LOGE("Create LightMediaScanner Proxy failed\n");
203         return -1;
204     }
205
206     g_signal_connect (MediaPlayerManage.lms_proxy,
207                       "g-properties-changed",
208                       G_CALLBACK (on_interface_proxy_properties_changed),
209                       NULL);
210
211     return 0;
212 }
213
214 static void *media_event_loop_thread(void *unused)
215 {
216     GMainLoop *loop = g_main_loop_new(NULL, FALSE);
217     int ret;
218
219     ret = MediaPlayerDBusInit();
220     if (ret == 0) {
221         LOGD("g_main_loop_run\n");
222         g_main_loop_run(loop);
223     }
224
225     g_main_loop_unref(loop);
226
227     return NULL;
228 }
229
230 void
231 unmount_cb (GFileMonitor      *mon,
232             GFile             *file,
233             GFile             *other_file,
234             GFileMonitorEvent  event,
235             gpointer           udata)
236 {
237     gchar *path = g_file_get_path(file);
238     gchar *uri = g_strconcat("file://", path, NULL);
239     g_free(path);
240
241     ListLock();
242
243     if (g_RegisterCallback.binding_device_removed &&
244         event == G_FILE_MONITOR_EVENT_DELETED) {
245             g_RegisterCallback.binding_device_removed(uri);
246     }
247
248     ListUnlock();
249     g_free(uri);
250 }
251
252 /*
253  * Create MediaPlayer Manager Thread
254  * Note: mediaplayer-api should do MediaPlayerManagerInit() before any other 
255  *       API calls
256  * Returns: 0 - success or error conditions
257  */
258 int MediaPlayerManagerInit() {
259     pthread_t thread_id;
260     GFile *file;
261     GFileMonitor *mon;
262
263     g_mutex_init(&(MediaPlayerManage.m));
264
265     file = g_file_new_for_path("/media");
266     g_assert(file != NULL);
267
268     mon = g_file_monitor (file, G_FILE_MONITOR_NONE, NULL, NULL);
269     g_assert(mon != NULL);
270     g_signal_connect (mon, "changed", G_CALLBACK(unmount_cb), NULL);
271
272     pthread_create(&thread_id, NULL, media_event_loop_thread, NULL);
273
274     return 0;
275 }
276
277 /*
278  * Register MediaPlayer Manager Callback functions
279  */
280 void BindingAPIRegister(const Binding_RegisterCallback_t* pstRegisterCallback)
281 {
282     if (NULL != pstRegisterCallback)
283     {
284         if (NULL != pstRegisterCallback->binding_device_added)
285         {
286             g_RegisterCallback.binding_device_added =
287                 pstRegisterCallback->binding_device_added;
288         }
289
290         if (NULL != pstRegisterCallback->binding_device_removed)
291         {
292             g_RegisterCallback.binding_device_removed =
293                 pstRegisterCallback->binding_device_removed;
294         }
295     }
296 }