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_watch_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)
205 if (node->is_for_monitor)
207 if (node->is_for_session)
211 debug_msg("session watch node for pid[%d] does not exist", pid);
216 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)
221 char *filename = NULL;
222 char *filename2 = NULL;
228 focus_cb_data cb_data;
230 if (!node || !stream_type) {
231 debug_error("[CB] invalid argument, node[%p], stream_type[%s]", node, stream_type);
235 memset(&cb_data, 0, sizeof(focus_cb_data));
236 cb_data.pid = node->pid;
237 cb_data.handle = node->handle_id;
238 cb_data.type = focus_type & node->status;
239 cb_data.state = (command == FOCUS_COMMAND_ACQUIRE) ? !FOCUS_STATUS_DEACTIVATED : FOCUS_STATUS_DEACTIVATED;
240 MMSOUND_STRNCPY(cb_data.stream_type, stream_type, MAX_STREAM_TYPE_LEN);
241 MMSOUND_STRNCPY(cb_data.ext_info, param->ext_info, MM_SOUND_NAME_NUM);
242 node->during_cb = true;
245 gettimeofday(&time, NULL);
246 starttime = time.tv_sec * 1000000 + time.tv_usec;
248 /**************************************
250 * Open callback cmd pipe
252 **************************************/
253 filename = __get_focus_pipe_path(cb_data.pid, cb_data.handle, NULL, true);
254 if (filename == NULL) {
255 debug_error("[CB] failed to get watch pipe");
258 if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
260 strerror_r(errno, str_error, sizeof(str_error));
261 debug_error("[CB] failed to open watch pipe (%s, err:%s)", filename, str_error);
265 /******************************************
267 * Open callback result pipe
268 * before writing callback cmd to pipe
270 ******************************************/
271 filename2 = __get_focus_pipe_path(cb_data.pid, cb_data.handle, "r", true);
272 if (filename2 == NULL) {
273 debug_error("[RETCB] failed to get watch return pipe");
276 if ((fd_FOCUS_R= open(filename2, O_RDONLY|O_NONBLOCK)) == -1) {
278 strerror_r(errno, str_error, sizeof(str_error));
279 debug_error("[RETCB] failed to open watch return pipe (%s, err:%s)", filename2, str_error);
283 /*******************************************
285 *******************************************/
286 if (write(fd_FOCUS, &cb_data ,sizeof(cb_data)) == -1) {
288 strerror_r(errno, str_error, sizeof(str_error));
289 debug_error("[CB] failed to write (err:%s)", str_error);
293 /*********************************************
295 * Wait callback result msg
297 ********************************************/
301 debug_msg("[RETCB] wait WATCH CALLBACK (client pid=%d, cmd=%d, timeout=%d(ms))", cb_data.pid, command, CALLBACK_TIMEOUT);
302 pret = poll(&pfd, 1, CALLBACK_TIMEOUT);
304 debug_error("[RETCB] poll failed (%d)", pret);
307 if (pfd.revents & POLLIN) {
308 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
310 strerror_r(errno, str_error, sizeof(str_error));
311 debug_error("[RETCB] failed to read (err:%s)", str_error);
316 /* Calculate endtime and display*/
317 gettimeofday(&time, NULL);
318 endtime = time.tv_sec * 1000000 + time.tv_usec;
319 debug_msg("[RETCB] WATCH CALLBACK returned (cbtimelab=%d(ms), client pid=%d, return handle=%d)", ((endtime-starttime)/1000), cb_data.pid, ret);
321 /**************************************
323 * Close callback result pipe
325 **************************************/
327 node->during_cb = false;
335 if (fd_FOCUS != -1) {
339 if (fd_FOCUS_R != -1) {
345 /* session backward compatibility for monitor handle */
346 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)
349 focus_node_t *node = NULL;
354 debug_error("[CB] my_node is null");
355 return MM_ERROR_INVALID_ARGUMENT;
358 for (list = g_focus_node_list; list != NULL; list = list->next) {
359 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
362 if (!node->is_for_watch || !node->is_for_monitor || !node->is_for_session)
364 if (!(node->status & focus_type))
366 /* check if it meets the condition to trigger monitor callback */
367 if (!_check_session_watch_node_exist(node->pid))
370 _invoke_watch_callback(node, my_node->stream_type, focus_type, command, param);
375 return MM_ERROR_NONE;
378 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)
381 focus_node_t *node = NULL;
386 debug_error("[CB] my_node is null");
387 return MM_ERROR_INVALID_ARGUMENT;
390 for (list = g_focus_node_list; list != NULL; list = list->next) {
391 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
392 if (!node->is_for_watch || !node->is_for_monitor || !node->is_for_session)
394 if (node == my_node || !(node->pid == my_node->pid && my_node->is_for_session))
396 if (!(node->status & focus_type))
398 /* check if it meets the condition to trigger monitor callback */
399 if (!_check_session_node_exist(node->pid))
402 _invoke_watch_callback(node, param->stream_type, focus_type, command, param);
407 return MM_ERROR_NONE;
410 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)
413 focus_node_t *node = NULL;
418 debug_error("[CB] my_node is null");
419 return MM_ERROR_INVALID_ARGUMENT;
422 for (list = g_focus_node_list; list != NULL; list = list->next) {
423 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
424 if (node == my_node || (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session))
426 if (!node->is_for_watch || !(node->status & focus_type))
428 if (node->is_for_monitor)
430 if (node->during_cb) {
431 debug_msg("it is about to invoke watch callback again during processing it, skip it");
435 _invoke_watch_callback(node, my_node->stream_type, focus_type, command, param);
440 return MM_ERROR_NONE;
443 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)
445 int res = MM_ERROR_NONE;
446 char *filename = NULL;
447 char *filename2 = NULL;
457 int flag_for_focus_type = 0;
458 int flag_for_taken_index = 0;
462 bool taken_by_session = false;
463 bool reacquisition_changed = false;
465 focus_cb_data cb_data;
467 debug_msg("for pid(%d) handle(%d)", victim_node->pid, victim_node->handle_id);
469 memset(&cb_data, 0, sizeof(focus_cb_data));
470 cb_data.pid= victim_node->pid;
471 cb_data.handle= victim_node->handle_id;
472 if (command == FOCUS_COMMAND_RELEASE) {
473 /* client will lost the acquired focus */
474 cb_data.type= assaulter_param->request_type & victim_node->status;
475 cb_data.state= FOCUS_STATUS_DEACTIVATED;
476 /* remove ext info. */
477 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
478 if (cb_data.type & (i+1)) {
479 memset(victim_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
480 victim_node->option[i] = 0;
484 /* client will gain the lost focus */
485 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
486 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)) {
487 flag_for_focus_type |= i+1; /* playback:1, capture:2 */
490 cb_data.type = flag_for_focus_type & assaulter_param->request_type;
491 cb_data.state = !FOCUS_STATUS_DEACTIVATED;
493 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
494 if (cb_data.type & (i+1)) {
495 MMSOUND_STRNCPY(victim_node->ext_info[i], assaulter_param->ext_info, MM_SOUND_NAME_NUM);
496 victim_node->option[i] = assaulter_param->option;
500 MMSOUND_STRNCPY(cb_data.stream_type, assaulter_param->stream_type, MAX_STREAM_TYPE_LEN);
501 MMSOUND_STRNCPY(cb_data.ext_info, assaulter_param->ext_info, MM_SOUND_NAME_NUM);
502 cb_data.option = assaulter_param->option;
505 gettimeofday(&time, NULL);
506 starttime = time.tv_sec * 1000000 + time.tv_usec;
508 /**************************************
510 * Open callback cmd pipe
512 **************************************/
513 filename = __get_focus_pipe_path(cb_data.pid, cb_data.handle, NULL, false);
514 if (filename == NULL) {
515 debug_error("[CB] failed to get pipe");
519 if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
521 strerror_r(errno, str_error, sizeof(str_error));
522 debug_error("[CB] failed to open pipe (%s, err:%s)", filename, str_error);
527 /******************************************
529 * Open callback result pipe
530 * before writing callback cmd to pipe
532 ******************************************/
533 filename2 = __get_focus_pipe_path(cb_data.pid, cb_data.handle, "r", false);
534 if (filename2 == NULL) {
535 debug_error("[RETCB] failed to get return pipe");
539 if ((fd_FOCUS_R = open(filename2,O_RDONLY|O_NONBLOCK)) == -1) {
541 strerror_r(errno, str_error, sizeof(str_error));
542 debug_error("[RETCB] failed to open return pipe (%s, err:%s)", filename2, str_error);
547 /*******************************************
549 *******************************************/
550 if (write(fd_FOCUS, &cb_data, sizeof(cb_data)) == -1) {
552 strerror_r(errno, str_error, sizeof(str_error));
553 debug_error("[CB] failed to write (err:%s)", str_error);
558 /*********************************************
560 * Wait callback result msg
562 ********************************************/
566 debug_msg("[RETCB] wait CALLBACK (client pid=%d, handle=%d, cmd=%d, timeout=%d(ms))",cb_data.pid, cb_data.handle, command, CALLBACK_TIMEOUT);
567 pret = poll(&pfd, 1, CALLBACK_TIMEOUT);
569 debug_error("[RETCB] poll failed (%d)", pret);
573 if (pfd.revents & POLLIN) {
574 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
576 strerror_r(errno, str_error, sizeof(str_error));
577 debug_error("[RETCB] failed to read (err:%s)", str_error);
581 /* ret contains data as below,
582 * |<--12bits--><--4bits (reacquisition)--><--16bits (handle)-->| */
583 ret_handle = (int)(ret & 0x0000ffff);
584 if (victim_node->reacquisition != (bool)((ret >> 16) & 0xf)) {
585 reacquisition_changed = true;
586 victim_node->reacquisition = (bool)((ret >> 16) & 0xf);
587 debug_msg("[RETCB] victim's reacquisition is changed to (%d)", victim_node->reacquisition);
591 /* Calculate endtime and display*/
592 gettimeofday(&time, NULL);
593 endtime = time.tv_sec * 1000000 + time.tv_usec;
594 debug_msg("[RETCB] CALLBACK returned (cbtimelab=%d(ms), client pid=%d, returned handle=%d)", ((endtime-starttime)/1000), cb_data.pid, ret_handle);
596 /* update victim node */
597 if (command == FOCUS_COMMAND_RELEASE) {
598 taken_pid = assaulter_param->pid;
599 taken_hid = assaulter_param->handle_id;
600 taken_by_session = assaulter_param->is_for_session;
601 flag_for_taken_index = assaulter_param->request_type & victim_node->status;
605 taken_by_session = false;
606 flag_for_taken_index = assaulter_param->request_type;
609 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
610 if (flag_for_taken_index & (i+1)) {
612 focus_node_t *node = NULL;
614 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)))) {
616 debug_error("skip updating victim node");
619 if (reacquisition_changed) {
620 if (!victim_node->reacquisition) {
621 for (list = g_focus_node_list; list != NULL; list = list->next) {
622 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
623 if (node->taken_by_id[i].pid == victim_node->pid) {
624 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);
625 UPDATE_FOCUS_TAKEN_INFO(by_id, node, taken_pid, taken_hid, taken_by_session);
626 } else if (!list->next) {
627 UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, taken_pid, taken_hid, taken_by_session);
628 UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, 0, 0, false);
632 for (list = g_focus_node_list; list != NULL; list = list->next) {
633 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
634 if (node->taken_backup[i].pid == victim_node->pid) {
635 UPDATE_FOCUS_TAKEN_INFO(by_id, node, node->taken_backup[i].pid, node->taken_backup[i].handle_id, node->taken_backup[i].by_session);
636 UPDATE_FOCUS_TAKEN_INFO(backup, node, 0, 0, false);
637 } else if (!list->next) {
638 UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, taken_pid, taken_hid, taken_by_session);
639 UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, 0, 0, false);
644 if (victim_node->reacquisition)
645 UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, taken_pid, taken_hid, taken_by_session);
647 UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, taken_pid, taken_hid, taken_by_session);
652 if (command == FOCUS_COMMAND_RELEASE || victim_node->reacquisition_with_released_state)
653 victim_node->status = victim_node->status & ~(cb_data.type);
654 else if (command == FOCUS_COMMAND_ACQUIRE)
655 victim_node->status = victim_node->status | cb_data.type;
657 if (strncmp(assaulter_param->stream_type, victim_node->stream_type, MAX_STREAM_TYPE_LEN))
658 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)assaulter_param->request_type, command, victim_node, assaulter_param);
659 _mm_sound_mgr_focus_do_monitor_callback((focus_type_e)assaulter_param->request_type, command, victim_node, assaulter_param);
668 if (fd_FOCUS != -1) {
672 if (fd_FOCUS_R != -1) {
680 static int _mm_sound_mgr_focus_list_dump ()
682 int ret = MM_ERROR_NONE;
684 focus_node_t *node = NULL;
686 debug_msg("================================================ focus node list : start ===================================================");
687 for (list = g_focus_node_list; list != NULL; list = list->next) {
688 if ((node = (focus_node_t *)list->data) && !node->is_for_watch) {
689 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]",
690 node->pid, node->handle_id, node->stream_type, node->priority, focus_status_str[node->status],
691 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,
692 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]);
695 debug_msg("================================================ focus node list : end =====================================================");
700 static int _mm_sound_mgr_focus_watch_list_dump()
702 int ret = MM_ERROR_NONE;
704 focus_node_t *node = NULL;
706 debug_msg("============================================= focus watch node list : start =================================================");
707 for (list = g_focus_node_list; list != NULL; list = list->next) {
708 if ((node = (focus_node_t *)list->data) && node->is_for_watch)
709 debug_msg("*** pid[%5d]/handle_id[%d]/watch on focus status[%s]/for_session[%d]/for_monitor[%d]",
710 node->pid, node->handle_id, focus_status_str[node->status], node->is_for_session, node->is_for_monitor);
712 debug_msg("============================================= focus watch node list : end ===================================================");
717 static void _mm_sound_mgr_focus_fill_info_from_msg(focus_node_t *node, const _mm_sound_mgr_focus_param_t *msg)
720 node->pid = msg->pid;
721 node->handle_id = msg->handle_id;
722 node->callback = msg->callback;
723 node->cbdata = msg->cbdata;
724 node->is_for_session = msg->is_for_session;
730 int mm_sound_mgr_focus_create_node(const _mm_sound_mgr_focus_param_t *param)
732 int ret = MM_ERROR_NONE;
734 focus_node_t *node = NULL;
739 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
741 /* Update list for dead process */
742 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
744 for (list = g_focus_node_list; list != NULL; list = list->next) {
745 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
746 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
748 debug_error("the node of pid[%d]/handle_id[%d] is already created", param->pid, param->handle_id);
749 ret = MM_ERROR_INVALID_ARGUMENT;
753 /* get priority from stream type */
754 ret = _mm_sound_mgr_focus_get_priority_from_stream_type(&priority, param->stream_type);
758 node = g_malloc0(sizeof(focus_node_t));
760 /* fill up information to the node */
761 _mm_sound_mgr_focus_fill_info_from_msg(node, param);
762 node->priority = priority;
763 node->status = FOCUS_STATUS_DEACTIVATED;
764 node->reacquisition = true;
765 MMSOUND_STRNCPY(node->stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
767 g_focus_node_list = g_list_append(g_focus_node_list, node);
768 if (g_focus_node_list) {
769 debug_log("new focus node is added");
771 debug_error("g_list_append failed");
772 ret = MM_ERROR_SOUND_INTERNAL;
776 _mm_sound_mgr_focus_list_dump();
778 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
784 int mm_sound_mgr_focus_destroy_node(const _mm_sound_mgr_focus_param_t *param)
786 int ret = MM_ERROR_NONE;
788 focus_node_t *node = NULL;
789 focus_node_t *my_node = NULL;
790 bool need_to_trigger = true;
795 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
797 /* Update list for dead process */
798 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
800 for (list = g_focus_node_list; list != NULL; list = list->next) {
801 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
802 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
804 debug_log("found the node of pid[%d]/handle_id[%d]", param->pid, param->handle_id);
808 if (my_node == NULL) {
809 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);
810 ret = MM_ERROR_INVALID_ARGUMENT;
814 /* Check if there's remaining focus for session for the same PID of incomming param */
815 if (my_node->is_for_session) {
816 for (list = g_focus_node_list; list != NULL; list = list->next) {
817 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
818 if (my_node == node || node->is_for_watch)
820 if (node->pid == my_node->pid && node->is_for_session && node->status) {
821 debug_warning("another focus node for session of this pid exists, skip invoking callback");
822 need_to_trigger = false;
828 if (need_to_trigger) {
829 bool need_to_trigger_watch_cb = true;
830 _mm_sound_mgr_focus_param_t *new_param = NULL;
832 if (!(new_param = g_malloc0(sizeof(_mm_sound_mgr_focus_param_t)))) {
833 debug_error("Fail to g_malloc0 for new_param");
836 new_param->pid = param->pid;
837 new_param->handle_id = param->handle_id;
838 new_param->is_for_session = my_node->is_for_session;
839 new_param->request_type = my_node->status;
840 new_param->option = my_node->option[i];
841 MMSOUND_STRNCPY(new_param->stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
842 MMSOUND_STRNCPY(new_param->ext_info, my_node->ext_info[i], MM_SOUND_NAME_NUM);
844 for (list = g_focus_node_list; list != NULL; list = list->next) {
845 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
846 if (my_node == node || node->is_for_watch)
848 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
849 if (node->taken_by_id[i].pid != param->pid)
852 if (my_node->taken_by_id[i].pid) {
853 /* If exists update the taken focus info to my victim node */
854 if (node->taken_by_id[i].by_session && !node->status) {
855 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);
856 } else if (node->taken_by_id[i].handle_id == param->handle_id) {
857 UPDATE_FOCUS_TAKEN_INFO(by_id, node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, false);
859 } else if (my_node->status & (i+1)) {
860 if (node->is_for_session)
862 if (node->taken_by_id[i].handle_id == new_param->handle_id || node->taken_by_id[i].by_session) {
863 /* do callback for resumption */
864 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, new_param)))
865 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]", node, ret);
866 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
867 need_to_trigger_watch_cb = false;
868 my_node->status &= ~(new_param->request_type);
874 if (need_to_trigger_watch_cb)
875 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)new_param->request_type, FOCUS_COMMAND_RELEASE, my_node, new_param);
881 /* Destroy my node */
882 __clear_focus_pipe(my_node);
883 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
886 _mm_sound_mgr_focus_list_dump();
887 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
893 int mm_sound_mgr_focus_set_reacquisition(const _mm_sound_mgr_focus_param_t *param)
895 int ret = MM_ERROR_NONE;
897 focus_node_t *node = NULL;
898 focus_node_t *my_node = NULL;
903 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
905 /* Update list for dead process */
906 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
908 /* Find node to set reacquisition */
909 for (list = g_focus_node_list; list != NULL; list = list->next) {
910 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
911 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
913 if (node->reacquisition == param->reacquisition) {
914 debug_msg("it is already set as same value of reacquisition(%d)", param->reacquisition);
917 node->reacquisition = param->reacquisition;
918 debug_msg("found a node(pid[%d]/handle_id[%d]) to set reacquisition to (%d)", node->pid, node->handle_id, param->reacquisition);
922 if (my_node == NULL) {
923 debug_error("could not find any node of pid[%d]/handle_id[%d]", param->pid, param->handle_id);
924 ret = MM_ERROR_INVALID_ARGUMENT;
928 if (!param->reacquisition) {
929 for (list = g_focus_node_list; list != NULL; list = list->next) {
930 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
931 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
932 if (node->taken_by_id[i].pid == param->pid) {
933 /* victim node : append my node's taken info to my victim node */
934 if (my_node->taken_by_id[i].pid != 0) {
935 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);
936 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);
938 } else if (!list->next) {
939 /* my node : backup and reset */
940 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);
941 UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, 0, 0, false);
946 for (list = g_focus_node_list; list != NULL; list = list->next) {
947 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
948 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
949 /* rollback and reset backup info. */
950 if (node->taken_by_id[i].pid && (node->taken_by_id[i].pid == my_node->taken_backup[i].pid)) {
951 UPDATE_FOCUS_TAKEN_INFO(by_id, node, node->taken_backup[i].pid, node->taken_backup[i].handle_id, node->taken_backup[i].by_session);
952 UPDATE_FOCUS_TAKEN_INFO(backup, node, 0, 0, false);
953 } else if (!list->next) {
954 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);
955 UPDATE_FOCUS_TAKEN_INFO(backup, my_node, 0, 0, false);
962 _mm_sound_mgr_focus_list_dump();
963 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
969 int mm_sound_mgr_focus_get_stream_type_of_acquired_focus(focus_type_e focus_type, char **stream_type, int *option, char **ext_info)
971 int ret = MM_ERROR_SOUND_NO_DATA;
973 focus_node_t *node = NULL;
977 if (!stream_type || !option)
978 return MM_ERROR_INVALID_ARGUMENT;
980 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
982 /* Update list for dead process */
983 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
985 /* Find node to set reacquisition */
986 for (list = g_focus_node_list; list != NULL; list = list->next) {
987 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
988 if (!node->is_for_watch && (node->status & focus_type)) {
989 /* In case of FOCUS_TYPE_BOTH, we use index for FOCUS_TYPE_PLAYBACK's forcedly.
990 * It is because this function can not return both index of option, ext_info results
991 * via out-parameter. This case is only used in framework internally for session
992 * backward compatibilty. */
993 int index = (focus_type == FOCUS_TYPE_BOTH) ? FOCUS_TYPE_PLAYBACK - 1 : focus_type - 1;
995 debug_msg("found a node : request_focus_type(%d), stream_type(%s)/ext info(%s) of acquired focus",
996 focus_type, node->stream_type, node->ext_info[index]);
998 *stream_type = node->stream_type;
999 *option = node->option[index];
1001 *ext_info = node->ext_info[index];
1002 ret = MM_ERROR_NONE;
1007 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1014 static void update_reacquisition_with_released_state(focus_node_t *node, int direction)
1017 debug_error("node is null");
1020 if (direction >= NUM_OF_STREAM_IO_TYPE) {
1021 debug_error("invalid direction(%d)", direction);
1025 /* In case of session backward compatibility for audio-io, mm-player, mm-camcorder, we mark a specific flag here.
1026 When invoking focus state changed callback for acquiring, state of the node will not be updated rather updated
1027 when the next request to acquire. */
1028 if (!strncmp("audio-io acquire focus", node->ext_info[direction], MM_SOUND_NAME_NUM) ||
1029 !strncmp("mm-player acquire focus", node->ext_info[direction], MM_SOUND_NAME_NUM) ||
1030 !strncmp("mm-camcorder acquire focus", node->ext_info[direction], MM_SOUND_NAME_NUM)) {
1031 debug_msg("this node[pid:%d, handle_id:%d] needs reacquisition with focus released state", node->pid, node->handle_id);
1032 node->reacquisition_with_released_state = true;
1036 int mm_sound_mgr_focus_request_acquire(const _mm_sound_mgr_focus_param_t *param)
1038 int ret = MM_ERROR_NONE;
1040 focus_node_t *node = NULL;
1041 focus_node_t *my_node = NULL;
1042 bool need_to_trigger_cb = false;
1043 bool need_to_trigger_watch_cb = true;
1044 bool need_to_trigger_monitor_cb = true;
1049 if (!param->is_in_thread)
1050 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1052 /* Update list for dead process */
1053 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1055 for (list = g_focus_node_list; list != NULL; list = list->next) {
1056 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1057 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
1060 if ((my_node->status > FOCUS_STATUS_DEACTIVATED) && (my_node->status & param->request_type)) {
1061 debug_error("focus status is already activated");
1062 ret = MM_ERROR_SOUND_INVALID_STATE;
1067 if (my_node == NULL) {
1068 debug_error("node is null");
1069 ret = MM_ERROR_INVALID_ARGUMENT;
1073 /* check if the priority of any node is higher than its based on io direction */
1074 for (list = g_focus_node_list; list != NULL; list = list->next) {
1075 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1076 if (my_node == node || node->is_for_watch)
1078 if (param->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
1079 (node->status & param->request_type)) {
1080 if (node->status <= FOCUS_STATUS_DEACTIVATED)
1083 if ((my_node->priority < node->priority)) {
1084 ret = MM_ERROR_POLICY_BLOCKED;
1085 need_to_trigger_cb = false;
1088 need_to_trigger_cb = true;
1093 if (need_to_trigger_cb) {
1094 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
1095 param_s->is_for_session = my_node->is_for_session;
1096 MMSOUND_STRNCPY(param_s->stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
1097 for (list = g_focus_node_list; list != NULL; list = list->next) {
1098 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1099 if (node == my_node || node->is_for_watch)
1101 if (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session)
1103 if (param_s->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
1104 (node->status & param_s->request_type)) {
1105 if (node->status <= FOCUS_STATUS_DEACTIVATED)
1107 if (my_node->priority >= node->priority) {
1108 /* do callback for interruption */
1109 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_RELEASE, node, param_s))) {
1110 debug_error("Fail to _focus_do_callback for COMMAND RELEASE to node[%x], ret[0x%x]", node, ret);
1111 /* but, keep going */
1112 ret = MM_ERROR_NONE;
1114 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN))
1115 need_to_trigger_watch_cb = false;
1117 need_to_trigger_monitor_cb = false;
1123 if (ret != MM_ERROR_POLICY_BLOCKED) {
1124 /* copy ext info. */
1125 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1126 if (param->request_type & (i+1)) {
1127 MMSOUND_STRNCPY(my_node->ext_info[i], param->ext_info, MM_SOUND_NAME_NUM);
1128 my_node->option[i] = param->option;
1129 update_reacquisition_with_released_state(my_node, i);
1133 my_node->status |= param->request_type;
1134 /* do watch callback due to the status of mine */
1135 if (need_to_trigger_watch_cb)
1136 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_ACQUIRE, my_node, param);
1137 if (need_to_trigger_monitor_cb)
1138 _mm_sound_mgr_focus_do_monitor_callback_outer((focus_type_e)param->request_type, FOCUS_COMMAND_RELEASE, my_node, param);
1140 /* update taken information */
1141 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1142 if (param->request_type & (i+1)) {
1143 UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, 0, 0, false);
1144 UPDATE_FOCUS_TAKEN_INFO(backup, my_node, 0, 0, false);
1149 _mm_sound_mgr_focus_list_dump();
1150 _mm_sound_mgr_focus_watch_list_dump ();
1152 if (!param->is_in_thread)
1153 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1159 int mm_sound_mgr_focus_request_release(const _mm_sound_mgr_focus_param_t *param)
1161 int ret = MM_ERROR_NONE;
1163 focus_node_t *node = NULL;
1164 focus_node_t *my_node = NULL;
1165 bool need_to_trigger_watch_cb = true;
1166 bool need_to_trigger_monitor_cb = true;
1167 bool need_to_trigger_cb = true;
1172 if (!param->is_in_thread)
1173 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1175 /* Update list for dead process */
1176 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1178 for (list = g_focus_node_list; list != NULL; list = list->next) {
1179 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1180 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
1183 if (my_node->status == FOCUS_STATUS_DEACTIVATED) {
1184 debug_error("focus status is already deactivated");
1185 ret = MM_ERROR_SOUND_INVALID_STATE;
1187 } else if ((my_node->status != FOCUS_STATUS_ACTIVATED_BOTH) && (my_node->status != (focus_status_e)param->request_type)) {
1188 debug_error("request type is not matched with current focus type");
1189 ret = MM_ERROR_SOUND_INVALID_STATE;
1195 if (my_node == NULL) {
1196 debug_error("node is null");
1197 ret = MM_ERROR_INVALID_ARGUMENT;
1201 /* Check if there's activating focus for session for the same PID of incomming param*/
1202 if (my_node->is_for_session) {
1203 for (list = g_focus_node_list; list != NULL; list = list->next) {
1204 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1205 if (node == my_node || node->is_for_watch)
1207 if (node->pid == my_node->pid && node->is_for_session && node->status) {
1208 debug_warning("another focus node for session of this pid exists, skip invoking callback");
1209 need_to_trigger_watch_cb = false;
1210 need_to_trigger_cb = false;
1216 if (need_to_trigger_cb) {
1217 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
1218 param_s->is_for_session = my_node->is_for_session;
1219 MMSOUND_STRNCPY(param_s->stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
1220 for (list = g_focus_node_list; list != NULL; list = list->next) {
1221 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1222 if (node == my_node || node->is_for_watch)
1224 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1225 if (param_s->request_type & (i+1)) {
1226 if (node->taken_by_id[i].pid == param_s->pid &&
1227 (node->taken_by_id[i].handle_id == param_s->handle_id || node->taken_by_id[i].by_session)) {
1228 /* exception case as per the previous session policy,
1229 * "session resumption" is only available for "media session" */
1230 if (my_node->is_for_session && node->is_for_session) {
1231 if (strncmp(node->stream_type, "media", MAX_STREAM_TYPE_LEN))
1234 /* do callback for resumption */
1235 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, param_s)))
1236 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]", node, ret);
1237 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
1238 need_to_trigger_watch_cb = false;
1240 need_to_trigger_monitor_cb = false;
1247 my_node->status &= ~(param->request_type);
1248 /* remove ext info. */
1249 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1250 if (!(my_node->status & (i+1))) {
1251 memset(my_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
1252 my_node->option[i] = 0;
1255 /* do watch callback due to the status of mine */
1256 if (need_to_trigger_watch_cb)
1257 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_RELEASE, my_node, param);
1258 if (need_to_trigger_monitor_cb)
1259 _mm_sound_mgr_focus_do_monitor_callback_outer((focus_type_e)param->request_type, FOCUS_COMMAND_ACQUIRE, my_node, param);
1261 _mm_sound_mgr_focus_list_dump();
1262 _mm_sound_mgr_focus_watch_list_dump ();
1264 if (!param->is_in_thread)
1265 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1271 int mm_sound_mgr_focus_set_watch_cb(const _mm_sound_mgr_focus_param_t *param)
1273 int ret = MM_ERROR_NONE;
1275 focus_node_t *node = NULL;
1279 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1281 /* Update list for dead process */
1282 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1284 for (list = g_focus_node_list; list != NULL; list = list->next) {
1285 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1286 if ((node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1287 debug_error("the node of pid[%d]/handle_id[%d] for watch focus is already created", param->pid, param->handle_id);
1288 ret = MM_ERROR_INVALID_ARGUMENT;
1293 node = g_malloc0(sizeof(focus_node_t));
1295 /* fill up information to the node */
1296 _mm_sound_mgr_focus_fill_info_from_msg(node, param);
1297 node->is_for_watch = true;
1298 node->is_for_monitor = param->is_for_monitor;
1299 node->status = param->request_type;
1301 g_focus_node_list = g_list_append(g_focus_node_list, node);
1302 if (g_focus_node_list) {
1303 debug_log("new focus node is added");
1305 debug_error("g_list_append failed");
1306 ret = MM_ERROR_SOUND_INTERNAL;
1310 _mm_sound_mgr_focus_watch_list_dump();
1312 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1318 int mm_sound_mgr_focus_unset_watch_cb(const _mm_sound_mgr_focus_param_t *param)
1320 int ret = MM_ERROR_SOUND_INTERNAL;
1322 focus_node_t *node = NULL;
1326 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1328 /* Update list for dead process */
1329 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1331 for (list = g_focus_node_list; list != NULL; list = list->next) {
1332 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1333 if ((node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1334 debug_log("found the node of pid[%d]/handle_id[%d] for watch focus", param->pid, param->handle_id);
1335 __clear_focus_pipe(node);
1336 g_focus_node_list = g_list_remove(g_focus_node_list, node);
1338 ret = MM_ERROR_NONE;
1343 debug_error("could not find any node of pid[%d]/handle_id[%d] for watch focus", param->pid, param->handle_id);
1344 ret = MM_ERROR_INVALID_ARGUMENT;
1348 _mm_sound_mgr_focus_watch_list_dump();
1350 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1356 int mm_sound_mgr_focus_deliver(const _mm_sound_mgr_focus_param_t *param)
1358 int ret = MM_ERROR_NONE;
1360 focus_node_t *src_node = NULL;
1361 focus_node_t *dst_node = NULL;
1366 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1368 /* Update list for dead process */
1369 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1371 for (list = g_focus_node_list; list != NULL; list = list->next) {
1372 CONTINUE_IF_LIST_DATA_IS_NULL(src_node, list);
1373 if ((src_node->pid == param->pid) && (src_node->handle_id == param->handle_id)) {
1374 debug_log("SRC: found the node of pid[%d]/handle_id[%d] for watch focus",
1375 param->pid, param->handle_id);
1379 if (src_node == NULL) {
1380 debug_error("could not find the source node of param, pid[%d]/handle_id[%d]",
1381 param->pid, param->handle_id);
1382 ret = MM_ERROR_INVALID_ARGUMENT;
1386 if (!(src_node->status & param->request_type)) {
1387 debug_error("invalid request type(0x%x), src_node->status(0x%x)",
1388 param->request_type, src_node->status);
1389 ret = MM_ERROR_SOUND_INVALID_STATE;
1393 for (list = g_focus_node_list; list != NULL; list = list->next) {
1394 CONTINUE_IF_LIST_DATA_IS_NULL(dst_node, list);
1395 if ((dst_node->pid == param->pid) && (dst_node->handle_id == param->handle_id_dst)) {
1396 debug_log("DST: found the destination node of param, pid[%d]/handle_id[%d]",
1397 param->pid, param->handle_id_dst);
1401 if (dst_node == NULL) {
1402 debug_error("could not find the destination node of param, pid[%d]/handle_id[%d]",
1403 param->pid, param->handle_id_dst);
1404 ret = MM_ERROR_INVALID_ARGUMENT;
1408 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1409 focus_node_t *node = NULL;
1410 if (!(param->request_type & (i+1)))
1413 for (list = g_focus_node_list; list != NULL; list = list->next) {
1414 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1415 if ((node->taken_by_id[i].pid == src_node->pid) &&
1416 (node->taken_by_id[i].handle_id == src_node->handle_id) &&
1417 (node->taken_by_id[i].by_session == false)) {
1418 debug_log("found the node that focus was taken by this src node, update it",
1419 node->pid, node->handle_id);
1420 UPDATE_FOCUS_TAKEN_INFO(by_id, node, dst_node->pid, dst_node->handle_id, false);
1422 if ((node->taken_backup[i].pid == src_node->pid) &&
1423 (node->taken_backup[i].handle_id == src_node->handle_id) &&
1424 (node->taken_backup[i].by_session == false)) {
1425 debug_log("found the node that focus was taken by this src node and set reacquisition to false, update it",
1426 node->pid, node->handle_id);
1427 UPDATE_FOCUS_TAKEN_INFO(backup, node, dst_node->pid, dst_node->handle_id, false);
1431 dst_node->status |= (i+1);
1432 UPDATE_FOCUS_TAKEN_INFO(by_id, dst_node, 0, 0, false);
1433 UPDATE_FOCUS_TAKEN_INFO(backup, dst_node, 0, 0, false);
1434 MMSOUND_STRNCPY(dst_node->ext_info[i], src_node->ext_info[i], MM_SOUND_NAME_NUM);
1435 dst_node->option[i] = src_node->option[i];
1437 src_node->status &= ~(i+1);
1438 memset(src_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
1439 src_node->option[i] = 0;
1442 _mm_sound_mgr_focus_list_dump();
1445 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1451 int mm_sound_mgr_focus_emergent_exit(const _mm_sound_mgr_focus_param_t *param)
1453 int ret = MM_ERROR_NONE;
1455 GList *list_s =NULL;
1456 focus_node_t *node = NULL;
1457 focus_node_t *my_node = NULL;
1462 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1464 /* Update list for dead process */
1465 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1467 list = g_focus_node_list;
1469 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1470 if (node->pid != param->pid) {
1472 debug_log("node not found, next list = %p",list);
1475 if (node->is_for_watch) {
1476 debug_log("clearing watch cb of pid(%d) handle(%d)", node->pid, node->handle_id);
1477 __clear_focus_pipe(node);
1478 g_focus_node_list = g_list_remove(g_focus_node_list, node);
1479 list = g_focus_node_list;
1483 if (node->status == FOCUS_STATUS_DEACTIVATED) {
1484 debug_log("clearing deactivated focus node of pid(%d) hande(%d)", node->pid, node->handle_id);
1486 /* update info of nodes that are lost their focus by the process exited */
1487 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1488 CONTINUE_IF_LIST_DATA_IS_NULL(node, list_s);
1489 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1490 if (node->taken_by_id[i].pid == param->pid) {
1491 if (my_node->taken_by_id[i].pid) {
1492 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);
1494 UPDATE_FOCUS_TAKEN_INFO(by_id, node, 0, 0, false);
1499 __clear_focus_pipe(my_node);
1500 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1501 list = g_focus_node_list;
1503 } else { /* node that acquired focus */
1504 bool need_to_trigger_watch_cb = true;
1505 _mm_sound_mgr_focus_param_t param_s;
1506 debug_log("clearing activated focus node of pid(%d) handle(%d)", node->pid, node->handle_id);
1509 memset(¶m_s, 0x00, sizeof(_mm_sound_mgr_focus_param_t));
1510 param_s.pid = my_node->pid;
1511 param_s.handle_id = my_node->handle_id;
1512 param_s.request_type = my_node->status;
1513 MMSOUND_STRNCPY(param_s.stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
1514 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1515 CONTINUE_IF_LIST_DATA_IS_NULL(node, list_s);
1516 if (my_node->pid == node->pid || node->is_for_watch)
1518 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1519 if (!(my_node->status & (i+1)))
1521 if (node->taken_by_id[i].pid == param_s.pid && node->taken_by_id[i].handle_id == param_s.handle_id) {
1522 /* do callback for resumption */
1523 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, ¶m_s)))
1524 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]", node, ret);
1525 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN))
1526 need_to_trigger_watch_cb = false;
1530 if (need_to_trigger_watch_cb) {
1531 if ((ret = _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param_s.request_type, FOCUS_COMMAND_RELEASE, my_node, ¶m_s)))
1532 debug_error("Fail to _focus_do_watch_callback, ret[0x%x]", ret);
1535 __clear_focus_pipe(my_node);
1536 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1537 list = g_focus_node_list;
1541 _mm_sound_mgr_focus_list_dump();
1542 _mm_sound_mgr_focus_watch_list_dump ();
1544 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1551 int MMSoundMgrFocusInit(void)
1553 int ret = MM_ERROR_NONE;
1556 ret = __mm_sound_mgr_focus_dbus_get_stream_list(&g_stream_list);
1558 debug_error("failed to __mm_sound_mgr_focus_dbus_get_stream_list()");
1564 int MMSoundMgrFocusFini(void)
1569 for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
1570 if (g_stream_list.stream_types[i]) {
1571 free(g_stream_list.stream_types[i]);
1576 return MM_ERROR_NONE;