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.
29 #include <mm_sound_pa_client.h>
33 #define MM_SOUND_CHANNEL_MIN 1
34 #define MM_SOUND_CHANNEL_MAX 6
36 typedef struct _mm_sound_handle_t {
46 int period; /* open api retrun value. */
52 uint32_t handle_count; /* use amotic operations */
57 pa_threaded_mainloop *mainloop;
59 } mm_sound_handle_mgr;
61 #define CHECK_HANDLE_RANGE(x) \
64 debug_msg("invalid handle(%d)", x); \
65 return MM_ERROR_INVALID_ARGUMENT; \
69 #define ATOMIC_INC(l, x) \
71 pthread_mutex_lock(l); \
75 pthread_mutex_unlock(l); \
78 // phandle(ret), GList, userdata, coimpare func
79 #define GET_HANDLE_DATA(p, l, u, func) \
82 list = g_list_find_custom(l, u, func); \
84 p = (mm_sound_handle_t*)list->data; \
89 #define PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT 1536 /* frames */
90 #define PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE 4
91 #define PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT 6
92 #define PA_SIMPLE_PERIODS_PER_BUFFER_VOIP 2
93 #define PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK 8
94 #define PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE 12
95 #define PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO 10
97 #define PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC 20
98 #define PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC 25
99 #define PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC 50
100 #define PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC 75
101 #define PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC 20
103 __attribute__ ((constructor))
104 void __mm_sound_pa_init(void)
106 memset(&mm_sound_handle_mgr, 0, sizeof(mm_sound_handle_mgr));
107 mm_sound_handle_mgr.state = FALSE;
109 mm_sound_handle_mgr.handles = g_list_alloc();
110 mm_sound_handle_mgr.handle_count = 1;
111 pthread_mutex_init(&mm_sound_handle_mgr.lock, NULL);
114 __attribute__ ((destructor))
115 void __mm_sound_pa_deinit(void)
117 g_list_free(mm_sound_handle_mgr.handles);
118 pthread_mutex_destroy(&mm_sound_handle_mgr.lock);
119 mm_sound_handle_mgr.handle_count = 0;
121 if (mm_sound_handle_mgr.state) {
122 debug_msg("mainloop(%p), context(%p)", mm_sound_handle_mgr.mainloop, mm_sound_handle_mgr.context);
123 pa_threaded_mainloop_stop(mm_sound_handle_mgr.mainloop);
124 pa_context_disconnect(mm_sound_handle_mgr.context);
125 pa_context_unref(mm_sound_handle_mgr.context);
126 pa_threaded_mainloop_free(mm_sound_handle_mgr.mainloop);
130 gint __mm_sound_handle_comparefunc(gconstpointer a, gconstpointer b)
132 mm_sound_handle_t *phandle = (mm_sound_handle_t *) a;
133 int *handle = (int *)b;
138 if (phandle->handle == *handle)
145 int mm_sound_pa_open(MMSoundHandleMode mode, int volume_config, pa_sample_spec * ss, pa_channel_map * channel_map,
146 int *size, char *stream_type, int stream_index)
152 int prop_vol_type = 0;
153 int prop_gain_type = VOLUME_GAIN_DEFAULT;
155 int err = MM_ERROR_SOUND_INTERNAL;
156 int period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
157 int samples_per_period = PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT;
158 int periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
160 int handle_mode = mode;
162 pa_proplist *proplist = NULL;
164 mm_sound_handle_t *handle = NULL;
166 if (ss->channels < MM_SOUND_CHANNEL_MIN || ss->channels > MM_SOUND_CHANNEL_MAX)
167 return MM_ERROR_INVALID_ARGUMENT;
169 proplist = pa_proplist_new();
171 if (channel_map == NULL) {
172 pa_channel_map_init_auto(&maps, ss->channels, PA_CHANNEL_MAP_ALSA);
176 switch (ss->format) {
178 sample_size = 1 * ss->channels;
180 case PA_SAMPLE_S16LE:
181 sample_size = 2 * ss->channels;
185 debug_error("Invalid sample size (%d)", sample_size);
189 if (stream_index != -1) {
190 char stream_index_s[11];
191 debug_msg("Set stream index [%d]", stream_index);
193 snprintf(stream_index_s, sizeof(stream_index_s) - 1, "%d", stream_index);
194 debug_msg("stream_index[%d] converted to string[%s]", stream_index, stream_index_s);
195 pa_proplist_sets(proplist, PA_PROP_MEDIA_PARENT_ID, stream_index_s);
197 /* Set stream type */
198 pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, stream_type);
200 memset(&attr, '\0', sizeof(attr));
202 switch (handle_mode) {
203 case HANDLE_MODE_INPUT:
204 period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
205 samples_per_period = (ss->rate * period_time) / 1000;
206 periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
211 attr.fragsize = samples_per_period * pa_sample_size(ss);
213 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "CAPTURE", ss, channel_map, &attr,
217 case HANDLE_MODE_INPUT_LOW_LATENCY:
218 period_time = PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC;
219 samples_per_period = (ss->rate * period_time) / 1000;
220 periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE;
225 attr.fragsize = samples_per_period * pa_sample_size(ss);
227 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "LOW LATENCY CAPTURE", ss, channel_map,
228 &attr, proplist, &err);
231 case HANDLE_MODE_INPUT_HIGH_LATENCY:
232 period_time = PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
233 samples_per_period = (ss->rate * period_time) / 1000;
234 periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE;
239 attr.fragsize = samples_per_period * pa_sample_size(ss);
241 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "HIGH LATENCY CAPTURE", ss, channel_map,
242 &attr, proplist, &err);
245 case HANDLE_MODE_OUTPUT:
246 period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
247 samples_per_period = (ss->rate * period_time) / 1000;
248 periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
251 attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
255 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "PLAYBACK", ss, channel_map, &attr,
259 case HANDLE_MODE_OUTPUT_LOW_LATENCY:
260 period_time = PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC;
261 samples_per_period = (ss->rate * period_time) / 1000;
262 periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE;
263 attr.prebuf = (ss->rate / 100) * pa_sample_size(ss) * ss->channels;
265 attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
268 debug_msg("rate(%d), samplesize(%zu), ch(%d) format(%d)", ss->rate, pa_sample_size(ss), ss->channels, ss->format);
270 debug_msg("prebuf(%d), minreq(%d), tlength(%d), maxlength(%d), fragsize(%d)", attr.prebuf, attr.minreq, attr.tlength,
271 attr.maxlength, attr.fragsize);
273 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", ss,
274 channel_map, &attr, proplist, &err);
277 case HANDLE_MODE_OUTPUT_CLOCK:
278 period_time = PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
279 samples_per_period = (ss->rate * period_time) / 1000;
280 periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK;
283 attr.tlength = (uint32_t) - 1;
287 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "HIGH LATENCY PLAYBACK", ss,
288 channel_map, &attr, proplist, &err);
291 case HANDLE_MODE_OUTPUT_VIDEO: /* low latency playback */
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_VIDEO;
295 attr.prebuf = 4 * (samples_per_period * pa_sample_size(ss));
296 attr.minreq = samples_per_period * pa_sample_size(ss);
297 attr.tlength = periods_per_buffer * samples_per_period * pa_sample_size(ss);
301 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", ss,
302 channel_map, &attr, proplist, &err);
305 case HANDLE_MODE_OUTPUT_AP_CALL:
306 #if defined(_MMFW_I386_ALL_SIMULATOR)
307 debug_msg("Does not support AP call mode at i386 simulator");
310 period_time = PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
311 samples_per_period = (ss->rate * period_time) / 1000;
312 periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VOIP;
314 attr.minreq = pa_usec_to_bytes(20 * PA_USEC_PER_MSEC, ss);
315 attr.tlength = pa_usec_to_bytes(100 * PA_USEC_PER_MSEC, ss);
319 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "VoIP PLAYBACK", ss, channel_map,
320 &attr, proplist, &err);
323 case HANDLE_MODE_INPUT_AP_CALL:
324 #if defined(_MMFW_I386_ALL_SIMULATOR)
325 debug_msg("Does not support AP call mode at i386 simulator");
328 period_time = PA_SIMPLE_PERIOD_TIME_FOR_VOIP_LATENCY_MSEC;
329 samples_per_period = (ss->rate * period_time) / 1000;
330 periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_VOIP;
335 attr.fragsize = samples_per_period * pa_sample_size(ss);
337 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_RECORD, NULL, "VoIP CAPTURE", ss, channel_map, &attr,
342 err = MM_ERROR_SOUND_INTERNAL;
348 debug_error("Open pulseaudio handle has failed - %s", pa_strerror(err));
349 if (!strncmp(pa_strerror(err), "Access denied by security check", strlen(pa_strerror(err))))
350 err = MM_ERROR_SOUND_PERMISSION_DENIED;
352 err = MM_ERROR_SOUND_INTERNAL;
356 handle = (mm_sound_handle_t *) malloc(sizeof(mm_sound_handle_t));
357 memset(handle, 0, sizeof(mm_sound_handle_t));
359 handle->volume_type = prop_vol_type;
360 handle->gain_type = prop_gain_type;
361 handle->rate = ss->rate;
362 handle->channels = ss->channels;
364 handle->period = samples_per_period * sample_size;
365 *size = handle->period;
366 handle->handle = mm_sound_handle_mgr.handle_count;
367 ATOMIC_INC(&mm_sound_handle_mgr.lock, mm_sound_handle_mgr.handle_count); // 0 is not used
369 mm_sound_handle_mgr.handles = g_list_append(mm_sound_handle_mgr.handles, handle);
371 if (handle->handle == 0) {
372 debug_msg("out of range. handle(%d)", handle->handle);
377 ("created handle[%d]. mode(%d), volumetype(%d), gain(%d), rate(%d), channels(%d), format(%d), s(%p), source_type(%d)",
378 handle->handle, handle->mode, handle->volume_type, handle->gain_type, handle->rate, handle->channels, ss->format,
379 handle->s, handle->source_type);
382 pa_proplist_free(proplist);
384 return handle->handle;
388 pa_proplist_free(proplist);
398 int mm_sound_pa_write(const int handle, void *buf, const int size)
400 mm_sound_handle_t *phandle = NULL;
401 int err = MM_ERROR_NONE;
404 return MM_ERROR_INVALID_ARGUMENT;
407 return MM_ERROR_INVALID_ARGUMENT;
409 return MM_ERROR_NONE;
411 CHECK_HANDLE_RANGE(handle);
412 GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
414 if (phandle == NULL) {
415 debug_msg("phandle is null");
416 return MM_ERROR_SOUND_INTERNAL;
419 if (0 > pa_simple_write(phandle->s, buf, size, &err)) {
420 debug_error("pa_simple_write() failed with %s", pa_strerror(err));
421 return MM_ERROR_SOUND_INTERNAL;
429 int mm_sound_pa_close(const int handle)
431 mm_sound_handle_t *phandle = NULL;
432 int err = MM_ERROR_NONE;
434 CHECK_HANDLE_RANGE(handle);
435 GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
436 if (phandle == NULL) {
437 debug_msg("phandle is null");
438 return MM_ERROR_SOUND_INTERNAL;
441 debug_msg("phandle(%p) s(%p), handle(%d), rate(%d), ch(%d)",
442 phandle, phandle->s, phandle->handle, phandle->rate, phandle->channels);
444 switch (phandle->mode) {
445 case HANDLE_MODE_OUTPUT:
446 case HANDLE_MODE_OUTPUT_CLOCK:
447 case HANDLE_MODE_OUTPUT_LOW_LATENCY:
448 case HANDLE_MODE_OUTPUT_AP_CALL:
449 case HANDLE_MODE_OUTPUT_VIDEO:
450 if (0 > pa_simple_flush(phandle->s, &err)) {
451 err = MM_ERROR_SOUND_INTERNAL;
452 debug_msg("pa_simple_flush() failed with %s", pa_strerror(err));
459 pa_simple_free(phandle->s);
462 debug_msg("leave: handle[%d]", handle);
464 mm_sound_handle_mgr.handles = g_list_remove(mm_sound_handle_mgr.handles, phandle);
465 if (phandle != NULL) {
475 int mm_sound_pa_drain(const int handle)
477 mm_sound_handle_t *phandle = NULL;
478 int err = MM_ERROR_NONE;
480 CHECK_HANDLE_RANGE(handle);
481 GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
483 return MM_ERROR_SOUND_INTERNAL;
485 if (0 > pa_simple_drain(phandle->s, &err)) {
486 debug_error("pa_simple_drain() failed with %s", pa_strerror(err));
487 err = MM_ERROR_SOUND_INTERNAL;