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