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", 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 CONTINUE_IF_LIST_DATA_IS_NULL(x_node, x_list) \
78 if (!((x_node) = (focus_node_t *)(x_list)->data)) \
81 #define CONTINUE_IF_NOT_MY_FOCUS_NODE(x_node, x_param) \
82 if ((x_node)->is_for_watch || ((x_node)->pid != (x_param)->pid) || ((x_node)->handle_id != (x_param)->handle_id) || \
83 ((x_node)->is_for_session != (x_param)->is_for_session)) \
86 static char* __get_focus_pipe_path(int instance_id, int handle, const char* postfix, bool is_watch)
92 path = g_strdup_printf("/tmp/FOCUS.%d.%d.wch", instance_id, handle);
94 path = g_strdup_printf("/tmp/FOCUS.%d.%d", instance_id, handle);
98 path2 = g_strconcat(path, postfix, NULL);
107 static void __clear_focus_pipe(focus_node_t *node)
109 char *filename = NULL;
110 char *filename2 = NULL;
114 if (!node->is_for_watch) {
115 filename = __get_focus_pipe_path(node->pid, node->handle_id, NULL, false);
116 filename2 = __get_focus_pipe_path(node->pid, node->handle_id, "r", false);
118 filename = __get_focus_pipe_path(node->pid, node->handle_id, NULL, true);
119 filename2 = __get_focus_pipe_path(node->pid, node->handle_id, "r", true);
122 if (remove(filename))
123 debug_error("remove() failure, filename(%s), errno(%d)", filename, errno);
125 debug_log("removed file(%s)", filename);
129 if (remove(filename2))
130 debug_error("remove() failure, filename2(%s), errno(%d)", filename2, errno);
132 debug_log("removed file(%s)", filename2);
139 static void _clear_focus_node_list_func(focus_node_t *node, gpointer user_data)
141 CLEAR_DEAD_NODE_LIST(g_focus_node_list);
144 static int _mm_sound_mgr_focus_get_priority_from_stream_type(int *priority, const char *stream_type)
146 int ret = MM_ERROR_NONE;
151 if (priority == NULL || stream_type == NULL) {
152 ret = MM_ERROR_INVALID_ARGUMENT;
153 debug_error("invalid argument, priority[0x%x], stream_type[%s], ret[0x%x]", priority, stream_type, ret);
155 for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
156 if (g_stream_list.stream_types[i] &&
157 !strncmp(g_stream_list.stream_types[i], stream_type, strlen(stream_type))) {
158 *priority = g_stream_list.priorities[i];
162 if (i == AVAIL_STREAMS_MAX) {
163 ret = MM_ERROR_NOT_SUPPORT_API;
164 debug_error("not supported stream_type[%s], ret[0x%x]", stream_type, ret);
166 debug_log("[%s] has priority of [%d]", stream_type, *priority);
174 static bool _check_session_node_exist(int pid)
177 focus_node_t *node = NULL;
179 for (list = g_focus_node_list; list != NULL; list = list->next) {
180 node = (focus_node_t *)list->data;
181 if (node->pid != pid)
183 if (node->is_for_monitor)
185 if (node->is_for_session)
189 debug_msg("session node for pid[%d] does not exist", pid);
194 static bool _check_session_monitor_node_exist(int pid)
197 focus_node_t *node = NULL;
199 for (list = g_focus_node_list; list != NULL; list = list->next) {
200 node = (focus_node_t *)list->data;
201 if (node->pid != pid)
203 if (node->is_for_watch && node->is_for_session && node->is_for_monitor)
207 debug_msg("session monitor node for pid[%d] does not exist", pid);
212 static void _invoke_watch_callback(focus_node_t *node, const char *stream_type, focus_type_e focus_type, focus_command_e command, const _mm_sound_mgr_focus_param_t *param)
217 char *filename = NULL;
218 char *filename2 = NULL;
224 focus_cb_data cb_data;
226 if (!node || !stream_type) {
227 debug_error("[CB] invalid argument, node[%p], stream_type[%s]", node, stream_type);
231 memset(&cb_data, 0, sizeof(focus_cb_data));
232 cb_data.pid = node->pid;
233 cb_data.handle = node->handle_id;
234 cb_data.type = focus_type & node->status;
235 cb_data.state = (command == FOCUS_COMMAND_ACQUIRE) ? !FOCUS_STATUS_DEACTIVATED : FOCUS_STATUS_DEACTIVATED;
236 MMSOUND_STRNCPY(cb_data.stream_type, stream_type, MAX_STREAM_TYPE_LEN);
237 MMSOUND_STRNCPY(cb_data.ext_info, param->ext_info, MM_SOUND_NAME_NUM);
238 node->during_cb = true;
241 gettimeofday(&time, NULL);
242 starttime = time.tv_sec * 1000000 + time.tv_usec;
244 /**************************************
246 * Open callback cmd pipe
248 **************************************/
249 filename = __get_focus_pipe_path(cb_data.pid, cb_data.handle, NULL, true);
250 if (filename == NULL) {
251 debug_error("[CB] failed to get watch pipe");
254 if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
256 strerror_r(errno, str_error, sizeof(str_error));
257 debug_error("[CB] failed to open watch pipe (%s, err:%s)", filename, str_error);
261 /******************************************
263 * Open callback result pipe
264 * before writing callback cmd to pipe
266 ******************************************/
267 filename2 = __get_focus_pipe_path(cb_data.pid, cb_data.handle, "r", true);
268 if (filename2 == NULL) {
269 debug_error("[RETCB] failed to get watch return pipe");
272 if ((fd_FOCUS_R= open(filename2, O_RDONLY|O_NONBLOCK)) == -1) {
274 strerror_r(errno, str_error, sizeof(str_error));
275 debug_error("[RETCB] failed to open watch return pipe (%s, err:%s)", filename2, str_error);
279 /*******************************************
281 *******************************************/
282 if (write(fd_FOCUS, &cb_data ,sizeof(cb_data)) == -1) {
284 strerror_r(errno, str_error, sizeof(str_error));
285 debug_error("[CB] failed to write (err:%s)", str_error);
289 /*********************************************
291 * Wait callback result msg
293 ********************************************/
297 debug_msg("[RETCB] wait WATCH CALLBACK (client pid=%d, cmd=%d, timeout=%d(ms))", cb_data.pid, command, CALLBACK_TIMEOUT);
298 pret = poll(&pfd, 1, CALLBACK_TIMEOUT);
300 debug_error("[RETCB] poll failed (%d)", pret);
303 if (pfd.revents & POLLIN) {
304 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
306 strerror_r(errno, str_error, sizeof(str_error));
307 debug_error("[RETCB] failed to read (err:%s)", str_error);
312 /* Calculate endtime and display*/
313 gettimeofday(&time, NULL);
314 endtime = time.tv_sec * 1000000 + time.tv_usec;
315 debug_msg("[RETCB] WATCH CALLBACK returned (cbtimelab=%d(ms), client pid=%d, return handle=%d)", ((endtime-starttime)/1000), cb_data.pid, ret);
317 /**************************************
319 * Close callback result pipe
321 **************************************/
323 node->during_cb = false;
331 if (fd_FOCUS != -1) {
335 if (fd_FOCUS_R != -1) {
341 /* session backward compatibility for monitor handle, it is for monitor callback of other nodes */
342 static int _mm_sound_mgr_focus_do_monitor_callback_outer(focus_type_e focus_type, focus_command_e command, focus_node_t *my_node, const _mm_sound_mgr_focus_param_t *param)
345 focus_node_t *node = NULL;
350 debug_error("[CB] my_node is null");
351 return MM_ERROR_INVALID_ARGUMENT;
354 for (list = g_focus_node_list; list != NULL; list = list->next) {
355 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
358 /* do not invoke monitor callback of mine */
359 if (node->pid == my_node->pid)
361 if (!node->is_for_watch || !node->is_for_monitor || !node->is_for_session)
363 if (!(node->status & focus_type))
365 /* check if it meets the condition to trigger monitor callback */
366 if (!_check_session_monitor_node_exist(node->pid))
369 _invoke_watch_callback(node, my_node->stream_type, focus_type, command, param);
374 return MM_ERROR_NONE;
377 static int _mm_sound_mgr_focus_do_monitor_callback(focus_type_e focus_type, focus_command_e command, focus_node_t *my_node, const _mm_sound_mgr_focus_param_t *param)
380 focus_node_t *node = NULL;
385 debug_error("[CB] my_node is null");
386 return MM_ERROR_INVALID_ARGUMENT;
389 for (list = g_focus_node_list; list != NULL; list = list->next) {
390 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
391 if (!node->is_for_watch || !node->is_for_monitor || !node->is_for_session)
393 if (node == my_node || !(node->pid == my_node->pid && my_node->is_for_session))
395 if (!(node->status & focus_type))
397 /* check if it meets the condition to trigger monitor callback */
398 if (!_check_session_node_exist(node->pid))
401 _invoke_watch_callback(node, param->stream_type, focus_type, command, param);
406 return MM_ERROR_NONE;
409 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)
412 focus_node_t *node = NULL;
417 debug_error("[CB] my_node is null");
418 return MM_ERROR_INVALID_ARGUMENT;
421 for (list = g_focus_node_list; list != NULL; list = list->next) {
422 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
423 if (node == my_node || (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session))
425 if (!node->is_for_watch || !(node->status & focus_type))
427 if (node->is_for_monitor)
429 if (node->during_cb) {
430 debug_msg("it is about to invoke watch callback again during processing it, skip it");
434 _invoke_watch_callback(node, my_node->stream_type, focus_type, command, param);
439 return MM_ERROR_NONE;
442 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)
444 int res = MM_ERROR_NONE;
445 char *filename = NULL;
446 char *filename2 = NULL;
456 int flag_for_focus_type = 0;
457 int flag_for_taken_index = 0;
461 bool taken_by_session = false;
462 bool reacquisition_changed = false;
464 focus_cb_data cb_data;
466 debug_msg("for pid(%d) handle(%d)", victim_node->pid, victim_node->handle_id);
468 memset(&cb_data, 0, sizeof(focus_cb_data));
469 cb_data.pid= victim_node->pid;
470 cb_data.handle= victim_node->handle_id;
471 if (command == FOCUS_COMMAND_RELEASE) {
472 /* client will lost the acquired focus */
473 cb_data.type= assaulter_param->request_type & victim_node->status;
474 cb_data.state= FOCUS_STATUS_DEACTIVATED;
475 /* remove ext info. */
476 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
477 if (cb_data.type & (i+1)) {
478 memset(victim_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
479 victim_node->option[i] = 0;
483 /* client will gain the lost focus */
484 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
485 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)) {
486 flag_for_focus_type |= i+1; /* playback:1, capture:2 */
489 cb_data.type = flag_for_focus_type & assaulter_param->request_type;
490 cb_data.state = !FOCUS_STATUS_DEACTIVATED;
492 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
493 if (cb_data.type & (i+1)) {
494 MMSOUND_STRNCPY(victim_node->ext_info[i], assaulter_param->ext_info, MM_SOUND_NAME_NUM);
495 victim_node->option[i] = assaulter_param->option;
499 MMSOUND_STRNCPY(cb_data.stream_type, assaulter_param->stream_type, MAX_STREAM_TYPE_LEN);
500 MMSOUND_STRNCPY(cb_data.ext_info, assaulter_param->ext_info, MM_SOUND_NAME_NUM);
501 cb_data.option = assaulter_param->option;
504 gettimeofday(&time, NULL);
505 starttime = time.tv_sec * 1000000 + time.tv_usec;
507 /**************************************
509 * Open callback cmd pipe
511 **************************************/
512 filename = __get_focus_pipe_path(cb_data.pid, cb_data.handle, NULL, false);
513 if (filename == NULL) {
514 debug_error("[CB] failed to get pipe");
518 if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
520 strerror_r(errno, str_error, sizeof(str_error));
521 debug_error("[CB] failed to open pipe (%s, err:%s)", filename, str_error);
526 /******************************************
528 * Open callback result pipe
529 * before writing callback cmd to pipe
531 ******************************************/
532 filename2 = __get_focus_pipe_path(cb_data.pid, cb_data.handle, "r", false);
533 if (filename2 == NULL) {
534 debug_error("[RETCB] failed to get return pipe");
538 if ((fd_FOCUS_R = open(filename2,O_RDONLY|O_NONBLOCK)) == -1) {
540 strerror_r(errno, str_error, sizeof(str_error));
541 debug_error("[RETCB] failed to open return pipe (%s, err:%s)", filename2, str_error);
546 /*******************************************
548 *******************************************/
549 if (write(fd_FOCUS, &cb_data, sizeof(cb_data)) == -1) {
551 strerror_r(errno, str_error, sizeof(str_error));
552 debug_error("[CB] failed to write (err:%s)", str_error);
557 /*********************************************
559 * Wait callback result msg
561 ********************************************/
565 debug_msg("[RETCB] wait CALLBACK (client pid=%d, handle=%d, cmd=%d, timeout=%d(ms))",cb_data.pid, cb_data.handle, command, CALLBACK_TIMEOUT);
566 pret = poll(&pfd, 1, CALLBACK_TIMEOUT);
568 debug_error("[RETCB] poll failed (%d)", pret);
572 if (pfd.revents & POLLIN) {
573 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
575 strerror_r(errno, str_error, sizeof(str_error));
576 debug_error("[RETCB] failed to read (err:%s)", str_error);
580 /* ret contains data as below,
581 * |<--12bits--><--4bits (reacquisition)--><--16bits (handle)-->| */
582 ret_handle = (int)(ret & 0x0000ffff);
583 if (victim_node->reacquisition != (bool)((ret >> 16) & 0xf)) {
584 reacquisition_changed = true;
585 victim_node->reacquisition = (bool)((ret >> 16) & 0xf);
586 debug_msg("[RETCB] victim's reacquisition is changed to (%d)", victim_node->reacquisition);
590 /* Calculate endtime and display*/
591 gettimeofday(&time, NULL);
592 endtime = time.tv_sec * 1000000 + time.tv_usec;
593 debug_msg("[RETCB] CALLBACK returned (cbtimelab=%d(ms), client pid=%d, returned handle=%d)", ((endtime-starttime)/1000), cb_data.pid, ret_handle);
595 /* update victim node */
596 if (command == FOCUS_COMMAND_RELEASE) {
597 taken_pid = assaulter_param->pid;
598 taken_hid = assaulter_param->handle_id;
599 taken_by_session = assaulter_param->is_for_session;
600 flag_for_taken_index = assaulter_param->request_type & victim_node->status;
604 taken_by_session = false;
605 flag_for_taken_index = assaulter_param->request_type;
608 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
609 if (flag_for_taken_index & (i+1)) {
611 focus_node_t *node = NULL;
613 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)))) {
615 debug_error("skip updating victim node");
618 if (reacquisition_changed) {
619 if (!victim_node->reacquisition) {
620 for (list = g_focus_node_list; list != NULL; list = list->next) {
621 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
622 if (node->taken_by_id[i].pid == victim_node->pid) {
623 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);
624 UPDATE_FOCUS_TAKEN_INFO(by_id, node, taken_pid, taken_hid, taken_by_session);
625 } else if (!list->next) {
626 UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, taken_pid, taken_hid, taken_by_session);
627 UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, 0, 0, false);
631 for (list = g_focus_node_list; list != NULL; list = list->next) {
632 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
633 if (node->taken_backup[i].pid == victim_node->pid) {
634 UPDATE_FOCUS_TAKEN_INFO(by_id, node, node->taken_backup[i].pid, node->taken_backup[i].handle_id, node->taken_backup[i].by_session);
635 UPDATE_FOCUS_TAKEN_INFO(backup, node, 0, 0, false);
636 } else if (!list->next) {
637 UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, taken_pid, taken_hid, taken_by_session);
638 UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, 0, 0, false);
643 if (victim_node->reacquisition)
644 UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, taken_pid, taken_hid, taken_by_session);
646 UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, taken_pid, taken_hid, taken_by_session);
651 if (command == FOCUS_COMMAND_RELEASE || victim_node->reacquisition_with_released_state)
652 victim_node->status = victim_node->status & ~(cb_data.type);
653 else if (command == FOCUS_COMMAND_ACQUIRE)
654 victim_node->status = victim_node->status | cb_data.type;
656 if (strncmp(assaulter_param->stream_type, victim_node->stream_type, MAX_STREAM_TYPE_LEN))
657 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)assaulter_param->request_type, command, victim_node, assaulter_param);
658 _mm_sound_mgr_focus_do_monitor_callback((focus_type_e)assaulter_param->request_type, command, victim_node, assaulter_param);
667 if (fd_FOCUS != -1) {
671 if (fd_FOCUS_R != -1) {
679 static int _mm_sound_mgr_focus_list_dump ()
681 int ret = MM_ERROR_NONE;
683 focus_node_t *node = NULL;
685 debug_msg("================================================ focus node list : start ===================================================");
686 for (list = g_focus_node_list; list != NULL; list = list->next) {
687 if ((node = (focus_node_t *)list->data) && !node->is_for_watch) {
688 debug_msg("*** 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]",
689 node->pid, node->handle_id, node->stream_type, node->priority, focus_status_str[node->status],
690 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,
691 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]);
694 debug_msg("================================================ focus node list : end =====================================================");
699 static int _mm_sound_mgr_focus_watch_list_dump()
701 int ret = MM_ERROR_NONE;
703 focus_node_t *node = NULL;
705 debug_msg("============================================= focus watch node list : start =================================================");
706 for (list = g_focus_node_list; list != NULL; list = list->next) {
707 if ((node = (focus_node_t *)list->data) && node->is_for_watch)
708 debug_msg("*** pid[%5d]/handle_id[%d]/watch on focus status[%s]/for_session[%d]/for_monitor[%d]",
709 node->pid, node->handle_id, focus_status_str[node->status], node->is_for_session, node->is_for_monitor);
711 debug_msg("============================================= focus watch node list : end ===================================================");
716 static void _mm_sound_mgr_focus_fill_info_from_msg(focus_node_t *node, const _mm_sound_mgr_focus_param_t *msg)
719 node->pid = msg->pid;
720 node->handle_id = msg->handle_id;
721 node->callback = msg->callback;
722 node->cbdata = msg->cbdata;
723 node->is_for_session = msg->is_for_session;
729 int mm_sound_mgr_focus_create_node(const _mm_sound_mgr_focus_param_t *param)
731 int ret = MM_ERROR_NONE;
733 focus_node_t *node = NULL;
738 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
740 /* Update list for dead process */
741 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
743 for (list = g_focus_node_list; list != NULL; list = list->next) {
744 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
745 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
747 debug_error("the node of pid[%d]/handle_id[%d] is already created", param->pid, param->handle_id);
748 ret = MM_ERROR_INVALID_ARGUMENT;
752 /* get priority from stream type */
753 ret = _mm_sound_mgr_focus_get_priority_from_stream_type(&priority, param->stream_type);
757 node = g_malloc0(sizeof(focus_node_t));
759 /* fill up information to the node */
760 _mm_sound_mgr_focus_fill_info_from_msg(node, param);
761 node->priority = priority;
762 node->status = FOCUS_STATUS_DEACTIVATED;
763 node->reacquisition = true;
764 MMSOUND_STRNCPY(node->stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
766 g_focus_node_list = g_list_append(g_focus_node_list, node);
767 if (g_focus_node_list) {
768 debug_log("new focus node is added");
770 debug_error("g_list_append failed");
771 ret = MM_ERROR_SOUND_INTERNAL;
775 _mm_sound_mgr_focus_list_dump();
777 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
783 int mm_sound_mgr_focus_destroy_node(const _mm_sound_mgr_focus_param_t *param)
785 int ret = MM_ERROR_NONE;
787 focus_node_t *node = NULL;
788 focus_node_t *my_node = NULL;
789 bool need_to_trigger = true;
794 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
796 /* Update list for dead process */
797 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
799 for (list = g_focus_node_list; list != NULL; list = list->next) {
800 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
801 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
803 debug_log("found the node of pid[%d]/handle_id[%d]", param->pid, param->handle_id);
807 if (my_node == NULL) {
808 debug_error("could not find any node of pid[%d]/handle_id[%d]/is_for_session[%d]", param->pid, param->handle_id, param->is_for_session);
809 ret = MM_ERROR_INVALID_ARGUMENT;
813 /* Check if there's remaining focus for session for the same PID of incomming param */
814 if (my_node->is_for_session) {
815 for (list = g_focus_node_list; list != NULL; list = list->next) {
816 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
817 if (my_node == node || node->is_for_watch)
819 if (node->pid == my_node->pid && node->is_for_session && node->status) {
820 debug_warning("another focus node for session of this pid exists, skip invoking callback");
821 need_to_trigger = false;
827 if (need_to_trigger) {
828 bool need_to_trigger_watch_cb = true;
829 _mm_sound_mgr_focus_param_t *new_param = NULL;
831 if (!(new_param = g_malloc0(sizeof(_mm_sound_mgr_focus_param_t)))) {
832 debug_error("Fail to g_malloc0 for new_param");
835 new_param->pid = param->pid;
836 new_param->handle_id = param->handle_id;
837 new_param->is_for_session = my_node->is_for_session;
838 new_param->request_type = my_node->status;
839 new_param->option = my_node->option[i];
840 MMSOUND_STRNCPY(new_param->stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
841 MMSOUND_STRNCPY(new_param->ext_info, my_node->ext_info[i], MM_SOUND_NAME_NUM);
843 for (list = g_focus_node_list; list != NULL; list = list->next) {
844 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
845 if (my_node == node || node->is_for_watch)
847 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
848 if (node->taken_by_id[i].pid != param->pid)
851 if (my_node->taken_by_id[i].pid) {
852 /* If exists update the taken focus info to my victim node */
853 if (node->taken_by_id[i].by_session && !node->status) {
854 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);
855 } else if (node->taken_by_id[i].handle_id == param->handle_id) {
856 UPDATE_FOCUS_TAKEN_INFO(by_id, node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, false);
858 } else if (my_node->status & (i+1)) {
859 if (node->is_for_session)
861 if (node->taken_by_id[i].handle_id == new_param->handle_id || node->taken_by_id[i].by_session) {
862 /* do callback for resumption */
863 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, new_param)))
864 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]", node, ret);
865 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
866 need_to_trigger_watch_cb = false;
867 my_node->status &= ~(new_param->request_type);
873 if (need_to_trigger_watch_cb)
874 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)new_param->request_type, FOCUS_COMMAND_RELEASE, my_node, new_param);
880 /* Destroy my node */
881 __clear_focus_pipe(my_node);
882 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
885 _mm_sound_mgr_focus_list_dump();
886 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
892 int mm_sound_mgr_focus_set_reacquisition(const _mm_sound_mgr_focus_param_t *param)
894 int ret = MM_ERROR_NONE;
896 focus_node_t *node = NULL;
897 focus_node_t *my_node = NULL;
902 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
904 /* Update list for dead process */
905 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
907 /* Find node to set reacquisition */
908 for (list = g_focus_node_list; list != NULL; list = list->next) {
909 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
910 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
912 if (node->reacquisition == param->reacquisition) {
913 debug_msg("it is already set as same value of reacquisition(%d)", param->reacquisition);
916 node->reacquisition = param->reacquisition;
917 debug_msg("found a node(pid[%d]/handle_id[%d]) to set reacquisition to (%d)", node->pid, node->handle_id, param->reacquisition);
921 if (my_node == NULL) {
922 debug_error("could not find any node of pid[%d]/handle_id[%d]", param->pid, param->handle_id);
923 ret = MM_ERROR_INVALID_ARGUMENT;
927 if (!param->reacquisition) {
928 for (list = g_focus_node_list; list != NULL; list = list->next) {
929 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
930 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
931 if (node->taken_by_id[i].pid == param->pid) {
932 /* victim node : append my node's taken info to my victim node */
933 if (my_node->taken_by_id[i].pid != 0) {
934 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);
935 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);
937 } else if (!list->next) {
938 /* my node : backup and reset */
939 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);
940 UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, 0, 0, false);
945 for (list = g_focus_node_list; list != NULL; list = list->next) {
946 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
947 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
948 /* rollback and reset backup info. */
949 if (node->taken_by_id[i].pid && (node->taken_by_id[i].pid == my_node->taken_backup[i].pid)) {
950 UPDATE_FOCUS_TAKEN_INFO(by_id, node, node->taken_backup[i].pid, node->taken_backup[i].handle_id, node->taken_backup[i].by_session);
951 UPDATE_FOCUS_TAKEN_INFO(backup, node, 0, 0, false);
952 } else if (!list->next) {
953 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);
954 UPDATE_FOCUS_TAKEN_INFO(backup, my_node, 0, 0, false);
961 _mm_sound_mgr_focus_list_dump();
962 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
968 int mm_sound_mgr_focus_get_stream_type_of_acquired_focus(focus_type_e focus_type, char **stream_type, int *option, char **ext_info)
970 int ret = MM_ERROR_SOUND_NO_DATA;
972 focus_node_t *node = NULL;
976 if (!stream_type || !option)
977 return MM_ERROR_INVALID_ARGUMENT;
979 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
981 /* Update list for dead process */
982 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
984 /* Find node to set reacquisition */
985 for (list = g_focus_node_list; list != NULL; list = list->next) {
986 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
987 if (!node->is_for_watch && (node->status & focus_type)) {
988 /* In case of FOCUS_TYPE_BOTH, we use index for FOCUS_TYPE_PLAYBACK's forcedly.
989 * It is because this function can not return both index of option, ext_info results
990 * via out-parameter. This case is only used in framework internally for session
991 * backward compatibilty. */
992 int index = (focus_type == FOCUS_TYPE_BOTH) ? FOCUS_TYPE_PLAYBACK - 1 : focus_type - 1;
994 debug_msg("found a node : request_focus_type(%d), stream_type(%s)/ext info(%s) of acquired focus",
995 focus_type, node->stream_type, node->ext_info[index]);
997 *stream_type = node->stream_type;
998 *option = node->option[index];
1000 *ext_info = node->ext_info[index];
1001 ret = MM_ERROR_NONE;
1006 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1013 static void update_reacquisition_with_released_state(focus_node_t *node, int direction)
1016 debug_error("node is null");
1019 if (direction >= NUM_OF_STREAM_IO_TYPE) {
1020 debug_error("invalid direction(%d)", direction);
1024 /* In case of session backward compatibility for audio-io, mm-player, mm-camcorder, we mark a specific flag here.
1025 When invoking focus state changed callback for acquiring, state of the node will not be updated rather updated
1026 when the next request to acquire. */
1027 if (!strncmp("audio-io acquire focus", node->ext_info[direction], MM_SOUND_NAME_NUM) ||
1028 !strncmp("mm-player acquire focus", node->ext_info[direction], MM_SOUND_NAME_NUM) ||
1029 !strncmp("mm-camcorder acquire focus", node->ext_info[direction], MM_SOUND_NAME_NUM)) {
1030 debug_msg("this node[pid:%d, handle_id:%d] needs reacquisition with focus released state", node->pid, node->handle_id);
1031 node->reacquisition_with_released_state = true;
1035 int mm_sound_mgr_focus_request_acquire(const _mm_sound_mgr_focus_param_t *param)
1037 int ret = MM_ERROR_NONE;
1039 focus_node_t *node = NULL;
1040 focus_node_t *my_node = NULL;
1041 bool need_to_trigger_cb = false;
1042 bool need_to_trigger_watch_cb = true;
1043 bool need_to_trigger_monitor_cb = true;
1048 if (!param->is_in_thread)
1049 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1051 /* Update list for dead process */
1052 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1054 for (list = g_focus_node_list; list != NULL; list = list->next) {
1055 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1056 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
1059 if ((my_node->status > FOCUS_STATUS_DEACTIVATED) && (my_node->status & param->request_type)) {
1060 debug_error("focus status is already activated");
1061 ret = MM_ERROR_SOUND_INVALID_STATE;
1066 if (my_node == NULL) {
1067 debug_error("node is null");
1068 ret = MM_ERROR_INVALID_ARGUMENT;
1072 /* check if the priority of any node is higher than its based on io direction */
1073 for (list = g_focus_node_list; list != NULL; list = list->next) {
1074 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1075 if (my_node == node || node->is_for_watch)
1077 if (param->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
1078 (node->status & param->request_type)) {
1079 if (node->status <= FOCUS_STATUS_DEACTIVATED)
1082 if ((my_node->priority < node->priority)) {
1083 ret = MM_ERROR_POLICY_BLOCKED;
1084 need_to_trigger_cb = false;
1087 need_to_trigger_cb = true;
1092 if (need_to_trigger_cb) {
1093 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
1094 param_s->is_for_session = my_node->is_for_session;
1095 MMSOUND_STRNCPY(param_s->stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
1096 for (list = g_focus_node_list; list != NULL; list = list->next) {
1097 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1098 if (node == my_node || node->is_for_watch)
1100 if (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session)
1102 if (param_s->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
1103 (node->status & param_s->request_type)) {
1104 if (node->status <= FOCUS_STATUS_DEACTIVATED)
1106 if (my_node->priority >= node->priority) {
1107 /* do callback for interruption */
1108 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_RELEASE, node, param_s))) {
1109 debug_error("Fail to _focus_do_callback for COMMAND RELEASE to node[%x], ret[0x%x]", node, ret);
1110 /* but, keep going */
1111 ret = MM_ERROR_NONE;
1113 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN))
1114 need_to_trigger_watch_cb = false;
1116 need_to_trigger_monitor_cb = false;
1122 if (ret != MM_ERROR_POLICY_BLOCKED) {
1123 /* copy ext info. */
1124 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1125 if (param->request_type & (i+1)) {
1126 MMSOUND_STRNCPY(my_node->ext_info[i], param->ext_info, MM_SOUND_NAME_NUM);
1127 my_node->option[i] = param->option;
1128 update_reacquisition_with_released_state(my_node, i);
1132 my_node->status |= param->request_type;
1133 /* do watch callback due to the status of mine */
1134 if (need_to_trigger_watch_cb)
1135 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_ACQUIRE, my_node, param);
1136 if (need_to_trigger_monitor_cb)
1137 _mm_sound_mgr_focus_do_monitor_callback_outer((focus_type_e)param->request_type, FOCUS_COMMAND_RELEASE, my_node, param);
1139 /* update taken information */
1140 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1141 if (param->request_type & (i+1)) {
1142 UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, 0, 0, false);
1143 UPDATE_FOCUS_TAKEN_INFO(backup, my_node, 0, 0, false);
1148 _mm_sound_mgr_focus_list_dump();
1149 _mm_sound_mgr_focus_watch_list_dump ();
1151 if (!param->is_in_thread)
1152 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1158 int mm_sound_mgr_focus_request_release(const _mm_sound_mgr_focus_param_t *param)
1160 int ret = MM_ERROR_NONE;
1162 focus_node_t *node = NULL;
1163 focus_node_t *my_node = NULL;
1164 bool need_to_trigger_watch_cb = true;
1165 bool need_to_trigger_monitor_cb = true;
1166 bool need_to_trigger_cb = true;
1171 if (!param->is_in_thread)
1172 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1174 /* Update list for dead process */
1175 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1177 for (list = g_focus_node_list; list != NULL; list = list->next) {
1178 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1179 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
1182 if (my_node->status == FOCUS_STATUS_DEACTIVATED) {
1183 debug_error("focus status is already deactivated");
1184 ret = MM_ERROR_SOUND_INVALID_STATE;
1186 } else if ((my_node->status != FOCUS_STATUS_ACTIVATED_BOTH) && (my_node->status != (focus_status_e)param->request_type)) {
1187 debug_error("request type is not matched with current focus type");
1188 ret = MM_ERROR_SOUND_INVALID_STATE;
1194 if (my_node == NULL) {
1195 debug_error("node is null");
1196 ret = MM_ERROR_INVALID_ARGUMENT;
1200 /* Check if there's activating focus for session for the same PID of incomming param*/
1201 if (my_node->is_for_session) {
1202 for (list = g_focus_node_list; list != NULL; list = list->next) {
1203 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1204 if (node == my_node || node->is_for_watch)
1206 if (node->pid == my_node->pid && node->is_for_session && node->status) {
1207 debug_warning("another focus node for session of this pid exists, skip invoking callback");
1208 need_to_trigger_watch_cb = false;
1209 need_to_trigger_cb = false;
1215 if (need_to_trigger_cb) {
1216 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
1217 param_s->is_for_session = my_node->is_for_session;
1218 MMSOUND_STRNCPY(param_s->stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
1219 for (list = g_focus_node_list; list != NULL; list = list->next) {
1220 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1221 if (node == my_node || node->is_for_watch)
1223 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1224 if (param_s->request_type & (i+1)) {
1225 if (node->taken_by_id[i].pid == param_s->pid &&
1226 (node->taken_by_id[i].handle_id == param_s->handle_id || node->taken_by_id[i].by_session)) {
1227 /* exception case as per the previous session policy,
1228 * "session resumption" is only available for "media session" */
1229 if (my_node->is_for_session && node->is_for_session) {
1230 if (strncmp(node->stream_type, "media", MAX_STREAM_TYPE_LEN))
1233 /* do callback for resumption */
1234 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, param_s)))
1235 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]", node, ret);
1236 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
1237 need_to_trigger_watch_cb = false;
1239 need_to_trigger_monitor_cb = false;
1246 my_node->status &= ~(param->request_type);
1247 /* remove ext info. */
1248 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1249 if (!(my_node->status & (i+1))) {
1250 memset(my_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
1251 my_node->option[i] = 0;
1254 /* do watch callback due to the status of mine */
1255 if (need_to_trigger_watch_cb)
1256 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_RELEASE, my_node, param);
1257 if (need_to_trigger_monitor_cb)
1258 _mm_sound_mgr_focus_do_monitor_callback_outer((focus_type_e)param->request_type, FOCUS_COMMAND_ACQUIRE, my_node, param);
1260 _mm_sound_mgr_focus_list_dump();
1261 _mm_sound_mgr_focus_watch_list_dump ();
1263 if (!param->is_in_thread)
1264 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1270 int mm_sound_mgr_focus_set_watch_cb(const _mm_sound_mgr_focus_param_t *param)
1272 int ret = MM_ERROR_NONE;
1274 focus_node_t *node = NULL;
1278 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1280 /* Update list for dead process */
1281 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1283 for (list = g_focus_node_list; list != NULL; list = list->next) {
1284 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1285 if ((node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1286 debug_error("the node of pid[%d]/handle_id[%d] for watch focus is already created", param->pid, param->handle_id);
1287 ret = MM_ERROR_INVALID_ARGUMENT;
1292 node = g_malloc0(sizeof(focus_node_t));
1294 /* fill up information to the node */
1295 _mm_sound_mgr_focus_fill_info_from_msg(node, param);
1296 node->is_for_watch = true;
1297 node->is_for_monitor = param->is_for_monitor;
1298 node->status = param->request_type;
1300 g_focus_node_list = g_list_append(g_focus_node_list, node);
1301 if (g_focus_node_list) {
1302 debug_log("new focus node is added");
1304 debug_error("g_list_append failed");
1305 ret = MM_ERROR_SOUND_INTERNAL;
1309 _mm_sound_mgr_focus_watch_list_dump();
1311 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1317 int mm_sound_mgr_focus_unset_watch_cb(const _mm_sound_mgr_focus_param_t *param)
1319 int ret = MM_ERROR_SOUND_INTERNAL;
1321 focus_node_t *node = NULL;
1325 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1327 /* Update list for dead process */
1328 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1330 for (list = g_focus_node_list; list != NULL; list = list->next) {
1331 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1332 if ((node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1333 debug_log("found the node of pid[%d]/handle_id[%d] for watch focus", param->pid, param->handle_id);
1334 __clear_focus_pipe(node);
1335 g_focus_node_list = g_list_remove(g_focus_node_list, node);
1337 ret = MM_ERROR_NONE;
1342 debug_error("could not find any node of pid[%d]/handle_id[%d] for watch focus", param->pid, param->handle_id);
1343 ret = MM_ERROR_INVALID_ARGUMENT;
1347 _mm_sound_mgr_focus_watch_list_dump();
1349 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1355 int mm_sound_mgr_focus_deliver(const _mm_sound_mgr_focus_param_t *param)
1357 int ret = MM_ERROR_NONE;
1359 focus_node_t *src_node = NULL;
1360 focus_node_t *dst_node = NULL;
1365 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1367 /* Update list for dead process */
1368 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1370 for (list = g_focus_node_list; list != NULL; list = list->next) {
1371 CONTINUE_IF_LIST_DATA_IS_NULL(src_node, list);
1372 if ((src_node->pid == param->pid) && (src_node->handle_id == param->handle_id)) {
1373 debug_log("SRC: found the node of pid[%d]/handle_id[%d] for watch focus",
1374 param->pid, param->handle_id);
1378 if (src_node == NULL) {
1379 debug_error("could not find the source node of param, pid[%d]/handle_id[%d]",
1380 param->pid, param->handle_id);
1381 ret = MM_ERROR_INVALID_ARGUMENT;
1385 if (!(src_node->status & param->request_type)) {
1386 debug_error("invalid request type(0x%x), src_node->status(0x%x)",
1387 param->request_type, src_node->status);
1388 ret = MM_ERROR_SOUND_INVALID_STATE;
1392 for (list = g_focus_node_list; list != NULL; list = list->next) {
1393 CONTINUE_IF_LIST_DATA_IS_NULL(dst_node, list);
1394 if ((dst_node->pid == param->pid) && (dst_node->handle_id == param->handle_id_dst)) {
1395 debug_log("DST: found the destination node of param, pid[%d]/handle_id[%d]",
1396 param->pid, param->handle_id_dst);
1400 if (dst_node == NULL) {
1401 debug_error("could not find the destination node of param, pid[%d]/handle_id[%d]",
1402 param->pid, param->handle_id_dst);
1403 ret = MM_ERROR_INVALID_ARGUMENT;
1407 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1408 focus_node_t *node = NULL;
1409 if (!(param->request_type & (i+1)))
1412 for (list = g_focus_node_list; list != NULL; list = list->next) {
1413 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1414 if ((node->taken_by_id[i].pid == src_node->pid) &&
1415 (node->taken_by_id[i].handle_id == src_node->handle_id) &&
1416 (node->taken_by_id[i].by_session == false)) {
1417 debug_log("found the node that focus was taken by this src node, update it",
1418 node->pid, node->handle_id);
1419 UPDATE_FOCUS_TAKEN_INFO(by_id, node, dst_node->pid, dst_node->handle_id, false);
1421 if ((node->taken_backup[i].pid == src_node->pid) &&
1422 (node->taken_backup[i].handle_id == src_node->handle_id) &&
1423 (node->taken_backup[i].by_session == false)) {
1424 debug_log("found the node that focus was taken by this src node and set reacquisition to false, update it",
1425 node->pid, node->handle_id);
1426 UPDATE_FOCUS_TAKEN_INFO(backup, node, dst_node->pid, dst_node->handle_id, false);
1430 dst_node->status |= (i+1);
1431 UPDATE_FOCUS_TAKEN_INFO(by_id, dst_node, 0, 0, false);
1432 UPDATE_FOCUS_TAKEN_INFO(backup, dst_node, 0, 0, false);
1433 MMSOUND_STRNCPY(dst_node->ext_info[i], src_node->ext_info[i], MM_SOUND_NAME_NUM);
1434 dst_node->option[i] = src_node->option[i];
1436 src_node->status &= ~(i+1);
1437 memset(src_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
1438 src_node->option[i] = 0;
1441 _mm_sound_mgr_focus_list_dump();
1444 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1450 int mm_sound_mgr_focus_emergent_exit(const _mm_sound_mgr_focus_param_t *param)
1452 int ret = MM_ERROR_NONE;
1454 GList *list_s =NULL;
1455 focus_node_t *node = NULL;
1456 focus_node_t *my_node = NULL;
1461 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1463 /* Update list for dead process */
1464 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1466 list = g_focus_node_list;
1468 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1469 if (node->pid != param->pid) {
1471 debug_log("node not found, next list = %p",list);
1474 if (node->is_for_watch) {
1475 debug_log("clearing watch cb of pid(%d) handle(%d)", node->pid, node->handle_id);
1476 __clear_focus_pipe(node);
1477 g_focus_node_list = g_list_remove(g_focus_node_list, node);
1478 list = g_focus_node_list;
1482 if (node->status == FOCUS_STATUS_DEACTIVATED) {
1483 debug_log("clearing deactivated focus node of pid(%d) hande(%d)", node->pid, node->handle_id);
1485 /* update info of nodes that are lost their focus by the process exited */
1486 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1487 CONTINUE_IF_LIST_DATA_IS_NULL(node, list_s);
1488 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1489 if (node->taken_by_id[i].pid == param->pid) {
1490 if (my_node->taken_by_id[i].pid) {
1491 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);
1493 UPDATE_FOCUS_TAKEN_INFO(by_id, node, 0, 0, false);
1498 __clear_focus_pipe(my_node);
1499 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1500 list = g_focus_node_list;
1502 } else { /* node that acquired focus */
1503 bool need_to_trigger_watch_cb = true;
1504 _mm_sound_mgr_focus_param_t param_s;
1505 debug_log("clearing activated focus node of pid(%d) handle(%d)", node->pid, node->handle_id);
1508 memset(¶m_s, 0x00, sizeof(_mm_sound_mgr_focus_param_t));
1509 param_s.pid = my_node->pid;
1510 param_s.handle_id = my_node->handle_id;
1511 param_s.request_type = my_node->status;
1512 MMSOUND_STRNCPY(param_s.stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
1513 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1514 CONTINUE_IF_LIST_DATA_IS_NULL(node, list_s);
1515 if (my_node->pid == node->pid || node->is_for_watch)
1517 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1518 if (!(my_node->status & (i+1)))
1520 if (node->taken_by_id[i].pid == param_s.pid && node->taken_by_id[i].handle_id == param_s.handle_id) {
1521 /* do callback for resumption */
1522 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, ¶m_s)))
1523 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]", node, ret);
1524 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN))
1525 need_to_trigger_watch_cb = false;
1529 if (need_to_trigger_watch_cb) {
1530 if ((ret = _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param_s.request_type, FOCUS_COMMAND_RELEASE, my_node, ¶m_s)))
1531 debug_error("Fail to _focus_do_watch_callback, ret[0x%x]", ret);
1534 __clear_focus_pipe(my_node);
1535 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1536 list = g_focus_node_list;
1540 _mm_sound_mgr_focus_list_dump();
1541 _mm_sound_mgr_focus_watch_list_dump ();
1543 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1550 int MMSoundMgrFocusInit(void)
1552 int ret = MM_ERROR_NONE;
1555 ret = __mm_sound_mgr_focus_dbus_get_stream_list(&g_stream_list);
1557 debug_error("failed to __mm_sound_mgr_focus_dbus_get_stream_list()");
1563 int MMSoundMgrFocusFini(void)
1568 for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
1569 if (g_stream_list.stream_types[i]) {
1570 free(g_stream_list.stream_types[i]);
1575 return MM_ERROR_NONE;