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;
71 #define SLOT_LOCK() do { \
72 debug_msg("Before Slot_mutex LOCK"); \
73 pthread_mutex_lock(&g_slot_mutex); \
74 debug_msg("After Slot_mutex LOCK"); \
76 #define SLOT_UNLOCK() do { \
77 debug_msg("Before Slot_mutex UNLOCK"); \
78 pthread_mutex_unlock(&g_slot_mutex); \
79 debug_msg("After Slot_mutex UNLOCK"); \
82 #define SLOT_LOCK() do { pthread_mutex_lock(&g_slot_mutex); } while (0)
83 #define SLOT_UNLOCK() do { pthread_mutex_unlock(&g_slot_mutex); } while (0)
86 static int _MMSoundMgrCodecRegisterInterface(MMSoundPluginType *plugin);
87 static int _MMSoundMgrCodecStopCallback(int param);
88 static gboolean _mm_sound_mgr_codec_slot_is_empty();
90 static gboolean _idle_cb(gpointer user_data)
92 if (_mm_sound_mgr_codec_slot_is_empty()) {
93 debug_msg("slot is empty, ready to shutdown! %p", g_shutdown_cb);
97 debug_warning("slot is not empty!!! no shutdown...");
103 static gboolean _timeout_cb(gpointer user_data)
105 debug_warning("TIMEOUT : add idle callback now...");
107 g_idle_add(_idle_cb, NULL);
114 /* FIXME : critical section for g_timer_id? */
115 static void _mm_sound_mgr_codec_shutdown_timer_start()
117 if (g_timer_id > 0) {
118 debug_error("Already active timer [%d] exists", g_timer_id);
122 g_timer_id = g_timeout_add_seconds(SHUTDOWN_TIMEOUT_SEC, _timeout_cb, NULL);
123 debug_warning("TIMER : new timer [%d]", g_timer_id);
125 debug_warning("No Timer started due to invalid shutdown callback");
129 static void _mm_sound_mgr_codec_shutdown_timer_stop()
131 if (g_timer_id > 0) {
132 debug_warning("TIMER : remove timer id [%d]", g_timer_id);
133 g_source_remove(g_timer_id);
136 debug_log("No Timer to stop...");
140 static int _mm_sound_mgr_codec_slot_get_empty(int *slot)
143 int err = MM_ERROR_NONE;
148 for (slotid = SOUND_SLOT_START; slotid < MANAGER_HANDLE_MAX ; slotid++) {
149 if (g_slots[slotid].status == STATUS_IDLE) {
150 g_slots[slotid].status = STATUS_SOUND;
155 if (slotid < MANAGER_HANDLE_MAX) {
156 debug_msg("New handle allocated (codec slot ID : [%d])", slotid);
161 /* FIXME: avoiding infinite wait is required */
162 debug_warning("Handle is full..wait for a while and will retry...");
166 _mm_sound_mgr_codec_shutdown_timer_stop();
173 static gboolean _mm_sound_mgr_codec_slot_is_empty()
177 for (slotid = SOUND_SLOT_START; slotid < MANAGER_HANDLE_MAX ; slotid++) {
178 if (g_slots[slotid].status == STATUS_SOUND)
182 return (slotid == MANAGER_HANDLE_MAX) ? TRUE : FALSE;
185 static void _mm_sound_mgr_codec_slot_clear(int slotid, bool dump)
187 memset(&g_slots[slotid], 0, sizeof(__mmsound_mgr_codec_handle_t));
188 g_slots[slotid].status = STATUS_IDLE;
191 debug_warning("SlotID [%d] cleared", slotid);
194 int MMSoundMgrCodecInit(const char *targetdir, GSourceFunc _shutdown_cb)
201 memset(g_slots, 0, sizeof(g_slots));
203 if (pthread_mutex_init(&g_slot_mutex, NULL)) {
204 debug_error("pthread_mutex_init failed");
205 return MM_ERROR_SOUND_INTERNAL;
208 for (slotid = 0; slotid < MANAGER_HANDLE_MAX; slotid++)
209 _mm_sound_mgr_codec_slot_clear(slotid, false);
211 if (g_codec_plugins) {
212 debug_warning("Please Check Init twice");
213 MMSoundPluginRelease(g_codec_plugins);
216 MMSoundPluginScan(targetdir, MM_SOUND_PLUGIN_TYPE_CODEC, &g_codec_plugins);
217 if (g_codec_plugins) {
218 while (g_codec_plugins[loop].type != MM_SOUND_PLUGIN_TYPE_NONE)
219 _MMSoundMgrCodecRegisterInterface(&g_codec_plugins[loop++]);
223 g_shutdown_cb = _shutdown_cb;
225 debug_warning("shutdown callback is NULL");
228 return MM_ERROR_NONE;
231 int MMSoundMgrCodecFini(void)
235 memset(g_plugins, 0, sizeof(mmsound_codec_interface_t) * MM_SOUND_SUPPORTED_CODEC_NUM);
236 MMSoundPluginRelease(g_codec_plugins);
237 g_codec_plugins = NULL;
238 pthread_mutex_destroy(&g_slot_mutex);
241 return MM_ERROR_NONE;
244 static int _MMSoundMgrCodecFindCodecPluginID(enum MMSoundSupportedCodec codec_to_find)
249 for (plugin_id = 0; plugin_id < MM_SOUND_SUPPORTED_CODEC_NUM; plugin_id++) {
250 if (g_plugins[plugin_id].GetSupportTypes) {
251 codec_type = g_plugins[plugin_id].GetSupportTypes();
252 if (codec_type[0] == codec_to_find)
260 int MMSoundMgrCodecPlayWithStreamInfo(int *slotid, const mmsound_mgr_codec_param_t *param)
263 mmsound_codec_info_t info;
264 mmsound_codec_param_t codec_param;
265 int err = MM_ERROR_NONE;
270 plugin_id = _MMSoundMgrCodecFindCodecPluginID(MM_SOUND_SUPPORTED_CODEC_WAVE);
271 if (plugin_id == -1) {
272 debug_error("Could not find proper codec plugin!!!");
273 err = MM_ERROR_SOUND_INTERNAL;
277 err = g_plugins[plugin_id].Parse(param->pfilename, &info);
278 if (err != MM_ERROR_NONE) {
279 debug_error("Could not parse file [%s] by plugin[%d]", param->pfilename, plugin_id);
283 err = _mm_sound_mgr_codec_slot_get_empty(slotid);
284 if (err != MM_ERROR_NONE || *slotid < 0) {
285 debug_error("Empty g_slot is not found");
289 codec_param.volume_config = -1; //setting volume config to -1 since using stream info instead of volume type
290 codec_param.repeat_count = param->repeat_count;
291 codec_param.volume = param->volume;
292 codec_param.pfilename = param->pfilename;
293 codec_param.stop_cb = _MMSoundMgrCodecStopCallback;
294 codec_param.param = *slotid;
295 codec_param.pid = (int)param->param;
296 codec_param.stream_index = param->stream_index;
297 MMSOUND_STRNCPY(codec_param.stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
300 /* Codec id WAV or MP3 */
301 g_slots[*slotid].pluginid = plugin_id;
302 g_slots[*slotid].param = param->param; /* This arg is used callback data */
304 debug_msg("Using Slotid : [%d] Slot Status : [%d]", *slotid, g_slots[*slotid].status);
306 err = g_plugins[g_slots[*slotid].pluginid].Create(&codec_param, &info, &(g_slots[*slotid].plughandle));
307 debug_msg("Created audio handle : [%p]", g_slots[*slotid].plughandle);
308 if (err != MM_ERROR_NONE) {
309 debug_error("Plugin create fail : 0x%08X", err);
310 g_slots[*slotid].status = STATUS_IDLE;
315 err = g_plugins[g_slots[*slotid].pluginid].Play(g_slots[*slotid].plughandle);
316 if (err != MM_ERROR_NONE) {
317 debug_error("Fail to play : 0x%08X", err);
318 g_plugins[g_slots[*slotid].pluginid].Destroy(g_slots[*slotid].plughandle);
324 if (_mm_sound_mgr_codec_slot_is_empty())
325 _mm_sound_mgr_codec_shutdown_timer_start();
335 int MMSoundMgrCodecPlayDtmfWithStreamInfo(int *slotid, const mmsound_mgr_codec_param_t *param)
338 mmsound_codec_info_t info;
339 mmsound_codec_param_t codec_param;
340 int err = MM_ERROR_NONE;
345 plugin_id = _MMSoundMgrCodecFindCodecPluginID(MM_SOUND_SUPPORTED_CODEC_DTMF);
346 if (plugin_id == -1) {
347 debug_error("Could not find proper codec plugin!!!");
348 err = MM_ERROR_SOUND_INTERNAL;
352 /*The count num means codec type DTMF */
353 debug_msg("DTMF[%d] Repeat[%d] Volume[%f] plugin_codec[%d]", param->tone, param->repeat_count, param->volume, plugin_id);
355 if (g_plugins[plugin_id].GetSupportTypes == NULL) { /* Codec not found */
356 debug_error("unsupported file type %d", plugin_id);
357 printf("unsupported file type %d", plugin_id);
358 err = MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
363 debug_msg("Get New handle");
366 err = _mm_sound_mgr_codec_slot_get_empty(slotid);
367 if (err != MM_ERROR_NONE || *slotid < 0) {
368 debug_error("Empty g_slot is not found");
372 codec_param.tone = param->tone;
373 codec_param.repeat_count = param->repeat_count;
374 codec_param.volume = param->volume;
375 codec_param.stop_cb = _MMSoundMgrCodecStopCallback;
376 codec_param.param = *slotid;
377 codec_param.pid = (int)param->param;
378 codec_param.volume_config = -1; //setting volume config to -1 since using stream info instead of volume type
379 codec_param.stream_index = param->stream_index;
380 MMSOUND_STRNCPY(codec_param.stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
383 g_slots[*slotid].pluginid = plugin_id;
384 g_slots[*slotid].param = param->param; /* This arg is used callback data */
387 debug_msg("Using Slotid : [%d] Slot Status : [%d]", *slotid, g_slots[*slotid].status);
390 err = g_plugins[g_slots[*slotid].pluginid].Create(&codec_param, &info, &(g_slots[*slotid].plughandle));
391 debug_msg("Created audio handle : [%p]", g_slots[*slotid].plughandle);
392 if (err != MM_ERROR_NONE) {
393 debug_error("Plugin create fail : 0x%08X", err);
394 g_slots[*slotid].status = STATUS_IDLE;
399 err = g_plugins[g_slots[*slotid].pluginid].Play(g_slots[*slotid].plughandle);
400 if (err != MM_ERROR_NONE) {
401 debug_error("Fail to play : 0x%08X", err);
402 g_plugins[g_slots[*slotid].pluginid].Destroy(g_slots[*slotid].plughandle);
406 debug_msg("Using Slotid : [%d] Slot Status : [%d]", *slotid, g_slots[*slotid].status);
417 int MMSoundMgrCodecStop(const int slotid)
419 int err = MM_ERROR_NONE;
421 debug_enter("(Slotid : [%d])", slotid);
423 if (slotid < 0 || MANAGER_HANDLE_MAX <= slotid)
424 return MM_ERROR_INVALID_ARGUMENT;
427 if (g_slots[slotid].status == STATUS_IDLE) {
428 err = MM_ERROR_SOUND_INVALID_STATE;
429 debug_warning("The playing slots is not found, Slot ID : [%d]", slotid);
433 debug_msg("Found slot, Slotid [%d] State [%d]", slotid, g_slots[slotid].status);
436 g_slots[slotid].stop_by_user = true;
438 err = g_plugins[g_slots[slotid].pluginid].Stop(g_slots[slotid].plughandle);
439 if (err != MM_ERROR_NONE)
440 debug_error("Fail to STOP Code : 0x%08X", err);
444 debug_leave("(err : 0x%08X)", err);
449 static int _MMSoundMgrCodecStopCallback(int param)
451 int err = MM_ERROR_NONE;
453 if (param < 0 || param >= MANAGER_HANDLE_MAX) {
454 debug_error("Slot(%d) is invalid", param);
455 return MM_ERROR_INVALID_ARGUMENT;
458 debug_enter("Slot(%d) : stop-by-user(%d)", param, g_slots[param].stop_by_user);
460 if (!g_slots[param].stop_by_user) {
462 __mm_sound_mgr_ipc_notify_play_file_end(param);
463 debug_msg("Client callback msg_type (instance) : [%d]", (int)g_slots[param].param);
466 debug_msg("Handle allocated handle : [%p]", g_slots[param].plughandle);
467 err = g_plugins[g_slots[param].pluginid].Destroy(g_slots[param].plughandle);
469 debug_critical("Slot(%d) : Fail to destroy slot, err [0x%x]", param, err);
471 _mm_sound_mgr_codec_slot_clear(param, true);
472 if (_mm_sound_mgr_codec_slot_is_empty())
473 _mm_sound_mgr_codec_shutdown_timer_start();
475 if (!g_slots[param].stop_by_user)
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);