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"
38 #include <pulse/pulseaudio.h>
44 char filename[MM_SOUND_MAX_FILENAME];
46 char stream_type[MAX_STREAM_TYPE_LEN];
49 pa_threaded_mainloop *m;
57 static int _sound_prepare(wave_info_t *h)
59 memset(&h->si, 0, sizeof(SF_INFO));
61 h->sf = sf_open(h->filename, SFM_READ, &h->si);
63 debug_error("sf_open error. path(%s), error(%d,%s)", h->filename, sf_error(h->sf), sf_strerror(h->sf));
64 return (sf_error(h->sf) == SF_ERR_SYSTEM) ? MM_ERROR_SOUND_INTERNAL : MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
67 sf_command(h->sf, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);
69 h->spec.rate = h->si.samplerate;
70 h->spec.channels = h->si.channels;
71 h->spec.format = PA_SAMPLE_S16LE;
73 debug_msg("SF_INFO : frames = %lld, samplerate = %d, channels = %d, format = 0x%X, sections = %d, seekable = %d",
74 h->si.frames, h->si.samplerate, h->si.channels, h->si.format, h->si.sections, h->si.seekable);
79 static int _sound_rewind(wave_info_t *h)
81 return (sf_seek(h->sf, 0, SEEK_SET) != -1) ? 0 : -1;
84 static int _sound_is_rewind_needed(wave_info_t *h)
86 return (h->repeat_count == -1 || h->repeat_count > 1);
89 static void _sound_unprepare(wave_info_t *h)
97 /* Context Callbacks */
98 static void _pa_context_state_callback(pa_context *c, void *userdata)
100 pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
103 switch (pa_context_get_state(c)) {
104 case PA_CONTEXT_CONNECTING:
105 case PA_CONTEXT_AUTHORIZING:
106 case PA_CONTEXT_SETTING_NAME:
107 debug_log("context(%p), state(%d)", c, pa_context_get_state(c));
110 case PA_CONTEXT_READY:
111 case PA_CONTEXT_TERMINATED:
112 case PA_CONTEXT_FAILED:
113 debug_warning("context(%p), state(%d)", c, pa_context_get_state(c));
114 pa_threaded_mainloop_signal(m, 0);
122 static void *_cleanup_thread_func(void *userdata)
124 pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
127 debug_error("now stop and free threaded_mainloop(%p) here", m);
128 pa_threaded_mainloop_stop(m);
129 pa_threaded_mainloop_free(m);
131 debug_warning("thread mainloop is already null");
137 static void _cleanup_threaded_mainloop(pa_threaded_mainloop *m)
143 ret = pthread_attr_init(&attr);
145 debug_error("failed to init pthread attr!!! errno=%d", ret);
149 ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
151 debug_error("failed to set detach state!!! errno=%d", ret);
155 ret = pthread_create(&thread_id, &attr, _cleanup_thread_func, m);
157 debug_error("failed to create _cleanup_thread_func!!! errno=%d", ret);
160 ret = pthread_attr_destroy(&attr);
162 debug_error("failed to destroy pthread attr!!! errno=%d", ret);
168 static void _pa_context_drain_complete_callback(pa_context *c, void *userdata)
170 debug_msg("context drain completed, cleanup context and mainloop");
172 pa_context_disconnect(c);
175 _cleanup_threaded_mainloop((pa_threaded_mainloop *)userdata);
178 /* Stream Callbacks */
179 static void _pa_stream_state_callback(pa_stream *s, void *userdata)
181 pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
185 switch (pa_stream_get_state(s)) {
186 case PA_STREAM_CREATING:
187 debug_log("stream(%p), state(%d)", s, pa_stream_get_state(s));
189 case PA_STREAM_READY:
190 case PA_STREAM_FAILED:
191 case PA_STREAM_TERMINATED:
192 debug_warning("stream(%p), state(%d)", s, pa_stream_get_state(s));
193 pa_threaded_mainloop_signal(m, 0);
200 static void _pa_stream_drain_complete_callback(pa_stream* s, int success, void *userdata)
202 pa_operation *o = NULL;
203 wave_info_t *h = (wave_info_t *)userdata;
205 debug_msg("drain complete : %p, %d", s, success);
208 debug_error("drain failed. s(%p), success(%d)", s, success);
209 //pa_threaded_mainloop_signal(h->m, 0);
212 pa_stream_disconnect(h->s);
213 pa_stream_unref(h->s);
216 if (!(o = pa_context_drain(h->c, _pa_context_drain_complete_callback, h->m))) {
217 debug_error("failed to drain context!");
218 pa_context_disconnect(h->c);
219 pa_context_unref(h->c);
222 pa_operation_unref(o);
225 debug_msg("Call stop callback(%p, %d) of mgr_codec", h->stop_cb, h->cb_param);
227 h->stop_cb(h->cb_param);
230 static void _pa_stream_moved_callback(pa_stream *s, void *userdata)
233 debug_msg("stream moved callback : %p", s);
236 static void _pa_stream_underflow_callback(pa_stream *s, void *userdata)
238 wave_info_t *h = (wave_info_t *)userdata;
241 debug_msg("stream underflow callback : %p, file(%s)", s, h->filename);
244 static void _pa_stream_buffer_attr_callback(pa_stream *s, void *userdata)
247 debug_msg("stream underflow callback : %p", s);
250 static void _pa_stream_write_callback(pa_stream *s, size_t length, void *userdata)
252 sf_count_t bytes = 0;
254 size_t data_length = 0;
256 pa_operation *o = NULL;
257 wave_info_t *h = (wave_info_t *)userdata;
259 if (!s || length <= 0) {
260 debug_error("write error. stream(%p), length(%d)", s, length);
264 frame_size = pa_frame_size(&h->spec);
265 data_length = length;
267 if (frame_size == 0) {
268 debug_error("frame size can't be 0");
272 if (pa_stream_begin_write(s, &data, &data_length) < 0) {
273 debug_error("failed to pa_stream_begin_write()");
277 if ((bytes = sf_readf_short(h->sf, data, (sf_count_t)(data_length / frame_size))) > 0)
278 bytes *= (sf_count_t)frame_size;
280 debug_log("=== %lld / %d ===", bytes, data_length);
283 pa_stream_write(s, data, (size_t)bytes, NULL, 0, PA_SEEK_RELATIVE);
285 pa_stream_cancel_write(s);
287 /* If No more data, drain stream */
288 if (bytes < (sf_count_t)data_length) {
289 debug_msg("EOS!!!!! %lld/%d", bytes, data_length);
292 if (_sound_is_rewind_needed(h)) {
293 debug_msg("repeat count = %d", h->repeat_count);
294 /* do not decrease it in case of -1 for infinite play */
295 if (h->repeat_count != -1)
298 if (_sound_rewind(h) == 0)
301 debug_error("REWIND failed....");
302 /* can't loop anymore, fallback and do drain */
305 /* EOS callback will be notified after drain is completed */
306 pa_stream_set_write_callback(s, NULL, NULL);
307 o = pa_stream_drain(s, _pa_stream_drain_complete_callback, h);
309 pa_operation_unref(o);
311 debug_error("failed to drain stream %p", s);
315 static int _pa_context_connect(wave_info_t *h)
317 pa_threaded_mainloop *m = NULL;
318 pa_context *c = NULL;
321 if (!(m = pa_threaded_mainloop_new())) {
322 debug_error("mainloop create failed");
327 if (!(c = pa_context_new(pa_threaded_mainloop_get_api(m), NULL))) {
328 debug_error("context create failed");
329 goto error_context_new;
332 pa_context_set_state_callback(c, _pa_context_state_callback, m);
334 pa_threaded_mainloop_lock(m);
336 if (pa_threaded_mainloop_start(m) < 0) {
337 debug_error("mainloop start failed");
341 if (pa_context_connect(c, NULL, 0, NULL) < 0) {
342 debug_error("context connect failed");
347 pa_context_state_t state = pa_context_get_state(c);
348 if (state == PA_CONTEXT_READY)
351 if (!PA_CONTEXT_IS_GOOD(state)) {
352 debug_error("Context error!!!! %d", pa_context_errno(c));
356 pa_threaded_mainloop_wait(m);
362 pa_threaded_mainloop_unlock(m);
368 pa_threaded_mainloop_unlock(m);
370 pa_threaded_mainloop_free(m);
375 static int _pa_stream_connect(wave_info_t *h)
378 pa_proplist *proplist = NULL;
379 pa_stream_state_t state;
381 proplist = pa_proplist_new();
384 pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, h->stream_type);
385 if (h->stream_index != -1)
386 pa_proplist_setf(proplist, PA_PROP_MEDIA_PARENT_ID, "%d", h->stream_index);
388 pa_threaded_mainloop_lock(h->m);
390 s = pa_stream_new_with_proplist(h->c, "wav-player", &h->spec, NULL, proplist);
391 pa_proplist_free(proplist);
393 debug_error("pa_stream_new failed. file(%s)", h->filename);
397 pa_stream_set_state_callback(s, _pa_stream_state_callback, h->m);
398 pa_stream_set_write_callback(s, _pa_stream_write_callback, h);
399 pa_stream_set_moved_callback(s, _pa_stream_moved_callback, h);
400 pa_stream_set_underflow_callback(s, _pa_stream_underflow_callback, h);
401 pa_stream_set_buffer_attr_callback(s, _pa_stream_buffer_attr_callback, h);
403 pa_stream_connect_playback(s, NULL, NULL,
404 PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE,
407 state = pa_stream_get_state(s);
409 if (state == PA_STREAM_READY)
412 if (!PA_STREAM_IS_GOOD(state)) {
413 debug_error("Stream error!!!! %d", state);
417 /* Wait until the stream is ready */
418 pa_threaded_mainloop_wait(h->m);
423 pa_threaded_mainloop_unlock(h->m);
431 pa_threaded_mainloop_unlock(h->m);
436 static void _pa_stream_uncork(wave_info_t *h)
438 pa_operation *o = NULL;
444 pa_threaded_mainloop_lock(h->m);
446 if ((o = pa_stream_cork(h->s, 0, NULL, NULL)))
447 pa_operation_unref(o);
449 debug_error("stream uncork failed");
451 pa_threaded_mainloop_unlock(h->m);
454 static void _pa_stream_stop_disconnect(wave_info_t *h)
459 pa_threaded_mainloop_lock(h->m);
461 pa_stream_disconnect(h->s);
462 pa_stream_unref(h->s);
466 pa_context_disconnect(h->c);
467 pa_context_unref(h->c);
470 pa_threaded_mainloop_unlock(h->m);
472 pa_threaded_mainloop_free(h->m);
476 static int* _mm_sound_plug_codec_wave_get_supported_types(void)
478 static int suported[2] = { MM_SOUND_SUPPORTED_CODEC_WAVE, 0 };
482 static int _mm_sound_plug_codec_wave_parse(const char *filename, mmsound_codec_info_t *info)
487 if (!filename || !info) {
488 debug_error("filename(%p) or info(%p) is invalid...", filename, info);
489 return MM_ERROR_INVALID_ARGUMENT;
492 /* FIXME : following sndfile code should be encapsulated */
493 memset(&si, 0, sizeof(SF_INFO));
494 sf = sf_open(filename, SFM_READ, &si);
496 debug_error("sf_open error. path(%s), error(%d, %s)", filename, sf_error(sf), sf_strerror(sf));
497 if (sf_error(sf) == SF_ERR_SYSTEM)
498 return MM_ERROR_SOUND_INTERNAL;
500 return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
503 info->codec = MM_SOUND_SUPPORTED_CODEC_WAVE;
504 info->channels = si.channels;
505 info->samplerate = si.samplerate;
507 debug_msg("filename = %s, frames[%lld], samplerate[%d], channels[%d], format[%x], sections[%d], seekable[%d]",
508 filename, si.frames, si.samplerate, si.channels, si.format, si.sections, si.seekable);
511 return MM_ERROR_NONE;
514 static int _mm_sound_plug_codec_wave_create(mmsound_codec_param_t *param, mmsound_codec_info_t *info, MMHandleType *handle)
516 wave_info_t* p = NULL;
523 p = (wave_info_t *) malloc(sizeof(wave_info_t));
525 debug_error("memory allocation failed");
526 return MM_ERROR_OUT_OF_MEMORY;
529 memset(p, 0, sizeof(wave_info_t));
531 p->repeat_count = param->repeat_count;
532 p->stop_cb = param->stop_cb;
533 p->cb_param = param->param;
534 MMSOUND_STRNCPY(p->filename, param->pfilename, MM_SOUND_MAX_FILENAME);
535 p->stream_index = param->stream_index;
536 MMSOUND_STRNCPY(p->stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
538 ret = _sound_prepare(p);
540 debug_error("failed to prepare sound");
544 ret = _pa_context_connect(p);
546 debug_error("failed to connect context...");
550 ret = _pa_stream_connect(p);
552 debug_error("failed to connect stream...");
556 *handle = (MMHandleType)p;
559 debug_leave("%p", p);
561 return MM_ERROR_NONE;
566 return MM_ERROR_SOUND_INTERNAL;
570 static int _mm_sound_plug_codec_wave_play(MMHandleType handle)
572 wave_info_t *p = (wave_info_t *) handle;
574 debug_msg("Start handle %p", p);
575 _pa_stream_uncork(p);
577 return MM_ERROR_NONE;
580 static int _mm_sound_plug_codec_wave_stop(MMHandleType handle)
582 wave_info_t *p = (wave_info_t*) handle;
585 debug_error("The handle is null");
586 return MM_ERROR_SOUND_INTERNAL;
589 debug_msg("Handle %p stop requested", p);
591 _pa_stream_stop_disconnect(p);
594 p->stop_cb(p->cb_param);
596 return MM_ERROR_NONE;
599 static int _mm_sound_plug_codec_wave_destroy(MMHandleType handle)
601 wave_info_t *p = (wave_info_t *)handle;
604 debug_error("Can not destroy handle :: handle is invalid");
605 return MM_ERROR_SOUND_INVALID_POINTER;
613 return MM_ERROR_NONE;
617 int MMSoundPlugCodecGetInterface(mmsound_codec_interface_t *intf)
621 intf->GetSupportTypes = _mm_sound_plug_codec_wave_get_supported_types;
622 intf->Parse = _mm_sound_plug_codec_wave_parse;
623 intf->Create = _mm_sound_plug_codec_wave_create;
624 intf->Play = _mm_sound_plug_codec_wave_play;
625 intf->Stop = _mm_sound_plug_codec_wave_stop;
626 intf->Destroy = _mm_sound_plug_codec_wave_destroy;
627 intf->SetThreadPool = NULL;
629 return MM_ERROR_NONE;
633 int MMSoundGetPluginType(void)
635 return MM_SOUND_PLUGIN_TYPE_CODEC;