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