4 * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. All rights reserved.
6 * Contact: Jonghyuk Choi <jhchoi.choi@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.
25 #include "avsys-audio-pasimple.h"
26 #include "avsys-types.h"
27 #include "avsys-error.h"
28 #include "avsys-debug.h"
30 #ifndef MURPHY_SUPPORT
31 #define PA_PROP_MEDIA_POLICY "media.policy"
34 #define PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT 1536 /* frames */
35 #define PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE 4
36 #define PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT 6
37 #define PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK 8
38 #define PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE 12
39 #define PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO 10
41 #define PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC 20
42 #define PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC 25
43 #define PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC 50
44 #define PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC 75
46 #define MSEC_TO_SAMPLE(samplerate,period_time) (samplerate*period_time/1000)
48 #define CHECK_VALID_HANDLE(handle) \
50 if (handle == NULL) { \
51 return AVSYS_STATE_ERR_NULL_POINTER; \
53 device = (avsys_audio_pasimple_handle_t *)handle->device; \
54 if (device == NULL) { \
55 return AVSYS_STATE_ERR_NULL_POINTER; \
57 if (device->pasimple_handle == NULL) { \
58 return AVSYS_STATE_ERR_NULL_POINTER; \
62 #define SET_PA_ATTR(pt,spp,ppb,pb,mr,tl,ml,fs) \
65 samples_per_period = spp; \
66 periods_per_buffer = ppb; \
70 attr.maxlength = ml; \
74 #define MEDIA_POLICY_AUTO "auto"
75 #define MEDIA_POLICY_PHONE "phone"
76 #define MEDIA_POLICY_ALL "all"
78 int avsys_audio_pasimple_open_device(const int mode, const unsigned int format, const unsigned int channel, const unsigned int samplerate, avsys_audio_handle_t *handle, int policy)
82 avsys_audio_pasimple_handle_t *device = NULL;
84 int err = AVSYS_STATE_SUCCESS;
85 int period_time = PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC;
86 int samples_per_period = PA_SIMPLE_SAMPLES_PER_PERIOD_DEFAULT;
87 int periods_per_buffer = PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT;
88 int vol_conf_type = AVSYS_AUDIO_VOLUME_CONFIG_TYPE(handle->gain_setting.volume_config);
89 pa_channel_map channel_map;
91 int p_time = PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC;
92 int p_count = PA_SIMPLE_PERIODS_PER_BUFFER_PLAYBACK;
93 char *time = getenv("AVSYS_PERIOD_TIME");
94 char *count = getenv("AVSYS_PERIOD_COUNT");
98 p_count = atoi(count);
100 #ifdef MURPHY_SUPPORT
101 const char *media_role;
104 avsys_info(AVAUDIO, ">>>[%s] mode=%d, format=%d, channel=%d, samplerate=%d\n", __func__, mode, format, channel, samplerate);
105 avsys_assert(handle != NULL);
107 if (channel < AVSYS_CHANNEL_MIN || channel > AVSYS_CHANNEL_MAX)
108 return AVSYS_STATE_ERR_DEVICE_NOT_SUPPORT;
110 device = (avsys_audio_pasimple_handle_t *)malloc(sizeof(avsys_audio_pasimple_handle_t));
111 if (device == NULL) {
112 avsys_critical(AVAUDIO, "PA Simple handle alloc fail\n");
113 return AVSYS_STATE_ERR_ALLOCATION;
116 ss.rate = samplerate;
117 ss.channels = channel;
119 pa_channel_map_init_auto(&channel_map, ss.channels, PA_CHANNEL_MAP_ALSA);
122 case AVSYS_AUDIO_FORMAT_8BIT:
123 ss.format = PA_SAMPLE_U8;
124 device->samplesize = 1 * channel;
126 case AVSYS_AUDIO_FORMAT_16BIT:
128 ss.format = PA_SAMPLE_S16LE;
129 device->samplesize = 2 * channel;
133 avsys_error(AVAUDIO, "Invalid format\n");
134 return AVSYS_STATE_ERR_DEVICE_NOT_SUPPORT;
136 handle->device = (void *)device;
138 pa_proplist *proplist = pa_proplist_new();
140 /* Set policy property */
141 avsys_info(AVAUDIO, ">>>[%s] policy=[%d], vol_type=[%d]\n", __func__, policy, vol_conf_type);
143 #ifdef MURPHY_SUPPORT
144 switch (vol_conf_type) {
146 case AVSYS_AUDIO_VOLUME_TYPE_SYSTEM:
147 media_role = "system";
150 case AVSYS_AUDIO_VOLUME_TYPE_NOTIFICATION:
151 media_role = "event";
154 case AVSYS_AUDIO_VOLUME_TYPE_ALARM:
155 media_role = "alarm";
158 case AVSYS_AUDIO_VOLUME_TYPE_RINGTONE:
159 media_role = "ringtone";
162 case AVSYS_AUDIO_VOLUME_TYPE_MEDIA:
163 media_role = "music";
166 case AVSYS_AUDIO_VOLUME_TYPE_CALL:
167 media_role = "phone";
170 case AVSYS_AUDIO_VOLUME_TYPE_FIXED:
171 case AVSYS_AUDIO_VOLUME_TYPE_EXT_SYSTEM_JAVA:
173 media_role = "music";
177 avsys_info(AVAUDIO, ": set media role to '%s'\n", media_role);
178 pa_proplist_sets(proplist, PA_PROP_MEDIA_ROLE, media_role);
180 if (policy == AVSYS_AUDIO_HANDLE_ROUTE_HANDSET_ONLY) {
181 avsys_info(AVAUDIO, ": set media plicy to PHONE\n");
182 pa_proplist_sets(proplist, PA_PROP_MEDIA_POLICY, MEDIA_POLICY_PHONE);
184 /* AVSYS_AUDIO_HANDLE_ROUTE_FOLLOWING_POLICY */
185 /* check stream type (vol type) */
187 switch (vol_conf_type)
189 case AVSYS_AUDIO_VOLUME_TYPE_NOTIFICATION:
190 case AVSYS_AUDIO_VOLUME_TYPE_ALARM:
191 avsys_info(AVAUDIO, ": set media plicy to ALL\n");
192 pa_proplist_sets(proplist, PA_PROP_MEDIA_POLICY, MEDIA_POLICY_ALL);
195 case AVSYS_AUDIO_VOLUME_TYPE_FIXED: /* Used for Emergency */
196 avsys_info(AVAUDIO, ": set media plicy to PHONE\n");
197 pa_proplist_sets(proplist, PA_PROP_MEDIA_POLICY, MEDIA_POLICY_PHONE);
201 avsys_info(AVAUDIO, ": set media plicy to AUTO\n");
202 pa_proplist_sets(proplist, PA_PROP_MEDIA_POLICY, MEDIA_POLICY_AUTO);
208 handle->handle_route = policy;
210 memset(&attr, '\0', sizeof(attr));
213 case AVSYS_AUDIO_MODE_INPUT:
214 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC,
215 MSEC_TO_SAMPLE(samplerate,period_time),
216 PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT,
217 0, -1, -1, -1, samples_per_period * device->samplesize);
219 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_RECORD, NULL, "CAPTURE", &ss, &channel_map, &attr, proplist, &err);
222 case AVSYS_AUDIO_MODE_INPUT_LOW_LATENCY:
223 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_ULOW_LATENCY_MSEC,
224 MSEC_TO_SAMPLE(samplerate,period_time),
225 PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE,
226 0, -1, -1, -1, samples_per_period * device->samplesize);
228 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_RECORD, NULL, "LOW LATENCY CAPTURE", &ss, &channel_map, &attr, proplist, &err);
231 case AVSYS_AUDIO_MODE_INPUT_HIGH_LATENCY:
232 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_HIGH_LATENCY_MSEC,
233 MSEC_TO_SAMPLE(samplerate,period_time),
234 PA_SIMPLE_PERIODS_PER_BUFFER_CAPTURE,
235 0, -1, -1, -1, samples_per_period * device->samplesize);
237 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_RECORD, NULL, "HIGH LATENCY CAPTURE", &ss, &channel_map, &attr, proplist, &err);
240 case AVSYS_AUDIO_MODE_OUTPUT: /* mid latency playback for normal audio case. */
241 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_MID_LATENCY_MSEC,
242 MSEC_TO_SAMPLE(samplerate,period_time),
243 PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT,
244 -1, -1, periods_per_buffer * samples_per_period * device->samplesize, attr.tlength, 0);
246 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_PLAYBACK, NULL, "PLAYBACK", &ss, &channel_map, &attr, proplist, &err);
249 case AVSYS_AUDIO_MODE_OUTPUT_LOW_LATENCY: /* This is special case for touch sound playback */
250 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC,
251 MSEC_TO_SAMPLE(samplerate,period_time),
252 PA_SIMPLE_PERIODS_PER_BUFFER_FASTMODE,
253 samples_per_period * device->samplesize, -1, samples_per_period * device->samplesize + 3430, (uint32_t)-1, 0);
255 s = pa_simple_new_proplist(NULL,"AVSYSTEM", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", &ss, &channel_map, &attr, proplist, &err);
257 case AVSYS_AUDIO_MODE_OUTPUT_CLOCK: /* high latency playback - lager buffer size */
259 MSEC_TO_SAMPLE(samplerate,period_time),
261 (uint32_t) -1, (uint32_t) -1, periods_per_buffer * samples_per_period * device->samplesize, (uint32_t)-1, 0);
263 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_PLAYBACK, NULL, "HIGH LATENCY PLAYBACK", &ss, &channel_map, &attr, proplist, &err);
266 case AVSYS_AUDIO_MODE_OUTPUT_VIDEO: /* low latency playback */
267 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC,
268 MSEC_TO_SAMPLE(samplerate,period_time),
269 PA_SIMPLE_PERIODS_PER_BUFFER_VIDEO,
270 4*(samples_per_period * device->samplesize), samples_per_period * device->samplesize, periods_per_buffer * samples_per_period * device->samplesize, (uint32_t)-1, 0);
272 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_PLAYBACK, NULL, "LOW LATENCY PLAYBACK", &ss, &channel_map, &attr, proplist, &err);
275 case AVSYS_AUDIO_MODE_OUTPUT_AP_CALL:
276 #if defined(_MMFW_I386_ALL_SIMULATOR)
277 avsys_warning(AVAUDIO, "Does not support AP call mode at i386 simulator\n");
280 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC,
281 MSEC_TO_SAMPLE(samplerate,period_time),
282 PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT,
283 (uint32_t) -1, (uint32_t) -1, periods_per_buffer * samples_per_period * device->samplesize, attr.tlength, 0);
286 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_PLAYBACK, NULL, "VoIP PLAYBACK", &ss, &channel_map, &attr, proplist, &err);
289 case AVSYS_AUDIO_MODE_INPUT_AP_CALL:
290 #if defined(_MMFW_I386_ALL_SIMULATOR)
291 avsys_warning(AVAUDIO, "Does not support AP call mode at i386 simulator\n");
294 SET_PA_ATTR(PA_SIMPLE_PERIOD_TIME_FOR_LOW_LATENCY_MSEC,
295 MSEC_TO_SAMPLE(samplerate,period_time),
296 PA_SIMPLE_PERIODS_PER_BUFFER_DEFAULT,
297 0, (uint32_t) -1, (uint32_t) -1, (uint32_t) -1, samples_per_period * device->samplesize);
299 s = pa_simple_new_proplist(NULL, "AVSYSTEM", PA_STREAM_RECORD, NULL, "VoIP CAPTURE", &ss, &channel_map, &attr, proplist, &err);
302 case AVSYS_AUDIO_MODE_CALL_OUT:
303 case AVSYS_AUDIO_MODE_CALL_IN:
305 avsys_error(AVAUDIO, "Does not support call device handling\n");
309 avsys_critical_r(AVAUDIO, "Invalid open mode %d\n", mode);
311 return AVSYS_STATE_ERR_INVALID_MODE;
316 avsys_error_r(AVAUDIO, "Open pulseaudio handle has failed - %s\n", pa_strerror(err));
317 err = AVSYS_STATE_ERR_INTERNAL;
321 avsys_info(AVAUDIO, "Samples(per period) : %d\t Periods(per buffer) : %d\n", samples_per_period, periods_per_buffer);
323 device->pasimple_handle = (void *)s;
325 device->period_frames = samples_per_period;
326 device->buffer_frames = periods_per_buffer * device->period_frames;
327 device->periods_per_buffer = periods_per_buffer;
328 handle->period = device->period_frames * device->samplesize;
329 handle->msec_per_period = period_time;
330 if (0 > pa_simple_get_stream_index(s, &handle->stream_index, &err)) {
331 avsys_error(AVAUDIO, "Can not get stream index %s\n", pa_strerror(err));
332 err = AVSYS_STATE_ERR_INVALID_HANDLE;
337 pa_proplist_free(proplist);
342 int avsys_audio_pasimple_close_device(avsys_audio_handle_t *handle)
345 avsys_audio_pasimple_handle_t *device = NULL;
348 avsys_info(AVAUDIO, "%s\n", __func__);
350 avsys_assert(handle != NULL);
351 CHECK_VALID_HANDLE(handle);
353 switch (handle->mode) {
354 case AVSYS_AUDIO_MODE_CALL_OUT:
355 case AVSYS_AUDIO_MODE_CALL_IN:
356 avsys_warning(AVAUDIO, "Unsupported close mode in pa function\n");
357 return AVSYS_STATE_ERR_INVALID_MODE;
358 case AVSYS_AUDIO_MODE_OUTPUT_AP_CALL:
359 case AVSYS_AUDIO_MODE_INPUT_AP_CALL:
360 #if defined(_MMFW_I386_ALL_SIMULATOR)
361 avsys_warning(AVAUDIO, "Skip close call device in SDK");
362 return AVSYS_STATE_SUCCESS;
368 s = (pa_simple *)device->pasimple_handle;
369 avsys_assert(s != NULL);
371 switch (handle->mode) {
372 case AVSYS_AUDIO_MODE_OUTPUT:
373 case AVSYS_AUDIO_MODE_OUTPUT_CLOCK:
374 case AVSYS_AUDIO_MODE_OUTPUT_LOW_LATENCY:
375 case AVSYS_AUDIO_MODE_OUTPUT_AP_CALL:
376 case AVSYS_AUDIO_MODE_OUTPUT_VIDEO:
377 if (0 > pa_simple_flush(s, &err)) {
378 avsys_error(AVAUDIO, "pa_simple_flush() failed with %s\n", pa_strerror(err));
387 device->pasimple_handle = NULL;
390 return AVSYS_STATE_SUCCESS;
393 int avsys_audio_pasimple_write(avsys_audio_handle_t *handle, const void *buf, int size)
396 avsys_audio_pasimple_handle_t *device = NULL;
400 return AVSYS_STATE_ERR_NULL_POINTER;
401 CHECK_VALID_HANDLE(handle);
404 return AVSYS_STATE_ERR_INVALID_PARAMETER;
408 s = (pa_simple *)device->pasimple_handle;
410 if (0 > pa_simple_write(s, buf, size, &err)) {
411 avsys_error(AVAUDIO, "pa_simple_write() failed with %s\n", pa_strerror(err));
412 return AVSYS_STATE_ERR_INTERNAL;
418 int avsys_audio_pasimple_read(avsys_audio_handle_t *handle, void *buf, int size)
421 avsys_audio_pasimple_handle_t *device = NULL;
425 return AVSYS_STATE_ERR_NULL_POINTER;
426 CHECK_VALID_HANDLE(handle);
429 return AVSYS_STATE_ERR_INVALID_PARAMETER;
433 s = (pa_simple *)device->pasimple_handle;
435 if (0 > pa_simple_read(s, buf, size, &err)) {
436 avsys_error(AVAUDIO, "pa_simple_read() failed with %s\n", pa_strerror(err));
437 return AVSYS_STATE_ERR_INTERNAL;
443 int avsys_audio_pasimple_reset(avsys_audio_handle_t *handle)
446 avsys_audio_pasimple_handle_t *device = NULL;
449 CHECK_VALID_HANDLE(handle);
451 if (handle->mode == AVSYS_AUDIO_MODE_INPUT || handle->mode == AVSYS_AUDIO_MODE_INPUT_LOW_LATENCY) {
452 avsys_warning(AVAUDIO, "Skip pa_simple_flush() when input mode\n");
453 return AVSYS_STATE_SUCCESS;
456 s = (pa_simple *)device->pasimple_handle;
458 if (0 > pa_simple_flush(s, &err)) {
459 avsys_error(AVAUDIO, "pa_simple_flush() failed with %s\n", pa_strerror(err));
460 return AVSYS_STATE_ERR_INTERNAL;
463 return AVSYS_STATE_SUCCESS;
466 int avsys_audio_pasimple_drain(avsys_audio_handle_t *handle)
469 avsys_audio_pasimple_handle_t *device = NULL;
472 CHECK_VALID_HANDLE(handle);
474 s = (pa_simple *)device->pasimple_handle;
476 if (0 > pa_simple_drain(s, &err)) {
477 avsys_error(AVAUDIO, "pa_simple_drain() failed with %s\n", pa_strerror(err));
478 return AVSYS_STATE_ERR_INTERNAL;
481 return AVSYS_STATE_SUCCESS;
484 int avsys_audio_pasimple_set_volume(avsys_audio_handle_t *handle, int volume)
487 avsys_audio_pasimple_handle_t *device = NULL;
490 CHECK_VALID_HANDLE(handle);
492 s = (pa_simple *)device->pasimple_handle;
494 if (0 > pa_simple_set_volume(s, volume, &err)) {
495 avsys_error(AVAUDIO, "pa_simple_set_volume() failed with %s\n", pa_strerror(err));
496 return AVSYS_STATE_ERR_INTERNAL;
499 return AVSYS_STATE_SUCCESS;
502 #define USEC_TO_SAMPLE(usec, rate) ((usec*rate)/1000000)
503 #define SAMPLES_TO_USEC(samples,rate) ((samples*1000000)/rate)
504 #define BYTES_TO_USEC(bytes,size_per_sample,rate) ((bytes*1000000)/(size_per_sample*rate))
506 int avsys_audio_pasimple_delay(avsys_audio_handle_t *handle, int *delay)
509 avsys_audio_pasimple_handle_t *device = NULL;
511 pa_usec_t latency_time = 0;
512 unsigned int latency_frames = 0;
515 return AVSYS_STATE_ERR_NULL_POINTER;
517 CHECK_VALID_HANDLE(handle);
519 s = (pa_simple *)device->pasimple_handle;
521 latency_time = pa_simple_get_latency(s, &err);
522 if (err > 0 && latency_time == 0) {
523 avsys_error(AVAUDIO, "pa_simple_get_latency() failed with %s\n", pa_strerror(err));
524 return AVSYS_STATE_ERR_INTERNAL;
526 /* convert time to sample */
527 latency_frames = USEC_TO_SAMPLE(latency_time, handle->samplerate);
528 *delay = latency_frames;
530 return AVSYS_STATE_SUCCESS;
533 int avsys_audio_pasimple_get_period_buffer_time(avsys_audio_handle_t *handle, unsigned int *period_time, unsigned int *buffer_time)
535 avsys_audio_pasimple_handle_t *device = NULL;
537 if ((period_time == NULL) || (buffer_time == NULL))
538 return AVSYS_STATE_ERR_INTERNAL;
540 CHECK_VALID_HANDLE(handle);
542 *period_time = SAMPLES_TO_USEC(device->period_frames,handle->samplerate);
543 *buffer_time = *period_time * device->periods_per_buffer;
545 avsys_info(AVAUDIO, "[%s][%d] period = %d, buffer = %d\n", __func__, __LINE__, *period_time, *buffer_time);
547 return AVSYS_STATE_SUCCESS;
550 int avsys_audio_pasimple_cork(avsys_audio_handle_t *handle, int cork)
553 avsys_audio_pasimple_handle_t *device = NULL;
556 CHECK_VALID_HANDLE(handle);
558 s = (pa_simple *)device->pasimple_handle;
560 if (0 > pa_simple_cork(s, cork, &err)) {
561 avsys_error(AVAUDIO, "pa_simple_cork() failed with %s\n", pa_strerror(err));
562 return AVSYS_STATE_ERR_INTERNAL;
565 return AVSYS_STATE_SUCCESS;
568 int avsys_audio_pasimple_is_corked(avsys_audio_handle_t *handle, int *is_corked)
571 avsys_audio_pasimple_handle_t *device = NULL;
574 if (is_corked == NULL)
575 return AVSYS_STATE_ERR_INTERNAL;
577 CHECK_VALID_HANDLE(handle);
579 s = (pa_simple *)device->pasimple_handle;
581 *is_corked = pa_simple_is_corked(s);
583 return AVSYS_STATE_SUCCESS;