4 * Copyright (c) 2017 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Sangchul Lee <sc11.lee@samsung.com>
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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.
34 #include "include/mm_sound_focus_private.h"
36 focus_sound_info_t g_focus_sound_handle[FOCUS_HANDLE_MAX];
38 static gpointer _focus_thread_func(gpointer data)
40 unsigned int thread_id = (unsigned int)pthread_self();
41 GMainLoop *focus_loop = (GMainLoop*)data;
43 debug_warning(">>> thread id(%u), mainloop[%p]", thread_id, focus_loop);
45 g_main_loop_run(focus_loop);
46 debug_warning("<<< quit : thread id(%u), mainloop[%p]", thread_id, focus_loop);
51 static gboolean _focus_fd_prepare(GSource *source, gint *timeout)
54 debug_warning("[ PREPARE : %p, (%p, %d)", source, timeout, timeout ? *timeout : -1);
59 static gboolean _focus_fd_check(GSource * source)
61 FocusSource* fsource = (FocusSource *)source;
64 debug_error("GSource is null");
68 debug_warning("CHECK : %p, 0x%x ]", source, fsource->pollfd.revents);
70 if (fsource->poll_fd.revents & (POLLIN | POLLPRI))
76 static gboolean _focus_fd_dispatch(GSource *source, GSourceFunc callback, gpointer user_data)
78 debug_warning("*** DISPATCH : %p, (%p, %p)", source, callback, user_data);
79 return callback(user_data);
82 static void _focus_fd_finalize(GSource *source)
84 debug_warning("### FINALIZE : %p", source);
87 static gboolean _focus_callback_handler(gpointer user_data)
89 focus_sound_info_t *focus_handle = (focus_sound_info_t *)user_data;
93 focus_cb_data_lib cb_data;
95 debug_log(">>> thread id(%u)", (unsigned int)pthread_self());
98 debug_error("focus_handle is null");
99 return G_SOURCE_CONTINUE;
101 poll_fd = &focus_handle->fsrc->poll_fd;
102 debug_log("focus_handle(%p), poll_fd(%p)", focus_handle, poll_fd);
104 memset(&cb_data, 0, sizeof(focus_cb_data_lib));
106 if (poll_fd->revents & (POLLIN | POLLPRI)) {
107 int changed_state = -1;
109 count = read(poll_fd->fd, &cb_data, sizeof(cb_data));
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;
116 changed_state = cb_data.state;
118 g_mutex_lock(&focus_handle->focus_lock);
120 tid = focus_handle->focus_pid;
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;
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]");
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);
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);
147 g_mutex_unlock(&focus_handle->focus_lock);
148 return G_SOURCE_CONTINUE;
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));
156 debug_msg("[RETCB] tid(%d) finishing CB (write=%d)", tid, rett);
160 g_mutex_unlock(&focus_handle->focus_lock);
164 return G_SOURCE_CONTINUE;
167 static gboolean _focus_watch_callback_handler(gpointer user_data)
169 focus_sound_info_t *focus_handle = (focus_sound_info_t *)user_data;
173 focus_cb_data_lib cb_data;
175 debug_log(">>> thread id(%u)", (unsigned int)pthread_self());
178 debug_error("focus_handle is null");
179 return G_SOURCE_CONTINUE;
181 poll_fd = &focus_handle->fsrc->poll_fd;
182 debug_log("focus_handle(%p), poll_fd(%p)", focus_handle, poll_fd);
184 memset(&cb_data, 0, sizeof(focus_cb_data_lib));
186 if (poll_fd->revents & (POLLIN | POLLPRI)) {
187 count = read(poll_fd->fd, &cb_data, sizeof(cb_data));
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;
195 if (!focus_handle->is_used) {
196 debug_warning("unsetting watch calllback has been already requested");
197 goto SKIP_CB_AND_RET;
200 g_mutex_lock(&focus_handle->focus_lock);
202 tid = focus_handle->focus_pid;
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);
207 if (focus_handle->watch_callback == NULL) {
208 debug_warning("watch callback is null..");
209 goto SKIP_CB_AND_RET;
211 if (focus_handle->unset_watch_callback_requested == true) {
212 debug_warning("unset_watch_callback_requested..");
213 goto SKIP_CB_AND_RET;
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]");
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);
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);
234 g_mutex_unlock(&focus_handle->focus_lock);
235 return G_SOURCE_CONTINUE;
237 buf = cb_data.handle;
238 rett = write(tmpfd, &buf, sizeof(buf));
241 debug_msg("[RETCB] tid(%d) finishing CB (write=%d)", tid, rett);
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);
252 return G_SOURCE_CONTINUE;
255 #define INTERVAL_MS 20
256 static int _focus_loop_is_running_timed_wait(GMainLoop *focus_loop, int timeout_ms)
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;
265 if (g_main_loop_is_running(focus_loop))
266 return MM_ERROR_NONE;
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);
273 debug_error("focus_loop is not running for timeout_ms(%d), focus_loop(%p) ", timeout_ms, focus_loop);
275 return MM_ERROR_SOUND_INTERNAL;
278 static void _focus_open_callback(int index, bool is_for_watching)
285 if (index < 0 || index >= FOCUS_HANDLE_MAX) {
286 debug_error("Invalid focus handle index [%d]", index);
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);
295 filename = g_strdup_printf("/tmp/FOCUS.%d.%d",
296 g_focus_sound_handle[index].focus_pid,
297 g_focus_sound_handle[index].handle);
300 if (mknod(filename, S_IFIFO|0666, 0))
301 debug_error("mknod() failure, errno(%d)", errno);
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);
307 debug_log("Open success : index(%d), filename(%s), fd(%d)",
308 index, filename, g_focus_sound_handle[index].focus_fd);
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);
318 filename = g_strdup_printf("/tmp/FOCUS.%d.%dr",
319 g_focus_sound_handle[index].focus_pid,
320 g_focus_sound_handle[index].handle);
323 if (mknod(filename, S_IFIFO | 0666, 0))
324 debug_error("mknod() failure, errno(%d)", errno);
332 void _focus_close_callback(int index, bool is_for_watching)
334 char *filename = NULL;
338 if (index < 0 || index >= FOCUS_HANDLE_MAX) {
339 debug_error("Invalid focus handle index [%d]", index);
343 if (g_focus_sound_handle[index].focus_fd < 0) {
344 debug_error("Close fail : index(%d)", index);
346 close(g_focus_sound_handle[index].focus_fd);
347 debug_log("Close Success : index(%d)", index);
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);
355 filename = g_strdup_printf("/tmp/FOCUS.%d.%d",
356 g_focus_sound_handle[index].focus_pid,
357 g_focus_sound_handle[index].handle);
359 if (remove(filename)) {
360 debug_warning("remove(%s) failure (focus_server probably removed it in advance), errno(%d)",
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);
371 filename = g_strdup_printf("/tmp/FOCUS.%d.%dr",
372 g_focus_sound_handle[index].focus_pid,
373 g_focus_sound_handle[index].handle);
375 if (remove(filename)) {
376 debug_warning("remove(%s) failure (focus_server probably removed it in advance), errno(%d)",
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,
392 static bool _focus_add_sound_callback(int index, focus_callback_handler_t focus_cb_handler)
394 FocusSource *fsrc = NULL;
400 g_mutex_init(&g_focus_sound_handle[index].focus_lock);
402 src = g_source_new(&event_funcs, sizeof(FocusSource));
404 debug_error("failed to g_source_new for focus source");
408 fsrc = (FocusSource*) src;
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);
414 g_source_set_callback(src, focus_cb_handler, (gpointer)&g_focus_sound_handle[index], NULL);
416 debug_warning("fsrc(%p), src_funcs(%p), pollfd(%p), fd(%d)",
417 fsrc, &event_funcs, &fsrc->poll_fd, fsrc->poll_fd.fd);
419 fsrc_id = g_source_attach(src, g_main_loop_get_context(g_focus_sound_handle[index].focus_loop));
421 debug_error("failed to attach the source to context");
426 g_focus_sound_handle[index].fsrc = fsrc;
438 static bool _focus_remove_sound_callback(int index)
440 focus_sound_info_t *h = NULL;
444 if (index < 0 || index >= FOCUS_HANDLE_MAX) {
445 debug_error("Invalid focus handle index [%d]", index);
449 h = &g_focus_sound_handle[index];
451 g_source_destroy((GSource *)h->fsrc);
455 h->focus_callback = NULL;
456 h->watch_callback = NULL;
458 g_mutex_clear(&h->focus_lock);
465 static void _focus_add_callback(int index, bool is_for_watching)
469 if (index < 0 || index >= FOCUS_HANDLE_MAX) {
470 debug_error("Invalid focus handle index [%d]", index);
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);
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);
484 static void _focus_remove_callback(int index)
487 if (!_focus_remove_sound_callback(index))
488 debug_error("failed to __focus_remove_sound_callback()");
492 int focus_find_empty_index(int *index)
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);
506 if (i == FOCUS_HANDLE_MAX) {
507 debug_error("could not find empty slot, it is full");
516 int focus_find_index_by_handle(int handle)
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;
528 int focus_watch_find_index_by_handle(int handle)
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;
540 #define LOOP_RUNNING_WAIT_TIME_MS 200
541 int focus_init_context(int index)
543 int ret = MM_ERROR_NONE;
544 GMainContext *focus_context;
548 if (index < 0 || index >= FOCUS_HANDLE_MAX) {
549 debug_error("index(%d) is not valid", index);
550 return MM_ERROR_INVALID_ARGUMENT;
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..");
561 g_focus_sound_handle[index].focus_cb_thread = g_thread_new("focus-cb-thread",
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..");
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);
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);
579 return MM_ERROR_NONE;
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;
586 return MM_ERROR_SOUND_INTERNAL;
589 void focus_deinit_context(int index)
593 if (index < 0 || index >= FOCUS_HANDLE_MAX) {
594 debug_error("index(%d) is not valid", index);
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);
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;
615 void focus_init_callback(int index, bool is_for_watching)
618 _focus_open_callback(index, is_for_watching);
619 _focus_add_callback(index, is_for_watching);
623 void focus_deinit_callback(int index, bool is_for_watching)
626 _focus_remove_callback(index);
627 _focus_close_callback(index, is_for_watching);