4 * Copyright (c) 2000 - 2015 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.
25 #include "include/mm_sound_mgr_focus.h"
26 #include "../include/mm_sound_common.h"
32 #include "include/mm_sound_mgr_focus_dbus.h"
33 #include "../include/mm_sound_utils.h"
36 #define CALLBACK_TIMEOUT 2500 /* millisecond */
38 static GList *g_focus_node_list = NULL;
39 static pthread_mutex_t g_focus_node_list_mutex = PTHREAD_MUTEX_INITIALIZER;
40 stream_list_t g_stream_list;
42 static const char* focus_status_str[] =
55 char stream_type[MAX_STREAM_TYPE_LEN];
56 char ext_info[MM_SOUND_NAME_NUM];
60 #define CLEAR_DEAD_NODE_LIST(x) do { \
61 debug_warning("list = %p, node = %p, pid=[%d]", x, node, (node)? node->pid : -1); \
62 if (x && node && (mm_sound_util_is_process_alive(node->pid) == FALSE)) { \
63 debug_warning("PID:%d does not exist now! remove from device cb list\n", node->pid); \
64 __clear_focus_pipe(node); \
65 x = g_list_remove (x, node); \
70 #define UPDATE_FOCUS_TAKEN_INFO(x_postfix, x_node, x_pid, x_hid, x_by_session) do { \
71 debug_msg("updating node[%p], taken_"#x_postfix"[%d] : pid = [%d], handle_id = [%d], is_for_session = [%d]", x_node, i, x_pid, x_hid, x_by_session); \
72 x_node->taken_##x_postfix[i].pid = x_pid; \
73 x_node->taken_##x_postfix[i].handle_id = x_hid; \
74 x_node->taken_##x_postfix[i].by_session = x_by_session; \
77 #define CHECK_MY_NODE(x_node, x_param) \
78 (x_node && !x_node->is_for_watch && (x_node->pid == x_param->pid) && (x_node->handle_id == x_param->handle_id) && (x_node->is_for_session == x_param->is_for_session))
80 static char* __get_focus_pipe_path(int instance_id, int handle, const char* postfix, bool is_watch)
86 path = g_strdup_printf("/tmp/FOCUS.%d.%d.wch", instance_id, handle);
88 path = g_strdup_printf("/tmp/FOCUS.%d.%d", instance_id, handle);
92 path2 = g_strconcat(path, postfix, NULL);
101 static void __clear_focus_pipe(focus_node_t *node)
103 char *filename = NULL;
104 char *filename2 = NULL;
108 if (!node->is_for_watch) {
109 filename = __get_focus_pipe_path(node->pid, node->handle_id, NULL, false);
110 filename2 = __get_focus_pipe_path(node->pid, node->handle_id, "r", false);
112 filename = __get_focus_pipe_path(node->pid, node->handle_id, NULL, true);
113 filename2 = __get_focus_pipe_path(node->pid, node->handle_id, "r", true);
116 if (remove(filename))
117 debug_error("remove() failure, filename(%s), errno(%d)", filename, errno);
119 debug_log("removed file(%s)", filename);
123 if (remove(filename2))
124 debug_error("remove() failure, filename2(%s), errno(%d)", filename2, errno);
126 debug_log("removed file(%s)", filename2);
133 static void _clear_focus_node_list_func(focus_node_t *node, gpointer user_data)
135 CLEAR_DEAD_NODE_LIST(g_focus_node_list);
138 static int _mm_sound_mgr_focus_get_priority_from_stream_type(int *priority, const char *stream_type)
140 int ret = MM_ERROR_NONE;
145 if (priority == NULL || stream_type == NULL) {
146 ret = MM_ERROR_INVALID_ARGUMENT;
147 debug_error("invalid argument, priority[0x%x], stream_type[%s], ret[0x%x]\n", priority, stream_type, ret);
149 for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
150 if (g_stream_list.stream_types[i] &&
151 !strncmp(g_stream_list.stream_types[i], stream_type, strlen(stream_type))) {
152 *priority = g_stream_list.priorities[i];
156 if (i == AVAIL_STREAMS_MAX) {
157 ret = MM_ERROR_NOT_SUPPORT_API;
158 debug_error("not supported stream_type[%s], ret[0x%x]\n", stream_type, ret);
160 debug_log("[%s] has priority of [%d]\n", stream_type, *priority);
168 static int _mm_sound_mgr_focus_do_watch_callback(focus_type_e focus_type, focus_command_e command, focus_node_t *my_node, const _mm_sound_mgr_focus_param_t *param)
170 char *filename = NULL;
171 char *filename2 = NULL;
182 focus_node_t *node = NULL;
183 focus_cb_data cb_data;
187 for (list = g_focus_node_list; list != NULL; list = list->next) {
188 node = (focus_node_t *)list->data;
189 if (node == my_node || (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session)) {
192 if (node->is_for_watch && (node->status & focus_type)) {
193 memset(&cb_data, 0, sizeof(focus_cb_data));
194 cb_data.pid = node->pid;
195 cb_data.handle = node->handle_id;
196 cb_data.type = focus_type & node->status;
197 cb_data.state = (command == FOCUS_COMMAND_ACQUIRE) ? !FOCUS_STATUS_DEACTIVATED : FOCUS_STATUS_DEACTIVATED;
198 MMSOUND_STRNCPY(cb_data.stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
199 MMSOUND_STRNCPY(cb_data.ext_info, param->ext_info, MM_SOUND_NAME_NUM);
202 gettimeofday(&time, NULL);
203 starttime = time.tv_sec * 1000000 + time.tv_usec;
205 /**************************************
207 * Open callback cmd pipe
209 **************************************/
210 filename = __get_focus_pipe_path(cb_data.pid, cb_data.handle, NULL, true);
211 if (filename == NULL) {
212 debug_error("[CB] failed to get watch pipe");
215 if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
217 strerror_r(errno, str_error, sizeof(str_error));
218 debug_error("[CB] failed to open watch pipe (%s, err:%s)\n", filename, str_error);
222 /******************************************
224 * Open callback result pipe
225 * before writing callback cmd to pipe
227 ******************************************/
228 filename2 = __get_focus_pipe_path(cb_data.pid, cb_data.handle, "r", true);
229 if (filename2 == NULL) {
230 debug_error("[RETCB] failed to get watch return pipe");
233 if ((fd_FOCUS_R= open(filename2, O_RDONLY|O_NONBLOCK)) == -1) {
235 strerror_r(errno, str_error, sizeof(str_error));
236 debug_error("[RETCB] failed to open watch return pipe (%s, err:%s)\n", filename2, str_error);
240 /*******************************************
242 *******************************************/
243 if (write(fd_FOCUS, &cb_data ,sizeof(cb_data)) == -1) {
245 strerror_r(errno, str_error, sizeof(str_error));
246 debug_error("[CB] failed to write (err:%s)\n", str_error);
250 /*********************************************
252 * Wait callback result msg
254 ********************************************/
258 debug_msg("[RETCB] wait WATCH CALLBACK (client pid=%d, cmd=%d, timeout=%d(ms))\n", cb_data.pid, command, CALLBACK_TIMEOUT);
259 pret = poll(&pfd, 1, CALLBACK_TIMEOUT);
261 debug_error("[RETCB] poll failed (%d)\n", pret);
264 if (pfd.revents & POLLIN) {
265 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
267 strerror_r(errno, str_error, sizeof(str_error));
268 debug_error("[RETCB] failed to read (err:%s)\n", str_error);
273 /* Calculate endtime and display*/
274 gettimeofday(&time, NULL);
275 endtime = time.tv_sec * 1000000 + time.tv_usec;
276 debug_msg("[RETCB] WATCH CALLBACK returned (cbtimelab=%d(ms), client pid=%d, return handle=%d)\n", ((endtime-starttime)/1000), cb_data.pid, ret);
278 /**************************************
280 * Close callback result pipe
282 **************************************/
290 if (fd_FOCUS != -1) {
294 if (fd_FOCUS_R != -1) {
304 return MM_ERROR_NONE;
307 int _mm_sound_mgr_focus_do_callback(focus_command_e command, focus_node_t *victim_node, const _mm_sound_mgr_focus_param_t *assaulter_param, const char *assaulter_stream_type)
309 int res = MM_ERROR_NONE;
310 char *filename = NULL;
311 char *filename2 = NULL;
321 int flag_for_focus_type = 0;
322 int flag_for_taken_index = 0;
326 bool taken_by_session = false;
327 bool reacquisition_changed = false;
329 focus_cb_data cb_data;
331 debug_msg(" __mm_sound_mgr_focus_do_callback_ for pid(%d) handle(%d)\n", victim_node->pid, victim_node->handle_id);
333 memset(&cb_data, 0, sizeof(focus_cb_data));
334 cb_data.pid= victim_node->pid;
335 cb_data.handle= victim_node->handle_id;
336 if (command == FOCUS_COMMAND_RELEASE) {
337 /* client will lost the acquired focus */
338 cb_data.type= assaulter_param->request_type & victim_node->status;
339 cb_data.state= FOCUS_STATUS_DEACTIVATED;
340 /* remove ext info. */
341 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
342 if (cb_data.type & (i+1)) {
343 memset(victim_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
344 victim_node->option[i] = 0;
348 /* client will gain the lost focus */
349 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
350 if ((victim_node->taken_by_id[i].pid == assaulter_param->pid) && ((victim_node->taken_by_id[i].handle_id == assaulter_param->handle_id) || victim_node->taken_by_id[i].by_session)) {
351 flag_for_focus_type |= i+1; /* playback:1, capture:2 */
354 cb_data.type = flag_for_focus_type & assaulter_param->request_type;
355 cb_data.state = !FOCUS_STATUS_DEACTIVATED;
357 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
358 if (cb_data.type & (i+1)) {
359 MMSOUND_STRNCPY(victim_node->ext_info[i], assaulter_param->ext_info, MM_SOUND_NAME_NUM);
360 victim_node->option[i] = assaulter_param->option;
364 MMSOUND_STRNCPY(cb_data.stream_type, assaulter_stream_type, MAX_STREAM_TYPE_LEN);
365 MMSOUND_STRNCPY(cb_data.ext_info, assaulter_param->ext_info, MM_SOUND_NAME_NUM);
366 cb_data.option = assaulter_param->option;
369 gettimeofday(&time, NULL);
370 starttime = time.tv_sec * 1000000 + time.tv_usec;
372 /**************************************
374 * Open callback cmd pipe
376 **************************************/
377 filename = __get_focus_pipe_path(cb_data.pid, cb_data.handle, NULL, false);
378 if (filename == NULL) {
379 debug_error("[CB] failed to get pipe");
383 if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
385 strerror_r(errno, str_error, sizeof(str_error));
386 debug_error("[CB] failed to open pipe (%s, err:%s)\n", filename, str_error);
391 /******************************************
393 * Open callback result pipe
394 * before writing callback cmd to pipe
396 ******************************************/
397 filename2 = __get_focus_pipe_path(cb_data.pid, cb_data.handle, "r", false);
398 if (filename2 == NULL) {
399 debug_error("[RETCB] failed to get return pipe");
403 if ((fd_FOCUS_R = open(filename2,O_RDONLY|O_NONBLOCK)) == -1) {
405 strerror_r(errno, str_error, sizeof(str_error));
406 debug_error("[RETCB] failed to open return pipe (%s, err:%s)\n", filename2, str_error);
411 /*******************************************
413 *******************************************/
414 if (write(fd_FOCUS, &cb_data, sizeof(cb_data)) == -1) {
416 strerror_r(errno, str_error, sizeof(str_error));
417 debug_error("[CB] failed to write (err:%s)\n", str_error);
422 /*********************************************
424 * Wait callback result msg
426 ********************************************/
430 debug_msg("[RETCB] wait CALLBACK (client pid=%d, handle=%d, cmd=%d, timeout=%d(ms))\n",cb_data.pid, cb_data.handle, command, CALLBACK_TIMEOUT);
431 pret = poll(&pfd, 1, CALLBACK_TIMEOUT);
433 debug_error("[RETCB] poll failed (%d)\n", pret);
437 if (pfd.revents & POLLIN) {
438 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
440 strerror_r(errno, str_error, sizeof(str_error));
441 debug_error("[RETCB] failed to read (err:%s)\n", str_error);
445 /* ret contains data as below,
446 * |<--12bits--><--4bits (reacquisition)--><--16bits (handle)-->| */
447 ret_handle = (int)(ret & 0x0000ffff);
448 if (victim_node->reacquisition != (bool)((ret >> 16) & 0xf)) {
449 reacquisition_changed = true;
450 victim_node->reacquisition = (bool)((ret >> 16) & 0xf);
451 debug_msg("[RETCB] victim's reacquisition is changed to (%d)\n", victim_node->reacquisition);
455 /* Calculate endtime and display*/
456 gettimeofday(&time, NULL);
457 endtime = time.tv_sec * 1000000 + time.tv_usec;
458 debug_msg("[RETCB] CALLBACK returned (cbtimelab=%d(ms), client pid=%d, returned handle=%d)\n", ((endtime-starttime)/1000), cb_data.pid, ret_handle);
460 /* update victim node */
461 if (command == FOCUS_COMMAND_RELEASE) {
462 taken_pid = assaulter_param->pid;
463 taken_hid = assaulter_param->handle_id;
464 taken_by_session = assaulter_param->is_for_session;
465 flag_for_taken_index = assaulter_param->request_type & victim_node->status;
469 taken_by_session = false;
470 flag_for_taken_index = assaulter_param->request_type;
473 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
474 if (flag_for_taken_index & (i+1)) {
476 focus_node_t *node = NULL;
478 if (command == FOCUS_COMMAND_ACQUIRE && (victim_node->taken_by_id[i].pid != assaulter_param->pid || (victim_node->taken_by_id[i].handle_id != assaulter_param->handle_id && !(victim_node->taken_by_id[i].by_session & assaulter_param->is_for_session)))) {
480 debug_error("skip updating victim node");
483 if (reacquisition_changed) {
484 if (!victim_node->reacquisition) {
485 for (list = g_focus_node_list; list != NULL; list = list->next) {
486 if (!(node = (focus_node_t *)list->data))
488 if (node->taken_by_id[i].pid == victim_node->pid) {
489 UPDATE_FOCUS_TAKEN_INFO(backup, node, node->taken_by_id[i].pid, node->taken_by_id[i].handle_id, node->taken_by_id[i].by_session);
490 UPDATE_FOCUS_TAKEN_INFO(by_id, node, taken_pid, taken_hid, taken_by_session);
491 } else if (!list->next) {
492 UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, taken_pid, taken_hid, taken_by_session);
493 UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, 0, 0, false);
497 for (list = g_focus_node_list; list != NULL; list = list->next) {
498 if (!(node = (focus_node_t *)list->data))
500 if (node->taken_backup[i].pid == victim_node->pid) {
501 UPDATE_FOCUS_TAKEN_INFO(by_id, node, node->taken_backup[i].pid, node->taken_backup[i].handle_id, node->taken_backup[i].by_session);
502 UPDATE_FOCUS_TAKEN_INFO(backup, node, 0, 0, false);
503 } else if (!list->next) {
504 UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, taken_pid, taken_hid, taken_by_session);
505 UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, 0, 0, false);
510 if (victim_node->reacquisition)
511 UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, taken_pid, taken_hid, taken_by_session);
513 UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, taken_pid, taken_hid, taken_by_session);
518 victim_node->status = (command == FOCUS_COMMAND_RELEASE) ? (victim_node->status & ~(cb_data.type)) : (victim_node->status | cb_data.type);
520 if (strncmp(assaulter_stream_type, victim_node->stream_type, MAX_STREAM_TYPE_LEN))
521 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)assaulter_param->request_type, command, victim_node, assaulter_param);
530 if (fd_FOCUS != -1) {
534 if (fd_FOCUS_R != -1) {
542 static int _mm_sound_mgr_focus_list_dump ()
544 int ret = MM_ERROR_NONE;
546 focus_node_t *node = NULL;
548 debug_log("================================================ focus node list : start ===================================================\n");
549 for (list = g_focus_node_list; list != NULL; list = list->next) {
550 if ((node = (focus_node_t *)list->data) && !node->is_for_watch) {
551 debug_log("*** pid[%5d]/handle_id[%2d]/[%14s]:priority[%2d],status[%s],taken_by[P(%5d/%2d/%2d)C(%5d/%2d/%2d)],session[%d],option[0x%x/0x%x],ext_info[%s/%s]\n",
552 node->pid, node->handle_id, node->stream_type, node->priority, focus_status_str[node->status],
553 node->taken_by_id[0].pid, node->taken_by_id[0].handle_id, node->taken_by_id[0].by_session, node->taken_by_id[1].pid,
554 node->taken_by_id[1].handle_id, node->taken_by_id[1].by_session, node->is_for_session, node->option[0], node->option[1], node->ext_info[0], node->ext_info[1]);
557 debug_log("================================================ focus node list : end =====================================================\n");
562 static int _mm_sound_mgr_focus_watch_list_dump()
564 int ret = MM_ERROR_NONE;
566 focus_node_t *node = NULL;
568 debug_log("============================================= focus watch node list : start =================================================\n");
569 for (list = g_focus_node_list; list != NULL; list = list->next) {
570 if ((node = (focus_node_t *)list->data) && node->is_for_watch)
571 debug_log("*** pid[%5d]/handle_id[%d]/watch on focus status[%s]/for_session[%d]\n", node->pid, node->handle_id, focus_status_str[node->status], node->is_for_session);
573 debug_log("============================================= focus watch node list : end ===================================================\n");
578 static void _mm_sound_mgr_focus_fill_info_from_msg(focus_node_t *node, const _mm_sound_mgr_focus_param_t *msg)
581 node->pid = msg->pid;
582 node->handle_id = msg->handle_id;
583 node->callback = msg->callback;
584 node->cbdata = msg->cbdata;
585 node->is_for_session = msg->is_for_session;
591 int mm_sound_mgr_focus_create_node(const _mm_sound_mgr_focus_param_t *param)
593 int ret = MM_ERROR_NONE;
595 focus_node_t *node = NULL;
600 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
602 /* Update list for dead process */
603 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
605 for (list = g_focus_node_list; list != NULL; list = list->next) {
606 node = (focus_node_t *)list->data;
607 if (CHECK_MY_NODE(node, param)) {
608 debug_error("the node of pid[%d]/handle_id[%d] is already created\n", param->pid, param->handle_id);
609 ret = MM_ERROR_INVALID_ARGUMENT;
614 /* get priority from stream type */
615 ret = _mm_sound_mgr_focus_get_priority_from_stream_type(&priority, param->stream_type);
619 node = g_malloc0(sizeof(focus_node_t));
621 /* fill up information to the node */
622 _mm_sound_mgr_focus_fill_info_from_msg(node, param);
623 node->priority = priority;
624 node->status = FOCUS_STATUS_DEACTIVATED;
625 node->reacquisition = true;
626 MMSOUND_STRNCPY(node->stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
628 g_focus_node_list = g_list_append(g_focus_node_list, node);
629 if (g_focus_node_list) {
630 debug_log("new focus node is added\n");
632 debug_error("g_list_append failed\n");
633 ret = MM_ERROR_SOUND_INTERNAL;
637 _mm_sound_mgr_focus_list_dump();
639 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
645 int mm_sound_mgr_focus_destroy_node(const _mm_sound_mgr_focus_param_t *param)
647 int ret = MM_ERROR_NONE;
649 focus_node_t *node = NULL;
650 focus_node_t *my_node = NULL;
651 bool need_to_trigger = true;
656 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
658 /* Update list for dead process */
659 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
661 for (list = g_focus_node_list; list != NULL; list = list->next) {
662 node = (focus_node_t *)list->data;
663 if (CHECK_MY_NODE(node, param)) {
664 debug_log("found the node of pid[%d]/handle_id[%d]\n", param->pid, param->handle_id);
669 if (my_node == NULL) {
670 debug_error("could not find any node of pid[%d]/handle_id[%d]/is_for_session[%d]\n", param->pid, param->handle_id, param->is_for_session);
671 ret = MM_ERROR_INVALID_ARGUMENT;
675 /* Check if there's remaining focus for session for the same PID of incomming param */
676 if (my_node->is_for_session) {
677 for (list = g_focus_node_list; list != NULL; list = list->next) {
678 if (!(node = (focus_node_t *)list->data))
680 if (my_node == node || node->is_for_watch)
682 if (node->pid == my_node->pid && node->is_for_session) {
683 debug_error("focus for session for this pid still remains, skip updating victim focus nodes");
684 need_to_trigger = false;
690 if (need_to_trigger) {
691 for (list = g_focus_node_list; list != NULL; list = list->next) {
692 if (!(node = (focus_node_t *)list->data))
694 if (my_node == node || node->is_for_watch)
696 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
697 if (node->taken_by_id[i].pid == param->pid) {
698 if (my_node->taken_by_id[i].pid) {
699 /* If exists update the taken focus info to my victim node */
700 if (node->taken_by_id[i].by_session && !node->status) {
701 UPDATE_FOCUS_TAKEN_INFO(by_id, node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, my_node->taken_by_id[i].by_session);
702 } else if (node->taken_by_id[i].handle_id == param->handle_id) {
703 UPDATE_FOCUS_TAKEN_INFO(by_id, node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, false);
705 } else if (my_node->status & (i+1)) {
706 if (node->is_for_session)
708 _mm_sound_mgr_focus_param_t *new_param = g_malloc0(sizeof(_mm_sound_mgr_focus_param_t));
710 debug_warning("Fail to g_malloc0 for new_param, but keep going\n");
713 new_param->pid = param->pid;
714 new_param->handle_id = param->handle_id;
715 new_param->is_for_session = my_node->is_for_session;
716 new_param->request_type = my_node->status;
717 new_param->option = my_node->option[i];
718 MMSOUND_STRNCPY(new_param->ext_info, my_node->ext_info[i], MM_SOUND_NAME_NUM);
720 if (node->taken_by_id[i].handle_id == new_param->handle_id || node->taken_by_id[i].by_session) {
721 /* do callback for resumption */
722 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, new_param, my_node->stream_type)))
723 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]\n", node, ret);
724 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
725 my_node->status &= ~(new_param->request_type);
726 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)new_param->request_type, FOCUS_COMMAND_RELEASE, my_node, new_param);
737 /* Destroy my node */
738 __clear_focus_pipe(my_node);
739 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
742 _mm_sound_mgr_focus_list_dump();
743 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
749 int mm_sound_mgr_focus_set_reacquisition(const _mm_sound_mgr_focus_param_t *param)
751 int ret = MM_ERROR_NONE;
753 focus_node_t *node = NULL;
754 focus_node_t *my_node = NULL;
759 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
761 /* Update list for dead process */
762 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
764 /* Find node to set reacquisition */
765 for (list = g_focus_node_list; list != NULL; list = list->next) {
766 node = (focus_node_t *)list->data;
767 if (CHECK_MY_NODE(node, param)) {
768 if (node->reacquisition == param->reacquisition) {
769 debug_msg("it is already set as same value of reacquisition(%d)\n", param->reacquisition);
772 node->reacquisition = param->reacquisition;
773 debug_msg("found a node(pid[%d]/handle_id[%d]) to set reacquisition to (%d)\n", node->pid, node->handle_id, param->reacquisition);
778 if (my_node == NULL) {
779 debug_error("could not find any node of pid[%d]/handle_id[%d]\n", param->pid, param->handle_id);
780 ret = MM_ERROR_INVALID_ARGUMENT;
784 if (!param->reacquisition) {
785 for (list = g_focus_node_list; list != NULL; list = list->next) {
786 if (!(node = (focus_node_t *)list->data))
788 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
789 if (node->taken_by_id[i].pid == param->pid) {
790 /* victim node : append my node's taken info to my victim node */
791 if (my_node->taken_by_id[i].pid != 0) {
792 UPDATE_FOCUS_TAKEN_INFO(backup, node, node->taken_by_id[i].pid, node->taken_by_id[i].handle_id, node->taken_by_id[i].by_session);
793 UPDATE_FOCUS_TAKEN_INFO(by_id, node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, my_node->taken_by_id[i].by_session);
795 } else if (!list->next) {
796 /* my node : backup and reset */
797 UPDATE_FOCUS_TAKEN_INFO(backup, my_node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, my_node->taken_by_id[i].by_session);
798 UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, 0, 0, false);
803 for (list = g_focus_node_list; list != NULL; list = list->next) {
804 if (!(node = (focus_node_t *)list->data))
806 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
807 /* rollback and reset backup info. */
808 if (node->taken_by_id[i].pid && (node->taken_by_id[i].pid == my_node->taken_backup[i].pid)) {
809 UPDATE_FOCUS_TAKEN_INFO(by_id, node, node->taken_backup[i].pid, node->taken_backup[i].handle_id, node->taken_backup[i].by_session);
810 UPDATE_FOCUS_TAKEN_INFO(backup, node, 0, 0, false);
811 } else if (!list->next) {
812 UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, my_node->taken_backup[i].pid, my_node->taken_backup[i].handle_id, my_node->taken_backup[i].by_session);
813 UPDATE_FOCUS_TAKEN_INFO(backup, my_node, 0, 0, false);
820 _mm_sound_mgr_focus_list_dump();
821 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
827 int mm_sound_mgr_focus_get_stream_type_of_acquired_focus(focus_type_e focus_type, char **stream_type, int *option, char **ext_info)
829 int ret = MM_ERROR_SOUND_NO_DATA;
831 focus_node_t *node = NULL;
835 if (focus_type == FOCUS_TYPE_BOTH) /* focus_type should be "playback" or "capture" */
836 return MM_ERROR_INVALID_ARGUMENT;
838 return MM_ERROR_INVALID_ARGUMENT;
840 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
842 /* Update list for dead process */
843 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
845 /* Find node to set reacquisition */
846 for (list = g_focus_node_list; list != NULL; list = list->next) {
847 if (!(node = (focus_node_t *)list->data))
849 if (!node->is_for_watch && (node->status & focus_type)) {
850 debug_msg("found a node : request_focus_type(%d), stream_type(%s)/ext info(%s) of acquired focus\n", focus_type, node->stream_type, node->ext_info);
851 *stream_type = node->stream_type;
852 *option = node->option[focus_type-1];
854 *ext_info = node->ext_info[focus_type-1];
860 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
867 int mm_sound_mgr_focus_request_acquire(const _mm_sound_mgr_focus_param_t *param)
869 int ret = MM_ERROR_NONE;
871 focus_node_t *node = NULL;
872 focus_node_t *my_node = NULL;
873 bool need_to_trigger_cb = false;
874 bool need_to_trigger_watch_cb = true;
879 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
881 /* Update list for dead process */
882 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
884 for (list = g_focus_node_list; list != NULL; list = list->next) {
885 node = (focus_node_t *)list->data;
886 if (CHECK_MY_NODE(node, param)) {
888 if ((my_node->status > FOCUS_STATUS_DEACTIVATED) && (my_node->status & param->request_type)) {
889 debug_error("focus status is already activated");
890 ret = MM_ERROR_SOUND_INVALID_STATE;
896 if (my_node == NULL) {
897 debug_error("node is null");
898 ret = MM_ERROR_INVALID_ARGUMENT;
902 /* check if the priority of any node is higher than its based on io direction */
903 for (list = g_focus_node_list; list != NULL; list = list->next) {
904 if (!(node = (focus_node_t *)list->data))
906 if (my_node == node || node->is_for_watch)
908 if (param->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
909 (node->status & param->request_type)) {
910 if (node->status > FOCUS_STATUS_DEACTIVATED) {
911 if ((my_node->priority < node->priority)) {
912 ret = MM_ERROR_POLICY_BLOCKED;
913 need_to_trigger_cb = false;
916 need_to_trigger_cb = true;
922 if (need_to_trigger_cb) {
923 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
924 param_s->is_for_session = my_node->is_for_session;
925 for (list = g_focus_node_list; list != NULL; list = list->next) {
926 if (!(node = (focus_node_t *)list->data))
928 if (node == my_node || node->is_for_watch || (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session))
930 if (param_s->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
931 (node->status & param_s->request_type)) {
932 if (node->status > FOCUS_STATUS_DEACTIVATED) {
933 if (my_node->priority >= node->priority) {
934 /* do callback for interruption */
935 ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_RELEASE, node, param_s, my_node->stream_type);
937 debug_error("Fail to _focus_do_callback for COMMAND RELEASE to node[%x], ret[0x%x]\n", node, ret);
938 /* but, keep going */
941 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
942 need_to_trigger_watch_cb = false;
950 if (ret != MM_ERROR_POLICY_BLOCKED) {
952 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
953 if (param->request_type & (i+1)) {
954 MMSOUND_STRNCPY(my_node->ext_info[i], param->ext_info, MM_SOUND_NAME_NUM);
955 my_node->option[i] = param->option;
959 my_node->status |= param->request_type;
960 /* do watch callback due to the status of mine */
961 if (need_to_trigger_watch_cb)
962 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_ACQUIRE, my_node, param);
963 /* update taken information */
964 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
965 if (param->request_type & (i+1)) {
966 UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, 0, 0, false);
967 UPDATE_FOCUS_TAKEN_INFO(backup, my_node, 0, 0, false);
972 _mm_sound_mgr_focus_list_dump();
973 _mm_sound_mgr_focus_watch_list_dump ();
975 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
981 int mm_sound_mgr_focus_request_release(const _mm_sound_mgr_focus_param_t *param)
983 int ret = MM_ERROR_NONE;
985 focus_node_t *node = NULL;
986 focus_node_t *my_node = NULL;
987 bool need_to_trigger_watch_cb = true;
988 bool need_to_trigger_cb = true;
993 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
995 /* Update list for dead process */
996 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
998 for (list = g_focus_node_list; list != NULL; list = list->next) {
999 node = (focus_node_t *)list->data;
1000 if (CHECK_MY_NODE(node, param)) {
1002 if (my_node->status == FOCUS_STATUS_DEACTIVATED) {
1003 debug_error("focus status is already deactivated");
1004 ret = MM_ERROR_SOUND_INVALID_STATE;
1006 } else if ((my_node->status != FOCUS_STATUS_ACTIVATED_BOTH) && (my_node->status != (focus_status_e)param->request_type)) {
1007 debug_error("request type is not matched with current focus type");
1008 ret = MM_ERROR_SOUND_INVALID_STATE;
1015 if (my_node == NULL) {
1016 debug_error("node is null");
1017 ret = MM_ERROR_INVALID_ARGUMENT;
1021 /* Check if there's activating focus for session for the same PID of incomming param*/
1022 if (my_node->is_for_session) {
1023 for (list = g_focus_node_list; list != NULL; list = list->next) {
1024 if (!(node = (focus_node_t *)list->data))
1026 if (node == my_node || node->is_for_watch)
1028 if (node->pid == my_node->pid && node->is_for_session && my_node->status & node->status) {
1029 debug_error("focus for session for this pid is active, skip callbacks");
1030 need_to_trigger_watch_cb = false;
1031 need_to_trigger_cb = false;
1037 if (need_to_trigger_cb) {
1038 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
1039 param_s->is_for_session = my_node->is_for_session;
1040 for (list = g_focus_node_list; list != NULL; list = list->next) {
1041 if (!(node = (focus_node_t *)list->data))
1043 if (node == my_node || node->is_for_watch)
1045 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1046 if (param_s->request_type & (i+1)) {
1047 if (node->taken_by_id[i].pid == param_s->pid && (node->taken_by_id[i].handle_id == param_s->handle_id || node->taken_by_id[i].by_session)) {
1048 /* do callback for resumption */
1049 ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, param_s, my_node->stream_type);
1051 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]\n", node, ret);
1053 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
1054 need_to_trigger_watch_cb = false;
1062 my_node->status &= ~(param->request_type);
1063 /* remove ext info. */
1064 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1065 if (!(my_node->status & (i+1))) {
1066 memset(my_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
1067 my_node->option[i] = 0;
1070 /* do watch callback due to the status of mine */
1071 if (need_to_trigger_watch_cb)
1072 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_RELEASE, my_node, param);
1074 _mm_sound_mgr_focus_list_dump();
1075 _mm_sound_mgr_focus_watch_list_dump ();
1077 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1083 int mm_sound_mgr_focus_set_watch_cb(const _mm_sound_mgr_focus_param_t *param)
1085 int ret = MM_ERROR_NONE;
1087 focus_node_t *node = NULL;
1091 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1093 /* Update list for dead process */
1094 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1096 for (list = g_focus_node_list; list != NULL; list = list->next) {
1097 if (!(node = (focus_node_t *)list->data))
1099 if ((node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1100 debug_error("the node of pid[%d]/handle_id[%d] for watch focus is already created\n", param->pid, param->handle_id);
1101 ret = MM_ERROR_INVALID_ARGUMENT;
1106 node = g_malloc0(sizeof(focus_node_t));
1108 /* fill up information to the node */
1109 _mm_sound_mgr_focus_fill_info_from_msg(node, param);
1110 node->is_for_watch = true;
1111 node->status = param->request_type;
1113 g_focus_node_list = g_list_append(g_focus_node_list, node);
1114 if (g_focus_node_list) {
1115 debug_log("new focus node is added\n");
1117 debug_error("g_list_append failed\n");
1118 ret = MM_ERROR_SOUND_INTERNAL;
1122 _mm_sound_mgr_focus_watch_list_dump();
1124 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1130 int mm_sound_mgr_focus_unset_watch_cb(const _mm_sound_mgr_focus_param_t *param)
1132 int ret = MM_ERROR_SOUND_INTERNAL;
1134 focus_node_t *node = NULL;
1138 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1140 /* Update list for dead process */
1141 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1143 for (list = g_focus_node_list; list != NULL; list = list->next) {
1144 if (!(node = (focus_node_t *)list->data))
1146 if ((node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1147 debug_log("found the node of pid[%d]/handle_id[%d] for watch focus\n", param->pid, param->handle_id);
1148 __clear_focus_pipe(node);
1149 g_focus_node_list = g_list_remove(g_focus_node_list, node);
1151 ret = MM_ERROR_NONE;
1156 debug_error("could not find any node of pid[%d]/handle_id[%d] for watch focus\n", param->pid, param->handle_id);
1157 ret = MM_ERROR_INVALID_ARGUMENT;
1161 _mm_sound_mgr_focus_watch_list_dump();
1163 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1169 int mm_sound_mgr_focus_emergent_exit(const _mm_sound_mgr_focus_param_t *param)
1171 int ret = MM_ERROR_NONE;
1173 GList *list_s =NULL;
1174 focus_node_t *node = NULL;
1175 focus_node_t *my_node = NULL;
1180 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1182 /* Update list for dead process */
1183 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1185 list = g_focus_node_list;
1187 if (!(node = (focus_node_t *)list->data))
1189 if (node->pid == param->pid) {
1190 debug_log("found pid node");
1191 if (node->is_for_watch) {
1192 debug_log("clearing watch cb of pid(%d) handle(%d)", node->pid, node->handle_id);
1193 __clear_focus_pipe(node);
1194 g_focus_node_list = g_list_remove(g_focus_node_list, node);
1195 list = g_focus_node_list;
1197 } else if (node->status == FOCUS_STATUS_DEACTIVATED) {
1198 debug_log("clearing deactivated focus node of pid(%d) hande(%d)", node->pid, node->handle_id);
1200 /* update info of nodes that are lost their focus by the process exited */
1201 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1202 if (!(node = (focus_node_t *)list_s->data))
1204 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1205 if (node->taken_by_id[i].pid == param->pid) {
1206 if (my_node->taken_by_id[i].pid) {
1207 UPDATE_FOCUS_TAKEN_INFO(by_id, node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, my_node->taken_by_id[i].by_session);
1209 UPDATE_FOCUS_TAKEN_INFO(by_id, node, 0, 0, false);
1214 __clear_focus_pipe(my_node);
1215 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1216 list = g_focus_node_list;
1218 } else { /* node that acquired focus */
1219 bool need_to_trigger_watch_cb = true;
1220 _mm_sound_mgr_focus_param_t param_s;
1221 debug_log("clearing activated focus node of pid(%d) handle(%d)", node->pid, node->handle_id);
1224 memset(¶m_s, 0x00, sizeof(_mm_sound_mgr_focus_param_t));
1225 param_s.pid = my_node->pid;
1226 param_s.handle_id = my_node->handle_id;
1227 param_s.request_type = my_node->status;
1228 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1229 if (!(node = (focus_node_t *)list_s->data))
1231 if (my_node->pid == node->pid || node->is_for_watch)
1233 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1234 if (my_node->status & (i+1)) {
1235 if (node->taken_by_id[i].pid == param_s.pid && node->taken_by_id[i].handle_id == param_s.handle_id) {
1236 /* do callback for resumption */
1237 ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, ¶m_s, my_node->stream_type);
1239 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]\n", node, ret);
1241 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
1242 need_to_trigger_watch_cb = false;
1248 if (need_to_trigger_watch_cb) {
1249 ret = _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param_s.request_type, FOCUS_COMMAND_RELEASE, my_node, ¶m_s);
1251 debug_error("Fail to _focus_do_watch_callback, ret[0x%x]\n", ret);
1254 __clear_focus_pipe(my_node);
1255 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1256 list = g_focus_node_list;
1260 debug_log("node not found, next list = %p",list);
1264 _mm_sound_mgr_focus_list_dump();
1265 _mm_sound_mgr_focus_watch_list_dump ();
1267 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1274 int MMSoundMgrFocusInit(void)
1276 int ret = MM_ERROR_NONE;
1279 ret = __mm_sound_mgr_focus_dbus_get_stream_list(&g_stream_list);
1281 debug_error("failed to __mm_sound_mgr_ipc_dbus_get_stream_list()\n");
1287 int MMSoundMgrFocusFini(void)
1292 for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
1293 if (g_stream_list.stream_types[i]) {
1294 free(g_stream_list.stream_types[i]);
1299 return MM_ERROR_NONE;