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;
char stream_type[MAX_STREAM_TYPE_LEN];
int stream_index;
+ int client_pid;
pa_threaded_mainloop *m;
pa_context *c;
- pa_stream* s;
+ pa_stream *s;
pa_sample_spec spec;
- SNDFILE* sf;
+ SNDFILE *sf;
SF_INFO si;
+
+ size_t written;
} wave_info_t;
static int _sound_prepare(wave_info_t *h)
h->spec.channels = h->si.channels;
h->spec.format = PA_SAMPLE_S16LE;
- debug_msg("SF_INFO : frames = %lld, samplerate = %d, channels = %d, format = 0x%X, sections = %d, seekable = %d",
+ 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);
return 0;
}
}
-static void _pa_stream_drain_complete_callback(pa_stream* s, int success, void *userdata)
+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;
- debug_msg("drain complete : %p, %d", s, success);
+ debug_msg("stream(%p) : drain completed(%d)", s, success);
if (!success) {
- debug_error("drain failed. s(%p), success(%d)", s, success);
+ debug_error("stream(%p) : drain failed(%d)", s, success);
//pa_threaded_mainloop_signal(h->m, 0);
}
h->s = NULL;
if (!(o = pa_context_drain(h->c, _pa_context_drain_complete_callback, h->m))) {
- debug_error("failed to drain context!");
+ debug_error("context(%p) failed to drain context!", h->c);
pa_context_disconnect(h->c);
pa_context_unref(h->c);
h->c = NULL;
pa_operation_unref(o);
}
- debug_msg("Call stop callback(%p, %d) of mgr_codec", h->stop_cb, h->cb_param);
+ 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);
+ h->stop_cb(h->cb_param, false);
}
static void _pa_stream_moved_callback(pa_stream *s, void *userdata)
{
assert(s);
- debug_msg("stream moved callback : %p", s);
+ debug_msg("stream(%p)", s);
}
static void _pa_stream_underflow_callback(pa_stream *s, void *userdata)
wave_info_t *h = (wave_info_t *)userdata;
assert(s);
- debug_msg("stream underflow callback : %p, file(%s)", s, h->filename);
+ debug_msg("stream(%p) : file(%s)", s, h->filename);
}
static void _pa_stream_buffer_attr_callback(pa_stream *s, void *userdata)
{
assert(s);
- debug_msg("stream underflow callback : %p", s);
+ debug_msg("stream(%p)", s);
+}
+
+static void _pa_stream_started_callback(pa_stream *s, void *userdata)
+{
+ assert(s);
+ debug_msg("stream(%p)", s);
}
static void _pa_stream_write_callback(pa_stream *s, size_t length, void *userdata)
wave_info_t *h = (wave_info_t *)userdata;
if (!s || length <= 0) {
- debug_error("write error. stream(%p), length(%d)", s, length);
+ debug_error("stream(%p) : length(%zu)", s, length);
return;
}
data_length = length;
if (frame_size == 0) {
- debug_error("frame size can't be 0");
+ debug_error("stream(%p) : frame size can't be 0", s);
return;
}
if (pa_stream_begin_write(s, &data, &data_length) < 0) {
- debug_error("failed to pa_stream_begin_write()");
+ debug_error("stream(%p) : failed to pa_stream_begin_write()", s);
return;
}
if ((bytes = sf_readf_short(h->sf, data, (sf_count_t)(data_length / frame_size))) > 0)
bytes *= (sf_count_t)frame_size;
- debug_log("=== %lld / %d ===", bytes, data_length);
+ 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);
+ h->written += bytes;
+
/* If No more data, drain stream */
if (bytes < (sf_count_t)data_length) {
- debug_msg("EOS!!!!! %lld/%d", bytes, data_length);
+ debug_msg("stream(%p) : End Of Stream", s);
/* Handle loop */
if (_sound_is_rewind_needed(h)) {
- debug_msg("repeat count = %d", h->repeat_count);
+ 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("REWIND failed....");
+ debug_error("stream(%p) : REWIND failed....", s);
/* can't loop anymore, fallback and do drain */
}
if (o)
pa_operation_unref(o);
else
- debug_error("failed to drain stream %p", s);
+ debug_error("stream(%p) : failed to drain", s);
+ debug_msg("stream(%p) : reset write callback and drain requested", s);
}
}
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;
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_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);
- pa_stream_connect_playback(s, NULL, NULL,
- PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE,
- NULL, NULL);
+ 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);
break;
if (!PA_STREAM_IS_GOOD(state)) {
- debug_error("Stream error!!!! %d", state);
+ debug_error("stream(%p) : state(%d)", s, state);
goto error;
}
if ((o = pa_stream_cork(h->s, 0, NULL, NULL)))
pa_operation_unref(o);
else
- debug_error("stream uncork failed");
+ debug_error("stream(%p) : uncork failed", h->s);
pa_threaded_mainloop_unlock(h->m);
}
h->m = NULL;
}
-static int* _mm_sound_plug_codec_wave_get_supported_types(void)
+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;
+ SNDFILE *sf = NULL;
SF_INFO si;
if (!filename || !info) {
info->channels = si.channels;
info->samplerate = si.samplerate;
- debug_msg("filename = %s, frames[%lld], samplerate[%d], channels[%d], format[%x], sections[%d], seekable[%d]",
+ 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);
static int _mm_sound_plug_codec_wave_create(mmsound_codec_param_t *param, mmsound_codec_info_t *info, MMHandleType *handle)
{
- wave_info_t* p = NULL;
+ wave_info_t *h = NULL;
int ret = 0;
#ifdef DEBUG_DETAIL
debug_enter();
#endif
- p = (wave_info_t *) malloc(sizeof(wave_info_t));
- if (p == NULL) {
+ h = (wave_info_t *)calloc(1, sizeof(wave_info_t));
+ if (h == NULL) {
debug_error("memory allocation failed");
return MM_ERROR_OUT_OF_MEMORY;
}
- memset(p, 0, sizeof(wave_info_t));
- p->handle = 0;
- p->repeat_count = param->repeat_count;
- p->stop_cb = param->stop_cb;
- p->cb_param = param->param;
- MMSOUND_STRNCPY(p->filename, param->pfilename, MM_SOUND_MAX_FILENAME);
- p->stream_index = param->stream_index;
- MMSOUND_STRNCPY(p->stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
+ 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(p);
+ ret = _sound_prepare(h);
if (ret < 0) {
debug_error("failed to prepare sound");
goto error;
}
- ret = _pa_context_connect(p);
+ ret = _pa_context_connect(h);
if (ret < 0) {
debug_error("failed to connect context...");
goto error;
}
- ret = _pa_stream_connect(p);
+ ret = _pa_stream_connect(h);
if (ret < 0) {
debug_error("failed to connect stream...");
goto error;
}
- *handle = (MMHandleType)p;
+ *handle = (MMHandleType)h;
#ifdef DEBUG_DETAIL
- debug_leave("%p", p);
+ debug_leave("%p", h);
#endif
return MM_ERROR_NONE;
error:
- _sound_unprepare(p);
- free(p);
+ _sound_unprepare(h);
+ free(h);
return MM_ERROR_SOUND_INTERNAL;
}
static int _mm_sound_plug_codec_wave_play(MMHandleType handle)
{
- wave_info_t *p = (wave_info_t *) handle;
+ wave_info_t *h = (wave_info_t *)handle;
- debug_msg("Start handle %p", p);
- _pa_stream_uncork(p);
+ 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) {
+ wave_info_t *h = (wave_info_t *)handle;
+ if (!h) {
debug_error("The handle is null");
return MM_ERROR_SOUND_INTERNAL;
}
- debug_msg("Handle %p stop requested", p);
+ debug_msg("Handle %p stop requested", h);
- _pa_stream_stop_disconnect(p);
+ _pa_stream_stop_disconnect(h);
- if (p->stop_cb)
- p->stop_cb(p->cb_param);
+ if (h->stop_cb)
+ h->stop_cb(h->cb_param, true);
return MM_ERROR_NONE;
}
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) {
+ if (!h) {
debug_error("Can not destroy handle :: handle is invalid");
return MM_ERROR_SOUND_INVALID_POINTER;
}
- _sound_unprepare(p);
+ _sound_unprepare(h);
- free(p);
- p = NULL;
+ free(h);
+ h = NULL;
return MM_ERROR_NONE;
}