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