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 */
68 int gain, out, in, option;
69 mm_sound_device_in device_in;
70 mm_sound_device_out device_out;
71 unsigned int volume_value;
73 /* Audio Infomations */
74 int transper_size; /* audio open return */
77 /* control Informations */
85 int SamplingFrequency;
92 static int (*g_thread_pool_func)(void*, void (*)(void*)) = NULL;
94 void _pcm_out_func(void *data)
96 ogg_info_t *p = (ogg_info_t*) data;
99 unsigned char* ogg_buf;
100 unsigned int ogg_remain;
105 sem_wait(&p->start_wave_signal);
106 ogg_buf = MMSourceGetPtr(p->source);
107 ogg_remain = MMSourceGetCurSize(p->source);
109 while (p->state == STATE_PLAY) {
110 err = OGGDEC_FrameDecode(p->decoder, ogg_buf+p->offset, &used_size, p->pcm_out_buf, &decoded_len);
111 if (decoded_len > 0) {
112 mm_sound_pa_write(p->handle, p->pcm_out_buf, decoded_len);
113 ogg_buf += used_size;
114 ogg_remain -= used_size;
115 if(err != OGGDEC_SUCCESS) {
116 MMSoundPlugCodecOggStop((MMHandleType)p);
117 debug_error("Decode done :: %d\n", err);
121 MMSoundPlugCodecOggStop((MMHandleType)p);
126 mm_sound_pa_drain(p->handle);
127 mm_sound_pa_close(p->handle);
130 /* OggDestory is called by stop_cb func */
131 /* INDEED the stop_cb must be called, after end of all progress */
133 p->stop_cb(p->cb_param);
138 int MMSoundPlugCodecOggSetThreadPool(int (*func)(void*, void (*)(void*)))
140 debug_enter("(func : %p)\n", func);
141 g_thread_pool_func = func;
143 return MM_ERROR_NONE;
146 int* MMSoundPlugCodecOggGetSupportTypes(void)
149 static int suported[2] = {MM_SOUND_SUPPORTED_CODEC_OGG, 0};
154 int MMSoundPlugCodecOggParse(MMSourceType *source, mmsound_codec_info_t *info)
156 unsigned char *ptr = NULL;
157 unsigned int size = 0;
159 OGG_DEC_INFO ogg_info;
163 ptr = (unsigned char*)MMSourceGetPtr(source);
164 size = MMSourceGetCurSize(source);
165 debug_msg("[CODEC OGG] source ptr :[0x%08X] ::: source size :[0x%d]\n", ptr, size);
167 err = OGGDEC_PreparseDecode(ptr, size, &ogg_info);
168 if (err != OGGDEC_SUCCESS) {
169 debug_error("Not valid Ogg data format");
170 return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
174 info->channels = ogg_info.channels;
175 info->samplerate = ogg_info.samplerate;
176 info->duration = ogg_info.duration;
177 info->codec = MM_AUDIO_CODEC_OGG;
178 debug_msg("[CODEC OGG]Channels %d Samplerate %d\n", ogg_info.channels, ogg_info.samplerate);
181 return MM_ERROR_NONE;
184 int MMSoundPlugCodecOggCreate(mmsound_codec_param_t *param, mmsound_codec_info_t *info, MMHandleType *handle)
186 ogg_info_t* p = NULL;
187 MMSourceType *source = NULL;
188 OGG_DEC_INFO ogg_info;
189 int err, used_size, skipsize;
190 int ret = MM_ERROR_NONE;
192 mm_sound_handle_route_info route_info;
193 route_info.policy = HANDLE_ROUTE_POLICY_OUT_AUTO;
197 int mode = HANDLE_MODE_OUTPUT_LOW_LATENCY;
201 if (g_thread_pool_func == NULL) {
202 debug_error("Need thread pool!\n");
203 return MM_ERROR_SOUND_INTERNAL;
206 source = param->source;
207 debug_msg("[CODEC OGG]Param source p 0x08%X\n", param->source);
209 p = (ogg_info_t *) malloc(sizeof(ogg_info_t));
211 debug_error("[CODEC OGG]Memory allocation Fail\n");
212 return MM_ERROR_OUT_OF_MEMORY;
215 memset(p, 0, sizeof(ogg_info_t));
216 p->source = param->source;
217 p->BufferSize = MMSourceGetCurSize(source);
219 pthread_mutex_init(&p->mutex, NULL);
221 err = sem_init(&p->start_ogg_signal, 0, 0);
223 debug_error("[CODEC OGG]Semaphore init fail\n");
224 ret = MM_ERROR_SOUND_INTERNAL;
225 goto error_before_create;
228 err = sem_init(&p->start_wave_signal, 0, 0);
230 debug_error("[CODEC OGG]Semaphore init fail\n");
231 sem_destroy(&p->start_ogg_signal);
232 ret = MM_ERROR_SOUND_INTERNAL;
233 goto error_before_create;
236 err = OGGDEC_CreateDecode(&p->decoder);
237 if (err != OGGDEC_SUCCESS) {
238 debug_error("[CODEC OGG]Fail to Create ogg decoder\n");
239 ret = MM_ERROR_SOUND_INTERNAL;
240 goto error_before_create;
242 p->pcm_out_buf = (char *)malloc(sizeof(char)*OGG_DEC_BUF_SIZE);
243 if (p->pcm_out_buf == NULL) {
244 debug_error("[CODEC OGG]Memory allocation fail\n");
245 ret = MM_ERROR_SOUND_NO_FREE_SPACE;
246 goto error_after_create;
248 err = OGGDEC_InitDecode(p->decoder, (unsigned char*)p->source->ptr, p->BufferSize, &skipsize);
249 if (err != OGGDEC_SUCCESS) {
250 debug_error("Fail to init ogg decoder\n");
251 ret = MM_ERROR_SOUND_INTERNAL;
252 goto error_after_buffer;
254 p->offset = skipsize;
256 err = OGGDEC_InfoDecode(p->decoder, p->source->ptr+p->offset, &used_size, &ogg_info);
257 if (err != OGGDEC_SUCCESS) {
258 debug_error("[CODEC OGG]Fail to get ogg info\n");
259 ret = MM_ERROR_SOUND_INTERNAL;
260 goto error_after_buffer;
262 p->offset += used_size;
263 p->Duration = info->duration;
264 p->format = info->format = 16;
265 info->channels = ogg_info.channels;
266 info->samplerate = ogg_info.samplerate;
268 /* Temporal code for debug */
270 debug_msg("([CODEC OGG]handle %x)\n", p);
271 debug_msg("[CODEC OGG]Type %s\n", info->codec == MM_AUDIO_CODEC_OGG ? "OGG" : "Unknown");
272 debug_msg("[CODEC OGG]channels : %d\n", info->channels);
273 debug_msg("[CODEC OGG]format : %d\n", info->format);
274 debug_msg("[CODEC OGG]samplerate : %d\n", info->samplerate);
275 debug_msg("[CODEC OGG]doffset : %d\n", info->doffset);
276 debug_msg("[CODEC OGG]priority : %d\n", param->priority);
277 debug_msg("[CODEC OGG]repeat : %d\n", param->repeat_count);
278 debug_msg("[CODEC OGG]volume : %d\n", param->volume);
279 debug_msg("[CODEC OGG]callback : %08x\n", param->stop_cb);
281 debug_msg("Audio duration [%d]", info->duration);
282 p->repeat_count = param ->repeat_count;
283 p->stop_cb = param->stop_cb;
284 p->cb_param = param->param;
286 if(info->duration < OGG_FILE_SAMPLE_PLAY_DURATION) {
287 mode = HANDLE_MODE_OUTPUT_LOW_LATENCY;
289 mode = HANDLE_MODE_OUTPUT;
292 route_info.policy = HANDLE_ROUTE_POLICY_OUT_AUTO;
294 p->handle_route = param->handle_route;
299 ss.format = PA_SAMPLE_U8;
302 ss.format = PA_SAMPLE_S16LE;
305 ss.format = PA_SAMPLE_S16LE;
308 ss.channels = info->channels;
309 ss.rate = info->samplerate;
311 debug_msg("[CODEC OGG] PARAM mode:[%d] priority:[%d] policy:[%d] channels:[%d] samplerate:[%d] format:[%d] volume type:[%x]\n",
312 mode,-1, route_info.policy, ss.channels, ss.rate, ss.format, param->volume_config);
314 p->handle = mm_sound_pa_open(HANDLE_MODE_OUTPUT_LOW_LATENCY, &route_info, 0, param->volume_config, &ss, NULL, &size, param->stream_type, param->stream_index);
316 debug_error("[CODEC OGG] Can not open audio handle\n");
317 ret = MM_ERROR_SOUND_INTERNAL;
318 goto error_after_buffer;
321 pthread_mutex_lock(&p->mutex);
322 p->state = STATE_READY;
323 pthread_mutex_unlock(&p->mutex);
326 err = g_thread_pool_func(p, _pcm_out_func);
328 debug_error("[CODEC OGG]pthread_create() fail in pcm thread\n");
329 ret = MM_ERROR_SOUND_INTERNAL;
330 goto error_after_buffer;
334 return MM_ERROR_NONE;
337 free(p->pcm_out_buf);
340 sem_destroy(&p->start_ogg_signal);
341 sem_destroy(&p->start_wave_signal);
342 OGGDEC_ResetDecode(p->decoder);
343 OGGDEC_DeleteDecode(p->decoder);
350 int MMSoundPlugCodecOggPlay(MMHandleType handle)
352 ogg_info_t *p = (ogg_info_t *) handle;
353 debug_enter("(handle %x)\n", handle);
355 if (p->BufferSize <= 0) {
356 debug_error("[CODEC OGG]End of file\n");
357 return MM_ERROR_END_OF_FILE;
359 pthread_mutex_lock(&p->mutex);
360 p->state = STATE_PLAY;
361 pthread_mutex_unlock(&p->mutex);
362 sem_post(&p->start_wave_signal);
365 return MM_ERROR_NONE;
368 int MMSoundPlugCodecOggStop(MMHandleType handle)
370 ogg_info_t *p = (ogg_info_t *) handle;
371 debug_enter("(handle %x)\n", handle);
372 pthread_mutex_lock(&p->mutex);
373 p->state = STATE_STOP;
374 pthread_mutex_unlock(&p->mutex);
377 return MM_ERROR_NONE;
380 int MMSoundPlugCodecOggDestroy(MMHandleType handle)
382 ogg_info_t *p = (ogg_info_t*) handle;
385 debug_enter("(handle %x)\n", handle);
388 debug_critical("Confirm the hadle (is NULL)\n");
389 err = MM_ERROR_SOUND_INTERNAL;
394 mm_source_close(p->source);
395 free(p->source); p->source = NULL;
398 err = OGGDEC_ResetDecode(p->decoder);
399 if (err != OGGDEC_SUCCESS) {
400 debug_error("[CODEC OGG]Codec Reset fail\n");
401 err = MM_ERROR_SOUND_INTERNAL;
404 err = OGGDEC_DeleteDecode(p->decoder);
405 if (err != OGGDEC_SUCCESS) {
406 debug_error("[CODEC OGG]Delete Decode fail\n");
407 err = MM_ERROR_SOUND_INTERNAL;
410 sem_destroy(&p->start_wave_signal);
411 sem_destroy(&p->start_ogg_signal);
414 free(p->pcm_out_buf);
415 p->pcm_out_buf = NULL;
428 int MMSoundGetPluginType(void)
432 return MM_SOUND_PLUGIN_TYPE_CODEC;
436 int MMSoundPlugCodecGetInterface(mmsound_codec_interface_t *intf)
440 debug_critical("Confirm the codec interface struct (is NULL)\n");
441 return MM_ERROR_SOUND_INTERNAL;
444 intf->GetSupportTypes = MMSoundPlugCodecOggGetSupportTypes;
445 intf->Parse = MMSoundPlugCodecOggParse;
446 intf->Create = MMSoundPlugCodecOggCreate;
447 intf->Destroy = MMSoundPlugCodecOggDestroy;
448 intf->Play = MMSoundPlugCodecOggPlay;
449 intf->Stop = MMSoundPlugCodecOggStop;
450 intf->SetThreadPool = MMSoundPlugCodecOggSetThreadPool;
453 return MM_ERROR_NONE;