4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Seungbae Shin <seungbae.shin@samsung.com>
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
36 #include <mm_session.h>
37 #include <mm_session_private.h>
38 #include <mm_sound_pa_client.h>
41 #include <pulse/simple.h>
42 #include <pulse/proplist.h>
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"
49 #define MM_SOUND_CHANNEL_MIN 1
50 #define MM_SOUND_CHANNEL_MAX 6
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"
59 typedef struct _mm_sound_handle_t {
70 int period; /* open api retrun value.*/
72 unsigned int stream_idx;
76 #define MM_SOUND_HANDLE_MAX 32
78 uint32_t handle_count; /* use amotic operations */
83 pa_threaded_mainloop *mainloop;
85 } mm_sound_handle_mgr;
87 #define CHECK_HANDLE_RANGE(x) \
90 debug_msg("invalid handle(%d)", x); \
91 return MM_ERROR_INVALID_ARGUMENT; \
95 #define CHECK_VOLUME_TYPE_RANGE(x) \
97 if(x < VOLUME_TYPE_SYSTEM || x >= VOLUME_TYPE_MAX) { \
98 debug_msg("invalid volume type(%d)", x); \
99 return MM_ERROR_INVALID_ARGUMENT; \
103 #define ATOMIC_INC(l, x) \
105 pthread_mutex_lock(l); \
109 pthread_mutex_unlock(l); \
112 // phandle(ret), GList, userdata, coimpare func
113 #define GET_HANDLE_DATA(p, l, u, func) \
116 list = g_list_find_custom(l, u, func); \
118 p = (mm_sound_handle_t*)list->data; \
124 #define CHECK_CONNECT_TO_PULSEAUDIO() __mm_sound_pa_connect_to_pa()
126 // should be call after pa_ext function.
127 #define WAIT_PULSEAUDIO_OPERATION(x, y) \
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"); \
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,
148 #define PA_SIMPLE_FADE_INTERVAL_USEC 20000
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
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
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 )
169 __attribute__ ((constructor)) void __mm_sound_pa_init(void)
171 memset(&mm_sound_handle_mgr, 0, sizeof(mm_sound_handle_mgr));
172 mm_sound_handle_mgr.state = FALSE;
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);
179 __attribute__ ((destructor)) void __mm_sound_pa_deinit(void)
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;
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);
194 gint __mm_sound_handle_comparefunc(gconstpointer a, gconstpointer b)
196 mm_sound_handle_t* phandle = (mm_sound_handle_t*)a;
197 int* handle = (int*)b;
202 if(phandle->handle == *handle)
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)
216 int prop_vol_type, prop_gain_type;
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;
223 unsigned long latency = 0;
224 int handle_mode = mode;
225 int handle_inout = HANDLE_DIRECTION_NONE;
227 pa_proplist *proplist = pa_proplist_new();
229 mm_sound_handle_t* handle = NULL;
230 MMSoundHandleRoutePolicy policy = HANDLE_ROUTE_POLICY_DEFAULT;
233 policy = route_info->policy;
236 if (ss->channels < MM_SOUND_CHANNEL_MIN || ss->channels > MM_SOUND_CHANNEL_MAX)
237 return MM_ERROR_INVALID_ARGUMENT;
239 if(channel_map == NULL) {
240 pa_channel_map_init_auto(&maps, ss->channels, PA_CHANNEL_MAP_ALSA);
246 sample_size = 1 * ss->channels;
248 case PA_SAMPLE_S16LE:
249 sample_size = 2 * ss->channels;
253 debug_error("Invalid sample size (%d)", sample_size);
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);
264 /* Set gain type of stream */
265 prop_gain_type = (volume_config >> 8) & 0x000000FF;
267 pa_proplist_setf(proplist, PA_PROP_MEDIA_TIZEN_GAIN_TYPE, "%d", prop_gain_type);
270 if (stream_index != -1) {
271 char stream_index_s[11];
272 debug_msg("Set stream index [%d]", stream_index);
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);
278 /* Set stream type */
279 pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, stream_type);
281 memset(&attr, '\0', sizeof(attr));
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;
292 attr.fragsize = samples_per_period * pa_sample_size(ss);
294 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "CAPTURE", ss, channel_map, &attr, proplist, &err);
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;
305 attr.fragsize = samples_per_period * pa_sample_size(ss);
307 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "LOW LATENCY CAPTURE", ss, channel_map, &attr, proplist, &err);
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;
318 attr.fragsize = samples_per_period * pa_sample_size(ss);
320 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "HIGH LATENCY CAPTURE", ss, channel_map, &attr, proplist, &err);
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;
329 attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
333 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "PLAYBACK", ss, channel_map, &attr, proplist, &err);
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;
342 attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
345 debug_msg("rate(%d), samplesize(%d), ch(%d) format(%d)", ss->rate, pa_sample_size(ss), ss->channels, ss->format);
347 debug_msg("prebuf(%d), minreq(%d), tlength(%d), maxlength(%d), fragsize(%d)", attr.prebuf, attr.minreq, attr.tlength, attr.maxlength, attr.fragsize);
349 s = pa_simple_new_proplist(NULL,"MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
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;
358 attr.tlength = (!latency) ? (uint32_t)-1 : periods_per_buffer * samples_per_period * pa_sample_size(ss);
362 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "HIGH LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
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);
375 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", ss, channel_map, &attr, proplist, &err);
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");
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;
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);
392 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "VoIP PLAYBACK", ss, channel_map, &attr, proplist, &err);
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");
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;
407 attr.fragsize = samples_per_period * pa_sample_size(ss);
409 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "VoIP CAPTURE", ss, channel_map, &attr, proplist, &err);
412 case HANDLE_MODE_CALL_OUT:
413 case HANDLE_MODE_CALL_IN:
414 debug_error("Does not support call device handling\n");
418 return MM_ERROR_SOUND_INTERNAL;
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;
428 err = MM_ERROR_SOUND_INTERNAL;
433 handle = (mm_sound_handle_t*)malloc(sizeof(mm_sound_handle_t));
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;
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
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;
452 g_list_append(mm_sound_handle_mgr.handles, handle);
454 if(handle->handle == 0) {
455 debug_msg("out of range. handle(%d)\n", handle->handle);
459 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)",
460 handle->handle, handle->mode, handle->policy, handle->volume_type, handle->gain_type,
461 handle->rate, handle->channels, ss->format, handle->stream_idx, handle->s, handle->source_type, handle_inout);
463 return handle->handle;
467 pa_proplist_free(proplist);
477 int mm_sound_pa_read(const int handle, void* buf, const int size)
479 mm_sound_handle_t* phandle = NULL;
480 int err = MM_ERROR_NONE;
482 #ifdef __STREAM_DEBUG__
483 debug_msg("handle(%d), buf(%p), size(%d)", handle, buf, size);
486 return MM_ERROR_INVALID_ARGUMENT;
489 return MM_ERROR_INVALID_ARGUMENT;
493 CHECK_HANDLE_RANGE(handle);
494 GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
495 if(phandle == NULL) {
496 debug_msg("phandle is null");
497 return MM_ERROR_SOUND_INTERNAL;
500 if (0 > pa_simple_read(phandle->s, buf, size, &err)) {
501 debug_error("pa_simple_read() failed with %s", pa_strerror(err));
502 return MM_ERROR_SOUND_INTERNAL;
509 int mm_sound_pa_write(const int handle, void* buf, const int size)
511 mm_sound_handle_t* phandle = NULL;
512 int err = MM_ERROR_NONE;
515 return MM_ERROR_INVALID_ARGUMENT;
518 return MM_ERROR_INVALID_ARGUMENT;
520 return MM_ERROR_NONE;
522 CHECK_HANDLE_RANGE(handle);
523 GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
525 #ifdef __STREAM_DEBUG__
526 debug_msg("phandle(%x) s(%x), handle(%d), rate(%d), ch(%d) stream_idx(%d), buf(%p), size(%d)",
527 phandle, phandle->s, phandle->handle, phandle->rate, phandle->channels, phandle->stream_idx. buf, size);
530 if(phandle == NULL) {
531 debug_msg("phandle is null");
532 return MM_ERROR_SOUND_INTERNAL;
535 if (0 > pa_simple_write(phandle->s, buf, size, &err)) {
536 debug_error("pa_simple_write() failed with %s\n", pa_strerror(err));
537 return MM_ERROR_SOUND_INTERNAL;
545 int mm_sound_pa_close(const int handle)
547 mm_sound_handle_t* phandle = NULL;
548 int err = MM_ERROR_NONE;
550 CHECK_HANDLE_RANGE(handle);
551 GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
552 if(phandle == NULL) {
553 debug_msg("phandle is null");
554 return MM_ERROR_SOUND_INTERNAL;
557 debug_msg("phandle(%x) s(%x), handle(%d), rate(%d), ch(%d) stream_idx(%d)",
558 phandle, phandle->s, phandle->handle, phandle->rate, phandle->channels, phandle->stream_idx);
560 switch (phandle->mode) {
561 case HANDLE_MODE_OUTPUT:
562 case HANDLE_MODE_OUTPUT_CLOCK:
563 case HANDLE_MODE_OUTPUT_LOW_LATENCY:
564 case HANDLE_MODE_OUTPUT_AP_CALL:
565 case HANDLE_MODE_OUTPUT_VIDEO:
566 if (0 > pa_simple_flush(phandle->s, &err)) {
567 err = MM_ERROR_SOUND_INTERNAL;
568 debug_msg("pa_simple_flush() failed with %s\n", pa_strerror(err));
575 pa_simple_free(phandle->s);
578 debug_msg("leave: handle[%d] stream_index[%d]\n", handle, phandle->stream_idx);
580 g_list_remove(mm_sound_handle_mgr.handles, phandle);
581 if(phandle != NULL) {
591 int mm_sound_pa_cork(const int handle, const int cork)
593 mm_sound_handle_t* phandle = NULL;
594 int err = MM_ERROR_NONE;
596 CHECK_HANDLE_RANGE(handle);
597 GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
598 if(phandle == NULL) {
599 debug_msg("phandle is null");
600 return MM_ERROR_SOUND_INTERNAL;
603 if (0 > pa_simple_cork(phandle->s, cork, &err)) {
604 debug_error("pa_simple_cork() failed with %s\n", pa_strerror(err));
605 err = MM_ERROR_SOUND_INTERNAL;
612 int mm_sound_pa_drain(const int handle)
614 mm_sound_handle_t* phandle = NULL;
615 int err = MM_ERROR_NONE;
617 CHECK_HANDLE_RANGE(handle);
618 GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
620 return MM_ERROR_SOUND_INTERNAL;
622 if (0 > pa_simple_drain(phandle->s, &err)) {
623 debug_error("pa_simple_drain() failed with %s\n", pa_strerror(err));
624 err = MM_ERROR_SOUND_INTERNAL;
631 int mm_sound_pa_flush(const int handle)
633 mm_sound_handle_t* phandle = NULL;
634 int err = MM_ERROR_NONE;
636 CHECK_HANDLE_RANGE(handle);
637 GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
639 return MM_ERROR_SOUND_INTERNAL;
641 if (0 > pa_simple_flush(phandle->s, &err)) {
642 debug_error("pa_simple_flush() failed with %s\n", pa_strerror(err));
643 err = MM_ERROR_SOUND_INTERNAL;
650 int mm_sound_pa_get_latency(const int handle, int* latency)
652 mm_sound_handle_t* phandle = NULL;
653 int err = MM_ERROR_NONE;
654 pa_usec_t latency_time = 0;
656 CHECK_HANDLE_RANGE(handle);
657 GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
658 if(phandle == NULL) {
659 debug_msg("phandle is null");
660 return MM_ERROR_SOUND_INTERNAL;
663 latency_time = pa_simple_get_final_latency(phandle->s, &err);
664 if (err > 0 && latency_time == 0) {
665 debug_error("pa_simple_get_latency() failed with %s\n", pa_strerror(err));
666 err = MM_ERROR_SOUND_INTERNAL;
668 *latency = latency_time / 1000; // usec to msec
673 static void __mm_sound_pa_state_cb(pa_context *c, void *userdata)
675 pa_threaded_mainloop *mainloop = userdata;
677 switch (pa_context_get_state(c)) {
678 case PA_CONTEXT_READY:
679 pa_threaded_mainloop_signal(mainloop, 0);
681 case PA_CONTEXT_TERMINATED:
682 case PA_CONTEXT_FAILED:
683 pa_threaded_mainloop_signal(mainloop, 0);
686 case PA_CONTEXT_UNCONNECTED:
687 case PA_CONTEXT_CONNECTING:
688 case PA_CONTEXT_AUTHORIZING:
689 case PA_CONTEXT_SETTING_NAME:
694 static void __mm_sound_pa_connect_to_pa()
696 if(mm_sound_handle_mgr.state)
699 if (!(mm_sound_handle_mgr.mainloop = pa_threaded_mainloop_new())) {
700 debug_error("mainloop create failed");
703 if (!(mm_sound_handle_mgr.context = pa_context_new(pa_threaded_mainloop_get_api(mm_sound_handle_mgr.mainloop), NULL))) {
704 debug_error("context create failed");
707 pa_threaded_mainloop_lock(mm_sound_handle_mgr.mainloop);
708 pa_context_set_state_callback(mm_sound_handle_mgr.context, __mm_sound_pa_state_cb, (void *)mm_sound_handle_mgr.mainloop);
710 if(pa_threaded_mainloop_start(mm_sound_handle_mgr.mainloop) < 0) {
711 debug_error("mainloop start failed");
714 if (pa_context_connect(mm_sound_handle_mgr.context, NULL, 0, NULL) < 0) {
715 debug_error("context connect failed");
719 pa_context_state_t state = pa_context_get_state(mm_sound_handle_mgr.context);
721 if (!PA_CONTEXT_IS_GOOD (state)) {
725 if (state == PA_CONTEXT_READY) {
729 debug_msg("waiting..................");
730 pa_threaded_mainloop_wait(mm_sound_handle_mgr.mainloop);
731 debug_msg("waiting DONE. check again...");
734 mm_sound_handle_mgr.state = TRUE;
736 pa_threaded_mainloop_unlock(mm_sound_handle_mgr.mainloop);
740 static void __mm_sound_pa_success_cb(pa_context *c, int success, void *userdata)
742 pa_threaded_mainloop *mainloop = (pa_threaded_mainloop *)userdata;
745 debug_error("pa control failed: %s\n", pa_strerror(pa_context_errno(c)));
747 debug_msg("pa control success\n");
749 pa_threaded_mainloop_signal(mainloop, 0);
752 typedef struct _get_volume_max_userdata_t
754 pa_threaded_mainloop* mainloop;
756 } get_volume_max_userdata_t;
758 static void __mm_sound_pa_get_cb(pa_context *c, uint32_t value, void *userdata)
760 get_volume_max_userdata_t* u = (get_volume_max_userdata_t*)userdata;
767 pa_threaded_mainloop_signal(u->mainloop, 0);
771 int mm_sound_pa_corkall(int cork)
773 pa_operation *o = NULL;
775 CHECK_CONNECT_TO_PULSEAUDIO();
777 pa_threaded_mainloop_lock(mm_sound_handle_mgr.mainloop);
779 o = pa_context_set_cork_all(mm_sound_handle_mgr.context, cork, __mm_sound_pa_success_cb, (void *)mm_sound_handle_mgr.mainloop);
780 WAIT_PULSEAUDIO_OPERATION(mm_sound_handle_mgr, o);
783 pa_operation_unref(o);
785 pa_threaded_mainloop_unlock(mm_sound_handle_mgr.mainloop);
787 return MM_ERROR_NONE;