Move out dbus unrelated logic code from client_dbus.c
[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 #define MEDIA_POLICY_AUTO                   "auto"
53 #define MEDIA_POLICY_PHONE                  "phone"
54 #define MEDIA_POLICY_ALL                    "all"
55 #define MEDIA_POLICY_VOIP                   "voip"
56 #define MEDIA_POLICY_MIRRORING              "mirroring"
57 #define MEDIA_POLICY_HIGH_LATENCY           "high-latency"
58
59 typedef struct _mm_sound_handle_t {
60     uint32_t handle;
61
62     int mode;
63     int policy;
64     int volume_type;
65     int gain_type;
66     int rate;
67     int channels;
68     pa_simple* s;
69
70     int period; /* open api retrun value.*/
71
72     unsigned int stream_idx;
73     int source_type;
74 } mm_sound_handle_t;
75
76 #define MM_SOUND_HANDLE_MAX                 32
77 static struct {
78     uint32_t handle_count; /* use amotic operations */
79     GList* handles;
80     pthread_mutex_t lock;
81
82     int state;
83     pa_threaded_mainloop *mainloop;
84     pa_context *context;
85 } mm_sound_handle_mgr;
86
87 #define CHECK_HANDLE_RANGE(x) \
88     do { \
89         if(x == 0) { \
90             debug_msg("invalid handle(%d)", x); \
91             return MM_ERROR_INVALID_ARGUMENT; \
92         } \
93     } while(0);
94
95 #define CHECK_VOLUME_TYPE_RANGE(x) \
96     do { \
97         if(x < VOLUME_TYPE_SYSTEM || x >= VOLUME_TYPE_MAX) { \
98             debug_msg("invalid volume type(%d)", x); \
99             return MM_ERROR_INVALID_ARGUMENT; \
100         } \
101     } while(0);
102
103 #define ATOMIC_INC(l, x) \
104     do { \
105         pthread_mutex_lock(l); \
106         x = x + 1; \
107         if(x == 0) \
108             x = x + 1; \
109         pthread_mutex_unlock(l); \
110     } while(0);
111
112 // phandle(ret), GList, userdata, coimpare func
113 #define GET_HANDLE_DATA(p, l, u, func) \
114     do { \
115         GList* list = 0; \
116         list = g_list_find_custom(l, u, func); \
117         if(list != 0) \
118             p = (mm_sound_handle_t*)list->data; \
119         else \
120             p = NULL; \
121     } while(0);
122
123
124 #define CHECK_CONNECT_TO_PULSEAUDIO()   __mm_sound_pa_connect_to_pa()
125
126 // should be call after pa_ext function.
127 #define WAIT_PULSEAUDIO_OPERATION(x, y) \
128     do { \
129         while (pa_operation_get_state(y) == PA_OPERATION_RUNNING) { \
130             debug_msg("waiting.................."); \
131             pa_threaded_mainloop_wait(x.mainloop); \
132             debug_msg("waiting DONE"); \
133         } \
134     } while(0);
135
136 static const pa_tizen_volume_type_t mm_sound_volume_type_to_pa[VOLUME_TYPE_MAX] = {
137         [VOLUME_TYPE_SYSTEM] = PA_TIZEN_VOLUME_TYPE_SYSTEM,
138         [VOLUME_TYPE_NOTIFICATION] = PA_TIZEN_VOLUME_TYPE_NOTIFICATION,
139         [VOLUME_TYPE_ALARM] = PA_TIZEN_VOLUME_TYPE_ALARM,
140         [VOLUME_TYPE_RINGTONE] = PA_TIZEN_VOLUME_TYPE_RINGTONE,
141         [VOLUME_TYPE_MEDIA] = PA_TIZEN_VOLUME_TYPE_MEDIA,
142         [VOLUME_TYPE_CALL] = PA_TIZEN_VOLUME_TYPE_CALL,
143         [VOLUME_TYPE_VOIP] = PA_TIZEN_VOLUME_TYPE_VOIP,
144         [VOLUME_TYPE_VOICE] = PA_TIZEN_VOLUME_TYPE_VOICE,
145         [VOLUME_TYPE_FIXED] = PA_TIZEN_VOLUME_TYPE_FIXED,
146 };
147
148 #define PA_SIMPLE_FADE_INTERVAL_USEC                                            20000
149
150 #define PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT                            1536    /* frames */
151 #define PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE                           4
152 #define PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT                            6
153 #define PA_SIMPLE_PERIODS_PER_BUFFER_VOIP                                       2
154 #define PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK                           8
155 #define PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE                            12
156 #define PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO                                      10
157
158 #define PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC                     20
159 #define PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC                      25
160 #define PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC                      50
161 #define PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC                     75
162 #define PA_SIMPLE_PERIOD_TIME_FOR_VERY_HIGH_LATENCY_MSEC                150
163 #define PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC                     20
164
165 #define IS_INPUT_HANDLE(x) \
166     if( x == HANDLE_MODE_INPUT || x == HANDLE_MODE_INPUT_HIGH_LATENCY || \
167         x == HANDLE_MODE_INPUT_LOW_LATENCY || x == HANDLE_MODE_INPUT_AP_CALL )
168
169 __attribute__ ((constructor)) void __mm_sound_pa_init(void)
170 {
171     memset(&mm_sound_handle_mgr, 0, sizeof(mm_sound_handle_mgr));
172     mm_sound_handle_mgr.state = FALSE;
173
174     mm_sound_handle_mgr.handles = g_list_alloc();
175     mm_sound_handle_mgr.handle_count = 1;
176     pthread_mutex_init(&mm_sound_handle_mgr.lock, NULL);
177 }
178
179 __attribute__ ((destructor)) void __mm_sound_pa_deinit(void)
180 {
181      g_list_free(mm_sound_handle_mgr.handles);
182      pthread_mutex_destroy(&mm_sound_handle_mgr.lock);
183      mm_sound_handle_mgr.handle_count = 0;
184
185     if(mm_sound_handle_mgr.state) {
186         debug_msg("mainloop(%x),  context(%x)", mm_sound_handle_mgr.mainloop, mm_sound_handle_mgr.context);
187         pa_threaded_mainloop_stop(mm_sound_handle_mgr.mainloop);
188         pa_context_disconnect(mm_sound_handle_mgr.context);
189         pa_context_unref(mm_sound_handle_mgr.context);
190         pa_threaded_mainloop_free(mm_sound_handle_mgr.mainloop);
191     }
192 }
193
194 gint __mm_sound_handle_comparefunc(gconstpointer a, gconstpointer b)
195 {
196     mm_sound_handle_t* phandle = (mm_sound_handle_t*)a;
197     int* handle = (int*)b;
198
199     if(phandle == NULL)
200         return -1;
201
202     if(phandle->handle == *handle)
203         return 0;
204     else
205         return -1;
206 }
207
208 EXPORT_API
209 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)
210 {
211     pa_simple *s = NULL;
212     pa_channel_map maps;
213     pa_buffer_attr attr;
214
215     int vol_conf_type;
216     int prop_vol_type, prop_gain_type;
217
218     int err = MM_ERROR_SOUND_INTERNAL;
219     int period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
220     int samples_per_period = PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT;
221     int periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
222
223     unsigned long latency = 0;
224     int handle_mode = mode;
225     int handle_inout = HANDLE_DIRECTION_NONE;
226     int sample_size = 0;
227     pa_proplist *proplist = pa_proplist_new();
228
229     mm_sound_handle_t* handle = NULL;
230     MMSoundHandleRoutePolicy policy = HANDLE_ROUTE_POLICY_DEFAULT;
231
232     if(route_info) {
233         policy = route_info->policy;
234     }
235
236     if (ss->channels < MM_SOUND_CHANNEL_MIN || ss->channels > MM_SOUND_CHANNEL_MAX)
237         return MM_ERROR_INVALID_ARGUMENT;
238
239     if(channel_map == NULL) {
240         pa_channel_map_init_auto(&maps, ss->channels, PA_CHANNEL_MAP_ALSA);
241         channel_map = &maps;
242     }
243
244     switch(ss->format) {
245         case PA_SAMPLE_U8:
246             sample_size = 1 * ss->channels;
247             break;
248         case PA_SAMPLE_S16LE:
249             sample_size = 2 * ss->channels;
250             break;
251         default :
252             sample_size = 0;
253             debug_error("Invalid sample size (%d)", sample_size);
254             break;
255     }
256
257     /* Set volume type of stream */
258     if(volume_config > 0) {
259         debug_log("setting gain type");
260         vol_conf_type = volume_config & 0x000000FF;
261         prop_vol_type = mm_sound_volume_type_to_pa[vol_conf_type];
262 //          pa_proplist_setf(proplist, PA_PROP_MEDIA_TIZEN_VOLUME_TYPE, "%d", prop_vol_type);
263
264         /* Set gain type of stream */
265         prop_gain_type = (volume_config >> 8) & 0x000000FF;
266
267         pa_proplist_setf(proplist, PA_PROP_MEDIA_TIZEN_GAIN_TYPE, "%d", prop_gain_type);
268     }
269
270     if (stream_index != -1) {
271         char stream_index_s[11];
272         debug_msg("Set stream index [%d]", stream_index);
273
274         snprintf(stream_index_s, sizeof(stream_index_s)-1, "%d", stream_index);
275         debug_msg("stream_index[%d] converted to string[%s]", stream_index, stream_index_s);
276         pa_proplist_sets(proplist, PA_PROP_MEDIA_PARENT_ID, stream_index_s);
277     }
278     /* Set stream type */
279     pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, stream_type);
280
281     memset(&attr, '\0', sizeof(attr));
282
283     switch (handle_mode) {
284     case HANDLE_MODE_INPUT:
285         period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
286         samples_per_period = (ss->rate * period_time) / 1000;
287         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
288         attr.prebuf = 0;
289         attr.minreq = -1;
290         attr.tlength = -1;
291         attr.maxlength = -1;
292         attr.fragsize = samples_per_period * pa_sample_size(ss);
293
294         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "CAPTURE", ss, channel_map, &attr, proplist, &err);
295         break;
296
297     case HANDLE_MODE_INPUT_LOW_LATENCY:
298         period_time = PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC;
299         samples_per_period = (ss->rate * period_time) / 1000;
300         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE;
301         attr.prebuf = 0;
302         attr.minreq = -1;
303         attr.tlength = -1;
304         attr.maxlength = -1;
305         attr.fragsize = samples_per_period * pa_sample_size(ss);
306
307         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "LOW LATENCY CAPTURE", ss, channel_map, &attr, proplist, &err);
308         break;
309
310     case HANDLE_MODE_INPUT_HIGH_LATENCY:
311         period_time = PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
312         samples_per_period = (ss->rate * period_time) / 1000;
313         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE;
314         attr.prebuf = 0;
315         attr.minreq = -1;
316         attr.tlength = -1;
317         attr.maxlength = -1;
318         attr.fragsize = samples_per_period * pa_sample_size(ss);
319
320         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "HIGH LATENCY CAPTURE", ss, channel_map, &attr, proplist, &err);
321         break;
322
323     case HANDLE_MODE_OUTPUT:
324         period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
325         samples_per_period = (ss->rate * period_time) / 1000;
326         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
327         attr.prebuf = -1;
328         attr.minreq = -1;
329         attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
330         attr.maxlength = -1;
331         attr.fragsize = 0;
332
333         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "PLAYBACK", ss, channel_map, &attr, proplist, &err);
334         break;
335
336     case HANDLE_MODE_OUTPUT_LOW_LATENCY:
337         period_time = PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
338         samples_per_period = (ss->rate * period_time) / 1000;
339         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE;
340         attr.prebuf = (ss->rate / 100) * pa_sample_size(ss) * ss->channels;
341         attr.minreq = -1;
342         attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
343         attr.maxlength = -1;
344         attr.fragsize = 0;
345         debug_msg("rate(%d), samplesize(%d), ch(%d) format(%d)", ss->rate, pa_sample_size(ss), ss->channels, ss->format);
346
347         debug_msg("prebuf(%d), minreq(%d), tlength(%d), maxlength(%d), fragsize(%d)", attr.prebuf, attr.minreq, attr.tlength, attr.maxlength, attr.fragsize);
348
349         s = pa_simple_new_proplist(NULL,"MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
350         break;
351
352     case HANDLE_MODE_OUTPUT_CLOCK:
353         period_time = (!latency) ? PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC : latency;
354         samples_per_period = (ss->rate * period_time) / 1000;
355         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK;
356         attr.prebuf = -1;
357         attr.minreq = -1;
358         attr.tlength = (!latency) ? (uint32_t)-1 : periods_per_buffer * samples_per_period * pa_sample_size(ss);
359         attr.maxlength = -1;
360         attr.fragsize = 0;
361
362         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "HIGH LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
363         break;
364
365     case HANDLE_MODE_OUTPUT_VIDEO: /* low latency playback */
366         period_time = PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
367         samples_per_period = (ss->rate * period_time) / 1000;
368         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO;
369         attr.prebuf = 4*(samples_per_period * pa_sample_size(ss));
370         attr.minreq = samples_per_period * pa_sample_size(ss);
371         attr.tlength = periods_per_buffer * samples_per_period * pa_sample_size(ss);
372         attr.maxlength = -1;
373         attr.fragsize = 0;
374
375         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
376         break;
377
378     case HANDLE_MODE_OUTPUT_AP_CALL:
379 #if defined(_MMFW_I386_ALL_SIMULATOR)
380         debug_msg("Does not support AP call mode at i386 simulator\n");
381         s = NULL;
382 #else
383         period_time = PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
384         samples_per_period = (ss->rate * period_time) / 1000;
385         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VOIP;
386         attr.prebuf = -1;
387         attr.minreq = pa_usec_to_bytes(20*PA_USEC_PER_MSEC, ss);
388         attr.tlength = pa_usec_to_bytes(100*PA_USEC_PER_MSEC, ss);
389         attr.maxlength = -1;
390         attr.fragsize = 0;
391
392         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "VoIP PLAYBACK", ss, channel_map, &attr, proplist, &err);
393 #endif
394         break;
395     case HANDLE_MODE_INPUT_AP_CALL:
396 #if defined(_MMFW_I386_ALL_SIMULATOR)
397         debug_msg("Does not support AP call mode at i386 simulator\n");
398         s = NULL;
399 #else
400         period_time = PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
401         samples_per_period = (ss->rate * period_time) / 1000;
402         periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VOIP;
403         attr.prebuf = 0;
404         attr.minreq = -1;
405         attr.tlength = -1;
406         attr.maxlength = -1;
407         attr.fragsize = samples_per_period * pa_sample_size(ss);
408
409         s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "VoIP CAPTURE", ss, channel_map, &attr, proplist, &err);
410 #endif
411         break;
412     case HANDLE_MODE_CALL_OUT:
413     case HANDLE_MODE_CALL_IN:
414         debug_error("Does not support call device handling\n");
415         assert(0);
416         break;
417     default:
418         return MM_ERROR_SOUND_INTERNAL;
419         assert(0);
420         break;
421     }
422
423     if (!s) {
424         debug_error("Open pulseaudio handle has failed - %s\n", pa_strerror(err));
425         if (!strncmp(pa_strerror(err), "Access denied by security check",strlen(pa_strerror(err)))) {
426             err = MM_ERROR_SOUND_PERMISSION_DENIED;
427         } else {
428             err = MM_ERROR_SOUND_INTERNAL;
429         }
430         goto fail;
431     }
432
433     handle = (mm_sound_handle_t*)malloc(sizeof(mm_sound_handle_t));
434
435     handle->mode = mode;
436     handle->policy = policy;
437     handle->volume_type = prop_vol_type;
438     handle->gain_type = prop_gain_type;
439     handle->rate = ss->rate;
440     handle->channels = ss->channels;
441     handle->s = s;
442     handle->period = samples_per_period * sample_size;
443     *size = handle->period;
444     handle->handle = mm_sound_handle_mgr.handle_count;
445     ATOMIC_INC(&mm_sound_handle_mgr.lock, mm_sound_handle_mgr.handle_count); // 0 is not used
446
447     if (0 > pa_simple_get_stream_index(s, &handle->stream_idx, &err)) {
448         debug_msg("Can not get stream index %s\n", pa_strerror(err));
449         err = MM_ERROR_SOUND_INTERNAL;
450         goto fail;
451     }
452     g_list_append(mm_sound_handle_mgr.handles, handle);
453
454     if(handle->handle == 0) {
455         debug_msg("out of range. handle(%d)\n", handle->handle);
456         goto fail;
457     }
458
459     mm_sound_pa_set_mute(handle->handle, prop_vol_type, handle_inout, 0);
460
461     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)",
462         handle->handle, handle->mode, handle->policy, handle->volume_type, handle->gain_type,
463         handle->rate, handle->channels, ss->format, handle->stream_idx, handle->s, handle->source_type, handle_inout);
464
465     return handle->handle;
466
467 fail:
468     if (proplist)
469         pa_proplist_free(proplist);
470
471     if(handle)
472         free(handle);
473
474     return err;
475
476 }
477
478 EXPORT_API
479 int mm_sound_pa_read(const int handle, void* buf, const int size)
480 {
481     mm_sound_handle_t* phandle = NULL;
482     int err = MM_ERROR_NONE;
483
484 #ifdef __STREAM_DEBUG__
485     debug_msg("handle(%d), buf(%p), size(%d)", handle, buf, size);
486 #endif
487     if (buf == NULL)
488         return MM_ERROR_INVALID_ARGUMENT;
489
490     if (size < 0)
491         return MM_ERROR_INVALID_ARGUMENT;
492     else if (size == 0)
493         return size;
494
495     CHECK_HANDLE_RANGE(handle);
496     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
497     if(phandle == NULL) {
498         debug_msg("phandle is null");
499         return MM_ERROR_SOUND_INTERNAL;
500     }
501
502     if (0 > pa_simple_read(phandle->s, buf, size, &err)) {
503         debug_error("pa_simple_read() failed with %s", pa_strerror(err));
504         return MM_ERROR_SOUND_INTERNAL;
505     }
506
507     return size;
508 }
509
510 EXPORT_API
511 int mm_sound_pa_write(const int handle, void* buf, const int size)
512 {
513     mm_sound_handle_t* phandle = NULL;
514     int err = MM_ERROR_NONE;
515
516     if (buf == NULL)
517         return MM_ERROR_INVALID_ARGUMENT;
518
519     if (size < 0)
520         return MM_ERROR_INVALID_ARGUMENT;
521     else if (size == 0)
522         return MM_ERROR_NONE;
523
524     CHECK_HANDLE_RANGE(handle);
525     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
526
527 #ifdef __STREAM_DEBUG__
528     debug_msg("phandle(%x) s(%x), handle(%d), rate(%d), ch(%d) stream_idx(%d), buf(%p), size(%d)",
529         phandle, phandle->s, phandle->handle, phandle->rate, phandle->channels, phandle->stream_idx. buf, size);
530 #endif
531
532     if(phandle == NULL) {
533         debug_msg("phandle is null");
534         return MM_ERROR_SOUND_INTERNAL;
535     }
536
537     if (0 > pa_simple_write(phandle->s, buf, size, &err)) {
538         debug_error("pa_simple_write() failed with %s\n", pa_strerror(err));
539         return MM_ERROR_SOUND_INTERNAL;
540     }
541
542     return size;
543
544 }
545
546 EXPORT_API
547 int mm_sound_pa_close(const int handle)
548 {
549     mm_sound_handle_t* phandle = NULL;
550     int err = MM_ERROR_NONE;
551
552     CHECK_HANDLE_RANGE(handle);
553     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
554     if(phandle == NULL) {
555         debug_msg("phandle is null");
556         return MM_ERROR_SOUND_INTERNAL;
557     }
558
559     debug_msg("phandle(%x) s(%x), handle(%d), rate(%d), ch(%d) stream_idx(%d)",
560             phandle, phandle->s, phandle->handle, phandle->rate, phandle->channels, phandle->stream_idx);
561
562         switch (phandle->mode) {
563         case HANDLE_MODE_OUTPUT:
564         case HANDLE_MODE_OUTPUT_CLOCK:
565         case HANDLE_MODE_OUTPUT_LOW_LATENCY:
566         case HANDLE_MODE_OUTPUT_AP_CALL:
567         case HANDLE_MODE_OUTPUT_VIDEO:
568                 if (0 > pa_simple_flush(phandle->s, &err)) {
569             err = MM_ERROR_SOUND_INTERNAL;
570                         debug_msg("pa_simple_flush() failed with %s\n", pa_strerror(err));
571                 }
572                 break;
573         default:
574                 break;
575         }
576
577         pa_simple_free(phandle->s);
578     phandle->s = NULL;
579
580     debug_msg("leave: handle[%d] stream_index[%d]\n", handle, phandle->stream_idx);
581
582     g_list_remove(mm_sound_handle_mgr.handles, phandle);
583     if(phandle != NULL) {
584         free(phandle);
585         phandle = NULL;
586     }
587
588     return err;
589
590 }
591
592 EXPORT_API
593 int mm_sound_pa_cork(const int handle, const int cork)
594 {
595     mm_sound_handle_t* phandle = NULL;
596     int err = MM_ERROR_NONE;
597
598         CHECK_HANDLE_RANGE(handle);
599     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
600     if(phandle == NULL) {
601         debug_msg("phandle is null");
602         return MM_ERROR_SOUND_INTERNAL;
603     }
604
605     if (0 > pa_simple_cork(phandle->s, cork, &err)) {
606         debug_error("pa_simple_cork() failed with %s\n", pa_strerror(err));
607         err = MM_ERROR_SOUND_INTERNAL;
608     }
609
610         return err;
611 }
612
613 EXPORT_API
614 int mm_sound_pa_drain(const int handle)
615 {
616     mm_sound_handle_t* phandle = NULL;
617     int err = MM_ERROR_NONE;
618
619         CHECK_HANDLE_RANGE(handle);
620     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
621     if(phandle == NULL)
622         return MM_ERROR_SOUND_INTERNAL;
623
624     if (0 > pa_simple_drain(phandle->s, &err)) {
625                 debug_error("pa_simple_drain() failed with %s\n", pa_strerror(err));
626                 err = MM_ERROR_SOUND_INTERNAL;
627         }
628
629         return err;
630 }
631
632 EXPORT_API
633 int mm_sound_pa_flush(const int handle)
634 {
635     mm_sound_handle_t* phandle = NULL;
636     int err = MM_ERROR_NONE;
637
638     CHECK_HANDLE_RANGE(handle);
639     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
640     if(phandle == NULL)
641         return MM_ERROR_SOUND_INTERNAL;
642
643     if (0 > pa_simple_flush(phandle->s, &err)) {
644         debug_error("pa_simple_flush() failed with %s\n", pa_strerror(err));
645         err = MM_ERROR_SOUND_INTERNAL;
646     }
647
648     return err;
649 }
650
651 EXPORT_API
652 int mm_sound_pa_get_latency(const int handle, int* latency)
653 {
654     mm_sound_handle_t* phandle = NULL;
655     int err = MM_ERROR_NONE;
656     pa_usec_t latency_time = 0;
657
658         CHECK_HANDLE_RANGE(handle);
659     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
660     if(phandle == NULL) {
661         debug_msg("phandle is null");
662         return MM_ERROR_SOUND_INTERNAL;
663     }
664
665     latency_time = pa_simple_get_final_latency(phandle->s, &err);
666     if (err > 0 && latency_time == 0) {
667         debug_error("pa_simple_get_latency() failed with %s\n", pa_strerror(err));
668         err = MM_ERROR_SOUND_INTERNAL;
669     }
670     *latency = latency_time / 1000; // usec to msec
671
672     return err;
673 }
674
675 static void __mm_sound_pa_state_cb(pa_context *c, void *userdata)
676 {
677     pa_threaded_mainloop *mainloop = userdata;
678
679     switch (pa_context_get_state(c)) {
680     case PA_CONTEXT_READY:
681         pa_threaded_mainloop_signal(mainloop, 0);
682         break;
683     case PA_CONTEXT_TERMINATED:
684     case PA_CONTEXT_FAILED:
685         pa_threaded_mainloop_signal(mainloop, 0);
686         break;
687
688     case PA_CONTEXT_UNCONNECTED:
689     case PA_CONTEXT_CONNECTING:
690     case PA_CONTEXT_AUTHORIZING:
691     case PA_CONTEXT_SETTING_NAME:
692         break;
693     }
694 }
695
696 static void __mm_sound_pa_connect_to_pa()
697 {
698     if(mm_sound_handle_mgr.state)
699         return;
700
701     if (!(mm_sound_handle_mgr.mainloop = pa_threaded_mainloop_new())) {
702         debug_error("mainloop create failed");
703     }
704
705     if (!(mm_sound_handle_mgr.context = pa_context_new(pa_threaded_mainloop_get_api(mm_sound_handle_mgr.mainloop), NULL))) {
706         debug_error("context create failed");
707     }
708
709     pa_threaded_mainloop_lock(mm_sound_handle_mgr.mainloop);
710     pa_context_set_state_callback(mm_sound_handle_mgr.context, __mm_sound_pa_state_cb, (void *)mm_sound_handle_mgr.mainloop);
711
712     if(pa_threaded_mainloop_start(mm_sound_handle_mgr.mainloop) < 0) {
713         debug_error("mainloop start failed");
714     }
715
716     if (pa_context_connect(mm_sound_handle_mgr.context, NULL, 0, NULL) < 0) {
717         debug_error("context connect failed");
718     }
719
720     while (TRUE) {
721         pa_context_state_t state = pa_context_get_state(mm_sound_handle_mgr.context);
722
723         if (!PA_CONTEXT_IS_GOOD (state)) {
724             break;
725         }
726
727         if (state == PA_CONTEXT_READY) {
728             break;
729         }
730
731         debug_msg("waiting..................");
732         pa_threaded_mainloop_wait(mm_sound_handle_mgr.mainloop);
733         debug_msg("waiting DONE. check again...");
734     }
735
736     mm_sound_handle_mgr.state = TRUE;
737
738     pa_threaded_mainloop_unlock(mm_sound_handle_mgr.mainloop);
739
740 }
741
742 static void __mm_sound_pa_success_cb(pa_context *c, int success, void *userdata)
743 {
744         pa_threaded_mainloop *mainloop = (pa_threaded_mainloop *)userdata;
745
746         if (!success) {
747                 debug_error("pa control failed: %s\n", pa_strerror(pa_context_errno(c)));
748         } else {
749                 debug_msg("pa control success\n");
750         }
751         pa_threaded_mainloop_signal(mainloop, 0);
752 }
753
754 EXPORT_API
755 int mm_sound_pa_set_call_mute(const int type, const int mute, int direction)
756 {
757     pa_operation *o = NULL;
758
759     CHECK_VOLUME_TYPE_RANGE(type);
760     CHECK_CONNECT_TO_PULSEAUDIO();
761
762     pa_threaded_mainloop_lock(mm_sound_handle_mgr.mainloop);
763
764     o = pa_ext_policy_set_mute(mm_sound_handle_mgr.context, -1, type, direction, mute, __mm_sound_pa_success_cb, (void *)mm_sound_handle_mgr.mainloop);
765     WAIT_PULSEAUDIO_OPERATION(mm_sound_handle_mgr, o);
766
767     if(o)
768         pa_operation_unref(o);
769
770     pa_threaded_mainloop_unlock(mm_sound_handle_mgr.mainloop);
771
772     return MM_ERROR_NONE;
773 }
774
775 typedef struct _get_volume_max_userdata_t
776 {
777     pa_threaded_mainloop* mainloop;
778     int value;
779 } get_volume_max_userdata_t;
780
781 static void __mm_sound_pa_get_cb(pa_context *c, uint32_t value, void *userdata)
782 {
783     get_volume_max_userdata_t* u = (get_volume_max_userdata_t*)userdata;
784
785     assert(c);
786     assert(u);
787
788     u->value = value;
789
790     pa_threaded_mainloop_signal(u->mainloop, 0);
791 }
792
793
794 EXPORT_API
795 int mm_sound_pa_get_volume_level(int handle, const int type, int* level)
796 {
797     mm_sound_handle_t* phandle = NULL;
798     get_volume_max_userdata_t userdata;
799     pa_operation *o = NULL;
800
801     CHECK_HANDLE_RANGE(handle);
802     CHECK_VOLUME_TYPE_RANGE(type);
803     CHECK_CONNECT_TO_PULSEAUDIO();
804
805     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
806     if(phandle == NULL) {
807         debug_msg("phandle is null");
808         return MM_ERROR_SOUND_INTERNAL;
809     }
810
811     pa_threaded_mainloop_lock(mm_sound_handle_mgr.mainloop);
812
813     userdata.mainloop = mm_sound_handle_mgr.mainloop;
814     userdata.value = -1;
815
816     o = pa_ext_policy_get_volume_level(mm_sound_handle_mgr.context, phandle->stream_idx, type, __mm_sound_pa_get_cb, (void *)&userdata);
817     WAIT_PULSEAUDIO_OPERATION(mm_sound_handle_mgr, o);
818
819     if(userdata.value < 0) {
820         debug_error("pa_ext_policy_get_volume_level() failed");
821         *level = -1;
822         pa_threaded_mainloop_unlock(mm_sound_handle_mgr.mainloop);
823         return MM_ERROR_SOUND_INTERNAL;
824     } else
825         pa_operation_unref(o);
826
827
828     *level = userdata.value;
829
830     pa_threaded_mainloop_unlock(mm_sound_handle_mgr.mainloop);
831
832     return MM_ERROR_NONE;
833 }
834
835 EXPORT_API
836 int mm_sound_pa_set_volume_level(int handle, const int type, int level)
837 {
838     mm_sound_handle_t* phandle = NULL;
839     pa_operation *o = NULL;
840
841     CHECK_HANDLE_RANGE(handle);
842     CHECK_VOLUME_TYPE_RANGE(type);
843     CHECK_CONNECT_TO_PULSEAUDIO();
844
845     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
846     if(phandle == NULL) {
847         debug_msg("phandle is null");
848         return MM_ERROR_SOUND_INTERNAL;
849     }
850
851     pa_threaded_mainloop_lock(mm_sound_handle_mgr.mainloop);
852
853     o = pa_ext_policy_set_volume_level(mm_sound_handle_mgr.context, phandle->stream_idx, type, level, __mm_sound_pa_success_cb, (void *)mm_sound_handle_mgr.mainloop);
854     WAIT_PULSEAUDIO_OPERATION(mm_sound_handle_mgr, o);
855
856     if(o)
857         pa_operation_unref(o);
858
859     pa_threaded_mainloop_unlock(mm_sound_handle_mgr.mainloop);
860
861     return MM_ERROR_NONE;
862 }
863
864 EXPORT_API
865 int mm_sound_pa_get_mute(int handle, const int type, int direction, int* mute)
866 {
867     mm_sound_handle_t* phandle = NULL;
868     get_volume_max_userdata_t userdata;
869     pa_operation *o = NULL;
870
871     CHECK_HANDLE_RANGE(handle);
872     CHECK_VOLUME_TYPE_RANGE(type);
873     CHECK_CONNECT_TO_PULSEAUDIO();
874
875     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
876     if(phandle == NULL) {
877         debug_msg("phandle is null");
878         return MM_ERROR_SOUND_INTERNAL;
879     }
880
881     pa_threaded_mainloop_lock(mm_sound_handle_mgr.mainloop);
882
883     userdata.mainloop = mm_sound_handle_mgr.mainloop;
884     userdata.value = -1;
885
886     o = pa_ext_policy_get_mute(mm_sound_handle_mgr.context, phandle->stream_idx, type, direction, __mm_sound_pa_get_cb, (void *)&userdata);
887     WAIT_PULSEAUDIO_OPERATION(mm_sound_handle_mgr, o);
888
889     if(userdata.value < 0) {
890         debug_error("mm_sound_pa_get_mute() failed");
891         *mute = -1;
892         pa_threaded_mainloop_unlock(mm_sound_handle_mgr.mainloop);
893         return MM_ERROR_SOUND_INTERNAL;
894     } else
895         pa_operation_unref(o);
896
897     pa_threaded_mainloop_unlock(mm_sound_handle_mgr.mainloop);
898
899     return MM_ERROR_NONE;
900 }
901
902 EXPORT_API
903 int mm_sound_pa_set_mute(int handle, const int type, int direction, int mute)
904 {
905     mm_sound_handle_t* phandle = NULL;
906     pa_operation *o = NULL;
907
908     CHECK_HANDLE_RANGE(handle);
909     CHECK_VOLUME_TYPE_RANGE(type);
910     CHECK_CONNECT_TO_PULSEAUDIO();
911
912     GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
913     if(phandle == NULL) {
914         debug_msg("phandle is null");
915         return MM_ERROR_SOUND_INTERNAL;
916     }
917
918     pa_threaded_mainloop_lock(mm_sound_handle_mgr.mainloop);
919
920     o = pa_ext_policy_set_mute(mm_sound_handle_mgr.context, phandle->stream_idx, type, direction, mute, __mm_sound_pa_success_cb, (void *)mm_sound_handle_mgr.mainloop);
921     WAIT_PULSEAUDIO_OPERATION(mm_sound_handle_mgr, o);
922
923     if(o)
924         pa_operation_unref(o);
925
926     pa_threaded_mainloop_unlock(mm_sound_handle_mgr.mainloop);
927
928     return MM_ERROR_NONE;
929 }
930
931 EXPORT_API
932 int mm_sound_pa_corkall(int cork)
933 {
934     pa_operation *o = NULL;
935
936     CHECK_CONNECT_TO_PULSEAUDIO();
937
938     pa_threaded_mainloop_lock(mm_sound_handle_mgr.mainloop);
939
940     o = pa_context_set_cork_all(mm_sound_handle_mgr.context, cork, __mm_sound_pa_success_cb, (void *)mm_sound_handle_mgr.mainloop);
941     WAIT_PULSEAUDIO_OPERATION(mm_sound_handle_mgr, o);
942
943     if(o)
944         pa_operation_unref(o);
945
946     pa_threaded_mainloop_unlock(mm_sound_handle_mgr.mainloop);
947
948     return MM_ERROR_NONE;
949 }
950