Support ogg loop playback
[platform/core/multimedia/libmm-sound.git] / server / plugin / ogg / mm_sound_plugin_codec_ogg.c
1 /*
2  * libmm-sound
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Seungbae Shin <seungbae.shin@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25
26 #include <semaphore.h>
27 #include <pthread.h>
28
29 #include <mm_error.h>
30 #include <mm_debug.h>
31 #include <tremolo_vorbisdec_api.h>
32
33 #include "../../include/mm_sound.h"
34 #include "../../include/mm_sound_plugin_codec.h"
35 #include "../../../include/mm_sound_pa_client.h"
36
37 #define OGG_DEC_BUF_SIZE 4096
38 #define OGG_FILE_SAMPLE_PLAY_DURATION 290
39
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)
44
45 int MMSoundPlugCodecOggStop(MMHandleType handle);
46
47 enum {
48    STATE_NONE = 0,
49    STATE_READY,
50    STATE_BEGIN,
51    STATE_PLAY,
52    STATE_ENDOFDECORD,
53    STATE_STOP,
54 };
55
56 typedef struct {
57         /* thread controls */
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;
61
62      /* Codec infomations */
63         void                    *decoder;
64         char* pcm_out_buf;
65         int                     offset;
66         int     period;
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;
71
72      /* Audio Infomations */
73         int                             transper_size; /* audio open return */
74         int                             handle;
75
76      /* control Informations */
77         int                             repeat_count;
78         int                             (*stop_cb)(int);
79         int                             cb_param;
80         int                             state;
81         MMSourceType         *source;
82         int codec;
83         int NumberOfChannels;
84         int SamplingFrequency;
85         int format;
86         int Duration;
87         int BitRate;
88         int BufferSize;
89 } ogg_info_t;
90
91 static int (*g_thread_pool_func)(void*, void (*)(void*)) = NULL;
92
93 static void _reset_ogg_decoder(ogg_info_t *p)
94 {
95         int err, used_size, skipsize;
96         OGG_DEC_INFO ogg_info;
97
98         err = OGGDEC_ResetDecode(p->decoder);
99         if (err != OGGDEC_SUCCESS) {
100                 debug_error("Failed to RESET decoder!");
101                 return;
102         }
103
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!");
107                 return;
108         }
109
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!");
113                 return;
114         }
115 }
116
117 void _pcm_out_func(void *data)
118 {
119         ogg_info_t *p = (ogg_info_t *)data;
120         int used_size = 0;
121         int decoded_len = 0;
122         unsigned char* ogg_buf = NULL;
123         int err = 0;
124
125         debug_enter();
126
127         if (!p) {
128                 debug_error("Invalid ogg_info_t...");
129                 return;
130         }
131
132         sem_wait(&p->start_wave_signal);
133
134         while (((p->repeat_count == -1) ? (1) : (p->repeat_count--)) && p->state == STATE_PLAY) {
135                 ogg_buf = MMSourceGetPtr(p->source) + p->offset;
136
137                 while (p->state == STATE_PLAY) {
138                         decoded_len = 0;
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);
142                                 break;
143                         }
144
145                         mm_sound_pa_write(p->handle, p->pcm_out_buf, decoded_len);
146                         ogg_buf += used_size;
147
148                         if (err != OGGDEC_SUCCESS)
149                                 break;
150                 }
151
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);
155                 else
156                         _reset_ogg_decoder(p);
157         }
158
159         mm_sound_pa_drain(p->handle);
160         mm_sound_pa_close(p->handle);
161
162         /* Notice */
163         /* OggDestory is called by stop_cb func */
164         /* INDEED the stop_cb must be called, after end of all progress */
165         if (p->stop_cb)
166                 p->stop_cb(p->cb_param);
167
168         debug_leave();
169 }
170
171 int MMSoundPlugCodecOggSetThreadPool(int (*func)(void*, void (*)(void*)))
172 {
173         debug_enter("(func : %p)\n", func);
174         g_thread_pool_func = func;
175         debug_leave("\n");
176         return MM_ERROR_NONE;
177 }
178
179 int* MMSoundPlugCodecOggGetSupportTypes(void)
180 {
181         debug_enter("\n");
182         static int suported[2] = {MM_SOUND_SUPPORTED_CODEC_OGG, 0};
183         debug_leave("\n");
184         return suported;
185 }
186
187 int MMSoundPlugCodecOggParse(MMSourceType *source, mmsound_codec_info_t *info)
188 {
189         unsigned char *ptr = NULL;
190         unsigned int size = 0;
191         int err;
192         OGG_DEC_INFO ogg_info;
193
194         debug_enter("\n");
195
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);
199
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;
204         }
205
206         info->format = 16;
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);
212         debug_leave("\n");
213
214         return MM_ERROR_NONE;
215 }
216
217 int MMSoundPlugCodecOggCreate(mmsound_codec_param_t *param, mmsound_codec_info_t *info, MMHandleType *handle)
218 {
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;
224
225         pa_sample_spec ss;
226         int size = 0;
227         int mode = HANDLE_MODE_OUTPUT_LOW_LATENCY;
228
229         debug_enter("\n");
230
231         if (g_thread_pool_func == NULL) {
232                 debug_error("Need thread pool!\n");
233                 return MM_ERROR_SOUND_INTERNAL;
234         }
235
236         source = param->source;
237         debug_msg("[CODEC OGG]Param source p 0x08%X\n", param->source);
238
239         p = (ogg_info_t *) malloc(sizeof(ogg_info_t));
240         if (p == NULL) {
241                 debug_error("[CODEC OGG]Memory allocation Fail\n");
242                 return MM_ERROR_OUT_OF_MEMORY;
243         }
244
245         memset(p, 0, sizeof(ogg_info_t));
246         p->source = param->source;
247         p->BufferSize = MMSourceGetCurSize(source);
248
249         pthread_mutex_init(&p->mutex, NULL);
250
251         err = sem_init(&p->start_ogg_signal, 0, 0);
252         if (err == -1) {
253                 debug_error("[CODEC OGG]Semaphore init fail\n");
254                 ret = MM_ERROR_SOUND_INTERNAL;
255                 goto error_before_create;
256         }
257
258         err = sem_init(&p->start_wave_signal, 0, 0);
259         if (err == -1) {
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;
264         }
265
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;
271         }
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;
277         }
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;
283         }
284         p->offset = skipsize;
285
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;
291         }
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;
297
298         /* Temporal code for debug */
299         /*
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);
309         */
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;
314
315         if(info->duration < OGG_FILE_SAMPLE_PLAY_DURATION) {
316                 mode = HANDLE_MODE_OUTPUT_LOW_LATENCY;
317         } else {
318                 mode = HANDLE_MODE_OUTPUT;
319         }
320
321         switch(info->format)
322         {
323         case 8:
324                 ss.format = PA_SAMPLE_U8;
325                 break;
326         case 16:
327                 ss.format =  PA_SAMPLE_S16LE;
328                 break;
329         default:
330                 ss.format =  PA_SAMPLE_S16LE;
331                 break;
332         }
333         ss.channels = info->channels;
334         ss.rate = info->samplerate;
335
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);
338
339         p->handle = mm_sound_pa_open(HANDLE_MODE_OUTPUT_LOW_LATENCY, param->volume_config, &ss, NULL, &size, param->stream_type, param->stream_index);
340         if(!p->handle) {
341                 debug_error("[CODEC OGG] Can not open audio handle\n");
342                 ret = MM_ERROR_SOUND_INTERNAL;
343                 goto error_after_buffer;
344         }
345
346         pthread_mutex_lock(&p->mutex);
347         p->state = STATE_READY;
348         pthread_mutex_unlock(&p->mutex);
349         *handle = p;
350
351         err = g_thread_pool_func(p, _pcm_out_func);
352         if (err) {
353                 debug_error("[CODEC OGG]pthread_create() fail in pcm thread\n");
354                 ret = MM_ERROR_SOUND_INTERNAL;
355                 goto error_after_buffer;
356         }
357
358         debug_leave("\n");
359         return MM_ERROR_NONE;
360
361 error_after_buffer:
362         free(p->pcm_out_buf);
363
364 error_after_create:
365         sem_destroy(&p->start_ogg_signal);
366         sem_destroy(&p->start_wave_signal);
367         OGGDEC_ResetDecode(p->decoder);
368         OGGDEC_DeleteDecode(p->decoder);
369
370 error_before_create:
371         free(p);
372         return ret;
373 }
374
375 int MMSoundPlugCodecOggPlay(MMHandleType handle)
376 {
377         ogg_info_t *p = (ogg_info_t *) handle;
378         debug_enter("(handle %x)\n", handle);
379
380         if (p->BufferSize <= 0) {
381             debug_error("[CODEC OGG]End of file\n");
382             return MM_ERROR_END_OF_FILE;
383         }
384         pthread_mutex_lock(&p->mutex);
385         p->state = STATE_PLAY;
386         pthread_mutex_unlock(&p->mutex);
387         sem_post(&p->start_wave_signal);
388
389         debug_leave("\n");
390         return MM_ERROR_NONE;
391 }
392
393 int MMSoundPlugCodecOggStop(MMHandleType handle)
394 {
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);
400         debug_leave("\n");
401
402         return MM_ERROR_NONE;
403 }
404
405 int MMSoundPlugCodecOggDestroy(MMHandleType handle)
406 {
407         ogg_info_t *p = (ogg_info_t*) handle;
408         int err;
409
410         debug_enter("(handle %x)\n", handle);
411
412         if (!p) {
413                 debug_critical("Confirm the hadle (is NULL)\n");
414                 err = MM_ERROR_SOUND_INTERNAL;
415                 return err;
416         }
417
418         if(p->source) {
419                 mm_source_close(p->source);
420                 free(p->source); p->source = NULL;
421         }
422
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;
427         }
428
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;
433         }
434
435         sem_destroy(&p->start_wave_signal);
436         sem_destroy(&p->start_ogg_signal);
437
438         if(p->pcm_out_buf) {
439                 free(p->pcm_out_buf);
440                 p->pcm_out_buf = NULL;
441         }
442
443         if (p) {
444                 free (p);
445                 p = NULL;
446         }
447
448         debug_leave("\n");
449         return err;
450 }
451
452 EXPORT_API
453 int MMSoundGetPluginType(void)
454 {
455         debug_enter("\n");
456         debug_leave("\n");
457         return MM_SOUND_PLUGIN_TYPE_CODEC;
458 }
459
460 EXPORT_API
461 int MMSoundPlugCodecGetInterface(mmsound_codec_interface_t *intf)
462 {
463         debug_enter("\n");
464         if (!intf) {
465                 debug_critical("Confirm the codec interface struct (is NULL)\n");
466                 return MM_ERROR_SOUND_INTERNAL;
467         }
468
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;
476
477         debug_leave("\n");
478         return MM_ERROR_NONE;
479 }