Fix ASAN build break
[platform/core/multimedia/libmm-sound.git] / mm_sound_focus_private.c
1 /*
2  * libmm-sound
3  *
4  * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Sangchul Lee <sc11.lee@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdbool.h>
24 #include <string.h>
25 #include <pthread.h>
26 #include <glib.h>
27 #include <poll.h>
28 #include <fcntl.h>
29 #include <sys/stat.h>
30 #include <unistd.h>
31
32 #include <mm_debug.h>
33 #include <mm_error.h>
34 #include "include/mm_sound_focus_private.h"
35
36 focus_sound_info_t g_focus_sound_handle[FOCUS_HANDLE_MAX];
37
38 static gpointer _focus_thread_func(gpointer data)
39 {
40         unsigned int thread_id = (unsigned int)pthread_self();
41         GMainLoop *focus_loop = (GMainLoop*)data;
42
43         debug_warning(">>> thread id(%u), mainloop[%p]", thread_id, focus_loop);
44         if (focus_loop)
45                 g_main_loop_run(focus_loop);
46         debug_warning("<<< quit : thread id(%u), mainloop[%p]", thread_id, focus_loop);
47
48         return NULL;
49 }
50
51 static gboolean _focus_fd_prepare(GSource *source, gint *timeout)
52 {
53 #ifdef __DEBUG__
54         debug_warning("[ PREPARE : %p, (%p, %d)", source, timeout, timeout ? *timeout : -1);
55 #endif
56         return FALSE;
57 }
58
59 static gboolean _focus_fd_check(GSource * source)
60 {
61         FocusSource* fsource = (FocusSource *)source;
62
63         if (!fsource) {
64                 debug_error("GSource is null");
65                 return FALSE;
66         }
67 #ifdef __DEBUG__
68         debug_warning("CHECK : %p, 0x%x ]", source, fsource->pollfd.revents);
69 #endif
70         if (fsource->poll_fd.revents & (POLLIN | POLLPRI))
71                 return TRUE;
72         else
73                 return FALSE;
74 }
75
76 static gboolean _focus_fd_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
77 {
78         debug_warning("*** DISPATCH : %p, (%p, %p)", source, callback, user_data);
79         return callback(user_data);
80 }
81
82 static void _focus_fd_finalize(GSource *source)
83 {
84         debug_warning("### FINALIZE : %p", source);
85 }
86
87 static gboolean _focus_callback_handler(gpointer user_data)
88 {
89         focus_sound_info_t *focus_handle = (focus_sound_info_t *)user_data;
90         GPollFD *poll_fd;
91         int count;
92         int tid = 0;
93         focus_cb_data_lib cb_data;
94
95         debug_log(">>> thread id(%u)", (unsigned int)pthread_self());
96
97         if (!focus_handle) {
98                 debug_error("focus_handle is null");
99                 return G_SOURCE_CONTINUE;
100         }
101         poll_fd = &focus_handle->fsrc->poll_fd;
102         debug_log("focus_handle(%p), poll_fd(%p)", focus_handle, poll_fd);
103
104         memset(&cb_data, 0, sizeof(focus_cb_data_lib));
105
106         if (poll_fd->revents & (POLLIN | POLLPRI)) {
107                 int changed_state = -1;
108
109                 count = read(poll_fd->fd, &cb_data, sizeof(cb_data));
110                 if (count < 0) {
111                         char str_error[256];
112                         strerror_r(errno, str_error, sizeof(str_error));
113                         debug_error("GpollFD read fail, errno=%d(%s)", errno, str_error);
114                         return G_SOURCE_CONTINUE;
115                 }
116                 changed_state = cb_data.state;
117
118                 g_mutex_lock(&focus_handle->focus_lock);
119
120                 tid = focus_handle->focus_pid;
121
122                 if (changed_state != -1) {
123                         debug_msg("Got and start CB : TID(%d), handle(%d), type(%d), state(%d,(DEACTIVATED(0)/ACTIVATED(1)), trigger(%s)",
124                                         tid, cb_data.handle, cb_data.type, cb_data.state, cb_data.stream_type);
125                         if (focus_handle->focus_callback == NULL) {
126                                         debug_error("focus callback is null..");
127                                         g_mutex_unlock(&focus_handle->focus_lock);
128                                         return G_SOURCE_CONTINUE;
129                         }
130                         debug_msg("[CALLBACK(%p) START]", focus_handle->focus_callback);
131                         (focus_handle->focus_callback)(cb_data.handle, cb_data.type, cb_data.state, cb_data.stream_type,
132                                                                                 cb_data.option, cb_data.ext_info, focus_handle->user_data);
133                         debug_msg("[CALLBACK END]");
134                 }
135                 {
136                         int rett = 0;
137                         int tmpfd = -1;
138                         unsigned int buf = 0;
139                         char *filename2 = g_strdup_printf("/tmp/FOCUS.%d.%dr", focus_handle->focus_pid, cb_data.handle);
140                         tmpfd = open(filename2, O_WRONLY | O_NONBLOCK);
141                         if (tmpfd < 0) {
142                                 char str_error[256];
143                                 strerror_r(errno, str_error, sizeof(str_error));
144                                 debug_warning("[RETCB][Failed(May Server Close First)]tid(%d) fd(%d) %s errno=%d(%s)",
145                                                         tid, tmpfd, filename2, errno, str_error);
146                                 g_free(filename2);
147                                 g_mutex_unlock(&focus_handle->focus_lock);
148                                 return G_SOURCE_CONTINUE;
149                         }
150                         /* buf contains data as below,
151                          * |<--12bits--><--4bits (reacquisition)--><--16bits (handle)-->| */
152                         buf = (unsigned int)((0x0000ffff & cb_data.handle) | (focus_handle->auto_reacquire << 16));
153                         rett = write(tmpfd, &buf, sizeof(buf));
154                         close(tmpfd);
155                         g_free(filename2);
156                         debug_msg("[RETCB] tid(%d) finishing CB (write=%d)", tid, rett);
157                 }
158         }
159
160         g_mutex_unlock(&focus_handle->focus_lock);
161
162         debug_fleave();
163
164         return G_SOURCE_CONTINUE;
165 }
166
167 static gboolean _focus_watch_callback_handler(gpointer user_data)
168 {
169         focus_sound_info_t *focus_handle = (focus_sound_info_t *)user_data;
170         GPollFD *poll_fd;
171         int count;
172         int tid = 0;
173         focus_cb_data_lib cb_data;
174
175         debug_log(">>> thread id(%u)", (unsigned int)pthread_self());
176
177         if (!focus_handle) {
178                 debug_error("focus_handle is null");
179                 return G_SOURCE_CONTINUE;
180         }
181         poll_fd = &focus_handle->fsrc->poll_fd;
182         debug_log("focus_handle(%p), poll_fd(%p)", focus_handle, poll_fd);
183
184         memset(&cb_data, 0, sizeof(focus_cb_data_lib));
185
186         if (poll_fd->revents & (POLLIN | POLLPRI)) {
187                 count = read(poll_fd->fd, &cb_data, sizeof(cb_data));
188                 if (count < 0) {
189                         char str_error[256];
190                         strerror_r(errno, str_error, sizeof(str_error));
191                         debug_error("GpollFD read fail, errno=%d(%s)", errno, str_error);
192                         return G_SOURCE_CONTINUE;
193                 }
194
195                 if (!focus_handle->is_used) {
196                         debug_warning("unsetting watch calllback has been already requested");
197                         goto SKIP_CB_AND_RET;
198                 }
199
200                 g_mutex_lock(&focus_handle->focus_lock);
201
202                 tid = focus_handle->focus_pid;
203
204                 debug_msg("Got and start CB : TID(%d), handle(%d), type(%d), state(%d,(DEACTIVATED(0)/ACTIVATED(1)), trigger(%s)",
205                                 tid, cb_data.handle,  cb_data.type, cb_data.state, cb_data.stream_type);
206
207                 if (focus_handle->watch_callback == NULL) {
208                         debug_warning("watch callback is null..");
209                         goto SKIP_CB_AND_RET;
210                 }
211                 if (focus_handle->unset_watch_callback_requested == true) {
212                         debug_warning("unset_watch_callback_requested..");
213                         goto SKIP_CB_AND_RET;
214                 }
215
216                 debug_msg("[CALLBACK(%p) START]", focus_handle->watch_callback);
217                 (focus_handle->watch_callback)(cb_data.handle, cb_data.type, cb_data.state, cb_data.stream_type,
218                                                                         cb_data.ext_info, focus_handle->user_data);
219                 debug_msg("[CALLBACK END]");
220
221 SKIP_CB_AND_RET:
222                 {
223                         int rett = 0;
224                         int tmpfd = -1;
225                         int buf = -1;
226                         char *filename2 = g_strdup_printf("/tmp/FOCUS.%d.%d.wchr", focus_handle->focus_pid, cb_data.handle);
227                         tmpfd = open(filename2, O_WRONLY | O_NONBLOCK);
228                         if (tmpfd < 0) {
229                                 char str_error[256];
230                                 strerror_r(errno, str_error, sizeof(str_error));
231                                 debug_warning("[RETCB][Failed(May Server Close First)]tid(%d) fd(%d) %s errno=%d(%s)",
232                                                         tid, tmpfd, filename2, errno, str_error);
233                                 g_free(filename2);
234                                 g_mutex_unlock(&focus_handle->focus_lock);
235                                 return G_SOURCE_CONTINUE;
236                         }
237                         buf = cb_data.handle;
238                         rett = write(tmpfd, &buf, sizeof(buf));
239                         close(tmpfd);
240                         g_free(filename2);
241                         debug_msg("[RETCB] tid(%d) finishing CB (write=%d)", tid, rett);
242                 }
243         }
244
245         if (focus_handle->is_used) {
246                 debug_msg("unlock focus_lock = %p", &focus_handle->focus_lock);
247                 g_mutex_unlock(&focus_handle->focus_lock);
248         }
249
250         debug_fleave();
251
252         return G_SOURCE_CONTINUE;
253 }
254
255 #define INTERVAL_MS 20
256 static int _focus_loop_is_running_timed_wait(GMainLoop *focus_loop, int timeout_ms)
257 {
258         int reduced_time_ms = timeout_ms;
259         if (!focus_loop || timeout_ms < 0) {
260                 debug_error("invalid argument, focus_loop(%p), timeout_ms(%d)", focus_loop, timeout_ms);
261                 return MM_ERROR_INVALID_ARGUMENT;
262         }
263
264         do {
265                 if (g_main_loop_is_running(focus_loop))
266                         return MM_ERROR_NONE;
267
268                 usleep(INTERVAL_MS * 1000);
269                 if (reduced_time_ms < timeout_ms)
270                         debug_warning("reduced_time_ms(%d)", reduced_time_ms);
271         } while ((reduced_time_ms -= INTERVAL_MS) >= 0);
272
273         debug_error("focus_loop is not running for timeout_ms(%d), focus_loop(%p) ", timeout_ms, focus_loop);
274
275         return MM_ERROR_SOUND_INTERNAL;
276 }
277
278 static void _focus_open_callback(int index, bool is_for_watching)
279 {
280         mode_t pre_mask;
281         char *filename;
282
283         debug_fenter();
284
285         if (index < 0 || index >= FOCUS_HANDLE_MAX) {
286                 debug_error("Invalid focus handle index [%d]", index);
287                 return;
288         }
289
290         if (is_for_watching) {
291                 filename = g_strdup_printf("/tmp/FOCUS.%d.%d.wch",
292                                                                 g_focus_sound_handle[index].focus_pid,
293                                                                 g_focus_sound_handle[index].handle);
294         } else {
295                 filename = g_strdup_printf("/tmp/FOCUS.%d.%d",
296                                                                 g_focus_sound_handle[index].focus_pid,
297                                                                 g_focus_sound_handle[index].handle);
298         }
299         pre_mask = umask(0);
300         if (mknod(filename, S_IFIFO|0666, 0))
301                 debug_error("mknod() failure, errno(%d)", errno);
302         umask(pre_mask);
303         g_focus_sound_handle[index].focus_fd = open(filename, O_RDWR|O_NONBLOCK);
304         if (g_focus_sound_handle[index].focus_fd == -1) {
305                 debug_error("Open fail : index(%d), file open error(%d)", index, errno);
306         } else {
307                 debug_log("Open success : index(%d), filename(%s), fd(%d)",
308                                 index, filename, g_focus_sound_handle[index].focus_fd);
309         }
310         g_free(filename);
311         filename = NULL;
312
313         if (is_for_watching) {
314                 filename = g_strdup_printf("/tmp/FOCUS.%d.%d.wchr",
315                                                                         g_focus_sound_handle[index].focus_pid,
316                                                                         g_focus_sound_handle[index].handle);
317         } else {
318                 filename = g_strdup_printf("/tmp/FOCUS.%d.%dr",
319                                                                         g_focus_sound_handle[index].focus_pid,
320                                                                         g_focus_sound_handle[index].handle);
321         }
322         pre_mask = umask(0);
323         if (mknod(filename, S_IFIFO | 0666, 0))
324                 debug_error("mknod() failure, errno(%d)", errno);
325         umask(pre_mask);
326         g_free(filename);
327         filename = NULL;
328
329         debug_fleave();
330 }
331
332 void _focus_close_callback(int index, bool is_for_watching)
333 {
334         char *filename = NULL;
335
336         debug_fenter();
337
338         if (index < 0 || index >= FOCUS_HANDLE_MAX) {
339                 debug_error("Invalid focus handle index [%d]", index);
340                 return;
341         }
342
343         if (g_focus_sound_handle[index].focus_fd < 0) {
344                 debug_error("Close fail : index(%d)", index);
345         } else {
346                 close(g_focus_sound_handle[index].focus_fd);
347                 debug_log("Close Success : index(%d)", index);
348         }
349
350         if (is_for_watching) {
351                 filename = g_strdup_printf("/tmp/FOCUS.%d.%d.wch",
352                                                                 g_focus_sound_handle[index].focus_pid,
353                                                                 g_focus_sound_handle[index].handle);
354         } else {
355                 filename = g_strdup_printf("/tmp/FOCUS.%d.%d",
356                                                                 g_focus_sound_handle[index].focus_pid,
357                                                                 g_focus_sound_handle[index].handle);
358         }
359         if (remove(filename)) {
360                 debug_warning("remove(%s) failure (focus_server probably removed it in advance), errno(%d)",
361                                         filename, errno);
362         }
363         g_free(filename);
364         filename = NULL;
365
366         if (is_for_watching) {
367                 filename = g_strdup_printf("/tmp/FOCUS.%d.%d.wchr",
368                                                                         g_focus_sound_handle[index].focus_pid,
369                                                                         g_focus_sound_handle[index].handle);
370         } else {
371                 filename = g_strdup_printf("/tmp/FOCUS.%d.%dr",
372                                                                         g_focus_sound_handle[index].focus_pid,
373                                                                         g_focus_sound_handle[index].handle);
374         }
375         if (remove(filename)) {
376                 debug_warning("remove(%s) failure (focus_server probably removed it in advance), errno(%d)",
377                                         filename, errno);
378         }
379         g_free(filename);
380         filename = NULL;
381
382         debug_fleave();
383 }
384
385 static GSourceFuncs event_funcs = {
386         .prepare = _focus_fd_prepare,
387         .check = _focus_fd_check,
388         .dispatch = _focus_fd_dispatch,
389         .finalize = _focus_fd_finalize,
390 };
391
392 static bool _focus_add_sound_callback(int index, focus_callback_handler_t focus_cb_handler)
393 {
394         FocusSource *fsrc = NULL;
395         GSource *src = NULL;
396         guint fsrc_id = 0;
397
398         debug_fenter();
399
400         g_mutex_init(&g_focus_sound_handle[index].focus_lock);
401
402         src = g_source_new(&event_funcs, sizeof(FocusSource));
403         if (!src) {
404                 debug_error("failed to g_source_new for focus source");
405                 goto ERROR;
406         }
407
408         fsrc = (FocusSource*) src;
409
410         fsrc->poll_fd.fd = g_focus_sound_handle[index].focus_fd;
411         fsrc->poll_fd.events = (gushort)(POLLIN | POLLPRI);
412         g_source_add_poll(src, &fsrc->poll_fd);
413
414         g_source_set_callback(src, focus_cb_handler, (gpointer)&g_focus_sound_handle[index], NULL);
415
416         debug_warning("fsrc(%p), src_funcs(%p), pollfd(%p), fd(%d)",
417                                 fsrc, &event_funcs, &fsrc->poll_fd, fsrc->poll_fd.fd);
418
419         fsrc_id = g_source_attach(src, g_main_loop_get_context(g_focus_sound_handle[index].focus_loop));
420         if (!fsrc_id) {
421                 debug_error("failed to attach the source to context");
422                 goto ERROR;
423         }
424         g_source_unref(src);
425
426         g_focus_sound_handle[index].fsrc = fsrc;
427
428         debug_fleave();
429         return true;
430
431 ERROR:
432         if (src)
433                 g_source_unref(src);
434
435         return false;
436 }
437
438 static bool _focus_remove_sound_callback(int index)
439 {
440         focus_sound_info_t *h = NULL;
441
442         debug_fenter();
443
444         if (index < 0 || index >= FOCUS_HANDLE_MAX) {
445                 debug_error("Invalid focus handle index [%d]", index);
446                 return false;
447         }
448
449         h = &g_focus_sound_handle[index];
450         if (h->fsrc) {
451                 g_source_destroy((GSource *)h->fsrc);
452                 h->fsrc = NULL;
453         }
454
455         h->focus_callback = NULL;
456         h->watch_callback = NULL;
457
458         g_mutex_clear(&h->focus_lock);
459
460         debug_fleave();
461
462         return true;
463 }
464
465 static void _focus_add_callback(int index, bool is_for_watching)
466 {
467         debug_fenter();
468
469         if (index < 0 || index >= FOCUS_HANDLE_MAX) {
470                 debug_error("Invalid focus handle index [%d]", index);
471                 return;
472         }
473
474         if (!is_for_watching) {
475                 if (!_focus_add_sound_callback(index, _focus_callback_handler))
476                         debug_error("failed to _focus_add_sound_callback(%p)", _focus_callback_handler);
477         } else {
478                 if (!_focus_add_sound_callback(index, _focus_watch_callback_handler))
479                         debug_error("failed to _focus_add_sound_callback(%p)", _focus_watch_callback_handler);
480         }
481         debug_fleave();
482 }
483
484 static void _focus_remove_callback(int index)
485 {
486         debug_fenter();
487         if (!_focus_remove_sound_callback(index))
488                 debug_error("failed to __focus_remove_sound_callback()");
489         debug_fleave();
490 }
491
492 int focus_find_empty_index(int *index)
493 {
494         int i = 0;
495
496         if (!index)
497                 return -1;
498
499         for (i = 0; i < FOCUS_HANDLE_MAX; i++) {
500                 if (g_focus_sound_handle[i].is_used == false) {
501                         g_focus_sound_handle[i].is_used = true;
502                         debug_log("use index[%d]", i);
503                         break;
504                 }
505         }
506         if (i == FOCUS_HANDLE_MAX) {
507                 debug_error("could not find empty slot, it is full");
508                 return -1;
509         }
510
511         *index = i;
512
513         return 0;
514 }
515
516 int focus_find_index_by_handle(int handle)
517 {
518         int i = 0;
519         for (i = 0; i < FOCUS_HANDLE_MAX; i++) {
520                 if (g_focus_sound_handle[i].focus_callback && handle == g_focus_sound_handle[i].handle) {
521                         /* debug_msg("found index(%d) for handle(%d)", i, handle);*/
522                         return (handle == FOCUS_HANDLE_INIT_VAL) ? -1 : i;
523                 }
524         }
525         return -1;
526 }
527
528 int focus_watch_find_index_by_handle(int handle)
529 {
530         int i = 0;
531         for (i = 0; i < FOCUS_HANDLE_MAX; i++) {
532                 if (g_focus_sound_handle[i].watch_callback && handle == g_focus_sound_handle[i].handle) {
533                         /* debug_msg("found index(%d) for watch handle(%d)", i, handle);*/
534                         return (handle == FOCUS_HANDLE_INIT_VAL) ? -1 : i;
535                 }
536         }
537         return -1;
538 }
539
540 #define LOOP_RUNNING_WAIT_TIME_MS 200
541 int focus_init_context(int index)
542 {
543         int ret = MM_ERROR_NONE;
544         GMainContext *focus_context;
545
546         debug_fenter();
547
548         if (index < 0 || index >= FOCUS_HANDLE_MAX) {
549                 debug_error("index(%d) is not valid", index);
550                 return MM_ERROR_INVALID_ARGUMENT;
551         }
552
553         focus_context = g_main_context_new();
554         g_focus_sound_handle[index].focus_loop = g_main_loop_new(focus_context, FALSE);
555         g_main_context_unref(focus_context);
556         if (g_focus_sound_handle[index].focus_loop == NULL) {
557                 debug_error("could not create mainloop..");
558                 goto ERROR;
559         }
560
561         g_focus_sound_handle[index].focus_cb_thread = g_thread_new("focus-cb-thread",
562                                                                         _focus_thread_func,
563                                                                         g_focus_sound_handle[index].focus_loop);
564         if (g_focus_sound_handle[index].focus_cb_thread == NULL) {
565                 debug_error("could not create thread..");
566                 goto ERROR;
567         }
568
569         debug_warning("focus cb thread[%p] with mainloop[%p] is created for index(%d)",
570                                 g_focus_sound_handle[index].focus_cb_thread, g_focus_sound_handle[index].focus_loop, index);
571
572         if ((ret = _focus_loop_is_running_timed_wait(g_focus_sound_handle[index].focus_loop, LOOP_RUNNING_WAIT_TIME_MS))) {
573                 debug_error("failed to _focus_loop_is_running_timed_wait(), ret[0x%x]", ret);
574                 goto ERROR;
575         }
576
577         debug_fleave();
578
579         return MM_ERROR_NONE;
580
581 ERROR:
582         if (g_focus_sound_handle[index].focus_loop) {
583                 g_main_loop_unref(g_focus_sound_handle[index].focus_loop);
584                 g_focus_sound_handle[index].focus_loop = NULL;
585         }
586         return MM_ERROR_SOUND_INTERNAL;
587 }
588
589 void focus_deinit_context(int index)
590 {
591         debug_fenter();
592
593         if (index < 0 || index >= FOCUS_HANDLE_MAX) {
594                 debug_error("index(%d) is not valid", index);
595                 return;
596         }
597
598         if (!g_focus_sound_handle[index].focus_loop || !g_focus_sound_handle[index].focus_cb_thread) {
599                 debug_error("focus_loop[%p] or focus_cb_thread[%p] is null",
600                                 g_focus_sound_handle[index].focus_loop, g_focus_sound_handle[index].focus_cb_thread);
601                 return;
602         }
603
604         g_main_loop_quit(g_focus_sound_handle[index].focus_loop);
605         g_thread_join(g_focus_sound_handle[index].focus_cb_thread);
606         debug_warning("after thread join, thread[%p], mainloop[%p] for index(%d)",
607                         g_focus_sound_handle[index].focus_cb_thread, g_focus_sound_handle[index].focus_loop, index);
608         g_main_loop_unref(g_focus_sound_handle[index].focus_loop);
609         g_focus_sound_handle[index].focus_loop = NULL;
610         g_focus_sound_handle[index].focus_cb_thread = NULL;
611
612         debug_fleave();
613 }
614
615 void focus_init_callback(int index, bool is_for_watching)
616 {
617         debug_fenter();
618         _focus_open_callback(index, is_for_watching);
619         _focus_add_callback(index, is_for_watching);
620         debug_fleave();
621 }
622
623 void focus_deinit_callback(int index, bool is_for_watching)
624 {
625         debug_fenter();
626         _focus_remove_callback(index);
627         _focus_close_callback(index, is_for_watching);
628         debug_fleave();
629 }