982144a5df66fb9bfa9ec780cd146c57540ffad2
[platform/core/multimedia/libmm-sound.git] / focus_server / mm_sound_mgr_focus.c
1 /*
2  * libmm-sound
3  *
4  * Copyright (c) 2000 - 2015 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Sangchul Lee <sc11.lee@samsung.com>
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24
25 #include "include/mm_sound_mgr_focus.h"
26 #include "../include/mm_sound_common.h"
27
28 #include <mm_debug.h>
29 #include <poll.h>
30 #include <fcntl.h>
31
32 #include "include/mm_sound_mgr_focus_dbus.h"
33 #include "../include/mm_sound_utils.h"
34 #include <sys/time.h>
35
36 #define CALLBACK_TIMEOUT          2500 /* millisecond */
37
38 static GList *g_focus_node_list = NULL;
39 static pthread_mutex_t g_focus_node_list_mutex = PTHREAD_MUTEX_INITIALIZER;
40 stream_list_t g_stream_list;
41
42 static const char* focus_status_str[] =
43 {
44         "DEACTIVATED",
45         "P ACTIVATED",
46         "C ACTIVATED",
47         "B ACTIVATED",
48 };
49
50 typedef struct {
51         int pid;
52         int handle;
53         int type;
54         int state;
55         char stream_type[MAX_STREAM_TYPE_LEN];
56         char ext_info[MM_SOUND_NAME_NUM];
57         int option;
58 } focus_cb_data;
59
60 #define CLEAR_DEAD_NODE_LIST(x)  do { \
61         debug_warning("list = %p, node = %p, pid=[%d]", x, node, (node)? node->pid : -1); \
62         if (x && node && (mm_sound_util_is_process_alive(node->pid) == FALSE)) { \
63                 debug_warning("PID:%d does not exist now! remove from device cb list", node->pid); \
64                 __clear_focus_pipe(node); \
65                 x = g_list_remove (x, node); \
66                 g_free (node); \
67         } \
68 } while (0)
69
70 #define UPDATE_FOCUS_TAKEN_INFO(x_postfix, x_node, x_pid, x_hid, x_by_session) do { \
71         debug_msg("updating node[%p], taken_"#x_postfix"[%d] : pid = [%d], handle_id = [%d], is_for_session = [%d]", x_node, i, x_pid, x_hid, x_by_session); \
72         x_node->taken_##x_postfix[i].pid = x_pid; \
73         x_node->taken_##x_postfix[i].handle_id = x_hid; \
74         x_node->taken_##x_postfix[i].by_session = x_by_session; \
75 } while (0)
76
77 #define CONTINUE_IF_LIST_DATA_IS_NULL(x_node, x_list) \
78         if (!((x_node) = (focus_node_t *)(x_list)->data)) \
79                 continue; \
80
81 #define CONTINUE_IF_NOT_MY_FOCUS_NODE(x_node, x_param) \
82         if ((x_node)->is_for_watch || ((x_node)->pid != (x_param)->pid) || ((x_node)->handle_id != (x_param)->handle_id) || \
83             ((x_node)->is_for_session != (x_param)->is_for_session)) \
84                 continue; \
85
86 static char* __get_focus_pipe_path(int instance_id, int handle, const char* postfix, bool is_watch)
87 {
88         gchar* path = NULL;
89         gchar* path2 = NULL;
90
91         if (is_watch) {
92                 path = g_strdup_printf("/tmp/FOCUS.%d.%d.wch", instance_id, handle);
93         } else {
94                 path = g_strdup_printf("/tmp/FOCUS.%d.%d", instance_id, handle);
95         }
96
97         if (postfix) {
98                 path2 = g_strconcat(path, postfix, NULL);
99                 g_free (path);
100                 path = NULL;
101                 return path2;
102         }
103
104         return path;
105 }
106
107 static void __clear_focus_pipe(focus_node_t *node)
108 {
109         char *filename = NULL;
110         char *filename2 = NULL;
111
112         debug_fenter();
113
114         if (!node->is_for_watch) {
115                 filename = __get_focus_pipe_path(node->pid, node->handle_id, NULL, false);
116                 filename2 = __get_focus_pipe_path(node->pid, node->handle_id, "r", false);
117         } else {
118                 filename = __get_focus_pipe_path(node->pid, node->handle_id, NULL, true);
119                 filename2 = __get_focus_pipe_path(node->pid, node->handle_id, "r", true);
120         }
121         if (filename) {
122                 if (remove(filename))
123                         debug_error("remove() failure, filename(%s), errno(%d)", filename, errno);
124                 else
125                         debug_log("removed file(%s)", filename);
126                 free(filename);
127         }
128         if (filename2) {
129                 if (remove(filename2))
130                         debug_error("remove() failure, filename2(%s), errno(%d)", filename2, errno);
131                 else
132                         debug_log("removed file(%s)", filename2);
133                 free(filename2);
134         }
135
136         debug_fleave();
137 }
138
139 static void _clear_focus_node_list_func(focus_node_t *node, gpointer user_data)
140 {
141         CLEAR_DEAD_NODE_LIST(g_focus_node_list);
142 }
143
144 static int _mm_sound_mgr_focus_get_priority_from_stream_type(int *priority, const char *stream_type)
145 {
146         int ret = MM_ERROR_NONE;
147         int i = 0;
148
149         debug_fenter();
150
151         if (priority == NULL || stream_type == NULL) {
152                 ret = MM_ERROR_INVALID_ARGUMENT;
153                 debug_error("invalid argument, priority[0x%x], stream_type[%s], ret[0x%x]", priority, stream_type, ret);
154         } else {
155                 for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
156                         if (g_stream_list.stream_types[i] &&
157                                 !strncmp(g_stream_list.stream_types[i], stream_type, strlen(stream_type))) {
158                                 *priority = g_stream_list.priorities[i];
159                                 break;
160                         }
161                 }
162                 if (i == AVAIL_STREAMS_MAX) {
163                         ret = MM_ERROR_NOT_SUPPORT_API;
164                         debug_error("not supported stream_type[%s], ret[0x%x]", stream_type, ret);
165                 } else {
166                         debug_log("[%s] has priority of [%d]", stream_type, *priority);
167                 }
168         }
169
170         debug_fleave();
171         return ret;
172 }
173
174 static bool _check_session_node_exist(int pid)
175 {
176         GList *list = NULL;
177         focus_node_t *node = NULL;
178
179         for (list = g_focus_node_list; list != NULL; list = list->next) {
180                 node = (focus_node_t *)list->data;
181                 if (node->pid != pid)
182                         continue;
183                 if (node->is_for_monitor)
184                         continue;
185                 if (node->is_for_session)
186                         return true;
187         }
188
189         debug_msg("session node for pid[%d] does not exist", pid);
190
191         return false;
192 }
193
194 static bool _check_session_monitor_node_exist(int pid)
195 {
196         GList *list = NULL;
197         focus_node_t *node = NULL;
198
199         for (list = g_focus_node_list; list != NULL; list = list->next) {
200                 node = (focus_node_t *)list->data;
201                 if (node->pid != pid)
202                         continue;
203                 if (node->is_for_watch && node->is_for_session && node->is_for_monitor)
204                         return true;
205         }
206
207         debug_msg("session monitor node for pid[%d] does not exist", pid);
208
209         return false;
210 }
211
212 static void _invoke_watch_callback(focus_node_t *node, const char *stream_type, focus_type_e focus_type, focus_command_e command, const _mm_sound_mgr_focus_param_t *param)
213 {
214         int ret = -1;
215         int pret = 0;
216         struct pollfd pfd;
217         char *filename = NULL;
218         char *filename2 = NULL;
219         struct timeval time;
220         int starttime = 0;
221         int endtime = 0;
222         int fd_FOCUS_R = -1;
223         int fd_FOCUS = -1;
224         focus_cb_data cb_data;
225
226         if (!node || !stream_type) {
227                 debug_error("[CB] invalid argument, node[%p], stream_type[%s]", node, stream_type);
228                 return;
229         }
230
231         memset(&cb_data, 0, sizeof(focus_cb_data));
232         cb_data.pid = node->pid;
233         cb_data.handle = node->handle_id;
234         cb_data.type = focus_type & node->status;
235         cb_data.state = (command == FOCUS_COMMAND_ACQUIRE) ? !FOCUS_STATUS_DEACTIVATED : FOCUS_STATUS_DEACTIVATED;
236         MMSOUND_STRNCPY(cb_data.stream_type, stream_type, MAX_STREAM_TYPE_LEN);
237         MMSOUND_STRNCPY(cb_data.ext_info, param->ext_info, MM_SOUND_NAME_NUM);
238         node->during_cb = true;
239
240         /* Set start time */
241         gettimeofday(&time, NULL);
242         starttime = time.tv_sec * 1000000 + time.tv_usec;
243
244         /**************************************
245          *
246          * Open callback cmd pipe
247          *
248          **************************************/
249         filename = __get_focus_pipe_path(cb_data.pid, cb_data.handle, NULL, true);
250         if (filename == NULL) {
251                 debug_error("[CB] failed to get watch pipe");
252                 goto RELEASE;
253         }
254         if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
255                 char str_error[256];
256                 strerror_r(errno, str_error, sizeof(str_error));
257                 debug_error("[CB] failed to open watch pipe (%s, err:%s)", filename, str_error);
258                 goto RELEASE;
259         }
260
261         /******************************************
262          *
263          * Open callback result pipe
264          * before writing callback cmd to pipe
265          *
266          ******************************************/
267          filename2 = __get_focus_pipe_path(cb_data.pid, cb_data.handle, "r", true);
268         if (filename2 == NULL) {
269                 debug_error("[RETCB] failed to get watch return pipe");
270                 goto RELEASE;
271         }
272         if ((fd_FOCUS_R= open(filename2, O_RDONLY|O_NONBLOCK)) == -1) {
273                 char str_error[256];
274                 strerror_r(errno, str_error, sizeof(str_error));
275                 debug_error("[RETCB] failed to open watch return pipe (%s, err:%s)", filename2, str_error);
276                 goto RELEASE;
277         }
278
279         /*******************************************
280          * Write Callback msg
281          *******************************************/
282         if (write(fd_FOCUS, &cb_data ,sizeof(cb_data)) == -1) {
283                 char str_error[256];
284                 strerror_r(errno, str_error, sizeof(str_error));
285                 debug_error("[CB] failed to write (err:%s)", str_error);
286                 goto RELEASE;
287         }
288
289         /*********************************************
290          *
291          * Wait callback result msg
292          *
293          ********************************************/
294         pfd.fd = fd_FOCUS_R;
295         pfd.events = POLLIN;
296         pfd.revents = 0;
297         debug_msg("[RETCB] wait WATCH CALLBACK (client pid=%d, cmd=%d, timeout=%d(ms))", cb_data.pid, command, CALLBACK_TIMEOUT);
298         pret = poll(&pfd, 1, CALLBACK_TIMEOUT);
299         if (pret < 0) {
300                 debug_error("[RETCB] poll failed (%d)", pret);
301                 goto RELEASE;
302         }
303         if (pfd.revents & POLLIN) {
304                 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
305                         char str_error[256];
306                         strerror_r(errno, str_error, sizeof(str_error));
307                         debug_error("[RETCB] failed to read (err:%s)", str_error);
308                         goto RELEASE;
309                 }
310         }
311
312         /* Calculate endtime and display*/
313         gettimeofday(&time, NULL);
314         endtime = time.tv_sec * 1000000 + time.tv_usec;
315         debug_msg("[RETCB] WATCH CALLBACK returned (cbtimelab=%d(ms), client pid=%d, return handle=%d)", ((endtime-starttime)/1000), cb_data.pid, ret);
316
317         /**************************************
318          *
319          * Close callback result pipe
320          *
321          **************************************/
322 RELEASE:
323         node->during_cb = false;
324
325         g_free(filename);
326         filename = NULL;
327
328         g_free(filename2);
329         filename2 = NULL;
330
331         if (fd_FOCUS != -1) {
332                 close(fd_FOCUS);
333                 fd_FOCUS = -1;
334         }
335         if (fd_FOCUS_R != -1) {
336                 close(fd_FOCUS_R);
337                 fd_FOCUS_R = -1;
338         }
339 }
340
341 /* session backward compatibility for monitor handle, it is for monitor callback of other nodes */
342 static int _mm_sound_mgr_focus_do_monitor_callback_outer(focus_type_e focus_type, focus_command_e command, focus_node_t *my_node, const _mm_sound_mgr_focus_param_t *param)
343 {
344         GList *list = NULL;
345         focus_node_t *node = NULL;
346
347         debug_fenter();
348
349         if (!my_node) {
350                 debug_error("[CB] my_node is null");
351                 return MM_ERROR_INVALID_ARGUMENT;
352         }
353
354         for (list = g_focus_node_list; list != NULL; list = list->next) {
355                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
356                 if (node == my_node)
357                         continue;
358                 /* do not invoke monitor callback of mine */
359                 if (node->pid == my_node->pid)
360                         continue;
361                 if (!node->is_for_watch || !node->is_for_monitor || !node->is_for_session)
362                         continue;
363                 if (!(node->status & focus_type))
364                         continue;
365                 /* check if it meets the condition to trigger monitor callback */
366                 if (!_check_session_monitor_node_exist(node->pid))
367                         continue;
368
369                 _invoke_watch_callback(node, my_node->stream_type, focus_type, command, param);
370         }
371
372         debug_fleave();
373
374         return MM_ERROR_NONE;
375 }
376
377 static int _mm_sound_mgr_focus_do_monitor_callback(focus_type_e focus_type, focus_command_e command, focus_node_t *my_node, const _mm_sound_mgr_focus_param_t *param)
378 {
379         GList *list = NULL;
380         focus_node_t *node = NULL;
381
382         debug_fenter();
383
384         if (!my_node) {
385                 debug_error("[CB] my_node is null");
386                 return MM_ERROR_INVALID_ARGUMENT;
387         }
388
389         for (list = g_focus_node_list; list != NULL; list = list->next) {
390                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
391                 if (!node->is_for_watch || !node->is_for_monitor || !node->is_for_session)
392                         continue;
393                 if (node == my_node || !(node->pid == my_node->pid && my_node->is_for_session))
394                         continue;
395                 if (!(node->status & focus_type))
396                         continue;
397                 /* check if it meets the condition to trigger monitor callback */
398                 if (!_check_session_node_exist(node->pid))
399                         continue;
400
401                 _invoke_watch_callback(node, param->stream_type, focus_type, command, param);
402         }
403
404         debug_fleave();
405
406         return MM_ERROR_NONE;
407 }
408
409 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)
410 {
411         GList *list = NULL;
412         focus_node_t *node = NULL;
413
414         debug_fenter();
415
416         if (!my_node) {
417                 debug_error("[CB] my_node is null");
418                 return MM_ERROR_INVALID_ARGUMENT;
419         }
420
421         for (list = g_focus_node_list; list != NULL; list = list->next) {
422                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
423                 if (node == my_node || (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session))
424                         continue;
425                 if (!node->is_for_watch || !(node->status & focus_type))
426                         continue;
427                 if (node->is_for_monitor)
428                         continue;
429                 if (node->during_cb) {
430                         debug_msg("it is about to invoke watch callback again during processing it, skip it");
431                         continue;
432                 }
433
434                 _invoke_watch_callback(node, my_node->stream_type, focus_type, command, param);
435         }
436
437         debug_fleave();
438
439         return MM_ERROR_NONE;
440 }
441
442 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)
443 {
444         int res = MM_ERROR_NONE;
445         char *filename = NULL;
446         char *filename2 = NULL;
447         struct timeval time;
448         int starttime = 0;
449         int endtime = 0;
450         int fd_FOCUS_R = -1;
451         int fd_FOCUS = -1;
452         unsigned int ret;
453         struct pollfd pfd;
454         int pret = 0;
455         int i = 0;
456         int flag_for_focus_type = 0;
457         int flag_for_taken_index = 0;
458         int taken_pid = 0;
459         int taken_hid = 0;
460         int ret_handle = -1;
461         bool taken_by_session = false;
462         bool reacquisition_changed = false;
463
464         focus_cb_data cb_data;
465
466         debug_msg("for pid(%d) handle(%d)", victim_node->pid, victim_node->handle_id);
467
468         memset(&cb_data, 0, sizeof(focus_cb_data));
469         cb_data.pid= victim_node->pid;
470         cb_data.handle= victim_node->handle_id;
471         if (command == FOCUS_COMMAND_RELEASE) {
472                 /* client will lost the acquired focus */
473                 cb_data.type= assaulter_param->request_type & victim_node->status;
474                 cb_data.state= FOCUS_STATUS_DEACTIVATED;
475                 /* remove ext info. */
476                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
477                         if (cb_data.type & (i+1)) {
478                                 memset(victim_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
479                                 victim_node->option[i] = 0;
480                         }
481                 }
482         } else {
483                 /* client will gain the lost focus */
484                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
485                         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)) {
486                                 flag_for_focus_type |= i+1; /* playback:1, capture:2 */
487                         }
488                 }
489                 cb_data.type = flag_for_focus_type & assaulter_param->request_type;
490                 cb_data.state = !FOCUS_STATUS_DEACTIVATED;
491                 /* copy ext info. */
492                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
493                         if (cb_data.type & (i+1)) {
494                                 MMSOUND_STRNCPY(victim_node->ext_info[i], assaulter_param->ext_info, MM_SOUND_NAME_NUM);
495                                 victim_node->option[i] = assaulter_param->option;
496                         }
497                 }
498         }
499         MMSOUND_STRNCPY(cb_data.stream_type, assaulter_param->stream_type, MAX_STREAM_TYPE_LEN);
500         MMSOUND_STRNCPY(cb_data.ext_info, assaulter_param->ext_info, MM_SOUND_NAME_NUM);
501         cb_data.option = assaulter_param->option;
502
503         /* Set start time */
504         gettimeofday(&time, NULL);
505         starttime = time.tv_sec * 1000000 + time.tv_usec;
506
507         /**************************************
508          *
509          * Open callback cmd pipe
510          *
511          **************************************/
512         filename = __get_focus_pipe_path(cb_data.pid, cb_data.handle, NULL, false);
513         if (filename == NULL) {
514                 debug_error("[CB] failed to get pipe");
515                 res = -1;
516                 goto RELEASE;
517         }
518         if ((fd_FOCUS = open(filename, O_WRONLY|O_NONBLOCK)) == -1) {
519                 char str_error[256];
520                 strerror_r(errno, str_error, sizeof(str_error));
521                 debug_error("[CB] failed to open pipe (%s, err:%s)", filename, str_error);
522                 res = -1;
523                 goto RELEASE;
524         }
525
526         /******************************************
527          *
528          * Open callback result pipe
529          * before writing callback cmd to pipe
530          *
531          ******************************************/
532         filename2 = __get_focus_pipe_path(cb_data.pid, cb_data.handle, "r", false);
533         if (filename2 == NULL) {
534                 debug_error("[RETCB] failed to get return pipe");
535                 res = -1;
536                 goto RELEASE;
537         }
538         if ((fd_FOCUS_R = open(filename2,O_RDONLY|O_NONBLOCK)) == -1) {
539                 char str_error[256];
540                 strerror_r(errno, str_error, sizeof(str_error));
541                 debug_error("[RETCB] failed to open return pipe (%s, err:%s)", filename2, str_error);
542                 res = -1;
543                 goto RELEASE;
544         }
545
546         /*******************************************
547          * Write Callback msg
548          *******************************************/
549         if (write(fd_FOCUS, &cb_data, sizeof(cb_data)) == -1) {
550                 char str_error[256];
551                 strerror_r(errno, str_error, sizeof(str_error));
552                 debug_error("[CB] failed to write (err:%s)", str_error);
553                 res = -1;
554                 goto RELEASE;
555         }
556
557         /*********************************************
558          *
559          * Wait callback result msg
560          *
561          ********************************************/
562         pfd.fd = fd_FOCUS_R;
563         pfd.events = POLLIN;
564         pfd.revents = 0;
565         debug_msg("[RETCB] wait CALLBACK (client pid=%d, handle=%d, cmd=%d, timeout=%d(ms))",cb_data.pid, cb_data.handle, command, CALLBACK_TIMEOUT);
566         pret = poll(&pfd, 1, CALLBACK_TIMEOUT);
567         if (pret < 0) {
568                 debug_error("[RETCB] poll failed (%d)", pret);
569                 res = -1;
570                 goto RELEASE;
571         }
572         if (pfd.revents & POLLIN) {
573                 if (read(fd_FOCUS_R, &ret, sizeof(ret)) == -1) {
574                         char str_error[256];
575                         strerror_r(errno, str_error, sizeof(str_error));
576                         debug_error("[RETCB] failed to read (err:%s)", str_error);
577                         res = -1;
578                         goto RELEASE;
579                 }
580                 /* ret contains data as below,
581                  * |<--12bits--><--4bits (reacquisition)--><--16bits (handle)-->| */
582                 ret_handle = (int)(ret & 0x0000ffff);
583                 if (victim_node->reacquisition != (bool)((ret >> 16) & 0xf)) {
584                         reacquisition_changed = true;
585                         victim_node->reacquisition = (bool)((ret >> 16) & 0xf);
586                         debug_msg("[RETCB] victim's reacquisition is changed to (%d)", victim_node->reacquisition);
587                 }
588         }
589
590         /* Calculate endtime and display*/
591         gettimeofday(&time, NULL);
592         endtime = time.tv_sec * 1000000 + time.tv_usec;
593         debug_msg("[RETCB] CALLBACK returned (cbtimelab=%d(ms), client pid=%d, returned handle=%d)", ((endtime-starttime)/1000), cb_data.pid, ret_handle);
594
595         /* update victim node */
596         if (command == FOCUS_COMMAND_RELEASE) {
597                 taken_pid = assaulter_param->pid;
598                 taken_hid = assaulter_param->handle_id;
599                 taken_by_session = assaulter_param->is_for_session;
600                 flag_for_taken_index = assaulter_param->request_type & victim_node->status;
601         } else {
602                 taken_pid = 0;
603                 taken_hid = 0;
604                 taken_by_session = false;
605                 flag_for_taken_index = assaulter_param->request_type;
606         }
607
608         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
609                 if (flag_for_taken_index & (i+1)) {
610                         GList *list = NULL;
611                         focus_node_t *node = NULL;
612
613                         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)))) {
614                                 /* skip */
615                                 debug_error("skip updating victim node");
616                                 continue;
617                         }
618                         if (reacquisition_changed) {
619                                 if (!victim_node->reacquisition) {
620                                         for (list = g_focus_node_list; list != NULL; list = list->next) {
621                                                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
622                                                 if (node->taken_by_id[i].pid == victim_node->pid) {
623                                                         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);
624                                                         UPDATE_FOCUS_TAKEN_INFO(by_id, node, taken_pid, taken_hid, taken_by_session);
625                                                 } else if (!list->next) {
626                                                         UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, taken_pid, taken_hid, taken_by_session);
627                                                         UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, 0, 0, false);
628                                                 }
629                                         }
630                                 } else {
631                                         for (list = g_focus_node_list; list != NULL; list = list->next) {
632                                                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
633                                                 if (node->taken_backup[i].pid == victim_node->pid) {
634                                                         UPDATE_FOCUS_TAKEN_INFO(by_id, node, node->taken_backup[i].pid, node->taken_backup[i].handle_id, node->taken_backup[i].by_session);
635                                                         UPDATE_FOCUS_TAKEN_INFO(backup, node, 0, 0, false);
636                                                 } else if (!list->next) {
637                                                         UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, taken_pid, taken_hid, taken_by_session);
638                                                         UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, 0, 0, false);
639                                                 }
640                                         }
641                                 }
642                         } else {
643                                 if (victim_node->reacquisition)
644                                         UPDATE_FOCUS_TAKEN_INFO(by_id, victim_node, taken_pid, taken_hid, taken_by_session);
645                                 else
646                                         UPDATE_FOCUS_TAKEN_INFO(backup, victim_node, taken_pid, taken_hid, taken_by_session);
647                         }
648                 }
649         }
650
651         if (command == FOCUS_COMMAND_RELEASE || victim_node->reacquisition_with_released_state)
652                 victim_node->status = victim_node->status & ~(cb_data.type);
653         else if (command == FOCUS_COMMAND_ACQUIRE)
654                 victim_node->status = victim_node->status | cb_data.type;
655
656         if (strncmp(assaulter_param->stream_type, victim_node->stream_type, MAX_STREAM_TYPE_LEN))
657                 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)assaulter_param->request_type, command, victim_node, assaulter_param);
658         _mm_sound_mgr_focus_do_monitor_callback((focus_type_e)assaulter_param->request_type, command, victim_node, assaulter_param);
659
660 RELEASE:
661         g_free(filename);
662         filename = NULL;
663
664         g_free(filename2);
665         filename2 = NULL;
666
667         if (fd_FOCUS != -1) {
668                 close(fd_FOCUS);
669                 fd_FOCUS = -1;
670         }
671         if (fd_FOCUS_R != -1) {
672                 close (fd_FOCUS_R);
673                 fd_FOCUS_R = -1;
674         }
675
676         return res;
677 }
678
679 static int _mm_sound_mgr_focus_list_dump ()
680 {
681         int ret = MM_ERROR_NONE;
682         GList *list = NULL;
683         focus_node_t *node = NULL;
684
685         debug_msg("================================================ focus node list : start ===================================================");
686         for (list = g_focus_node_list; list != NULL; list = list->next) {
687                 if ((node = (focus_node_t *)list->data) && !node->is_for_watch) {
688                         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]",
689                                   node->pid, node->handle_id, node->stream_type, node->priority, focus_status_str[node->status],
690                                   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,
691                                   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]);
692                 }
693         }
694         debug_msg("================================================ focus node list : end =====================================================");
695
696         return ret;
697 }
698
699 static int _mm_sound_mgr_focus_watch_list_dump()
700 {
701         int ret = MM_ERROR_NONE;
702         GList *list = NULL;
703         focus_node_t *node = NULL;
704
705         debug_msg("============================================= focus watch node list : start =================================================");
706         for (list = g_focus_node_list; list != NULL; list = list->next) {
707                 if ((node = (focus_node_t *)list->data) && node->is_for_watch)
708                         debug_msg("*** pid[%5d]/handle_id[%d]/watch on focus status[%s]/for_session[%d]/for_monitor[%d]",
709                                   node->pid, node->handle_id, focus_status_str[node->status], node->is_for_session, node->is_for_monitor);
710         }
711         debug_msg("============================================= focus watch node list : end ===================================================");
712
713         return ret;
714 }
715
716 static void _mm_sound_mgr_focus_fill_info_from_msg(focus_node_t *node, const _mm_sound_mgr_focus_param_t *msg)
717 {
718         debug_fenter();
719         node->pid = msg->pid;
720         node->handle_id = msg->handle_id;
721         node->callback = msg->callback;
722         node->cbdata = msg->cbdata;
723         node->is_for_session = msg->is_for_session;
724
725         debug_fleave();
726         return;
727 }
728
729 int mm_sound_mgr_focus_create_node(const _mm_sound_mgr_focus_param_t *param)
730 {
731         int ret = MM_ERROR_NONE;
732         GList *list = NULL;
733         focus_node_t *node = NULL;
734         int priority = 0;
735
736         debug_fenter();
737
738         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
739
740         /* Update list for dead process */
741         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
742
743         for (list = g_focus_node_list; list != NULL; list = list->next) {
744                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
745                 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
746
747                 debug_error("the node of pid[%d]/handle_id[%d] is already created", param->pid, param->handle_id);
748                 ret = MM_ERROR_INVALID_ARGUMENT;
749                 goto FINISH;
750         }
751
752         /* get priority from stream type */
753         ret = _mm_sound_mgr_focus_get_priority_from_stream_type(&priority, param->stream_type);
754         if (ret) {
755                 goto FINISH;
756         }
757         node = g_malloc0(sizeof(focus_node_t));
758
759         /* fill up information to the node */
760         _mm_sound_mgr_focus_fill_info_from_msg(node, param);
761         node->priority = priority;
762         node->status = FOCUS_STATUS_DEACTIVATED;
763         node->reacquisition = true;
764         MMSOUND_STRNCPY(node->stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
765
766         g_focus_node_list = g_list_append(g_focus_node_list, node);
767         if (g_focus_node_list) {
768                 debug_log("new focus node is added");
769         } else {
770                 debug_error("g_list_append failed");
771                 ret = MM_ERROR_SOUND_INTERNAL;
772                 g_free(node);
773         }
774
775         _mm_sound_mgr_focus_list_dump();
776 FINISH:
777         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
778
779         debug_fleave();
780         return ret;
781 }
782
783 int mm_sound_mgr_focus_destroy_node(const _mm_sound_mgr_focus_param_t *param)
784 {
785         int ret = MM_ERROR_NONE;
786         GList *list = NULL;
787         focus_node_t *node = NULL;
788         focus_node_t *my_node = NULL;
789         bool need_to_trigger = true;
790         int i = 0;
791
792         debug_fenter();
793
794         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
795
796         /* Update list for dead process */
797         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
798
799         for (list = g_focus_node_list; list != NULL; list = list->next) {
800                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
801                 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
802
803                 debug_log("found the node of pid[%d]/handle_id[%d]", param->pid, param->handle_id);
804                 my_node = node;
805                 break;
806         }
807         if (my_node == NULL) {
808                 debug_error("could not find any node of pid[%d]/handle_id[%d]/is_for_session[%d]", param->pid, param->handle_id, param->is_for_session);
809                 ret = MM_ERROR_INVALID_ARGUMENT;
810                 goto FINISH;
811         }
812
813         /* Check if there's remaining focus for session for the same PID of incomming param */
814         if (my_node->is_for_session) {
815                 for (list = g_focus_node_list; list != NULL; list = list->next) {
816                         CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
817                         if (my_node == node || node->is_for_watch)
818                                 continue;
819                         if (node->pid == my_node->pid && node->is_for_session && node->status) {
820                                 debug_warning("another focus node for session of this pid exists, skip invoking callback");
821                                 need_to_trigger = false;
822                                 break;
823                         }
824                 }
825         }
826
827         if (need_to_trigger) {
828                 bool need_to_trigger_watch_cb = true;
829                 _mm_sound_mgr_focus_param_t *new_param = NULL;
830
831                 if (!(new_param = g_malloc0(sizeof(_mm_sound_mgr_focus_param_t)))) {
832                         debug_error("Fail to g_malloc0 for new_param");
833                         goto CLEAR_NODE;
834                 }
835                 new_param->pid = param->pid;
836                 new_param->handle_id = param->handle_id;
837                 new_param->is_for_session = my_node->is_for_session;
838                 new_param->request_type = my_node->status;
839                 new_param->option = my_node->option[i];
840                 MMSOUND_STRNCPY(new_param->stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
841                 MMSOUND_STRNCPY(new_param->ext_info, my_node->ext_info[i], MM_SOUND_NAME_NUM);
842
843                 for (list = g_focus_node_list; list != NULL; list = list->next) {
844                         CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
845                         if (my_node == node || node->is_for_watch)
846                                 continue;
847                         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
848                                 if (node->taken_by_id[i].pid != param->pid)
849                                         continue;
850
851                                 if (my_node->taken_by_id[i].pid) {
852                                 /* If exists update the taken focus info to my victim node */
853                                         if (node->taken_by_id[i].by_session && !node->status) {
854                                                 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);
855                                         } else if (node->taken_by_id[i].handle_id == param->handle_id) {
856                                                 UPDATE_FOCUS_TAKEN_INFO(by_id, node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, false);
857                                         }
858                                 } else if (my_node->status & (i+1)) {
859                                         if (node->is_for_session)
860                                                 continue;
861                                         if (node->taken_by_id[i].handle_id == new_param->handle_id || node->taken_by_id[i].by_session) {
862                                                 /* do callback for resumption */
863                                                 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, new_param)))
864                                                         debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]", node, ret);
865                                                 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
866                                                         need_to_trigger_watch_cb = false;
867                                                         my_node->status &= ~(new_param->request_type);
868                                                 }
869                                         }
870                                 }
871                         }
872                 }
873                 if (need_to_trigger_watch_cb)
874                         _mm_sound_mgr_focus_do_watch_callback((focus_type_e)new_param->request_type, FOCUS_COMMAND_RELEASE, my_node, new_param);
875
876                 g_free(new_param);
877         }
878
879 CLEAR_NODE:
880         /* Destroy my node  */
881         __clear_focus_pipe(my_node);
882         g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
883         g_free(my_node);
884 FINISH:
885         _mm_sound_mgr_focus_list_dump();
886         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
887
888         debug_fleave();
889         return ret;
890 }
891
892 int mm_sound_mgr_focus_set_reacquisition(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         int i;
899
900         debug_fenter();
901
902         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
903
904         /* Update list for dead process */
905         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
906
907         /* Find node to set reacquisition */
908         for (list = g_focus_node_list; list != NULL; list = list->next) {
909                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
910                 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
911
912                 if (node->reacquisition == param->reacquisition) {
913                         debug_msg("it is already set as same value of reacquisition(%d)", param->reacquisition);
914                         goto FINISH;
915                 }
916                 node->reacquisition = param->reacquisition;
917                 debug_msg("found a node(pid[%d]/handle_id[%d]) to set reacquisition to (%d)", node->pid, node->handle_id, param->reacquisition);
918                 my_node = node;
919                 break;
920         }
921         if (my_node == NULL) {
922                 debug_error("could not find any node of pid[%d]/handle_id[%d]", param->pid, param->handle_id);
923                 ret = MM_ERROR_INVALID_ARGUMENT;
924                 goto FINISH;
925         }
926
927         if (!param->reacquisition) {
928                 for (list = g_focus_node_list; list != NULL; list = list->next) {
929                         CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
930                         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
931                                 if (node->taken_by_id[i].pid == param->pid) {
932                                         /* victim node : append my node's taken info to my victim node */
933                                         if (my_node->taken_by_id[i].pid != 0) {
934                                                 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);
935                                                 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);
936                                         }
937                                 } else if (!list->next) {
938                                         /* my node : backup and reset */
939                                         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);
940                                         UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, 0, 0, false);
941                                 }
942                         }
943                 }
944         } else {
945                 for (list = g_focus_node_list; list != NULL; list = list->next) {
946                         CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
947                         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
948                                 /* rollback and reset backup info. */
949                                 if (node->taken_by_id[i].pid && (node->taken_by_id[i].pid == my_node->taken_backup[i].pid)) {
950                                         UPDATE_FOCUS_TAKEN_INFO(by_id, node, node->taken_backup[i].pid, node->taken_backup[i].handle_id, node->taken_backup[i].by_session);
951                                         UPDATE_FOCUS_TAKEN_INFO(backup, node, 0, 0, false);
952                                 } else if (!list->next) {
953                                         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);
954                                         UPDATE_FOCUS_TAKEN_INFO(backup, my_node, 0, 0, false);
955                                 }
956                         }
957                 }
958         }
959
960 FINISH:
961         _mm_sound_mgr_focus_list_dump();
962         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
963
964         debug_fleave();
965         return ret;
966 }
967
968 int mm_sound_mgr_focus_get_stream_type_of_acquired_focus(focus_type_e focus_type, char **stream_type, int *option, char **ext_info)
969 {
970         int ret = MM_ERROR_SOUND_NO_DATA;
971         GList *list = NULL;
972         focus_node_t *node = NULL;
973
974         debug_fenter();
975
976         if (!stream_type || !option)
977                 return MM_ERROR_INVALID_ARGUMENT;
978
979         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
980
981         /* Update list for dead process */
982         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
983
984         /* Find node to set reacquisition */
985         for (list = g_focus_node_list; list != NULL; list = list->next) {
986                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
987                 if (!node->is_for_watch && (node->status & focus_type)) {
988                          /* In case of FOCUS_TYPE_BOTH, we use index for FOCUS_TYPE_PLAYBACK's forcedly.
989                           * It is because this function can not return both index of option, ext_info results
990                           * via out-parameter. This case is only used in framework internally for session
991                           * backward compatibilty. */
992                         int index = (focus_type == FOCUS_TYPE_BOTH) ? FOCUS_TYPE_PLAYBACK - 1 : focus_type - 1;
993
994                         debug_msg("found a node : request_focus_type(%d), stream_type(%s)/ext info(%s) of acquired focus",
995                                   focus_type, node->stream_type, node->ext_info[index]);
996
997                         *stream_type = node->stream_type;
998                         *option = node->option[index];
999                         if (ext_info)
1000                                 *ext_info = node->ext_info[index];
1001                         ret = MM_ERROR_NONE;
1002                         break;
1003                 }
1004         }
1005
1006         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1007
1008         debug_fleave();
1009
1010         return ret;
1011 }
1012
1013 static void update_reacquisition_with_released_state(focus_node_t *node, int direction)
1014 {
1015         if (!node) {
1016                 debug_error("node is null");
1017                 return;
1018         }
1019         if (direction >= NUM_OF_STREAM_IO_TYPE) {
1020                 debug_error("invalid direction(%d)", direction);
1021                 return;
1022         }
1023
1024         /* In case of session backward compatibility for audio-io, mm-player, mm-camcorder, we mark a specific flag here.
1025          When invoking focus state changed callback for acquiring, state of the node will not be updated rather updated
1026          when the next request to acquire. */
1027         if (!strncmp("audio-io acquire focus", node->ext_info[direction], MM_SOUND_NAME_NUM) ||
1028             !strncmp("mm-player acquire focus", node->ext_info[direction], MM_SOUND_NAME_NUM) ||
1029             !strncmp("mm-camcorder acquire focus", node->ext_info[direction], MM_SOUND_NAME_NUM)) {
1030                 debug_msg("this node[pid:%d, handle_id:%d] needs reacquisition with focus released state", node->pid, node->handle_id);
1031                 node->reacquisition_with_released_state = true;
1032         }
1033 }
1034
1035 int mm_sound_mgr_focus_request_acquire(const _mm_sound_mgr_focus_param_t *param)
1036 {
1037         int ret = MM_ERROR_NONE;
1038         GList *list = NULL;
1039         focus_node_t *node = NULL;
1040         focus_node_t *my_node = NULL;
1041         bool need_to_trigger_cb = false;
1042         bool need_to_trigger_watch_cb = true;
1043         bool need_to_trigger_monitor_cb = true;
1044         int i;
1045
1046         debug_fenter();
1047
1048         if (!param->is_in_thread)
1049                 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1050
1051         /* Update list for dead process */
1052         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1053
1054         for (list = g_focus_node_list; list != NULL; list = list->next) {
1055                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1056                 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
1057
1058                 my_node = node;
1059                 if ((my_node->status > FOCUS_STATUS_DEACTIVATED) && (my_node->status & param->request_type)) {
1060                         debug_error("focus status is already activated");
1061                         ret = MM_ERROR_SOUND_INVALID_STATE;
1062                         goto FINISH;
1063                 }
1064         }
1065
1066         if (my_node == NULL) {
1067                 debug_error("node is null");
1068                 ret = MM_ERROR_INVALID_ARGUMENT;
1069                 goto FINISH;
1070         }
1071
1072         /* check if the priority of any node is higher than its based on io direction */
1073         for (list = g_focus_node_list; list != NULL; list = list->next) {
1074                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1075                 if (my_node == node || node->is_for_watch)
1076                         continue;
1077                 if (param->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
1078                         (node->status & param->request_type)) {
1079                         if (node->status <= FOCUS_STATUS_DEACTIVATED)
1080                                 continue;
1081
1082                         if ((my_node->priority < node->priority)) {
1083                                 ret = MM_ERROR_POLICY_BLOCKED;
1084                                 need_to_trigger_cb = false;
1085                                 break;
1086                         } else {
1087                                 need_to_trigger_cb = true;
1088                         }
1089                 }
1090         }
1091
1092         if (need_to_trigger_cb) {
1093                 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
1094                 param_s->is_for_session = my_node->is_for_session;
1095                 MMSOUND_STRNCPY(param_s->stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
1096                 for (list = g_focus_node_list; list != NULL; list = list->next) {
1097                         CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1098                         if (node == my_node || node->is_for_watch)
1099                                 continue;
1100                         if (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session)
1101                                 continue;
1102                         if (param_s->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
1103                                 (node->status & param_s->request_type)) {
1104                                 if (node->status <= FOCUS_STATUS_DEACTIVATED)
1105                                         continue;
1106                                 if (my_node->priority >= node->priority) {
1107                                         /* do callback for interruption */
1108                                         if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_RELEASE, node, param_s))) {
1109                                                 debug_error("Fail to _focus_do_callback for COMMAND RELEASE to node[%x], ret[0x%x]", node, ret);
1110                                                 /* but, keep going */
1111                                                 ret = MM_ERROR_NONE;
1112                                         }
1113                                         if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN))
1114                                                 need_to_trigger_watch_cb = false;
1115
1116                                         need_to_trigger_monitor_cb = false;
1117                                 }
1118                         }
1119                 }
1120         }
1121
1122         if (ret != MM_ERROR_POLICY_BLOCKED) {
1123                 /* copy ext info. */
1124                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1125                         if (param->request_type & (i+1)) {
1126                                 MMSOUND_STRNCPY(my_node->ext_info[i], param->ext_info, MM_SOUND_NAME_NUM);
1127                                 my_node->option[i] = param->option;
1128                                 update_reacquisition_with_released_state(my_node, i);
1129                         }
1130                 }
1131                 /* update status */
1132                 my_node->status |= param->request_type;
1133                 /* do watch callback due to the status of mine */
1134                 if (need_to_trigger_watch_cb)
1135                         _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_ACQUIRE, my_node, param);
1136                 if (need_to_trigger_monitor_cb)
1137                         _mm_sound_mgr_focus_do_monitor_callback_outer((focus_type_e)param->request_type, FOCUS_COMMAND_RELEASE, my_node, param);
1138
1139                 /* update taken information */
1140                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1141                         if (param->request_type & (i+1)) {
1142                                 UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, 0, 0, false);
1143                                 UPDATE_FOCUS_TAKEN_INFO(backup, my_node, 0, 0, false);
1144                         }
1145                 }
1146         }
1147
1148         _mm_sound_mgr_focus_list_dump();
1149         _mm_sound_mgr_focus_watch_list_dump ();
1150 FINISH:
1151         if (!param->is_in_thread)
1152                 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1153
1154         debug_fleave();
1155         return ret;
1156 }
1157
1158 int mm_sound_mgr_focus_request_release(const _mm_sound_mgr_focus_param_t *param)
1159 {
1160         int ret = MM_ERROR_NONE;
1161         GList *list = NULL;
1162         focus_node_t *node = NULL;
1163         focus_node_t *my_node = NULL;
1164         bool need_to_trigger_watch_cb = true;
1165         bool need_to_trigger_monitor_cb = true;
1166         bool need_to_trigger_cb = true;
1167         int i = 0;
1168
1169         debug_fenter();
1170
1171         if (!param->is_in_thread)
1172                 MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1173
1174         /* Update list for dead process */
1175         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1176
1177         for (list = g_focus_node_list; list != NULL; list = list->next) {
1178                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1179                 CONTINUE_IF_NOT_MY_FOCUS_NODE(node, param);
1180
1181                 my_node = node;
1182                 if (my_node->status == FOCUS_STATUS_DEACTIVATED) {
1183                         debug_error("focus status is already deactivated");
1184                         ret = MM_ERROR_SOUND_INVALID_STATE;
1185                         goto FINISH;
1186                 } else if ((my_node->status != FOCUS_STATUS_ACTIVATED_BOTH) && (my_node->status != (focus_status_e)param->request_type)) {
1187                         debug_error("request type is not matched with current focus type");
1188                         ret = MM_ERROR_SOUND_INVALID_STATE;
1189                         goto FINISH;
1190                 }
1191                 break;
1192         }
1193
1194         if (my_node == NULL) {
1195                 debug_error("node is null");
1196                 ret = MM_ERROR_INVALID_ARGUMENT;
1197                 goto FINISH;
1198         }
1199
1200         /* Check if there's activating focus for session for the same PID of incomming param*/
1201         if (my_node->is_for_session) {
1202                 for (list = g_focus_node_list; list != NULL; list = list->next) {
1203                         CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1204                         if (node == my_node || node->is_for_watch)
1205                                 continue;
1206                         if (node->pid == my_node->pid && node->is_for_session && node->status) {
1207                                 debug_warning("another focus node for session of this pid exists, skip invoking callback");
1208                                 need_to_trigger_watch_cb = false;
1209                                 need_to_trigger_cb = false;
1210                                 break;
1211                         }
1212                 }
1213         }
1214
1215         if (need_to_trigger_cb) {
1216                 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
1217                 param_s->is_for_session = my_node->is_for_session;
1218                 MMSOUND_STRNCPY(param_s->stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
1219                 for (list = g_focus_node_list; list != NULL; list = list->next) {
1220                         CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1221                         if (node == my_node || node->is_for_watch)
1222                                 continue;
1223                         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1224                                 if (param_s->request_type & (i+1)) {
1225                                         if (node->taken_by_id[i].pid == param_s->pid &&
1226                                             (node->taken_by_id[i].handle_id == param_s->handle_id || node->taken_by_id[i].by_session)) {
1227                                                 /* exception case as per the previous session policy,
1228                                                  * "session resumption" is only available for "media session" */
1229                                                 if (my_node->is_for_session && node->is_for_session) {
1230                                                         if (strncmp(node->stream_type, "media", MAX_STREAM_TYPE_LEN))
1231                                                                 continue;
1232                                                 }
1233                                                 /* do callback for resumption */
1234                                                 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, param_s)))
1235                                                         debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]", node, ret);
1236                                                 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
1237                                                         need_to_trigger_watch_cb = false;
1238                                                 }
1239                                                 need_to_trigger_monitor_cb = false;
1240                                         }
1241                                 }
1242                         }
1243                 }
1244         }
1245         /* update status */
1246         my_node->status &= ~(param->request_type);
1247         /* remove ext info. */
1248         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1249                 if (!(my_node->status & (i+1))) {
1250                         memset(my_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
1251                         my_node->option[i] = 0;
1252                 }
1253         }
1254         /* do watch callback due to the status of mine */
1255         if (need_to_trigger_watch_cb)
1256                 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_RELEASE, my_node, param);
1257         if (need_to_trigger_monitor_cb)
1258                 _mm_sound_mgr_focus_do_monitor_callback_outer((focus_type_e)param->request_type, FOCUS_COMMAND_ACQUIRE, my_node, param);
1259
1260         _mm_sound_mgr_focus_list_dump();
1261         _mm_sound_mgr_focus_watch_list_dump ();
1262 FINISH:
1263         if (!param->is_in_thread)
1264                 MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1265
1266         debug_fleave();
1267         return ret;
1268 }
1269
1270 int mm_sound_mgr_focus_set_watch_cb(const _mm_sound_mgr_focus_param_t *param)
1271 {
1272         int ret = MM_ERROR_NONE;
1273         GList *list = NULL;
1274         focus_node_t *node = NULL;
1275
1276         debug_fenter();
1277
1278         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1279
1280         /* Update list for dead process */
1281         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1282
1283         for (list = g_focus_node_list; list != NULL; list = list->next) {
1284                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1285                 if ((node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1286                         debug_error("the node of pid[%d]/handle_id[%d] for watch focus is already created", param->pid, param->handle_id);
1287                         ret = MM_ERROR_INVALID_ARGUMENT;
1288                         goto FINISH;
1289                 }
1290         }
1291
1292         node = g_malloc0(sizeof(focus_node_t));
1293
1294         /* fill up information to the node */
1295         _mm_sound_mgr_focus_fill_info_from_msg(node, param);
1296         node->is_for_watch = true;
1297         node->is_for_monitor = param->is_for_monitor;
1298         node->status = param->request_type;
1299
1300         g_focus_node_list = g_list_append(g_focus_node_list, node);
1301         if (g_focus_node_list) {
1302                 debug_log("new focus node is added");
1303         } else {
1304                 debug_error("g_list_append failed");
1305                 ret = MM_ERROR_SOUND_INTERNAL;
1306                 g_free(node);
1307         }
1308
1309         _mm_sound_mgr_focus_watch_list_dump();
1310 FINISH:
1311         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1312
1313         debug_fleave();
1314         return ret;
1315 }
1316
1317 int mm_sound_mgr_focus_unset_watch_cb(const _mm_sound_mgr_focus_param_t *param)
1318 {
1319         int ret = MM_ERROR_SOUND_INTERNAL;
1320         GList *list = NULL;
1321         focus_node_t *node = NULL;
1322
1323         debug_fenter();
1324
1325         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1326
1327         /* Update list for dead process */
1328         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1329
1330         for (list = g_focus_node_list; list != NULL; list = list->next) {
1331                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1332                 if ((node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1333                         debug_log("found the node of pid[%d]/handle_id[%d] for watch focus", param->pid, param->handle_id);
1334                         __clear_focus_pipe(node);
1335                         g_focus_node_list = g_list_remove(g_focus_node_list, node);
1336                         g_free(node);
1337                         ret = MM_ERROR_NONE;
1338                         break;
1339                 }
1340         }
1341         if (list == NULL) {
1342                 debug_error("could not find any node of pid[%d]/handle_id[%d] for watch focus", param->pid, param->handle_id);
1343                 ret = MM_ERROR_INVALID_ARGUMENT;
1344                 goto FINISH;
1345         }
1346
1347         _mm_sound_mgr_focus_watch_list_dump();
1348 FINISH:
1349         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1350
1351         debug_fleave();
1352         return ret;
1353 }
1354
1355 int mm_sound_mgr_focus_deliver(const _mm_sound_mgr_focus_param_t *param)
1356 {
1357         int ret = MM_ERROR_NONE;
1358         GList *list = NULL;
1359         focus_node_t *src_node = NULL;
1360         focus_node_t *dst_node = NULL;
1361         int i = 0;
1362
1363         debug_fenter();
1364
1365         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1366
1367         /* Update list for dead process */
1368         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1369
1370         for (list = g_focus_node_list; list != NULL; list = list->next) {
1371                 CONTINUE_IF_LIST_DATA_IS_NULL(src_node, list);
1372                 if ((src_node->pid == param->pid) && (src_node->handle_id == param->handle_id)) {
1373                         debug_log("SRC: found the node of pid[%d]/handle_id[%d] for watch focus",
1374                                   param->pid, param->handle_id);
1375                         break;
1376                 }
1377         }
1378         if (src_node == NULL) {
1379                 debug_error("could not find the source node of param, pid[%d]/handle_id[%d]",
1380                             param->pid, param->handle_id);
1381                 ret = MM_ERROR_INVALID_ARGUMENT;
1382                 goto FINISH;
1383         }
1384
1385         if (!(src_node->status & param->request_type)) {
1386                 debug_error("invalid request type(0x%x), src_node->status(0x%x)",
1387                             param->request_type, src_node->status);
1388                 ret = MM_ERROR_SOUND_INVALID_STATE;
1389                 goto FINISH;
1390         }
1391
1392         for (list = g_focus_node_list; list != NULL; list = list->next) {
1393                 CONTINUE_IF_LIST_DATA_IS_NULL(dst_node, list);
1394                 if ((dst_node->pid == param->pid) && (dst_node->handle_id == param->handle_id_dst)) {
1395                         debug_log("DST: found the destination node of param, pid[%d]/handle_id[%d]",
1396                                   param->pid, param->handle_id_dst);
1397                         break;
1398                 }
1399         }
1400         if (dst_node == NULL) {
1401                 debug_error("could not find the destination node of param, pid[%d]/handle_id[%d]",
1402                             param->pid, param->handle_id_dst);
1403                 ret = MM_ERROR_INVALID_ARGUMENT;
1404                 goto FINISH;
1405         }
1406
1407         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1408                 focus_node_t *node = NULL;
1409                 if (!(param->request_type & (i+1)))
1410                         continue;
1411
1412                 for (list = g_focus_node_list; list != NULL; list = list->next) {
1413                         CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1414                         if ((node->taken_by_id[i].pid == src_node->pid) &&
1415                             (node->taken_by_id[i].handle_id == src_node->handle_id) &&
1416                             (node->taken_by_id[i].by_session == false)) {
1417                                 debug_log("found the node that focus was taken by this src node, update it",
1418                                           node->pid, node->handle_id);
1419                                 UPDATE_FOCUS_TAKEN_INFO(by_id, node, dst_node->pid, dst_node->handle_id, false);
1420                         }
1421                         if ((node->taken_backup[i].pid == src_node->pid) &&
1422                             (node->taken_backup[i].handle_id == src_node->handle_id) &&
1423                             (node->taken_backup[i].by_session == false)) {
1424                                 debug_log("found the node that focus was taken by this src node and set reacquisition to false, update it",
1425                                           node->pid, node->handle_id);
1426                                 UPDATE_FOCUS_TAKEN_INFO(backup, node, dst_node->pid, dst_node->handle_id, false);
1427                         }
1428                 }
1429
1430                 dst_node->status |= (i+1);
1431                 UPDATE_FOCUS_TAKEN_INFO(by_id, dst_node, 0, 0, false);
1432                 UPDATE_FOCUS_TAKEN_INFO(backup, dst_node, 0, 0, false);
1433                 MMSOUND_STRNCPY(dst_node->ext_info[i], src_node->ext_info[i], MM_SOUND_NAME_NUM);
1434                 dst_node->option[i] = src_node->option[i];
1435
1436                 src_node->status &= ~(i+1);
1437                 memset(src_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
1438                 src_node->option[i] = 0;
1439         }
1440
1441         _mm_sound_mgr_focus_list_dump();
1442
1443 FINISH:
1444         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1445
1446         debug_fleave();
1447         return ret;
1448 }
1449
1450 int mm_sound_mgr_focus_emergent_exit(const _mm_sound_mgr_focus_param_t *param)
1451 {
1452         int ret = MM_ERROR_NONE;
1453         GList *list = NULL;
1454         GList *list_s =NULL;
1455         focus_node_t *node = NULL;
1456         focus_node_t *my_node = NULL;
1457         int i;
1458
1459         debug_fenter();
1460
1461         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1462
1463         /* Update list for dead process */
1464         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1465
1466         list = g_focus_node_list;
1467         while (list) {
1468                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list);
1469                 if (node->pid != param->pid) {
1470                         list = list->next;
1471                         debug_log("node not found, next list = %p",list);
1472                         continue;
1473                 }
1474                 if (node->is_for_watch) {
1475                         debug_log("clearing watch cb of pid(%d) handle(%d)", node->pid, node->handle_id);
1476                         __clear_focus_pipe(node);
1477                         g_focus_node_list = g_list_remove(g_focus_node_list, node);
1478                         list = g_focus_node_list;
1479                         g_free(node);
1480                         continue;
1481                 }
1482                 if (node->status == FOCUS_STATUS_DEACTIVATED) {
1483                         debug_log("clearing deactivated focus node of pid(%d) hande(%d)", node->pid, node->handle_id);
1484                         my_node = node;
1485                         /* update info of nodes that are lost their focus by the process exited */
1486                         for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1487                                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list_s);
1488                                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1489                                         if (node->taken_by_id[i].pid == param->pid) {
1490                                                 if (my_node->taken_by_id[i].pid) {
1491                                                         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);
1492                                                 } else {
1493                                                         UPDATE_FOCUS_TAKEN_INFO(by_id, node, 0, 0, false);
1494                                                 }
1495                                         }
1496                                 }
1497                         }
1498                         __clear_focus_pipe(my_node);
1499                         g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1500                         list = g_focus_node_list;
1501                         g_free(my_node);
1502                 } else { /* node that acquired focus */
1503                         bool need_to_trigger_watch_cb = true;
1504                         _mm_sound_mgr_focus_param_t param_s;
1505                         debug_log("clearing activated focus node of pid(%d) handle(%d)", node->pid, node->handle_id);
1506
1507                         my_node = node;
1508                         memset(&param_s, 0x00, sizeof(_mm_sound_mgr_focus_param_t));
1509                         param_s.pid = my_node->pid;
1510                         param_s.handle_id = my_node->handle_id;
1511                         param_s.request_type = my_node->status;
1512                         MMSOUND_STRNCPY(param_s.stream_type, my_node->stream_type, MAX_STREAM_TYPE_LEN);
1513                         for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1514                                 CONTINUE_IF_LIST_DATA_IS_NULL(node, list_s);
1515                                 if (my_node->pid == node->pid || node->is_for_watch)
1516                                         continue;
1517                                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1518                                         if (!(my_node->status & (i+1)))
1519                                                 continue;
1520                                         if (node->taken_by_id[i].pid == param_s.pid && node->taken_by_id[i].handle_id == param_s.handle_id) {
1521                                                 /* do callback for resumption */
1522                                                 if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, &param_s)))
1523                                                         debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]", node, ret);
1524                                                 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN))
1525                                                         need_to_trigger_watch_cb = false;
1526                                         }
1527                                 }
1528                         }
1529                         if (need_to_trigger_watch_cb) {
1530                                 if ((ret = _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param_s.request_type, FOCUS_COMMAND_RELEASE, my_node, &param_s)))
1531                                         debug_error("Fail to _focus_do_watch_callback, ret[0x%x]", ret);
1532                         }
1533
1534                         __clear_focus_pipe(my_node);
1535                         g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1536                         list = g_focus_node_list;
1537                 }
1538         }
1539
1540         _mm_sound_mgr_focus_list_dump();
1541         _mm_sound_mgr_focus_watch_list_dump ();
1542
1543         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1544
1545         debug_fleave();
1546         return ret;
1547
1548 }
1549
1550 int MMSoundMgrFocusInit(void)
1551 {
1552         int ret = MM_ERROR_NONE;
1553         debug_fenter();
1554
1555         ret = __mm_sound_mgr_focus_dbus_get_stream_list(&g_stream_list);
1556         if (ret)
1557                 debug_error("failed to __mm_sound_mgr_focus_dbus_get_stream_list()");
1558
1559         debug_fleave();
1560         return ret;
1561 }
1562
1563 int MMSoundMgrFocusFini(void)
1564 {
1565         int i = 0;
1566         debug_fenter();
1567
1568         for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
1569                 if (g_stream_list.stream_types[i]) {
1570                         free(g_stream_list.stream_types[i]);
1571                 }
1572         }
1573
1574         debug_fleave();
1575         return MM_ERROR_NONE;
1576 }