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