5 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
7 * Contact: Seungbae Shin <seungbae.shin@samsung.com>
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
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
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"
40 #include "../include/mm_sound_common.h"
41 #include "../include/mm_sound.h"
43 #define SHUTDOWN_TIMEOUT_SEC 60
45 #define STATUS_SOUND 3
46 #define SOUND_SLOT_START 0
47 #define MANAGER_HANDLE_MAX 256
50 int (*callback)(int, void *, void *, int); /* msg_type(pid) client callback & client data info */
55 MMHandleType plughandle;
61 } __mmsound_mgr_codec_handle_t;
63 static MMSoundPluginType *g_codec_plugins = NULL;
64 static __mmsound_mgr_codec_handle_t g_slots[MANAGER_HANDLE_MAX];
65 static mmsound_codec_interface_t g_plugins[MM_SOUND_SUPPORTED_CODEC_NUM];
66 static pthread_mutex_t g_slot_mutex;
67 static GSourceFunc g_shutdown_cb;
68 static guint g_timer_id = 0;
70 #define SLOT_LOCK() do { pthread_mutex_lock(&g_slot_mutex); /* debug_msg("After Slot_mutex LOCK"); */ } while (0)
71 #define SLOT_UNLOCK() do { pthread_mutex_unlock(&g_slot_mutex); /* debug_msg("After Slot_mutex UNLOCK"); */ } while (0)
73 static int _MMSoundMgrCodecRegisterInterface(MMSoundPluginType *plugin);
74 static int _MMSoundMgrCodecStopCallback(int param);
75 static gboolean _mm_sound_mgr_codec_slot_is_empty();
77 static gboolean _idle_cb(gpointer user_data)
79 if (_mm_sound_mgr_codec_slot_is_empty()) {
80 debug_msg("slot is empty, ready to shutdown! %p", g_shutdown_cb);
84 debug_warning("slot is not empty!!! no shutdown...");
90 static gboolean _timeout_cb(gpointer user_data)
92 debug_warning("TIMEOUT : add idle callback now...");
94 g_idle_add(_idle_cb, NULL);
101 /* FIXME : critical section for g_timer_id? */
102 static void _mm_sound_mgr_codec_shutdown_timer_start()
104 if (g_timer_id > 0) {
105 debug_error("Already active timer [%d] exists", g_timer_id);
109 g_timer_id = g_timeout_add_seconds(SHUTDOWN_TIMEOUT_SEC, _timeout_cb, NULL);
110 debug_error("TIMER : new timer [%d]", g_timer_id);
112 debug_warning("No Timer started due to invalid shutdown callback");
116 static void _mm_sound_mgr_codec_shutdown_timer_stop()
118 if (g_timer_id > 0) {
119 debug_error("TIMER : remove timer id [%d]", g_timer_id);
120 g_source_remove(g_timer_id);
123 debug_log("No Timer to stop...");
127 static int _mm_sound_mgr_codec_slot_get_empty(int *slot)
130 int err = MM_ERROR_NONE;
135 for (slotid = SOUND_SLOT_START; slotid < MANAGER_HANDLE_MAX ; slotid++) {
136 if (g_slots[slotid].status == STATUS_IDLE) {
137 g_slots[slotid].status = STATUS_SOUND;
142 if (slotid < MANAGER_HANDLE_MAX) {
143 debug_msg("New handle allocated (codec slot ID : [%d])", slotid);
148 /* FIXME: avoiding infinite wait is required */
149 debug_warning("Handle is full..wait for a while and will retry...");
153 _mm_sound_mgr_codec_shutdown_timer_stop();
160 static gboolean _mm_sound_mgr_codec_slot_is_empty()
164 for (slotid = SOUND_SLOT_START; slotid < MANAGER_HANDLE_MAX ; slotid++) {
165 if (g_slots[slotid].status == STATUS_SOUND)
169 return (slotid == MANAGER_HANDLE_MAX) ? TRUE : FALSE;
172 static void _mm_sound_mgr_codec_slot_clear(int slotid)
174 memset(&g_slots[slotid], 0, sizeof(__mmsound_mgr_codec_handle_t));
175 g_slots[slotid].status = STATUS_IDLE;
177 debug_error("SlotID [%d] cleared", slotid);
180 int MMSoundMgrCodecInit(const char *targetdir, GSourceFunc _shutdown_cb)
187 memset(g_slots, 0, sizeof(g_slots));
189 if (pthread_mutex_init(&g_slot_mutex, NULL)) {
190 debug_error("pthread_mutex_init failed");
191 return MM_ERROR_SOUND_INTERNAL;
194 for (slotid = 0; slotid < MANAGER_HANDLE_MAX; slotid++)
195 _mm_sound_mgr_codec_slot_clear(slotid);
197 if (g_codec_plugins) {
198 debug_warning("Please Check Init twice");
199 MMSoundPluginRelease(g_codec_plugins);
202 MMSoundPluginScan(targetdir, MM_SOUND_PLUGIN_TYPE_CODEC, &g_codec_plugins);
203 if (g_codec_plugins) {
204 while (g_codec_plugins[loop].type != MM_SOUND_PLUGIN_TYPE_NONE)
205 _MMSoundMgrCodecRegisterInterface(&g_codec_plugins[loop++]);
209 g_shutdown_cb = _shutdown_cb;
211 debug_warning("shutdown callback is NULL");
214 return MM_ERROR_NONE;
217 int MMSoundMgrCodecFini(void)
221 memset(g_plugins, 0, sizeof(mmsound_codec_interface_t) * MM_SOUND_SUPPORTED_CODEC_NUM);
222 MMSoundPluginRelease(g_codec_plugins);
223 g_codec_plugins = NULL;
224 pthread_mutex_destroy(&g_slot_mutex);
227 return MM_ERROR_NONE;
230 static int _MMSoundMgrCodecFindCodecPluginID(enum MMSoundSupportedCodec codec_to_find)
235 for (plugin_id = 0; plugin_id < MM_SOUND_SUPPORTED_CODEC_NUM; plugin_id++) {
236 if (g_plugins[plugin_id].GetSupportTypes) {
237 codec_type = g_plugins[plugin_id].GetSupportTypes();
238 if (codec_type[0] == codec_to_find)
246 int MMSoundMgrCodecPlayWithStreamInfo(int *slotid, const mmsound_mgr_codec_param_t *param)
249 mmsound_codec_info_t info;
250 mmsound_codec_param_t codec_param;
251 int err = MM_ERROR_NONE;
256 plugin_id = _MMSoundMgrCodecFindCodecPluginID(MM_SOUND_SUPPORTED_CODEC_WAVE);
257 if (plugin_id == -1) {
258 debug_error("Could not find proper codec plugin!!!");
259 err = MM_ERROR_SOUND_INTERNAL;
263 err = g_plugins[plugin_id].Parse(param->pfilename, &info);
264 if (err != MM_ERROR_NONE) {
265 debug_error("Could not parse file [%s] by plugin[%d]", param->pfilename, plugin_id);
269 err = _mm_sound_mgr_codec_slot_get_empty(slotid);
270 if (err != MM_ERROR_NONE || *slotid < 0) {
271 debug_error("Empty g_slot is not found");
275 codec_param.volume_config = -1; //setting volume config to -1 since using stream info instead of volume type
276 codec_param.repeat_count = param->repeat_count;
277 codec_param.volume = param->volume;
278 codec_param.pfilename = param->pfilename;
279 codec_param.stop_cb = _MMSoundMgrCodecStopCallback;
280 codec_param.param = *slotid;
281 codec_param.pid = (int)param->param;
282 codec_param.stream_index = param->stream_index;
283 MMSOUND_STRNCPY(codec_param.stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
286 /* Codec id WAV or MP3 */
287 g_slots[*slotid].pluginid = plugin_id;
288 g_slots[*slotid].param = param->param; /* This arg is used callback data */
290 debug_msg("Using Slotid : [%d] Slot Status : [%d]", *slotid, g_slots[*slotid].status);
292 err = g_plugins[g_slots[*slotid].pluginid].Create(&codec_param, &info, &(g_slots[*slotid].plughandle));
293 debug_msg("Created audio handle : [%p]", g_slots[*slotid].plughandle);
294 if (err != MM_ERROR_NONE) {
295 debug_error("Plugin create fail : 0x%08X", err);
296 g_slots[*slotid].status = STATUS_IDLE;
301 err = g_plugins[g_slots[*slotid].pluginid].Play(g_slots[*slotid].plughandle);
302 if (err != MM_ERROR_NONE) {
303 debug_error("Fail to play : 0x%08X", err);
304 g_plugins[g_slots[*slotid].pluginid].Destroy(g_slots[*slotid].plughandle);
310 if (_mm_sound_mgr_codec_slot_is_empty())
311 _mm_sound_mgr_codec_shutdown_timer_start();
321 int MMSoundMgrCodecPlayDtmfWithStreamInfo(int *slotid, const mmsound_mgr_codec_param_t *param)
324 mmsound_codec_info_t info;
325 mmsound_codec_param_t codec_param;
326 int err = MM_ERROR_NONE;
331 plugin_id = _MMSoundMgrCodecFindCodecPluginID(MM_SOUND_SUPPORTED_CODEC_DTMF);
332 if (plugin_id == -1) {
333 debug_error("Could not find proper codec plugin!!!");
334 err = MM_ERROR_SOUND_INTERNAL;
338 /*The count num means codec type DTMF */
339 debug_msg("DTMF[%d] Repeat[%d] Volume[%f] plugin_codec[%d]", param->tone, param->repeat_count, param->volume, plugin_id);
341 if (g_plugins[plugin_id].GetSupportTypes == NULL) { /* Codec not found */
342 debug_error("unsupported file type %d", plugin_id);
343 printf("unsupported file type %d", plugin_id);
344 err = MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
349 debug_msg("Get New handle");
352 err = _mm_sound_mgr_codec_slot_get_empty(slotid);
353 if (err != MM_ERROR_NONE || *slotid < 0) {
354 debug_error("Empty g_slot is not found");
358 codec_param.tone = param->tone;
359 codec_param.repeat_count = param->repeat_count;
360 codec_param.volume = param->volume;
361 codec_param.stop_cb = _MMSoundMgrCodecStopCallback;
362 codec_param.param = *slotid;
363 codec_param.pid = (int)param->param;
364 codec_param.volume_config = -1; //setting volume config to -1 since using stream info instead of volume type
365 codec_param.stream_index = param->stream_index;
366 MMSOUND_STRNCPY(codec_param.stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
369 g_slots[*slotid].pluginid = plugin_id;
370 g_slots[*slotid].param = param->param; /* This arg is used callback data */
373 debug_msg("Using Slotid : [%d] Slot Status : [%d]", *slotid, g_slots[*slotid].status);
376 err = g_plugins[g_slots[*slotid].pluginid].Create(&codec_param, &info, &(g_slots[*slotid].plughandle));
377 debug_msg("Created audio handle : [%p]", g_slots[*slotid].plughandle);
378 if (err != MM_ERROR_NONE) {
379 debug_error("Plugin create fail : 0x%08X", err);
380 g_slots[*slotid].status = STATUS_IDLE;
385 err = g_plugins[g_slots[*slotid].pluginid].Play(g_slots[*slotid].plughandle);
386 if (err != MM_ERROR_NONE) {
387 debug_error("Fail to play : 0x%08X", err);
388 g_plugins[g_slots[*slotid].pluginid].Destroy(g_slots[*slotid].plughandle);
392 debug_msg("Using Slotid : [%d] Slot Status : [%d]", *slotid, g_slots[*slotid].status);
403 int MMSoundMgrCodecStop(const int slotid)
405 int err = MM_ERROR_NONE;
407 debug_enter("(Slotid : [%d])", slotid);
409 if (slotid < 0 || MANAGER_HANDLE_MAX <= slotid)
410 return MM_ERROR_INVALID_ARGUMENT;
413 if (g_slots[slotid].status == STATUS_IDLE) {
414 err = MM_ERROR_SOUND_INVALID_STATE;
415 debug_warning("The playing slots is not found, Slot ID : [%d]", slotid);
419 debug_msg("Found slot, Slotid [%d] State [%d]", slotid, g_slots[slotid].status);
422 g_slots[slotid].stop_by_user = true;
424 err = g_plugins[g_slots[slotid].pluginid].Stop(g_slots[slotid].plughandle);
425 if (err != MM_ERROR_NONE)
426 debug_error("Fail to STOP Code : 0x%08X", err);
430 debug_leave("(err : 0x%08X)", err);
435 static int _MMSoundMgrCodecStopCallback(int param)
437 int err = MM_ERROR_NONE;
439 if (param < 0 || param >= MANAGER_HANDLE_MAX) {
440 debug_error("Slot index param [%d] is invalid", param);
441 return MM_ERROR_INVALID_ARGUMENT;
444 debug_enter("(Slot : %d) stop-by-user : %d", param, g_slots[param].stop_by_user);
446 if (!g_slots[param].stop_by_user) {
448 __mm_sound_mgr_ipc_notify_play_file_end(param);
449 debug_msg("Client callback msg_type (instance) : [%d]", (int)g_slots[param].param);
452 debug_msg("Handle allocated handle : [%p]", g_slots[param].plughandle);
453 err = g_plugins[g_slots[param].pluginid].Destroy(g_slots[param].plughandle);
455 debug_critical("[CODEC MGR] Fail to destroy slot number : [%d] err [0x%x]", param, err);
457 _mm_sound_mgr_codec_slot_clear(param);
458 if (_mm_sound_mgr_codec_slot_is_empty())
459 _mm_sound_mgr_codec_shutdown_timer_start();
461 if (!g_slots[param].stop_by_user)
471 static int _MMSoundMgrCodecRegisterInterface(MMSoundPluginType *plugin)
473 int err = MM_ERROR_NONE;
475 void *getinterface = NULL;
481 /* find emptry slot */
482 for (plugin_id = 0; plugin_id < MM_SOUND_SUPPORTED_CODEC_NUM; plugin_id++) {
483 if (g_plugins[plugin_id].GetSupportTypes == NULL)
487 if (plugin_id == MM_SOUND_SUPPORTED_CODEC_NUM) {
488 debug_critical("The plugin support type is not valid");
489 return MM_ERROR_COMMON_OUT_OF_RANGE;
492 err = MMSoundPluginGetSymbol(plugin, CODEC_GET_INTERFACE_FUNC_NAME, &getinterface);
493 if (err != MM_ERROR_NONE) {
494 debug_error("Get Symbol CODEC_GET_INTERFACE_FUNC_NAME is fail : %x", err);
497 debug_msg("interface[%p] empty_slot[%d]", getinterface, plugin_id);
499 err = MMSoundPlugCodecCastGetInterface(getinterface)(&g_plugins[plugin_id]);
500 if (err != MM_ERROR_NONE) {
501 debug_error("Get interface fail : %x", err);
504 /* If error occur, clean interface */
505 memset(&g_plugins[plugin_id], 0, sizeof(mmsound_codec_interface_t));
507 if (g_plugins[plugin_id].SetThreadPool)
508 g_plugins[plugin_id].SetThreadPool(MMSoundThreadPoolRun);