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