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.
30 #include <mm_sound_pa_client.h>
32 #include "../../include/mm_sound_plugin_codec.h"
33 #include "../../../include/mm_sound_common.h"
37 #include <pulse/pulseaudio.h>
43 char filename[MM_SOUND_MAX_FILENAME];
45 char stream_type[MAX_STREAM_TYPE_LEN];
48 pa_threaded_mainloop *m;
56 static int _sound_prepare(wave_info_t *h)
58 memset(&h->si, 0, sizeof(SF_INFO));
60 h->sf = sf_open(h->filename, SFM_READ, &h->si);
62 debug_error("sf_open error. path(%s), error(%d,%s)", h->filename, sf_error(h->sf), sf_strerror(h->sf));
63 return (sf_error(h->sf) == SF_ERR_SYSTEM) ? MM_ERROR_SOUND_INTERNAL : MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
66 h->spec.rate = h->si.samplerate;
67 h->spec.channels = h->si.channels;
68 h->spec.format = PA_SAMPLE_S16LE;
70 debug_msg("SF_INFO : frames = %lld, samplerate = %d, channels = %d, format = 0x%X, sections = %d, seekable = %d",
71 h->si.frames, h->si.samplerate, h->si.channels, h->si.format, h->si.sections, h->si.seekable);
76 static int _sound_rewind(wave_info_t *h)
78 return (sf_seek(h->sf, 0, SEEK_SET) != -1) ? 0 : -1;
81 static int _sound_is_rewind_needed(wave_info_t *h)
83 return (h->repeat_count == -1 || h->repeat_count > 1);
86 static void _sound_unprepare(wave_info_t *h)
94 /* Context Callbacks */
95 static void _pa_context_state_callback(pa_context *c, void *userdata)
97 pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
100 switch (pa_context_get_state(c)) {
101 case PA_CONTEXT_CONNECTING:
102 case PA_CONTEXT_AUTHORIZING:
103 case PA_CONTEXT_SETTING_NAME:
104 debug_log("context(%p), state(%d)", c, pa_context_get_state(c));
107 case PA_CONTEXT_READY:
108 case PA_CONTEXT_TERMINATED:
109 case PA_CONTEXT_FAILED:
110 debug_warning("context(%p), state(%d)", c, pa_context_get_state(c));
111 pa_threaded_mainloop_signal(m, 0);
119 static void _pa_context_drain_complete_callback(pa_context *c, void *userdata)
121 pa_context_disconnect(c);
124 /* Stream Callbacks */
125 static void _pa_stream_state_callback(pa_stream *s, void *userdata)
127 pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
131 switch (pa_stream_get_state(s)) {
132 case PA_STREAM_CREATING:
133 debug_log("stream(%p), state(%d)", s, pa_stream_get_state(s));
135 case PA_STREAM_READY:
136 case PA_STREAM_FAILED:
137 case PA_STREAM_TERMINATED:
138 debug_warning("stream(%p), state(%d)", s, pa_stream_get_state(s));
139 pa_threaded_mainloop_signal(m, 0);
146 static void _pa_stream_drain_complete_callback(pa_stream* s, int success, void *userdata)
148 pa_operation *o = NULL;
149 wave_info_t *h = (wave_info_t *)userdata;
151 debug_msg("drain complete : %p, %d", s, success);
154 debug_error("drain failed. s(%p), success(%d)", s, success);
155 //pa_threaded_mainloop_signal(h->m, 0);
158 pa_stream_disconnect(h->s);
159 pa_stream_unref(h->s);
162 if (!(o = pa_context_drain(h->c, _pa_context_drain_complete_callback, h)))
163 pa_context_disconnect(h->c);
165 pa_operation_unref(o);
167 debug_msg("Call stop callback(%p, %p) of mgr_codec", h->stop_cb, h->cb_param);
169 h->stop_cb(h->cb_param);
172 static void _pa_stream_moved_callback(pa_stream *s, void *userdata)
175 debug_msg("stream moved callback : %p", s);
178 static void _pa_stream_underflow_callback(pa_stream *s, void *userdata)
180 wave_info_t *h = (wave_info_t *)userdata;
183 debug_msg("stream underflow callback : %p, file(%s)", s, h->filename);
186 static void _pa_stream_buffer_attr_callback(pa_stream *s, void *userdata)
189 debug_msg("stream underflow callback : %p", s);
192 static void _pa_stream_write_callback(pa_stream *s, size_t length, void *userdata)
194 sf_count_t bytes = 0;
196 size_t data_length = 0;
198 pa_operation *o = NULL;
199 wave_info_t *h = (wave_info_t *)userdata;
201 if (!s || length <= 0) {
202 debug_error("write error. stream(%p), length(%d)", s, length);
206 frame_size = pa_frame_size(&h->spec);
207 data_length = length;
209 if (frame_size == 0) {
210 debug_error("frame size can't be 0");
214 if (pa_stream_begin_write(s, &data, &data_length) < 0) {
215 debug_error("failed to pa_stream_begin_write()");
219 if ((bytes = sf_readf_short(h->sf, data, (sf_count_t)(data_length / frame_size))) > 0)
220 bytes *= (sf_count_t)frame_size;
222 debug_log("=== %lld / %d ===", bytes, data_length);
225 pa_stream_write(s, data, (size_t)bytes, NULL, 0, PA_SEEK_RELATIVE);
227 pa_stream_cancel_write(s);
229 /* If No more data, drain stream */
230 if (bytes < (sf_count_t)data_length) {
231 debug_msg("EOS!!!!! %lld/%d", bytes, data_length);
234 if (_sound_is_rewind_needed(h)) {
235 debug_msg("repeat count = %d", h->repeat_count);
236 /* do not decrease it in case of -1 for infinite play */
237 if (h->repeat_count != -1)
240 if (_sound_rewind(h) == 0)
243 debug_error("REWIND failed....");
244 /* can't loop anymore, fallback and do drain */
247 /* EOS callback will be notified after drain is completed */
248 pa_stream_set_write_callback(s, NULL, NULL);
249 o = pa_stream_drain(s, _pa_stream_drain_complete_callback, h);
251 pa_operation_unref(o);
255 static int _pa_context_connect(wave_info_t *h)
257 pa_threaded_mainloop *m = NULL;
258 pa_context *c = NULL;
261 if (!(m = pa_threaded_mainloop_new())) {
262 debug_error("mainloop create failed");
267 if (!(c = pa_context_new(pa_threaded_mainloop_get_api(m), NULL))) {
268 debug_error("context create failed");
272 pa_context_set_state_callback(c, _pa_context_state_callback, m);
274 pa_threaded_mainloop_lock(m);
276 if (pa_threaded_mainloop_start(m) < 0) {
277 debug_error("mainloop start failed");
281 if (pa_context_connect(c, NULL, 0, NULL) < 0) {
282 debug_error("context connect failed");
287 pa_context_state_t state = pa_context_get_state(c);
288 if (state == PA_CONTEXT_READY)
291 if (!PA_CONTEXT_IS_GOOD(state)) {
292 debug_error("Context error!!!! %d", pa_context_errno(c));
296 pa_threaded_mainloop_wait(m);
302 pa_threaded_mainloop_unlock(m);
310 pa_threaded_mainloop_unlock(m);
313 pa_threaded_mainloop_free(m);
318 static int _pa_stream_connect(wave_info_t *h)
321 pa_proplist *proplist = NULL;
322 pa_stream_state_t state;
324 proplist = pa_proplist_new();
327 pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, h->stream_type);
328 if (h->stream_index != -1)
329 pa_proplist_setf(proplist, PA_PROP_MEDIA_PARENT_ID, "%d", h->stream_index);
331 pa_threaded_mainloop_lock(h->m);
333 s = pa_stream_new_with_proplist(h->c, "wav-player", &h->spec, NULL, proplist);
334 pa_proplist_free(proplist);
336 debug_error("pa_stream_new failed. file(%s)", h->filename);
340 pa_stream_set_state_callback(s, _pa_stream_state_callback, h->m);
341 pa_stream_set_write_callback(s, _pa_stream_write_callback, h);
342 pa_stream_set_moved_callback(s, _pa_stream_moved_callback, h);
343 pa_stream_set_underflow_callback(s, _pa_stream_underflow_callback, h);
344 pa_stream_set_buffer_attr_callback(s, _pa_stream_buffer_attr_callback, h);
346 pa_stream_connect_playback(s, NULL, NULL,
347 PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE,
350 state = pa_stream_get_state(s);
352 if (state == PA_STREAM_READY)
355 if (!PA_STREAM_IS_GOOD(state)) {
356 debug_error("Stream error!!!! %d", state);
360 /* Wait until the stream is ready */
361 pa_threaded_mainloop_wait(h->m);
366 pa_threaded_mainloop_unlock(h->m);
374 pa_threaded_mainloop_unlock(h->m);
379 static void _pa_stream_uncork(wave_info_t *h)
381 pa_operation *o = NULL;
387 pa_threaded_mainloop_lock(h->m);
389 if ((o = pa_stream_cork(h->s, 0, NULL, NULL)))
390 pa_operation_unref(o);
392 debug_error("stream uncork failed");
394 pa_threaded_mainloop_unlock(h->m);
397 static int _pa_stream_stop_disconnect(wave_info_t *h)
402 pa_threaded_mainloop_lock(h->m);
404 pa_stream_disconnect(h->s);
405 pa_stream_unref(h->s);
409 pa_context_unref(h->c);
412 pa_threaded_mainloop_unlock(h->m);
414 pa_threaded_mainloop_free(h->m);
420 static int* _mm_sound_plug_codec_wave_get_supported_types(void)
422 static int suported[2] = { MM_SOUND_SUPPORTED_CODEC_WAVE, 0 };
426 static int _mm_sound_plug_codec_wave_parse(const char *filename, mmsound_codec_info_t *info)
431 if (!filename || !info) {
432 debug_error("filename(%p) or info(%p) is invalid...", filename, info);
433 return MM_ERROR_INVALID_ARGUMENT;
436 /* FIXME : following sndfile code should be encapsulated */
437 memset(&si, 0, sizeof(SF_INFO));
438 sf = sf_open(filename, SFM_READ, &si);
440 debug_error("sf_open error. path(%s), error(%d, %s)", filename, sf_error(sf), sf_strerror(sf));
441 if (sf_error(sf) == SF_ERR_SYSTEM)
442 return MM_ERROR_SOUND_INTERNAL;
444 return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
447 info->codec = MM_SOUND_SUPPORTED_CODEC_WAVE;
448 info->channels = si.channels;
449 info->samplerate = si.samplerate;
451 debug_msg("filename = %s, frames[%lld], samplerate[%d], channels[%d], format[%x], sections[%d], seekable[%d]",
452 filename, si.frames, si.samplerate, si.channels, si.format, si.sections, si.seekable);
455 return MM_ERROR_NONE;
458 static int _mm_sound_plug_codec_wave_create(mmsound_codec_param_t *param, mmsound_codec_info_t *info, MMHandleType *handle)
460 wave_info_t* p = NULL;
467 p = (wave_info_t *) malloc(sizeof(wave_info_t));
469 debug_error("memory allocation failed");
470 return MM_ERROR_OUT_OF_MEMORY;
473 memset(p, 0, sizeof(wave_info_t));
475 p->repeat_count = param->repeat_count;
476 p->stop_cb = param->stop_cb;
477 p->cb_param = param->param;
478 MMSOUND_STRNCPY(p->filename, param->pfilename, MM_SOUND_MAX_FILENAME);
479 p->stream_index = param->stream_index;
480 MMSOUND_STRNCPY(p->stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
482 ret = _sound_prepare(p);
484 debug_error("failed to prepare sound");
488 ret = _pa_context_connect(p);
490 debug_error("failed to connect context...");
494 ret = _pa_stream_connect(p);
496 debug_error("failed to connect stream...");
500 *handle = (MMHandleType)p;
503 debug_leave("%p", p);
505 return MM_ERROR_NONE;
510 return MM_ERROR_SOUND_INTERNAL;
514 static int _mm_sound_plug_codec_wave_play(MMHandleType handle)
516 wave_info_t *p = (wave_info_t *) handle;
518 debug_msg("Start handle %p", p);
519 _pa_stream_uncork(p);
521 return MM_ERROR_NONE;
524 static int _mm_sound_plug_codec_wave_stop(MMHandleType handle)
527 wave_info_t *p = (wave_info_t*) handle;
530 debug_error("The handle is null");
531 return MM_ERROR_SOUND_INTERNAL;
534 debug_msg("Handle %p stop requested", p);
536 ret = _pa_stream_stop_disconnect(p);
539 p->stop_cb(p->cb_param);
541 return (ret == 0) ? MM_ERROR_NONE : MM_ERROR_SOUND_INTERNAL;
544 static int _mm_sound_plug_codec_wave_destroy(MMHandleType handle)
546 wave_info_t *p = (wave_info_t *)handle;
549 debug_error("Can not destroy handle :: handle is invalid");
550 return MM_ERROR_SOUND_INVALID_POINTER;
558 return MM_ERROR_NONE;
562 int MMSoundPlugCodecGetInterface(mmsound_codec_interface_t *intf)
566 intf->GetSupportTypes = _mm_sound_plug_codec_wave_get_supported_types;
567 intf->Parse = _mm_sound_plug_codec_wave_parse;
568 intf->Create = _mm_sound_plug_codec_wave_create;
569 intf->Play = _mm_sound_plug_codec_wave_play;
570 intf->Stop = _mm_sound_plug_codec_wave_stop;
571 intf->Destroy = _mm_sound_plug_codec_wave_destroy;
572 intf->SetThreadPool = NULL;
574 return MM_ERROR_NONE;
578 int MMSoundGetPluginType(void)
580 return MM_SOUND_PLUGIN_TYPE_CODEC;