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