Remove unused include statement
[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 static GList *g_focus_node_list = NULL;
37 static pthread_mutex_t g_focus_node_list_mutex = PTHREAD_MUTEX_INITIALIZER;
38 stream_list_t g_stream_list;
39
40 static const char* focus_status_str[] =
41 {
42         "DEACTIVATED",
43         "P ACTIVATED",
44         "C ACTIVATED",
45         "B ACTIVATED",
46 };
47
48 typedef struct {
49         int pid;
50         int handle;
51         int type;
52         int state;
53         char stream_type [MAX_STREAM_TYPE_LEN];
54         char name [MM_SOUND_NAME_NUM];
55 }focus_cb_data;
56
57 #define CLEAR_DEAD_NODE_LIST(x)  do { \
58         debug_warning ("list = %p, node = %p, pid=[%d]", x, node, (node)? node->pid : -1); \
59         if (x && node && (mm_sound_util_is_process_alive(node->pid) == FALSE)) { \
60                 debug_warning("PID:%d does not exist now! remove from device cb list\n", node->pid); \
61                 __clear_focus_pipe(node); \
62                 x = g_list_remove (x, node); \
63                 g_free (node); \
64         } \
65 }while(0)
66
67 #define UPDATE_FOCUS_TAKEN_INFO(x, y, z, q) \
68         debug_warning ("updating node[%p]'s taken info : pid = [%d], handle_id = [%d], is_for_session = [%d]",x, y, z, q); \
69         x->taken_by_id[i].pid = y; \
70         x->taken_by_id[i].handle_id = z; \
71         x->taken_by_id[i].by_session = q; \
72
73 #ifdef SUPPORT_CONTAINER
74 static void __set_container_data(int pid, int handle, const char* container_name, int container_pid)
75 {
76         GList *list = NULL;
77         focus_node_t *node = NULL;
78
79         for (list = g_focus_node_list; list != NULL; list = list->next) {
80                 node = (focus_node_t *)list->data;
81                 if (!node->is_for_watch && node->pid == pid && node->handle_id == handle) {
82                         debug_error("Set container [%s][%d] to handle[%d] instanceID[%d]",
83                                                 container_name, container_pid, handle, node->pid);
84                         if (container_name)
85                                 MMSOUND_STRNCPY(node->container.name, container_name, CONTAINER_NAME_MAX);
86                         node->container.pid = container_pid;
87                         break;
88                 }
89                 else if (node->is_for_watch && node->pid == pid) {
90                         debug_error("Set container [%s][%d] to instanceID[%d]",
91                                                 container_name, container_pid, pid);
92                         if (container_name)
93                                 MMSOUND_STRNCPY(node->container.name, container_name, CONTAINER_NAME_MAX);
94                         node->container.pid = container_pid;
95                         break;
96                 }
97         }
98 }
99
100 static container_info_t* __get_container_info(int instance_id)
101 {
102         GList *list = NULL;
103         focus_node_t *node = NULL;
104
105         for (list = g_focus_node_list; list != NULL; list = list->next) {
106                 node = (focus_node_t *)list->data;
107                 if (node->pid == instance_id) {
108                         return &node->container;
109                 }
110         }
111         return NULL;
112 }
113 #endif /* SUPPORT_CONTAINER */
114
115 static char* __get_focus_pipe_path(int instance_id, int handle, const char* postfix, bool is_watch)
116 {
117         gchar* path = NULL;
118         gchar* path2 = NULL;
119
120 #ifdef SUPPORT_CONTAINER
121         container_info_t* container_info = __get_container_info(instance_id);
122         if (!container_info) {
123                 debug_error ("__get_container_info failed");
124                 return NULL;
125         }
126         if (instance_id == container_info->pid) {
127                 debug_error ("This might be in the HOST(%s)[%d], let's form normal path",
128                                         container_info->name, instance_id);
129                 if (is_watch) {
130                         path = g_strdup_printf("/tmp/FOCUS.%d.wch", instance_id);
131                 } else {
132                         path = g_strdup_printf("/tmp/FOCUS.%d.%d", instance_id, handle);
133                 }
134         } else {
135                 if (is_watch) {
136                         path = g_strdup_printf("/var/lib/lxc/%s/rootfs/tmp/FOCUS.%d.wch",
137                                                                         container_info->name, container_info->pid);
138                 } else {
139                         path = g_strdup_printf("/var/lib/lxc/%s/rootfs/tmp/FOCUS.%d.%d",
140                                                                         container_info->name, container_info->pid, handle);
141                 }
142         }
143 #else
144         if (is_watch) {
145                 path = g_strdup_printf("/tmp/FOCUS.%d.wch", instance_id);
146         } else {
147                 path = g_strdup_printf("/tmp/FOCUS.%d.%d", instance_id, handle);
148         }
149 #endif
150
151         if (postfix) {
152                 path2 = g_strconcat(path, postfix, NULL);
153                 g_free (path);
154                 path = NULL;
155                 return path2;
156         }
157
158         return path;
159 }
160
161 static void __clear_focus_pipe(focus_node_t *node)
162 {
163         char *filename = NULL;
164         char *filename2 = NULL;
165
166         debug_fenter();
167
168         if (!node->is_for_watch) {
169                 filename = __get_focus_pipe_path(node->pid, node->handle_id, NULL, false);
170                 filename2 = __get_focus_pipe_path(node->pid, node->handle_id, "r", false);
171         } else {
172                 filename = __get_focus_pipe_path(node->pid, -1, NULL, true);
173                 filename2 = __get_focus_pipe_path(node->pid, -1, "r", true);
174         }
175         if (filename) {
176                 if(remove(filename))
177                         debug_error("remove() failure, filename(%s), errno(%d)", filename, errno);
178                 free(filename);
179         }
180         if (filename2) {
181                 if(remove(filename2))
182                         debug_error("remove() failure, filename2(%s), errno(%d)", filename2, errno);
183                 free(filename2);
184         }
185
186         debug_fleave();
187 }
188
189 static void _clear_focus_node_list_func (focus_node_t *node, gpointer user_data)
190 {
191         CLEAR_DEAD_NODE_LIST(g_focus_node_list);
192 }
193
194 static int _mm_sound_mgr_focus_get_priority_from_stream_type(int *priority, const char *stream_type)
195 {
196         int ret = MM_ERROR_NONE;
197         int i = 0;
198
199         debug_fenter();
200
201         if (priority == NULL || stream_type == NULL) {
202                 ret = MM_ERROR_INVALID_ARGUMENT;
203                 debug_error("invalid argument, priority[0x%x], stream_type[%s], ret[0x%x]\n", priority, stream_type, ret);
204         } else {
205                 for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
206                         if (!strncmp(g_stream_list.stream_types[i], stream_type, strlen(stream_type))) {
207                                 *priority = g_stream_list.priorities[i];
208                                 break;
209                         }
210                 }
211                 if (i == AVAIL_STREAMS_MAX) {
212                         ret = MM_ERROR_NOT_SUPPORT_API;
213                         debug_error("not supported stream_type[%s], ret[0x%x]\n", stream_type, ret);
214                 } else {
215                         debug_log("[%s] has priority of [%d]\n", stream_type, *priority);
216                 }
217         }
218
219         debug_fleave();
220         return ret;
221 }
222
223 static int _mm_sound_mgr_focus_do_watch_callback(focus_type_e focus_type, focus_command_e command,
224                                                                                                 focus_node_t *my_node, const _mm_sound_mgr_focus_param_t *param)
225 {
226         char *filename = NULL;
227         char *filename2 = NULL;
228         struct timeval time;
229         int starttime = 0;
230         int endtime = 0;
231         int fd_FOCUS_R = -1;
232         int fd_FOCUS = -1;
233         int ret = -1;
234         struct pollfd pfd;
235         int pret = 0;
236         int pollingTimeout = 2500; /* NOTE : This is temporary code, because of Deadlock issues. If you fix that issue, remove this comment */
237
238         GList *list = NULL;
239         focus_node_t *node = NULL;
240         focus_cb_data cb_data;
241
242         debug_fenter();
243
244         for (list = g_focus_node_list; list != NULL; list = list->next) {
245                 node = (focus_node_t *)list->data;
246                 if (node == my_node || (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session)) {
247                         /* skip my own */
248                 } else {
249                         if (node->is_for_watch && (node->status & focus_type)) {
250                                 memset(&cb_data, 0, sizeof(focus_cb_data));
251                                 cb_data.pid = node->pid;
252                                 cb_data.handle = node->handle_id;
253                                 cb_data.type = focus_type & node->status;
254                                 cb_data.state = (command == FOCUS_COMMAND_ACQUIRE) ? !FOCUS_STATUS_DEACTIVATED : FOCUS_STATUS_DEACTIVATED;
255                                 MMSOUND_STRNCPY(cb_data.stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
256                                 MMSOUND_STRNCPY(cb_data.name, param->option, MM_SOUND_NAME_NUM);
257
258                                 /* Set start time */
259                                 gettimeofday(&time, NULL);
260                                 starttime = time.tv_sec * 1000000 + time.tv_usec;
261
262                                 /**************************************
263                                  *
264                                  * Open callback cmd pipe
265                                  *
266                                  **************************************/
267                                 filename = __get_focus_pipe_path(cb_data.pid, -1, NULL, true);
268                                 if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
269                                         debug_error("[CallCB] %s open error\n", filename);
270                                         goto fail;
271                                 }
272
273                                 /******************************************
274                                  *
275                                  * Open callback result pipe
276                                  * before writing callback cmd to pipe
277                                  *
278                                  ******************************************/
279                                  filename2 = __get_focus_pipe_path(cb_data.pid, -1, "r", true);
280                                 if (filename2 == NULL) {
281                                         debug_error("[RETCB] Fail to get watch return pipe");
282                                         goto fail;
283                                 }
284                                 if ((fd_FOCUS_R= open(filename2,O_RDONLY|O_NONBLOCK)) == -1) {
285                                         char str_error[256];
286                                         strerror_r (errno, str_error, sizeof(str_error));
287                                         debug_error("[RETCB] Fail to open fifo (%s)\n", str_error);
288                                         goto fail;
289                                 }
290                                 debug_log(" open return cb %s\n", filename2);
291
292                                 /*******************************************
293                                  * Write Callback msg
294                                  *******************************************/
295                                 if (write(fd_FOCUS, &cb_data ,sizeof(cb_data)) == -1) {
296                                         debug_error("[CallCB] %s fprintf error\n", filename);
297                                         goto fail;
298                                 }
299
300                                 /**************************************
301                                  *
302                                  * Close callback cmd pipe
303                                  *
304                                  **************************************/
305                                 close(fd_FOCUS);
306                                 fd_FOCUS = -1;
307
308                                 g_free(filename);
309                                 filename = NULL;
310
311                                 pfd.fd = fd_FOCUS_R;
312                                 pfd.events = POLLIN;
313
314                                 /*********************************************
315                                  *
316                                  * Wait callback result msg
317                                  *
318                                  ********************************************/
319                                 debug_error("[RETCB]wait callback(tid=%d, cmd=%d, timeout=%d)\n", cb_data.pid, command, pollingTimeout);
320                                 pret = poll(&pfd, 1, pollingTimeout); /* timeout 7sec */
321                                 debug_error("after poll");
322                                 if (pret < 0) {
323                                         debug_error("[RETCB]poll failed (%d)\n", pret);
324                                         goto fail;
325                                 }
326                                 if (pfd.revents & POLLIN) {
327                                         if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
328                                                 debug_error("fscanf error\n");
329                                                 goto fail;
330                                         }
331                                 }
332
333                                 g_free(filename2);
334                                 filename2 = NULL;
335
336                                 /* Calculate endtime and display*/
337                                 gettimeofday(&time, NULL);
338                                 endtime = time.tv_sec * 1000000 + time.tv_usec;
339                                 debug_error("[RETCB] FOCUS_CB_END cbtimelab=%3.3f(second), timeout=%d(milli second) (reciever=%d) Return value = (handle_id=%d)\n", ((endtime-starttime)/1000000.), pollingTimeout, cb_data.pid, ret);
340
341                                 /**************************************
342                                  *
343                                  * Close callback result pipe
344                                  *
345                                  **************************************/
346                                 if (fd_FOCUS_R != -1) {
347                                         close(fd_FOCUS_R);
348                                         fd_FOCUS_R = -1;
349                                 }
350                         }
351                 }
352         }
353         debug_fleave();
354         return MM_ERROR_NONE;
355
356 fail:
357         if (filename) {
358                 g_free (filename);
359                 filename = NULL;
360         }
361         if (filename2) {
362                 g_free (filename2);
363                 filename2 = NULL;
364         }
365         if (fd_FOCUS != -1) {
366                 close(fd_FOCUS);
367                 fd_FOCUS = -1;
368         }
369         if (fd_FOCUS_R != -1) {
370                 close (fd_FOCUS_R);
371                 fd_FOCUS_R = -1;
372         }
373         debug_fleave();
374         return -1;
375 }
376
377 int _mm_sound_mgr_focus_do_callback(focus_command_e command, focus_node_t *victim_node, const _mm_sound_mgr_focus_param_t *assaulter_param, const char *assaulter_stream_type)
378 {
379         char *filename = NULL;
380         char *filename2 = NULL;
381         struct timeval time;
382         int starttime = 0;
383         int endtime = 0;
384         int fd_FOCUS_R = -1;
385         int fd_FOCUS = -1;
386         unsigned int ret;
387         struct pollfd pfd;
388         int pret = 0;
389         int pollingTimeout = 2500; /* NOTE : This is temporary code, because of Deadlock issues. If you fix that issue, remove this comment */
390
391         int i = 0;
392         int flag_for_focus_type = 0;
393         int flag_for_taken_index = 0;
394         int taken_pid = 0;
395         int taken_hid = 0;
396         int ret_handle = -1;
397         bool taken_by_session = false;
398
399         focus_cb_data cb_data;
400
401         debug_error(" __mm_sound_mgr_focus_do_callback_ for pid(%d) handle(%d)\n", victim_node->pid, victim_node->handle_id);
402
403         memset(&cb_data, 0, sizeof(focus_cb_data));
404         cb_data.pid= victim_node->pid;
405         cb_data.handle= victim_node->handle_id;
406         if (command == FOCUS_COMMAND_RELEASE) {
407                 /* client will lost the acquired focus */
408                 cb_data.type= assaulter_param->request_type & victim_node->status;
409                 cb_data.state= FOCUS_STATUS_DEACTIVATED;
410                 /* remove additional info. */
411                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
412                         if (cb_data.type & (i+1))
413                                 memset(victim_node->option[i], 0x0, MM_SOUND_NAME_NUM);
414                 }
415         } else {
416                 /* client will gain the lost focus */
417                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
418                         if ((victim_node->taken_by_id[i].pid == assaulter_param->pid) && ((victim_node->taken_by_id[i].handle_id == assaulter_param->handle_id) || victim_node->taken_by_id[i].by_session)) {
419                                 flag_for_focus_type |= i+1; /* playback:1, capture:2 */
420                         }
421                 }
422                 cb_data.type = flag_for_focus_type & assaulter_param->request_type;
423                 cb_data.state = !FOCUS_STATUS_DEACTIVATED;
424                 /* copy additional info. */
425                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
426                         if (cb_data.type & (i+1))
427                                 MMSOUND_STRNCPY(victim_node->option[i], assaulter_param->option, MM_SOUND_NAME_NUM);
428                 }
429         }
430         MMSOUND_STRNCPY(cb_data.stream_type, assaulter_stream_type, MAX_STREAM_TYPE_LEN);
431         MMSOUND_STRNCPY(cb_data.name, assaulter_param->option, MM_SOUND_NAME_NUM);
432
433         /* Set start time */
434         gettimeofday(&time, NULL);
435         starttime = time.tv_sec * 1000000 + time.tv_usec;
436
437         /**************************************
438          *
439          * Open callback cmd pipe
440          *
441          **************************************/
442         filename = __get_focus_pipe_path(cb_data.pid, cb_data.handle, NULL, false);
443         if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
444                 debug_error("[CallCB] %s open error\n", filename);
445                 goto fail;
446         }
447
448         /******************************************
449          *
450          * Open callback result pipe
451          * before writing callback cmd to pipe
452          *
453          ******************************************/
454         filename2 = __get_focus_pipe_path(cb_data.pid, cb_data.handle, "r", false);
455         if (filename2 == NULL) {
456                 debug_error("[RETCB] Fail to get return pipe");
457                 goto fail;
458         }
459         if ((fd_FOCUS_R = open(filename2,O_RDONLY|O_NONBLOCK)) == -1) {
460                 char str_error[256];
461                 strerror_r (errno, str_error, sizeof(str_error));
462                 debug_error("[RETCB] Fail to open fifo (%s)\n", str_error);
463                 goto fail;
464         }
465         debug_log(" open return cb %s\n", filename2);
466
467
468         /*******************************************
469          * Write Callback msg
470          *******************************************/
471         if (write(fd_FOCUS, &cb_data, sizeof(cb_data)) == -1) {
472                 debug_error("[CallCB] %s write error\n", filename);
473                 goto fail;
474         }
475         /**************************************
476          *
477          * Close callback cmd pipe
478          *
479          **************************************/
480         close(fd_FOCUS);
481         fd_FOCUS = -1;
482
483         g_free(filename);
484         filename = NULL;
485
486         pfd.fd = fd_FOCUS_R;
487         pfd.events = POLLIN;
488
489         /*********************************************
490          *
491          * Wait callback result msg
492          *
493          ********************************************/
494         debug_error("[RETCB]wait callback(tid=%d, handle=%d, cmd=%d, timeout=%d)\n",cb_data.pid, cb_data.handle, command, pollingTimeout);
495         pret = poll(&pfd, 1, pollingTimeout);
496         if (pret < 0) {
497                 debug_error("[RETCB]poll failed (%d)\n", pret);
498                 goto fail;
499         }
500         if (pfd.revents & POLLIN) {
501                 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
502                         debug_error("read error\n");
503                         goto fail;
504                 }
505                 ret_handle = (int)(ret & 0x0000ffff);
506                 victim_node->reacquisition= (bool)((ret >> 16) & 0xf);
507         }
508         g_free(filename2);
509         filename2 = NULL;
510
511         /* Calculate endtime and display*/
512         gettimeofday(&time, NULL);
513         endtime = time.tv_sec * 1000000 + time.tv_usec;
514         debug_error("[RETCB] FOCUS_CB_END cbtimelab=%3.3f(second), timeout=%d(milli second) (reciever=%d) Return value = (handle_id=%d)\n", ((endtime-starttime)/1000000.), pollingTimeout, cb_data.pid, ret);
515
516         /**************************************
517          *
518          * Close callback result pipe
519          *
520          **************************************/
521         if (fd_FOCUS_R != -1) {
522                 close(fd_FOCUS_R);
523                 fd_FOCUS_R = -1;
524         }
525         //debug_log("[RETCB] Return value 0x%x\n", buf);
526
527         /* update victim node */
528         if (command == FOCUS_COMMAND_RELEASE) {
529                 taken_pid = assaulter_param->pid;
530                 taken_hid = assaulter_param->handle_id;
531                 taken_by_session = assaulter_param->is_for_session;
532                 flag_for_taken_index = assaulter_param->request_type & victim_node->status;
533         } else {
534                 taken_pid = 0;
535                 taken_hid = 0;
536                 taken_by_session = false;
537                 flag_for_taken_index = assaulter_param->request_type;
538         }
539
540         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
541                 if (flag_for_taken_index & (i+1)) {
542                         if (command == FOCUS_COMMAND_ACQUIRE && (victim_node->taken_by_id[i].pid != assaulter_param->pid || (victim_node->taken_by_id[i].handle_id != assaulter_param->handle_id && !(victim_node->taken_by_id[i].by_session & assaulter_param->is_for_session)))) {
543                                 /* skip */
544                                 debug_error("skip updating victim node");
545                                 continue;
546                         }
547                         if (!victim_node->reacquisition) {
548                                 GList *list = NULL;
549                                 focus_node_t *node = NULL;
550                                 for (list = g_focus_node_list; list != NULL; list = list->next) {
551                                         node = (focus_node_t *)list->data;
552                                         if (node && (node->taken_by_id[i].pid == victim_node->pid)) {
553                                                 UPDATE_FOCUS_TAKEN_INFO(node, taken_pid, taken_hid, taken_by_session);
554                                         } else if (!list->next) {
555                                                 UPDATE_FOCUS_TAKEN_INFO(victim_node, 0, 0, false);
556                                         }
557                                 }
558                         } else {
559                                 UPDATE_FOCUS_TAKEN_INFO(victim_node, taken_pid, taken_hid, taken_by_session);
560                         }
561                 }
562         }
563
564         if (ret_handle == victim_node->handle_id) {
565                 /* return from client is success, ret_handle will be its handle_id */
566                 victim_node->status = (command == FOCUS_COMMAND_RELEASE) ? (victim_node->status & ~(cb_data.type)) : (victim_node->status | cb_data.type);
567         } else {
568                 victim_node->status = FOCUS_STATUS_DEACTIVATED;
569         }
570
571         if (strncmp(assaulter_stream_type, victim_node->stream_type, MAX_STREAM_TYPE_LEN))
572                 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)assaulter_param->request_type, command, victim_node, assaulter_param);
573
574
575         return MM_ERROR_NONE;
576
577 fail:
578         if (filename) {
579                 g_free (filename);
580                 filename = NULL;
581         }
582         if (filename2) {
583                 g_free (filename2);
584                 filename2 = NULL;
585         }
586         if (fd_FOCUS != -1) {
587                 close(fd_FOCUS);
588                 fd_FOCUS = -1;
589         }
590         if (fd_FOCUS_R != -1) {
591                 close (fd_FOCUS_R);
592                 fd_FOCUS_R = -1;
593         }
594
595         return -1;
596 }
597
598 static int _mm_sound_mgr_focus_list_dump ()
599 {
600         int ret = MM_ERROR_NONE;
601         GList *list = NULL;
602         focus_node_t *node = NULL;
603
604         debug_log("================================================ focus node list : start ===================================================\n");
605         for (list = g_focus_node_list; list != NULL; list = list->next) {
606                 node = (focus_node_t *)list->data;
607                 if (node && !node->is_for_watch) {
608                         debug_log("*** pid[%5d]/handle_id[%d]/[%15s]:priority[%2d],status[%s],taken_by[P(%5d/%2d/%2d)C(%5d/%2d/%2d)],for_session[%d],add.info[%s/%s]\n",
609                                         node->pid, node->handle_id, node->stream_type, node->priority, focus_status_str[node->status],
610                                         node->taken_by_id[0].pid, node->taken_by_id[0].handle_id, node->taken_by_id[0].by_session, node->taken_by_id[1].pid,
611                                         node->taken_by_id[1].handle_id, node->taken_by_id[1].by_session, node->is_for_session, node->option[0], node->option[1]);
612                 }
613         }
614         debug_log("================================================ focus node list : end =====================================================\n");
615
616         return ret;
617 }
618
619 static int _mm_sound_mgr_focus_watch_list_dump ()
620 {
621         int ret = MM_ERROR_NONE;
622         GList *list = NULL;
623         focus_node_t *node = NULL;
624
625         debug_log("============================================= focus watch node list : start =================================================\n");
626         for (list = g_focus_node_list; list != NULL; list = list->next) {
627                 node = (focus_node_t *)list->data;
628                 if (node && node->is_for_watch) {
629                         debug_log("*** pid[%5d]/handle_id[%d]/watch on focus status[%s]/for_session[%d]\n", node->pid, node->handle_id, focus_status_str[node->status], node->is_for_session);
630                 }
631         }
632         debug_log("============================================= focus watch node list : end ===================================================\n");
633
634         return ret;
635 }
636
637 static void _mm_sound_mgr_focus_fill_info_from_msg (focus_node_t *node, const _mm_sound_mgr_focus_param_t *msg)
638 {
639         debug_fenter();
640         node->pid = msg->pid;
641         node->handle_id = msg->handle_id;
642         node->callback = msg->callback;
643         node->cbdata = msg->cbdata;
644         node->is_for_session = msg->is_for_session;
645 #ifdef SUPPORT_CONTAINER
646         memset (&node->container, 0, sizeof (container_info_t));
647         MMSOUND_STRNCPY(node->container.name, "NONAME", CONTAINER_NAME_MAX);
648         node->container.pid = msg->pid;
649 #endif
650
651         debug_fleave();
652         return;
653 }
654
655 #ifdef SUPPORT_CONTAINER
656 void mm_sound_mgr_focus_update_container_data(int pid,int handle, const char* container_name, int container_pid)
657 {
658         __set_container_data(pid, handle, container_name, container_pid);
659         //__temp_print_list(NULL);
660 }
661 #endif
662
663 int mm_sound_mgr_focus_create_node (const _mm_sound_mgr_focus_param_t *param)
664 {
665         int ret = MM_ERROR_NONE;
666         GList *list = NULL;
667         focus_node_t *node = NULL;
668         int priority = 0;
669
670         debug_fenter();
671
672         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
673
674         /* Update list for dead process */
675         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
676
677         for (list = g_focus_node_list; list != NULL; list = list->next) {
678                 node = (focus_node_t *)list->data;
679                 if (node && !node->is_for_watch && (node->pid == param->pid) && (node->handle_id == param->handle_id)) {
680                         debug_error("the node of pid[%d]/handle_id[%d] is already created\n", param->pid, param->handle_id);
681                         ret = MM_ERROR_INVALID_ARGUMENT;
682                         goto FINISH;
683                 }
684         }
685
686         /* get priority from stream type */
687         ret = _mm_sound_mgr_focus_get_priority_from_stream_type(&priority, param->stream_type);
688         if (ret) {
689                 goto FINISH;
690         }
691         node = g_malloc0(sizeof(focus_node_t));
692
693         /* fill up information to the node */
694         _mm_sound_mgr_focus_fill_info_from_msg(node, param);
695         node->priority = priority;
696         node->status = FOCUS_STATUS_DEACTIVATED;
697         MMSOUND_STRNCPY(node->stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
698
699         g_focus_node_list = g_list_append(g_focus_node_list, node);
700         if (g_focus_node_list) {
701                 debug_log("new focus node is added\n");
702         } else {
703                 debug_error("g_list_append failed\n");
704                 ret = MM_ERROR_SOUND_INTERNAL;
705                 g_free(node);
706         }
707
708         _mm_sound_mgr_focus_list_dump();
709 FINISH:
710         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
711
712         debug_fleave();
713         return ret;
714 }
715
716 int mm_sound_mgr_focus_destroy_node (const _mm_sound_mgr_focus_param_t *param)
717 {
718         int ret = MM_ERROR_NONE;
719         GList *list = NULL;
720         focus_node_t *node = NULL;
721         focus_node_t *my_node = NULL;
722         bool need_to_trigger = true;
723         int i = 0;
724
725         debug_fenter();
726
727         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
728
729         /* Update list for dead process */
730         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
731
732         for (list = g_focus_node_list; list != NULL; list = list->next) {
733                 node = (focus_node_t *)list->data;
734                 if (node && !node->is_for_watch && (node->pid == param->pid) && (node->handle_id == param->handle_id)) {
735                         debug_log("found the node of pid[%d]/handle_id[%d]\n", param->pid, param->handle_id);
736                         my_node = node;
737                         break;
738                 }
739         }
740         if (my_node == NULL) {
741                 debug_error("could not find any node of pid[%d]/handle_id[%d]\n", param->pid, param->handle_id);
742                 ret = MM_ERROR_INVALID_ARGUMENT;
743                 goto FINISH;
744         }
745
746         /* Check if there's remaining focus for session for the same PID of incomming param*/
747         if(my_node->is_for_session) {
748                 for (list = g_focus_node_list; list != NULL; list = list->next) {
749                         node = (focus_node_t *)list->data;
750                         if (!node) {
751                                 /* skip */
752                         } else if (my_node == node || node->is_for_watch) {
753                                 /* skip */
754                         } else {
755                                 if (node->pid == my_node->pid && node->is_for_session) {
756                                         debug_error("focus for session for this pid still remains, skip updating victim focus nodes");
757                                         need_to_trigger = false;
758                                         break;
759                                 }
760                         }
761                 }
762         }
763
764         if(need_to_trigger) {
765                 for (list = g_focus_node_list; list != NULL; list = list->next) {
766                         node = (focus_node_t *)list->data;
767                         if (!node) {
768                                 /* skip */
769                         } else if (my_node == node || node->is_for_watch) {
770                                 /* skip */
771                         } else {
772                                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
773                                         if (node->taken_by_id[i].pid == param->pid) {
774                                                 if(my_node->taken_by_id[i].pid) {
775                                                 /* If exists update the taken focus info to my victim node */
776                                                         if (node->taken_by_id[i].by_session && !node->status) {
777                                                                 UPDATE_FOCUS_TAKEN_INFO(node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, my_node->taken_by_id[i].by_session);
778                                                         } else if (node->taken_by_id[i].handle_id == param->handle_id) {
779                                                                 UPDATE_FOCUS_TAKEN_INFO(node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, false);
780                                                         }
781                                                 } else {
782                                                         if (node->taken_by_id[i].by_session && !node->status) {
783                                                                 UPDATE_FOCUS_TAKEN_INFO(node, 0, 0, false);
784                                                         } else if (node->taken_by_id[i].handle_id == param->handle_id) {
785                                                                 UPDATE_FOCUS_TAKEN_INFO(node, 0, 0, false);
786                                                         }
787                                                 }
788                                         }
789                                 }
790                         }
791                 }
792         }
793
794         /* Destroy my node  */
795         __clear_focus_pipe(my_node);
796         g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
797         g_free(my_node);
798
799         _mm_sound_mgr_focus_list_dump();
800 FINISH:
801         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
802
803         debug_fleave();
804         return ret;
805 }
806
807 int mm_sound_mgr_focus_set_reacquisition (const _mm_sound_mgr_focus_param_t *param)
808 {
809         int ret = MM_ERROR_NONE;
810         GList *list = NULL;
811         focus_node_t *node = NULL;
812         focus_node_t *my_node = NULL;
813
814         debug_fenter();
815
816         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
817
818         /* Update list for dead process */
819         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
820
821         /* Find node to set reacquisition */
822         for (list = g_focus_node_list; list != NULL; list = list->next) {
823                 node = (focus_node_t *)list->data;
824                 if (node && !node->is_for_watch && (node->pid == param->pid) && (node->handle_id == param->handle_id)) {
825                         node->reacquisition = param->reacquisition;
826                         my_node = node;
827                         break;
828                 }
829         }
830
831         /* Append my node's taken info to my victim node */
832         if(!param->reacquisition) {
833                 int i;
834                 for (list = g_focus_node_list; list != NULL; list = list->next) {
835                         node = (focus_node_t *)list->data;
836                         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
837                                 if (node && (node->taken_by_id[i].pid == param->pid)) {
838                                         if (my_node->taken_by_id[i].pid) {
839                                                 UPDATE_FOCUS_TAKEN_INFO(node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, my_node->taken_by_id[i].by_session);
840                                         }
841                                 } else if (!list->next) {
842                                         UPDATE_FOCUS_TAKEN_INFO(my_node, 0, 0, false);
843                                 }
844                         }
845                 }
846         }
847
848         _mm_sound_mgr_focus_list_dump();
849         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
850
851         debug_fleave();
852         return ret;
853 }
854
855 int mm_sound_mgr_focus_get_stream_type_of_acquired_focus(focus_type_e focus_type, char **stream_type, char **additional_info)
856 {
857         int ret = MM_ERROR_SOUND_NO_DATA;
858         GList *list = NULL;
859         focus_node_t *node = NULL;
860
861         debug_fenter();
862
863         if (focus_type == FOCUS_TYPE_BOTH) /* focus_type should be "playback" or "capture" */
864                 return MM_ERROR_INVALID_ARGUMENT;
865         if (!stream_type)
866                 return MM_ERROR_INVALID_ARGUMENT;
867
868         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
869
870         /* Update list for dead process */
871         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
872
873         /* Find node to set reacquisition */
874         for (list = g_focus_node_list; list != NULL; list = list->next) {
875                 node = (focus_node_t *)list->data;
876                 if (node && !node->is_for_watch && (node->status & focus_type)) {
877                         debug_msg("found a node : request_focus_type(%d), stream_type(%s)/additional info(%s) of acquired focus\n", focus_type, node->stream_type, node->option);
878                         *stream_type = node->stream_type;
879                         if (additional_info)
880                                 *additional_info = node->option[focus_type-1];
881                         ret = MM_ERROR_NONE;
882                         break;
883                 }
884         }
885
886         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
887
888         debug_fleave();
889
890         return ret;
891 }
892
893 int mm_sound_mgr_focus_request_acquire(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         bool need_to_trigger_cb = false;
900         bool need_to_trigger_watch_cb = true;
901         int i;
902
903         debug_fenter();
904
905         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
906
907         /* Update list for dead process */
908         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
909
910         for (list = g_focus_node_list; list != NULL; list = list->next) {
911                 node = (focus_node_t *)list->data;
912                 if (node && !node->is_for_watch && (node->pid == param->pid) && (node->handle_id == param->handle_id)) {
913                         my_node = node;
914                         if ((my_node->status > FOCUS_STATUS_DEACTIVATED) && (my_node->status & param->request_type)) {
915                                 debug_error("focus status is already activated");
916                                 ret = MM_ERROR_SOUND_INVALID_STATE;
917                                 goto FINISH;
918                         }
919                 }
920         }
921
922         if (my_node == NULL) {
923                 debug_error("node is null");
924                 ret = MM_ERROR_INVALID_ARGUMENT;
925                 goto FINISH;
926         }
927
928         /* check if the priority of any node is higher than its based on io direction */
929         for (list = g_focus_node_list; list != NULL; list = list->next) {
930                 node = (focus_node_t *)list->data;
931                 if (!node) {
932                         /* skip */
933                 } else if (my_node == node || node->is_for_watch) {
934                         /* skip */
935                 } else if (param->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
936                                         (node->status & param->request_type)) {
937                         if (node->status > FOCUS_STATUS_DEACTIVATED) {
938                                 if ((my_node->priority < node->priority)) {
939                                         ret = MM_ERROR_POLICY_BLOCKED;
940                                         need_to_trigger_cb = false;
941                                         break;
942                                 } else {
943                                         need_to_trigger_cb = true;
944                                 }
945                         }
946                 }
947         }
948
949         if (need_to_trigger_cb) {
950                 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
951                 param_s->is_for_session = my_node->is_for_session;
952                 for (list = g_focus_node_list; list != NULL; list = list->next) {
953                         node = (focus_node_t *)list->data;
954                         if (!node) {
955                                 /* skip */
956                         } else if (node == my_node || node->is_for_watch || (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session)) {
957                                 /* skip */
958                         } else if (param_s->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
959                                         (node->status & param_s->request_type)) {
960                                 if (node->status > FOCUS_STATUS_DEACTIVATED) {
961                                         if (my_node->priority >= node->priority) {
962                                                 /* do callback for interruption */
963                                                 ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_RELEASE, node, param_s, my_node->stream_type);
964                                                 if (ret) {
965                                                         debug_error("Fail to _focus_do_callback for COMMAND RELEASE to node[%x], ret[0x%x]\n", node, ret);
966                                                         /* but, keep going */
967                                                         ret = MM_ERROR_NONE;
968                                                 }
969                                                 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
970                                                         need_to_trigger_watch_cb = false;
971                                                 }
972                                         }
973                                 }
974                         }
975                 }
976         }
977
978         if (ret != MM_ERROR_POLICY_BLOCKED) {
979                 /* copy additional info. */
980                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
981                         if (param->request_type & (i+1))
982                                 MMSOUND_STRNCPY(my_node->option[i], param->option, MM_SOUND_NAME_NUM);
983                 }
984                 /* update status */
985                 my_node->status |= param->request_type;
986                 /* do watch callback due to the status of mine */
987                 if (need_to_trigger_watch_cb)
988                         _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_ACQUIRE, my_node, param);
989         }
990
991         /* update taken information */
992         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
993                 if (param->request_type & (i+1) && my_node->taken_by_id[i].pid) {
994                         UPDATE_FOCUS_TAKEN_INFO(my_node, 0, 0, false);
995                 }
996         }
997
998         _mm_sound_mgr_focus_list_dump();
999         _mm_sound_mgr_focus_watch_list_dump ();
1000 FINISH:
1001         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1002
1003         debug_fleave();
1004         return ret;
1005 }
1006
1007 int mm_sound_mgr_focus_request_release (const _mm_sound_mgr_focus_param_t *param)
1008 {
1009         int ret = MM_ERROR_NONE;
1010         GList *list = NULL;
1011         focus_node_t *node = NULL;
1012         focus_node_t *my_node = NULL;
1013         bool need_to_trigger_watch_cb = true;
1014         bool need_to_trigger_cb = true;
1015         int i = 0;
1016
1017         debug_fenter();
1018
1019         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1020
1021         /* Update list for dead process */
1022         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1023
1024         for (list = g_focus_node_list; list != NULL; list = list->next) {
1025                 node = (focus_node_t *)list->data;
1026                 if (node && !node->is_for_watch && (node->pid == param->pid) && (node->handle_id == param->handle_id)) {
1027                         my_node = node;
1028                         if (my_node->status == FOCUS_STATUS_DEACTIVATED) {
1029                                 debug_error("focus status is already deactivated");
1030                                 ret = MM_ERROR_SOUND_INVALID_STATE;
1031                                 goto FINISH;
1032                         } else if ((my_node->status != FOCUS_STATUS_ACTIVATED_BOTH) && (my_node->status != (focus_status_e)param->request_type)) {
1033                                 debug_error("request type is not matched with current focus type");
1034                                 ret = MM_ERROR_SOUND_INVALID_STATE;
1035                                 goto FINISH;
1036                         }
1037                         break;
1038                 }
1039         }
1040
1041         if (my_node == NULL) {
1042                 debug_error("node is null");
1043                 ret = MM_ERROR_INVALID_ARGUMENT;
1044                 goto FINISH;
1045         }
1046
1047         /* Check if there's activating focus for session for the same PID of incomming param*/
1048         if(my_node->is_for_session) {
1049                 for (list = g_focus_node_list; list != NULL; list = list->next) {
1050                         node = (focus_node_t *)list->data;
1051                         if (!node) {
1052                                 /* skip */
1053                         } else if (node != my_node && node->pid == my_node->pid && node->is_for_session && !node->is_for_watch
1054                                 && my_node->status & node->status) {
1055                                 debug_error("focus for session for this pid is active, skip callbacks");
1056                                 need_to_trigger_watch_cb = false;
1057                                 need_to_trigger_cb = false;
1058                                 break;
1059                         }
1060                 }
1061         }
1062
1063         if (need_to_trigger_cb) {
1064                 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
1065                 param_s->is_for_session = my_node->is_for_session;
1066                 for (list = g_focus_node_list; list != NULL; list = list->next) {
1067                         node = (focus_node_t *)list->data;
1068                         if (!node) {
1069                                 /* skip */
1070                         } else if (node == my_node || node->is_for_watch) {
1071                                 /* skip */
1072                         } else {
1073                                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1074                                         if (param_s->request_type & (i+1)) {
1075                                                 if (node->taken_by_id[i].pid == param_s->pid && (node->taken_by_id[i].handle_id == param_s->handle_id || node->taken_by_id[i].by_session)) {
1076                                                         /* do callback for resumption */
1077                                                         ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, param_s, my_node->stream_type);
1078                                                         if (ret) {
1079                                                                 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]\n", node, ret);
1080                                                         }
1081                                                         if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
1082                                                                 need_to_trigger_watch_cb = false;
1083                                                         }
1084                                                 }
1085                                         }
1086                                 }
1087                         }
1088                 }
1089         }
1090         /* update status */
1091         my_node->status &= ~(param->request_type);
1092         /* remove additional info. */
1093         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1094                 if (!(my_node->status & (i+1)))
1095                         memset(my_node->option[i], 0x0, MM_SOUND_NAME_NUM);
1096         }
1097         /* do watch callback due to the status of mine */
1098         if (need_to_trigger_watch_cb)
1099                 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_RELEASE, my_node, param);
1100
1101         _mm_sound_mgr_focus_list_dump();
1102         _mm_sound_mgr_focus_watch_list_dump ();
1103 FINISH:
1104         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1105
1106         debug_fleave();
1107         return ret;
1108 }
1109
1110 int mm_sound_mgr_focus_set_watch_cb (const _mm_sound_mgr_focus_param_t *param)
1111 {
1112         int ret = MM_ERROR_NONE;
1113         GList *list = NULL;
1114         focus_node_t *node = NULL;
1115
1116         debug_fenter();
1117
1118         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1119
1120         /* Update list for dead process */
1121         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1122
1123         for (list = g_focus_node_list; list != NULL; list = list->next) {
1124                 node = (focus_node_t *)list->data;
1125                 if (node && (node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1126                         debug_error("the node of pid[%d]/handle_id[%d] for watch focus is already created\n", param->pid, param->handle_id);
1127                         ret = MM_ERROR_INVALID_ARGUMENT;
1128                         goto FINISH;
1129                 }
1130         }
1131
1132         node = g_malloc0(sizeof(focus_node_t));
1133
1134         /* fill up information to the node */
1135         _mm_sound_mgr_focus_fill_info_from_msg(node, param);
1136         node->is_for_watch = true;
1137         node->status = param->request_type;
1138
1139         g_focus_node_list = g_list_append(g_focus_node_list, node);
1140         if (g_focus_node_list) {
1141                 debug_log("new focus node is added\n");
1142         } else {
1143                 debug_error("g_list_append failed\n");
1144                 ret = MM_ERROR_SOUND_INTERNAL;
1145                 g_free(node);
1146         }
1147
1148         _mm_sound_mgr_focus_watch_list_dump();
1149 FINISH:
1150         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1151
1152         debug_fleave();
1153         return ret;
1154 }
1155
1156 int mm_sound_mgr_focus_unset_watch_cb (const _mm_sound_mgr_focus_param_t *param)
1157 {
1158         int ret = MM_ERROR_SOUND_INTERNAL;
1159         GList *list = NULL;
1160         focus_node_t *node = NULL;
1161
1162         debug_fenter();
1163
1164         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1165
1166         /* Update list for dead process */
1167         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1168
1169         for (list = g_focus_node_list; list != NULL; list = list->next) {
1170                 node = (focus_node_t *)list->data;
1171                 if (node && (node->pid == param->pid) && (node->handle_id == param->handle_id) && (node->is_for_watch)) {
1172                         debug_log("found the node of pid[%d]/handle_id[%d] for watch focus\n", param->pid, param->handle_id);
1173                         __clear_focus_pipe(node);
1174                         g_focus_node_list = g_list_remove(g_focus_node_list, node);
1175                         g_free(node);
1176                         ret = MM_ERROR_NONE;
1177                         break;
1178                 }
1179         }
1180         if (list == NULL) {
1181                 debug_error("could not find any node of pid[%d]/handle_id[%d] for watch focus\n", param->pid, param->handle_id);
1182                 ret = MM_ERROR_INVALID_ARGUMENT;
1183                 goto FINISH;
1184         }
1185
1186         _mm_sound_mgr_focus_watch_list_dump();
1187 FINISH:
1188         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1189
1190         debug_fleave();
1191         return ret;
1192 }
1193
1194 int mm_sound_mgr_focus_emergent_exit(const _mm_sound_mgr_focus_param_t *param)
1195 {
1196         int ret = MM_ERROR_NONE;
1197         GList *list = NULL;
1198         GList *list_s =NULL;
1199         focus_node_t *node = NULL;
1200         focus_node_t *my_node = NULL;
1201         int i;
1202
1203         debug_fenter();
1204
1205         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1206
1207         /* Update list for dead process */
1208         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1209
1210         list = g_focus_node_list;
1211         while(list) {
1212                 node = (focus_node_t *)list->data;
1213                 if (node && (node->pid == param->pid)) {
1214                         debug_log("found pid node");
1215                         if(node->is_for_watch) {
1216                                 debug_log("clearing watch cb of pid(%d) handle(%d)", node->pid, node->handle_id);
1217                                 __clear_focus_pipe(node);
1218                                 g_focus_node_list = g_list_remove(g_focus_node_list, node);
1219                                 list = g_focus_node_list;
1220                                 g_free(node);
1221                         } else if (node->status == FOCUS_STATUS_DEACTIVATED) {
1222                                 debug_log("clearing deactivated focus node of pid(%d) hande(%d)", node->pid, node->handle_id);
1223                                 my_node = node;
1224                                 /* update info of nodes that are lost their focus by the process exited */
1225                                 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1226                                         node = (focus_node_t *)list_s->data;
1227                                         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1228                                                 if (node && (node->taken_by_id[i].pid == param->pid)) {
1229                                                         if (my_node->taken_by_id[i].pid) {
1230                                                                 UPDATE_FOCUS_TAKEN_INFO(node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, my_node->taken_by_id[i].by_session);
1231                                                         } else {
1232                                                                 UPDATE_FOCUS_TAKEN_INFO(node, 0, 0, false);
1233                                                         }
1234                                                 }
1235                                         }
1236                                 }
1237                                 __clear_focus_pipe(my_node);
1238                                 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1239                                 list = g_focus_node_list;
1240                                 g_free(my_node);
1241                         } else { /* node that acquired focus */
1242                                 bool need_to_trigger_watch_cb = true;
1243                                 _mm_sound_mgr_focus_param_t param_s;
1244                                 debug_log("clearing activated focus node of pid(%d) handle(%d)", node->pid, node->handle_id);
1245
1246                                 my_node = node;
1247                                 memset(&param_s, 0x00, sizeof(_mm_sound_mgr_focus_param_t));
1248                                 param_s.pid = my_node->pid;
1249                                 param_s.handle_id = my_node->handle_id;
1250                                 param_s.request_type = my_node->status;
1251                                 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1252                                         node = (focus_node_t *)list_s->data;
1253                                         if (my_node->pid == node->pid || node->is_for_watch) {
1254                                                 /* skip */
1255                                         } else {
1256                                                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1257                                                         if (my_node->status & (i+1)) {
1258                                                                 if (node && (node->taken_by_id[i].pid == param_s.pid && node->taken_by_id[i].handle_id == param_s.handle_id)) {
1259                                                                         /* do callback for resumption */
1260                                                                         ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, &param_s, my_node->stream_type);
1261                                                                         if (ret) {
1262                                                                                 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]\n", node, ret);
1263                                                                         }
1264                                                                         if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
1265                                                                                 need_to_trigger_watch_cb = false;
1266                                                                         }
1267                                                                 }
1268                                                         }
1269                                                 }
1270                                         }
1271                                 }
1272                                 if (need_to_trigger_watch_cb) {
1273                                         ret = _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param_s.request_type, FOCUS_COMMAND_RELEASE, my_node, &param_s);
1274                                         if (ret) {
1275                                                 debug_error("Fail to _focus_do_watch_callback, ret[0x%x]\n", ret);
1276                                         }
1277                                 }
1278                                 __clear_focus_pipe(my_node);
1279                                 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1280                                 list = g_focus_node_list;
1281                         }
1282                 }else {
1283                         list = list->next;
1284                         debug_log("node not found, next list = %p",list);
1285                 }
1286         }
1287
1288         _mm_sound_mgr_focus_list_dump();
1289         _mm_sound_mgr_focus_watch_list_dump ();
1290
1291         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1292
1293         debug_fleave();
1294         return ret;
1295
1296 }
1297
1298 int MMSoundMgrFocusInit(void)
1299 {
1300         int ret = MM_ERROR_NONE;
1301         debug_fenter();
1302
1303         ret = __mm_sound_mgr_focus_dbus_get_stream_list(&g_stream_list);
1304         if (ret)
1305                 debug_error("failed to __mm_sound_mgr_ipc_dbus_get_stream_list()\n");
1306
1307         debug_fleave();
1308         return ret;
1309 }
1310
1311 int MMSoundMgrFocusFini(void)
1312 {
1313         int i = 0;
1314         debug_fenter();
1315
1316         for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
1317                 if (g_stream_list.stream_types[i]) {
1318                         free (g_stream_list.stream_types[i]);
1319                 }
1320         }
1321
1322         debug_fleave();
1323         return MM_ERROR_NONE;
1324 }
1325