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[] = {
54 char stream_type[MAX_STREAM_TYPE_LEN];
55 char ext_info[MM_SOUND_NAME_NUM];
59 #define UPDATE_FOCUS_TAKEN_INFO(x_postfix, x_node, x_pid, x_hid) do { \
60 debug_msg("updating node[%p], taken_"#x_postfix"[%d] : pid = [%d], handle_id = [%d]", x_node, i, x_pid, x_hid); \
61 x_node->taken_##x_postfix[i].pid = x_pid; \
62 x_node->taken_##x_postfix[i].handle_id = x_hid; \
65 #define CONTINUE_IF_LIST_DATA_IS_NULL(x_node, x_list) \
66 if (!((x_node) = (focus_node_t *)(x_list)->data)) \
69 #define CONTINUE_IF_NOT_MY_FOCUS_NODE(x_node, x_param) \
70 if ((x_node)->is_for_watch || ((x_node)->pid != (x_param)->pid) || ((x_node)->handle_id != (x_param)->handle_id)) \
73 static char* __get_focus_pipe_path(int instance_id, int handle, const char *postfix, bool is_watch)
79 path = g_strdup_printf("/tmp/FOCUS.%d.%d.wch", instance_id, handle);
81 path = g_strdup_printf("/tmp/FOCUS.%d.%d", instance_id, handle);
84 path2 = g_strconcat(path, postfix, NULL);
93 static void __clear_focus_pipe(focus_node_t *node)
95 char *filename = NULL;
96 char *filename2 = NULL;
100 if (!node->is_for_watch) {
101 filename = __get_focus_pipe_path(node->pid, node->handle_id, NULL, false);
102 filename2 = __get_focus_pipe_path(node->pid, node->handle_id, "r", false);
104 filename = __get_focus_pipe_path(node->pid, node->handle_id, NULL, true);
105 filename2 = __get_focus_pipe_path(node->pid, node->handle_id, "r", true);
108 if (remove(filename)) {
110 strerror_r(errno, str_error, sizeof(str_error));
111 debug_error("remove() failure, filename(%s), err[%s]", filename, str_error);
113 debug_log("removed file(%s)", filename);
118 if (remove(filename2)) {
120 strerror_r(errno, str_error, sizeof(str_error));
121 debug_error("remove() failure, filename2(%s), err[%s]", filename2, str_error);
123 debug_log("removed file(%s)", filename2);
131 static int _mm_sound_mgr_focus_get_priority_from_stream_type(int *priority, const char *stream_type)
133 int ret = MM_ERROR_NONE;
138 if (priority == NULL || stream_type == NULL) {
139 ret = MM_ERROR_INVALID_ARGUMENT;
140 debug_error("invalid argument, priority[%p], stream_type[%s], ret[0x%x]", priority, stream_type, ret);
142 for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
143 if (g_stream_list.stream_types[i] &&
144 !strncmp(g_stream_list.stream_types[i], stream_type, strlen(stream_type))) {
145 *priority = g_stream_list.priorities[i];
149 if (i == AVAIL_STREAMS_MAX) {
150 ret = MM_ERROR_NOT_SUPPORT_API;
151 debug_error("not supported stream_type[%s], ret[0x%x]", stream_type, ret);
153 debug_log("[%s] has priority of [%d]", stream_type, *priority);
161 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)
166 char *filename = NULL;
167 char *filename2 = NULL;
173 focus_cb_data cb_data;
175 if (!node || !stream_type) {
176 debug_error("[CB] invalid argument, node[%p], stream_type[%s]", node, stream_type);
180 memset(&cb_data, 0, sizeof(focus_cb_data));
181 cb_data.pid = node->pid;
182 cb_data.handle = node->handle_id;
183 cb_data.type = focus_type & node->status;
184 cb_data.state = (command == FOCUS_COMMAND_ACQUIRE) ? !FOCUS_STATUS_DEACTIVATED : FOCUS_STATUS_DEACTIVATED;
185 MMSOUND_STRNCPY(cb_data.stream_type, stream_type, MAX_STREAM_TYPE_LEN);
186 MMSOUND_STRNCPY(cb_data.ext_info, param->ext_info, MM_SOUND_NAME_NUM);
187 node->during_cb = true;
190 gettimeofday(&time, NULL);
191 starttime = time.tv_sec * 1000000 + time.tv_usec;
193 /**************************************
195 * Open callback cmd pipe
197 **************************************/
198 filename = __get_focus_pipe_path(cb_data.pid, cb_data.handle, NULL, true);
199 if (filename == NULL) {
200 debug_error("[CB] failed to get watch pipe");
203 if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
205 strerror_r(errno, str_error, sizeof(str_error));
206 debug_error("[CB] failed to open watch pipe (%s, err:%s)", filename, str_error);
210 /******************************************
212 * Open callback result pipe
213 * before writing callback cmd to pipe
215 ******************************************/
216 filename2 = __get_focus_pipe_path(cb_data.pid, cb_data.handle, "r", true);
217 if (filename2 == NULL) {
218 debug_error("[RETCB] failed to get watch return pipe");
221 if ((fd_FOCUS_R = open(filename2, O_RDONLY | O_NONBLOCK)) == -1) {
223 strerror_r(errno, str_error, sizeof(str_error));
224 debug_error("[RETCB] failed to open watch return pipe (%s, err:%s)", filename2, str_error);
228 /*******************************************
230 *******************************************/
231 if (write(fd_FOCUS, &cb_data, sizeof(cb_data)) == -1) {
233 strerror_r(errno, str_error, sizeof(str_error));
234 debug_error("[CB] failed to write (err:%s)", str_error);
238 /*********************************************
240 * Wait callback result msg
242 ********************************************/
246 debug_msg("[RETCB] wait WATCH CALLBACK (client pid=%d, cmd=%d, timeout=%d(ms))", cb_data.pid, command, CALLBACK_TIMEOUT);
247 pret = poll(&pfd, 1, CALLBACK_TIMEOUT);
249 debug_error("[RETCB] poll failed (%d)", pret);
252 if (pfd.revents & POLLIN) {
253 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
255 strerror_r(errno, str_error, sizeof(str_error));
256 debug_error("[RETCB] failed to read (err:%s)", str_error);
261 /* Calculate endtime and display*/
262 gettimeofday(&time, NULL);
263 endtime = time.tv_sec * 1000000 + time.tv_usec;
264 debug_msg("[RETCB] WATCH CALLBACK returned (cbtimelab=%d(ms), client pid=%d, return handle=%d)", ((endtime-starttime)/1000), cb_data.pid, ret);
266 /**************************************
268 * Close callback result pipe
270 **************************************/
272 node->during_cb = false;
280 if (fd_FOCUS != -1) {
284 if (fd_FOCUS_R != -1) {
290 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)
293 focus_node_t *node = NULL;
298 debug_error("[CB] my_node is null");
299 return MM_ERROR_INVALID_ARGUMENT;
302 for (list = g_focus_node_list; list != NULL; list = list->next) {
303 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
306 if (!node->is_for_watch || !(node->status & focus_type))
308 if (node->during_cb) {
309 debug_msg("it is about to invoke watch callback again during processing it, skip it");
313 _invoke_watch_callback(node, my_node->stream_type, focus_type, command, param);
318 return MM_ERROR_NONE;
321 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)
323 int res = MM_ERROR_NONE;
324 char *filename = NULL;
325 char *filename2 = NULL;
335 int flag_for_focus_type = 0;
336 int flag_for_taken_index = 0;
340 bool reacquisition_changed = false;
342 focus_cb_data cb_data;
344 debug_msg("for pid(%d) handle(%d)", victim_node->pid, victim_node->handle_id);
346 memset(&cb_data, 0, sizeof(focus_cb_data));
347 cb_data.pid = victim_node->pid;
348 cb_data.handle = victim_node->handle_id;
349 if (command == FOCUS_COMMAND_RELEASE) {
350 /* client will lost the acquired focus */
351 cb_data.type = assaulter_param->request_type & victim_node->status;
352 cb_data.state = FOCUS_STATUS_DEACTIVATED;
353 /* remove ext info. */
354 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
355 if (cb_data.type & (i+1)) {
356 memset(victim_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
357 victim_node->option[i] = 0;
361 /* client will gain the lost focus */
362 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
363 if ((victim_node->taken_by_id[i].pid == assaulter_param->pid) &&
364 ((victim_node->taken_by_id[i].handle_id == assaulter_param->handle_id))) {
365 flag_for_focus_type |= i + 1; /* playback:1, capture:2 */
368 cb_data.type = flag_for_focus_type & assaulter_param->request_type;
369 cb_data.state = !FOCUS_STATUS_DEACTIVATED;
371 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
372 if (cb_data.type & (i+1)) {
373 MMSOUND_STRNCPY(victim_node->ext_info[i], assaulter_param->ext_info, MM_SOUND_NAME_NUM);
374 victim_node->option[i] = assaulter_param->option;
378 MMSOUND_STRNCPY(cb_data.stream_type, assaulter_param->stream_type, MAX_STREAM_TYPE_LEN);
379 MMSOUND_STRNCPY(cb_data.ext_info, assaulter_param->ext_info, MM_SOUND_NAME_NUM);
380 cb_data.option = assaulter_param->option;
383 gettimeofday(&time, NULL);
384 starttime = time.tv_sec * 1000000 + time.tv_usec;
386 /**************************************
388 * Open callback cmd pipe
390 **************************************/
391 filename = __get_focus_pipe_path(cb_data.pid, cb_data.handle, NULL, false);
392 if (filename == NULL) {
393 debug_error("[CB] failed to get pipe");
397 if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
399 strerror_r(errno, str_error, sizeof(str_error));
400 debug_error("[CB] failed to open pipe (%s, err:%s)", filename, str_error);
405 /******************************************
407 * Open callback result pipe
408 * before writing callback cmd to pipe
410 ******************************************/
411 filename2 = __get_focus_pipe_path(cb_data.pid, cb_data.handle, "r", false);
412 if (filename2 == NULL) {
413 debug_error("[RETCB] failed to get return pipe");
417 if ((fd_FOCUS_R = open(filename2, O_RDONLY | O_NONBLOCK)) == -1) {
419 strerror_r(errno, str_error, sizeof(str_error));
420 debug_error("[RETCB] failed to open return pipe (%s, err:%s)", filename2, str_error);
425 /*******************************************
427 *******************************************/
428 if (write(fd_FOCUS, &cb_data, sizeof(cb_data)) == -1) {
430 strerror_r(errno, str_error, sizeof(str_error));
431 debug_error("[CB] failed to write (err:%s)", str_error);
436 /*********************************************
438 * Wait callback result msg
440 ********************************************/
444 debug_msg("[RETCB] wait CALLBACK (client pid=%d, handle=%d, cmd=%d, timeout=%d(ms))",
445 cb_data.pid, cb_data.handle, command, CALLBACK_TIMEOUT);
446 pret = poll(&pfd, 1, CALLBACK_TIMEOUT);
448 debug_error("[RETCB] poll failed (%d)", pret);
452 if (pfd.revents & POLLIN) {
453 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
455 strerror_r(errno, str_error, sizeof(str_error));
456 debug_error("[RETCB] failed to read (err:%s)", str_error);
460 /* ret contains data as below,
461 * |<--12bits--><--4bits (reacquisition)--><--16bits (handle)-->| */
462 ret_handle = (int)(ret & 0x0000ffff);
463 if (victim_node->reacquisition != (bool)((ret >> 16) & 0xf)) {
464 reacquisition_changed = true;
465 victim_node->reacquisition = (bool)((ret >> 16) & 0xf);
466 debug_msg("[RETCB] victim's reacquisition is changed to (%d)", victim_node->reacquisition);
470 /* Calculate endtime and display*/
471 gettimeofday(&time, NULL);
472 endtime = time.tv_sec * 1000000 + time.tv_usec;
473 debug_msg("[RETCB] CALLBACK returned (cbtimelab=%d(ms), client pid=%d, returned handle=%d)", ((endtime-starttime)/1000), cb_data.pid, ret_handle);
475 /* update victim node */
476 if (command == FOCUS_COMMAND_RELEASE) {
477 taken_pid = assaulter_param->pid;
478 taken_hid = assaulter_param->handle_id;
479 flag_for_taken_index = assaulter_param->request_type & victim_node->status;
483 flag_for_taken_index = assaulter_param->request_type;
486 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
487 if (flag_for_taken_index & (i+1)) {
489 focus_node_t *node = NULL;
491 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))) {
493 debug_error("skip updating victim node");
496 if (reacquisition_changed) {
497 if (!victim_node->reacquisition) {
498 for (list = g_focus_node_list; list != NULL; list = list->next) {
499 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
500 if (node->taken_by_id[i].pid == victim_node->pid) {
501 UPDATE_FOCUS_TAKEN_INFO(backup, node, node->taken_by_id[i].pid, node->taken_by_id[i].handle_id);
502 UPDATE_FOCUS_TAKEN_INFO(by_id, node, taken_pid, taken_hid);
503 } else if (!list->next) {
504 UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, taken_pid, taken_hid);
505 UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, 0, 0);
509 UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, taken_pid, taken_hid);
510 UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, 0, 0);
513 if (victim_node->reacquisition)
514 UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, taken_pid, taken_hid);
516 UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, taken_pid, taken_hid);
521 if (command == FOCUS_COMMAND_RELEASE)
522 victim_node->status = victim_node->status & ~(cb_data.type);
523 else if (command == FOCUS_COMMAND_ACQUIRE)
524 victim_node->status = victim_node->status | cb_data.type;
526 if (strncmp(assaulter_param->stream_type, victim_node->stream_type, MAX_STREAM_TYPE_LEN))
527 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)assaulter_param->request_type, command, victim_node, assaulter_param);
536 if (fd_FOCUS != -1) {
540 if (fd_FOCUS_R != -1) {
548 static int _mm_sound_mgr_focus_list_dump()
550 int ret = MM_ERROR_NONE;
552 focus_node_t *node = NULL;
554 debug_msg("================================================ focus node list : start ===================================================");
555 for (list = g_focus_node_list; list != NULL; list = list->next) {
556 if ((node = (focus_node_t *)list->data) && !node->is_for_watch) {
557 debug_msg("*** pid[%5d]/handle_id[%2d]/[%14s]:priority[%2d],status[%s],taken_by[P(%5d/%2d)C(%5d/%2d)],option[0x%x/0x%x],ext_info[%s/%s]",
558 node->pid, node->handle_id, node->stream_type, node->priority, focus_status_str[node->status],
559 node->taken_by_id[0].pid, node->taken_by_id[0].handle_id,
560 node->taken_by_id[1].pid, node->taken_by_id[1].handle_id,
561 node->option[0], node->option[1],
562 node->ext_info[0], node->ext_info[1]);
565 debug_msg("================================================ focus node list : end =====================================================");
570 static int _mm_sound_mgr_focus_watch_list_dump()
572 int ret = MM_ERROR_NONE;
574 focus_node_t *node = NULL;
576 debug_msg("============================================= focus watch node list : start =================================================");
577 for (list = g_focus_node_list; list != NULL; list = list->next) {
578 if ((node = (focus_node_t *)list->data) && node->is_for_watch)
579 debug_msg("*** pid[%5d]/handle_id[%d]/watch on focus status[%s]",
580 node->pid, node->handle_id, focus_status_str[node->status]);
582 debug_msg("============================================= focus watch node list : end ===================================================");
587 static void _mm_sound_mgr_focus_fill_info_from_msg(focus_node_t *node, const _mm_sound_mgr_focus_param_t *msg)
590 node->pid = msg->pid;
591 node->handle_id = msg->handle_id;
592 node->callback = msg->callback;
593 node->cbdata = msg->cbdata;
599 int mm_sound_mgr_focus_create_node(const _mm_sound_mgr_focus_param_t *param)
601 int ret = MM_ERROR_NONE;
603 focus_node_t *node = NULL;
608 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
610 for (list = g_focus_node_list; list != NULL; list = list->next) {
611 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
612 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
614 debug_error("the node of pid[%d]/handle_id[%d] is already created", param->pid, param->handle_id);
615 ret = MM_ERROR_INVALID_ARGUMENT;
619 /* get priority from stream type */
620 ret = _mm_sound_mgr_focus_get_priority_from_stream_type(&priority, param->stream_type);
624 node = g_malloc0(sizeof(focus_node_t));
626 /* fill up information to the node */
627 _mm_sound_mgr_focus_fill_info_from_msg(node, param);
628 node->priority = priority;
629 node->status = FOCUS_STATUS_DEACTIVATED;
630 node->reacquisition = true;
631 MMSOUND_STRNCPY(node->stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
633 g_focus_node_list = g_list_append(g_focus_node_list, node);
634 if (g_focus_node_list) {
635 debug_log("new focus node is added");
637 debug_error("g_list_append failed");
638 ret = MM_ERROR_SOUND_INTERNAL;
642 _mm_sound_mgr_focus_list_dump();
644 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
650 int mm_sound_mgr_focus_destroy_node(const _mm_sound_mgr_focus_param_t *param)
652 int ret = MM_ERROR_NONE;
654 focus_node_t *node = NULL;
655 focus_node_t *my_node = NULL;
656 bool need_to_trigger = true;
661 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
663 for (list = g_focus_node_list; list != NULL; list = list->next) {
664 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
665 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
667 debug_log("found the node of pid[%d]/handle_id[%d]", param->pid, param->handle_id);
671 if (my_node == NULL) {
672 debug_error("could not find any node of pid[%d]/handle_id[%d]", param->pid, param->handle_id);
673 ret = MM_ERROR_INVALID_ARGUMENT;
677 if (need_to_trigger) {
678 bool need_to_trigger_watch_cb = true;
679 _mm_sound_mgr_focus_param_t *new_param = NULL;
681 if (!(new_param = g_malloc0(sizeof(_mm_sound_mgr_focus_param_t)))) {
682 debug_error("Fail to g_malloc0 for new_param");
685 new_param->pid = param->pid;
686 new_param->handle_id = param->handle_id;
687 new_param->request_type = my_node->status;
688 new_param->option = my_node->option[i];
689 MMSOUND_STRNCPY(new_param->stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
690 MMSOUND_STRNCPY(new_param->ext_info, my_node->ext_info[i], MM_SOUND_NAME_NUM);
692 for (list = g_focus_node_list; list != NULL; list = list->next) {
693 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
694 if (my_node == node || node->is_for_watch)
696 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
697 if (node->taken_by_id[i].pid != param->pid)
700 if (my_node->taken_by_id[i].pid) {
701 /* If exists update the taken focus info to my victim node */
702 if (node->taken_by_id[i].handle_id == param->handle_id)
703 UPDATE_FOCUS_TAKEN_INFO(by_id, node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id);
704 } else if (my_node->status & (i+1)) {
705 if (node->taken_by_id[i].handle_id == new_param->handle_id) {
706 /* do callback for resumption */
707 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, new_param)))
708 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%p], ret[0x%x]", node, ret);
709 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
710 need_to_trigger_watch_cb = false;
711 my_node->status &= ~(new_param->request_type);
717 if (need_to_trigger_watch_cb)
718 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)new_param->request_type, FOCUS_COMMAND_RELEASE, my_node, new_param);
724 /* Destroy my node */
725 __clear_focus_pipe(my_node);
726 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
729 _mm_sound_mgr_focus_list_dump();
730 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
736 int mm_sound_mgr_focus_set_reacquisition(const _mm_sound_mgr_focus_param_t *param)
738 int ret = MM_ERROR_NONE;
740 focus_node_t *node = NULL;
741 focus_node_t *my_node = NULL;
746 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
748 /* Find node to set reacquisition */
749 for (list = g_focus_node_list; list != NULL; list = list->next) {
750 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
751 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
753 if (node->reacquisition == param->reacquisition) {
754 debug_msg("it is already set as same value of reacquisition(%d)", param->reacquisition);
757 node->reacquisition = param->reacquisition;
758 debug_msg("found a node(pid[%d]/handle_id[%d]) to set reacquisition to (%d)", node->pid, node->handle_id, param->reacquisition);
762 if (my_node == NULL) {
763 debug_error("could not find any node of pid[%d]/handle_id[%d]", param->pid, param->handle_id);
764 ret = MM_ERROR_INVALID_ARGUMENT;
768 if (!param->reacquisition) {
769 for (list = g_focus_node_list; list != NULL; list = list->next) {
770 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
771 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
772 if (node->taken_by_id[i].pid == param->pid) {
773 /* victim node : append my node's taken info to my victim node */
774 if (my_node->taken_by_id[i].pid != 0) {
775 UPDATE_FOCUS_TAKEN_INFO(backup, node, node->taken_by_id[i].pid, node->taken_by_id[i].handle_id);
776 UPDATE_FOCUS_TAKEN_INFO(by_id, node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id);
778 } else if (!list->next) {
779 /* my node : backup and reset */
780 UPDATE_FOCUS_TAKEN_INFO(backup, my_node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id);
781 UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, 0, 0);
786 for (list = g_focus_node_list; list != NULL; list = list->next) {
787 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
788 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
789 /* rollback and reset backup info. */
790 if (node->taken_by_id[i].pid && (node->taken_by_id[i].pid == my_node->taken_backup[i].pid)) {
791 UPDATE_FOCUS_TAKEN_INFO(by_id, node, node->taken_backup[i].pid, node->taken_backup[i].handle_id);
792 UPDATE_FOCUS_TAKEN_INFO(backup, node, 0, 0);
793 } else if (!list->next) {
794 UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, my_node->taken_backup[i].pid, my_node->taken_backup[i].handle_id);
795 UPDATE_FOCUS_TAKEN_INFO(backup, my_node, 0, 0);
802 _mm_sound_mgr_focus_list_dump();
803 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
809 int mm_sound_mgr_focus_get_stream_type_of_acquired_focus(focus_type_e focus_type, char **stream_type, int *option, char **ext_info)
811 int ret = MM_ERROR_SOUND_NO_DATA;
813 focus_node_t *node = NULL;
817 if (!stream_type || !option)
818 return MM_ERROR_INVALID_ARGUMENT;
820 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
822 /* Find node to set reacquisition */
823 for (list = g_focus_node_list; list != NULL; list = list->next) {
824 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
825 if (!node->is_for_watch && (node->status & focus_type)) {
826 int index = focus_type - 1;
828 debug_msg("found a node : request_focus_type(%d), stream_type(%s)/ext info(%s) of acquired focus",
829 focus_type, node->stream_type, node->ext_info[index]);
831 *stream_type = node->stream_type;
832 *option = node->option[index];
834 *ext_info = node->ext_info[index];
840 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
847 static void update_reacquisition_with_released_state(focus_node_t *node, int direction)
850 debug_error("node is null");
853 if (direction >= NUM_OF_STREAM_IO_TYPE) {
854 debug_error("invalid direction(%d)", direction);
859 int mm_sound_mgr_focus_request_acquire(const _mm_sound_mgr_focus_param_t *param)
861 int ret = MM_ERROR_NONE;
863 focus_node_t *node = NULL;
864 focus_node_t *my_node = NULL;
865 bool need_to_trigger_cb = false;
866 bool need_to_trigger_watch_cb = true;
871 if (!param->is_in_thread)
872 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
874 for (list = g_focus_node_list; list != NULL; list = list->next) {
875 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
876 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
879 if ((my_node->status > FOCUS_STATUS_DEACTIVATED) && (my_node->status & param->request_type)) {
880 debug_error("focus status is already activated");
881 ret = MM_ERROR_SOUND_INVALID_STATE;
886 if (my_node == NULL) {
887 debug_error("node is null");
888 ret = MM_ERROR_INVALID_ARGUMENT;
892 /* check if the priority of any node is higher than its based on io direction */
893 for (list = g_focus_node_list; list != NULL; list = list->next) {
894 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
895 if (my_node == node || node->is_for_watch)
897 if (param->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
898 (node->status & param->request_type)) {
899 if (node->status <= FOCUS_STATUS_DEACTIVATED)
902 if ((my_node->priority < node->priority)) {
903 ret = MM_ERROR_POLICY_BLOCKED;
904 need_to_trigger_cb = false;
907 need_to_trigger_cb = true;
912 if (need_to_trigger_cb) {
913 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
914 MMSOUND_STRNCPY(param_s->stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
915 for (list = g_focus_node_list; list != NULL; list = list->next) {
916 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
917 if (node == my_node || node->is_for_watch)
919 if (param_s->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
920 (node->status & param_s->request_type)) {
921 if (node->status <= FOCUS_STATUS_DEACTIVATED)
923 if (my_node->priority >= node->priority) {
924 /* do callback for interruption */
925 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_RELEASE, node, param_s))) {
926 debug_error("Fail to _focus_do_callback for COMMAND RELEASE to node[%p], ret[0x%x]", node, ret);
927 /* but, keep going */
930 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN))
931 need_to_trigger_watch_cb = false;
937 if (ret != MM_ERROR_POLICY_BLOCKED) {
939 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
940 if (param->request_type & (i+1)) {
941 MMSOUND_STRNCPY(my_node->ext_info[i], param->ext_info, MM_SOUND_NAME_NUM);
942 my_node->option[i] = param->option;
943 update_reacquisition_with_released_state(my_node, i);
947 my_node->status |= param->request_type;
948 /* do watch callback due to the status of mine */
949 if (need_to_trigger_watch_cb)
950 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_ACQUIRE, my_node, param);
952 /* update taken information */
953 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
954 if (param->request_type & (i+1)) {
955 UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, 0, 0);
956 UPDATE_FOCUS_TAKEN_INFO(backup, my_node, 0, 0);
961 _mm_sound_mgr_focus_list_dump();
962 _mm_sound_mgr_focus_watch_list_dump();
964 if (!param->is_in_thread)
965 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
971 int mm_sound_mgr_focus_request_release(const _mm_sound_mgr_focus_param_t *param)
973 int ret = MM_ERROR_NONE;
975 focus_node_t *node = NULL;
976 focus_node_t *my_node = NULL;
977 bool need_to_trigger_watch_cb = true;
978 bool need_to_trigger_cb = true;
983 if (!param->is_in_thread)
984 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
986 for (list = g_focus_node_list; list != NULL; list = list->next) {
987 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
988 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
991 if (my_node->status == FOCUS_STATUS_DEACTIVATED) {
992 debug_error("focus status is already deactivated");
993 ret = MM_ERROR_SOUND_INVALID_STATE;
995 } else if ((my_node->status != FOCUS_STATUS_ACTIVATED_BOTH) && (my_node->status != (focus_status_e)param->request_type)) {
996 debug_error("request type is not matched with current focus type");
997 ret = MM_ERROR_SOUND_INVALID_STATE;
1003 if (my_node == NULL) {
1004 debug_error("node is null");
1005 ret = MM_ERROR_INVALID_ARGUMENT;
1009 if (need_to_trigger_cb) {
1010 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
1011 MMSOUND_STRNCPY(param_s->stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
1012 for (list = g_focus_node_list; list != NULL; list = list->next) {
1013 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1014 if (node == my_node || node->is_for_watch)
1016 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1017 if (param_s->request_type & (i+1)) {
1018 if (node->taken_by_id[i].pid == param_s->pid &&
1019 node->taken_by_id[i].handle_id == param_s->handle_id) {
1020 /* do callback for resumption */
1021 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, param_s)))
1022 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%p], ret[0x%x]", node, ret);
1023 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN))
1024 need_to_trigger_watch_cb = false;
1031 my_node->status &= ~(param->request_type);
1032 /* remove ext info. */
1033 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1034 if (!(my_node->status & (i+1))) {
1035 memset(my_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
1036 my_node->option[i] = 0;
1039 /* do watch callback due to the status of mine */
1040 if (need_to_trigger_watch_cb)
1041 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_RELEASE, my_node, param);
1043 _mm_sound_mgr_focus_list_dump();
1044 _mm_sound_mgr_focus_watch_list_dump();
1046 if (!param->is_in_thread)
1047 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1053 int mm_sound_mgr_focus_add_watch_node(const _mm_sound_mgr_focus_param_t *param)
1055 int ret = MM_ERROR_NONE;
1057 focus_node_t *node = NULL;
1061 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1063 for (list = g_focus_node_list; list != NULL; list = list->next) {
1064 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1065 if ((node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1066 debug_error("the node of pid[%d]/handle_id[%d] for watch focus is already created", param->pid, param->handle_id);
1067 ret = MM_ERROR_INVALID_ARGUMENT;
1072 node = g_malloc0(sizeof(focus_node_t));
1074 /* fill up information to the node */
1075 _mm_sound_mgr_focus_fill_info_from_msg(node, param);
1076 node->is_for_watch = true;
1077 node->status = param->request_type;
1079 g_focus_node_list = g_list_append(g_focus_node_list, node);
1080 if (g_focus_node_list) {
1081 debug_log("new focus node is added");
1083 debug_error("g_list_append failed");
1084 ret = MM_ERROR_SOUND_INTERNAL;
1088 _mm_sound_mgr_focus_watch_list_dump();
1090 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1096 int mm_sound_mgr_focus_remove_watch_node(const _mm_sound_mgr_focus_param_t *param)
1098 int ret = MM_ERROR_SOUND_INTERNAL;
1100 focus_node_t *node = NULL;
1104 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1106 for (list = g_focus_node_list; list != NULL; list = list->next) {
1107 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1108 if ((node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1109 debug_log("found the node of pid[%d]/handle_id[%d] for watch focus", param->pid, param->handle_id);
1110 __clear_focus_pipe(node);
1111 g_focus_node_list = g_list_remove(g_focus_node_list, node);
1113 ret = MM_ERROR_NONE;
1118 debug_error("could not find any node of pid[%d]/handle_id[%d] for watch focus", param->pid, param->handle_id);
1119 ret = MM_ERROR_INVALID_ARGUMENT;
1123 _mm_sound_mgr_focus_watch_list_dump();
1125 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1131 int mm_sound_mgr_focus_deliver(const _mm_sound_mgr_focus_param_t *param)
1133 int ret = MM_ERROR_NONE;
1135 focus_node_t *src_node = NULL;
1136 focus_node_t *dst_node = NULL;
1141 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1143 for (list = g_focus_node_list; list != NULL; list = list->next) {
1144 CONTINUE_IF_LIST_DATA_IS_NULL(src_node, list);
1145 if ((src_node->pid == param->pid) && (src_node->handle_id == param->handle_id)) {
1146 debug_log("SRC: found the node of pid[%d]/handle_id[%d] for watch focus",
1147 param->pid, param->handle_id);
1151 if (src_node == NULL) {
1152 debug_error("could not find the source node of param, pid[%d]/handle_id[%d]",
1153 param->pid, param->handle_id);
1154 ret = MM_ERROR_INVALID_ARGUMENT;
1158 if (!(src_node->status & param->request_type)) {
1159 debug_error("invalid request type(0x%x), src_node->status(0x%x)",
1160 param->request_type, src_node->status);
1161 ret = MM_ERROR_SOUND_INVALID_STATE;
1165 for (list = g_focus_node_list; list != NULL; list = list->next) {
1166 CONTINUE_IF_LIST_DATA_IS_NULL(dst_node, list);
1167 if ((dst_node->pid == param->pid) && (dst_node->handle_id == param->handle_id_dst)) {
1168 debug_log("DST: found the destination node of param, pid[%d]/handle_id[%d]",
1169 param->pid, param->handle_id_dst);
1173 if (dst_node == NULL) {
1174 debug_error("could not find the destination node of param, pid[%d]/handle_id[%d]",
1175 param->pid, param->handle_id_dst);
1176 ret = MM_ERROR_INVALID_ARGUMENT;
1180 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1181 focus_node_t *node = NULL;
1182 if (!(param->request_type & (i+1)))
1185 for (list = g_focus_node_list; list != NULL; list = list->next) {
1186 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1187 if ((node->taken_by_id[i].pid == src_node->pid) &&
1188 (node->taken_by_id[i].handle_id == src_node->handle_id)) {
1189 debug_log("found the node pid[%d]/handle_id[%d] that focus was taken by this src node, update it",
1190 node->pid, node->handle_id);
1191 UPDATE_FOCUS_TAKEN_INFO(by_id, node, dst_node->pid, dst_node->handle_id);
1193 if ((node->taken_backup[i].pid == src_node->pid) &&
1194 (node->taken_backup[i].handle_id == src_node->handle_id)) {
1195 debug_log("found the node pid[%d]/handle_id[%d] that focus was taken by this src node and set reacquisition to false, update it",
1196 node->pid, node->handle_id);
1197 UPDATE_FOCUS_TAKEN_INFO(backup, node, dst_node->pid, dst_node->handle_id);
1201 dst_node->status |= (i+1);
1202 UPDATE_FOCUS_TAKEN_INFO(by_id, dst_node, 0, 0);
1203 UPDATE_FOCUS_TAKEN_INFO(backup, dst_node, 0, 0);
1204 MMSOUND_STRNCPY(dst_node->ext_info[i], src_node->ext_info[i], MM_SOUND_NAME_NUM);
1205 dst_node->option[i] = src_node->option[i];
1207 src_node->status &= ~(i+1);
1208 memset(src_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
1209 src_node->option[i] = 0;
1212 _mm_sound_mgr_focus_list_dump();
1215 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1221 int mm_sound_mgr_focus_emergent_exit_by_id(int id)
1223 int ret = MM_ERROR_NONE;
1225 GList *list_s = NULL;
1226 focus_node_t *node = NULL;
1227 focus_node_t *my_node = NULL;
1232 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1234 list = g_focus_node_list;
1236 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1237 if (node->handle_id != id) {
1241 if (node->is_for_watch) {
1242 debug_log("clearing watch cb of pid(%d) handle(%d)", node->pid, node->handle_id);
1243 __clear_focus_pipe(node);
1244 g_focus_node_list = g_list_remove(g_focus_node_list, node);
1245 list = g_focus_node_list;
1249 if (node->status == FOCUS_STATUS_DEACTIVATED) {
1250 debug_log("clearing deactivated focus node of pid(%d) hande(%d)", node->pid, node->handle_id);
1252 /* update info of nodes that are lost their focus by the process exited */
1253 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1254 CONTINUE_IF_LIST_DATA_IS_NULL(node, list_s);
1255 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1256 if (node->taken_by_id[i].handle_id == id) {
1257 if (my_node->taken_by_id[i].handle_id)
1258 UPDATE_FOCUS_TAKEN_INFO(by_id, node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id);
1260 UPDATE_FOCUS_TAKEN_INFO(by_id, node, 0, 0);
1264 __clear_focus_pipe(my_node);
1265 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1266 list = g_focus_node_list;
1268 } else { /* node that acquired focus */
1269 bool need_to_trigger_watch_cb = true;
1270 _mm_sound_mgr_focus_param_t param_s;
1271 debug_log("clearing activated focus node of pid(%d) handle(%d)", node->pid, node->handle_id);
1274 memset(¶m_s, 0x00, sizeof(_mm_sound_mgr_focus_param_t));
1275 param_s.pid = my_node->pid;
1276 param_s.handle_id = my_node->handle_id;
1277 param_s.request_type = my_node->status;
1278 MMSOUND_STRNCPY(param_s.stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
1279 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1280 CONTINUE_IF_LIST_DATA_IS_NULL(node, list_s);
1281 if (my_node->handle_id == node->handle_id || node->is_for_watch)
1283 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1284 if (!(my_node->status & (i+1)))
1286 if (node->taken_by_id[i].handle_id == param_s.handle_id) {
1287 /* do callback for resumption */
1288 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, ¶m_s)))
1289 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%p], ret[0x%x]", node, ret);
1290 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN))
1291 need_to_trigger_watch_cb = false;
1295 if (need_to_trigger_watch_cb) {
1296 if ((ret = _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param_s.request_type, FOCUS_COMMAND_RELEASE, my_node, ¶m_s)))
1297 debug_error("Fail to _focus_do_watch_callback, ret[0x%x]", ret);
1300 __clear_focus_pipe(my_node);
1301 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1302 list = g_focus_node_list;
1306 _mm_sound_mgr_focus_list_dump();
1307 _mm_sound_mgr_focus_watch_list_dump();
1309 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1315 int MMSoundMgrFocusInit(void)
1317 int ret = MM_ERROR_NONE;
1320 ret = __mm_sound_mgr_focus_dbus_get_stream_list(&g_stream_list);
1322 debug_error("failed to __mm_sound_mgr_focus_dbus_get_stream_list()");
1328 int MMSoundMgrFocusFini(void)
1333 for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
1334 if (g_stream_list.stream_types[i])
1335 free(g_stream_list.stream_types[i]);
1339 return MM_ERROR_NONE;