Add new functions to acquire/release focus with option
[platform/core/multimedia/libmm-sound.git] / server / mm_sound_mgr_codec.c
1
2 /*
3  * libmm-sound
4  *
5  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6  *
7  * Contact: Seungbae Shin <seungbae.shin@samsung.com>
8  *
9  * Licensed under the Apache License, Version 2.0 (the "License");
10  * you may not use this file except in compliance with the License.
11  * You may obtain a copy of the License at
12  *
13  * http://www.apache.org/licenses/LICENSE-2.0
14  *
15  * Unless required by applicable law or agreed to in writing, software
16  * distributed under the License is distributed on an "AS IS" BASIS,
17  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18  * See the License for the specific language governing permissions and
19  * limitations under the License.
20  *
21  */
22
23 #include <stdlib.h>
24 #include <stdio.h>
25 #include <string.h>
26 #include <pthread.h>
27
28 #include <mm_source.h>
29 #include <mm_error.h>
30 #include <mm_types.h>
31 #include <mm_debug.h>
32 #include <mm_ipc.h>
33 #include <mm_session.h>
34
35 #include "include/mm_sound_mgr_common.h"
36 #include "include/mm_sound_mgr_codec.h"
37 #include "include/mm_sound_mgr_ipc.h"
38 #include "include/mm_sound_plugin_codec.h"
39 #include "include/mm_sound_thread_pool.h"
40
41 #include "../include/mm_sound_common.h"
42 #include "../include/mm_sound_focus.h"
43
44 #define _ENABLE_KEYTONE /* Temporal test code */
45
46 /* #define FOCUS_INTEGRATION */
47
48 typedef struct {
49         int (*callback)(int, void *, void *, int);      /* msg_type(pid) client callback & client data info */
50         void *param;
51         int pid;
52         void *msgcallback;
53         void *msgdata;
54         MMHandleType plughandle;
55
56         int pluginid;
57         int status;
58         int session_type;
59         int session_options;
60 #ifdef FOCUS_INTEGRATION
61         int focus_handle;
62         int focus_wcb_id;
63         unsigned int subs_id;
64         mm_sound_focus_type_e current_focus_type;
65 #endif
66
67         bool enable_session;
68  } __mmsound_mgr_codec_handle_t;
69
70 static MMSoundPluginType *g_codec_plugins = NULL;
71 static __mmsound_mgr_codec_handle_t g_slots[MANAGER_HANDLE_MAX];
72 static mmsound_codec_interface_t g_plugins[MM_SOUND_SUPPORTED_CODEC_NUM];
73 static pthread_mutex_t g_slot_mutex;
74 static pthread_mutex_t codec_wave_mutex;
75 static int _MMSoundMgrCodecStopCallback(int param);
76 static int _MMSoundMgrCodecGetEmptySlot(int *slotid);
77 static int _MMSoundMgrCodecRegisterInterface(MMSoundPluginType *plugin);
78
79 #define STATUS_IDLE 0
80 #define STATUS_SOUND 3
81
82 #define SOUND_SLOT_START 0
83
84 #ifdef FOCUS_INTEGRATION
85
86 void sound_codec_focus_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state, const char *reason_for_change, int option, const char *ext_info, void *user_data)
87 {
88
89         int slotid = (int)user_data;
90         int result = MM_ERROR_NONE;
91
92         debug_warning ("focus callback called -> focus_stae(%d), reasoun_for_change(%s)", focus_state, reason_for_change ? reason_for_change : "N/A");
93
94         if(g_slots[slotid].session_options & MM_SESSION_OPTION_UNINTERRUPTIBLE){
95                 debug_warning ("session option is UNINTERRUPTIBLE, nothing to do with focus");
96                 return;
97         }
98         if (focus_state == FOCUS_IS_RELEASED) {
99                 g_slots[slotid].current_focus_type = FOCUS_FOR_BOTH&(~focus_type);
100                 debug_warning ("focus is released -> stop playing");
101                 result = MMSoundMgrCodecStop(slotid);
102                 if (result != MM_ERROR_NONE) {
103                         debug_log("result error %d\n", result);
104                 }
105
106         }
107         return;
108 }
109
110 void sound_codec_focus_watch_callback(int id, mm_sound_focus_type_e focus_type, mm_sound_focus_state_e focus_state, const char *reason_for_change, const char* ext_info, void *user_data)
111 {
112         int slotid = (int)user_data;
113         int result = MM_ERROR_NONE;
114
115         debug_warning ("focus callback called -> focus_stae(%d), reasoun_for_change(%s)", focus_state, reason_for_change ? reason_for_change : "N/A");
116
117         if(g_slots[slotid].session_options & MM_SESSION_OPTION_UNINTERRUPTIBLE){
118                 debug_warning ("session option is UNINTERRUPTIBLE, nothing to do with focus");
119                 return;
120         }
121         if (focus_state == FOCUS_IS_ACQUIRED) {
122                 debug_warning ("focus is released -> stop playing");
123                 result = MMSoundMgrCodecStop(slotid);
124                 if (result != MM_ERROR_NONE) {
125                         debug_log("result error %d\n", result);
126                 }
127
128         }
129         return;
130 }
131
132
133 void sound_codec_device_connected_callback(MMSoundDevice_t device, bool is_connected, void *user_data)
134 {
135         int slotid = (int)user_data;
136         int result = MM_ERROR_NONE;
137         mm_sound_device_type_e type;
138
139         debug_warning ("device_connected_callback called");
140
141         if (mm_sound_get_device_type (device, &type) != MM_ERROR_NONE) {
142                 debug_error("getting device type failed");
143         } else {
144                 switch (type) {
145                         case MM_SOUND_DEVICE_TYPE_AUDIOJACK:
146                         case MM_SOUND_DEVICE_TYPE_BLUETOOTH:
147                         case MM_SOUND_DEVICE_TYPE_HDMI:
148                         case MM_SOUND_DEVICE_TYPE_MIRRORING:
149                         case MM_SOUND_DEVICE_TYPE_USB_AUDIO:
150                                 if (!is_connected) {
151                                         debug_warning("sound device unplugged");
152                                         result = MMSoundMgrCodecStop(slotid);
153                                         if (result != MM_ERROR_NONE) {
154                                                 debug_error("MMSoundMgrCodecStop error %d\n", result);
155                                         }
156                                         result = mm_sound_remove_device_connected_callback(g_slots[slotid].subs_id);
157                                         if (result != MM_ERROR_NONE) {
158                                                 debug_error("mm_sound_remove_device_connected_callback error %d\n", result);
159                                         }
160                                 }
161                                 break;
162                         default:
163                                 break;
164                 }
165         }
166 }
167 #endif
168
169 int MMSoundMgrCodecInit(const char *targetdir)
170 {
171         int loop = 0;
172         int count = 0;
173
174         debug_enter("\n");
175
176         memset (g_slots, 0, sizeof(g_slots));
177
178         if(pthread_mutex_init(&g_slot_mutex, NULL)) {
179                 debug_error("pthread_mutex_init failed\n");
180                 return MM_ERROR_SOUND_INTERNAL;
181         }
182
183         if(pthread_mutex_init(&codec_wave_mutex, NULL)) {
184                 debug_error("pthread_mutex_init failed\n");
185                 return MM_ERROR_SOUND_INTERNAL;
186         }
187
188         for (count = 0; count < MANAGER_HANDLE_MAX; count++) {
189                 g_slots[count].status = STATUS_IDLE;
190                 g_slots[count].plughandle = 0;
191         }
192
193         if (g_codec_plugins) {
194                 debug_warning("Please Check Init twice\n");
195                 MMSoundPluginRelease(g_codec_plugins);
196         }
197
198         MMSoundPluginScan(targetdir, MM_SOUND_PLUGIN_TYPE_CODEC, &g_codec_plugins);
199         if (g_codec_plugins) {
200                 while (g_codec_plugins[loop].type != MM_SOUND_PLUGIN_TYPE_NONE) {
201                         _MMSoundMgrCodecRegisterInterface(&g_codec_plugins[loop++]);
202                 }
203         }
204
205         debug_leave("\n");
206         return MM_ERROR_NONE;
207 }
208
209 int MMSoundMgrCodecFini(void)
210 {
211         debug_enter("\n");
212
213         memset(g_plugins, 0, sizeof(mmsound_codec_interface_t) * MM_SOUND_SUPPORTED_CODEC_NUM);
214         MMSoundPluginRelease(g_codec_plugins);
215         g_codec_plugins = NULL;
216         pthread_mutex_destroy(&g_slot_mutex);
217         pthread_mutex_destroy(&codec_wave_mutex);
218         debug_leave("\n");
219         return MM_ERROR_NONE;
220 }
221
222
223 int MMSoundMgrCodecPlay(int *slotid, const mmsound_mgr_codec_param_t *param)
224 {
225         int count = 0;
226         mmsound_codec_info_t info;
227         mmsound_codec_param_t codec_param;
228         int err = MM_ERROR_NONE;
229 #ifdef FOCUS_INTEGRATION
230         int need_focus_unregister = 0;
231 #endif
232
233 #ifdef DEBUG_DETAIL
234         debug_enter("\n");
235 #endif
236
237         for (count = 0; g_plugins[count].GetSupportTypes; count++) {
238                 /* Find codec */
239                 if (g_plugins[count].Parse(param->source, &info) == MM_ERROR_NONE)
240                         break;
241         }
242
243         /*The count num means codec type WAV, MP3 */
244         debug_msg("DTMF[%d] Repeat[%d] Volume[%f] plugin_codec[%d]\n", param->tone, param->repeat_count, param->volume, count);
245
246         if (g_plugins[count].GetSupportTypes == NULL) { /* Codec not found */
247                 debug_error("unsupported file type %d\n", count);
248                 err = MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
249                 goto cleanup;
250         }
251
252 #ifdef DEBUG_DETAIL
253         debug_msg("Get New handle\n");
254 #endif
255
256         err = _MMSoundMgrCodecGetEmptySlot(slotid);
257         if (err != MM_ERROR_NONE || *slotid < 0) {
258                 debug_error("Empty g_slot is not found\n");
259                 goto cleanup;
260         }
261
262         codec_param.tone = param->tone;
263         codec_param.volume_config = param->volume_config;
264         codec_param.repeat_count = param->repeat_count;
265         codec_param.volume = param->volume;
266         codec_param.source = param->source;
267         codec_param.priority = param->priority;
268         codec_param.stop_cb = _MMSoundMgrCodecStopCallback;
269         codec_param.param = *slotid;
270         codec_param.pid = (int)param->param;
271         codec_param.handle_route = param->handle_route;
272         codec_param.codec_wave_mutex = &codec_wave_mutex;
273         codec_param.stream_index = param->stream_index;
274         MMSOUND_STRNCPY(codec_param.stream_type, param->stream_type, MM_SOUND_STREAM_TYPE_LEN);
275         pthread_mutex_lock(&g_slot_mutex);
276 #ifdef DEBUG_DETAIL
277         debug_msg("After Slot_mutex LOCK\n");
278 #endif
279
280 #ifdef FOCUS_INTEGRATION
281         /*
282          * Register FOCUS here
283          */
284
285         if (param->session_type != MM_SESSION_TYPE_CALL &&
286                 param->session_type != MM_SESSION_TYPE_VIDEOCALL &&
287                 param->session_type != MM_SESSION_TYPE_VOIP &&
288                 param->session_type != MM_SESSION_TYPE_VOICE_RECOGNITION &&
289                 param->enable_session) {
290
291                 unsigned int subs_id = 0;
292
293                 err = mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG, (mm_sound_device_connected_cb)sound_codec_device_connected_callback, (void*) *slotid, &subs_id);
294                 if (err) {
295                         debug_error("mm_sound_add_device_connected_callback failed [0x%x]", err);
296                         pthread_mutex_unlock(&g_slot_mutex);
297                         return MM_ERROR_POLICY_INTERNAL;
298                 }
299                 g_slots[*slotid].subs_id = subs_id;
300
301                 if ((param->session_options & MM_SESSION_OPTION_PAUSE_OTHERS) || param->session_type == MM_SESSION_TYPE_ALARM || param->session_type == MM_SESSION_TYPE_NOTIFY || param->session_type == MM_SESSION_TYPE_EMERGENCY) {
302                         debug_warning("session option is PAUSE_OTHERS -> acquire focus");
303                         err = mm_sound_focus_get_id((int *)(&param->focus_handle));
304                         err = mm_sound_register_focus_for_session(param->focus_handle, (int)param->param, "media", sound_codec_focus_callback, (void*)*slotid);
305                         if (err) {
306                                 debug_error("mm_sound_register_focus_for_session failed [0x%x]", err);
307                                 pthread_mutex_unlock(&g_slot_mutex);
308                                 return MM_ERROR_POLICY_INTERNAL;
309                         }
310                         err = mm_sound_acquire_focus(param->focus_handle, FOCUS_FOR_BOTH, NULL);
311                         if (err) {
312                                 debug_error("mm_sound_acquire_focus failed [0x%x]", err);
313                                 err = mm_sound_unregister_focus(param->focus_handle);
314                                 pthread_mutex_unlock(&g_slot_mutex);
315                                 return MM_ERROR_POLICY_INTERNAL;
316                         }
317                         g_slots[*slotid].current_focus_type = FOCUS_FOR_BOTH;
318                 } else if (param->session_options & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
319                         /* do nothing */
320                         debug_warning("session option is UNINTERRUPTIBLE, nothing to do with focus");
321                 } else {
322                         debug_warning("need to set focus watch callback");
323                         err = mm_sound_set_focus_watch_callback_for_session((int)param->param, FOCUS_FOR_BOTH, sound_codec_focus_watch_callback, (void*)*slotid, (int *)(&param->focus_wcb_id));
324                         if (err) {
325                                 debug_error("mm_sound_set_focus_watch_callback_for_session failed [0x%x]", err);
326                                 pthread_mutex_unlock(&g_slot_mutex);
327                                 return MM_ERROR_POLICY_INTERNAL;
328                         }
329                 }
330         }
331         //
332 #endif
333
334         /* Codec id WAV or MP3 */
335         g_slots[*slotid].pluginid = count;
336         g_slots[*slotid].param    = param->param;               /* This arg is used callback data */
337         g_slots[*slotid].session_type = param->session_type;
338         g_slots[*slotid].session_options = param->session_options;
339 #ifdef FOCUS_INTEGRATION
340         g_slots[*slotid].focus_handle = param->focus_handle;
341         g_slots[*slotid].focus_wcb_id = param->focus_wcb_id;
342 #endif
343         g_slots[*slotid].enable_session = true;
344         g_slots[*slotid].pid = (int)param->param;
345
346
347         debug_msg("Using Slotid : [%d] Slot Status : [%d]\n", *slotid, g_slots[*slotid].status);
348
349         err = g_plugins[g_slots[*slotid].pluginid].Create(&codec_param, &info, &(g_slots[*slotid].plughandle));
350         debug_msg("Created audio handle : [%d]\n", g_slots[*slotid].plughandle);
351         if (err != MM_ERROR_NONE) {
352                 debug_error("Plugin create fail : 0x%08X\n", err);
353                 g_slots[*slotid].status = STATUS_IDLE;
354                 pthread_mutex_unlock(&g_slot_mutex);
355                 debug_warning("After Slot_mutex UNLOCK\n");
356 #ifdef FOCUS_INTEGRATION
357                 if (param->focus_handle) {
358                         need_focus_unregister = 1;
359                 }
360 #endif
361                 goto cleanup;
362         }
363
364         err = g_plugins[g_slots[*slotid].pluginid].Play(g_slots[*slotid].plughandle);
365         if (err != MM_ERROR_NONE) {
366                 debug_error("Fail to play : 0x%08X\n", err);
367                 g_plugins[g_slots[*slotid].pluginid].Destroy(g_slots[*slotid].plughandle);
368 #ifdef FOCUS_INTEGRATION
369                 if (param->focus_handle) {
370                         need_focus_unregister = 1;
371                 }
372 #endif
373         }
374
375         pthread_mutex_unlock(&g_slot_mutex);
376 #ifdef DEBUG_DETAIL
377         debug_msg("After Slot_mutex UNLOCK\n");
378 #endif
379
380 cleanup:
381 #ifdef FOCUS_INTEGRATION
382         if(param->session_type != MM_SESSION_TYPE_CALL &&
383                 param->session_type != MM_SESSION_TYPE_VIDEOCALL &&
384                 param->session_type != MM_SESSION_TYPE_VOIP &&
385                 param->session_type != MM_SESSION_TYPE_VOICE_RECOGNITION &&
386                 param->enable_session &&
387                 need_focus_unregister == 1) {
388
389                 if (param->session_options & MM_SESSION_OPTION_PAUSE_OTHERS || param->session_type == MM_SESSION_TYPE_ALARM || param->session_type == MM_SESSION_TYPE_NOTIFY || param->session_type == MM_SESSION_TYPE_EMERGENCY) {
390                         err = mm_sound_release_focus(param->focus_handle, FOCUS_FOR_BOTH, NULL);
391                         if(mm_sound_unregister_focus(param->focus_handle) || err) {
392                                 debug_error("focus cleaning up failed[0x%x]", err);
393                                 return MM_ERROR_POLICY_INTERNAL;
394                         }
395                 } else if (~(param->session_options & MM_SESSION_OPTION_PAUSE_OTHERS)) {
396                         err = mm_sound_unset_focus_watch_callback(param->focus_wcb_id);
397                         if (err) {
398                                 debug_error("focus watch cleaning up failed[0x%x]", err);
399                                 return MM_ERROR_POLICY_INTERNAL;
400                         }
401                 }
402         }
403 #endif
404
405 #ifdef DEBUG_DETAIL
406         debug_leave("\n");
407 #endif
408
409         return err;
410 }
411
412 int MMSoundMgrCodecPlayWithStreamInfo(int *slotid, const mmsound_mgr_codec_param_t *param)
413 {
414         int count = 0;
415         mmsound_codec_info_t info;
416         mmsound_codec_param_t codec_param;
417         int err = MM_ERROR_NONE;
418
419 #ifdef DEBUG_DETAIL
420         debug_enter("\n");
421 #endif
422
423         for (count = 0; g_plugins[count].GetSupportTypes; count++) {
424                 /* Find codec */
425                 if (g_plugins[count].Parse(param->source, &info) == MM_ERROR_NONE)
426                         break;
427         }
428
429         /*The count num means codec type WAV, MP3 */
430         debug_msg("Repeat[%d] Volume[%f] plugin_codec[%d]\n", param->repeat_count, param->volume, count);
431
432         if (g_plugins[count].GetSupportTypes == NULL) { /* Codec not found */
433                 debug_error("unsupported file type %d\n", count);
434                 err = MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
435                 goto cleanup;
436         }
437
438         err = _MMSoundMgrCodecGetEmptySlot(slotid);
439         if (err != MM_ERROR_NONE || *slotid < 0) {
440                 debug_error("Empty g_slot is not found\n");
441                 goto cleanup;
442         }
443
444         codec_param.volume_config = -1; //setting volume config to -1 since using stream info instead of volume type
445         codec_param.repeat_count = param->repeat_count;
446         codec_param.volume = param->volume;
447         codec_param.source = param->source;
448         codec_param.priority = param->priority;
449         codec_param.stop_cb = _MMSoundMgrCodecStopCallback;
450         codec_param.param = *slotid;
451         codec_param.pid = (int)param->param;
452         codec_param.handle_route = param->handle_route;
453         codec_param.codec_wave_mutex = &codec_wave_mutex;
454         codec_param.stream_index = param->stream_index;
455         MMSOUND_STRNCPY(codec_param.stream_type, param->stream_type, MM_SOUND_STREAM_TYPE_LEN);
456         pthread_mutex_lock(&g_slot_mutex);
457 #ifdef DEBUG_DETAIL
458         debug_msg("After Slot_mutex LOCK\n");
459 #endif
460
461         /* Codec id WAV or MP3 */
462         g_slots[*slotid].pluginid = count;
463         g_slots[*slotid].param    = param->param;               /* This arg is used callback data */
464
465         debug_msg("Using Slotid : [%d] Slot Status : [%d]\n", *slotid, g_slots[*slotid].status);
466
467         err = g_plugins[g_slots[*slotid].pluginid].Create(&codec_param, &info, &(g_slots[*slotid].plughandle));
468         debug_msg("Created audio handle : [%d]\n", g_slots[*slotid].plughandle);
469         if (err != MM_ERROR_NONE) {
470                 debug_error("Plugin create fail : 0x%08X\n", err);
471                 g_slots[*slotid].status = STATUS_IDLE;
472                 pthread_mutex_unlock(&g_slot_mutex);
473                 debug_warning("After Slot_mutex UNLOCK\n");
474                 goto cleanup;
475         }
476
477         err = g_plugins[g_slots[*slotid].pluginid].Play(g_slots[*slotid].plughandle);
478         if (err != MM_ERROR_NONE) {
479                 debug_error("Fail to play : 0x%08X\n", err);
480                 g_plugins[g_slots[*slotid].pluginid].Destroy(g_slots[*slotid].plughandle);
481         }
482
483         pthread_mutex_unlock(&g_slot_mutex);
484 #ifdef DEBUG_DETAIL
485         debug_msg("After Slot_mutex UNLOCK\n");
486 #endif
487
488 cleanup:
489
490 #ifdef DEBUG_DETAIL
491         debug_leave("\n");
492 #endif
493
494         return err;
495
496 }
497
498 #define DTMF_PLUGIN_COUNT 2
499 int MMSoundMgrCodecPlayDtmf(int *slotid, const mmsound_mgr_codec_param_t *param)
500 {
501         int count = 0;
502         int *codec_type;
503         mmsound_codec_info_t info;
504         mmsound_codec_param_t codec_param;
505         int err = MM_ERROR_NONE;
506 #ifdef FOCUS_INTEGRATION
507         int need_focus_unregister = 0;
508 #endif
509
510 #ifdef DEBUG_DETAIL
511         debug_enter("\n");
512 #endif
513
514         for (count = 0; g_plugins[count].GetSupportTypes; count++) {
515                 /* Find codec */
516                 codec_type = g_plugins[count].GetSupportTypes();
517                 if(codec_type && (MM_SOUND_SUPPORTED_CODEC_DTMF == codec_type[0]))
518                         break;
519         }
520
521         /*The count num means codec type DTMF */
522         debug_msg("DTMF[%d] Repeat[%d] Volume[%f] plugin_codec[%d]\n", param->tone, param->repeat_count, param->volume, count);
523
524         if (g_plugins[count].GetSupportTypes == NULL) { /* Codec not found */
525                 debug_error("unsupported file type %d\n", count);
526                 printf("unsupported file type %d\n", count);
527                 err = MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
528                 goto cleanup;
529         }
530
531 #ifdef DEBUG_DETAIL
532         debug_msg("Get New handle\n");
533 #endif
534
535         err = _MMSoundMgrCodecGetEmptySlot(slotid);
536         if(err != MM_ERROR_NONE || *slotid < 0)
537         {
538                 debug_error("Empty g_slot is not found\n");
539                 goto cleanup;
540         }
541
542         codec_param.tone = param->tone;
543         codec_param.priority = 0;
544         codec_param.volume_config = param->volume_config;
545         codec_param.repeat_count = param->repeat_count;
546         codec_param.volume = param->volume;
547         codec_param.stop_cb = _MMSoundMgrCodecStopCallback;
548         codec_param.param = *slotid;
549         codec_param.pid = (int)param->param;
550         codec_param.stream_index = param->stream_index;
551         MMSOUND_STRNCPY(codec_param.stream_type, param->stream_type, MM_SOUND_STREAM_TYPE_LEN);
552
553         pthread_mutex_lock(&g_slot_mutex);
554 #ifdef DEBUG_DETAIL
555         debug_msg("After Slot_mutex LOCK\n");
556 #endif
557
558 #ifdef FOCUS_INTEGRATION
559         //
560         /*
561          * Register FOCUS here
562          */
563
564         if (param->session_type != MM_SESSION_TYPE_CALL &&
565                 param->session_type != MM_SESSION_TYPE_VIDEOCALL &&
566                 param->session_type != MM_SESSION_TYPE_VOIP &&
567                 param->session_type != MM_SESSION_TYPE_VOICE_RECOGNITION &&
568                 param->enable_session) {
569
570                 unsigned int subs_id = 0;
571
572                 err = mm_sound_add_device_connected_callback(MM_SOUND_DEVICE_STATE_ACTIVATED_FLAG, (mm_sound_device_connected_cb)sound_codec_device_connected_callback, (void*) *slotid, &subs_id);
573                 if (err) {
574                         debug_error("mm_sound_add_device_connected_callback failed [0x%x]", err);
575                         pthread_mutex_unlock(&g_slot_mutex);
576                         return MM_ERROR_POLICY_INTERNAL;
577                 }
578                 g_slots[*slotid].subs_id = subs_id;
579
580                 if ((param->session_options & MM_SESSION_OPTION_PAUSE_OTHERS) || param->session_type == MM_SESSION_TYPE_ALARM || param->session_type == MM_SESSION_TYPE_NOTIFY || param->session_type == MM_SESSION_TYPE_EMERGENCY) {
581                         debug_warning("session option is PAUSE_OTHERS -> acquire focus");
582                         err = mm_sound_focus_get_id((int *)(&param->focus_handle));
583                         err = mm_sound_register_focus_for_session(param->focus_handle, (int)param->param, "media", sound_codec_focus_callback, (void*)*slotid);
584                         if (err) {
585                                 debug_error("mm_sound_register_focus failed [0x%x]", err);
586                                 pthread_mutex_unlock(&g_slot_mutex);
587                                 return MM_ERROR_POLICY_INTERNAL;
588                         }
589                         err = mm_sound_acquire_focus(param->focus_handle, FOCUS_FOR_BOTH, NULL);
590                         if (err) {
591                                 debug_error("mm_sound_acquire_focus failed [0x%x]", err);
592                                 err = mm_sound_unregister_focus(param->focus_handle);
593                                 pthread_mutex_unlock(&g_slot_mutex);
594                                 return MM_ERROR_POLICY_INTERNAL;
595                         }
596                         g_slots[*slotid].current_focus_type = FOCUS_FOR_BOTH;
597                 } else if (param->session_options & MM_SESSION_OPTION_UNINTERRUPTIBLE) {
598                         /* do nothing */
599                         debug_warning("session option is UNINTERRUPTIBLE, nothing to do with focus");
600                 } else {
601                         debug_warning("need to set focus watch callback");
602                         err = mm_sound_set_focus_watch_callback_for_session((int)param->param, FOCUS_FOR_BOTH, sound_codec_focus_watch_callback, (void*)*slotid, (int *)(&param->focus_wcb_id));
603                         if (err) {
604                                 debug_error("mm_sound_set_focus_watch_callback failed [0x%x]", err);
605                                 pthread_mutex_unlock(&g_slot_mutex);
606                                 return MM_ERROR_POLICY_INTERNAL;
607                         }
608                 }
609         }
610 #endif
611
612         g_slots[*slotid].pluginid = count;
613         g_slots[*slotid].param    = param->param;               /* This arg is used callback data */
614         g_slots[*slotid].session_type = param->session_type;
615         g_slots[*slotid].session_options = param->session_options;
616 #ifdef FOCUS_INTEGRATION
617         g_slots[*slotid].focus_handle= param->focus_handle;
618         g_slots[*slotid].focus_wcb_id= param->focus_wcb_id;
619 #endif
620         g_slots[*slotid].enable_session = param->enable_session;
621         g_slots[*slotid].pid = (int)param->param;
622
623 #ifdef DEBUG_DETAIL
624         debug_msg("Using Slotid : [%d] Slot Status : [%d]\n", *slotid, g_slots[*slotid].status);
625 #endif
626
627         err = g_plugins[g_slots[*slotid].pluginid].Create(&codec_param, &info, &(g_slots[*slotid].plughandle));
628         debug_msg("Created audio handle : [%d]\n", g_slots[*slotid].plughandle);
629         if (err != MM_ERROR_NONE) {
630                 debug_error("Plugin create fail : 0x%08X\n", err);
631                 g_slots[*slotid].status = STATUS_IDLE;
632                 pthread_mutex_unlock(&g_slot_mutex);
633                 debug_warning("After Slot_mutex UNLOCK\n");
634 #ifdef FOCUS_INTEGRATION
635                 need_focus_unregister = 1;
636 #endif
637                 goto cleanup;
638         }
639
640         err = g_plugins[g_slots[*slotid].pluginid].Play(g_slots[*slotid].plughandle);
641         if (err != MM_ERROR_NONE) {
642                 debug_error("Fail to play : 0x%08X\n", err);
643                 g_plugins[g_slots[*slotid].pluginid].Destroy(g_slots[*slotid].plughandle);
644 #ifdef FOCUS_INTEGRATION
645                 need_focus_unregister = 1;
646 #endif
647         }
648
649         pthread_mutex_unlock(&g_slot_mutex);
650
651         debug_msg("Using Slotid : [%d] Slot Status : [%d]\n", *slotid, g_slots[*slotid].status);
652 #ifdef DEBUG_DETAIL
653         debug_msg("After Slot_mutex UNLOCK\n")
654 #endif
655
656 cleanup:
657 #ifdef FOCUS_INTEGRATION
658         if (param->session_type != MM_SESSION_TYPE_CALL &&
659                 param->session_type != MM_SESSION_TYPE_VIDEOCALL &&
660                 param->session_type != MM_SESSION_TYPE_VOIP &&
661                 param->session_type != MM_SESSION_TYPE_VOICE_RECOGNITION &&
662                 param->enable_session &&
663                 need_focus_unregister == 1) {
664
665                 if (param->session_options & MM_SESSION_OPTION_PAUSE_OTHERS || param->session_type == MM_SESSION_TYPE_ALARM || param->session_type == MM_SESSION_TYPE_NOTIFY || param->session_type == MM_SESSION_TYPE_EMERGENCY) {
666                         err = mm_sound_release_focus(param->focus_handle, FOCUS_FOR_BOTH, NULL);
667                         if(mm_sound_unregister_focus(param->focus_handle) || err) {
668                                 debug_error("focus cleaning up failed[0x%x]", err);
669                                 return MM_ERROR_POLICY_INTERNAL;
670                         }
671                 } else if (~(param->session_options & MM_SESSION_OPTION_PAUSE_OTHERS)) {
672                         err = mm_sound_unset_focus_watch_callback(param->focus_wcb_id);
673                         if (err) {
674                                 debug_error("focus watch cleaning up failed[0x%x]", err);
675                                 return MM_ERROR_POLICY_INTERNAL;
676                         }
677                 }
678         }
679 #endif
680
681 #ifdef DEBUG_DETAIL
682         debug_leave("\n");
683 #endif
684
685         return err;
686 }
687
688 int MMSoundMgrCodecPlayDtmfWithStreamInfo(int *slotid, const mmsound_mgr_codec_param_t *param)
689 {
690         int count = 0;
691         int *codec_type;
692         mmsound_codec_info_t info;
693         mmsound_codec_param_t codec_param;
694         int err = MM_ERROR_NONE;
695
696 #ifdef DEBUG_DETAIL
697         debug_enter("\n");
698 #endif
699
700         for (count = 0; g_plugins[count].GetSupportTypes; count++) {
701                 /* Find codec */
702                 codec_type = g_plugins[count].GetSupportTypes();
703                 if(codec_type && (MM_SOUND_SUPPORTED_CODEC_DTMF == codec_type[0]))
704                         break;
705         }
706
707         /*The count num means codec type DTMF */
708         debug_msg("DTMF[%d] Repeat[%d] Volume[%f] plugin_codec[%d]\n", param->tone, param->repeat_count, param->volume, count);
709
710         if (g_plugins[count].GetSupportTypes == NULL) { /* Codec not found */
711                 debug_error("unsupported file type %d\n", count);
712                 printf("unsupported file type %d\n", count);
713                 err = MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
714                 goto cleanup;
715         }
716
717 #ifdef DEBUG_DETAIL
718         debug_msg("Get New handle\n");
719 #endif
720
721         err = _MMSoundMgrCodecGetEmptySlot(slotid);
722         if(err != MM_ERROR_NONE || *slotid < 0)
723         {
724                 debug_error("Empty g_slot is not found\n");
725                 goto cleanup;
726         }
727
728         codec_param.tone = param->tone;
729         codec_param.priority = 0;
730         codec_param.repeat_count = param->repeat_count;
731         codec_param.volume = param->volume;
732         codec_param.stop_cb = _MMSoundMgrCodecStopCallback;
733         codec_param.param = *slotid;
734         codec_param.pid = (int)param->param;
735         codec_param.volume_config = -1; //setting volume config to -1 since using stream info instead of volume type
736         codec_param.stream_index = param->stream_index;
737         MMSOUND_STRNCPY(codec_param.stream_type, param->stream_type, MM_SOUND_STREAM_TYPE_LEN);
738
739         pthread_mutex_lock(&g_slot_mutex);
740 #ifdef DEBUG_DETAIL
741         debug_msg("After Slot_mutex LOCK\n");
742 #endif
743                 g_slots[*slotid].pluginid = count;
744                 g_slots[*slotid].param    = param->param;               /* This arg is used callback data */
745                 g_slots[*slotid].enable_session = param->enable_session;
746
747 #ifdef DEBUG_DETAIL
748                 debug_msg("Using Slotid : [%d] Slot Status : [%d]\n", *slotid, g_slots[*slotid].status);
749 #endif
750
751                 err = g_plugins[g_slots[*slotid].pluginid].Create(&codec_param, &info, &(g_slots[*slotid].plughandle));
752                 debug_msg("Created audio handle : [%d]\n", g_slots[*slotid].plughandle);
753                 if (err != MM_ERROR_NONE) {
754                         debug_error("Plugin create fail : 0x%08X\n", err);
755                         g_slots[*slotid].status = STATUS_IDLE;
756                         pthread_mutex_unlock(&g_slot_mutex);
757                         debug_warning("After Slot_mutex UNLOCK\n");
758                         goto cleanup;
759                 }
760
761                 err = g_plugins[g_slots[*slotid].pluginid].Play(g_slots[*slotid].plughandle);
762                 if (err != MM_ERROR_NONE) {
763                         debug_error("Fail to play : 0x%08X\n", err);
764                         g_plugins[g_slots[*slotid].pluginid].Destroy(g_slots[*slotid].plughandle);
765                 }
766
767                 pthread_mutex_unlock(&g_slot_mutex);
768
769                 debug_msg("Using Slotid : [%d] Slot Status : [%d]\n", *slotid, g_slots[*slotid].status);
770 #ifdef DEBUG_DETAIL
771                 debug_msg("After Slot_mutex UNLOCK\n");
772 #endif
773
774         cleanup:
775 #ifdef DEBUG_DETAIL
776                 debug_leave("\n");
777 #endif
778
779                 return err;
780
781 }
782
783 int MMSoundMgrCodecStop(const int slotid)
784 {
785         int err = MM_ERROR_NONE;
786
787         debug_enter("(Slotid : [%d])\n", slotid);
788
789         if (slotid < 0 || MANAGER_HANDLE_MAX <= slotid) {
790                 return MM_ERROR_INVALID_ARGUMENT;
791         }
792
793         pthread_mutex_lock (&g_slot_mutex);
794 #ifdef DEBUG_DETAIL
795         debug_msg("After Slot_mutex LOCK\n");
796 #endif
797         if (g_slots[slotid].status == STATUS_IDLE) {
798                 err = MM_ERROR_SOUND_INVALID_STATE;
799                 debug_warning("The playing slots is not found, Slot ID : [%d]\n", slotid);
800                 goto cleanup;
801         }
802 #ifdef DEBUG_DETAIL
803         debug_msg("Found slot, Slotid [%d] State [%d]\n", slotid, g_slots[slotid].status);
804 #endif
805
806         err = g_plugins[g_slots[slotid].pluginid].Stop(g_slots[slotid].plughandle);
807         if (err != MM_ERROR_NONE) {
808                 debug_error("Fail to STOP Code : 0x%08X\n", err);
809         }
810         debug_msg("Found slot, Slotid [%d] State [%d]\n", slotid, g_slots[slotid].status);
811 cleanup:
812         pthread_mutex_unlock(&g_slot_mutex);
813 #ifdef DEBUG_DETAIL
814         debug_msg("After Slot_mutex UNLOCK\n");
815 #endif
816         debug_leave("(err : 0x%08X)\n", err);
817
818         return err;
819 }
820 #ifdef FOCUS_INTEGRATION
821 int MMSoundMgrCodecClearFocus(int pid)
822 {
823         int err = MM_ERROR_NONE;
824         int slotid;
825
826         debug_enter("(pid : [%d])\n", pid);
827
828         pthread_mutex_lock (&g_slot_mutex);
829
830         for (slotid = 0 ; slotid < MANAGER_HANDLE_MAX ; slotid++) {
831                 if (g_slots[slotid].pid == pid) {
832                         if (g_slots[slotid].focus_handle || g_slots[slotid].focus_wcb_id) {
833                                 if(g_slots[slotid].session_type != MM_SESSION_TYPE_CALL &&
834                                         g_slots[slotid].session_type != MM_SESSION_TYPE_VIDEOCALL &&
835                                         g_slots[slotid].session_type != MM_SESSION_TYPE_VOIP &&
836                                         g_slots[slotid].session_type != MM_SESSION_TYPE_VOICE_RECOGNITION &&
837                                         g_slots[slotid].enable_session ) {
838                                         if ((g_slots[slotid].session_options & MM_SESSION_OPTION_PAUSE_OTHERS) || g_slots[slotid].session_type == MM_SESSION_TYPE_ALARM || g_slots[slotid].session_type == MM_SESSION_TYPE_NOTIFY || g_slots[slotid].session_type == MM_SESSION_TYPE_EMERGENCY) {
839                                                 err = mm_sound_release_focus(g_slots[slotid].focus_handle, FOCUS_FOR_BOTH, NULL);
840                                                 if (err) {
841                                                         debug_error("mm_sound_release_focus failed [0x%x]", err);
842                                                 }
843                                                 if(mm_sound_unregister_focus(g_slots[slotid].focus_handle) || err) {
844                                                         debug_error("Focus clean up failed [0x%x]", err);
845                                                         err = MM_ERROR_POLICY_INTERNAL;
846                                                         goto cleanup;
847                                                 }
848                                         } else if (~(g_slots[slotid].session_options & MM_SESSION_OPTION_PAUSE_OTHERS)) {
849                                                 err = mm_sound_unset_focus_watch_callback(g_slots[slotid].focus_wcb_id);
850                                                 if (err) {
851                                                         debug_error("mm_sound_unset_focus_watch_callback failed [0x%x]", err);
852                                                         err = MM_ERROR_POLICY_INTERNAL;
853                                                         goto cleanup;
854                                                 }
855                                         }
856                                 }
857                                 if(mm_sound_remove_device_connected_callback(g_slots[slotid].subs_id) != MM_ERROR_NONE)
858                                         debug_error("mm_sound_remove_device_connected_callback() failed");
859                                 g_slots[slotid].focus_handle = 0;
860                                 g_slots[slotid].focus_wcb_id = 0;
861                                 g_slots[slotid].subs_id = 0;
862                         }
863                 }
864         }
865
866 cleanup:
867         pthread_mutex_unlock(&g_slot_mutex);
868         debug_leave("(err : 0x%08X)\n", err);
869
870         return err;
871 }
872 #endif
873
874 static int _MMSoundMgrCodecStopCallback(int param)
875 {
876         int err = MM_ERROR_NONE;
877
878         debug_enter("(Slot : %d)\n", param);
879
880         if (param < 0 || param >= MANAGER_HANDLE_MAX) {
881                 debug_error ("Slot index param [%d] is invalid", param);
882                 return MM_ERROR_INVALID_ARGUMENT;
883         }
884
885         pthread_mutex_lock(&g_slot_mutex);
886         debug_msg("[CODEC MGR] Slot_mutex lock done\n");
887
888 #ifdef FOCUS_INTEGRATION
889         /*
890          * Unregister FOCUS here
891          */
892         debug_msg("[CODEC MGR] enable_session %d ",g_slots[param].enable_session);
893
894         if (g_slots[param].focus_handle || g_slots[param].focus_wcb_id) {
895                 if(g_slots[param].session_type != MM_SESSION_TYPE_CALL &&
896                         g_slots[param].session_type != MM_SESSION_TYPE_VIDEOCALL &&
897                         g_slots[param].session_type != MM_SESSION_TYPE_VOIP &&
898                         g_slots[param].session_type != MM_SESSION_TYPE_VOICE_RECOGNITION &&
899                         g_slots[param].enable_session ) {
900                         if ((g_slots[param].session_options & MM_SESSION_OPTION_PAUSE_OTHERS) || g_slots[param].session_type == MM_SESSION_TYPE_ALARM || g_slots[param].session_type == MM_SESSION_TYPE_NOTIFY || g_slots[param].session_type == MM_SESSION_TYPE_EMERGENCY) {
901                                 if(g_slots[param].current_focus_type != FOCUS_NONE) {
902                                         err = mm_sound_release_focus(g_slots[param].focus_handle, g_slots[param].current_focus_type, NULL);
903                                         if (err) {
904                                                 debug_error("mm_sound_release_focus failed [0x%x]", err);
905                                         }
906                                 }
907                                 if(mm_sound_unregister_focus(g_slots[param].focus_handle) || err) {
908                                         debug_error("Focus clean up failed [0x%x]", err);
909                                         pthread_mutex_unlock(&g_slot_mutex);
910                                         return MM_ERROR_POLICY_INTERNAL;
911                                 }
912                         } else if (~(g_slots[param].session_options & MM_SESSION_OPTION_PAUSE_OTHERS)) {
913                                 err = mm_sound_unset_focus_watch_callback(g_slots[param].focus_wcb_id);
914                                 if (err) {
915                                         debug_error("mm_sound_unset_focus_watch_callback failed [0x%x]", err);
916                                         pthread_mutex_unlock(&g_slot_mutex);
917                                         return MM_ERROR_POLICY_INTERNAL;
918                                 }
919                         }
920                 }
921                 if(mm_sound_remove_device_connected_callback(g_slots[param].subs_id) != MM_ERROR_NONE)
922                         debug_error("mm_sound_remove_device_connected_callback() failed");
923         }
924 #endif
925
926         __mm_sound_mgr_ipc_notify_play_file_end(param);
927
928         debug_msg("Client callback msg_type (instance) : [%d]\n", (int)g_slots[param].param);
929         debug_msg("Handle allocated handle : [0x%08X]\n", g_slots[param].plughandle);
930         err = g_plugins[g_slots[param].pluginid].Destroy(g_slots[param].plughandle);
931         if (err < 0 ) {
932                 debug_critical("[CODEC MGR] Fail to destroy slot number : [%d] err [0x%x]\n", param, err);
933         }
934         memset(&g_slots[param], 0, sizeof(__mmsound_mgr_codec_handle_t));
935         g_slots[param].status = STATUS_IDLE;
936         pthread_mutex_unlock(&g_slot_mutex);
937         debug_msg("[CODEC MGR] Slot_mutex done\n");
938
939         return err;
940 }
941
942 static int _MMSoundMgrCodecGetEmptySlot(int *slot)
943 {
944         int count = 0;
945         int err = MM_ERROR_NONE;
946
947 #ifdef DEBUG_DETAIL
948         debug_enter("\n");
949 #endif
950         debug_msg("Codec slot ID : [%d]\n", *slot);
951         pthread_mutex_lock(&g_slot_mutex);
952 #ifdef DEBUG_DETAIL
953         debug_msg("After Slot_mutex LOCK\n");
954 #endif
955
956         for (count = SOUND_SLOT_START; count < MANAGER_HANDLE_MAX ; count++) {
957                 if (g_slots[count].status == STATUS_IDLE) {
958                         g_slots[count].status = STATUS_SOUND;
959                         break;
960                 }
961         }
962         pthread_mutex_unlock(&g_slot_mutex);
963 #ifdef DEBUG_DETAIL
964         debug_msg("After Slot_mutex UNLOCK\n");
965 #endif
966
967         if (count < MANAGER_HANDLE_MAX) {
968                 debug_msg("New handle allocated (codec slot ID : [%d])\n", count);
969                 *slot = count;
970                 err =  MM_ERROR_NONE;
971         } else {
972                 debug_warning("Handle is full handle : [%d]\n", count);
973                 *slot = -1;
974                 /* Temporal code for reset */
975                 while(count--) {
976                         g_slots[count].status = STATUS_IDLE;
977                 }
978                 err =  MM_ERROR_SOUND_INTERNAL;
979         }
980
981 #ifdef DEBUG_DETAIL
982         debug_leave("\n");
983 #endif
984
985         return err;
986 }
987
988 static int _MMSoundMgrCodecRegisterInterface(MMSoundPluginType *plugin)
989 {
990         int err = MM_ERROR_NONE;
991         int count = 0;
992         void *getinterface = NULL;
993
994 #ifdef DEBUG_DETAIL
995         debug_enter("\n");
996 #endif
997
998         /* find emptry slot */
999         for (count = 0; count < MM_SOUND_SUPPORTED_CODEC_NUM; count++) {
1000                 if (g_plugins[count].GetSupportTypes == NULL)
1001                         break;
1002         }
1003
1004         if (count == MM_SOUND_SUPPORTED_CODEC_NUM) {
1005                 debug_critical("The plugin support type is not valid\n");
1006                 return MM_ERROR_COMMON_OUT_OF_RANGE;
1007         }
1008
1009         err = MMSoundPluginGetSymbol(plugin, CODEC_GET_INTERFACE_FUNC_NAME, &getinterface);
1010         if (err != MM_ERROR_NONE) {
1011                 debug_error("Get Symbol CODEC_GET_INTERFACE_FUNC_NAME is fail : %x\n", err);
1012                 goto cleanup;
1013         }
1014         debug_msg("interface[%p] empty_slot[%d]\n", getinterface, count);
1015
1016         err = MMSoundPlugCodecCastGetInterface(getinterface)(&g_plugins[count]);
1017         if (err != MM_ERROR_NONE) {
1018                 debug_error("Get interface fail : %x\n", err);
1019
1020 cleanup:
1021                 /* If error occur, clean interface */
1022                 memset(&g_plugins[count], 0, sizeof(mmsound_codec_interface_t));
1023         } else {
1024                 if (g_plugins[count].SetThreadPool)
1025                         g_plugins[count].SetThreadPool(MMSoundThreadPoolRun);
1026         }
1027
1028 #ifdef DEBUG_DETAIL
1029         debug_leave("\n");
1030 #endif
1031
1032         return err;
1033 }
1034