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 static GList *g_focus_node_list = NULL;
37 static pthread_mutex_t g_focus_node_list_mutex = PTHREAD_MUTEX_INITIALIZER;
38 stream_list_t g_stream_list;
40 static const char* focus_status_str[] =
53 char stream_type [MAX_STREAM_TYPE_LEN];
54 char name [MM_SOUND_NAME_NUM];
57 #define CLEAR_DEAD_NODE_LIST(x) do { \
58 debug_warning ("list = %p, node = %p, pid=[%d]", x, node, (node)? node->pid : -1); \
59 if (x && node && (mm_sound_util_is_process_alive(node->pid) == FALSE)) { \
60 debug_warning("PID:%d does not exist now! remove from device cb list\n", node->pid); \
61 __clear_focus_pipe(node); \
62 x = g_list_remove (x, node); \
67 #define UPDATE_FOCUS_TAKEN_INFO(x, y, z, q) \
68 debug_warning ("updating node[%p]'s taken info : pid = [%d], handle_id = [%d], is_for_session = [%d]",x, y, z, q); \
69 x->taken_by_id[i].pid = y; \
70 x->taken_by_id[i].handle_id = z; \
71 x->taken_by_id[i].by_session = q; \
73 #ifdef SUPPORT_CONTAINER
74 static void __set_container_data(int pid, int handle, const char* container_name, int container_pid)
77 focus_node_t *node = NULL;
79 for (list = g_focus_node_list; list != NULL; list = list->next) {
80 node = (focus_node_t *)list->data;
81 if (!node->is_for_watch && node->pid == pid && node->handle_id == handle) {
82 debug_error("Set container [%s][%d] to handle[%d] instanceID[%d]",
83 container_name, container_pid, handle, node->pid);
85 MMSOUND_STRNCPY(node->container.name, container_name, CONTAINER_NAME_MAX);
86 node->container.pid = container_pid;
89 else if (node->is_for_watch && node->pid == pid) {
90 debug_error("Set container [%s][%d] to instanceID[%d]",
91 container_name, container_pid, pid);
93 MMSOUND_STRNCPY(node->container.name, container_name, CONTAINER_NAME_MAX);
94 node->container.pid = container_pid;
100 static container_info_t* __get_container_info(int instance_id)
103 focus_node_t *node = NULL;
105 for (list = g_focus_node_list; list != NULL; list = list->next) {
106 node = (focus_node_t *)list->data;
107 if (node->pid == instance_id) {
108 return &node->container;
113 #endif /* SUPPORT_CONTAINER */
115 static char* __get_focus_pipe_path(int instance_id, int handle, const char* postfix, bool is_watch)
120 #ifdef SUPPORT_CONTAINER
121 container_info_t* container_info = __get_container_info(instance_id);
122 if (!container_info) {
123 debug_error ("__get_container_info failed");
126 if (instance_id == container_info->pid) {
127 debug_error ("This might be in the HOST(%s)[%d], let's form normal path",
128 container_info->name, instance_id);
130 path = g_strdup_printf("/tmp/FOCUS.%d.wch", instance_id);
132 path = g_strdup_printf("/tmp/FOCUS.%d.%d", instance_id, handle);
136 path = g_strdup_printf("/var/lib/lxc/%s/rootfs/tmp/FOCUS.%d.wch",
137 container_info->name, container_info->pid);
139 path = g_strdup_printf("/var/lib/lxc/%s/rootfs/tmp/FOCUS.%d.%d",
140 container_info->name, container_info->pid, handle);
145 path = g_strdup_printf("/tmp/FOCUS.%d.wch", instance_id);
147 path = g_strdup_printf("/tmp/FOCUS.%d.%d", instance_id, handle);
152 path2 = g_strconcat(path, postfix, NULL);
161 static void __clear_focus_pipe(focus_node_t *node)
163 char *filename = NULL;
164 char *filename2 = NULL;
168 if (!node->is_for_watch) {
169 filename = __get_focus_pipe_path(node->pid, node->handle_id, NULL, false);
170 filename2 = __get_focus_pipe_path(node->pid, node->handle_id, "r", false);
172 filename = __get_focus_pipe_path(node->pid, -1, NULL, true);
173 filename2 = __get_focus_pipe_path(node->pid, -1, "r", true);
177 debug_error("remove() failure, filename(%s), errno(%d)", filename, errno);
181 if(remove(filename2))
182 debug_error("remove() failure, filename2(%s), errno(%d)", filename2, errno);
189 static void _clear_focus_node_list_func (focus_node_t *node, gpointer user_data)
191 CLEAR_DEAD_NODE_LIST(g_focus_node_list);
194 static int _mm_sound_mgr_focus_get_priority_from_stream_type(int *priority, const char *stream_type)
196 int ret = MM_ERROR_NONE;
201 if (priority == NULL || stream_type == NULL) {
202 ret = MM_ERROR_INVALID_ARGUMENT;
203 debug_error("invalid argument, priority[0x%x], stream_type[%s], ret[0x%x]\n", priority, stream_type, ret);
205 for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
206 if (!strncmp(g_stream_list.stream_types[i], stream_type, strlen(stream_type))) {
207 *priority = g_stream_list.priorities[i];
211 if (i == AVAIL_STREAMS_MAX) {
212 ret = MM_ERROR_NOT_SUPPORT_API;
213 debug_error("not supported stream_type[%s], ret[0x%x]\n", stream_type, ret);
215 debug_log("[%s] has priority of [%d]\n", stream_type, *priority);
223 static int _mm_sound_mgr_focus_do_watch_callback(focus_type_e focus_type, focus_command_e command,
224 focus_node_t *my_node, const _mm_sound_mgr_focus_param_t *param)
226 char *filename = NULL;
227 char *filename2 = NULL;
236 int pollingTimeout = 2500; /* NOTE : This is temporary code, because of Deadlock issues. If you fix that issue, remove this comment */
239 focus_node_t *node = NULL;
240 focus_cb_data cb_data;
244 for (list = g_focus_node_list; list != NULL; list = list->next) {
245 node = (focus_node_t *)list->data;
246 if (node == my_node || (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session)) {
249 if (node->is_for_watch && (node->status & focus_type)) {
250 memset(&cb_data, 0, sizeof(focus_cb_data));
251 cb_data.pid = node->pid;
252 cb_data.handle = node->handle_id;
253 cb_data.type = focus_type & node->status;
254 cb_data.state = (command == FOCUS_COMMAND_ACQUIRE) ? !FOCUS_STATUS_DEACTIVATED : FOCUS_STATUS_DEACTIVATED;
255 MMSOUND_STRNCPY(cb_data.stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
256 MMSOUND_STRNCPY(cb_data.name, param->option, MM_SOUND_NAME_NUM);
259 gettimeofday(&time, NULL);
260 starttime = time.tv_sec * 1000000 + time.tv_usec;
262 /**************************************
264 * Open callback cmd pipe
266 **************************************/
267 filename = __get_focus_pipe_path(cb_data.pid, -1, NULL, true);
268 if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
269 debug_error("[CallCB] %s open error\n", filename);
273 /******************************************
275 * Open callback result pipe
276 * before writing callback cmd to pipe
278 ******************************************/
279 filename2 = __get_focus_pipe_path(cb_data.pid, -1, "r", true);
280 if (filename2 == NULL) {
281 debug_error("[RETCB] Fail to get watch return pipe");
284 if ((fd_FOCUS_R= open(filename2,O_RDONLY|O_NONBLOCK)) == -1) {
286 strerror_r (errno, str_error, sizeof(str_error));
287 debug_error("[RETCB] Fail to open fifo (%s)\n", str_error);
290 debug_log(" open return cb %s\n", filename2);
292 /*******************************************
294 *******************************************/
295 if (write(fd_FOCUS, &cb_data ,sizeof(cb_data)) == -1) {
296 debug_error("[CallCB] %s fprintf error\n", filename);
300 /**************************************
302 * Close callback cmd pipe
304 **************************************/
314 /*********************************************
316 * Wait callback result msg
318 ********************************************/
319 debug_error("[RETCB]wait callback(tid=%d, cmd=%d, timeout=%d)\n", cb_data.pid, command, pollingTimeout);
320 pret = poll(&pfd, 1, pollingTimeout); /* timeout 7sec */
321 debug_error("after poll");
323 debug_error("[RETCB]poll failed (%d)\n", pret);
326 if (pfd.revents & POLLIN) {
327 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
328 debug_error("fscanf error\n");
336 /* Calculate endtime and display*/
337 gettimeofday(&time, NULL);
338 endtime = time.tv_sec * 1000000 + time.tv_usec;
339 debug_error("[RETCB] FOCUS_CB_END cbtimelab=%3.3f(second), timeout=%d(milli second) (reciever=%d) Return value = (handle_id=%d)\n", ((endtime-starttime)/1000000.), pollingTimeout, cb_data.pid, ret);
341 /**************************************
343 * Close callback result pipe
345 **************************************/
346 if (fd_FOCUS_R != -1) {
354 return MM_ERROR_NONE;
365 if (fd_FOCUS != -1) {
369 if (fd_FOCUS_R != -1) {
377 int _mm_sound_mgr_focus_do_callback(focus_command_e command, focus_node_t *victim_node, const _mm_sound_mgr_focus_param_t *assaulter_param, const char *assaulter_stream_type)
379 char *filename = NULL;
380 char *filename2 = NULL;
389 int pollingTimeout = 2500; /* NOTE : This is temporary code, because of Deadlock issues. If you fix that issue, remove this comment */
392 int flag_for_focus_type = 0;
393 int flag_for_taken_index = 0;
397 bool taken_by_session = false;
399 focus_cb_data cb_data;
401 debug_error(" __mm_sound_mgr_focus_do_callback_ for pid(%d) handle(%d)\n", victim_node->pid, victim_node->handle_id);
403 memset(&cb_data, 0, sizeof(focus_cb_data));
404 cb_data.pid= victim_node->pid;
405 cb_data.handle= victim_node->handle_id;
406 if (command == FOCUS_COMMAND_RELEASE) {
407 /* client will lost the acquired focus */
408 cb_data.type= assaulter_param->request_type & victim_node->status;
409 cb_data.state= FOCUS_STATUS_DEACTIVATED;
410 /* remove additional info. */
411 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
412 if (cb_data.type & (i+1))
413 memset(victim_node->option[i], 0x0, MM_SOUND_NAME_NUM);
416 /* client will gain the lost focus */
417 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
418 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)) {
419 flag_for_focus_type |= i+1; /* playback:1, capture:2 */
422 cb_data.type = flag_for_focus_type & assaulter_param->request_type;
423 cb_data.state = !FOCUS_STATUS_DEACTIVATED;
424 /* copy additional info. */
425 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
426 if (cb_data.type & (i+1))
427 MMSOUND_STRNCPY(victim_node->option[i], assaulter_param->option, MM_SOUND_NAME_NUM);
430 MMSOUND_STRNCPY(cb_data.stream_type, assaulter_stream_type, MAX_STREAM_TYPE_LEN);
431 MMSOUND_STRNCPY(cb_data.name, assaulter_param->option, MM_SOUND_NAME_NUM);
434 gettimeofday(&time, NULL);
435 starttime = time.tv_sec * 1000000 + time.tv_usec;
437 /**************************************
439 * Open callback cmd pipe
441 **************************************/
442 filename = __get_focus_pipe_path(cb_data.pid, cb_data.handle, NULL, false);
443 if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
444 debug_error("[CallCB] %s open error\n", filename);
448 /******************************************
450 * Open callback result pipe
451 * before writing callback cmd to pipe
453 ******************************************/
454 filename2 = __get_focus_pipe_path(cb_data.pid, cb_data.handle, "r", false);
455 if (filename2 == NULL) {
456 debug_error("[RETCB] Fail to get return pipe");
459 if ((fd_FOCUS_R = open(filename2,O_RDONLY|O_NONBLOCK)) == -1) {
461 strerror_r (errno, str_error, sizeof(str_error));
462 debug_error("[RETCB] Fail to open fifo (%s)\n", str_error);
465 debug_log(" open return cb %s\n", filename2);
468 /*******************************************
470 *******************************************/
471 if (write(fd_FOCUS, &cb_data, sizeof(cb_data)) == -1) {
472 debug_error("[CallCB] %s write error\n", filename);
475 /**************************************
477 * Close callback cmd pipe
479 **************************************/
489 /*********************************************
491 * Wait callback result msg
493 ********************************************/
494 debug_error("[RETCB]wait callback(tid=%d, handle=%d, cmd=%d, timeout=%d)\n",cb_data.pid, cb_data.handle, command, pollingTimeout);
495 pret = poll(&pfd, 1, pollingTimeout);
497 debug_error("[RETCB]poll failed (%d)\n", pret);
500 if (pfd.revents & POLLIN) {
501 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
502 debug_error("read error\n");
505 ret_handle = (int)(ret & 0x0000ffff);
506 victim_node->reacquisition= (bool)((ret >> 16) & 0xf);
511 /* Calculate endtime and display*/
512 gettimeofday(&time, NULL);
513 endtime = time.tv_sec * 1000000 + time.tv_usec;
514 debug_error("[RETCB] FOCUS_CB_END cbtimelab=%3.3f(second), timeout=%d(milli second) (reciever=%d) Return value = (handle_id=%d)\n", ((endtime-starttime)/1000000.), pollingTimeout, cb_data.pid, ret);
516 /**************************************
518 * Close callback result pipe
520 **************************************/
521 if (fd_FOCUS_R != -1) {
525 //debug_log("[RETCB] Return value 0x%x\n", buf);
527 /* update victim node */
528 if (command == FOCUS_COMMAND_RELEASE) {
529 taken_pid = assaulter_param->pid;
530 taken_hid = assaulter_param->handle_id;
531 taken_by_session = assaulter_param->is_for_session;
532 flag_for_taken_index = assaulter_param->request_type & victim_node->status;
536 taken_by_session = false;
537 flag_for_taken_index = assaulter_param->request_type;
540 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
541 if (flag_for_taken_index & (i+1)) {
542 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)))) {
544 debug_error("skip updating victim node");
547 if (!victim_node->reacquisition) {
549 focus_node_t *node = NULL;
550 for (list = g_focus_node_list; list != NULL; list = list->next) {
551 node = (focus_node_t *)list->data;
552 if (node && (node->taken_by_id[i].pid == victim_node->pid)) {
553 UPDATE_FOCUS_TAKEN_INFO(node, taken_pid, taken_hid, taken_by_session);
554 } else if (!list->next) {
555 UPDATE_FOCUS_TAKEN_INFO(victim_node, 0, 0, false);
559 UPDATE_FOCUS_TAKEN_INFO(victim_node, taken_pid, taken_hid, taken_by_session);
564 if (ret_handle == victim_node->handle_id) {
565 /* return from client is success, ret_handle will be its handle_id */
566 victim_node->status = (command == FOCUS_COMMAND_RELEASE) ? (victim_node->status & ~(cb_data.type)) : (victim_node->status | cb_data.type);
568 victim_node->status = FOCUS_STATUS_DEACTIVATED;
571 if (strncmp(assaulter_stream_type, victim_node->stream_type, MAX_STREAM_TYPE_LEN))
572 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)assaulter_param->request_type, command, victim_node, assaulter_param);
575 return MM_ERROR_NONE;
586 if (fd_FOCUS != -1) {
590 if (fd_FOCUS_R != -1) {
598 static int _mm_sound_mgr_focus_list_dump ()
600 int ret = MM_ERROR_NONE;
602 focus_node_t *node = NULL;
604 debug_log("================================================ focus node list : start ===================================================\n");
605 for (list = g_focus_node_list; list != NULL; list = list->next) {
606 node = (focus_node_t *)list->data;
607 if (node && !node->is_for_watch) {
608 debug_log("*** pid[%5d]/handle_id[%d]/[%15s]:priority[%2d],status[%s],taken_by[P(%5d/%2d/%2d)C(%5d/%2d/%2d)],for_session[%d],add.info[%s/%s]\n",
609 node->pid, node->handle_id, node->stream_type, node->priority, focus_status_str[node->status],
610 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,
611 node->taken_by_id[1].handle_id, node->taken_by_id[1].by_session, node->is_for_session, node->option[0], node->option[1]);
614 debug_log("================================================ focus node list : end =====================================================\n");
619 static int _mm_sound_mgr_focus_watch_list_dump ()
621 int ret = MM_ERROR_NONE;
623 focus_node_t *node = NULL;
625 debug_log("============================================= focus watch node list : start =================================================\n");
626 for (list = g_focus_node_list; list != NULL; list = list->next) {
627 node = (focus_node_t *)list->data;
628 if (node && node->is_for_watch) {
629 debug_log("*** pid[%5d]/handle_id[%d]/watch on focus status[%s]/for_session[%d]\n", node->pid, node->handle_id, focus_status_str[node->status], node->is_for_session);
632 debug_log("============================================= focus watch node list : end ===================================================\n");
637 static void _mm_sound_mgr_focus_fill_info_from_msg (focus_node_t *node, const _mm_sound_mgr_focus_param_t *msg)
640 node->pid = msg->pid;
641 node->handle_id = msg->handle_id;
642 node->callback = msg->callback;
643 node->cbdata = msg->cbdata;
644 node->is_for_session = msg->is_for_session;
645 #ifdef SUPPORT_CONTAINER
646 memset (&node->container, 0, sizeof (container_info_t));
647 MMSOUND_STRNCPY(node->container.name, "NONAME", CONTAINER_NAME_MAX);
648 node->container.pid = msg->pid;
655 #ifdef SUPPORT_CONTAINER
656 void mm_sound_mgr_focus_update_container_data(int pid,int handle, const char* container_name, int container_pid)
658 __set_container_data(pid, handle, container_name, container_pid);
659 //__temp_print_list(NULL);
663 int mm_sound_mgr_focus_create_node (const _mm_sound_mgr_focus_param_t *param)
665 int ret = MM_ERROR_NONE;
667 focus_node_t *node = NULL;
672 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
674 /* Update list for dead process */
675 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
677 for (list = g_focus_node_list; list != NULL; list = list->next) {
678 node = (focus_node_t *)list->data;
679 if (node && !node->is_for_watch && (node->pid == param->pid) && (node->handle_id == param->handle_id)) {
680 debug_error("the node of pid[%d]/handle_id[%d] is already created\n", param->pid, param->handle_id);
681 ret = MM_ERROR_INVALID_ARGUMENT;
686 /* get priority from stream type */
687 ret = _mm_sound_mgr_focus_get_priority_from_stream_type(&priority, param->stream_type);
691 node = g_malloc0(sizeof(focus_node_t));
693 /* fill up information to the node */
694 _mm_sound_mgr_focus_fill_info_from_msg(node, param);
695 node->priority = priority;
696 node->status = FOCUS_STATUS_DEACTIVATED;
697 MMSOUND_STRNCPY(node->stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
699 g_focus_node_list = g_list_append(g_focus_node_list, node);
700 if (g_focus_node_list) {
701 debug_log("new focus node is added\n");
703 debug_error("g_list_append failed\n");
704 ret = MM_ERROR_SOUND_INTERNAL;
708 _mm_sound_mgr_focus_list_dump();
710 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
716 int mm_sound_mgr_focus_destroy_node (const _mm_sound_mgr_focus_param_t *param)
718 int ret = MM_ERROR_NONE;
720 focus_node_t *node = NULL;
721 focus_node_t *my_node = NULL;
722 bool need_to_trigger = true;
727 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
729 /* Update list for dead process */
730 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
732 for (list = g_focus_node_list; list != NULL; list = list->next) {
733 node = (focus_node_t *)list->data;
734 if (node && !node->is_for_watch && (node->pid == param->pid) && (node->handle_id == param->handle_id)) {
735 debug_log("found the node of pid[%d]/handle_id[%d]\n", param->pid, param->handle_id);
740 if (my_node == NULL) {
741 debug_error("could not find any node of pid[%d]/handle_id[%d]\n", param->pid, param->handle_id);
742 ret = MM_ERROR_INVALID_ARGUMENT;
746 /* Check if there's remaining focus for session for the same PID of incomming param*/
747 if(my_node->is_for_session) {
748 for (list = g_focus_node_list; list != NULL; list = list->next) {
749 node = (focus_node_t *)list->data;
752 } else if (my_node == node || node->is_for_watch) {
755 if (node->pid == my_node->pid && node->is_for_session) {
756 debug_error("focus for session for this pid still remains, skip updating victim focus nodes");
757 need_to_trigger = false;
764 if(need_to_trigger) {
765 for (list = g_focus_node_list; list != NULL; list = list->next) {
766 node = (focus_node_t *)list->data;
769 } else if (my_node == node || node->is_for_watch) {
772 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
773 if (node->taken_by_id[i].pid == param->pid) {
774 if(my_node->taken_by_id[i].pid) {
775 /* If exists update the taken focus info to my victim node */
776 if (node->taken_by_id[i].by_session && !node->status) {
777 UPDATE_FOCUS_TAKEN_INFO(node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, my_node->taken_by_id[i].by_session);
778 } else if (node->taken_by_id[i].handle_id == param->handle_id) {
779 UPDATE_FOCUS_TAKEN_INFO(node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, false);
782 if (node->taken_by_id[i].by_session && !node->status) {
783 UPDATE_FOCUS_TAKEN_INFO(node, 0, 0, false);
784 } else if (node->taken_by_id[i].handle_id == param->handle_id) {
785 UPDATE_FOCUS_TAKEN_INFO(node, 0, 0, false);
794 /* Destroy my node */
795 __clear_focus_pipe(my_node);
796 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
799 _mm_sound_mgr_focus_list_dump();
801 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
807 int mm_sound_mgr_focus_set_reacquisition (const _mm_sound_mgr_focus_param_t *param)
809 int ret = MM_ERROR_NONE;
811 focus_node_t *node = NULL;
812 focus_node_t *my_node = NULL;
816 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
818 /* Update list for dead process */
819 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
821 /* Find node to set reacquisition */
822 for (list = g_focus_node_list; list != NULL; list = list->next) {
823 node = (focus_node_t *)list->data;
824 if (node && !node->is_for_watch && (node->pid == param->pid) && (node->handle_id == param->handle_id)) {
825 node->reacquisition = param->reacquisition;
831 /* Append my node's taken info to my victim node */
832 if(!param->reacquisition) {
834 for (list = g_focus_node_list; list != NULL; list = list->next) {
835 node = (focus_node_t *)list->data;
836 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
837 if (node && (node->taken_by_id[i].pid == param->pid)) {
838 if (my_node->taken_by_id[i].pid) {
839 UPDATE_FOCUS_TAKEN_INFO(node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, my_node->taken_by_id[i].by_session);
841 } else if (!list->next) {
842 UPDATE_FOCUS_TAKEN_INFO(my_node, 0, 0, false);
848 _mm_sound_mgr_focus_list_dump();
849 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
855 int mm_sound_mgr_focus_get_stream_type_of_acquired_focus(focus_type_e focus_type, char **stream_type, char **additional_info)
857 int ret = MM_ERROR_SOUND_NO_DATA;
859 focus_node_t *node = NULL;
863 if (focus_type == FOCUS_TYPE_BOTH) /* focus_type should be "playback" or "capture" */
864 return MM_ERROR_INVALID_ARGUMENT;
866 return MM_ERROR_INVALID_ARGUMENT;
868 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
870 /* Update list for dead process */
871 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
873 /* Find node to set reacquisition */
874 for (list = g_focus_node_list; list != NULL; list = list->next) {
875 node = (focus_node_t *)list->data;
876 if (node && !node->is_for_watch && (node->status & focus_type)) {
877 debug_msg("found a node : request_focus_type(%d), stream_type(%s)/additional info(%s) of acquired focus\n", focus_type, node->stream_type, node->option);
878 *stream_type = node->stream_type;
880 *additional_info = node->option[focus_type-1];
886 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
893 int mm_sound_mgr_focus_request_acquire(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;
899 bool need_to_trigger_cb = false;
900 bool need_to_trigger_watch_cb = true;
905 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
907 /* Update list for dead process */
908 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
910 for (list = g_focus_node_list; list != NULL; list = list->next) {
911 node = (focus_node_t *)list->data;
912 if (node && !node->is_for_watch && (node->pid == param->pid) && (node->handle_id == param->handle_id)) {
914 if ((my_node->status > FOCUS_STATUS_DEACTIVATED) && (my_node->status & param->request_type)) {
915 debug_error("focus status is already activated");
916 ret = MM_ERROR_SOUND_INVALID_STATE;
922 if (my_node == NULL) {
923 debug_error("node is null");
924 ret = MM_ERROR_INVALID_ARGUMENT;
928 /* check if the priority of any node is higher than its based on io direction */
929 for (list = g_focus_node_list; list != NULL; list = list->next) {
930 node = (focus_node_t *)list->data;
933 } else if (my_node == node || node->is_for_watch) {
935 } else if (param->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
936 (node->status & param->request_type)) {
937 if (node->status > FOCUS_STATUS_DEACTIVATED) {
938 if ((my_node->priority < node->priority)) {
939 ret = MM_ERROR_POLICY_BLOCKED;
940 need_to_trigger_cb = false;
943 need_to_trigger_cb = true;
949 if (need_to_trigger_cb) {
950 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
951 param_s->is_for_session = my_node->is_for_session;
952 for (list = g_focus_node_list; list != NULL; list = list->next) {
953 node = (focus_node_t *)list->data;
956 } else if (node == my_node || node->is_for_watch || (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session)) {
958 } else if (param_s->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
959 (node->status & param_s->request_type)) {
960 if (node->status > FOCUS_STATUS_DEACTIVATED) {
961 if (my_node->priority >= node->priority) {
962 /* do callback for interruption */
963 ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_RELEASE, node, param_s, my_node->stream_type);
965 debug_error("Fail to _focus_do_callback for COMMAND RELEASE to node[%x], ret[0x%x]\n", node, ret);
966 /* but, keep going */
969 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
970 need_to_trigger_watch_cb = false;
978 if (ret != MM_ERROR_POLICY_BLOCKED) {
979 /* copy additional info. */
980 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
981 if (param->request_type & (i+1))
982 MMSOUND_STRNCPY(my_node->option[i], param->option, MM_SOUND_NAME_NUM);
985 my_node->status |= param->request_type;
986 /* do watch callback due to the status of mine */
987 if (need_to_trigger_watch_cb)
988 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_ACQUIRE, my_node, param);
991 /* update taken information */
992 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
993 if (param->request_type & (i+1) && my_node->taken_by_id[i].pid) {
994 UPDATE_FOCUS_TAKEN_INFO(my_node, 0, 0, false);
998 _mm_sound_mgr_focus_list_dump();
999 _mm_sound_mgr_focus_watch_list_dump ();
1001 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1007 int mm_sound_mgr_focus_request_release (const _mm_sound_mgr_focus_param_t *param)
1009 int ret = MM_ERROR_NONE;
1011 focus_node_t *node = NULL;
1012 focus_node_t *my_node = NULL;
1013 bool need_to_trigger_watch_cb = true;
1014 bool need_to_trigger_cb = true;
1019 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1021 /* Update list for dead process */
1022 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1024 for (list = g_focus_node_list; list != NULL; list = list->next) {
1025 node = (focus_node_t *)list->data;
1026 if (node && !node->is_for_watch && (node->pid == param->pid) && (node->handle_id == param->handle_id)) {
1028 if (my_node->status == FOCUS_STATUS_DEACTIVATED) {
1029 debug_error("focus status is already deactivated");
1030 ret = MM_ERROR_SOUND_INVALID_STATE;
1032 } else if ((my_node->status != FOCUS_STATUS_ACTIVATED_BOTH) && (my_node->status != (focus_status_e)param->request_type)) {
1033 debug_error("request type is not matched with current focus type");
1034 ret = MM_ERROR_SOUND_INVALID_STATE;
1041 if (my_node == NULL) {
1042 debug_error("node is null");
1043 ret = MM_ERROR_INVALID_ARGUMENT;
1047 /* Check if there's activating focus for session for the same PID of incomming param*/
1048 if(my_node->is_for_session) {
1049 for (list = g_focus_node_list; list != NULL; list = list->next) {
1050 node = (focus_node_t *)list->data;
1053 } else if (node != my_node && node->pid == my_node->pid && node->is_for_session && !node->is_for_watch
1054 && my_node->status & node->status) {
1055 debug_error("focus for session for this pid is active, skip callbacks");
1056 need_to_trigger_watch_cb = false;
1057 need_to_trigger_cb = false;
1063 if (need_to_trigger_cb) {
1064 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
1065 param_s->is_for_session = my_node->is_for_session;
1066 for (list = g_focus_node_list; list != NULL; list = list->next) {
1067 node = (focus_node_t *)list->data;
1070 } else if (node == my_node || node->is_for_watch) {
1073 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1074 if (param_s->request_type & (i+1)) {
1075 if (node->taken_by_id[i].pid == param_s->pid && (node->taken_by_id[i].handle_id == param_s->handle_id || node->taken_by_id[i].by_session)) {
1076 /* do callback for resumption */
1077 ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, param_s, my_node->stream_type);
1079 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]\n", node, ret);
1081 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
1082 need_to_trigger_watch_cb = false;
1091 my_node->status &= ~(param->request_type);
1092 /* remove additional info. */
1093 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1094 if (!(my_node->status & (i+1)))
1095 memset(my_node->option[i], 0x0, MM_SOUND_NAME_NUM);
1097 /* do watch callback due to the status of mine */
1098 if (need_to_trigger_watch_cb)
1099 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_RELEASE, my_node, param);
1101 _mm_sound_mgr_focus_list_dump();
1102 _mm_sound_mgr_focus_watch_list_dump ();
1104 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1110 int mm_sound_mgr_focus_set_watch_cb (const _mm_sound_mgr_focus_param_t *param)
1112 int ret = MM_ERROR_NONE;
1114 focus_node_t *node = NULL;
1118 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1120 /* Update list for dead process */
1121 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1123 for (list = g_focus_node_list; list != NULL; list = list->next) {
1124 node = (focus_node_t *)list->data;
1125 if (node && (node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1126 debug_error("the node of pid[%d]/handle_id[%d] for watch focus is already created\n", param->pid, param->handle_id);
1127 ret = MM_ERROR_INVALID_ARGUMENT;
1132 node = g_malloc0(sizeof(focus_node_t));
1134 /* fill up information to the node */
1135 _mm_sound_mgr_focus_fill_info_from_msg(node, param);
1136 node->is_for_watch = true;
1137 node->status = param->request_type;
1139 g_focus_node_list = g_list_append(g_focus_node_list, node);
1140 if (g_focus_node_list) {
1141 debug_log("new focus node is added\n");
1143 debug_error("g_list_append failed\n");
1144 ret = MM_ERROR_SOUND_INTERNAL;
1148 _mm_sound_mgr_focus_watch_list_dump();
1150 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1156 int mm_sound_mgr_focus_unset_watch_cb (const _mm_sound_mgr_focus_param_t *param)
1158 int ret = MM_ERROR_SOUND_INTERNAL;
1160 focus_node_t *node = NULL;
1164 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1166 /* Update list for dead process */
1167 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1169 for (list = g_focus_node_list; list != NULL; list = list->next) {
1170 node = (focus_node_t *)list->data;
1171 if (node && (node->pid == param->pid) && (node->handle_id == param->handle_id) && (node->is_for_watch)) {
1172 debug_log("found the node of pid[%d]/handle_id[%d] for watch focus\n", param->pid, param->handle_id);
1173 __clear_focus_pipe(node);
1174 g_focus_node_list = g_list_remove(g_focus_node_list, node);
1176 ret = MM_ERROR_NONE;
1181 debug_error("could not find any node of pid[%d]/handle_id[%d] for watch focus\n", param->pid, param->handle_id);
1182 ret = MM_ERROR_INVALID_ARGUMENT;
1186 _mm_sound_mgr_focus_watch_list_dump();
1188 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1194 int mm_sound_mgr_focus_emergent_exit(const _mm_sound_mgr_focus_param_t *param)
1196 int ret = MM_ERROR_NONE;
1198 GList *list_s =NULL;
1199 focus_node_t *node = NULL;
1200 focus_node_t *my_node = NULL;
1205 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1207 /* Update list for dead process */
1208 g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1210 list = g_focus_node_list;
1212 node = (focus_node_t *)list->data;
1213 if (node && (node->pid == param->pid)) {
1214 debug_log("found pid node");
1215 if(node->is_for_watch) {
1216 debug_log("clearing watch cb of pid(%d) handle(%d)", node->pid, node->handle_id);
1217 __clear_focus_pipe(node);
1218 g_focus_node_list = g_list_remove(g_focus_node_list, node);
1219 list = g_focus_node_list;
1221 } else if (node->status == FOCUS_STATUS_DEACTIVATED) {
1222 debug_log("clearing deactivated focus node of pid(%d) hande(%d)", node->pid, node->handle_id);
1224 /* update info of nodes that are lost their focus by the process exited */
1225 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1226 node = (focus_node_t *)list_s->data;
1227 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1228 if (node && (node->taken_by_id[i].pid == param->pid)) {
1229 if (my_node->taken_by_id[i].pid) {
1230 UPDATE_FOCUS_TAKEN_INFO(node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, my_node->taken_by_id[i].by_session);
1232 UPDATE_FOCUS_TAKEN_INFO(node, 0, 0, false);
1237 __clear_focus_pipe(my_node);
1238 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1239 list = g_focus_node_list;
1241 } else { /* node that acquired focus */
1242 bool need_to_trigger_watch_cb = true;
1243 _mm_sound_mgr_focus_param_t param_s;
1244 debug_log("clearing activated focus node of pid(%d) handle(%d)", node->pid, node->handle_id);
1247 memset(¶m_s, 0x00, sizeof(_mm_sound_mgr_focus_param_t));
1248 param_s.pid = my_node->pid;
1249 param_s.handle_id = my_node->handle_id;
1250 param_s.request_type = my_node->status;
1251 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1252 node = (focus_node_t *)list_s->data;
1253 if (my_node->pid == node->pid || node->is_for_watch) {
1256 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1257 if (my_node->status & (i+1)) {
1258 if (node && (node->taken_by_id[i].pid == param_s.pid && node->taken_by_id[i].handle_id == param_s.handle_id)) {
1259 /* do callback for resumption */
1260 ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, ¶m_s, my_node->stream_type);
1262 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]\n", node, ret);
1264 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
1265 need_to_trigger_watch_cb = false;
1272 if (need_to_trigger_watch_cb) {
1273 ret = _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param_s.request_type, FOCUS_COMMAND_RELEASE, my_node, ¶m_s);
1275 debug_error("Fail to _focus_do_watch_callback, ret[0x%x]\n", ret);
1278 __clear_focus_pipe(my_node);
1279 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1280 list = g_focus_node_list;
1284 debug_log("node not found, next list = %p",list);
1288 _mm_sound_mgr_focus_list_dump();
1289 _mm_sound_mgr_focus_watch_list_dump ();
1291 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1298 int MMSoundMgrFocusInit(void)
1300 int ret = MM_ERROR_NONE;
1303 ret = __mm_sound_mgr_focus_dbus_get_stream_list(&g_stream_list);
1305 debug_error("failed to __mm_sound_mgr_ipc_dbus_get_stream_list()\n");
1311 int MMSoundMgrFocusFini(void)
1316 for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
1317 if (g_stream_list.stream_types[i]) {
1318 free (g_stream_list.stream_types[i]);
1323 return MM_ERROR_NONE;