4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Seungbae Shin <seungbae.shin@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
26 #include <semaphore.h>
31 #include <tremolo_vorbisdec_api.h>
33 #include "../../include/mm_sound.h"
34 #include "../../include/mm_sound_plugin_codec.h"
35 #include "../../../include/mm_sound_pa_client.h"
37 #define OGG_DEC_BUF_SIZE 4096
38 #define OGG_FILE_SAMPLE_PLAY_DURATION 290
40 #define TIME_MSEC (1000)
41 #define SILENT_SND_MIN_VALUE (90)
42 #define CODEC_OGG_LOCK(LOCK) do { pthread_mutex_lock(LOCK); } while (0)
43 #define CODEC_OGG_UNLOCK(LOCK) do { pthread_mutex_unlock(LOCK); } while (0)
45 int MMSoundPlugCodecOggStop(MMHandleType handle);
58 sem_t start_wave_signal; /* control start of pcm write thread */
59 sem_t start_ogg_signal; /* control start of ogg decord thread*/
60 pthread_mutex_t mutex;
62 /* Codec infomations */
67 int gain, out, in, option;
68 mm_sound_device_in device_in;
69 mm_sound_device_out device_out;
70 unsigned int volume_value;
72 /* Audio Infomations */
73 int transper_size; /* audio open return */
76 /* control Informations */
84 int SamplingFrequency;
91 static int (*g_thread_pool_func)(void*, void (*)(void*)) = NULL;
93 static void _reset_ogg_decoder(ogg_info_t *p)
95 int err, used_size, skipsize;
96 OGG_DEC_INFO ogg_info;
98 err = OGGDEC_ResetDecode(p->decoder);
99 if (err != OGGDEC_SUCCESS) {
100 debug_error("Failed to RESET decoder!");
104 err = OGGDEC_InitDecode(p->decoder, (unsigned char*)p->source->ptr, p->BufferSize, &skipsize);
105 if (err != OGGDEC_SUCCESS) {
106 debug_error("Failed to INIT decoder!");
110 err = OGGDEC_InfoDecode(p->decoder, p->source->ptr + skipsize, &used_size, &ogg_info);
111 if (err != OGGDEC_SUCCESS) {
112 debug_error("Failed to INFO decoder!");
117 void _pcm_out_func(void *data)
119 ogg_info_t *p = (ogg_info_t *)data;
122 unsigned char* ogg_buf = NULL;
128 debug_error("Invalid ogg_info_t...");
132 sem_wait(&p->start_wave_signal);
134 while (((p->repeat_count == -1) ? (1) : (p->repeat_count--)) && p->state == STATE_PLAY) {
135 ogg_buf = MMSourceGetPtr(p->source) + p->offset;
137 while (p->state == STATE_PLAY) {
139 err = OGGDEC_FrameDecode(p->decoder, ogg_buf, &used_size, p->pcm_out_buf, &decoded_len);
140 if (decoded_len <= 0) {
141 debug_error("decoded len = %d", decoded_len);
145 mm_sound_pa_write(p->handle, p->pcm_out_buf, decoded_len);
146 ogg_buf += used_size;
148 if (err != OGGDEC_SUCCESS)
152 debug_error("decode done = [%d], repeat_count = [%d]", err, p->repeat_count);
153 if (err == OGGDEC_FAIL || p->repeat_count == 0)
154 MMSoundPlugCodecOggStop((MMHandleType)p);
156 _reset_ogg_decoder(p);
159 mm_sound_pa_drain(p->handle);
160 mm_sound_pa_close(p->handle);
163 /* OggDestory is called by stop_cb func */
164 /* INDEED the stop_cb must be called, after end of all progress */
166 p->stop_cb(p->cb_param);
171 int MMSoundPlugCodecOggSetThreadPool(int (*func)(void*, void (*)(void*)))
173 debug_enter("(func : %p)\n", func);
174 g_thread_pool_func = func;
176 return MM_ERROR_NONE;
179 int* MMSoundPlugCodecOggGetSupportTypes(void)
182 static int suported[2] = {MM_SOUND_SUPPORTED_CODEC_OGG, 0};
187 int MMSoundPlugCodecOggParse(MMSourceType *source, mmsound_codec_info_t *info)
189 unsigned char *ptr = NULL;
190 unsigned int size = 0;
192 OGG_DEC_INFO ogg_info;
196 ptr = (unsigned char*)MMSourceGetPtr(source);
197 size = MMSourceGetCurSize(source);
198 debug_msg("[CODEC OGG] source ptr :[0x%08X] ::: source size :[0x%d]\n", ptr, size);
200 err = OGGDEC_PreparseDecode(ptr, size, &ogg_info);
201 if (err != OGGDEC_SUCCESS) {
202 debug_error("Not valid Ogg data format");
203 return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
207 info->channels = ogg_info.channels;
208 info->samplerate = ogg_info.samplerate;
209 info->duration = ogg_info.duration;
210 info->codec = MM_AUDIO_CODEC_OGG;
211 debug_msg("[CODEC OGG]Channels %d Samplerate %d\n", ogg_info.channels, ogg_info.samplerate);
214 return MM_ERROR_NONE;
217 int MMSoundPlugCodecOggCreate(mmsound_codec_param_t *param, mmsound_codec_info_t *info, MMHandleType *handle)
219 ogg_info_t* p = NULL;
220 MMSourceType *source = NULL;
221 OGG_DEC_INFO ogg_info;
222 int err, used_size, skipsize;
223 int ret = MM_ERROR_NONE;
227 int mode = HANDLE_MODE_OUTPUT_LOW_LATENCY;
231 if (g_thread_pool_func == NULL) {
232 debug_error("Need thread pool!\n");
233 return MM_ERROR_SOUND_INTERNAL;
236 source = param->source;
237 debug_msg("[CODEC OGG]Param source p 0x08%X\n", param->source);
239 p = (ogg_info_t *) malloc(sizeof(ogg_info_t));
241 debug_error("[CODEC OGG]Memory allocation Fail\n");
242 return MM_ERROR_OUT_OF_MEMORY;
245 memset(p, 0, sizeof(ogg_info_t));
246 p->source = param->source;
247 p->BufferSize = MMSourceGetCurSize(source);
249 pthread_mutex_init(&p->mutex, NULL);
251 err = sem_init(&p->start_ogg_signal, 0, 0);
253 debug_error("[CODEC OGG]Semaphore init fail\n");
254 ret = MM_ERROR_SOUND_INTERNAL;
255 goto error_before_create;
258 err = sem_init(&p->start_wave_signal, 0, 0);
260 debug_error("[CODEC OGG]Semaphore init fail\n");
261 sem_destroy(&p->start_ogg_signal);
262 ret = MM_ERROR_SOUND_INTERNAL;
263 goto error_before_create;
266 err = OGGDEC_CreateDecode(&p->decoder);
267 if (err != OGGDEC_SUCCESS) {
268 debug_error("[CODEC OGG]Fail to Create ogg decoder\n");
269 ret = MM_ERROR_SOUND_INTERNAL;
270 goto error_before_create;
272 p->pcm_out_buf = (char *)malloc(sizeof(char)*OGG_DEC_BUF_SIZE);
273 if (p->pcm_out_buf == NULL) {
274 debug_error("[CODEC OGG]Memory allocation fail\n");
275 ret = MM_ERROR_SOUND_NO_FREE_SPACE;
276 goto error_after_create;
278 err = OGGDEC_InitDecode(p->decoder, (unsigned char*)p->source->ptr, p->BufferSize, &skipsize);
279 if (err != OGGDEC_SUCCESS) {
280 debug_error("Fail to init ogg decoder\n");
281 ret = MM_ERROR_SOUND_INTERNAL;
282 goto error_after_buffer;
284 p->offset = skipsize;
286 err = OGGDEC_InfoDecode(p->decoder, p->source->ptr+p->offset, &used_size, &ogg_info);
287 if (err != OGGDEC_SUCCESS) {
288 debug_error("[CODEC OGG]Fail to get ogg info\n");
289 ret = MM_ERROR_SOUND_INTERNAL;
290 goto error_after_buffer;
292 p->offset += used_size;
293 p->Duration = info->duration;
294 p->format = info->format = 16;
295 info->channels = ogg_info.channels;
296 info->samplerate = ogg_info.samplerate;
298 /* Temporal code for debug */
300 debug_msg("([CODEC OGG]handle %x)\n", p);
301 debug_msg("[CODEC OGG]Type %s\n", info->codec == MM_AUDIO_CODEC_OGG ? "OGG" : "Unknown");
302 debug_msg("[CODEC OGG]channels : %d\n", info->channels);
303 debug_msg("[CODEC OGG]format : %d\n", info->format);
304 debug_msg("[CODEC OGG]samplerate : %d\n", info->samplerate);
305 debug_msg("[CODEC OGG]doffset : %d\n", info->doffset);
306 debug_msg("[CODEC OGG]repeat : %d\n", param->repeat_count);
307 debug_msg("[CODEC OGG]volume : %d\n", param->volume);
308 debug_msg("[CODEC OGG]callback : %08x\n", param->stop_cb);
310 debug_msg("Audio duration [%d]", info->duration);
311 p->repeat_count = param ->repeat_count;
312 p->stop_cb = param->stop_cb;
313 p->cb_param = param->param;
315 if(info->duration < OGG_FILE_SAMPLE_PLAY_DURATION) {
316 mode = HANDLE_MODE_OUTPUT_LOW_LATENCY;
318 mode = HANDLE_MODE_OUTPUT;
324 ss.format = PA_SAMPLE_U8;
327 ss.format = PA_SAMPLE_S16LE;
330 ss.format = PA_SAMPLE_S16LE;
333 ss.channels = info->channels;
334 ss.rate = info->samplerate;
336 debug_msg("[CODEC OGG] PARAM mode:[%d] channels:[%d] samplerate:[%d] format:[%d] volume type:[%x]\n",
337 mode, ss.channels, ss.rate, ss.format, param->volume_config);
339 p->handle = mm_sound_pa_open(HANDLE_MODE_OUTPUT_LOW_LATENCY, param->volume_config, &ss, NULL, &size, param->stream_type, param->stream_index);
341 debug_error("[CODEC OGG] Can not open audio handle\n");
342 ret = MM_ERROR_SOUND_INTERNAL;
343 goto error_after_buffer;
346 pthread_mutex_lock(&p->mutex);
347 p->state = STATE_READY;
348 pthread_mutex_unlock(&p->mutex);
351 err = g_thread_pool_func(p, _pcm_out_func);
353 debug_error("[CODEC OGG]pthread_create() fail in pcm thread\n");
354 ret = MM_ERROR_SOUND_INTERNAL;
355 goto error_after_buffer;
359 return MM_ERROR_NONE;
362 free(p->pcm_out_buf);
365 sem_destroy(&p->start_ogg_signal);
366 sem_destroy(&p->start_wave_signal);
367 OGGDEC_ResetDecode(p->decoder);
368 OGGDEC_DeleteDecode(p->decoder);
375 int MMSoundPlugCodecOggPlay(MMHandleType handle)
377 ogg_info_t *p = (ogg_info_t *) handle;
378 debug_enter("(handle %x)\n", handle);
380 if (p->BufferSize <= 0) {
381 debug_error("[CODEC OGG]End of file\n");
382 return MM_ERROR_END_OF_FILE;
384 pthread_mutex_lock(&p->mutex);
385 p->state = STATE_PLAY;
386 pthread_mutex_unlock(&p->mutex);
387 sem_post(&p->start_wave_signal);
390 return MM_ERROR_NONE;
393 int MMSoundPlugCodecOggStop(MMHandleType handle)
395 ogg_info_t *p = (ogg_info_t *) handle;
396 debug_enter("(handle %x)\n", handle);
397 pthread_mutex_lock(&p->mutex);
398 p->state = STATE_STOP;
399 pthread_mutex_unlock(&p->mutex);
402 return MM_ERROR_NONE;
405 int MMSoundPlugCodecOggDestroy(MMHandleType handle)
407 ogg_info_t *p = (ogg_info_t*) handle;
410 debug_enter("(handle %x)\n", handle);
413 debug_critical("Confirm the hadle (is NULL)\n");
414 err = MM_ERROR_SOUND_INTERNAL;
419 mm_source_close(p->source);
420 free(p->source); p->source = NULL;
423 err = OGGDEC_ResetDecode(p->decoder);
424 if (err != OGGDEC_SUCCESS) {
425 debug_error("[CODEC OGG]Codec Reset fail\n");
426 err = MM_ERROR_SOUND_INTERNAL;
429 err = OGGDEC_DeleteDecode(p->decoder);
430 if (err != OGGDEC_SUCCESS) {
431 debug_error("[CODEC OGG]Delete Decode fail\n");
432 err = MM_ERROR_SOUND_INTERNAL;
435 sem_destroy(&p->start_wave_signal);
436 sem_destroy(&p->start_ogg_signal);
439 free(p->pcm_out_buf);
440 p->pcm_out_buf = NULL;
453 int MMSoundGetPluginType(void)
457 return MM_SOUND_PLUGIN_TYPE_CODEC;
461 int MMSoundPlugCodecGetInterface(mmsound_codec_interface_t *intf)
465 debug_critical("Confirm the codec interface struct (is NULL)\n");
466 return MM_ERROR_SOUND_INTERNAL;
469 intf->GetSupportTypes = MMSoundPlugCodecOggGetSupportTypes;
470 intf->Parse = MMSoundPlugCodecOggParse;
471 intf->Create = MMSoundPlugCodecOggCreate;
472 intf->Destroy = MMSoundPlugCodecOggDestroy;
473 intf->Play = MMSoundPlugCodecOggPlay;
474 intf->Stop = MMSoundPlugCodecOggStop;
475 intf->SetThreadPool = MMSoundPlugCodecOggSetThreadPool;
478 return MM_ERROR_NONE;