Fix SVACE
[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 <stdlib.h>
23 #include <string.h>
24 #include <sys/shm.h>
25 #include <sys/mman.h>
26 #include <sys/stat.h>
27 #include <fcntl.h>
28 #include <sys/msg.h>
29 #include <assert.h>
30 #include <errno.h>
31 #include <stdio.h>
32
33 #include <mm_error.h>
34 #include <mm_debug.h>
35
36 #include <mm_session.h>
37 #include <mm_session_private.h>
38 #include <mm_sound_pa_client.h>
39
40 #include <glib.h>
41 #include <pulse/simple.h>
42 #include <pulse/proplist.h>
43
44 #include "include/mm_sound.h"
45 #include "include/mm_sound_private.h"
46 #include "include/mm_sound_utils.h"
47 #include "include/mm_sound_common.h"
48
49 #define MM_SOUND_CHANNEL_MIN                1
50 #define MM_SOUND_CHANNEL_MAX                6
51
52 typedef struct _mm_sound_handle_t {
53     uint32_t handle;
54
55     int mode;
56     int policy;
57     int volume_type;
58     int gain_type;
59     int rate;
60     int channels;
61     pa_simple* s;
62
63     int period; /* open api retrun value.*/
64
65     unsigned int stream_idx;
66     int source_type;
67 } mm_sound_handle_t;
68
69 #define MM_SOUND_HANDLE_MAX                 32
70 static struct {
71     uint32_t handle_count; /* use amotic operations */
72     GList* handles;
73     pthread_mutex_t lock;
74
75     int state;
76     pa_threaded_mainloop *mainloop;
77     pa_context *context;
78 } mm_sound_handle_mgr;
79
80 #define CHECK_HANDLE_RANGE(x) \
81     do { \
82         if(x == 0) { \
83             debug_msg("invalid handle(%d)", x); \
84             return MM_ERROR_INVALID_ARGUMENT; \
85         } \
86     } while(0);
87
88 #define CHECK_VOLUME_TYPE_RANGE(x) \
89     do { \
90         if(x < VOLUME_TYPE_SYSTEM || x >= VOLUME_TYPE_MAX) { \
91             debug_msg("invalid volume type(%d)", x); \
92             return MM_ERROR_INVALID_ARGUMENT; \
93         } \
94     } while(0);
95
96 #define ATOMIC_INC(l, x) \
97     do { \
98         pthread_mutex_lock(l); \
99         x = x + 1; \
100         if(x == 0) \
101             x = x + 1; \
102         pthread_mutex_unlock(l); \
103     } while(0);
104
105 // phandle(ret), GList, userdata, coimpare func
106 #define GET_HANDLE_DATA(p, l, u, func) \
107     do { \
108         GList* list = 0; \
109         list = g_list_find_custom(l, u, func); \
110         if(list != 0) \
111             p = (mm_sound_handle_t*)list->data; \
112         else \
113             p = NULL; \
114     } while(0);
115
116
117 #define CHECK_CONNECT_TO_PULSEAUDIO()   __mm_sound_pa_connect_to_pa()
118
119 // should be call after pa_ext function.
120 #define WAIT_PULSEAUDIO_OPERATION(x, y) \
121     do { \
122         while (pa_operation_get_state(y) == PA_OPERATION_RUNNING) { \
123             debug_msg("waiting.................."); \
124             pa_threaded_mainloop_wait(x.mainloop); \
125             debug_msg("waiting DONE"); \
126         } \
127     } while(0);
128
129 #define PA_SIMPLE_FADE_INTERVAL_USEC                                            20000
130
131 #define PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT                            1536    /* frames */
132 #define PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE                           4
133 #define PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT                            6
134 #define PA_SIMPLE_PERIODS_PER_BUFFER_VOIP                                       2
135 #define PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK                           8
136 #define PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE                            12
137 #define PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO                                      10
138
139 #define PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC                     20
140 #define PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC                      25
141 #define PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC                      50
142 #define PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC                     75
143 #define PA_SIMPLE_PERIOD_TIME_FOR_VERY_HIGH_LATENCY_MSEC                150
144 #define PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC                     20
145
146 #define IS_INPUT_HANDLE(x) \
147     if( x == HANDLE_MODE_INPUT || x == HANDLE_MODE_INPUT_HIGH_LATENCY || \
148         x == HANDLE_MODE_INPUT_LOW_LATENCY || x == HANDLE_MODE_INPUT_AP_CALL )
149
150 __attribute__ ((constructor)) void __mm_sound_pa_init(void)
151 {
152     memset(&mm_sound_handle_mgr, 0, sizeof(mm_sound_handle_mgr));
153     mm_sound_handle_mgr.state = FALSE;
154
155     mm_sound_handle_mgr.handles = g_list_alloc();
156     mm_sound_handle_mgr.handle_count = 1;
157     pthread_mutex_init(&mm_sound_handle_mgr.lock, NULL);
158 }
159
160 __attribute__ ((destructor)) void __mm_sound_pa_deinit(void)
161 {
162      g_list_free(mm_sound_handle_mgr.handles);
163      pthread_mutex_destroy(&mm_sound_handle_mgr.lock);
164      mm_sound_handle_mgr.handle_count = 0;
165
166     if(mm_sound_handle_mgr.state) {
167         debug_msg("mainloop(%x),  context(%x)", mm_sound_handle_mgr.mainloop, mm_sound_handle_mgr.context);
168         pa_threaded_mainloop_stop(mm_sound_handle_mgr.mainloop);
169         pa_context_disconnect(mm_sound_handle_mgr.context);
170         pa_context_unref(mm_sound_handle_mgr.context);
171         pa_threaded_mainloop_free(mm_sound_handle_mgr.mainloop);
172     }
173 }
174
175 gint __mm_sound_handle_comparefunc(gconstpointer a, gconstpointer b)
176 {
177     mm_sound_handle_t* phandle = (mm_sound_handle_t*)a;
178     int* handle = (int*)b;
179
180     if(phandle == NULL)
181         return -1;
182
183     if(phandle->handle == *handle)
184         return 0;
185     else
186         return -1;
187 }
188
189 EXPORT_API
190 int mm_sound_pa_open(MMSoundHandleMode mode, mm_sound_handle_route_info *route_info, MMSoundHandlePriority priority, int volume_config, pa_sample_spec* ss, pa_channel_map* channel_map, int* size, char *stream_type, int stream_index)
191 {
192     pa_simple *s = NULL;
193     pa_channel_map maps;
194     pa_buffer_attr attr;
195
196     int vol_conf_type;
197     int prop_vol_type, prop_gain_type;
198
199     int err = MM_ERROR_SOUND_INTERNAL;
200     int period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
201     int samples_per_period = PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT;
202     int periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
203
204     int handle_mode = mode;
205     int handle_inout = HANDLE_DIRECTION_NONE;
206     int sample_size = 0;
207     pa_proplist *proplist = NULL;
208
209     mm_sound_handle_t* handle = NULL;
210     MMSoundHandleRoutePolicy policy = HANDLE_ROUTE_POLICY_DEFAULT;
211
212     if(route_info) {
213         policy = route_info->policy;
214     }
215
216     if (ss->channels < MM_SOUND_CHANNEL_MIN || ss->channels > MM_SOUND_CHANNEL_MAX)
217         return MM_ERROR_INVALID_ARGUMENT;
218
219     proplist = pa_proplist_new();
220
221     if(channel_map == NULL) {
222         pa_channel_map_init_auto(&maps, ss->channels, PA_CHANNEL_MAP_ALSA);
223         channel_map = &maps;
224     }
225
226     switch(ss->format) {
227         case PA_SAMPLE_U8:
228             sample_size = 1 * ss->channels;
229             break;
230         case PA_SAMPLE_S16LE:
231             sample_size = 2 * ss->channels;
232             break;
233         default :
234             sample_size = 0;
235             debug_error("Invalid sample size (%d)", sample_size);
236             break;
237     }
238
239     /* Set volume type of stream */
240     if(volume_config > 0) {
241         debug_log("setting gain type");
242         prop_vol_type = 0; /* not used, set it system(0) temporarily */
243
244         /* Set gain type of stream */
245         prop_gain_type = (volume_config >> 8) & 0x000000FF;
246
247         pa_proplist_setf(proplist, PA_PROP_MEDIA_TIZEN_GAIN_TYPE, "%d", prop_gain_type);
248     }
249
250     if (stream_index != -1) {
251         char stream_index_s[11];
252         debug_msg("Set stream index [%d]", stream_index);
253
254         snprintf(stream_index_s, sizeof(stream_index_s)-1, "%d", stream_index);
255         debug_msg("stream_index[%d] converted to string[%s]", stream_index, stream_index_s);
256         pa_proplist_sets(proplist, PA_PROP_MEDIA_PARENT_ID, stream_index_s);
257     }
258     /* Set stream type */
259     pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, stream_type);
260
261     memset(&attr, '\0', sizeof(attr));
262
263     switch (handle_mode) {
264     case HANDLE_MODE_INPUT:
265         period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
266         samples_per_period = (ss->rate * period_time) / 1000;
267         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
268         attr.prebuf = 0;
269         attr.minreq = -1;
270         attr.tlength = -1;
271         attr.maxlength = -1;
272         attr.fragsize = samples_per_period * pa_sample_size(ss);
273
274         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "CAPTURE", ss, channel_map, &attr, proplist, &err);
275         break;
276
277     case HANDLE_MODE_INPUT_LOW_LATENCY:
278         period_time = PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC;
279         samples_per_period = (ss->rate * period_time) / 1000;
280         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE;
281         attr.prebuf = 0;
282         attr.minreq = -1;
283         attr.tlength = -1;
284         attr.maxlength = -1;
285         attr.fragsize = samples_per_period * pa_sample_size(ss);
286
287         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "LOW LATENCY CAPTURE", ss, channel_map, &attr, proplist, &err);
288         break;
289
290     case HANDLE_MODE_INPUT_HIGH_LATENCY:
291         period_time = PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
292         samples_per_period = (ss->rate * period_time) / 1000;
293         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE;
294         attr.prebuf = 0;
295         attr.minreq = -1;
296         attr.tlength = -1;
297         attr.maxlength = -1;
298         attr.fragsize = samples_per_period * pa_sample_size(ss);
299
300         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "HIGH LATENCY CAPTURE", ss, channel_map, &attr, proplist, &err);
301         break;
302
303     case HANDLE_MODE_OUTPUT:
304         period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
305         samples_per_period = (ss->rate * period_time) / 1000;
306         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
307         attr.prebuf = -1;
308         attr.minreq = -1;
309         attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
310         attr.maxlength = -1;
311         attr.fragsize = 0;
312
313         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "PLAYBACK", ss, channel_map, &attr, proplist, &err);
314         break;
315
316     case HANDLE_MODE_OUTPUT_LOW_LATENCY:
317         period_time = PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
318         samples_per_period = (ss->rate * period_time) / 1000;
319         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE;
320         attr.prebuf = (ss->rate / 100) * pa_sample_size(ss) * ss->channels;
321         attr.minreq = -1;
322         attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
323         attr.maxlength = -1;
324         attr.fragsize = 0;
325         debug_msg("rate(%d), samplesize(%d), ch(%d) format(%d)", ss->rate, pa_sample_size(ss), ss->channels, ss->format);
326
327         debug_msg("prebuf(%d), minreq(%d), tlength(%d), maxlength(%d), fragsize(%d)", attr.prebuf, attr.minreq, attr.tlength, attr.maxlength, attr.fragsize);
328
329         s = pa_simple_new_proplist(NULL,"MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
330         break;
331
332     case HANDLE_MODE_OUTPUT_CLOCK:
333         period_time = PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
334         samples_per_period = (ss->rate * period_time) / 1000;
335         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK;
336         attr.prebuf = -1;
337         attr.minreq = -1;
338         attr.tlength = (uint32_t)-1;
339         attr.maxlength = -1;
340         attr.fragsize = 0;
341
342         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "HIGH LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
343         break;
344
345     case HANDLE_MODE_OUTPUT_VIDEO: /* low latency playback */
346         period_time = PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
347         samples_per_period = (ss->rate * period_time) / 1000;
348         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO;
349         attr.prebuf = 4*(samples_per_period * pa_sample_size(ss));
350         attr.minreq = samples_per_period * pa_sample_size(ss);
351         attr.tlength = periods_per_buffer * samples_per_period * pa_sample_size(ss);
352         attr.maxlength = -1;
353         attr.fragsize = 0;
354
355         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
356         break;
357
358     case HANDLE_MODE_OUTPUT_AP_CALL:
359 #if defined(_MMFW_I386_ALL_SIMULATOR)
360         debug_msg("Does not support AP call mode at i386 simulator\n");
361         s = NULL;
362 #else
363         period_time = PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
364         samples_per_period = (ss->rate * period_time) / 1000;
365         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VOIP;
366         attr.prebuf = -1;
367         attr.minreq = pa_usec_to_bytes(20*PA_USEC_PER_MSEC, ss);
368         attr.tlength = pa_usec_to_bytes(100*PA_USEC_PER_MSEC, ss);
369         attr.maxlength = -1;
370         attr.fragsize = 0;
371
372         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "VoIP PLAYBACK", ss, channel_map, &attr, proplist, &err);
373 #endif
374         break;
375     case HANDLE_MODE_INPUT_AP_CALL:
376 #if defined(_MMFW_I386_ALL_SIMULATOR)
377         debug_msg("Does not support AP call mode at i386 simulator\n");
378         s = NULL;
379 #else
380         period_time = PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
381         samples_per_period = (ss->rate * period_time) / 1000;
382         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VOIP;
383         attr.prebuf = 0;
384         attr.minreq = -1;
385         attr.tlength = -1;
386         attr.maxlength = -1;
387         attr.fragsize = samples_per_period * pa_sample_size(ss);
388
389         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "VoIP CAPTURE", ss, channel_map, &attr, proplist, &err);
390 #endif
391         break;
392     case HANDLE_MODE_CALL_OUT:
393     case HANDLE_MODE_CALL_IN:
394         debug_error("Does not support call device handling\n");
395         assert(0);
396         break;
397     default:
398         return MM_ERROR_SOUND_INTERNAL;
399         assert(0);
400         break;
401     }
402
403     if (!s) {
404         debug_error("Open pulseaudio handle has failed - %s\n", pa_strerror(err));
405         if (!strncmp(pa_strerror(err), "Access denied by security check",strlen(pa_strerror(err)))) {
406             err = MM_ERROR_SOUND_PERMISSION_DENIED;
407         } else {
408             err = MM_ERROR_SOUND_INTERNAL;
409         }
410         goto fail;
411     }
412
413     handle = (mm_sound_handle_t*)malloc(sizeof(mm_sound_handle_t));
414
415     handle->mode = mode;
416     handle->policy = policy;
417     handle->volume_type = prop_vol_type;
418     handle->gain_type = prop_gain_type;
419     handle->rate = ss->rate;
420     handle->channels = ss->channels;
421     handle->s = s;
422     handle->period = samples_per_period * sample_size;
423     *size = handle->period;
424     handle->handle = mm_sound_handle_mgr.handle_count;
425     ATOMIC_INC(&mm_sound_handle_mgr.lock, mm_sound_handle_mgr.handle_count); // 0 is not used
426
427     if (0 > pa_simple_get_stream_index(s, &handle->stream_idx, &err)) {
428         debug_msg("Can not get stream index %s\n", pa_strerror(err));
429         err = MM_ERROR_SOUND_INTERNAL;
430         goto fail;
431     }
432     g_list_append(mm_sound_handle_mgr.handles, handle);
433
434     if(handle->handle == 0) {
435         debug_msg("out of range. handle(%d)\n", handle->handle);
436         goto fail;
437     }
438
439     debug_msg("created handle[%d]. mode(%d), policy(%d), volumetype(%d), gain(%d), rate(%d), channels(%d), format(%d), stream_idx(%d), s(%x), source_type(%d) handle_inout(%d)",
440         handle->handle, handle->mode, handle->policy, handle->volume_type, handle->gain_type,
441         handle->rate, handle->channels, ss->format, handle->stream_idx, handle->s, handle->source_type, handle_inout);
442
443     return handle->handle;
444
445 fail:
446     if (proplist)
447         pa_proplist_free(proplist);
448
449     if(handle)
450         free(handle);
451
452     return err;
453
454 }
455
456 EXPORT_API
457 int mm_sound_pa_read(const int handle, void* buf, const int size)
458 {
459     mm_sound_handle_t* phandle = NULL;
460     int err = MM_ERROR_NONE;
461
462 #ifdef __STREAM_DEBUG__
463     debug_msg("handle(%d), buf(%p), size(%d)", handle, buf, size);
464 #endif
465     if (buf == NULL)
466         return MM_ERROR_INVALID_ARGUMENT;
467
468     if (size < 0)
469         return MM_ERROR_INVALID_ARGUMENT;
470     else if (size == 0)
471         return size;
472
473     CHECK_HANDLE_RANGE(handle);
474     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
475     if(phandle == NULL) {
476         debug_msg("phandle is null");
477         return MM_ERROR_SOUND_INTERNAL;
478     }
479
480     if (0 > pa_simple_read(phandle->s, buf, size, &err)) {
481         debug_error("pa_simple_read() failed with %s", pa_strerror(err));
482         return MM_ERROR_SOUND_INTERNAL;
483     }
484
485     return size;
486 }
487
488 EXPORT_API
489 int mm_sound_pa_write(const int handle, void* buf, const int size)
490 {
491     mm_sound_handle_t* phandle = NULL;
492     int err = MM_ERROR_NONE;
493
494     if (buf == NULL)
495         return MM_ERROR_INVALID_ARGUMENT;
496
497     if (size < 0)
498         return MM_ERROR_INVALID_ARGUMENT;
499     else if (size == 0)
500         return 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
505 #ifdef __STREAM_DEBUG__
506     debug_msg("phandle(%x) s(%x), handle(%d), rate(%d), ch(%d) stream_idx(%d), buf(%p), size(%d)",
507         phandle, phandle->s, phandle->handle, phandle->rate, phandle->channels, phandle->stream_idx. buf, size);
508 #endif
509
510     if(phandle == NULL) {
511         debug_msg("phandle is null");
512         return MM_ERROR_SOUND_INTERNAL;
513     }
514
515     if (0 > pa_simple_write(phandle->s, buf, size, &err)) {
516         debug_error("pa_simple_write() failed with %s\n", pa_strerror(err));
517         return MM_ERROR_SOUND_INTERNAL;
518     }
519
520     return size;
521
522 }
523
524 EXPORT_API
525 int mm_sound_pa_close(const int handle)
526 {
527     mm_sound_handle_t* phandle = NULL;
528     int err = MM_ERROR_NONE;
529
530     CHECK_HANDLE_RANGE(handle);
531     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
532     if(phandle == NULL) {
533         debug_msg("phandle is null");
534         return MM_ERROR_SOUND_INTERNAL;
535     }
536
537     debug_msg("phandle(%x) s(%x), handle(%d), rate(%d), ch(%d) stream_idx(%d)",
538             phandle, phandle->s, phandle->handle, phandle->rate, phandle->channels, phandle->stream_idx);
539
540         switch (phandle->mode) {
541         case HANDLE_MODE_OUTPUT:
542         case HANDLE_MODE_OUTPUT_CLOCK:
543         case HANDLE_MODE_OUTPUT_LOW_LATENCY:
544         case HANDLE_MODE_OUTPUT_AP_CALL:
545         case HANDLE_MODE_OUTPUT_VIDEO:
546                 if (0 > pa_simple_flush(phandle->s, &err)) {
547             err = MM_ERROR_SOUND_INTERNAL;
548                         debug_msg("pa_simple_flush() failed with %s\n", pa_strerror(err));
549                 }
550                 break;
551         default:
552                 break;
553         }
554
555         pa_simple_free(phandle->s);
556     phandle->s = NULL;
557
558     debug_msg("leave: handle[%d] stream_index[%d]\n", handle, phandle->stream_idx);
559
560     g_list_remove(mm_sound_handle_mgr.handles, phandle);
561     if(phandle != NULL) {
562         free(phandle);
563         phandle = NULL;
564     }
565
566     return err;
567
568 }
569
570 EXPORT_API
571 int mm_sound_pa_cork(const int handle, const int cork)
572 {
573     mm_sound_handle_t* phandle = NULL;
574     int err = MM_ERROR_NONE;
575
576         CHECK_HANDLE_RANGE(handle);
577     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
578     if(phandle == NULL) {
579         debug_msg("phandle is null");
580         return MM_ERROR_SOUND_INTERNAL;
581     }
582
583     if (0 > pa_simple_cork(phandle->s, cork, &err)) {
584         debug_error("pa_simple_cork() failed with %s\n", pa_strerror(err));
585         err = MM_ERROR_SOUND_INTERNAL;
586     }
587
588         return err;
589 }
590
591 EXPORT_API
592 int mm_sound_pa_drain(const int handle)
593 {
594     mm_sound_handle_t* phandle = NULL;
595     int err = MM_ERROR_NONE;
596
597         CHECK_HANDLE_RANGE(handle);
598     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
599     if(phandle == NULL)
600         return MM_ERROR_SOUND_INTERNAL;
601
602     if (0 > pa_simple_drain(phandle->s, &err)) {
603                 debug_error("pa_simple_drain() failed with %s\n", pa_strerror(err));
604                 err = MM_ERROR_SOUND_INTERNAL;
605         }
606
607         return err;
608 }
609
610 EXPORT_API
611 int mm_sound_pa_flush(const int handle)
612 {
613     mm_sound_handle_t* phandle = NULL;
614     int err = MM_ERROR_NONE;
615
616     CHECK_HANDLE_RANGE(handle);
617     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
618     if(phandle == NULL)
619         return MM_ERROR_SOUND_INTERNAL;
620
621     if (0 > pa_simple_flush(phandle->s, &err)) {
622         debug_error("pa_simple_flush() failed with %s\n", pa_strerror(err));
623         err = MM_ERROR_SOUND_INTERNAL;
624     }
625
626     return err;
627 }
628
629 EXPORT_API
630 int mm_sound_pa_get_latency(const int handle, int* latency)
631 {
632     mm_sound_handle_t* phandle = NULL;
633     int err = MM_ERROR_NONE;
634     pa_usec_t latency_time = 0;
635
636         CHECK_HANDLE_RANGE(handle);
637     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
638     if(phandle == NULL) {
639         debug_msg("phandle is null");
640         return MM_ERROR_SOUND_INTERNAL;
641     }
642
643     latency_time = pa_simple_get_final_latency(phandle->s, &err);
644     if (err > 0 && latency_time == 0) {
645         debug_error("pa_simple_get_latency() failed with %s\n", pa_strerror(err));
646         err = MM_ERROR_SOUND_INTERNAL;
647     }
648     *latency = latency_time / 1000; // usec to msec
649
650     return err;
651 }
652
653 static void __mm_sound_pa_state_cb(pa_context *c, void *userdata)
654 {
655     pa_threaded_mainloop *mainloop = userdata;
656
657     switch (pa_context_get_state(c)) {
658     case PA_CONTEXT_READY:
659         pa_threaded_mainloop_signal(mainloop, 0);
660         break;
661     case PA_CONTEXT_TERMINATED:
662     case PA_CONTEXT_FAILED:
663         pa_threaded_mainloop_signal(mainloop, 0);
664         break;
665
666     case PA_CONTEXT_UNCONNECTED:
667     case PA_CONTEXT_CONNECTING:
668     case PA_CONTEXT_AUTHORIZING:
669     case PA_CONTEXT_SETTING_NAME:
670         break;
671     }
672 }
673
674 static void __mm_sound_pa_connect_to_pa()
675 {
676     if(mm_sound_handle_mgr.state)
677         return;
678
679     if (!(mm_sound_handle_mgr.mainloop = pa_threaded_mainloop_new())) {
680         debug_error("mainloop create failed");
681     }
682
683     if (!(mm_sound_handle_mgr.context = pa_context_new(pa_threaded_mainloop_get_api(mm_sound_handle_mgr.mainloop), NULL))) {
684         debug_error("context create failed");
685     }
686
687     pa_threaded_mainloop_lock(mm_sound_handle_mgr.mainloop);
688     pa_context_set_state_callback(mm_sound_handle_mgr.context, __mm_sound_pa_state_cb, (void *)mm_sound_handle_mgr.mainloop);
689
690     if(pa_threaded_mainloop_start(mm_sound_handle_mgr.mainloop) < 0) {
691         debug_error("mainloop start failed");
692     }
693
694     if (pa_context_connect(mm_sound_handle_mgr.context, NULL, 0, NULL) < 0) {
695         debug_error("context connect failed");
696     }
697
698     while (TRUE) {
699         pa_context_state_t state = pa_context_get_state(mm_sound_handle_mgr.context);
700
701         if (!PA_CONTEXT_IS_GOOD (state)) {
702             break;
703         }
704
705         if (state == PA_CONTEXT_READY) {
706             break;
707         }
708
709         debug_msg("waiting..................");
710         pa_threaded_mainloop_wait(mm_sound_handle_mgr.mainloop);
711         debug_msg("waiting DONE. check again...");
712     }
713
714     mm_sound_handle_mgr.state = TRUE;
715
716     pa_threaded_mainloop_unlock(mm_sound_handle_mgr.mainloop);
717
718 }
719
720 static void __mm_sound_pa_success_cb(pa_context *c, int success, void *userdata)
721 {
722         pa_threaded_mainloop *mainloop = (pa_threaded_mainloop *)userdata;
723
724         if (!success) {
725                 debug_error("pa control failed: %s\n", pa_strerror(pa_context_errno(c)));
726         } else {
727                 debug_msg("pa control success\n");
728         }
729         pa_threaded_mainloop_signal(mainloop, 0);
730 }
731
732 typedef struct _get_volume_max_userdata_t
733 {
734     pa_threaded_mainloop* mainloop;
735     int value;
736 } get_volume_max_userdata_t;
737
738 static void __mm_sound_pa_get_cb(pa_context *c, uint32_t value, void *userdata)
739 {
740     get_volume_max_userdata_t* u = (get_volume_max_userdata_t*)userdata;
741
742     assert(c);
743     assert(u);
744
745     u->value = value;
746
747     pa_threaded_mainloop_signal(u->mainloop, 0);
748 }
749
750 EXPORT_API
751 int mm_sound_pa_corkall(int cork)
752 {
753     pa_operation *o = NULL;
754
755     CHECK_CONNECT_TO_PULSEAUDIO();
756
757     pa_threaded_mainloop_lock(mm_sound_handle_mgr.mainloop);
758
759     o = pa_context_set_cork_all(mm_sound_handle_mgr.context, cork, __mm_sound_pa_success_cb, (void *)mm_sound_handle_mgr.mainloop);
760     WAIT_PULSEAUDIO_OPERATION(mm_sound_handle_mgr, o);
761
762     if(o)
763         pa_operation_unref(o);
764
765     pa_threaded_mainloop_unlock(mm_sound_handle_mgr.mainloop);
766
767     return MM_ERROR_NONE;
768 }
769