Fix undefined symbol error on wav plugin
[platform/core/multimedia/libmm-sound.git] / server / plugin / wav / mm_sound_plugin_codec_wave.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 #include <stdint.h>
26
27 #include <semaphore.h>
28 #include <unistd.h>
29
30 #include <mm_error.h>
31 #include <mm_debug.h>
32 #include <pthread.h>
33 #include <mm_sound_pa_client.h>
34
35 #include "../../include/mm_sound.h"
36 #include "../../include/mm_ipc.h"
37 #include "../../include/mm_sound_thread_pool.h"
38 #include "../../include/mm_sound_plugin_codec.h"
39 #include "../../../include/mm_sound_private.h"
40 #include "../../../include/mm_sound_common.h"
41
42 #define SAMPLE_COUNT    128
43 #define WAV_FILE_SAMPLE_PLAY_DURATION           350                     /*Unit: ms*/
44 enum {
45         WAVE_CODE_UNKNOWN                               = 0,
46         WAVE_CODE_PCM                                   = 1,
47         WAVE_CODE_ADPCM                         = 2,
48         WAVE_CODE_G711                                  = 3,
49         WAVE_CODE_IMA_ADPCM                             = 17,
50         WAVE_CODE_G723_ADPCM                    = 20,
51         WAVE_CODE_GSM                                   = 49,
52         WAVE_CODE_G721_ADPCM                    = 64,
53         WAVE_CODE_MPEG                                  = 80,
54 };
55
56 #define MAKE_FOURCC(a, b, c, d)         ((a) | (b) << 8) | ((c) << 16 | ((d) << 24))
57 #define RIFF_CHUNK_ID                           ((uint32_t) MAKE_FOURCC('R', 'I', 'F', 'F'))
58 #define RIFF_CHUNK_TYPE                 ((uint32_t) MAKE_FOURCC('W', 'A', 'V', 'E'))
59 #define FMT_CHUNK_ID                            ((uint32_t) MAKE_FOURCC('f', 'm', 't', ' '))
60 #define DATA_CHUNK_ID                           ((uint32_t) MAKE_FOURCC('d', 'a', 't', 'a'))
61
62 #define CODEC_WAVE_LOCK(LOCK) do { pthread_mutex_lock(LOCK); } while (0)
63 #define CODEC_WAVE_UNLOCK(LOCK) do { pthread_mutex_unlock(LOCK); } while (0)
64
65 enum {
66    STATE_NONE = 0,
67    STATE_READY,
68    STATE_BEGIN,
69    STATE_PLAY,
70    STATE_STOP,
71 };
72
73 typedef struct
74 {
75         char *ptr_current;
76         int size;
77         int transper_size;
78         int handle;
79         int period;
80         int tone;
81         int keytone;
82         int repeat_count;
83         int (*stop_cb)(int);
84         int cb_param; // slotid
85         int state;
86         pthread_mutex_t mutex;
87         pthread_mutex_t *codec_wave_mutex;
88         int mode;
89         int volume_config;
90         int channels;
91         int samplerate;
92         int format;
93         int handle_route;
94         int priority;
95         MMSourceType *source;
96         char buffer[48000 / 1000 * SAMPLE_COUNT * 2 *2];//segmentation fault when above 22.05KHz stereo
97         int gain, out, in, option;
98         char stream_type[MM_SOUND_STREAM_TYPE_LEN];
99         int stream_index;
100 } wave_info_t;
101
102 static void _runing(void *param);
103
104 static int (*g_thread_pool_func)(void*, void (*)(void*)) = NULL;
105
106 int MMSoundPlugCodecWaveSetThreadPool(int (*func)(void*, void (*)(void*)))
107 {
108     debug_enter("(func : %p)\n", func);
109     g_thread_pool_func = func;
110     debug_leave("\n");
111     return MM_ERROR_NONE;
112 }
113
114 int* MMSoundPlugCodecWaveGetSupportTypes(void)
115 {
116     debug_enter("\n");
117     static int suported[2] = {MM_SOUND_SUPPORTED_CODEC_WAVE, 0};
118     debug_leave("\n");
119     return suported;
120 }
121
122 int MMSoundPlugCodecWaveParse(MMSourceType *source, mmsound_codec_info_t *info)
123 {
124         struct __riff_chunk
125         {
126                 uint32_t chunkid;
127                 uint32_t chunksize;
128                 uint32_t rifftype;
129         };
130
131         struct __wave_chunk
132         {
133                 uint32_t chunkid;
134                 uint32_t chunksize;
135                 uint16_t compression;
136                 uint16_t channels;
137                 uint32_t samplerate;
138                 uint32_t avgbytepersec;
139                 uint16_t blockkalign;
140                 uint16_t bitspersample;
141         };
142
143         struct __data_chunk
144         {
145                 uint32_t chunkid;
146                 uint32_t chunkSize;
147         };
148
149         struct __riff_chunk *priff = NULL;
150         struct __wave_chunk *pwav = NULL;
151         struct __data_chunk *pdata = NULL;
152 //      struct __fmt_chunk *pfmt = NULL;
153
154         int datalen = -1;
155         char *data = NULL;
156         unsigned int tSize;
157
158         debug_enter("\n");
159
160         data = MMSourceGetPtr(source);
161         debug_msg("[CODEC WAV] source ptr :[%p]\n", data);
162
163         datalen = MMSourceGetCurSize(source);
164         debug_msg("[CODEC WAV] source size :[0x%08X]\n", datalen);
165
166         priff = (struct __riff_chunk *) data;
167
168         /* Must be checked, Just for wav or not */
169         if (priff->chunkid != RIFF_CHUNK_ID ||priff->rifftype != RIFF_CHUNK_TYPE)
170                 return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
171
172         if(priff->chunksize != datalen -8)
173                 priff->chunksize = (datalen-8);
174
175         if (priff->chunkid != RIFF_CHUNK_ID ||priff->chunksize != datalen -8 ||priff->rifftype != RIFF_CHUNK_TYPE) {
176                 debug_msg("[CODEC WAV] This contents is not RIFF file\n");
177                 debug_msg("[CODEC WAV] cunkid : %ld, chunksize : %ld, rifftype : 0x%lx\n", priff->chunkid, priff->chunksize, priff->rifftype);
178                 //debug_msg("[CODEC WAV] cunkid : %ld, chunksize : %d, rifftype : 0x%lx\n", RIFF_CHUNK_ID, datalen-8, RIFF_CHUNK_TYPE);
179                 return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
180         }
181
182         debug_msg("[CODEC WAV] cunkid : %ld, chunksize : %ld, rifftype : 0x%lx\n", priff->chunkid, priff->chunksize, priff->rifftype);
183         //debug_msg("[CODEC WAV] cunkid : %ld, chunksize : %d, rifftype : 0x%lx\n", RIFF_CHUNK_ID, datalen-8, RIFF_CHUNK_TYPE);
184
185         tSize = sizeof(struct __riff_chunk);
186         pdata = (struct __data_chunk*)(data+tSize);
187
188         while (pdata->chunkid != FMT_CHUNK_ID && tSize < datalen) {
189                 tSize += (pdata->chunkSize+8);
190
191                 if (tSize >= datalen) {
192                         debug_warning("[CODEC WAV] Parsing finished : unable to find the Wave Format chunk\n");
193                         return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
194                 } else {
195                         pdata = (struct __data_chunk*)(data+tSize);
196                 }
197         }
198         pwav = (struct __wave_chunk*)(data+tSize);
199
200         if (pwav->chunkid != FMT_CHUNK_ID ||
201             pwav->compression != WAVE_CODE_PCM ||       /* Only supported PCM */
202             pwav->avgbytepersec != pwav->samplerate * pwav->blockkalign ||
203             pwav->blockkalign != (pwav->bitspersample >> 3)*pwav->channels) {
204                 debug_msg("[CODEC WAV] This contents is not supported wave file\n");
205                 debug_msg("[CODEC WAV] chunkid : 0x%lx, comp : 0x%x, av byte/sec : %lu, blockalign : %d\n", pwav->chunkid, pwav->compression, pwav->avgbytepersec, pwav->blockkalign);
206                 return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
207         }
208
209         /* Only One data chunk support */
210
211         tSize += (pwav->chunksize+8);
212         pdata = (struct __data_chunk *)(data+tSize);
213
214         while (pdata->chunkid != DATA_CHUNK_ID && tSize < datalen) {
215                 tSize += (pdata->chunkSize+8);
216                 if (tSize >= datalen) {
217                         debug_warning("[CODEC WAV] Parsing finished : unable to find the data chunk\n");
218                         return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
219                 } else {
220                         pdata = (struct __data_chunk*)(data+tSize);
221                 }
222         }
223
224         info->codec = MM_SOUND_SUPPORTED_CODEC_WAVE;
225         info->channels = pwav->channels;
226         info->format = pwav->bitspersample;
227         info->samplerate = pwav->samplerate;
228         info->doffset = (tSize+8);
229         info->size = pdata->chunkSize;
230         info->duration = ((info->size)*1000)/pwav->avgbytepersec;
231         debug_msg("info->size:%d info->duration: %d\n", info->size, info->duration);
232
233         debug_leave("\n");
234         return MM_ERROR_NONE;
235 }
236
237
238
239 int MMSoundPlugCodecWaveCreate(mmsound_codec_param_t *param, mmsound_codec_info_t *info, MMHandleType *handle)
240 {
241         wave_info_t* p = NULL;
242         MMSourceType *source;
243         static int keytone_period = 0;
244
245 #ifdef DEBUG_DETAIL
246         debug_enter("\n");
247 #endif
248
249         debug_msg("period[%d] type[%s] ch[%d] format[%d] rate[%d] doffset[%d] priority[%d] repeat[%d] volume[%f] callback[%p] route[%d]\n",
250                         keytone_period, (info->codec == MM_SOUND_SUPPORTED_CODEC_WAVE) ? "Wave" : "Unknown",
251                         info->channels, info->format, info->samplerate, info->doffset, param->priority, param->repeat_count,
252                         param->volume, param->stop_cb, param->handle_route);
253         source = param->source;
254
255         if (g_thread_pool_func == NULL) {
256                 debug_error("[CODEC WAV] Need thread pool!\n");
257                 return MM_ERROR_SOUND_INTERNAL;
258         }
259
260         p = (wave_info_t *) malloc(sizeof(wave_info_t));
261
262         if (p == NULL) {
263                 debug_error("[CODEC WAV] memory allocation failed\n");
264                 return MM_ERROR_OUT_OF_MEMORY;
265         }
266
267         memset(p, 0, sizeof(wave_info_t));
268         p->handle = 0;
269
270         p->ptr_current = MMSourceGetPtr(source) + info->doffset;
271
272         p->size = info->size;
273         p->transper_size = info->samplerate / 1000 * SAMPLE_COUNT * (info->format >> 3) * info->channels;
274
275         p->tone = param->tone;
276         p->repeat_count = param ->repeat_count;
277         p->stop_cb = param->stop_cb;
278         p->cb_param = param->param;
279         p->source = source;
280         p->codec_wave_mutex = param->codec_wave_mutex;
281         p->stream_index = param->stream_index;
282         MMSOUND_STRNCPY(p->stream_type, param->stream_type, MM_SOUND_STREAM_TYPE_LEN);
283         //      pthread_mutex_init(&p->mutex, NULL);
284
285         debug_msg("[CODEC WAV] transper_size : %d\n", p->transper_size);
286         debug_msg("[CODEC WAV] size : %d\n", p->size);
287
288         if(info->duration < WAV_FILE_SAMPLE_PLAY_DURATION) {
289                 p->mode = HANDLE_MODE_OUTPUT_LOW_LATENCY;
290         } else {
291                 p->mode = HANDLE_MODE_OUTPUT;
292         }
293
294         p->priority = param->priority;
295         p->volume_config = param->volume_config;
296         p->channels = info->channels;
297         p->samplerate = info->samplerate;
298
299         p->handle_route = param->handle_route;
300
301         switch(info->format)
302         {
303         case 8:
304                 p->format =  PA_SAMPLE_U8;
305                 break;
306         case 16:
307                 p->format =  PA_SAMPLE_S16LE;
308                 break;
309         default:
310                 p->format =  PA_SAMPLE_S16LE;
311                 break;
312         }
313
314         debug_msg("[CODEC WAV] PARAM mode : [%d]\n", p->mode);
315         debug_msg("[CODEC WAV] PARAM channels : [%d]\n", p->channels);
316         debug_msg("[CODEC WAV] PARAM samplerate : [%d]\n", p->samplerate);
317         debug_msg("[CODEC WAV] PARAM format : [%d]\n", p->format);
318         debug_msg("[CODEC WAV] PARAM volume type : [%x]\n", p->volume_config);
319
320         p->state = STATE_READY;
321
322         g_thread_pool_func(p, _runing);
323         debug_msg("[CODEC WAV] Thread pool start\n");
324         *handle = (MMHandleType)p;
325
326 #ifdef DEBUG_DETAIL
327         debug_leave("\n");
328 #endif
329
330         return MM_ERROR_NONE;
331 }
332
333
334 int MMSoundPlugCodecWavePlay(MMHandleType handle)
335 {
336         wave_info_t *p = (wave_info_t *) handle;
337
338         debug_enter("(handle %x)\n", handle);
339
340         if (p->size <= 0) {
341                 debug_error("[CODEC WAV] end of file\n");
342                 return MM_ERROR_END_OF_FILE;
343         }
344         debug_msg("[CODEC WAV] send start signal\n");
345         p->state = STATE_BEGIN;
346
347         debug_leave("\n");
348
349         return MM_ERROR_NONE;
350 }
351
352 static void _runing(void *param)
353 {
354         wave_info_t *p = (wave_info_t*) param;
355         int nread = 0;
356         char *org_cur = NULL;
357         int org_size = 0;
358         char *dummy = NULL;
359         int size;
360
361         pa_sample_spec ss;
362         mm_sound_handle_route_info route_info;
363
364         mm_sound_device_in device_in_before = MM_SOUND_DEVICE_IN_NONE;
365         mm_sound_device_out device_out_before = MM_SOUND_DEVICE_OUT_NONE;
366
367         if (p == NULL) {
368                 debug_error("[CODEC WAV] param is null\n");
369                 return;
370         }
371
372         debug_enter("[CODEC WAV] (Slot ID %d)\n", p->cb_param);
373         CODEC_WAVE_LOCK(p->codec_wave_mutex);
374
375         /*
376          * set path here
377          */
378         switch(p->handle_route)
379         {
380                 case MM_SOUND_HANDLE_ROUTE_SPEAKER:
381                 case MM_SOUND_HANDLE_ROUTE_SPEAKER_NO_RESTORE:
382                         debug_msg("[CODEC WAV] Save backup path\n");
383                         __mm_sound_lock();
384
385                         /* get route info from pulseaudio */
386                         /* MMSoundMgrPulseGetActiveDevice(&p->in, &p->out); */
387                         mm_sound_get_audio_path(&device_in_before, &device_out_before);
388                         /* if current out is not speaker, then force set path to speaker */
389                         if (device_out_before != MM_SOUND_DEVICE_OUT_SPEAKER) {
390                                 debug_msg("[CODEC WAV] current out is not SPEAKER, set path to SPEAKER now!!!\n");
391                                 mm_sound_pa_corkall(1);
392                                 mm_sound_set_sound_path_for_active_device(MM_SOUND_DEVICE_OUT_SPEAKER, MM_SOUND_DEVICE_IN_NONE);
393                         }
394
395                         /* set route info */
396                         route_info.device_in = MM_SOUND_DEVICE_IN_NONE;
397                         route_info.device_out = MM_SOUND_DEVICE_OUT_SPEAKER;
398                         route_info.policy = HANDLE_ROUTE_POLICY_OUT_HANDSET;
399                         /* MMSoundMgrPulseSetActiveDevice(route_info_device_in, route_info.device_out); */
400                         break;
401                 case MM_SOUND_HANDLE_ROUTE_USING_CURRENT:
402                         route_info.policy = HANDLE_ROUTE_POLICY_OUT_AUTO;
403                         break;
404                 default:
405                         break;
406         }
407
408         ss.rate = p->samplerate;
409         ss.channels = p->channels;
410         ss.format = p->format;
411         p->period = pa_sample_size(&ss) * ((ss.rate * 25) / 1000);
412         p->handle = mm_sound_pa_open(p->mode, &route_info, p->priority, p->volume_config, &ss, NULL, &size, p->stream_type, p->stream_index);
413         if(!p->handle) {
414                 debug_critical("[CODEC WAV] Can not open audio handle\n");
415                 CODEC_WAVE_UNLOCK(p->codec_wave_mutex);
416                 if (p->handle_route == MM_SOUND_HANDLE_ROUTE_SPEAKER || p->handle_route == MM_SOUND_HANDLE_ROUTE_SPEAKER_NO_RESTORE) {
417                         __mm_sound_unlock();
418                 }
419                 return;
420         }
421         
422         if (p->handle == 0) {
423                 debug_critical("[CODEC WAV] audio_handle is not created !! \n");
424                 CODEC_WAVE_UNLOCK(p->codec_wave_mutex);
425                 free(p);
426                 p = NULL;
427                 return;
428         }
429
430         /* Set the thread schedule */
431         org_cur = p->ptr_current;
432         org_size = p->size;
433
434         dummy = malloc(p->period);
435         if(!dummy) {
436                 debug_error("[CODEC WAV] not enough memory");
437                 CODEC_WAVE_UNLOCK(p->codec_wave_mutex);
438                 if (p->handle_route == MM_SOUND_HANDLE_ROUTE_SPEAKER || p->handle_route == MM_SOUND_HANDLE_ROUTE_SPEAKER_NO_RESTORE) {
439                         __mm_sound_unlock();
440                 }
441                 return;
442         }
443         memset(dummy, 0, p->period);
444         p->transper_size = p->period;
445         /* stop_size = org_size > p->period ? org_size : p->period; */
446
447         debug_msg("[CODEC WAV] Wait start signal\n");
448
449         while(p->state == STATE_READY) {
450                 usleep(4);
451         }
452
453         debug_msg("[CODEC WAV] Recv start signal\n");
454         debug_msg("[CODEC WAV] repeat : %d\n", p->repeat_count);
455         debug_msg("[CODEC WAV] transper_size : %d\n", p->transper_size);
456
457         if (p->state != STATE_STOP) {
458                 debug_msg("[CODEC WAV] Play start\n");
459                 p->state = STATE_PLAY;
460         } else {
461                 debug_warning ("[CODEC WAV] state is already STATE_STOP\n");
462         }
463
464         while (((p->repeat_count == -1)?(1):(p->repeat_count--)) && p->state == STATE_PLAY) {
465                 while (p->state == STATE_PLAY && p->size > 0) {
466                         if (p->size >= p->transper_size) {
467                                 nread = p->transper_size;
468                                 memcpy(p->buffer, p->ptr_current, nread);
469                                 mm_sound_pa_write(p->handle, p->buffer, nread);
470                                 p->ptr_current += nread;
471                                 p->size -= nread;
472                                 debug_msg("[CODEC WAV] Playing, nRead_data : %d Size : %d \n", nread, p->size);
473                         } else {
474                                 /* Write remain size */
475                                 nread = p->size;
476                                 memcpy(p->buffer, p->ptr_current, nread);
477                                 mm_sound_pa_write(p->handle, p->buffer, nread);
478                                 mm_sound_pa_write(p->handle, dummy, (p->transper_size-nread));
479                                 p->ptr_current += nread;
480                                 p->size = 0;
481                         }
482                 }
483                 p->ptr_current = org_cur;
484                 p->size = org_size;
485         }
486
487         debug_msg("[CODEC WAV] End playing\n");
488         p->state = STATE_STOP;
489
490         if (p->handle == 0) {
491                 usleep(200000);
492                 debug_warning("[CODEC WAV] audio already unrealize !!\n");
493         } else {
494                 /* usleep(75000); */
495                 if(MM_ERROR_NONE != mm_sound_pa_drain(p->handle))
496                         debug_error("mm_sound_pa_drain() failed\n");
497
498                 if(MM_ERROR_NONE != mm_sound_pa_close(p->handle)) {
499                         debug_error("[CODEC WAV] Can not close audio handle\n");
500                 } else {
501                         p->handle = 0;
502                 }
503                 /*
504                  * Restore path here
505                  */
506                 if (p->handle_route == MM_SOUND_HANDLE_ROUTE_SPEAKER) {
507                         /* If current path is not same as before playing sound, restore the sound path */
508                         if (device_out_before != MM_SOUND_DEVICE_OUT_SPEAKER) {
509                                 mm_sound_set_sound_path_for_active_device(device_out_before, device_in_before);
510                                 mm_sound_pa_corkall(0);
511                         }
512                 }
513                 if (p->handle_route == MM_SOUND_HANDLE_ROUTE_SPEAKER || p->handle_route == MM_SOUND_HANDLE_ROUTE_SPEAKER_NO_RESTORE) {
514                         __mm_sound_unlock();
515                 }
516         }
517         CODEC_WAVE_UNLOCK(p->codec_wave_mutex);
518
519         p->handle = 0;
520
521         p->state = STATE_NONE;
522
523         free(dummy); dummy = NULL;
524         if (p->stop_cb)
525         {
526                 debug_msg("[CODEC WAV] Play is finished, Now start callback\n");
527                 p->stop_cb(p->cb_param);
528         }
529         debug_leave("\n");
530 }
531
532
533 int MMSoundPlugCodecWaveStop(MMHandleType handle)
534 {
535         wave_info_t *p = (wave_info_t*) handle;
536
537         if (!p) {
538                 debug_error("The handle is null\n");
539                 return MM_ERROR_SOUND_INTERNAL;
540         }
541         debug_msg("[CODEC WAV] Current state is state %d\n", p->state);
542         debug_msg("[CODEC WAV] Handle 0x%08X stop requested\n", handle);
543
544         p->state = STATE_STOP;
545
546     return MM_ERROR_NONE;
547 }
548
549 int MMSoundPlugCodecWaveDestroy(MMHandleType handle)
550 {
551         wave_info_t *p = (wave_info_t*) handle;
552
553         if (!p) {
554                 debug_warning("Can not destroy handle :: handle is invalid");
555                 return MM_ERROR_SOUND_INVALID_POINTER;
556         }
557
558         if(p->source) {
559                 mm_source_close(p->source);
560                 free(p->source); p->source = NULL;
561         }
562
563         free(p); p = NULL;
564
565         return MM_ERROR_NONE;
566 }
567
568 EXPORT_API
569 int MMSoundGetPluginType(void)
570 {
571     return MM_SOUND_PLUGIN_TYPE_CODEC;
572 }
573
574 EXPORT_API
575 int MMSoundPlugCodecGetInterface(mmsound_codec_interface_t *intf)
576 {
577     intf->GetSupportTypes   = MMSoundPlugCodecWaveGetSupportTypes;
578     intf->Parse             = MMSoundPlugCodecWaveParse;
579     intf->Create            = MMSoundPlugCodecWaveCreate;
580     intf->Destroy           = MMSoundPlugCodecWaveDestroy;
581     intf->Play              = MMSoundPlugCodecWavePlay;
582     intf->Stop              = MMSoundPlugCodecWaveStop;
583     intf->SetThreadPool     = MMSoundPlugCodecWaveSetThreadPool;
584
585     return MM_ERROR_NONE;
586 }
587
588