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;
159 int handle_mode = mode;
161 pa_proplist *proplist = NULL;
163 mm_sound_handle_t *handle = NULL;
165 if (ss->channels < MM_SOUND_CHANNEL_MIN || ss->channels > MM_SOUND_CHANNEL_MAX)
166 return MM_ERROR_INVALID_ARGUMENT;
168 proplist = pa_proplist_new();
170 if (channel_map == NULL) {
171 pa_channel_map_init_auto(&maps, ss->channels, PA_CHANNEL_MAP_ALSA);
175 switch (ss->format) {
177 sample_size = 1 * ss->channels;
179 case PA_SAMPLE_S16LE:
180 sample_size = 2 * ss->channels;
184 debug_error("Invalid sample size (%d)", sample_size);
188 if (stream_index != -1) {
189 char stream_index_s[11];
190 debug_msg("Set stream index [%d]", stream_index);
192 snprintf(stream_index_s, sizeof(stream_index_s) - 1, "%d", stream_index);
193 debug_msg("stream_index[%d] converted to string[%s]", stream_index, stream_index_s);
194 pa_proplist_sets(proplist, PA_PROP_MEDIA_PARENT_ID, stream_index_s);
196 /* Set stream type */
197 pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, stream_type);
199 memset(&attr, '\0', sizeof(attr));
201 switch (handle_mode) {
202 case HANDLE_MODE_OUTPUT:
203 period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
204 samples_per_period = (ss->rate * period_time) / 1000;
207 attr.tlength = (ss->rate / 10) * pa_sample_size(ss) * ss->channels;
211 s = pa_simple_new_proplist(NULL, "MM_SOUND_PA_CLIENT", PA_STREAM_PLAYBACK, NULL, "PLAYBACK", ss, channel_map, &attr,
216 err = MM_ERROR_SOUND_INTERNAL;
222 debug_error("Open pulseaudio handle has failed - %s", pa_strerror(err));
223 if (!strncmp(pa_strerror(err), "Access denied by security check", strlen(pa_strerror(err))))
224 err = MM_ERROR_SOUND_PERMISSION_DENIED;
226 err = MM_ERROR_SOUND_INTERNAL;
230 handle = (mm_sound_handle_t *) malloc(sizeof(mm_sound_handle_t));
231 memset(handle, 0, sizeof(mm_sound_handle_t));
233 handle->volume_type = prop_vol_type;
234 handle->gain_type = prop_gain_type;
235 handle->rate = ss->rate;
236 handle->channels = ss->channels;
238 handle->period = samples_per_period * sample_size;
239 *size = handle->period;
240 handle->handle = mm_sound_handle_mgr.handle_count;
241 ATOMIC_INC(&mm_sound_handle_mgr.lock, mm_sound_handle_mgr.handle_count); // 0 is not used
243 mm_sound_handle_mgr.handles = g_list_append(mm_sound_handle_mgr.handles, handle);
245 if (handle->handle == 0) {
246 debug_msg("out of range. handle(%d)", handle->handle);
251 ("created handle[%d]. mode(%d), volumetype(%d), gain(%d), rate(%d), channels(%d), format(%d), s(%p), source_type(%d)",
252 handle->handle, handle->mode, handle->volume_type, handle->gain_type, handle->rate, handle->channels, ss->format,
253 handle->s, handle->source_type);
256 pa_proplist_free(proplist);
258 return handle->handle;
262 pa_proplist_free(proplist);
272 int mm_sound_pa_write(const int handle, void *buf, const int size)
274 mm_sound_handle_t *phandle = NULL;
275 int err = MM_ERROR_NONE;
278 return MM_ERROR_INVALID_ARGUMENT;
281 return MM_ERROR_INVALID_ARGUMENT;
283 return MM_ERROR_NONE;
285 CHECK_HANDLE_RANGE(handle);
286 GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
288 if (phandle == NULL) {
289 debug_msg("phandle is null");
290 return MM_ERROR_SOUND_INTERNAL;
293 if (0 > pa_simple_write(phandle->s, buf, size, &err)) {
294 debug_error("pa_simple_write() failed with %s", pa_strerror(err));
295 return MM_ERROR_SOUND_INTERNAL;
303 int mm_sound_pa_close(const int handle)
305 mm_sound_handle_t *phandle = NULL;
306 int err = MM_ERROR_NONE;
308 CHECK_HANDLE_RANGE(handle);
309 GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
310 if (phandle == NULL) {
311 debug_msg("phandle is null");
312 return MM_ERROR_SOUND_INTERNAL;
315 debug_msg("phandle(%p) s(%p), handle(%d), rate(%d), ch(%d)",
316 phandle, phandle->s, phandle->handle, phandle->rate, phandle->channels);
318 switch (phandle->mode) {
319 case HANDLE_MODE_OUTPUT:
320 if (0 > pa_simple_flush(phandle->s, &err)) {
321 err = MM_ERROR_SOUND_INTERNAL;
322 debug_msg("pa_simple_flush() failed with %s", pa_strerror(err));
329 pa_simple_free(phandle->s);
332 debug_msg("leave: handle[%d]", handle);
334 mm_sound_handle_mgr.handles = g_list_remove(mm_sound_handle_mgr.handles, phandle);
335 if (phandle != NULL) {
345 int mm_sound_pa_drain(const int handle)
347 mm_sound_handle_t *phandle = NULL;
348 int err = MM_ERROR_NONE;
350 CHECK_HANDLE_RANGE(handle);
351 GET_HANDLE_DATA(phandle, mm_sound_handle_mgr.handles, &handle, __mm_sound_handle_comparefunc);
353 return MM_ERROR_SOUND_INTERNAL;
355 if (0 > pa_simple_drain(phandle->s, &err)) {
356 debug_error("pa_simple_drain() failed with %s", pa_strerror(err));
357 err = MM_ERROR_SOUND_INTERNAL;