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
1 /*
2  * libmm-sound
3  *
4  * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact: Seungbae Shin <seungbae.shin@samsung.com>
7  *
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
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
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.
19  *
20  */
21
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <stdint.h>
26
27
28 #include <mm_error.h>
29 #include <mm_debug.h>
30 #include <mm_sound_pa_client.h>
31
32 #include "../../include/mm_sound_plugin_codec.h"
33 #include "../../../include/mm_sound_common.h"
34 #include <unistd.h>
35
36 #include <sndfile.h>
37 #include <pthread.h>
38 #include <pulse/pulseaudio.h>
39
40 typedef struct {
41         int handle;
42         int repeat_count;
43         int (*stop_cb)(int, bool);
44         char filename[MM_SOUND_MAX_FILENAME];
45         int cb_param;
46         char stream_type[MAX_STREAM_TYPE_LEN];
47         int stream_index;
48         int client_pid;
49
50         pa_threaded_mainloop *m;
51         pa_context *c;
52         pa_stream *s;
53         pa_sample_spec spec;
54         SNDFILE *sf;
55         SF_INFO si;
56
57         size_t written;
58 } wave_info_t;
59
60 static int _sound_prepare(wave_info_t *h)
61 {
62         memset(&h->si, 0, sizeof(SF_INFO));
63
64         h->sf = sf_open(h->filename, SFM_READ, &h->si);
65         if (!h->sf) {
66                 debug_error("sf_open error. path(%s), error(%d,%s)", h->filename, sf_error(h->sf), sf_strerror(h->sf));
67                 return (sf_error(h->sf) == SF_ERR_SYSTEM) ? MM_ERROR_SOUND_INTERNAL : MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
68         }
69
70         sf_command(h->sf, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);
71
72         h->spec.rate = h->si.samplerate;
73         h->spec.channels = h->si.channels;
74         h->spec.format = PA_SAMPLE_S16LE;
75
76         debug_msg("SF_INFO : frames = %"PRId64", samplerate = %d, channels = %d, format = 0x%X, sections = %d, seekable = %d",
77                         h->si.frames, h->si.samplerate, h->si.channels, h->si.format, h->si.sections, h->si.seekable);
78
79         return 0;
80 }
81
82 static int _sound_rewind(wave_info_t *h)
83 {
84         return (sf_seek(h->sf, 0, SEEK_SET) != -1) ? 0 : -1;
85 }
86
87 static int _sound_is_rewind_needed(wave_info_t *h)
88 {
89         return (h->repeat_count == -1 || h->repeat_count > 1);
90 }
91
92 static void _sound_unprepare(wave_info_t *h)
93 {
94         if (h->sf) {
95                 sf_close(h->sf);
96                 h->sf = NULL;
97         }
98 }
99
100 /* Context Callbacks */
101 static void _pa_context_state_callback(pa_context *c, void *userdata)
102 {
103         pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
104         assert(c);
105
106         switch (pa_context_get_state(c)) {
107         case PA_CONTEXT_CONNECTING:
108         case PA_CONTEXT_AUTHORIZING:
109         case PA_CONTEXT_SETTING_NAME:
110                 debug_log("context(%p), state(%d)", c, pa_context_get_state(c));
111                 break;
112
113         case PA_CONTEXT_READY:
114         case PA_CONTEXT_TERMINATED:
115         case PA_CONTEXT_FAILED:
116                 debug_warning("context(%p), state(%d)", c, pa_context_get_state(c));
117                 pa_threaded_mainloop_signal(m, 0);
118                 break;
119
120         default:
121                 break;
122         }
123 }
124
125 static void *_cleanup_thread_func(void *userdata)
126 {
127         pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
128
129         if (m) {
130                 debug_error("now stop and free threaded_mainloop(%p) here", m);
131                 pa_threaded_mainloop_stop(m);
132                 pa_threaded_mainloop_free(m);
133         } else {
134                 debug_warning("thread mainloop is already null");
135         }
136
137         pthread_exit(NULL);
138 }
139
140 static void _cleanup_threaded_mainloop(pa_threaded_mainloop *m)
141 {
142         int ret = 0;
143         pthread_t thread_id;
144         pthread_attr_t attr;
145
146         ret = pthread_attr_init(&attr);
147         if (ret != 0) {
148                 debug_error("failed to init pthread attr!!! errno=%d", ret);
149                 return;
150         }
151
152         ret = pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
153         if (ret != 0) {
154                 debug_error("failed to set detach state!!! errno=%d", ret);
155                 goto finish;
156         }
157
158         ret = pthread_create(&thread_id, &attr, _cleanup_thread_func, m);
159         if (ret != 0)
160                 debug_error("failed to create _cleanup_thread_func!!! errno=%d", ret);
161
162 finish:
163         ret = pthread_attr_destroy(&attr);
164         if (ret != 0)
165                 debug_error("failed to destroy pthread attr!!! errno=%d", ret);
166
167         return;
168 }
169
170
171 static void _pa_context_drain_complete_callback(pa_context *c, void *userdata)
172 {
173         debug_msg("context drain completed, cleanup context and mainloop");
174
175         pa_context_disconnect(c);
176         pa_context_unref(c);
177
178         _cleanup_threaded_mainloop((pa_threaded_mainloop *)userdata);
179 }
180
181 /* Stream Callbacks */
182 static void _pa_stream_state_callback(pa_stream *s, void *userdata)
183 {
184         pa_threaded_mainloop *m = (pa_threaded_mainloop *)userdata;
185
186         assert(s);
187
188         switch (pa_stream_get_state(s)) {
189         case PA_STREAM_CREATING:
190                 debug_log("stream(%p), state(%d)", s, pa_stream_get_state(s));
191                 break;
192         case PA_STREAM_READY:
193         case PA_STREAM_FAILED:
194         case PA_STREAM_TERMINATED:
195                 debug_warning("stream(%p), state(%d)", s, pa_stream_get_state(s));
196                 pa_threaded_mainloop_signal(m, 0);
197                 break;
198         default:
199                 break;
200         }
201 }
202
203 static void _pa_stream_drain_complete_callback(pa_stream *s, int success, void *userdata)
204 {
205         pa_operation *o = NULL;
206         wave_info_t *h = (wave_info_t *)userdata;
207
208         debug_msg("stream(%p) : drain completed(%d)", s, success);
209
210         if (!success) {
211                 debug_error("stream(%p) : drain failed(%d)", s, success);
212                 //pa_threaded_mainloop_signal(h->m, 0);
213         }
214
215         pa_stream_disconnect(h->s);
216         pa_stream_unref(h->s);
217         h->s = NULL;
218
219         if (!(o = pa_context_drain(h->c, _pa_context_drain_complete_callback, h->m))) {
220                 debug_error("context(%p) failed to drain context!", h->c);
221                 pa_context_disconnect(h->c);
222                 pa_context_unref(h->c);
223                 h->c = NULL;
224         } else {
225                 pa_operation_unref(o);
226         }
227
228         debug_msg("Invoke stop callback(%p, %d) of mgr_codec", h->stop_cb, h->cb_param);
229         if (h->stop_cb)
230                 h->stop_cb(h->cb_param, false);
231 }
232
233 static void _pa_stream_moved_callback(pa_stream *s, void *userdata)
234 {
235         assert(s);
236         debug_msg("stream(%p)", s);
237 }
238
239 static void _pa_stream_underflow_callback(pa_stream *s, void *userdata)
240 {
241         wave_info_t *h = (wave_info_t *)userdata;
242         assert(s);
243
244         debug_msg("stream(%p) : file(%s)", s, h->filename);
245 }
246
247 static void _pa_stream_buffer_attr_callback(pa_stream *s, void *userdata)
248 {
249         assert(s);
250         debug_msg("stream(%p)", s);
251 }
252
253 static void _pa_stream_started_callback(pa_stream *s, void *userdata)
254 {
255         assert(s);
256         debug_msg("stream(%p)", s);
257 }
258
259 static void _pa_stream_write_callback(pa_stream *s, size_t length, void *userdata)
260 {
261         sf_count_t bytes = 0;
262         void *data = NULL;
263         size_t data_length = 0;
264         size_t frame_size;
265         pa_operation *o = NULL;
266         wave_info_t *h = (wave_info_t *)userdata;
267
268         if (!s || length <= 0) {
269                 debug_error("stream(%p) : length(%zu)", s, length);
270                 return;
271         }
272
273         frame_size = pa_frame_size(&h->spec);
274         data_length = length;
275
276         if (frame_size == 0) {
277                 debug_error("stream(%p) : frame size can't be 0", s);
278                 return;
279         }
280
281         if (pa_stream_begin_write(s, &data, &data_length) < 0) {
282                 debug_error("stream(%p) : failed to pa_stream_begin_write()", s);
283                 return;
284         }
285
286         if ((bytes = sf_readf_short(h->sf, data, (sf_count_t)(data_length / frame_size))) > 0)
287                 bytes *= (sf_count_t)frame_size;
288
289         debug_msg("stream(%p) : === %"PRId64" / %zu / %zu ===", s, bytes, data_length, h->written);
290
291         if (bytes > 0)
292                 pa_stream_write(s, data, (size_t)bytes, NULL, 0, PA_SEEK_RELATIVE);
293         else
294                 pa_stream_cancel_write(s);
295
296         h->written += bytes;
297
298         /* If No more data, drain stream */
299         if (bytes < (sf_count_t)data_length) {
300                 debug_msg("stream(%p) : End Of Stream", s);
301
302                 /* Handle loop */
303                 if (_sound_is_rewind_needed(h)) {
304                         debug_msg("stream(%p) : repeat count = %d", s, h->repeat_count);
305                         /* do not decrease it in case of -1 for infinite play */
306                         if (h->repeat_count != -1)
307                                 h->repeat_count--;
308
309                         if (_sound_rewind(h) == 0)
310                                 return;
311
312                         debug_error("stream(%p) : REWIND failed....", s);
313                         /* can't loop anymore, fallback and do drain */
314                 }
315
316                 /* EOS callback will be notified after drain is completed */
317                 pa_stream_set_write_callback(s, NULL, NULL);
318                 o = pa_stream_drain(s, _pa_stream_drain_complete_callback, h);
319                 if (o)
320                         pa_operation_unref(o);
321                 else
322                         debug_error("stream(%p) : failed to drain", s);
323                 debug_msg("stream(%p) : reset write callback and drain requested", s);
324         }
325 }
326
327 static int _pa_context_connect(wave_info_t *h)
328 {
329         pa_threaded_mainloop *m = NULL;
330         pa_context *c = NULL;
331
332         /* Mainloop */
333         if (!(m = pa_threaded_mainloop_new())) {
334                 debug_error("mainloop create failed");
335                 return -1;
336         }
337
338         /* Context */
339         if (!(c = pa_context_new(pa_threaded_mainloop_get_api(m), NULL))) {
340                 debug_error("context create failed");
341                 goto error_context_new;
342         }
343
344         pa_context_set_state_callback(c, _pa_context_state_callback, m);
345
346         pa_threaded_mainloop_lock(m);
347
348         if (pa_threaded_mainloop_start(m) < 0) {
349                 debug_error("mainloop start failed");
350                 goto error;
351         }
352
353         if (pa_context_connect(c, NULL, 0, NULL) < 0) {
354                 debug_error("context connect failed");
355                 goto error;
356         }
357
358         for (;;) {
359                 pa_context_state_t state = pa_context_get_state(c);
360                 if (state == PA_CONTEXT_READY)
361                         break;
362
363                 if (!PA_CONTEXT_IS_GOOD(state)) {
364                         debug_error("Context error!!!! %d", pa_context_errno(c));
365                         goto error;
366                 }
367
368                 pa_threaded_mainloop_wait(m);
369         }
370
371         h->m = m;
372         h->c = c;
373
374         pa_threaded_mainloop_unlock(m);
375
376         return 0;
377
378 error:
379         pa_context_unref(c);
380         pa_threaded_mainloop_unlock(m);
381 error_context_new:
382         pa_threaded_mainloop_free(m);
383
384         return -1;
385 }
386
387 static int _pa_stream_connect(wave_info_t *h)
388 {
389         int ret = PA_OK;
390         pa_stream *s = NULL;
391         pa_proplist *proplist = NULL;
392         pa_stream_state_t state;
393
394         proplist = pa_proplist_new();
395         if (!proplist)
396                 return -1;
397         pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, h->stream_type);
398         pa_proplist_setf(proplist, PA_PROP_APPLICATION_PROCESS_ID_ORIGIN, "%d", h->client_pid);
399         if (h->stream_index != -1)
400                 pa_proplist_setf(proplist, PA_PROP_MEDIA_PARENT_ID, "%d", h->stream_index);
401
402         pa_threaded_mainloop_lock(h->m);
403
404         s = pa_stream_new_with_proplist(h->c, "wav-player", &h->spec, NULL, proplist);
405         pa_proplist_free(proplist);
406         if (!s) {
407                 debug_error("pa_stream_new failed. file(%s)", h->filename);
408                 goto error;
409         }
410
411         pa_stream_set_state_callback(s, _pa_stream_state_callback, h->m);
412         pa_stream_set_write_callback(s, _pa_stream_write_callback, h);
413         pa_stream_set_moved_callback(s, _pa_stream_moved_callback, h);
414         pa_stream_set_underflow_callback(s, _pa_stream_underflow_callback, h);
415         pa_stream_set_buffer_attr_callback(s, _pa_stream_buffer_attr_callback, h);
416         pa_stream_set_started_callback(s, _pa_stream_started_callback, h);
417
418         ret = pa_stream_connect_playback(s, NULL, NULL,
419                 PA_STREAM_INTERPOLATE_TIMING | PA_STREAM_ADJUST_LATENCY | PA_STREAM_AUTO_TIMING_UPDATE | PA_STREAM_START_CORKED,
420                 NULL, NULL);
421         if (ret < 0) {
422                 debug_error("stream(%p) : failed to connect playback, ret(%d)", s, ret);
423                 goto error;
424         }
425         for (;;) {
426                 state = pa_stream_get_state(s);
427
428                 if (state == PA_STREAM_READY)
429                         break;
430
431                 if (!PA_STREAM_IS_GOOD(state)) {
432                         debug_error("stream(%p) : state(%d)", s, state);
433                         goto error;
434                 }
435
436                 /* Wait until the stream is ready */
437                 pa_threaded_mainloop_wait(h->m);
438         }
439
440         h->s = s;
441
442         pa_threaded_mainloop_unlock(h->m);
443
444         return 0;
445
446 error:
447         if (s)
448                 pa_stream_unref(s);
449
450         pa_threaded_mainloop_unlock(h->m);
451
452         return -1;
453 }
454
455 static void _pa_stream_uncork(wave_info_t *h)
456 {
457         pa_operation *o = NULL;
458
459         assert(h);
460         assert(h->m);
461         assert(h->s);
462
463         pa_threaded_mainloop_lock(h->m);
464
465         if ((o = pa_stream_cork(h->s, 0, NULL, NULL)))
466                 pa_operation_unref(o);
467         else
468                 debug_error("stream(%p) : uncork failed", h->s);
469
470         pa_threaded_mainloop_unlock(h->m);
471 }
472
473 static void _pa_stream_stop_disconnect(wave_info_t *h)
474 {
475         assert(h);
476         assert(h->m);
477
478         pa_threaded_mainloop_lock(h->m);
479         if (h->s) {
480                 pa_stream_disconnect(h->s);
481                 pa_stream_unref(h->s);
482                 h->s = NULL;
483         }
484         if (h->c) {
485                 pa_context_disconnect(h->c);
486                 pa_context_unref(h->c);
487                 h->c = NULL;
488         }
489         pa_threaded_mainloop_unlock(h->m);
490
491         pa_threaded_mainloop_free(h->m);
492         h->m = NULL;
493 }
494
495 static int * _mm_sound_plug_codec_wave_get_supported_types(void)
496 {
497         static int suported[2] = { MM_SOUND_SUPPORTED_CODEC_WAVE, 0 };
498         return suported;
499 }
500
501 static int _mm_sound_plug_codec_wave_parse(const char *filename, mmsound_codec_info_t *info)
502 {
503         SNDFILE *sf = NULL;
504         SF_INFO si;
505
506         if (!filename || !info) {
507                 debug_error("filename(%p) or info(%p) is invalid...", filename, info);
508                 return MM_ERROR_INVALID_ARGUMENT;
509         }
510
511         /* FIXME : following sndfile code should be encapsulated */
512         memset(&si, 0, sizeof(SF_INFO));
513         sf = sf_open(filename, SFM_READ, &si);
514         if (!sf) {
515                 debug_error("sf_open error. path(%s), error(%d, %s)", filename, sf_error(sf), sf_strerror(sf));
516                 if (sf_error(sf) == SF_ERR_SYSTEM)
517                         return MM_ERROR_SOUND_INTERNAL;
518                 else
519                         return MM_ERROR_SOUND_UNSUPPORTED_MEDIA_TYPE;
520         }
521
522         info->codec = MM_SOUND_SUPPORTED_CODEC_WAVE;
523         info->channels = si.channels;
524         info->samplerate = si.samplerate;
525
526         debug_msg("filename[%s], frames[%"PRId64"], samplerate[%d], channels[%d], format[%x], sections[%d], seekable[%d]",
527                         filename, si.frames, si.samplerate, si.channels, si.format, si.sections, si.seekable);
528         sf_close(sf);
529
530         return MM_ERROR_NONE;
531 }
532
533 static int _mm_sound_plug_codec_wave_create(mmsound_codec_param_t *param, mmsound_codec_info_t *info, MMHandleType *handle)
534 {
535         wave_info_t *h = NULL;
536         int ret = 0;
537
538 #ifdef DEBUG_DETAIL
539         debug_enter();
540 #endif
541
542         h = (wave_info_t *)calloc(1, sizeof(wave_info_t));
543         if (h == NULL) {
544                 debug_error("memory allocation failed");
545                 return MM_ERROR_OUT_OF_MEMORY;
546         }
547
548         h->handle = 0;
549         h->repeat_count = param->repeat_count;
550         h->stop_cb = param->stop_cb;
551         h->cb_param = param->param;
552         MMSOUND_STRNCPY(h->filename, param->pfilename, MM_SOUND_MAX_FILENAME);
553         h->client_pid = param->pid;
554         h->stream_index = param->stream_index;
555         MMSOUND_STRNCPY(h->stream_type, param->stream_type, MAX_STREAM_TYPE_LEN);
556
557         ret = _sound_prepare(h);
558         if (ret < 0) {
559                 debug_error("failed to prepare sound");
560                 goto error;
561         }
562
563         ret = _pa_context_connect(h);
564         if (ret < 0) {
565                 debug_error("failed to connect context...");
566                 goto error;
567         }
568
569         ret = _pa_stream_connect(h);
570         if (ret < 0) {
571                 debug_error("failed to connect stream...");
572                 goto error;
573         }
574
575         *handle = (MMHandleType)h;
576
577 #ifdef DEBUG_DETAIL
578         debug_leave("%p", h);
579 #endif
580         return MM_ERROR_NONE;
581
582 error:
583         _sound_unprepare(h);
584         free(h);
585         return MM_ERROR_SOUND_INTERNAL;
586 }
587
588
589 static int _mm_sound_plug_codec_wave_play(MMHandleType handle)
590 {
591         wave_info_t *h = (wave_info_t *)handle;
592
593         debug_msg("Start handle(%p), stream(%p), written(%zu)", h, h->s, h->written);
594         _pa_stream_uncork(h);
595
596         return MM_ERROR_NONE;
597 }
598
599 static int _mm_sound_plug_codec_wave_stop(MMHandleType handle)
600 {
601         wave_info_t *h = (wave_info_t *)handle;
602         if (!h) {
603                 debug_error("The handle is null");
604                 return MM_ERROR_SOUND_INTERNAL;
605         }
606
607         debug_msg("Handle %p stop requested", h);
608
609         _pa_stream_stop_disconnect(h);
610
611         if (h->stop_cb)
612                 h->stop_cb(h->cb_param, true);
613
614         return MM_ERROR_NONE;
615 }
616
617 static int _mm_sound_plug_codec_wave_destroy(MMHandleType handle)
618 {
619         wave_info_t *h = (wave_info_t *)handle;
620
621         if (!h) {
622                 debug_error("Can not destroy handle :: handle is invalid");
623                 return MM_ERROR_SOUND_INVALID_POINTER;
624         }
625
626         _sound_unprepare(h);
627
628         free(h);
629         h = NULL;
630
631         return MM_ERROR_NONE;
632 }
633
634 EXPORT_API
635 int MMSoundPlugCodecGetInterface(mmsound_codec_interface_t *intf)
636 {
637         assert(intf);
638
639         intf->GetSupportTypes   = _mm_sound_plug_codec_wave_get_supported_types;
640         intf->Parse             = _mm_sound_plug_codec_wave_parse;
641         intf->Create            = _mm_sound_plug_codec_wave_create;
642         intf->Play              = _mm_sound_plug_codec_wave_play;
643         intf->Stop              = _mm_sound_plug_codec_wave_stop;
644         intf->Destroy           = _mm_sound_plug_codec_wave_destroy;
645         intf->SetThreadPool     = NULL;
646
647         return MM_ERROR_NONE;
648 }
649
650 EXPORT_API
651 int MMSoundGetPluginType(void)
652 {
653         return MM_SOUND_PLUGIN_TYPE_CODEC;
654 }
655
656