0d9171a64421b928cd876f2b6be36f523064f50c
[platform/core/multimedia/libmm-sound.git] / mm_sound_pa_client.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
26 #include <mm_error.h>
27 #include <mm_debug.h>
28
29 #include <mm_sound_pa_client.h>
30
31 #include <glib.h>
32
33 #define MM_SOUND_CHANNEL_MIN                1
34 #define MM_SOUND_CHANNEL_MAX                6
35
36 typedef struct _mm_sound_handle_t {
37     uint32_t handle;
38
39     int mode;
40     int volume_type;
41     int gain_type;
42     int rate;
43     int channels;
44     pa_simple* s;
45
46     int period; /* open api retrun value.*/
47
48     unsigned int stream_idx;
49     int source_type;
50 } mm_sound_handle_t;
51
52 #define MM_SOUND_HANDLE_MAX                 32
53 static struct {
54     uint32_t handle_count; /* use amotic operations */
55     GList* handles;
56     pthread_mutex_t lock;
57
58     int state;
59     pa_threaded_mainloop *mainloop;
60     pa_context *context;
61 } mm_sound_handle_mgr;
62
63 #define CHECK_HANDLE_RANGE(x) \
64     do { \
65         if(x == 0) { \
66             debug_msg("invalid handle(%d)", x); \
67             return MM_ERROR_INVALID_ARGUMENT; \
68         } \
69     } while(0);
70
71 #define CHECK_VOLUME_TYPE_RANGE(x) \
72     do { \
73         if(x < VOLUME_TYPE_SYSTEM || x >= VOLUME_TYPE_MAX) { \
74             debug_msg("invalid volume type(%d)", x); \
75             return MM_ERROR_INVALID_ARGUMENT; \
76         } \
77     } while(0);
78
79 #define ATOMIC_INC(l, x) \
80     do { \
81         pthread_mutex_lock(l); \
82         x = x + 1; \
83         if(x == 0) \
84             x = x + 1; \
85         pthread_mutex_unlock(l); \
86     } while(0);
87
88 // phandle(ret), GList, userdata, coimpare func
89 #define GET_HANDLE_DATA(p, l, u, func) \
90     do { \
91         GList* list = 0; \
92         list = g_list_find_custom(l, u, func); \
93         if(list != 0) \
94             p = (mm_sound_handle_t*)list->data; \
95         else \
96             p = NULL; \
97     } while(0);
98
99
100 // should be call after pa_ext function.
101 #define WAIT_PULSEAUDIO_OPERATION(x, y) \
102     do { \
103         while (pa_operation_get_state(y) == PA_OPERATION_RUNNING) { \
104             debug_msg("waiting.................."); \
105             pa_threaded_mainloop_wait(x.mainloop); \
106             debug_msg("waiting DONE"); \
107         } \
108     } while(0);
109
110 #define PA_SIMPLE_FADE_INTERVAL_USEC                                            20000
111
112 #define PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT                            1536    /* frames */
113 #define PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE                           4
114 #define PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT                            6
115 #define PA_SIMPLE_PERIODS_PER_BUFFER_VOIP                                       2
116 #define PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK                           8
117 #define PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE                            12
118 #define PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO                                      10
119
120 #define PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC                     20
121 #define PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC                      25
122 #define PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC                      50
123 #define PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC                     75
124 #define PA_SIMPLE_PERIOD_TIME_FOR_VERY_HIGH_LATENCY_MSEC                150
125 #define PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC                     20
126
127 #define IS_INPUT_HANDLE(x) \
128     if( x == HANDLE_MODE_INPUT || x == HANDLE_MODE_INPUT_HIGH_LATENCY || \
129         x == HANDLE_MODE_INPUT_LOW_LATENCY || x == HANDLE_MODE_INPUT_AP_CALL )
130
131 __attribute__ ((constructor)) void __mm_sound_pa_init(void)
132 {
133     memset(&mm_sound_handle_mgr, 0, sizeof(mm_sound_handle_mgr));
134     mm_sound_handle_mgr.state = FALSE;
135
136     mm_sound_handle_mgr.handles = g_list_alloc();
137     mm_sound_handle_mgr.handle_count = 1;
138     pthread_mutex_init(&mm_sound_handle_mgr.lock, NULL);
139 }
140
141 __attribute__ ((destructor)) void __mm_sound_pa_deinit(void)
142 {
143      g_list_free(mm_sound_handle_mgr.handles);
144      pthread_mutex_destroy(&mm_sound_handle_mgr.lock);
145      mm_sound_handle_mgr.handle_count = 0;
146
147     if(mm_sound_handle_mgr.state) {
148         debug_msg("mainloop(%x),  context(%x)", mm_sound_handle_mgr.mainloop, mm_sound_handle_mgr.context);
149         pa_threaded_mainloop_stop(mm_sound_handle_mgr.mainloop);
150         pa_context_disconnect(mm_sound_handle_mgr.context);
151         pa_context_unref(mm_sound_handle_mgr.context);
152         pa_threaded_mainloop_free(mm_sound_handle_mgr.mainloop);
153     }
154 }
155
156 gint __mm_sound_handle_comparefunc(gconstpointer a, gconstpointer b)
157 {
158     mm_sound_handle_t* phandle = (mm_sound_handle_t*)a;
159     int* handle = (int*)b;
160
161     if(phandle == NULL)
162         return -1;
163
164     if(phandle->handle == *handle)
165         return 0;
166     else
167         return -1;
168 }
169
170 EXPORT_API
171 int mm_sound_pa_open(MMSoundHandleMode mode, int volume_config, pa_sample_spec* ss, pa_channel_map* channel_map, int* size, char *stream_type, int stream_index)
172 {
173     pa_simple *s = NULL;
174     pa_channel_map maps;
175     pa_buffer_attr attr;
176
177     int prop_vol_type = 0;
178     int prop_gain_type = VOLUME_GAIN_DEFAULT;
179
180     int err = MM_ERROR_SOUND_INTERNAL;
181     int period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
182     int samples_per_period = PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT;
183     int periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
184
185     int handle_mode = mode;
186     int sample_size = 0;
187     pa_proplist *proplist = NULL;
188
189     mm_sound_handle_t* handle = NULL;
190
191     if (ss->channels < MM_SOUND_CHANNEL_MIN || ss->channels > MM_SOUND_CHANNEL_MAX)
192         return MM_ERROR_INVALID_ARGUMENT;
193
194     proplist = pa_proplist_new();
195
196     if(channel_map == NULL) {
197         pa_channel_map_init_auto(&maps, ss->channels, PA_CHANNEL_MAP_ALSA);
198         channel_map = &maps;
199     }
200
201     switch(ss->format) {
202         case PA_SAMPLE_U8:
203             sample_size = 1 * ss->channels;
204             break;
205         case PA_SAMPLE_S16LE:
206             sample_size = 2 * ss->channels;
207             break;
208         default :
209             sample_size = 0;
210             debug_error("Invalid sample size (%d)", sample_size);
211             break;
212     }
213
214     /* Set volume type of stream */
215     if(volume_config > 0) {
216         debug_log("setting gain type");
217         prop_vol_type = 0; /* not used, set it system(0) temporarily */
218
219         /* Set gain type of stream */
220         prop_gain_type = (volume_config >> 8) & 0x000000FF;
221
222         pa_proplist_setf(proplist, PA_PROP_MEDIA_TIZEN_GAIN_TYPE, "%d", prop_gain_type);
223     }
224
225     if (stream_index != -1) {
226         char stream_index_s[11];
227         debug_msg("Set stream index [%d]", stream_index);
228
229         snprintf(stream_index_s, sizeof(stream_index_s)-1, "%d", stream_index);
230         debug_msg("stream_index[%d] converted to string[%s]", stream_index, stream_index_s);
231         pa_proplist_sets(proplist, PA_PROP_MEDIA_PARENT_ID, stream_index_s);
232     }
233     /* Set stream type */
234     pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, stream_type);
235
236     memset(&attr, '\0', sizeof(attr));
237
238     switch (handle_mode) {
239     case HANDLE_MODE_INPUT:
240         period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
241         samples_per_period = (ss->rate * period_time) / 1000;
242         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
243         attr.prebuf = 0;
244         attr.minreq = -1;
245         attr.tlength = -1;
246         attr.maxlength = -1;
247         attr.fragsize = samples_per_period * pa_sample_size(ss);
248
249         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "CAPTURE", ss, channel_map, &attr, proplist, &err);
250         break;
251
252     case HANDLE_MODE_INPUT_LOW_LATENCY:
253         period_time = PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC;
254         samples_per_period = (ss->rate * period_time) / 1000;
255         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE;
256         attr.prebuf = 0;
257         attr.minreq = -1;
258         attr.tlength = -1;
259         attr.maxlength = -1;
260         attr.fragsize = samples_per_period * pa_sample_size(ss);
261
262         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "LOW LATENCY CAPTURE", ss, channel_map, &attr, proplist, &err);
263         break;
264
265     case HANDLE_MODE_INPUT_HIGH_LATENCY:
266         period_time = PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
267         samples_per_period = (ss->rate * period_time) / 1000;
268         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE;
269         attr.prebuf = 0;
270         attr.minreq = -1;
271         attr.tlength = -1;
272         attr.maxlength = -1;
273         attr.fragsize = samples_per_period * pa_sample_size(ss);
274
275         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "HIGH LATENCY CAPTURE", ss, channel_map, &attr, proplist, &err);
276         break;
277
278     case HANDLE_MODE_OUTPUT:
279         period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
280         samples_per_period = (ss->rate * period_time) / 1000;
281         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
282         attr.prebuf = -1;
283         attr.minreq = -1;
284         attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
285         attr.maxlength = -1;
286         attr.fragsize = 0;
287
288         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "PLAYBACK", ss, channel_map, &attr, proplist, &err);
289         break;
290
291     case HANDLE_MODE_OUTPUT_LOW_LATENCY:
292         period_time = PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
293         samples_per_period = (ss->rate * period_time) / 1000;
294         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE;
295         attr.prebuf = (ss->rate / 100) * pa_sample_size(ss) * ss->channels;
296         attr.minreq = -1;
297         attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
298         attr.maxlength = -1;
299         attr.fragsize = 0;
300         debug_msg("rate(%d), samplesize(%d), ch(%d) format(%d)", ss->rate, pa_sample_size(ss), ss->channels, ss->format);
301
302         debug_msg("prebuf(%d), minreq(%d), tlength(%d), maxlength(%d), fragsize(%d)", attr.prebuf, attr.minreq, attr.tlength, attr.maxlength, attr.fragsize);
303
304         s = pa_simple_new_proplist(NULL,"MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
305         break;
306
307     case HANDLE_MODE_OUTPUT_CLOCK:
308         period_time = PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
309         samples_per_period = (ss->rate * period_time) / 1000;
310         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK;
311         attr.prebuf = -1;
312         attr.minreq = -1;
313         attr.tlength = (uint32_t)-1;
314         attr.maxlength = -1;
315         attr.fragsize = 0;
316
317         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "HIGH LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
318         break;
319
320     case HANDLE_MODE_OUTPUT_VIDEO: /* low latency playback */
321         period_time = PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
322         samples_per_period = (ss->rate * period_time) / 1000;
323         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO;
324         attr.prebuf = 4*(samples_per_period * pa_sample_size(ss));
325         attr.minreq = samples_per_period * pa_sample_size(ss);
326         attr.tlength = periods_per_buffer * samples_per_period * pa_sample_size(ss);
327         attr.maxlength = -1;
328         attr.fragsize = 0;
329
330         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
331         break;
332
333     case HANDLE_MODE_OUTPUT_AP_CALL:
334 #if defined(_MMFW_I386_ALL_SIMULATOR)
335         debug_msg("Does not support AP call mode at i386 simulator\n");
336         s = NULL;
337 #else
338         period_time = PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
339         samples_per_period = (ss->rate * period_time) / 1000;
340         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VOIP;
341         attr.prebuf = -1;
342         attr.minreq = pa_usec_to_bytes(20*PA_USEC_PER_MSEC, ss);
343         attr.tlength = pa_usec_to_bytes(100*PA_USEC_PER_MSEC, ss);
344         attr.maxlength = -1;
345         attr.fragsize = 0;
346
347         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "VoIP PLAYBACK", ss, channel_map, &attr, proplist, &err);
348 #endif
349         break;
350     case HANDLE_MODE_INPUT_AP_CALL:
351 #if defined(_MMFW_I386_ALL_SIMULATOR)
352         debug_msg("Does not support AP call mode at i386 simulator\n");
353         s = NULL;
354 #else
355         period_time = PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
356         samples_per_period = (ss->rate * period_time) / 1000;
357         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VOIP;
358         attr.prebuf = 0;
359         attr.minreq = -1;
360         attr.tlength = -1;
361         attr.maxlength = -1;
362         attr.fragsize = samples_per_period * pa_sample_size(ss);
363
364         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "VoIP CAPTURE", ss, channel_map, &attr, proplist, &err);
365 #endif
366         break;
367     default:
368         err = MM_ERROR_SOUND_INTERNAL;
369         goto fail;
370         break;
371     }
372
373     if (!s) {
374         debug_error("Open pulseaudio handle has failed - %s\n", pa_strerror(err));
375         if (!strncmp(pa_strerror(err), "Access denied by security check",strlen(pa_strerror(err)))) {
376             err = MM_ERROR_SOUND_PERMISSION_DENIED;
377         } else {
378             err = MM_ERROR_SOUND_INTERNAL;
379         }
380         goto fail;
381     }
382
383     handle = (mm_sound_handle_t*)malloc(sizeof(mm_sound_handle_t));
384     memset(handle, 0, sizeof(mm_sound_handle_t));
385     handle->mode = mode;
386     handle->volume_type = prop_vol_type;
387     handle->gain_type = prop_gain_type;
388     handle->rate = ss->rate;
389     handle->channels = ss->channels;
390     handle->s = s;
391     handle->period = samples_per_period * sample_size;
392     *size = handle->period;
393     handle->handle = mm_sound_handle_mgr.handle_count;
394     ATOMIC_INC(&mm_sound_handle_mgr.lock, mm_sound_handle_mgr.handle_count); // 0 is not used
395
396     if (0 > pa_simple_get_stream_index(s, &handle->stream_idx, &err)) {
397         debug_msg("Can not get stream index %s\n", pa_strerror(err));
398         err = MM_ERROR_SOUND_INTERNAL;
399         goto fail;
400     }
401     mm_sound_handle_mgr.handles = g_list_append(mm_sound_handle_mgr.handles, handle);
402
403     if(handle->handle == 0) {
404         debug_msg("out of range. handle(%d)\n", handle->handle);
405         goto fail;
406     }
407
408     debug_msg("created handle[%d]. mode(%d), volumetype(%d), gain(%d), rate(%d), channels(%d), format(%d), stream_idx(%d), s(%x), source_type(%d)",
409         handle->handle, handle->mode, handle->volume_type, handle->gain_type,
410         handle->rate, handle->channels, ss->format, handle->stream_idx, handle->s, handle->source_type);
411
412     if (proplist)
413         pa_proplist_free(proplist);
414
415     return handle->handle;
416
417 fail:
418     if (proplist)
419         pa_proplist_free(proplist);
420
421     if(handle)
422         free(handle);
423
424     return err;
425
426 }
427
428 EXPORT_API
429 int mm_sound_pa_read(const int handle, void* buf, const int size)
430 {
431     mm_sound_handle_t* phandle = NULL;
432     int err = MM_ERROR_NONE;
433
434 #ifdef __STREAM_DEBUG__
435     debug_msg("handle(%d), buf(%p), size(%d)", handle, buf, size);
436 #endif
437     if (buf == NULL)
438         return MM_ERROR_INVALID_ARGUMENT;
439
440     if (size < 0)
441         return MM_ERROR_INVALID_ARGUMENT;
442     else if (size == 0)
443         return size;
444
445     CHECK_HANDLE_RANGE(handle);
446     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
447     if(phandle == NULL) {
448         debug_msg("phandle is null");
449         return MM_ERROR_SOUND_INTERNAL;
450     }
451
452     if (0 > pa_simple_read(phandle->s, buf, size, &err)) {
453         debug_error("pa_simple_read() failed with %s", pa_strerror(err));
454         return MM_ERROR_SOUND_INTERNAL;
455     }
456
457     return size;
458 }
459
460 EXPORT_API
461 int mm_sound_pa_write(const int handle, void* buf, const int size)
462 {
463     mm_sound_handle_t* phandle = NULL;
464     int err = MM_ERROR_NONE;
465
466     if (buf == NULL)
467         return MM_ERROR_INVALID_ARGUMENT;
468
469     if (size < 0)
470         return MM_ERROR_INVALID_ARGUMENT;
471     else if (size == 0)
472         return MM_ERROR_NONE;
473
474     CHECK_HANDLE_RANGE(handle);
475     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
476
477 #ifdef __STREAM_DEBUG__
478     debug_msg("phandle(%x) s(%x), handle(%d), rate(%d), ch(%d) stream_idx(%d), buf(%p), size(%d)",
479         phandle, phandle->s, phandle->handle, phandle->rate, phandle->channels, phandle->stream_idx. buf, size);
480 #endif
481
482     if(phandle == NULL) {
483         debug_msg("phandle is null");
484         return MM_ERROR_SOUND_INTERNAL;
485     }
486
487     if (0 > pa_simple_write(phandle->s, buf, size, &err)) {
488         debug_error("pa_simple_write() failed with %s\n", pa_strerror(err));
489         return MM_ERROR_SOUND_INTERNAL;
490     }
491
492     return size;
493
494 }
495
496 EXPORT_API
497 int mm_sound_pa_close(const int handle)
498 {
499     mm_sound_handle_t* phandle = NULL;
500     int err = MM_ERROR_NONE;
501
502     CHECK_HANDLE_RANGE(handle);
503     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
504     if(phandle == NULL) {
505         debug_msg("phandle is null");
506         return MM_ERROR_SOUND_INTERNAL;
507     }
508
509     debug_msg("phandle(%x) s(%x), handle(%d), rate(%d), ch(%d) stream_idx(%d)",
510             phandle, phandle->s, phandle->handle, phandle->rate, phandle->channels, phandle->stream_idx);
511
512         switch (phandle->mode) {
513         case HANDLE_MODE_OUTPUT:
514         case HANDLE_MODE_OUTPUT_CLOCK:
515         case HANDLE_MODE_OUTPUT_LOW_LATENCY:
516         case HANDLE_MODE_OUTPUT_AP_CALL:
517         case HANDLE_MODE_OUTPUT_VIDEO:
518                 if (0 > pa_simple_flush(phandle->s, &err)) {
519             err = MM_ERROR_SOUND_INTERNAL;
520                         debug_msg("pa_simple_flush() failed with %s\n", pa_strerror(err));
521                 }
522                 break;
523         default:
524                 break;
525         }
526
527         pa_simple_free(phandle->s);
528     phandle->s = NULL;
529
530     debug_msg("leave: handle[%d] stream_index[%d]\n", handle, phandle->stream_idx);
531
532     mm_sound_handle_mgr.handles = g_list_remove(mm_sound_handle_mgr.handles, phandle);
533     if(phandle != NULL) {
534         free(phandle);
535         phandle = NULL;
536     }
537
538     return err;
539
540 }
541
542 EXPORT_API
543 int mm_sound_pa_drain(const int handle)
544 {
545     mm_sound_handle_t* phandle = NULL;
546     int err = MM_ERROR_NONE;
547
548         CHECK_HANDLE_RANGE(handle);
549     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
550     if(phandle == NULL)
551         return MM_ERROR_SOUND_INTERNAL;
552
553     if (0 > pa_simple_drain(phandle->s, &err)) {
554                 debug_error("pa_simple_drain() failed with %s\n", pa_strerror(err));
555                 err = MM_ERROR_SOUND_INTERNAL;
556         }
557
558         return err;
559 }
560
561 EXPORT_API
562 int mm_sound_pa_flush(const int handle)
563 {
564     mm_sound_handle_t* phandle = NULL;
565     int err = MM_ERROR_NONE;
566
567     CHECK_HANDLE_RANGE(handle);
568     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
569     if(phandle == NULL)
570         return MM_ERROR_SOUND_INTERNAL;
571
572     if (0 > pa_simple_flush(phandle->s, &err)) {
573         debug_error("pa_simple_flush() failed with %s\n", pa_strerror(err));
574         err = MM_ERROR_SOUND_INTERNAL;
575     }
576
577     return err;
578 }
579
580 typedef struct _get_volume_max_userdata_t
581 {
582     pa_threaded_mainloop* mainloop;
583     int value;
584 } get_volume_max_userdata_t;