Support ogg loop playback
[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         victim_node->status = (command == FOCUS_COMMAND_RELEASE) ? (victim_node->status & ~(cb_data.type)) : (victim_node->status | cb_data.type);
519
520         if (strncmp(assaulter_stream_type, victim_node->stream_type, MAX_STREAM_TYPE_LEN))
521                 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)assaulter_param->request_type, command, victim_node, assaulter_param);
522
523 RELEASE:
524         g_free(filename);
525         filename = NULL;
526
527         g_free(filename2);
528         filename2 = NULL;
529
530         if (fd_FOCUS != -1) {
531                 close(fd_FOCUS);
532                 fd_FOCUS = -1;
533         }
534         if (fd_FOCUS_R != -1) {
535                 close (fd_FOCUS_R);
536                 fd_FOCUS_R = -1;
537         }
538
539         return res;
540 }
541
542 static int _mm_sound_mgr_focus_list_dump ()
543 {
544         int ret = MM_ERROR_NONE;
545         GList *list = NULL;
546         focus_node_t *node = NULL;
547
548         debug_msg("================================================ focus node list : start ===================================================\n");
549         for (list = g_focus_node_list; list != NULL; list = list->next) {
550                 if ((node = (focus_node_t *)list->data) && !node->is_for_watch) {
551                         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",
552                                         node->pid, node->handle_id, node->stream_type, node->priority, focus_status_str[node->status],
553                                         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,
554                                         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]);
555                 }
556         }
557         debug_msg("================================================ focus node list : end =====================================================\n");
558
559         return ret;
560 }
561
562 static int _mm_sound_mgr_focus_watch_list_dump()
563 {
564         int ret = MM_ERROR_NONE;
565         GList *list = NULL;
566         focus_node_t *node = NULL;
567
568         debug_msg("============================================= focus watch node list : start =================================================\n");
569         for (list = g_focus_node_list; list != NULL; list = list->next) {
570                 if ((node = (focus_node_t *)list->data) && node->is_for_watch)
571                         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);
572         }
573         debug_msg("============================================= focus watch node list : end ===================================================\n");
574
575         return ret;
576 }
577
578 static void _mm_sound_mgr_focus_fill_info_from_msg(focus_node_t *node, const _mm_sound_mgr_focus_param_t *msg)
579 {
580         debug_fenter();
581         node->pid = msg->pid;
582         node->handle_id = msg->handle_id;
583         node->callback = msg->callback;
584         node->cbdata = msg->cbdata;
585         node->is_for_session = msg->is_for_session;
586
587         debug_fleave();
588         return;
589 }
590
591 int mm_sound_mgr_focus_create_node(const _mm_sound_mgr_focus_param_t *param)
592 {
593         int ret = MM_ERROR_NONE;
594         GList *list = NULL;
595         focus_node_t *node = NULL;
596         int priority = 0;
597
598         debug_fenter();
599
600         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
601
602         /* Update list for dead process */
603         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
604
605         for (list = g_focus_node_list; list != NULL; list = list->next) {
606                 node = (focus_node_t *)list->data;
607                 if (CHECK_MY_NODE(node, param)) {
608                         debug_error("the node of pid[%d]/handle_id[%d] is already created\n", param->pid, param->handle_id);
609                         ret = MM_ERROR_INVALID_ARGUMENT;
610                         goto FINISH;
611                 }
612         }
613
614         /* get priority from stream type */
615         ret = _mm_sound_mgr_focus_get_priority_from_stream_type(&priority, param->stream_type);
616         if (ret) {
617                 goto FINISH;
618         }
619         node = g_malloc0(sizeof(focus_node_t));
620
621         /* fill up information to the node */
622         _mm_sound_mgr_focus_fill_info_from_msg(node, param);
623         node->priority = priority;
624         node->status = FOCUS_STATUS_DEACTIVATED;
625         node->reacquisition = true;
626         MMSOUND_STRNCPY(node->stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
627
628         g_focus_node_list = g_list_append(g_focus_node_list, node);
629         if (g_focus_node_list) {
630                 debug_log("new focus node is added\n");
631         } else {
632                 debug_error("g_list_append failed\n");
633                 ret = MM_ERROR_SOUND_INTERNAL;
634                 g_free(node);
635         }
636
637         _mm_sound_mgr_focus_list_dump();
638 FINISH:
639         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
640
641         debug_fleave();
642         return ret;
643 }
644
645 int mm_sound_mgr_focus_destroy_node(const _mm_sound_mgr_focus_param_t *param)
646 {
647         int ret = MM_ERROR_NONE;
648         GList *list = NULL;
649         focus_node_t *node = NULL;
650         focus_node_t *my_node = NULL;
651         bool need_to_trigger = true;
652         int i = 0;
653
654         debug_fenter();
655
656         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
657
658         /* Update list for dead process */
659         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
660
661         for (list = g_focus_node_list; list != NULL; list = list->next) {
662                 node = (focus_node_t *)list->data;
663                 if (CHECK_MY_NODE(node, param)) {
664                         debug_log("found the node of pid[%d]/handle_id[%d]\n", param->pid, param->handle_id);
665                         my_node = node;
666                         break;
667                 }
668         }
669         if (my_node == NULL) {
670                 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);
671                 ret = MM_ERROR_INVALID_ARGUMENT;
672                 goto FINISH;
673         }
674
675         /* Check if there's remaining focus for session for the same PID of incomming param */
676         if (my_node->is_for_session) {
677                 for (list = g_focus_node_list; list != NULL; list = list->next) {
678                         if (!(node = (focus_node_t *)list->data))
679                                 continue;
680                         if (my_node == node || node->is_for_watch)
681                                 continue;
682                         if (node->pid == my_node->pid && node->is_for_session) {
683                                 debug_error("focus for session for this pid still remains, skip updating victim focus nodes");
684                                 need_to_trigger = false;
685                                 break;
686                         }
687                 }
688         }
689
690         if (need_to_trigger) {
691                 for (list = g_focus_node_list; list != NULL; list = list->next) {
692                         if (!(node = (focus_node_t *)list->data))
693                                 continue;
694                         if (my_node == node || node->is_for_watch)
695                                 continue;
696                         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
697                                 if (node->taken_by_id[i].pid == param->pid) {
698                                         if (my_node->taken_by_id[i].pid) {
699                                         /* If exists update the taken focus info to my victim node */
700                                                 if (node->taken_by_id[i].by_session && !node->status) {
701                                                         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);
702                                                 } else if (node->taken_by_id[i].handle_id == param->handle_id) {
703                                                         UPDATE_FOCUS_TAKEN_INFO(by_id, node, my_node->taken_by_id[i].pid, my_node->taken_by_id[i].handle_id, false);
704                                                 }
705                                         } else if (my_node->status & (i+1)) {
706                                                 if (node->is_for_session)
707                                                         continue;
708                                                 _mm_sound_mgr_focus_param_t *new_param = g_malloc0(sizeof(_mm_sound_mgr_focus_param_t));
709                                                 if (!new_param) {
710                                                         debug_warning("Fail to g_malloc0 for new_param, but keep going\n");
711                                                         goto CLEAR_NODE;
712                                                 }
713                                                 new_param->pid = param->pid;
714                                                 new_param->handle_id = param->handle_id;
715                                                 new_param->is_for_session = my_node->is_for_session;
716                                                 new_param->request_type = my_node->status;
717                                                 new_param->option = my_node->option[i];
718                                                 MMSOUND_STRNCPY(new_param->ext_info, my_node->ext_info[i], MM_SOUND_NAME_NUM);
719
720                                                 if (node->taken_by_id[i].handle_id == new_param->handle_id || node->taken_by_id[i].by_session) {
721                                                         /* do callback for resumption */
722                                                         if ((ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, new_param, my_node->stream_type)))
723                                                                 debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]\n", node, ret);
724                                                         if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
725                                                                 my_node->status &= ~(new_param->request_type);
726                                                                 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)new_param->request_type, FOCUS_COMMAND_RELEASE, my_node, new_param);
727                                                         }
728                                                 }
729                                                 g_free(new_param);
730                                         }
731                                 }
732                         }
733                 }
734         }
735
736 CLEAR_NODE:
737         /* Destroy my node  */
738         __clear_focus_pipe(my_node);
739         g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
740         g_free(my_node);
741 FINISH:
742         _mm_sound_mgr_focus_list_dump();
743         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
744
745         debug_fleave();
746         return ret;
747 }
748
749 int mm_sound_mgr_focus_set_reacquisition(const _mm_sound_mgr_focus_param_t *param)
750 {
751         int ret = MM_ERROR_NONE;
752         GList *list = NULL;
753         focus_node_t *node = NULL;
754         focus_node_t *my_node = NULL;
755         int i;
756
757         debug_fenter();
758
759         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
760
761         /* Update list for dead process */
762         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
763
764         /* Find node to set reacquisition */
765         for (list = g_focus_node_list; list != NULL; list = list->next) {
766                 node = (focus_node_t *)list->data;
767                 if (CHECK_MY_NODE(node, param)) {
768                         if (node->reacquisition == param->reacquisition) {
769                                 debug_msg("it is already set as same value of reacquisition(%d)\n", param->reacquisition);
770                                 goto FINISH;
771                         }
772                         node->reacquisition = param->reacquisition;
773                         debug_msg("found a node(pid[%d]/handle_id[%d]) to set reacquisition to (%d)\n", node->pid, node->handle_id, param->reacquisition);
774                         my_node = node;
775                         break;
776                 }
777         }
778         if (my_node == NULL) {
779                 debug_error("could not find any node of pid[%d]/handle_id[%d]\n", param->pid, param->handle_id);
780                 ret = MM_ERROR_INVALID_ARGUMENT;
781                 goto FINISH;
782         }
783
784         if (!param->reacquisition) {
785                 for (list = g_focus_node_list; list != NULL; list = list->next) {
786                         if (!(node = (focus_node_t *)list->data))
787                                 continue;
788                         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
789                                 if (node->taken_by_id[i].pid == param->pid) {
790                                         /* victim node : append my node's taken info to my victim node */
791                                         if (my_node->taken_by_id[i].pid != 0) {
792                                                 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);
793                                                 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);
794                                         }
795                                 } else if (!list->next) {
796                                         /* my node : backup and reset */
797                                         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);
798                                         UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, 0, 0, false);
799                                 }
800                         }
801                 }
802         } else {
803                 for (list = g_focus_node_list; list != NULL; list = list->next) {
804                         if (!(node = (focus_node_t *)list->data))
805                                 continue;
806                         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
807                                 /* rollback and reset backup info. */
808                                 if (node->taken_by_id[i].pid && (node->taken_by_id[i].pid == my_node->taken_backup[i].pid)) {
809                                         UPDATE_FOCUS_TAKEN_INFO(by_id, node, node->taken_backup[i].pid, node->taken_backup[i].handle_id, node->taken_backup[i].by_session);
810                                         UPDATE_FOCUS_TAKEN_INFO(backup, node, 0, 0, false);
811                                 } else if (!list->next) {
812                                         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);
813                                         UPDATE_FOCUS_TAKEN_INFO(backup, my_node, 0, 0, false);
814                                 }
815                         }
816                 }
817         }
818
819 FINISH:
820         _mm_sound_mgr_focus_list_dump();
821         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
822
823         debug_fleave();
824         return ret;
825 }
826
827 int mm_sound_mgr_focus_get_stream_type_of_acquired_focus(focus_type_e focus_type, char **stream_type, int *option, char **ext_info)
828 {
829         int ret = MM_ERROR_SOUND_NO_DATA;
830         GList *list = NULL;
831         focus_node_t *node = NULL;
832
833         debug_fenter();
834
835         if (focus_type == FOCUS_TYPE_BOTH) /* focus_type should be "playback" or "capture" */
836                 return MM_ERROR_INVALID_ARGUMENT;
837         if (!stream_type)
838                 return MM_ERROR_INVALID_ARGUMENT;
839
840         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
841
842         /* Update list for dead process */
843         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
844
845         /* Find node to set reacquisition */
846         for (list = g_focus_node_list; list != NULL; list = list->next) {
847                 if (!(node = (focus_node_t *)list->data))
848                         continue;
849                 if (!node->is_for_watch && (node->status & focus_type)) {
850                         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);
851                         *stream_type = node->stream_type;
852                         *option = node->option[focus_type-1];
853                         if (ext_info)
854                                 *ext_info = node->ext_info[focus_type-1];
855                         ret = MM_ERROR_NONE;
856                         break;
857                 }
858         }
859
860         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
861
862         debug_fleave();
863
864         return ret;
865 }
866
867 int mm_sound_mgr_focus_request_acquire(const _mm_sound_mgr_focus_param_t *param)
868 {
869         int ret = MM_ERROR_NONE;
870         GList *list = NULL;
871         focus_node_t *node = NULL;
872         focus_node_t *my_node = NULL;
873         bool need_to_trigger_cb = false;
874         bool need_to_trigger_watch_cb = true;
875         int i;
876
877         debug_fenter();
878
879         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
880
881         /* Update list for dead process */
882         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
883
884         for (list = g_focus_node_list; list != NULL; list = list->next) {
885                 node = (focus_node_t *)list->data;
886                 if (CHECK_MY_NODE(node, param)) {
887                         my_node = node;
888                         if ((my_node->status > FOCUS_STATUS_DEACTIVATED) && (my_node->status & param->request_type)) {
889                                 debug_error("focus status is already activated");
890                                 ret = MM_ERROR_SOUND_INVALID_STATE;
891                                 goto FINISH;
892                         }
893                 }
894         }
895
896         if (my_node == NULL) {
897                 debug_error("node is null");
898                 ret = MM_ERROR_INVALID_ARGUMENT;
899                 goto FINISH;
900         }
901
902         /* check if the priority of any node is higher than its based on io direction */
903         for (list = g_focus_node_list; list != NULL; list = list->next) {
904                 if (!(node = (focus_node_t *)list->data))
905                         continue;
906                 if (my_node == node || node->is_for_watch)
907                         continue;
908                 if (param->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
909                         (node->status & param->request_type)) {
910                         if (node->status > FOCUS_STATUS_DEACTIVATED) {
911                                 if ((my_node->priority < node->priority)) {
912                                         ret = MM_ERROR_POLICY_BLOCKED;
913                                         need_to_trigger_cb = false;
914                                         break;
915                                 } else {
916                                         need_to_trigger_cb = true;
917                                 }
918                         }
919                 }
920         }
921
922         if (need_to_trigger_cb) {
923                 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
924                 param_s->is_for_session = my_node->is_for_session;
925                 for (list = g_focus_node_list; list != NULL; list = list->next) {
926                         if (!(node = (focus_node_t *)list->data))
927                                 continue;
928                         if (node == my_node || node->is_for_watch || (node->pid == my_node->pid && node->is_for_session && my_node->is_for_session))
929                                 continue;
930                         if (param_s->request_type == FOCUS_TYPE_BOTH || node->status == FOCUS_STATUS_ACTIVATED_BOTH ||
931                                 (node->status & param_s->request_type)) {
932                                 if (node->status > FOCUS_STATUS_DEACTIVATED) {
933                                         if (my_node->priority >= node->priority) {
934                                                 /* do callback for interruption */
935                                                 ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_RELEASE, node, param_s, my_node->stream_type);
936                                                 if (ret) {
937                                                         debug_error("Fail to _focus_do_callback for COMMAND RELEASE to node[%x], ret[0x%x]\n", node, ret);
938                                                         /* but, keep going */
939                                                         ret = MM_ERROR_NONE;
940                                                 }
941                                                 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
942                                                         need_to_trigger_watch_cb = false;
943                                                 }
944                                         }
945                                 }
946                         }
947                 }
948         }
949
950         if (ret != MM_ERROR_POLICY_BLOCKED) {
951                 /* copy ext info. */
952                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
953                         if (param->request_type & (i+1)) {
954                                 MMSOUND_STRNCPY(my_node->ext_info[i], param->ext_info, MM_SOUND_NAME_NUM);
955                                 my_node->option[i] = param->option;
956                         }
957                 }
958                 /* update status */
959                 my_node->status |= param->request_type;
960                 /* do watch callback due to the status of mine */
961                 if (need_to_trigger_watch_cb)
962                         _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_ACQUIRE, my_node, param);
963                 /* update taken information */
964                 for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
965                         if (param->request_type & (i+1)) {
966                                 UPDATE_FOCUS_TAKEN_INFO(by_id, my_node, 0, 0, false);
967                                 UPDATE_FOCUS_TAKEN_INFO(backup, my_node, 0, 0, false);
968                         }
969                 }
970         }
971
972         _mm_sound_mgr_focus_list_dump();
973         _mm_sound_mgr_focus_watch_list_dump ();
974 FINISH:
975         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
976
977         debug_fleave();
978         return ret;
979 }
980
981 int mm_sound_mgr_focus_request_release(const _mm_sound_mgr_focus_param_t *param)
982 {
983         int ret = MM_ERROR_NONE;
984         GList *list = NULL;
985         focus_node_t *node = NULL;
986         focus_node_t *my_node = NULL;
987         bool need_to_trigger_watch_cb = true;
988         bool need_to_trigger_cb = true;
989         int i = 0;
990
991         debug_fenter();
992
993         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
994
995         /* Update list for dead process */
996         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
997
998         for (list = g_focus_node_list; list != NULL; list = list->next) {
999                 node = (focus_node_t *)list->data;
1000                 if (CHECK_MY_NODE(node, param)) {
1001                         my_node = node;
1002                         if (my_node->status == FOCUS_STATUS_DEACTIVATED) {
1003                                 debug_error("focus status is already deactivated");
1004                                 ret = MM_ERROR_SOUND_INVALID_STATE;
1005                                 goto FINISH;
1006                         } else if ((my_node->status != FOCUS_STATUS_ACTIVATED_BOTH) && (my_node->status != (focus_status_e)param->request_type)) {
1007                                 debug_error("request type is not matched with current focus type");
1008                                 ret = MM_ERROR_SOUND_INVALID_STATE;
1009                                 goto FINISH;
1010                         }
1011                         break;
1012                 }
1013         }
1014
1015         if (my_node == NULL) {
1016                 debug_error("node is null");
1017                 ret = MM_ERROR_INVALID_ARGUMENT;
1018                 goto FINISH;
1019         }
1020
1021         /* Check if there's activating focus for session for the same PID of incomming param*/
1022         if (my_node->is_for_session) {
1023                 for (list = g_focus_node_list; list != NULL; list = list->next) {
1024                         if (!(node = (focus_node_t *)list->data))
1025                                 continue;
1026                         if (node == my_node || node->is_for_watch)
1027                                 continue;
1028                         if (node->pid == my_node->pid && node->is_for_session && my_node->status & node->status) {
1029                                 debug_error("focus for session for this pid is active, skip callbacks");
1030                                 need_to_trigger_watch_cb = false;
1031                                 need_to_trigger_cb = false;
1032                                 break;
1033                         }
1034                 }
1035         }
1036
1037         if (need_to_trigger_cb) {
1038                 _mm_sound_mgr_focus_param_t *param_s = (_mm_sound_mgr_focus_param_t *)param;
1039                 param_s->is_for_session = my_node->is_for_session;
1040                 for (list = g_focus_node_list; list != NULL; list = list->next) {
1041                         if (!(node = (focus_node_t *)list->data))
1042                                 continue;
1043                         if (node == my_node || node->is_for_watch)
1044                                 continue;
1045                         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1046                                 if (param_s->request_type & (i+1)) {
1047                                         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)) {
1048                                                 /* do callback for resumption */
1049                                                 ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, param_s, my_node->stream_type);
1050                                                 if (ret) {
1051                                                         debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]\n", node, ret);
1052                                                 }
1053                                                 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
1054                                                         need_to_trigger_watch_cb = false;
1055                                                 }
1056                                         }
1057                                 }
1058                         }
1059                 }
1060         }
1061         /* update status */
1062         my_node->status &= ~(param->request_type);
1063         /* remove ext info. */
1064         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1065                 if (!(my_node->status & (i+1))) {
1066                         memset(my_node->ext_info[i], 0x0, MM_SOUND_NAME_NUM);
1067                         my_node->option[i] = 0;
1068                 }
1069         }
1070         /* do watch callback due to the status of mine */
1071         if (need_to_trigger_watch_cb)
1072                 _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param->request_type, FOCUS_COMMAND_RELEASE, my_node, param);
1073
1074         _mm_sound_mgr_focus_list_dump();
1075         _mm_sound_mgr_focus_watch_list_dump ();
1076 FINISH:
1077         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1078
1079         debug_fleave();
1080         return ret;
1081 }
1082
1083 int mm_sound_mgr_focus_set_watch_cb(const _mm_sound_mgr_focus_param_t *param)
1084 {
1085         int ret = MM_ERROR_NONE;
1086         GList *list = NULL;
1087         focus_node_t *node = NULL;
1088
1089         debug_fenter();
1090
1091         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1092
1093         /* Update list for dead process */
1094         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1095
1096         for (list = g_focus_node_list; list != NULL; list = list->next) {
1097                 if (!(node = (focus_node_t *)list->data))
1098                         continue;
1099                 if ((node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1100                         debug_error("the node of pid[%d]/handle_id[%d] for watch focus is already created\n", param->pid, param->handle_id);
1101                         ret = MM_ERROR_INVALID_ARGUMENT;
1102                         goto FINISH;
1103                 }
1104         }
1105
1106         node = g_malloc0(sizeof(focus_node_t));
1107
1108         /* fill up information to the node */
1109         _mm_sound_mgr_focus_fill_info_from_msg(node, param);
1110         node->is_for_watch = true;
1111         node->status = param->request_type;
1112
1113         g_focus_node_list = g_list_append(g_focus_node_list, node);
1114         if (g_focus_node_list) {
1115                 debug_log("new focus node is added\n");
1116         } else {
1117                 debug_error("g_list_append failed\n");
1118                 ret = MM_ERROR_SOUND_INTERNAL;
1119                 g_free(node);
1120         }
1121
1122         _mm_sound_mgr_focus_watch_list_dump();
1123 FINISH:
1124         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1125
1126         debug_fleave();
1127         return ret;
1128 }
1129
1130 int mm_sound_mgr_focus_unset_watch_cb(const _mm_sound_mgr_focus_param_t *param)
1131 {
1132         int ret = MM_ERROR_SOUND_INTERNAL;
1133         GList *list = NULL;
1134         focus_node_t *node = NULL;
1135
1136         debug_fenter();
1137
1138         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1139
1140         /* Update list for dead process */
1141         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1142
1143         for (list = g_focus_node_list; list != NULL; list = list->next) {
1144                 if (!(node = (focus_node_t *)list->data))
1145                         continue;
1146                 if ((node->pid == param->pid) && (node->handle_id == param->handle_id) && node->is_for_watch) {
1147                         debug_log("found the node of pid[%d]/handle_id[%d] for watch focus\n", param->pid, param->handle_id);
1148                         __clear_focus_pipe(node);
1149                         g_focus_node_list = g_list_remove(g_focus_node_list, node);
1150                         g_free(node);
1151                         ret = MM_ERROR_NONE;
1152                         break;
1153                 }
1154         }
1155         if (list == NULL) {
1156                 debug_error("could not find any node of pid[%d]/handle_id[%d] for watch focus\n", param->pid, param->handle_id);
1157                 ret = MM_ERROR_INVALID_ARGUMENT;
1158                 goto FINISH;
1159         }
1160
1161         _mm_sound_mgr_focus_watch_list_dump();
1162 FINISH:
1163         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1164
1165         debug_fleave();
1166         return ret;
1167 }
1168
1169 int mm_sound_mgr_focus_emergent_exit(const _mm_sound_mgr_focus_param_t *param)
1170 {
1171         int ret = MM_ERROR_NONE;
1172         GList *list = NULL;
1173         GList *list_s =NULL;
1174         focus_node_t *node = NULL;
1175         focus_node_t *my_node = NULL;
1176         int i;
1177
1178         debug_fenter();
1179
1180         MMSOUND_ENTER_CRITICAL_SECTION_WITH_RETURN(&g_focus_node_list_mutex, MM_ERROR_SOUND_INTERNAL);
1181
1182         /* Update list for dead process */
1183         g_list_foreach (g_focus_node_list, (GFunc)_clear_focus_node_list_func, NULL);
1184
1185         list = g_focus_node_list;
1186         while (list) {
1187                 if (!(node = (focus_node_t *)list->data))
1188                         continue;
1189                 if (node->pid == param->pid) {
1190                         debug_log("found pid node");
1191                         if (node->is_for_watch) {
1192                                 debug_log("clearing watch cb of pid(%d) handle(%d)", node->pid, node->handle_id);
1193                                 __clear_focus_pipe(node);
1194                                 g_focus_node_list = g_list_remove(g_focus_node_list, node);
1195                                 list = g_focus_node_list;
1196                                 g_free(node);
1197                         } else if (node->status == FOCUS_STATUS_DEACTIVATED) {
1198                                 debug_log("clearing deactivated focus node of pid(%d) hande(%d)", node->pid, node->handle_id);
1199                                 my_node = node;
1200                                 /* update info of nodes that are lost their focus by the process exited */
1201                                 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1202                                         if (!(node = (focus_node_t *)list_s->data))
1203                                                 continue;
1204                                         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1205                                                 if (node->taken_by_id[i].pid == param->pid) {
1206                                                         if (my_node->taken_by_id[i].pid) {
1207                                                                 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);
1208                                                         } else {
1209                                                                 UPDATE_FOCUS_TAKEN_INFO(by_id, node, 0, 0, false);
1210                                                         }
1211                                                 }
1212                                         }
1213                                 }
1214                                 __clear_focus_pipe(my_node);
1215                                 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1216                                 list = g_focus_node_list;
1217                                 g_free(my_node);
1218                         } else { /* node that acquired focus */
1219                                 bool need_to_trigger_watch_cb = true;
1220                                 _mm_sound_mgr_focus_param_t param_s;
1221                                 debug_log("clearing activated focus node of pid(%d) handle(%d)", node->pid, node->handle_id);
1222
1223                                 my_node = node;
1224                                 memset(&param_s, 0x00, sizeof(_mm_sound_mgr_focus_param_t));
1225                                 param_s.pid = my_node->pid;
1226                                 param_s.handle_id = my_node->handle_id;
1227                                 param_s.request_type = my_node->status;
1228                                 for (list_s = g_focus_node_list; list_s != NULL; list_s = list_s->next) {
1229                                         if (!(node = (focus_node_t *)list_s->data))
1230                                                 continue;
1231                                         if (my_node->pid == node->pid || node->is_for_watch)
1232                                                 continue;
1233                                         for (i = 0; i < NUM_OF_STREAM_IO_TYPE; i++) {
1234                                                 if (my_node->status & (i+1)) {
1235                                                         if (node->taken_by_id[i].pid == param_s.pid && node->taken_by_id[i].handle_id == param_s.handle_id) {
1236                                                                 /* do callback for resumption */
1237                                                                 ret = _mm_sound_mgr_focus_do_callback(FOCUS_COMMAND_ACQUIRE, node, &param_s, my_node->stream_type);
1238                                                                 if (ret) {
1239                                                                         debug_error("Fail to _focus_do_callback for COMMAND ACQUIRE to node[%x], ret[0x%x]\n", node, ret);
1240                                                                 }
1241                                                                 if (!strncmp(my_node->stream_type, node->stream_type, MAX_STREAM_TYPE_LEN)) {
1242                                                                         need_to_trigger_watch_cb = false;
1243                                                                 }
1244                                                         }
1245                                                 }
1246                                         }
1247                                 }
1248                                 if (need_to_trigger_watch_cb) {
1249                                         ret = _mm_sound_mgr_focus_do_watch_callback((focus_type_e)param_s.request_type, FOCUS_COMMAND_RELEASE, my_node, &param_s);
1250                                         if (ret) {
1251                                                 debug_error("Fail to _focus_do_watch_callback, ret[0x%x]\n", ret);
1252                                         }
1253                                 }
1254                                 __clear_focus_pipe(my_node);
1255                                 g_focus_node_list = g_list_remove(g_focus_node_list, my_node);
1256                                 list = g_focus_node_list;
1257                         }
1258                 } else {
1259                         list = list->next;
1260                         debug_log("node not found, next list = %p",list);
1261                 }
1262         }
1263
1264         _mm_sound_mgr_focus_list_dump();
1265         _mm_sound_mgr_focus_watch_list_dump ();
1266
1267         MMSOUND_LEAVE_CRITICAL_SECTION(&g_focus_node_list_mutex);
1268
1269         debug_fleave();
1270         return ret;
1271
1272 }
1273
1274 int MMSoundMgrFocusInit(void)
1275 {
1276         int ret = MM_ERROR_NONE;
1277         debug_fenter();
1278
1279         ret = __mm_sound_mgr_focus_dbus_get_stream_list(&g_stream_list);
1280         if (ret)
1281                 debug_error("failed to __mm_sound_mgr_ipc_dbus_get_stream_list()\n");
1282
1283         debug_fleave();
1284         return ret;
1285 }
1286
1287 int MMSoundMgrFocusFini(void)
1288 {
1289         int i = 0;
1290         debug_fenter();
1291
1292         for (i = 0; i < AVAIL_STREAMS_MAX; i++) {
1293                 if (g_stream_list.stream_types[i]) {
1294                         free(g_stream_list.stream_types[i]);
1295                 }
1296         }
1297
1298         debug_fleave();
1299         return MM_ERROR_NONE;
1300 }