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.
27 #include <semaphore.h>
32 #include <mm_sound_pa_client.h>
34 #include "../../include/mm_sound_plugin_codec.h"
35 #include "../../../include/mm_sound_common.h"
37 #define SAMPLE_COUNT 128
38 #define WAV_FILE_SAMPLE_PLAY_DURATION 350 /*Unit: ms*/
40 WAVE_CODE_UNKNOWN = 0,
44 WAVE_CODE_IMA_ADPCM = 17,
45 WAVE_CODE_G723_ADPCM = 20,
47 WAVE_CODE_G721_ADPCM = 64,
51 #define MAKE_FOURCC(a, b, c, d) ((a) | (b) << 8) | ((c) << 16 | ((d) << 24))
52 #define RIFF_CHUNK_ID ((uint32_t) MAKE_FOURCC('R', 'I', 'F', 'F'))
53 #define RIFF_CHUNK_TYPE ((uint32_t) MAKE_FOURCC('W', 'A', 'V', 'E'))
54 #define FMT_CHUNK_ID ((uint32_t) MAKE_FOURCC('f', 'm', 't', ' '))
55 #define DATA_CHUNK_ID ((uint32_t) MAKE_FOURCC('d', 'a', 't', 'a'))
57 #define CODEC_WAVE_LOCK(LOCK) do { pthread_mutex_lock(LOCK); } while (0)
58 #define CODEC_WAVE_UNLOCK(LOCK) do { pthread_mutex_unlock(LOCK); } while (0)
79 int cb_param; // slotid
81 pthread_mutex_t mutex;
82 pthread_mutex_t *codec_wave_mutex;
91 char buffer[48000 / 1000 * SAMPLE_COUNT * 2 *2];//segmentation fault when above 22.05KHz stereo
92 int gain, out, in, option;
93 char stream_type[MM_SOUND_STREAM_TYPE_LEN];
97 static void _runing(void *param);
99 static int (*g_thread_pool_func)(void*, void (*)(void*)) = NULL;
101 int MMSoundPlugCodecWaveSetThreadPool(int (*func)(void*, void (*)(void*)))
103 debug_enter("(func : %p)\n", func);
104 g_thread_pool_func = func;
106 return MM_ERROR_NONE;
109 int* MMSoundPlugCodecWaveGetSupportTypes(void)
112 static int suported[2] = {MM_SOUND_SUPPORTED_CODEC_WAVE, 0};
117 int MMSoundPlugCodecWaveParse(MMSourceType *source, mmsound_codec_info_t *info)
130 uint16_t compression;
133 uint32_t avgbytepersec;
134 uint16_t blockkalign;
135 uint16_t bitspersample;
144 struct __riff_chunk *priff = NULL;
145 struct __wave_chunk *pwav = NULL;
146 struct __data_chunk *pdata = NULL;
147 // struct __fmt_chunk *pfmt = NULL;
155 data = MMSourceGetPtr(source);
156 debug_msg("[CODEC WAV] source ptr :[%p]\n", data);
158 datalen = MMSourceGetCurSize(source);
159 debug_msg("[CODEC WAV] source size :[0x%08X]\n", datalen);
161 priff = (struct __riff_chunk *) data;
163 /* Must be checked, Just for wav or not */
164 if (priff->chunkid != RIFF_CHUNK_ID ||priff->rifftype != RIFF_CHUNK_TYPE)
165 return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
167 if(priff->chunksize != datalen -8)
168 priff->chunksize = (datalen-8);
170 if (priff->chunkid != RIFF_CHUNK_ID ||priff->chunksize != datalen -8 ||priff->rifftype != RIFF_CHUNK_TYPE) {
171 debug_msg("[CODEC WAV] This contents is not RIFF file\n");
172 debug_msg("[CODEC WAV] cunkid : %ld, chunksize : %ld, rifftype : 0x%lx\n", priff->chunkid, priff->chunksize, priff->rifftype);
173 //debug_msg("[CODEC WAV] cunkid : %ld, chunksize : %d, rifftype : 0x%lx\n", RIFF_CHUNK_ID, datalen-8, RIFF_CHUNK_TYPE);
174 return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
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);
180 tSize = sizeof(struct __riff_chunk);
181 pdata = (struct __data_chunk*)(data+tSize);
183 while (pdata->chunkid != FMT_CHUNK_ID && tSize < datalen) {
184 tSize += (pdata->chunkSize+8);
186 if (tSize >= datalen) {
187 debug_warning("[CODEC WAV] Parsing finished : unable to find the Wave Format chunk\n");
188 return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
190 pdata = (struct __data_chunk*)(data+tSize);
193 pwav = (struct __wave_chunk*)(data+tSize);
195 if (pwav->chunkid != FMT_CHUNK_ID ||
196 pwav->compression != WAVE_CODE_PCM || /* Only supported PCM */
197 pwav->avgbytepersec != pwav->samplerate * pwav->blockkalign ||
198 pwav->blockkalign != (pwav->bitspersample >> 3)*pwav->channels) {
199 debug_msg("[CODEC WAV] This contents is not supported wave file\n");
200 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);
201 return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
204 /* Only One data chunk support */
206 tSize += (pwav->chunksize+8);
207 pdata = (struct __data_chunk *)(data+tSize);
209 while (pdata->chunkid != DATA_CHUNK_ID && tSize < datalen) {
210 tSize += (pdata->chunkSize+8);
211 if (tSize >= datalen) {
212 debug_warning("[CODEC WAV] Parsing finished : unable to find the data chunk\n");
213 return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
215 pdata = (struct __data_chunk*)(data+tSize);
219 info->codec = MM_SOUND_SUPPORTED_CODEC_WAVE;
220 info->channels = pwav->channels;
221 info->format = pwav->bitspersample;
222 info->samplerate = pwav->samplerate;
223 info->doffset = (tSize+8);
224 info->size = pdata->chunkSize;
225 info->duration = ((info->size)*1000)/pwav->avgbytepersec;
226 debug_msg("info->size:%d info->duration: %d\n", info->size, info->duration);
229 return MM_ERROR_NONE;
234 int MMSoundPlugCodecWaveCreate(mmsound_codec_param_t *param, mmsound_codec_info_t *info, MMHandleType *handle)
236 wave_info_t* p = NULL;
237 MMSourceType *source;
238 static int keytone_period = 0;
244 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",
245 keytone_period, (info->codec == MM_SOUND_SUPPORTED_CODEC_WAVE) ? "Wave" : "Unknown",
246 info->channels, info->format, info->samplerate, info->doffset, param->priority, param->repeat_count,
247 param->volume, param->stop_cb, param->handle_route);
248 source = param->source;
250 if (g_thread_pool_func == NULL) {
251 debug_error("[CODEC WAV] Need thread pool!\n");
252 return MM_ERROR_SOUND_INTERNAL;
255 p = (wave_info_t *) malloc(sizeof(wave_info_t));
258 debug_error("[CODEC WAV] memory allocation failed\n");
259 return MM_ERROR_OUT_OF_MEMORY;
262 memset(p, 0, sizeof(wave_info_t));
265 p->ptr_current = MMSourceGetPtr(source) + info->doffset;
267 p->size = info->size;
268 p->transper_size = info->samplerate / 1000 * SAMPLE_COUNT * (info->format >> 3) * info->channels;
270 p->tone = param->tone;
271 p->repeat_count = param ->repeat_count;
272 p->stop_cb = param->stop_cb;
273 p->cb_param = param->param;
275 p->codec_wave_mutex = param->codec_wave_mutex;
276 p->stream_index = param->stream_index;
277 MMSOUND_STRNCPY(p->stream_type, param->stream_type, MM_SOUND_STREAM_TYPE_LEN);
278 // pthread_mutex_init(&p->mutex, NULL);
280 debug_msg("[CODEC WAV] transper_size : %d\n", p->transper_size);
281 debug_msg("[CODEC WAV] size : %d\n", p->size);
283 if(info->duration < WAV_FILE_SAMPLE_PLAY_DURATION) {
284 p->mode = HANDLE_MODE_OUTPUT_LOW_LATENCY;
286 p->mode = HANDLE_MODE_OUTPUT;
289 p->priority = param->priority;
290 p->volume_config = param->volume_config;
291 p->channels = info->channels;
292 p->samplerate = info->samplerate;
294 p->handle_route = param->handle_route;
299 p->format = PA_SAMPLE_U8;
302 p->format = PA_SAMPLE_S16LE;
305 p->format = PA_SAMPLE_S16LE;
309 debug_msg("[CODEC WAV] PARAM mode : [%d]\n", p->mode);
310 debug_msg("[CODEC WAV] PARAM channels : [%d]\n", p->channels);
311 debug_msg("[CODEC WAV] PARAM samplerate : [%d]\n", p->samplerate);
312 debug_msg("[CODEC WAV] PARAM format : [%d]\n", p->format);
313 debug_msg("[CODEC WAV] PARAM volume type : [%x]\n", p->volume_config);
315 p->state = STATE_READY;
317 g_thread_pool_func(p, _runing);
318 debug_msg("[CODEC WAV] Thread pool start\n");
319 *handle = (MMHandleType)p;
325 return MM_ERROR_NONE;
329 int MMSoundPlugCodecWavePlay(MMHandleType handle)
331 wave_info_t *p = (wave_info_t *) handle;
333 debug_enter("(handle %x)\n", handle);
336 debug_error("[CODEC WAV] end of file\n");
337 return MM_ERROR_END_OF_FILE;
339 debug_msg("[CODEC WAV] send start signal\n");
340 p->state = STATE_BEGIN;
344 return MM_ERROR_NONE;
347 static void _runing(void *param)
349 wave_info_t *p = (wave_info_t*) param;
351 char *org_cur = NULL;
357 mm_sound_handle_route_info route_info;
360 debug_error("[CODEC WAV] param is null\n");
364 debug_enter("[CODEC WAV] (Slot ID %d)\n", p->cb_param);
365 CODEC_WAVE_LOCK(p->codec_wave_mutex);
367 route_info.policy = HANDLE_ROUTE_POLICY_OUT_AUTO;
369 ss.rate = p->samplerate;
370 ss.channels = p->channels;
371 ss.format = p->format;
372 p->period = pa_sample_size(&ss) * ((ss.rate * 25) / 1000);
373 p->handle = mm_sound_pa_open(p->mode, &route_info, p->priority, p->volume_config, &ss, NULL, &size, p->stream_type, p->stream_index);
375 debug_critical("[CODEC WAV] Can not open audio handle\n");
376 CODEC_WAVE_UNLOCK(p->codec_wave_mutex);
380 if (p->handle == 0) {
381 debug_critical("[CODEC WAV] audio_handle is not created !! \n");
382 CODEC_WAVE_UNLOCK(p->codec_wave_mutex);
388 /* Set the thread schedule */
389 org_cur = p->ptr_current;
392 dummy = malloc(p->period);
394 debug_error("[CODEC WAV] not enough memory");
395 CODEC_WAVE_UNLOCK(p->codec_wave_mutex);
398 memset(dummy, 0, p->period);
399 p->transper_size = p->period;
400 /* stop_size = org_size > p->period ? org_size : p->period; */
402 debug_msg("[CODEC WAV] Wait start signal\n");
404 while(p->state == STATE_READY) {
408 debug_msg("[CODEC WAV] Recv start signal\n");
409 debug_msg("[CODEC WAV] repeat : %d\n", p->repeat_count);
410 debug_msg("[CODEC WAV] transper_size : %d\n", p->transper_size);
412 if (p->state != STATE_STOP) {
413 debug_msg("[CODEC WAV] Play start\n");
414 p->state = STATE_PLAY;
416 debug_warning ("[CODEC WAV] state is already STATE_STOP\n");
419 while (((p->repeat_count == -1)?(1):(p->repeat_count--)) && p->state == STATE_PLAY) {
420 while (p->state == STATE_PLAY && p->size > 0) {
421 if (p->size >= p->transper_size) {
422 nread = p->transper_size;
423 memcpy(p->buffer, p->ptr_current, nread);
424 mm_sound_pa_write(p->handle, p->buffer, nread);
425 p->ptr_current += nread;
427 debug_msg("[CODEC WAV] Playing, nRead_data : %d Size : %d \n", nread, p->size);
429 /* Write remain size */
431 memcpy(p->buffer, p->ptr_current, nread);
432 mm_sound_pa_write(p->handle, p->buffer, nread);
433 mm_sound_pa_write(p->handle, dummy, (p->transper_size-nread));
434 p->ptr_current += nread;
438 p->ptr_current = org_cur;
442 debug_msg("[CODEC WAV] End playing\n");
443 p->state = STATE_STOP;
445 if (p->handle == 0) {
447 debug_warning("[CODEC WAV] audio already unrealize !!\n");
450 if(MM_ERROR_NONE != mm_sound_pa_drain(p->handle))
451 debug_error("mm_sound_pa_drain() failed\n");
453 if(MM_ERROR_NONE != mm_sound_pa_close(p->handle)) {
454 debug_error("[CODEC WAV] Can not close audio handle\n");
459 CODEC_WAVE_UNLOCK(p->codec_wave_mutex);
463 p->state = STATE_NONE;
465 free(dummy); dummy = NULL;
468 debug_msg("[CODEC WAV] Play is finished, Now start callback\n");
469 p->stop_cb(p->cb_param);
475 int MMSoundPlugCodecWaveStop(MMHandleType handle)
477 wave_info_t *p = (wave_info_t*) handle;
480 debug_error("The handle is null\n");
481 return MM_ERROR_SOUND_INTERNAL;
483 debug_msg("[CODEC WAV] Current state is state %d\n", p->state);
484 debug_msg("[CODEC WAV] Handle 0x%08X stop requested\n", handle);
486 p->state = STATE_STOP;
488 return MM_ERROR_NONE;
491 int MMSoundPlugCodecWaveDestroy(MMHandleType handle)
493 wave_info_t *p = (wave_info_t*) handle;
496 debug_warning("Can not destroy handle :: handle is invalid");
497 return MM_ERROR_SOUND_INVALID_POINTER;
501 mm_source_close(p->source);
502 free(p->source); p->source = NULL;
507 return MM_ERROR_NONE;
511 int MMSoundGetPluginType(void)
513 return MM_SOUND_PLUGIN_TYPE_CODEC;
517 int MMSoundPlugCodecGetInterface(mmsound_codec_interface_t *intf)
519 intf->GetSupportTypes = MMSoundPlugCodecWaveGetSupportTypes;
520 intf->Parse = MMSoundPlugCodecWaveParse;
521 intf->Create = MMSoundPlugCodecWaveCreate;
522 intf->Destroy = MMSoundPlugCodecWaveDestroy;
523 intf->Play = MMSoundPlugCodecWavePlay;
524 intf->Stop = MMSoundPlugCodecWaveStop;
525 intf->SetThreadPool = MMSoundPlugCodecWaveSetThreadPool;
527 return MM_ERROR_NONE;