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