d614b781d3ac925153fbb8683f37a7f2597d38f7
[platform/core/multimedia/libmm-sound.git] / focus_server / mm_sound_mgr_focus.c
1 /*
2  * libmm-sound
3  *
4  * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Sangchul Lee <sc11.lee@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include "include/mm_sound_mgr_focus.h"
26 #include "../include/mm_sound_common.h"
27
28 #include <mm_debug.h>
29 #include <poll.h>
30 #include <fcntl.h>
31
32 #include "include/mm_sound_mgr_focus_dbus.h"
33 #include "../include/mm_sound_utils.h"
34 #include <sys/time.h>
35
36 #define CALLBACK_TIMEOUT          2500 /* millisecond */
37
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;
41
42 static const char* focus_status_str[] =
43 {
44         "DEACTIVATED",
45         "P ACTIVATED",
46         "C ACTIVATED",
47         "B ACTIVATED",
48 };
49
50 typedef struct {
51         int pid;
52         int handle;
53         int type;
54         int state;
55         char stream_type[MAX_STREAM_TYPE_LEN];
56         char ext_info[MM_SOUND_NAME_NUM];
57         int option;
58 } focus_cb_data;
59
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); \
66                 g_free (node); \
67         } \
68 } while (0)
69
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; \
75 } while (0)
76
77 #define CONTINUE_IF_LIST_DATA_IS_NULL(x_node, x_list) \
78         if (!((x_node) = (focus_node_t *)(x_list)->data)) \
79                 continue; \
80
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)) \
84                 continue; \
85
86 static char* __get_focus_pipe_path(int instance_id, int handle, const char* postfix, bool is_watch)
87 {
88         gchar* path = NULL;
89         gchar* path2 = NULL;
90
91         if (is_watch) {
92                 path = g_strdup_printf("/tmp/FOCUS.%d.%d.wch", instance_id, handle);
93         } else {
94                 path = g_strdup_printf("/tmp/FOCUS.%d.%d", instance_id, handle);
95         }
96
97         if (postfix) {
98                 path2 = g_strconcat(path, postfix, NULL);
99                 g_free (path);
100                 path = NULL;
101                 return path2;
102         }
103
104         return path;
105 }
106
107 static void __clear_focus_pipe(focus_node_t *node)
108 {
109         char *filename = NULL;
110         char *filename2 = NULL;
111
112         debug_fenter();
113
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);
117         } else {
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);
120         }
121         if (filename) {
122                 if (remove(filename))
123                         debug_error("remove() failure, filename(%s), errno(%d)", filename, errno);
124                 else
125                         debug_log("removed file(%s)", filename);
126                 free(filename);
127         }
128         if (filename2) {
129                 if (remove(filename2))
130                         debug_error("remove() failure, filename2(%s), errno(%d)", filename2, errno);
131                 else
132                         debug_log("removed file(%s)", filename2);
133                 free(filename2);
134         }
135
136         debug_fleave();
137 }
138
139 static void _clear_focus_node_list_func(focus_node_t *node, gpointer user_data)
140 {
141         CLEAR_DEAD_NODE_LIST(g_focus_node_list);
142 }
143
144 static int _mm_sound_mgr_focus_get_priority_from_stream_type(int *priority, const char *stream_type)
145 {
146         int ret = MM_ERROR_NONE;
147         int i = 0;
148
149         debug_fenter();
150
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);
154         } else {
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];
159                                 break;
160                         }
161                 }
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);
165                 } else {
166                         debug_log("[%s] has priority of [%d]", stream_type, *priority);
167                 }
168         }
169
170         debug_fleave();
171         return ret;
172 }
173
174 static bool _check_session_node_exist(int pid)
175 {
176         GList *list = NULL;
177         focus_node_t *node = NULL;
178
179         for (list = g_focus_node_list; list != NULL; list = list->next) {
180                 node = (focus_node_t *)list->data;
181                 if (node->pid != pid)
182                         continue;
183                 if (node->is_for_monitor)
184                         continue;
185                 if (node->is_for_session)
186                         return true;
187         }
188
189         debug_msg("session node for pid[%d] does not exist", pid);
190
191         return false;
192 }
193
194 static bool _check_session_watch_node_exist(int pid)
195 {
196         GList *list = NULL;
197         focus_node_t *node = NULL;
198
199         for (list = g_focus_node_list; list != NULL; list = list->next) {
200                 node = (focus_node_t *)list->data;
201                 if (node->pid != pid)
202                         continue;
203                 if (!node->is_for_watch)
204                         continue;
205                 if (node->is_for_monitor)
206                         continue;
207                 if (node->is_for_session)
208                         return true;
209         }
210
211         debug_msg("session watch node for pid[%d] does not exist", pid);
212
213         return false;
214 }
215
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)
217 {
218         int ret = -1;
219         int pret = 0;
220         struct pollfd pfd;
221         char *filename = NULL;
222         char *filename2 = NULL;
223         struct timeval time;
224         int starttime = 0;
225         int endtime = 0;
226         int fd_FOCUS_R = -1;
227         int fd_FOCUS = -1;
228         focus_cb_data cb_data;
229
230         if (!node || !stream_type) {
231                 debug_error("[CB] invalid argument, node[%p], stream_type[%s]", node, stream_type);
232                 return;
233         }
234
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;
243
244         /* Set start time */
245         gettimeofday(&time, NULL);
246         starttime = time.tv_sec * 1000000 + time.tv_usec;
247
248         /**************************************
249          *
250          * Open callback cmd pipe
251          *
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");
256                 goto RELEASE;
257         }
258         if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
259                 char str_error[256];
260                 strerror_r(errno, str_error, sizeof(str_error));
261                 debug_error("[CB] failed to open watch pipe (%s, err:%s)", filename, str_error);
262                 goto RELEASE;
263         }
264
265         /******************************************
266          *
267          * Open callback result pipe
268          * before writing callback cmd to pipe
269          *
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");
274                 goto RELEASE;
275         }
276         if ((fd_FOCUS_R= open(filename2, O_RDONLY|O_NONBLOCK)) == -1) {
277                 char str_error[256];
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);
280                 goto RELEASE;
281         }
282
283         /*******************************************
284          * Write Callback msg
285          *******************************************/
286         if (write(fd_FOCUS, &cb_data ,sizeof(cb_data)) == -1) {
287                 char str_error[256];
288                 strerror_r(errno, str_error, sizeof(str_error));
289                 debug_error("[CB] failed to write (err:%s)", str_error);
290                 goto RELEASE;
291         }
292
293         /*********************************************
294          *
295          * Wait callback result msg
296          *
297          ********************************************/
298         pfd.fd = fd_FOCUS_R;
299         pfd.events = POLLIN;
300         pfd.revents = 0;
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);
303         if (pret < 0) {
304                 debug_error("[RETCB] poll failed (%d)", pret);
305                 goto RELEASE;
306         }
307         if (pfd.revents & POLLIN) {
308                 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
309                         char str_error[256];
310                         strerror_r(errno, str_error, sizeof(str_error));
311                         debug_error("[RETCB] failed to read (err:%s)", str_error);
312                         goto RELEASE;
313                 }
314         }
315
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);
320
321         /**************************************
322          *
323          * Close callback result pipe
324          *
325          **************************************/
326 RELEASE:
327         node->during_cb = false;
328
329         g_free(filename);
330         filename = NULL;
331
332         g_free(filename2);
333         filename2 = NULL;
334
335         if (fd_FOCUS != -1) {
336                 close(fd_FOCUS);
337                 fd_FOCUS = -1;
338         }
339         if (fd_FOCUS_R != -1) {
340                 close(fd_FOCUS_R);
341                 fd_FOCUS_R = -1;
342         }
343 }
344
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)
347 {
348         GList *list = NULL;
349         focus_node_t *node = NULL;
350
351         debug_fenter();
352
353         if (!my_node) {
354                 debug_error("[CB] my_node is null");
355                 return MM_ERROR_INVALID_ARGUMENT;
356         }
357
358         for (list = g_focus_node_list; list != NULL; list = list->next) {
359                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
360                 if (node == my_node)
361                         continue;
362                 if (!node->is_for_watch || !node->is_for_monitor || !node->is_for_session)
363                         continue;
364                 if (!(node->status & focus_type))
365                         continue;
366                 /* check if it meets the condition to trigger monitor callback */
367                 if (!_check_session_watch_node_exist(node->pid))
368                         continue;
369
370                 _invoke_watch_callback(node, my_node->stream_type, focus_type, command, param);
371         }
372
373         debug_fleave();
374
375         return MM_ERROR_NONE;
376 }
377
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)
379 {
380         GList *list = NULL;
381         focus_node_t *node = NULL;
382
383         debug_fenter();
384
385         if (!my_node) {
386                 debug_error("[CB] my_node is null");
387                 return MM_ERROR_INVALID_ARGUMENT;
388         }
389
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)
393                         continue;
394                 if (node == my_node || !(node->pid == my_node->pid && my_node->is_for_session))
395                         continue;
396                 if (!(node->status & focus_type))
397                         continue;
398                 /* check if it meets the condition to trigger monitor callback */
399                 if (!_check_session_node_exist(node->pid))
400                         continue;
401
402                 _invoke_watch_callback(node, param->stream_type, focus_type, command, param);
403         }
404
405         debug_fleave();
406
407         return MM_ERROR_NONE;
408 }
409
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)
411 {
412         GList *list = NULL;
413         focus_node_t *node = NULL;
414
415         debug_fenter();
416
417         if (!my_node) {
418                 debug_error("[CB] my_node is null");
419                 return MM_ERROR_INVALID_ARGUMENT;
420         }
421
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))
425                         continue;
426                 if (!node->is_for_watch || !(node->status & focus_type))
427                         continue;
428                 if (node->is_for_monitor)
429                         continue;
430                 if (node->during_cb) {
431                         debug_msg("it is about to invoke watch callback again during processing it, skip it");
432                         continue;
433                 }
434
435                 _invoke_watch_callback(node, my_node->stream_type, focus_type, command, param);
436         }
437
438         debug_fleave();
439
440         return MM_ERROR_NONE;
441 }
442
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)
444 {
445         int res = MM_ERROR_NONE;
446         char *filename = NULL;
447         char *filename2 = NULL;
448         struct timeval time;
449         int starttime = 0;
450         int endtime = 0;
451         int fd_FOCUS_R = -1;
452         int fd_FOCUS = -1;
453         unsigned int ret;
454         struct pollfd pfd;
455         int pret = 0;
456         int i = 0;
457         int flag_for_focus_type = 0;
458         int flag_for_taken_index = 0;
459         int taken_pid = 0;
460         int taken_hid = 0;
461         int ret_handle = -1;
462         bool taken_by_session = false;
463         bool reacquisition_changed = false;
464
465         focus_cb_data cb_data;
466
467         debug_msg("for pid(%d) handle(%d)", victim_node->pid, victim_node->handle_id);
468
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;
481                         }
482                 }
483         } else {
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 */
488                         }
489                 }
490                 cb_data.type = flag_for_focus_type & assaulter_param->request_type;
491                 cb_data.state = !FOCUS_STATUS_DEACTIVATED;
492                 /* copy ext info. */
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;
497                         }
498                 }
499         }
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;
503
504         /* Set start time */
505         gettimeofday(&time, NULL);
506         starttime = time.tv_sec * 1000000 + time.tv_usec;
507
508         /**************************************
509          *
510          * Open callback cmd pipe
511          *
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");
516                 res = -1;
517                 goto RELEASE;
518         }
519         if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
520                 char str_error[256];
521                 strerror_r(errno, str_error, sizeof(str_error));
522                 debug_error("[CB] failed to open pipe (%s, err:%s)", filename, str_error);
523                 res = -1;
524                 goto RELEASE;
525         }
526
527         /******************************************
528          *
529          * Open callback result pipe
530          * before writing callback cmd to pipe
531          *
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");
536                 res = -1;
537                 goto RELEASE;
538         }
539         if ((fd_FOCUS_R = open(filename2,O_RDONLY|O_NONBLOCK)) == -1) {
540                 char str_error[256];
541                 strerror_r(errno, str_error, sizeof(str_error));
542                 debug_error("[RETCB] failed to open return pipe (%s, err:%s)", filename2, str_error);
543                 res = -1;
544                 goto RELEASE;
545         }
546
547         /*******************************************
548          * Write Callback msg
549          *******************************************/
550         if (write(fd_FOCUS, &cb_data, sizeof(cb_data)) == -1) {
551                 char str_error[256];
552                 strerror_r(errno, str_error, sizeof(str_error));
553                 debug_error("[CB] failed to write (err:%s)", str_error);
554                 res = -1;
555                 goto RELEASE;
556         }
557
558         /*********************************************
559          *
560          * Wait callback result msg
561          *
562          ********************************************/
563         pfd.fd = fd_FOCUS_R;
564         pfd.events = POLLIN;
565         pfd.revents = 0;
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);
568         if (pret < 0) {
569                 debug_error("[RETCB] poll failed (%d)", pret);
570                 res = -1;
571                 goto RELEASE;
572         }
573         if (pfd.revents & POLLIN) {
574                 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
575                         char str_error[256];
576                         strerror_r(errno, str_error, sizeof(str_error));
577                         debug_error("[RETCB] failed to read (err:%s)", str_error);
578                         res = -1;
579                         goto RELEASE;
580                 }
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);
588                 }
589         }
590
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);
595
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;
602         } else {
603                 taken_pid = 0;
604                 taken_hid = 0;
605                 taken_by_session = false;
606                 flag_for_taken_index = assaulter_param->request_type;
607         }
608
609         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
610                 if (flag_for_taken_index & (i+1)) {
611                         GList *list = NULL;
612                         focus_node_t *node = NULL;
613
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)))) {
615                                 /* skip */
616                                 debug_error("skip updating victim node");
617                                 continue;
618                         }
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);
629                                                 }
630                                         }
631                                 } else {
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);
640                                                 }
641                                         }
642                                 }
643                         } else {
644                                 if (victim_node->reacquisition)
645                                         UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, taken_pid, taken_hid, taken_by_session);
646                                 else
647                                         UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, taken_pid, taken_hid, taken_by_session);
648                         }
649                 }
650         }
651
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;
656
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);
660
661 RELEASE:
662         g_free(filename);
663         filename = NULL;
664
665         g_free(filename2);
666         filename2 = NULL;
667
668         if (fd_FOCUS != -1) {
669                 close(fd_FOCUS);
670                 fd_FOCUS = -1;
671         }
672         if (fd_FOCUS_R != -1) {
673                 close (fd_FOCUS_R);
674                 fd_FOCUS_R = -1;
675         }
676
677         return res;
678 }
679
680 static int _mm_sound_mgr_focus_list_dump ()
681 {
682         int ret = MM_ERROR_NONE;
683         GList *list = NULL;
684         focus_node_t *node = NULL;
685
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]);
693                 }
694         }
695         debug_msg("================================================ focus node list : end =====================================================");
696
697         return ret;
698 }
699
700 static int _mm_sound_mgr_focus_watch_list_dump()
701 {
702         int ret = MM_ERROR_NONE;
703         GList *list = NULL;
704         focus_node_t *node = NULL;
705
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);
711         }
712         debug_msg("============================================= focus watch node list : end ===================================================");
713
714         return ret;
715 }
716
717 static void _mm_sound_mgr_focus_fill_info_from_msg(focus_node_t *node, const _mm_sound_mgr_focus_param_t *msg)
718 {
719         debug_fenter();
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;
725
726         debug_fleave();
727         return;
728 }
729
730 int mm_sound_mgr_focus_create_node(const _mm_sound_mgr_focus_param_t *param)
731 {
732         int ret = MM_ERROR_NONE;
733         GList *list = NULL;
734         focus_node_t *node = NULL;
735         int priority = 0;
736
737         debug_fenter();
738
739         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
740
741         /* Update list for dead process */
742         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
743
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);
747
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;
750                 goto FINISH;
751         }
752
753         /* get priority from stream type */
754         ret = _mm_sound_mgr_focus_get_priority_from_stream_type(&priority, param->stream_type);
755         if (ret) {
756                 goto FINISH;
757         }
758         node = g_malloc0(sizeof(focus_node_t));
759
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);
766
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");
770         } else {
771                 debug_error("g_list_append failed");
772                 ret = MM_ERROR_SOUND_INTERNAL;
773                 g_free(node);
774         }
775
776         _mm_sound_mgr_focus_list_dump();
777 FINISH:
778         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
779
780         debug_fleave();
781         return ret;
782 }
783
784 int mm_sound_mgr_focus_destroy_node(const _mm_sound_mgr_focus_param_t *param)
785 {
786         int ret = MM_ERROR_NONE;
787         GList *list = NULL;
788         focus_node_t *node = NULL;
789         focus_node_t *my_node = NULL;
790         bool need_to_trigger = true;
791         int i = 0;
792
793         debug_fenter();
794
795         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
796
797         /* Update list for dead process */
798         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
799
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);
803
804                 debug_log("found the node of pid[%d]/handle_id[%d]", param->pid, param->handle_id);
805                 my_node = node;
806                 break;
807         }
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;
811                 goto FINISH;
812         }
813
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)
819                                 continue;
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;
823                                 break;
824                         }
825                 }
826         }
827
828         if (need_to_trigger) {
829                 bool need_to_trigger_watch_cb = true;
830                 _mm_sound_mgr_focus_param_t *new_param = NULL;
831
832                 if (!(new_param = g_malloc0(sizeof(_mm_sound_mgr_focus_param_t)))) {
833                         debug_error("Fail to g_malloc0 for new_param");
834                         goto CLEAR_NODE;
835                 }
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);
843
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)
847                                 continue;
848                         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
849                                 if (node->taken_by_id[i].pid != param->pid)
850                                         continue;
851
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);
858                                         }
859                                 } else if (my_node->status & (i+1)) {
860                                         if (node->is_for_session)
861                                                 continue;
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);
869                                                 }
870                                         }
871                                 }
872                         }
873                 }
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);
876
877                 g_free(new_param);
878         }
879
880 CLEAR_NODE:
881         /* Destroy my node  */
882         __clear_focus_pipe(my_node);
883         g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
884         g_free(my_node);
885 FINISH:
886         _mm_sound_mgr_focus_list_dump();
887         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
888
889         debug_fleave();
890         return ret;
891 }
892
893 int mm_sound_mgr_focus_set_reacquisition(const _mm_sound_mgr_focus_param_t *param)
894 {
895         int ret = MM_ERROR_NONE;
896         GList *list = NULL;
897         focus_node_t *node = NULL;
898         focus_node_t *my_node = NULL;
899         int i;
900
901         debug_fenter();
902
903         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
904
905         /* Update list for dead process */
906         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
907
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);
912
913                 if (node->reacquisition == param->reacquisition) {
914                         debug_msg("it is already set as same value of reacquisition(%d)", param->reacquisition);
915                         goto FINISH;
916                 }
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);
919                 my_node = node;
920                 break;
921         }
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;
925                 goto FINISH;
926         }
927
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);
937                                         }
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);
942                                 }
943                         }
944                 }
945         } else {
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);
956                                 }
957                         }
958                 }
959         }
960
961 FINISH:
962         _mm_sound_mgr_focus_list_dump();
963         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
964
965         debug_fleave();
966         return ret;
967 }
968
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)
970 {
971         int ret = MM_ERROR_SOUND_NO_DATA;
972         GList *list = NULL;
973         focus_node_t *node = NULL;
974
975         debug_fenter();
976
977         if (!stream_type || !option)
978                 return MM_ERROR_INVALID_ARGUMENT;
979
980         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
981
982         /* Update list for dead process */
983         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
984
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;
994
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]);
997
998                         *stream_type = node->stream_type;
999                         *option = node->option[index];
1000                         if (ext_info)
1001                                 *ext_info = node->ext_info[index];
1002                         ret = MM_ERROR_NONE;
1003                         break;
1004                 }
1005         }
1006
1007         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1008
1009         debug_fleave();
1010
1011         return ret;
1012 }
1013
1014 static void update_reacquisition_with_released_state(focus_node_t *node, int direction)
1015 {
1016         if (!node) {
1017                 debug_error("node is null");
1018                 return;
1019         }
1020         if (direction >= NUM_OF_STREAM_IO_TYPE) {
1021                 debug_error("invalid direction(%d)", direction);
1022                 return;
1023         }
1024
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;
1033         }
1034 }
1035
1036 int mm_sound_mgr_focus_request_acquire(const _mm_sound_mgr_focus_param_t *param)
1037 {
1038         int ret = MM_ERROR_NONE;
1039         GList *list = NULL;
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;
1045         int i;
1046
1047         debug_fenter();
1048
1049         if (!param->is_in_thread)
1050                 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1051
1052         /* Update list for dead process */
1053         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1054
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);
1058
1059                 my_node = node;
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;
1063                         goto FINISH;
1064                 }
1065         }
1066
1067         if (my_node == NULL) {
1068                 debug_error("node is null");
1069                 ret = MM_ERROR_INVALID_ARGUMENT;
1070                 goto FINISH;
1071         }
1072
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)
1077                         continue;
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)
1081                                 continue;
1082
1083                         if ((my_node->priority < node->priority)) {
1084                                 ret = MM_ERROR_POLICY_BLOCKED;
1085                                 need_to_trigger_cb = false;
1086                                 break;
1087                         } else {
1088                                 need_to_trigger_cb = true;
1089                         }
1090                 }
1091         }
1092
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)
1100                                 continue;
1101                         if (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session)
1102                                 continue;
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)
1106                                         continue;
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;
1113                                         }
1114                                         if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN))
1115                                                 need_to_trigger_watch_cb = false;
1116
1117                                         need_to_trigger_monitor_cb = false;
1118                                 }
1119                         }
1120                 }
1121         }
1122
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);
1130                         }
1131                 }
1132                 /* update status */
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);
1139
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);
1145                         }
1146                 }
1147         }
1148
1149         _mm_sound_mgr_focus_list_dump();
1150         _mm_sound_mgr_focus_watch_list_dump ();
1151 FINISH:
1152         if (!param->is_in_thread)
1153                 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1154
1155         debug_fleave();
1156         return ret;
1157 }
1158
1159 int mm_sound_mgr_focus_request_release(const _mm_sound_mgr_focus_param_t *param)
1160 {
1161         int ret = MM_ERROR_NONE;
1162         GList *list = NULL;
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;
1168         int i = 0;
1169
1170         debug_fenter();
1171
1172         if (!param->is_in_thread)
1173                 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1174
1175         /* Update list for dead process */
1176         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1177
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);
1181
1182                 my_node = node;
1183                 if (my_node->status == FOCUS_STATUS_DEACTIVATED) {
1184                         debug_error("focus status is already deactivated");
1185                         ret = MM_ERROR_SOUND_INVALID_STATE;
1186                         goto FINISH;
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;
1190                         goto FINISH;
1191                 }
1192                 break;
1193         }
1194
1195         if (my_node == NULL) {
1196                 debug_error("node is null");
1197                 ret = MM_ERROR_INVALID_ARGUMENT;
1198                 goto FINISH;
1199         }
1200
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)
1206                                 continue;
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;
1211                                 break;
1212                         }
1213                 }
1214         }
1215
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)
1223                                 continue;
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))
1232                                                                 continue;
1233                                                 }
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;
1239                                                 }
1240                                                 need_to_trigger_monitor_cb = false;
1241                                         }
1242                                 }
1243                         }
1244                 }
1245         }
1246         /* update status */
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;
1253                 }
1254         }
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);
1260
1261         _mm_sound_mgr_focus_list_dump();
1262         _mm_sound_mgr_focus_watch_list_dump ();
1263 FINISH:
1264         if (!param->is_in_thread)
1265                 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1266
1267         debug_fleave();
1268         return ret;
1269 }
1270
1271 int mm_sound_mgr_focus_set_watch_cb(const _mm_sound_mgr_focus_param_t *param)
1272 {
1273         int ret = MM_ERROR_NONE;
1274         GList *list = NULL;
1275         focus_node_t *node = NULL;
1276
1277         debug_fenter();
1278
1279         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1280
1281         /* Update list for dead process */
1282         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1283
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;
1289                         goto FINISH;
1290                 }
1291         }
1292
1293         node = g_malloc0(sizeof(focus_node_t));
1294
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;
1300
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");
1304         } else {
1305                 debug_error("g_list_append failed");
1306                 ret = MM_ERROR_SOUND_INTERNAL;
1307                 g_free(node);
1308         }
1309
1310         _mm_sound_mgr_focus_watch_list_dump();
1311 FINISH:
1312         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1313
1314         debug_fleave();
1315         return ret;
1316 }
1317
1318 int mm_sound_mgr_focus_unset_watch_cb(const _mm_sound_mgr_focus_param_t *param)
1319 {
1320         int ret = MM_ERROR_SOUND_INTERNAL;
1321         GList *list = NULL;
1322         focus_node_t *node = NULL;
1323
1324         debug_fenter();
1325
1326         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1327
1328         /* Update list for dead process */
1329         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1330
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);
1337                         g_free(node);
1338                         ret = MM_ERROR_NONE;
1339                         break;
1340                 }
1341         }
1342         if (list == NULL) {
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;
1345                 goto FINISH;
1346         }
1347
1348         _mm_sound_mgr_focus_watch_list_dump();
1349 FINISH:
1350         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1351
1352         debug_fleave();
1353         return ret;
1354 }
1355
1356 int mm_sound_mgr_focus_deliver(const _mm_sound_mgr_focus_param_t *param)
1357 {
1358         int ret = MM_ERROR_NONE;
1359         GList *list = NULL;
1360         focus_node_t *src_node = NULL;
1361         focus_node_t *dst_node = NULL;
1362         int i = 0;
1363
1364         debug_fenter();
1365
1366         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1367
1368         /* Update list for dead process */
1369         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1370
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);
1376                         break;
1377                 }
1378         }
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;
1383                 goto FINISH;
1384         }
1385
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;
1390                 goto FINISH;
1391         }
1392
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);
1398                         break;
1399                 }
1400         }
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;
1405                 goto FINISH;
1406         }
1407
1408         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1409                 focus_node_t *node = NULL;
1410                 if (!(param->request_type & (i+1)))
1411                         continue;
1412
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);
1421                         }
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);
1428                         }
1429                 }
1430
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];
1436
1437                 src_node->status &= ~(i+1);
1438                 memset(src_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
1439                 src_node->option[i] = 0;
1440         }
1441
1442         _mm_sound_mgr_focus_list_dump();
1443
1444 FINISH:
1445         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1446
1447         debug_fleave();
1448         return ret;
1449 }
1450
1451 int mm_sound_mgr_focus_emergent_exit(const _mm_sound_mgr_focus_param_t *param)
1452 {
1453         int ret = MM_ERROR_NONE;
1454         GList *list = NULL;
1455         GList *list_s =NULL;
1456         focus_node_t *node = NULL;
1457         focus_node_t *my_node = NULL;
1458         int i;
1459
1460         debug_fenter();
1461
1462         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1463
1464         /* Update list for dead process */
1465         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1466
1467         list = g_focus_node_list;
1468         while (list) {
1469                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1470                 if (node->pid != param->pid) {
1471                         list = list->next;
1472                         debug_log("node not found, next list = %p",list);
1473                         continue;
1474                 }
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;
1480                         g_free(node);
1481                         continue;
1482                 }
1483                 if (node->status == FOCUS_STATUS_DEACTIVATED) {
1484                         debug_log("clearing deactivated focus node of pid(%d) hande(%d)", node->pid, node->handle_id);
1485                         my_node = node;
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);
1493                                                 } else {
1494                                                         UPDATE_FOCUS_TAKEN_INFO(by_id, node, 0, 0, false);
1495                                                 }
1496                                         }
1497                                 }
1498                         }
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;
1502                         g_free(my_node);
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);
1507
1508                         my_node = node;
1509                         memset(&param_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)
1517                                         continue;
1518                                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1519                                         if (!(my_node->status & (i+1)))
1520                                                 continue;
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, &param_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;
1527                                         }
1528                                 }
1529                         }
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, &param_s)))
1532                                         debug_error("Fail to _focus_do_watch_callback, ret[0x%x]", ret);
1533                         }
1534
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;
1538                 }
1539         }
1540
1541         _mm_sound_mgr_focus_list_dump();
1542         _mm_sound_mgr_focus_watch_list_dump ();
1543
1544         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1545
1546         debug_fleave();
1547         return ret;
1548
1549 }
1550
1551 int MMSoundMgrFocusInit(void)
1552 {
1553         int ret = MM_ERROR_NONE;
1554         debug_fenter();
1555
1556         ret = __mm_sound_mgr_focus_dbus_get_stream_list(&g_stream_list);
1557         if (ret)
1558                 debug_error("failed to __mm_sound_mgr_focus_dbus_get_stream_list()");
1559
1560         debug_fleave();
1561         return ret;
1562 }
1563
1564 int MMSoundMgrFocusFini(void)
1565 {
1566         int i = 0;
1567         debug_fenter();
1568
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]);
1572                 }
1573         }
1574
1575         debug_fleave();
1576         return MM_ERROR_NONE;
1577 }