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;
59 } __mmsound_mgr_codec_handle_t;
61 static MMSoundPluginType *g_codec_plugins = NULL;
62 static __mmsound_mgr_codec_handle_t g_slots[MANAGER_HANDLE_MAX];
63 static mmsound_codec_interface_t g_plugins[MM_SOUND_SUPPORTED_CODEC_NUM];
64 static pthread_mutex_t g_slot_mutex;
65 static GSourceFunc g_shutdown_cb;
66 static guint g_timer_id = 0;
69 #define SLOT_LOCK() do { \
70 debug_msg("Before Slot_mutex LOCK"); \
71 pthread_mutex_lock(&g_slot_mutex); \
72 debug_msg("After Slot_mutex LOCK"); \
74 #define SLOT_UNLOCK() do { \
75 debug_msg("Before Slot_mutex UNLOCK"); \
76 pthread_mutex_unlock(&g_slot_mutex); \
77 debug_msg("After Slot_mutex UNLOCK"); \
80 #define SLOT_LOCK() do { pthread_mutex_lock(&g_slot_mutex); } while (0)
81 #define SLOT_UNLOCK() do { pthread_mutex_unlock(&g_slot_mutex); } while (0)
84 static int _MMSoundMgrCodecRegisterInterface(MMSoundPluginType *plugin);
85 static int _MMSoundMgrCodecStopCallback(int slotid, bool stop_by_user);
86 static gboolean _mm_sound_mgr_codec_slot_is_empty();
88 static gboolean _idle_cb(gpointer user_data)
90 if (_mm_sound_mgr_codec_slot_is_empty()) {
91 debug_msg("slot is empty, ready to shutdown! %p", g_shutdown_cb);
95 debug_warning("slot is not empty!!! no shutdown...");
101 static gboolean _timeout_cb(gpointer user_data)
103 debug_warning("TIMEOUT : add idle callback now...");
105 g_idle_add(_idle_cb, NULL);
112 /* FIXME : critical section for g_timer_id? */
113 static void _mm_sound_mgr_codec_shutdown_timer_start()
115 if (g_timer_id > 0) {
116 debug_error("Already active timer [%d] exists", g_timer_id);
120 g_timer_id = g_timeout_add_seconds(SHUTDOWN_TIMEOUT_SEC, _timeout_cb, NULL);
121 debug_warning("TIMER : new timer [%d]", g_timer_id);
123 debug_warning("No Timer started due to invalid shutdown callback");
127 static void _mm_sound_mgr_codec_shutdown_timer_stop()
129 if (g_timer_id > 0) {
130 debug_warning("TIMER : remove timer id [%d]", g_timer_id);
131 g_source_remove(g_timer_id);
134 debug_log("No Timer to stop...");
138 static int _mm_sound_mgr_codec_slot_get_empty(int *slot)
141 int err = MM_ERROR_NONE;
146 for (slotid = SOUND_SLOT_START; slotid < MANAGER_HANDLE_MAX ; slotid++) {
147 if (g_slots[slotid].status == STATUS_IDLE) {
148 g_slots[slotid].status = STATUS_SOUND;
153 if (slotid < MANAGER_HANDLE_MAX) {
154 debug_msg("New handle allocated (codec slot ID : [%d])", slotid);
159 /* FIXME: avoiding infinite wait is required */
160 debug_warning("Handle is full..wait for a while and will retry...");
164 _mm_sound_mgr_codec_shutdown_timer_stop();
171 static gboolean _mm_sound_mgr_codec_slot_is_empty()
175 for (slotid = SOUND_SLOT_START; slotid < MANAGER_HANDLE_MAX ; slotid++) {
176 if (g_slots[slotid].status == STATUS_SOUND)
180 return (slotid == MANAGER_HANDLE_MAX) ? TRUE : FALSE;
183 static void _mm_sound_mgr_codec_slot_clear(int slotid, bool dump)
185 memset(&g_slots[slotid], 0, sizeof(__mmsound_mgr_codec_handle_t));
186 g_slots[slotid].status = STATUS_IDLE;
189 debug_warning("SlotID [%d] cleared", slotid);
192 int MMSoundMgrCodecInit(const char *targetdir, GSourceFunc _shutdown_cb)
199 memset(g_slots, 0, sizeof(g_slots));
201 if (pthread_mutex_init(&g_slot_mutex, NULL)) {
202 debug_error("pthread_mutex_init failed");
203 return MM_ERROR_SOUND_INTERNAL;
206 for (slotid = 0; slotid < MANAGER_HANDLE_MAX; slotid++)
207 _mm_sound_mgr_codec_slot_clear(slotid, false);
209 if (g_codec_plugins) {
210 debug_warning("Please Check Init twice");
211 MMSoundPluginRelease(g_codec_plugins);
214 MMSoundPluginScan(targetdir, MM_SOUND_PLUGIN_TYPE_CODEC, &g_codec_plugins);
215 if (g_codec_plugins) {
216 while (g_codec_plugins[loop].type != MM_SOUND_PLUGIN_TYPE_NONE)
217 _MMSoundMgrCodecRegisterInterface(&g_codec_plugins[loop++]);
221 g_shutdown_cb = _shutdown_cb;
223 debug_warning("shutdown callback is NULL");
226 return MM_ERROR_NONE;
229 int MMSoundMgrCodecFini(void)
233 memset(g_plugins, 0, sizeof(mmsound_codec_interface_t) * MM_SOUND_SUPPORTED_CODEC_NUM);
234 MMSoundPluginRelease(g_codec_plugins);
235 g_codec_plugins = NULL;
236 pthread_mutex_destroy(&g_slot_mutex);
239 return MM_ERROR_NONE;
242 static int _MMSoundMgrCodecFindCodecPluginID(enum MMSoundSupportedCodec codec_to_find)
247 for (plugin_id = 0; plugin_id < MM_SOUND_SUPPORTED_CODEC_NUM; plugin_id++) {
248 if (g_plugins[plugin_id].GetSupportTypes) {
249 codec_type = g_plugins[plugin_id].GetSupportTypes();
250 if (codec_type[0] == codec_to_find)
258 int MMSoundMgrCodecPlayWithStreamInfo(int *slotid, const mmsound_mgr_codec_param_t *param)
261 mmsound_codec_info_t info;
262 mmsound_codec_param_t codec_param;
263 int err = MM_ERROR_NONE;
268 plugin_id = _MMSoundMgrCodecFindCodecPluginID(MM_SOUND_SUPPORTED_CODEC_WAVE);
269 if (plugin_id == -1) {
270 debug_error("Could not find proper codec plugin!!!");
271 err = MM_ERROR_SOUND_INTERNAL;
275 err = g_plugins[plugin_id].Parse(param->pfilename, &info);
276 if (err != MM_ERROR_NONE) {
277 debug_error("Could not parse file [%s] by plugin[%d]", param->pfilename, plugin_id);
281 err = _mm_sound_mgr_codec_slot_get_empty(slotid);
282 if (err != MM_ERROR_NONE || *slotid < 0) {
283 debug_error("Empty g_slot is not found");
287 codec_param.volume_config = -1; //setting volume config to -1 since using stream info instead of volume type
288 codec_param.repeat_count = param->repeat_count;
289 codec_param.volume = param->volume;
290 codec_param.pfilename = param->pfilename;
291 codec_param.stop_cb = _MMSoundMgrCodecStopCallback;
292 codec_param.param = *slotid;
293 codec_param.pid = (int)param->param;
294 codec_param.stream_index = param->stream_index;
295 MMSOUND_STRNCPY(codec_param.stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
298 /* Codec id WAV or MP3 */
299 g_slots[*slotid].pluginid = plugin_id;
300 g_slots[*slotid].param = param->param; /* This arg is used callback data */
302 debug_msg("Using Slotid : [%d] Slot Status : [%d]", *slotid, g_slots[*slotid].status);
304 err = g_plugins[g_slots[*slotid].pluginid].Create(&codec_param, &info, &(g_slots[*slotid].plughandle));
305 debug_msg("Created audio handle : [%p]", g_slots[*slotid].plughandle);
306 if (err != MM_ERROR_NONE) {
307 debug_error("Plugin create fail : 0x%08X", err);
308 g_slots[*slotid].status = STATUS_IDLE;
313 err = g_plugins[g_slots[*slotid].pluginid].Play(g_slots[*slotid].plughandle);
314 if (err != MM_ERROR_NONE) {
315 debug_error("Fail to play : 0x%08X", err);
316 g_plugins[g_slots[*slotid].pluginid].Destroy(g_slots[*slotid].plughandle);
322 if (_mm_sound_mgr_codec_slot_is_empty())
323 _mm_sound_mgr_codec_shutdown_timer_start();
333 int MMSoundMgrCodecPlayDtmfWithStreamInfo(int *slotid, const mmsound_mgr_codec_param_t *param)
336 mmsound_codec_info_t info;
337 mmsound_codec_param_t codec_param;
338 int err = MM_ERROR_NONE;
343 plugin_id = _MMSoundMgrCodecFindCodecPluginID(MM_SOUND_SUPPORTED_CODEC_DTMF);
344 if (plugin_id == -1) {
345 debug_error("Could not find proper codec plugin!!!");
346 err = MM_ERROR_SOUND_INTERNAL;
350 /*The count num means codec type DTMF */
351 debug_msg("DTMF[%d] Repeat[%d] Volume[%f] plugin_codec[%d]", param->tone, param->repeat_count, param->volume, plugin_id);
353 if (g_plugins[plugin_id].GetSupportTypes == NULL) { /* Codec not found */
354 debug_error("unsupported file type %d", plugin_id);
355 printf("unsupported file type %d", plugin_id);
356 err = MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
361 debug_msg("Get New handle");
364 err = _mm_sound_mgr_codec_slot_get_empty(slotid);
365 if (err != MM_ERROR_NONE || *slotid < 0) {
366 debug_error("Empty g_slot is not found");
370 codec_param.tone = param->tone;
371 codec_param.repeat_count = param->repeat_count;
372 codec_param.volume = param->volume;
373 codec_param.stop_cb = _MMSoundMgrCodecStopCallback;
374 codec_param.param = *slotid;
375 codec_param.pid = (int)param->param;
376 codec_param.volume_config = -1; //setting volume config to -1 since using stream info instead of volume type
377 codec_param.stream_index = param->stream_index;
378 MMSOUND_STRNCPY(codec_param.stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
381 g_slots[*slotid].pluginid = plugin_id;
382 g_slots[*slotid].param = param->param; /* This arg is used callback data */
385 debug_msg("Using Slotid : [%d] Slot Status : [%d]", *slotid, g_slots[*slotid].status);
388 err = g_plugins[g_slots[*slotid].pluginid].Create(&codec_param, &info, &(g_slots[*slotid].plughandle));
389 debug_msg("Created audio handle : [%p]", g_slots[*slotid].plughandle);
390 if (err != MM_ERROR_NONE) {
391 debug_error("Plugin create fail : 0x%08X", err);
392 g_slots[*slotid].status = STATUS_IDLE;
397 err = g_plugins[g_slots[*slotid].pluginid].Play(g_slots[*slotid].plughandle);
398 if (err != MM_ERROR_NONE) {
399 debug_error("Fail to play : 0x%08X", err);
400 g_plugins[g_slots[*slotid].pluginid].Destroy(g_slots[*slotid].plughandle);
404 debug_msg("Using Slotid : [%d] Slot Status : [%d]", *slotid, g_slots[*slotid].status);
415 int MMSoundMgrCodecStop(const int slotid)
417 int err = MM_ERROR_NONE;
419 debug_enter("(Slotid : [%d])", slotid);
421 if (slotid < 0 || MANAGER_HANDLE_MAX <= slotid)
422 return MM_ERROR_INVALID_ARGUMENT;
425 if (g_slots[slotid].status == STATUS_IDLE) {
426 err = MM_ERROR_SOUND_INVALID_STATE;
427 debug_warning("The playing slots is not found, Slot ID : [%d]", slotid);
431 debug_msg("Found slot, Slotid [%d] State [%d]", slotid, g_slots[slotid].status);
434 err = g_plugins[g_slots[slotid].pluginid].Stop(g_slots[slotid].plughandle);
435 if (err != MM_ERROR_NONE)
436 debug_error("Fail to STOP Code : 0x%08X", err);
440 debug_leave("(err : 0x%08X)", err);
445 static int _MMSoundMgrCodecStopCallback(int slotid, bool stop_by_user)
447 int err = MM_ERROR_NONE;
449 if (slotid < 0 || slotid >= MANAGER_HANDLE_MAX) {
450 debug_error("Slot(%d) is invalid", slotid);
451 return MM_ERROR_INVALID_ARGUMENT;
454 debug_enter("Slot(%d) : stop-by-user(%d)", slotid, stop_by_user);
457 /* NOTE : slot is already locked by MMSoundMgrCodecStop() in user stop case */
460 if (g_slots[slotid].pluginid == MM_SOUND_SUPPORTED_CODEC_WAVE)
461 __mm_sound_mgr_ipc_notify_play_file_end(slotid);
463 debug_msg("Client callback msg_type (instance) : [%d]", (int)g_slots[slotid].param);
466 debug_msg("Handle allocated handle : [%p]", g_slots[slotid].plughandle);
467 err = g_plugins[g_slots[slotid].pluginid].Destroy(g_slots[slotid].plughandle);
469 debug_critical("Slot(%d) : Fail to destroy slot, err [0x%x]", slotid, err);
471 _mm_sound_mgr_codec_slot_clear(slotid, true);
472 if (_mm_sound_mgr_codec_slot_is_empty())
473 _mm_sound_mgr_codec_shutdown_timer_start();
485 static int _MMSoundMgrCodecRegisterInterface(MMSoundPluginType *plugin)
487 int err = MM_ERROR_NONE;
489 void *getinterface = NULL;
495 /* find emptry slot */
496 for (plugin_id = 0; plugin_id < MM_SOUND_SUPPORTED_CODEC_NUM; plugin_id++) {
497 if (g_plugins[plugin_id].GetSupportTypes == NULL)
501 if (plugin_id == MM_SOUND_SUPPORTED_CODEC_NUM) {
502 debug_critical("The plugin support type is not valid");
503 return MM_ERROR_COMMON_OUT_OF_RANGE;
506 err = MMSoundPluginGetSymbol(plugin, CODEC_GET_INTERFACE_FUNC_NAME, &getinterface);
507 if (err != MM_ERROR_NONE) {
508 debug_error("Get Symbol CODEC_GET_INTERFACE_FUNC_NAME is fail : %x", err);
511 debug_msg("interface[%p] empty_slot[%d]", getinterface, plugin_id);
513 err = MMSoundPlugCodecCastGetInterface(getinterface)(&g_plugins[plugin_id]);
514 if (err != MM_ERROR_NONE) {
515 debug_error("Get interface fail : %x", err);
518 /* If error occur, clean interface */
519 memset(&g_plugins[plugin_id], 0, sizeof(mmsound_codec_interface_t));
521 if (g_plugins[plugin_id].SetThreadPool)
522 g_plugins[plugin_id].SetThreadPool(MMSoundThreadPoolRun);