Fix double unlock of slot mutex in user stops scneario
[platform/core/multimedia/libmm-sound.git] / server / plugin / wav / mm_sound_plugin_codec_wave.c
index 09b2d32..65ea459 100644 (file)
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <stdint.h>
 
-#include <semaphore.h>
-#include <unistd.h>
 
 #include <mm_error.h>
 #include <mm_debug.h>
-#include <pthread.h>
-#include <avsys-audio.h>
+#include <mm_sound_pa_client.h>
 
-#include "../../include/mm_sound.h"
-#include "../../include/mm_ipc.h"
-#include "../../include/mm_sound_thread_pool.h"
 #include "../../include/mm_sound_plugin_codec.h"
-#include "../../include/mm_sound_hal.h"
-#include "../../../include/mm_sound_private.h"
-
-
-#define SAMPLE_COUNT   128
-enum {
-       WAVE_CODE_UNKNOWN                               = 0,
-       WAVE_CODE_PCM                                   = 1,
-       WAVE_CODE_ADPCM                         = 2,
-       WAVE_CODE_G711                                  = 3,
-       WAVE_CODE_IMA_ADPCM                             = 17,
-       WAVE_CODE_G723_ADPCM                    = 20,
-       WAVE_CODE_GSM                                   = 49,
-       WAVE_CODE_G721_ADPCM                    = 64,
-       WAVE_CODE_MPEG                                  = 80,
-};
-
-#define MAKE_FOURCC(a, b, c, d)                ((a) | (b) << 8) | ((c) << 16 | ((d) << 24))
-#define RIFF_CHUNK_ID                          ((unsigned long) MAKE_FOURCC('R', 'I', 'F', 'F'))
-#define RIFF_CHUNK_TYPE                                ((unsigned long) MAKE_FOURCC('W', 'A', 'V', 'E'))
-#define FMT_CHUNK_ID                           ((unsigned long) MAKE_FOURCC('f', 'm', 't', ' '))
-#define DATA_CHUNK_ID                          ((unsigned long) MAKE_FOURCC('d', 'a', 't', 'a'))
-
-enum {
-   STATE_NONE = 0,
-   STATE_READY,
-   STATE_BEGIN,
-   STATE_PLAY,
-   STATE_STOP,
-};
-
-typedef struct
-{
-       char *ptr_current;
-       int size;
-       int transper_size;
-       avsys_handle_t audio_handle;
-       int period;
-       int tone;
-       int keytone;
+#include "../../../include/mm_sound_common.h"
+#include <unistd.h>
+
+#include <sndfile.h>
+#include <pthread.h>
+#include <pulse/pulseaudio.h>
+
+typedef struct {
+       int handle;
        int repeat_count;
-       int (*stop_cb)(int);
+       int (*stop_cb)(int, bool);
+       char filename[MM_SOUND_MAX_FILENAME];
        int cb_param;
-       int state;
-       pthread_mutex_t mutex;
-       MMSourceType *source;
-       char buffer[48000 / 1000 * SAMPLE_COUNT * 2 *2];//segmentation fault when above 22.05KHz stereo
-       int handle_route;
+       char stream_type[MAX_STREAM_TYPE_LEN];
+       int stream_index;
+       int client_pid;
+
+       pa_threaded_mainloop *m;
+       pa_context *c;
+       pa_stream *s;
+       pa_sample_spec spec;
+       SNDFILE *sf;
+       SF_INFO si;
+
+       size_t written;
 } wave_info_t;
 
-static void _runing(void *param);
+static int _sound_prepare(wave_info_t *h)
+{
+       memset(&h->si, 0, sizeof(SF_INFO));
+
+       h->sf = sf_open(h->filename, SFM_READ, &h->si);
+       if (!h->sf) {
+               debug_error("sf_open error. path(%s), error(%d,%s)", h->filename, sf_error(h->sf), sf_strerror(h->sf));
+               return (sf_error(h->sf) == SF_ERR_SYSTEM) ? MM_ERROR_SOUND_INTERNAL : MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
+       }
+
+       sf_command(h->sf, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);
+
+       h->spec.rate = h->si.samplerate;
+       h->spec.channels = h->si.channels;
+       h->spec.format = PA_SAMPLE_S16LE;
 
-static int (*g_thread_pool_func)(void*, void (*)(void*)) = NULL;
+       debug_msg("SF_INFO : frames = %"PRId64", samplerate = %d, channels = %d, format = 0x%X, sections = %d, seekable = %d",
+                       h->si.frames, h->si.samplerate, h->si.channels, h->si.format, h->si.sections, h->si.seekable);
 
-int MMSoundPlugCodecWaveSetThreadPool(int (*func)(void*, void (*)(void*)))
+       return 0;
+}
+
+static int _sound_rewind(wave_info_t *h)
 {
-    debug_enter("(func : %p)\n", func);
-    g_thread_pool_func = func;
-    debug_leave("\n");
-    return MM_ERROR_NONE;
+       return (sf_seek(h->sf, 0, SEEK_SET) != -1) ? 0 : -1;
 }
 
-int* MMSoundPlugCodecWaveGetSupportTypes(void)
+static int _sound_is_rewind_needed(wave_info_t *h)
 {
-    debug_enter("\n");
-    static int suported[2] = {MM_SOUND_SUPPORTED_CODEC_WAVE, 0};
-    debug_leave("\n");
-    return suported;
+       return (h->repeat_count == -1 || h->repeat_count > 1);
 }
 
-int MMSoundPlugCodecWaveParse(MMSourceType *source, mmsound_codec_info_t *info)
+static void _sound_unprepare(wave_info_t *h)
 {
-       struct __riff_chunk
-       {
-               long chunkid;
-               long chunksize;
-               long rifftype;
-       };
-
-       struct __wave_chunk
-       {
-               long chunkid;
-               long chunksize;
-               unsigned short compression;
-               unsigned short channels;
-               unsigned long samplerate;
-               unsigned long avgbytepersec;
-               unsigned short blockkalign;
-               unsigned short bitspersample;
-       };
-
-       struct __data_chunk
-       {
-               long chunkid;
-               long chunkSize;
-       };
-
-       struct __riff_chunk *priff = NULL;
-       struct __wave_chunk *pwav = NULL;
-       struct __data_chunk *pdata = NULL;
-//     struct __fmt_chunk *pfmt = NULL;
-
-       int datalen = -1;
-       char *data = NULL;
-       unsigned int tSize;
-
-       debug_enter("\n");
-
-       data = MMSourceGetPtr(source);
-       debug_msg("[CODEC WAV] source ptr :[%p]\n", data);
-
-       datalen = MMSourceGetCurSize(source);
-       debug_msg("[CODEC WAV] source size :[0x%08X]\n", datalen);
-
-       priff = (struct __riff_chunk *) data;
-       
-       /* Must be checked, Just for wav or not */
-       if (priff->chunkid != RIFF_CHUNK_ID ||priff->rifftype != RIFF_CHUNK_TYPE)
-               return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
-               
-       if(priff->chunksize != datalen -8)
-               priff->chunksize = (datalen-8);
-       
-       if (priff->chunkid != RIFF_CHUNK_ID ||priff->chunksize != datalen -8 ||priff->rifftype != RIFF_CHUNK_TYPE) {
-               debug_msg("[CODEC WAV] This contents is not RIFF file\n");
-               debug_msg("[CODEC WAV] cunkid : %ld, chunksize : %ld, rifftype : 0x%lx\n", priff->chunkid, priff->chunksize, priff->rifftype);
-               //debug_msg("[CODEC WAV] cunkid : %ld, chunksize : %d, rifftype : 0x%lx\n", RIFF_CHUNK_ID, datalen-8, RIFF_CHUNK_TYPE);
-               return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
+       if (h->sf) {
+               sf_close(h->sf);
+               h->sf = NULL;
        }
+}
 
-       debug_msg("[CODEC WAV] cunkid : %ld, chunksize : %ld, rifftype : 0x%lx\n", priff->chunkid, priff->chunksize, priff->rifftype);
-       //debug_msg("[CODEC WAV] cunkid : %ld, chunksize : %d, rifftype : 0x%lx\n", RIFF_CHUNK_ID, datalen-8, RIFF_CHUNK_TYPE);
+/* Context Callbacks */
+static void _pa_context_state_callback(pa_context *c, void *userdata)
+{
+       pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
+       assert(c);
+
+       switch (pa_context_get_state(c)) {
+       case PA_CONTEXT_CONNECTING:
+       case PA_CONTEXT_AUTHORIZING:
+       case PA_CONTEXT_SETTING_NAME:
+               debug_log("context(%p), state(%d)", c, pa_context_get_state(c));
+               break;
 
-       tSize = sizeof(struct __riff_chunk);
-       pdata = (struct __data_chunk*)(data+tSize);
-               
-       while (pdata->chunkid != FMT_CHUNK_ID && tSize < datalen) {
-               tSize += (pdata->chunkSize+8);
+       case PA_CONTEXT_READY:
+       case PA_CONTEXT_TERMINATED:
+       case PA_CONTEXT_FAILED:
+               debug_warning("context(%p), state(%d)", c, pa_context_get_state(c));
+               pa_threaded_mainloop_signal(m, 0);
+               break;
 
-               if (tSize >= datalen) {
-                       debug_warning("[CODEC WAV] Parsing finished : unable to find the Wave Format chunk\n");
-                       return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
-               } else {
-                       pdata = (struct __data_chunk*)(data+tSize);
-               }
-       }
-       pwav = (struct __wave_chunk*)(data+tSize);
-
-       if (pwav->chunkid != FMT_CHUNK_ID ||
-           pwav->compression != WAVE_CODE_PCM ||       /* Only supported PCM */
-           pwav->avgbytepersec != pwav->samplerate * pwav->blockkalign ||
-           pwav->blockkalign != (pwav->bitspersample >> 3)*pwav->channels) {
-               debug_msg("[CODEC WAV] This contents is not supported wave file\n");
-               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);
-               return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
+       default:
+               break;
        }
+}
 
-       /* Only One data chunk support */
-
-       tSize += (pwav->chunksize+8);
-       pdata = (struct __data_chunk *)(data+tSize);
+static void *_cleanup_thread_func(void *userdata)
+{
+       pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
 
-       while (pdata->chunkid != DATA_CHUNK_ID && tSize < datalen) {
-               tSize += (pdata->chunkSize+8);
-               if (tSize >= datalen) {
-                       debug_warning("[CODEC WAV] Parsing finished : unable to find the data chunk\n");
-                       return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
-               } else {
-                       pdata = (struct __data_chunk*)(data+tSize);
-               }       
+       if (m) {
+               debug_error("now stop and free threaded_mainloop(%p) here", m);
+               pa_threaded_mainloop_stop(m);
+               pa_threaded_mainloop_free(m);
+       } else {
+               debug_warning("thread mainloop is already null");
        }
-       
-       info->codec = MM_SOUND_SUPPORTED_CODEC_WAVE;
-       info->channels = pwav->channels;
-       info->format = pwav->bitspersample;
-       info->samplerate = pwav->samplerate;
-       info->doffset = (tSize+8);
-       info->size = pdata->chunkSize;
-       debug_msg("info->size:%d\n", info->size);
-
-       debug_leave("\n");
-       return MM_ERROR_NONE;
+
+       pthread_exit(NULL);
 }
 
+static void _cleanup_threaded_mainloop(pa_threaded_mainloop *m)
+{
+       int ret = 0;
+       pthread_t thread_id;
+       pthread_attr_t attr;
 
+       ret = pthread_attr_init(&attr);
+       if (ret != 0) {
+               debug_error("failed to init pthread attr!!! errno=%d", ret);
+               return;
+       }
 
-int MMSoundPlugCodecWaveCreate(mmsound_codec_param_t *param, mmsound_codec_info_t *info, MMHandleType *handle)
-{
-       int ret = MM_ERROR_NONE;
-       wave_info_t* p = NULL;
+       ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
+       if (ret != 0) {
+               debug_error("failed to set detach state!!! errno=%d", ret);
+               goto finish;
+       }
 
-       avsys_audio_param_t audio_param;
+       ret = pthread_create(&thread_id, &attr, _cleanup_thread_func, m);
+       if (ret != 0)
+               debug_error("failed to create _cleanup_thread_func!!! errno=%d", ret);
 
-       static avsys_handle_t keytone_handle = (avsys_handle_t)-1;
-       MMSourceType *source;
+finish:
+       ret = pthread_attr_destroy(&attr);
+       if (ret != 0)
+               debug_error("failed to destroy pthread attr!!! errno=%d", ret);
 
-       static int keytone_period = 0;
+       return;
+}
 
-       debug_enter("\n");
-       debug_msg("[CODEC WAV] Local keytone_period : %d\n", keytone_period);
-       debug_msg("[CODEC WAV] Local keytone_handle : %d\n", (int)keytone_handle);
-       
-       debug_msg("[CODEC WAV] Type %s\n", info->codec == MM_SOUND_SUPPORTED_CODEC_WAVE ? "PCM Wave" : "Unknown");
-       debug_msg("[CODEC WAV] channels   : %d\n", info->channels);
-       debug_msg("[CODEC WAV] format     : %d\n", info->format);
-       debug_msg("[CODEC WAV] samplerate : %d\n", info->samplerate);
-       debug_msg("[CODEC WAV] doffset    : %d\n", info->doffset);
 
-       debug_msg("[CODEC WAV] priority : %d\n", param->priority);
-       debug_msg("[CODEC WAV] repeat : %d\n", param->repeat_count);
-       debug_msg("[CODEC WAV] volume type : %d\n", param->volume);
-       debug_msg("[CODEC WAV] callback : %p\n", param->stop_cb);
-       debug_msg("[CODEC WAV] Keytonemode : %08x\n", param->keytone);
-       debug_msg("[CODEC WAV] handle route : %d\n", param->handle_route);
+static void _pa_context_drain_complete_callback(pa_context *c, void *userdata)
+{
+       debug_msg("context drain completed, cleanup context and mainloop");
 
-       source = param->source;
+       pa_context_disconnect(c);
+       pa_context_unref(c);
 
-       if (g_thread_pool_func == NULL) {
-               debug_error("[CODEC WAV] Need thread pool!\n");
-               return MM_ERROR_SOUND_INTERNAL;
-       }
+       _cleanup_threaded_mainloop((pa_threaded_mainloop *)userdata);
+}
 
-       p = (wave_info_t *) malloc(sizeof(wave_info_t));
+/* Stream Callbacks */
+static void _pa_stream_state_callback(pa_stream *s, void *userdata)
+{
+       pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
 
-       if (p == NULL) {
-               debug_error("[CODEC WAV] memory allocation failed\n");
-               return MM_ERROR_OUT_OF_MEMORY;
-       }
+       assert(s);
 
-       memset(p, 0, sizeof(wave_info_t));
-       p->audio_handle = (avsys_handle_t)-1;
-
-       p->ptr_current = MMSourceGetPtr(source) + info->doffset;
-
-       p->size = info->size;
-       p->transper_size = info->samplerate / 1000 * SAMPLE_COUNT * (info->format >> 3) * info->channels;
-
-       p->tone = param->tone;
-       p->repeat_count = param ->repeat_count;
-       p->stop_cb = param->stop_cb;
-       p->cb_param = param->param;
-       p->source = source;
-       //      pthread_mutex_init(&p->mutex, NULL);
-
-       debug_msg("[CODEC WAV] transper_size : %d\n", p->transper_size);
-       debug_msg("[CODEC WAV] size : %d\n", p->size);
-
-
-       /* audio param setting */
-       memset (&audio_param, 0, sizeof(avsys_audio_param_t));
-       audio_param.mode = AVSYS_AUDIO_MODE_OUTPUT;
-       audio_param.priority = param->priority;
-       audio_param.vol_type = param->volume_config;
-       audio_param.channels = info->channels;
-       audio_param.samplerate = info->samplerate;
-       if(param->handle_route == MM_SOUND_HANDLE_ROUTE_USING_CURRENT) /* normal, solo */
-               audio_param.handle_route = AVSYS_AUDIO_HANDLE_ROUTE_FOLLOWING_POLICY;
-       else /* loud solo */
-               audio_param.handle_route = AVSYS_AUDIO_HANDLE_ROUTE_HANDSET_ONLY;
-       p->handle_route = param->handle_route;
-
-       switch(info->format)
-       {
-       case 8:
-               audio_param.format =  AVSYS_AUDIO_FORMAT_8BIT;
+       switch (pa_stream_get_state(s)) {
+       case PA_STREAM_CREATING:
+               debug_log("stream(%p), state(%d)", s, pa_stream_get_state(s));
                break;
-       case 16:
-               audio_param.format =  AVSYS_AUDIO_FORMAT_16BIT;
+       case PA_STREAM_READY:
+       case PA_STREAM_FAILED:
+       case PA_STREAM_TERMINATED:
+               debug_warning("stream(%p), state(%d)", s, pa_stream_get_state(s));
+               pa_threaded_mainloop_signal(m, 0);
                break;
        default:
-               audio_param.format =  AVSYS_AUDIO_FORMAT_16BIT;
                break;
        }
+}
 
-       debug_msg("[CODEC WAV] PARAM mode : [%d]\n", audio_param.mode);
-       debug_msg("[CODEC WAV] PARAM priority: [%d]\n", audio_param.priority);
-       debug_msg("[CODEC WAV] PARAM channels : [%d]\n", audio_param.channels);
-       debug_msg("[CODEC WAV] PARAM samplerate : [%d]\n", audio_param.samplerate);
-       debug_msg("[CODEC WAV] PARAM format : [%d]\n", audio_param.format);
-       debug_msg("[CODEC WAV] PARAM volume type : [%x]\n", audio_param.vol_type);
+static void _pa_stream_drain_complete_callback(pa_stream *s, int success, void *userdata)
+{
+       pa_operation *o = NULL;
+       wave_info_t *h = (wave_info_t *)userdata;
 
-       ret = avsys_audio_open(&audio_param, &p->audio_handle, &p->period);
-       if (ret != MM_ERROR_NONE)
-               debug_critical("[CODEC WAV] Can not open audio handle\n");
+       debug_msg("stream(%p) : drain completed(%d)", s, success);
 
+       if (!success) {
+               debug_error("stream(%p) : drain failed(%d)", s, success);
+               //pa_threaded_mainloop_signal(h->m, 0);
+       }
 
+       pa_stream_disconnect(h->s);
+       pa_stream_unref(h->s);
+       h->s = NULL;
 
-       if (p->audio_handle == (avsys_handle_t)-1) {
-               debug_critical("[CODEC WAV] audio_handle is not created !! \n");
-               if (p)
-                       free(p);
-               return MM_ERROR_SOUND_INTERNAL;
+       if (!(o = pa_context_drain(h->c, _pa_context_drain_complete_callback, h->m))) {
+               debug_error("context(%p) failed to drain context!", h->c);
+               pa_context_disconnect(h->c);
+               pa_context_unref(h->c);
+               h->c = NULL;
+       } else {
+               pa_operation_unref(o);
        }
 
+       debug_msg("Invoke stop callback(%p, %d) of mgr_codec", h->stop_cb, h->cb_param);
+       if (h->stop_cb)
+               h->stop_cb(h->cb_param, false);
+}
 
-       p->state = STATE_READY;
+static void _pa_stream_moved_callback(pa_stream *s, void *userdata)
+{
+       assert(s);
+       debug_msg("stream(%p)", s);
+}
 
-       g_thread_pool_func(p, _runing);
-       debug_msg("[CODEC WAV] Thread pool start\n");
-       *handle = (MMHandleType)p;
+static void _pa_stream_underflow_callback(pa_stream *s, void *userdata)
+{
+       wave_info_t *h = (wave_info_t *)userdata;
+       assert(s);
 
-       debug_leave("\n");
+       debug_msg("stream(%p) : file(%s)", s, h->filename);
+}
 
-       return MM_ERROR_NONE;
+static void _pa_stream_buffer_attr_callback(pa_stream *s, void *userdata)
+{
+       assert(s);
+       debug_msg("stream(%p)", s);
 }
 
+static void _pa_stream_started_callback(pa_stream *s, void *userdata)
+{
+       assert(s);
+       debug_msg("stream(%p)", s);
+}
 
-int MMSoundPlugCodecWavePlay(MMHandleType handle)
+static void _pa_stream_write_callback(pa_stream *s, size_t length, void *userdata)
 {
-       wave_info_t *p = (wave_info_t *) handle;
+       sf_count_t bytes = 0;
+       void *data = NULL;
+       size_t data_length = 0;
+       size_t frame_size;
+       pa_operation *o = NULL;
+       wave_info_t *h = (wave_info_t *)userdata;
+
+       if (!s || length <= 0) {
+               debug_error("stream(%p) : length(%zu)", s, length);
+               return;
+       }
 
-       debug_enter("(handle %x)\n", handle);
+       frame_size = pa_frame_size(&h->spec);
+       data_length = length;
 
-       if (p->size <= 0) {
-               debug_error("[CODEC WAV] end of file\n");
-               return MM_ERROR_END_OF_FILE;
+       if (frame_size == 0) {
+               debug_error("stream(%p) : frame size can't be 0", s);
+               return;
        }
-       debug_msg("[CODEC WAV] send start signal\n");
-       p->state = STATE_BEGIN;
 
-       debug_leave("\n");
+       if (pa_stream_begin_write(s, &data, &data_length) < 0) {
+               debug_error("stream(%p) : failed to pa_stream_begin_write()", s);
+               return;
+       }
 
-       return MM_ERROR_NONE;
- }
+       if ((bytes = sf_readf_short(h->sf, data, (sf_count_t)(data_length / frame_size))) > 0)
+               bytes *= (sf_count_t)frame_size;
 
+       debug_msg("stream(%p) : === %"PRId64" / %zu / %zu ===", s, bytes, data_length, h->written);
 
+       if (bytes > 0)
+               pa_stream_write(s, data, (size_t)bytes, NULL, 0, PA_SEEK_RELATIVE);
+       else
+               pa_stream_cancel_write(s);
 
-static void _runing(void *param)
+       h->written += bytes;
+
+       /* If No more data, drain stream */
+       if (bytes < (sf_count_t)data_length) {
+               debug_msg("stream(%p) : End Of Stream", s);
+
+               /* Handle loop */
+               if (_sound_is_rewind_needed(h)) {
+                       debug_msg("stream(%p) : repeat count = %d", s, h->repeat_count);
+                       /* do not decrease it in case of -1 for infinite play */
+                       if (h->repeat_count != -1)
+                               h->repeat_count--;
+
+                       if (_sound_rewind(h) == 0)
+                               return;
+
+                       debug_error("stream(%p) : REWIND failed....", s);
+                       /* can't loop anymore, fallback and do drain */
+               }
+
+               /* EOS callback will be notified after drain is completed */
+               pa_stream_set_write_callback(s, NULL, NULL);
+               o = pa_stream_drain(s, _pa_stream_drain_complete_callback, h);
+               if (o)
+                       pa_operation_unref(o);
+               else
+                       debug_error("stream(%p) : failed to drain", s);
+               debug_msg("stream(%p) : reset write callback and drain requested", s);
+       }
+}
+
+static int _pa_context_connect(wave_info_t *h)
 {
-       wave_info_t *p = (wave_info_t*) param;
-       int nread = 0;
-       char *org_cur = NULL;
-       int org_size = 0;
-       char *dummy = NULL;
-       int ret;
+       pa_threaded_mainloop *m = NULL;
+       pa_context *c = NULL;
 
-       int gain, out, in, option;
-       int gain_after, out_after, in_after, option_after;
+       /* Mainloop */
+       if (!(m = pa_threaded_mainloop_new())) {
+               debug_error("mainloop create failed");
+               return -1;
+       }
 
+       /* Context */
+       if (!(c = pa_context_new(pa_threaded_mainloop_get_api(m), NULL))) {
+               debug_error("context create failed");
+               goto error_context_new;
+       }
 
-       debug_enter("[CODEC WAV] (Slot ID %d)\n", p->cb_param);
+       pa_context_set_state_callback(c, _pa_context_state_callback, m);
 
-       /* Set the thread schedule */
-       org_cur = p->ptr_current;
-       org_size = p->size;
+       pa_threaded_mainloop_lock(m);
 
-       dummy = malloc(p->period);
-       if(!dummy) {
-               debug_error("[CODEC WAV] not enough memory");
-               return;
+       if (pa_threaded_mainloop_start(m) < 0) {
+               debug_error("mainloop start failed");
+               goto error;
+       }
+
+       if (pa_context_connect(c, NULL, 0, NULL) < 0) {
+               debug_error("context connect failed");
+               goto error;
        }
-       memset(dummy, 0, p->period);
-       p->transper_size = p->period;
-
-       debug_msg("[CODEC WAV] Wait start signal\n");
-
-       while(p->state == STATE_READY)
-               usleep(4);
-
-       /*
-        * set path here
-        */
-       switch(p->handle_route)
-       {
-       case MM_SOUND_HANDLE_ROUTE_SPEAKER:
-       case MM_SOUND_HANDLE_ROUTE_SPEAKER_NO_RESTORE:
-               debug_msg("[CODEC WAV] Save backup path\n");
-               avsys_audio_get_path_ex(&gain, &out, &in, &option);
-
-               /* if current out is not speaker, then force set path to speaker */
-               if (out != AVSYS_AUDIO_PATH_EX_SPK) {
-                       debug_msg("[CODEC WAV] current out is not SPEAKER, set path to SPEAKER now!!!\n");
-                       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);
+
+       for (;;) {
+               pa_context_state_t state = pa_context_get_state(c);
+               if (state == PA_CONTEXT_READY)
+                       break;
+
+               if (!PA_CONTEXT_IS_GOOD(state)) {
+                       debug_error("Context error!!!! %d", pa_context_errno(c));
+                       goto error;
                }
-               break;
-       case MM_SOUND_HANDLE_ROUTE_USING_CURRENT:
-       default:
-               break;
+
+               pa_threaded_mainloop_wait(m);
        }
 
-       debug_msg("[CODEC WAV] Recv start signal\n");
-       debug_msg("[CODEC WAV] repeat : %d\n", p->repeat_count);
-       debug_msg("[CODEC WAV] transper_size : %d\n", p->transper_size);
+       h->m = m;
+       h->c = c;
 
-       if (p->state != STATE_STOP) {
-               debug_msg("[CODEC WAV] Play start\n");
-               p->state = STATE_PLAY;
-       } else {
-               debug_warning ("[CODEC WAV] state is already STATE_STOP\n");
+       pa_threaded_mainloop_unlock(m);
+
+       return 0;
+
+error:
+       pa_context_unref(c);
+       pa_threaded_mainloop_unlock(m);
+error_context_new:
+       pa_threaded_mainloop_free(m);
+
+       return -1;
+}
+
+static int _pa_stream_connect(wave_info_t *h)
+{
+       int ret = PA_OK;
+       pa_stream *s = NULL;
+       pa_proplist *proplist = NULL;
+       pa_stream_state_t state;
+
+       proplist = pa_proplist_new();
+       if (!proplist)
+               return -1;
+       pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, h->stream_type);
+       pa_proplist_setf(proplist, PA_PROP_APPLICATION_PROCESS_ID_ORIGIN, "%d", h->client_pid);
+       if (h->stream_index != -1)
+               pa_proplist_setf(proplist, PA_PROP_MEDIA_PARENT_ID, "%d", h->stream_index);
+
+       pa_threaded_mainloop_lock(h->m);
+
+       s = pa_stream_new_with_proplist(h->c, "wav-player", &h->spec, NULL, proplist);
+       pa_proplist_free(proplist);
+       if (!s) {
+               debug_error("pa_stream_new failed. file(%s)", h->filename);
+               goto error;
+       }
+
+       pa_stream_set_state_callback(s, _pa_stream_state_callback, h->m);
+       pa_stream_set_write_callback(s, _pa_stream_write_callback, h);
+       pa_stream_set_moved_callback(s, _pa_stream_moved_callback, h);
+       pa_stream_set_underflow_callback(s, _pa_stream_underflow_callback, h);
+       pa_stream_set_buffer_attr_callback(s, _pa_stream_buffer_attr_callback, h);
+       pa_stream_set_started_callback(s, _pa_stream_started_callback, h);
+
+       ret = pa_stream_connect_playback(s, NULL, NULL,
+               PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_START_CORKED,
+               NULL, NULL);
+       if (ret < 0) {
+               debug_error("stream(%p) : failed to connect playback, ret(%d)", s, ret);
+               goto error;
        }
+       for (;;) {
+               state = pa_stream_get_state(s);
 
-       while (((p->repeat_count == -1)?(1):(p->repeat_count--)) && p->state == STATE_PLAY) {
-               while (p->state == STATE_PLAY && p->size > 0) {
-                       if (p->size >= p->transper_size) {
-                               nread = p->transper_size;
-                               memcpy(p->buffer, p->ptr_current, nread);
-                               avsys_audio_write(p->audio_handle, p->buffer, nread);
-                               p->ptr_current += nread;
-                               p->size -= nread;
-                               debug_msg("[CODEC WAV] Playing, nRead_data : %d Size : %d \n", nread, p->size);
-                       } else {
-                               /* Write remain size */
-                               nread = p->size;
-                               memcpy(p->buffer, p->ptr_current, nread);
-                               avsys_audio_write(p->audio_handle, p->buffer, nread);
-                               avsys_audio_write(p->audio_handle, dummy, (p->transper_size-nread));
-                               //avsys_audio_drain(p->audio_handle);
-                               //debug_error("Drain is called\n");
-                               p->ptr_current += nread;
-                               p->size = 0;
-                       }
+               if (state == PA_STREAM_READY)
+                       break;
+
+               if (!PA_STREAM_IS_GOOD(state)) {
+                       debug_error("stream(%p) : state(%d)", s, state);
+                       goto error;
                }
-               p->ptr_current = org_cur;
-               p->size = org_size;
+
+               /* Wait until the stream is ready */
+               pa_threaded_mainloop_wait(h->m);
        }
 
-       debug_msg("[CODEC WAV] End playing\n");
-       p->state = STATE_STOP;
+       h->s = s;
 
-       if (p->audio_handle == (avsys_handle_t)-1) {
-               usleep(200000);
-               debug_warning("[CODEC WAV] audio already unrealize !!\n");
-       } else {
-               //usleep(75000);
+       pa_threaded_mainloop_unlock(h->m);
 
-               if(AVSYS_FAIL(avsys_audio_drain(p->audio_handle)))
-               {
-                       debug_error("avsys_audio_drain() failed\n");
-               }
+       return 0;
 
-               /*
-                * Restore path here
-                */
-               if (p->handle_route == MM_SOUND_HANDLE_ROUTE_SPEAKER) {
-                       avsys_audio_get_path_ex(&gain_after, &out_after, &in_after, &option_after);
+error:
+       if (s)
+               pa_stream_unref(s);
 
-                       /* If current path is not same as before playing sound, restore the sound path */
-                       if (gain_after != gain || out_after != out || in_after != in || option_after != option) {
+       pa_threaded_mainloop_unlock(h->m);
 
-                               debug_msg("[CODEC WAV] Restore path to previous one\n");
-                               if (audio_hal_set_sound_path(gain, out, in, option)) {
-                                       debug_error("[CODEC WAV] Can not restore sound path\n");
-                               }
-                       }
-               }
+       return -1;
+}
 
-               ret = avsys_audio_close(p->audio_handle);
-               if (AVSYS_FAIL(ret)) {
-                       debug_critical("[CODEC WAV] Can not close audio handle\n");
-               }
+static void _pa_stream_uncork(wave_info_t *h)
+{
+       pa_operation *o = NULL;
+
+       assert(h);
+       assert(h->m);
+       assert(h->s);
+
+       pa_threaded_mainloop_lock(h->m);
+
+       if ((o = pa_stream_cork(h->s, 0, NULL, NULL)))
+               pa_operation_unref(o);
+       else
+               debug_error("stream(%p) : uncork failed", h->s);
+
+       pa_threaded_mainloop_unlock(h->m);
+}
+
+static void _pa_stream_stop_disconnect(wave_info_t *h)
+{
+       assert(h);
+       assert(h->m);
+
+       pa_threaded_mainloop_lock(h->m);
+       if (h->s) {
+               pa_stream_disconnect(h->s);
+               pa_stream_unref(h->s);
+               h->s = NULL;
+       }
+       if (h->c) {
+               pa_context_disconnect(h->c);
+               pa_context_unref(h->c);
+               h->c = NULL;
+       }
+       pa_threaded_mainloop_unlock(h->m);
+
+       pa_threaded_mainloop_free(h->m);
+       h->m = NULL;
+}
+
+static int * _mm_sound_plug_codec_wave_get_supported_types(void)
+{
+       static int suported[2] = { MM_SOUND_SUPPORTED_CODEC_WAVE, 0 };
+       return suported;
+}
+
+static int _mm_sound_plug_codec_wave_parse(const char *filename, mmsound_codec_info_t *info)
+{
+       SNDFILE *sf = NULL;
+       SF_INFO si;
 
+       if (!filename || !info) {
+               debug_error("filename(%p) or info(%p) is invalid...", filename, info);
+               return MM_ERROR_INVALID_ARGUMENT;
        }
-       p->audio_handle = (avsys_handle_t)-1;
 
-       p->state = STATE_NONE;
+       /* FIXME : following sndfile code should be encapsulated */
+       memset(&si, 0, sizeof(SF_INFO));
+       sf = sf_open(filename, SFM_READ, &si);
+       if (!sf) {
+               debug_error("sf_open error. path(%s), error(%d, %s)", filename, sf_error(sf), sf_strerror(sf));
+               if (sf_error(sf) == SF_ERR_SYSTEM)
+                       return MM_ERROR_SOUND_INTERNAL;
+               else
+                       return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
+       }
+
+       info->codec = MM_SOUND_SUPPORTED_CODEC_WAVE;
+       info->channels = si.channels;
+       info->samplerate = si.samplerate;
+
+       debug_msg("filename[%s], frames[%"PRId64"], samplerate[%d], channels[%d], format[%x], sections[%d], seekable[%d]",
+                       filename, si.frames, si.samplerate, si.channels, si.format, si.sections, si.seekable);
+       sf_close(sf);
+
+       return MM_ERROR_NONE;
+}
+
+static int _mm_sound_plug_codec_wave_create(mmsound_codec_param_t *param, mmsound_codec_info_t *info, MMHandleType *handle)
+{
+       wave_info_t *h = NULL;
+       int ret = 0;
 
-       free(dummy);
-       if (p->stop_cb)
-       {
-               debug_msg("[CODEC WAV] Play is finished, Now start callback\n");
-               p->stop_cb(p->cb_param);
+#ifdef DEBUG_DETAIL
+       debug_enter();
+#endif
+
+       h = (wave_info_t *)calloc(1, sizeof(wave_info_t));
+       if (h == NULL) {
+               debug_error("memory allocation failed");
+               return MM_ERROR_OUT_OF_MEMORY;
+       }
+
+       h->handle = 0;
+       h->repeat_count = param->repeat_count;
+       h->stop_cb = param->stop_cb;
+       h->cb_param = param->param;
+       MMSOUND_STRNCPY(h->filename, param->pfilename, MM_SOUND_MAX_FILENAME);
+       h->client_pid = param->pid;
+       h->stream_index = param->stream_index;
+       MMSOUND_STRNCPY(h->stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
+
+       ret = _sound_prepare(h);
+       if (ret < 0) {
+               debug_error("failed to prepare sound");
+               goto error;
+       }
+
+       ret = _pa_context_connect(h);
+       if (ret < 0) {
+               debug_error("failed to connect context...");
+               goto error;
+       }
+
+       ret = _pa_stream_connect(h);
+       if (ret < 0) {
+               debug_error("failed to connect stream...");
+               goto error;
        }
-       debug_leave("\n");
+
+       *handle = (MMHandleType)h;
+
+#ifdef DEBUG_DETAIL
+       debug_leave("%p", h);
+#endif
+       return MM_ERROR_NONE;
+
+error:
+       _sound_unprepare(h);
+       free(h);
+       return MM_ERROR_SOUND_INTERNAL;
 }
 
 
-int MMSoundPlugCodecWaveStop(MMHandleType handle)
+static int _mm_sound_plug_codec_wave_play(MMHandleType handle)
+{
+       wave_info_t *h = (wave_info_t *)handle;
+
+       debug_msg("Start handle(%p), stream(%p), written(%zu)", h, h->s, h->written);
+       _pa_stream_uncork(h);
+
+       return MM_ERROR_NONE;
+}
+
+static int _mm_sound_plug_codec_wave_stop(MMHandleType handle)
 {
-       wave_info_t *p = (wave_info_t*) handle;
-       if (!p) {
-               debug_error("The handle is NULL\n");
+       wave_info_t *h = (wave_info_t *)handle;
+       if (!h) {
+               debug_error("The handle is null");
                return MM_ERROR_SOUND_INTERNAL;
        }
-       debug_msg("[CODEC WAV] Current state is state %d\n", p->state);
-       debug_msg("[CODEC WAV] Handle 0x%08X stop requested\n", handle);
 
-       p->state = STATE_STOP;
+       debug_msg("Handle %p stop requested", h);
+
+       _pa_stream_stop_disconnect(h);
+
+       if (h->stop_cb)
+               h->stop_cb(h->cb_param, true);
 
-    return MM_ERROR_NONE;
+       return MM_ERROR_NONE;
 }
 
-int MMSoundPlugCodecWaveDestroy(MMHandleType handle)
+static int _mm_sound_plug_codec_wave_destroy(MMHandleType handle)
 {
-       wave_info_t *p = (wave_info_t*) handle;
+       wave_info_t *h = (wave_info_t *)handle;
 
-       if(!p) {
-               debug_warning("Can not destroy handle :: handle is null\n");
+       if (!h) {
+               debug_error("Can not destroy handle :: handle is invalid");
                return MM_ERROR_SOUND_INVALID_POINTER;
        }
 
-       if(p->source) {
-               mm_source_close(p->source);
-               free(p->source);
-       }
+       _sound_unprepare(h);
 
-       free(p);
+       free(h);
+       h = NULL;
 
        return MM_ERROR_NONE;
 }
 
 EXPORT_API
-int MMSoundGetPluginType(void)
+int MMSoundPlugCodecGetInterface(mmsound_codec_interface_t *intf)
 {
-    return MM_SOUND_PLUGIN_TYPE_CODEC;
+       assert(intf);
+
+       intf->GetSupportTypes   = _mm_sound_plug_codec_wave_get_supported_types;
+       intf->Parse             = _mm_sound_plug_codec_wave_parse;
+       intf->Create            = _mm_sound_plug_codec_wave_create;
+       intf->Play              = _mm_sound_plug_codec_wave_play;
+       intf->Stop              = _mm_sound_plug_codec_wave_stop;
+       intf->Destroy           = _mm_sound_plug_codec_wave_destroy;
+       intf->SetThreadPool     = NULL;
+
+       return MM_ERROR_NONE;
 }
 
 EXPORT_API
-int MMSoundPlugCodecGetInterface(mmsound_codec_interface_t *intf)
+int MMSoundGetPluginType(void)
 {
-    intf->GetSupportTypes   = MMSoundPlugCodecWaveGetSupportTypes;
-    intf->Parse             = MMSoundPlugCodecWaveParse;
-    intf->Create            = MMSoundPlugCodecWaveCreate;
-    intf->Destroy           = MMSoundPlugCodecWaveDestroy;
-    intf->Play              = MMSoundPlugCodecWavePlay;
-    intf->Stop              = MMSoundPlugCodecWaveStop;
-    intf->SetThreadPool     = MMSoundPlugCodecWaveSetThreadPool;
-
-    return MM_ERROR_NONE;
+       return MM_SOUND_PLUGIN_TYPE_CODEC;
 }