4 * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
10 * http://www.apache.org/licenses/LICENSE-2.0
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
29 #include "tizen-audio-internal.h"
31 #ifndef __USE_TINYALSA__
32 /* FIXME : To avoid build warning... */
33 int _snd_pcm_poll_descriptor(snd_pcm_t *pcm);
36 /* #define DEBUG_TIMING */
38 static device_type_t outDeviceTypes[] = {
39 { AUDIO_DEVICE_OUT_SPEAKER, "Speaker" },
40 { AUDIO_DEVICE_OUT_RECEIVER, "Earpiece" },
41 { AUDIO_DEVICE_OUT_JACK, "Headphones" },
42 { AUDIO_DEVICE_OUT_BT_SCO, "Bluetooth" },
46 static device_type_t inDeviceTypes[] = {
47 { AUDIO_DEVICE_IN_MAIN_MIC, "MainMic" },
48 { AUDIO_DEVICE_IN_SUB_MIC, "SubMic" },
49 { AUDIO_DEVICE_IN_JACK, "HeadsetMic" },
50 { AUDIO_DEVICE_IN_BT_SCO, "BT Mic" },
54 static const char* mode_to_verb_str[] = {
55 AUDIO_USE_CASE_VERB_HIFI,
56 AUDIO_USE_CASE_VERB_VOICECALL,
57 AUDIO_USE_CASE_VERB_VIDEOCALL,
58 AUDIO_USE_CASE_VERB_VOIP,
61 static int _voice_pcm_open(audio_hal_t *ah);
62 static int _voice_pcm_close(audio_hal_t *ah, uint32_t direction);
63 static void _reset_pcm_devices(audio_hal_t *ah);
64 static void _reset_voice_devices_info(audio_hal_t *ah);
66 static uint32_t convert_device_string_to_enum(const char* device_str, uint32_t direction)
70 if (!strncmp(device_str, "builtin-speaker", MAX_NAME_LEN)) {
71 device = AUDIO_DEVICE_OUT_SPEAKER;
72 } else if (!strncmp(device_str, "builtin-receiver", MAX_NAME_LEN)) {
73 device = AUDIO_DEVICE_OUT_RECEIVER;
74 } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
75 device = AUDIO_DEVICE_OUT_JACK;
76 } else if ((!strncmp(device_str, "bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
77 device = AUDIO_DEVICE_OUT_BT_SCO;
78 } else if ((!strncmp(device_str, "builtin-mic", MAX_NAME_LEN))) {
79 device = AUDIO_DEVICE_IN_MAIN_MIC;
81 } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
82 device = AUDIO_DEVICE_IN_JACK;
83 } else if ((!strncmp(device_str, "bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
84 device = AUDIO_DEVICE_IN_BT_SCO;
86 device = AUDIO_DEVICE_NONE;
88 AUDIO_LOG_INFO("device type(%s), enum(0x%x)", device_str, device);
92 static audio_return_t set_devices(audio_hal_t *ah, const char *verb, device_info_t *devices, uint32_t num_of_devices)
94 audio_return_t audio_ret = AUDIO_RET_OK;
95 uint32_t new_device = 0;
96 const char *active_devices[MAX_DEVICES] = {NULL,};
97 int i = 0, j = 0, dev_idx = 0;
99 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
100 AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
101 AUDIO_RETURN_VAL_IF_FAIL(num_of_devices, AUDIO_ERR_PARAMETER);
103 if (num_of_devices > MAX_DEVICES) {
104 num_of_devices = MAX_DEVICES;
105 AUDIO_LOG_ERROR("error: num_of_devices");
106 return AUDIO_ERR_PARAMETER;
109 if (devices[0].direction == AUDIO_DIRECTION_OUT) {
110 ah->device.active_out &= 0x0;
111 if (ah->device.active_in) {
112 /* check the active in devices */
113 for (j = 0; j < inDeviceTypes[j].type; j++) {
114 if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[j].type))
115 active_devices[dev_idx++] = inDeviceTypes[j].name;
118 } else if (devices[0].direction == AUDIO_DIRECTION_IN) {
119 ah->device.active_in &= 0x0;
120 if (ah->device.active_out) {
121 /* check the active out devices */
122 for (j = 0; j < outDeviceTypes[j].type; j++) {
123 if (ah->device.active_out & outDeviceTypes[j].type)
124 active_devices[dev_idx++] = outDeviceTypes[j].name;
129 for (i = 0; i < num_of_devices; i++) {
130 new_device = convert_device_string_to_enum(devices[i].type, devices[i].direction);
131 if (new_device & AUDIO_DEVICE_IN) {
132 for (j = 0; j < inDeviceTypes[j].type; j++) {
133 if (new_device == inDeviceTypes[j].type) {
134 active_devices[dev_idx++] = inDeviceTypes[j].name;
135 ah->device.active_in |= new_device;
139 for (j = 0; j < outDeviceTypes[j].type; j++) {
140 if (new_device == outDeviceTypes[j].type) {
141 active_devices[dev_idx++] = outDeviceTypes[j].name;
142 ah->device.active_out |= new_device;
148 if (active_devices[0] == NULL) {
149 AUDIO_LOG_ERROR("Failed to set device: active device is NULL");
150 return AUDIO_ERR_PARAMETER;
153 audio_ret = _audio_ucm_set_devices(ah, verb, active_devices);
155 AUDIO_LOG_ERROR("Failed to set device: error = %d", audio_ret);
160 audio_return_t _audio_device_init(audio_hal_t *ah)
162 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
164 ah->device.active_in = 0x0;
165 ah->device.active_out = 0x0;
166 ah->device.pcm_in = NULL;
167 ah->device.pcm_out = NULL;
168 ah->device.mode = VERB_NORMAL;
169 pthread_mutex_init(&ah->device.pcm_lock, NULL);
170 pthread_mutex_init(&ah->device.device_lock, NULL);
171 pthread_cond_init(&ah->device.device_cond, NULL);
172 ah->device.pcm_count = 0;
177 audio_return_t _audio_device_deinit(audio_hal_t *ah)
179 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
181 pthread_mutex_destroy(&ah->device.pcm_lock);
182 pthread_mutex_destroy(&ah->device.device_lock);
183 pthread_cond_destroy(&ah->device.device_cond);
187 static audio_return_t _update_route_ap_playback_capture(audio_hal_t *ah, audio_route_info_t *route_info)
189 audio_return_t audio_ret = AUDIO_RET_OK;
190 device_info_t *devices = NULL;
191 const char *verb = mode_to_verb_str[VERB_NORMAL];
192 #if 0 /* Disable setting modifiers, because driver does not support it yet */
194 const char *modifiers[MAX_MODIFIERS] = {NULL,};
197 if (ah->modem.is_connected) {
198 AUDIO_LOG_INFO("modem is connected, skip verb[%s]", verb);
202 if (ah->device.mode != VERB_NORMAL) {
203 if (ah->device.mode == VERB_VOICECALL) {
204 _reset_voice_devices_info(ah);
205 COND_SIGNAL(ah->device.device_cond, "device_cond");
207 _reset_pcm_devices(ah);
208 ah->device.mode = VERB_NORMAL;
211 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
212 AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
214 devices = route_info->device_infos;
216 AUDIO_LOG_INFO("update_route_ap_playback_capture++ ");
218 audio_ret = set_devices(ah, verb, devices, route_info->num_of_devices);
220 AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
223 ah->device.mode = VERB_NORMAL;
225 #if 0 /* Disable setting modifiers, because driver does not support it yet */
227 if (!strncmp("voice_recognition", route_info->role, MAX_NAME_LEN)) {
228 modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_VOICESEARCH;
229 } else if ((!strncmp("alarm", route_info->role, MAX_NAME_LEN))||(!strncmp("notifiication", route_info->role, MAX_NAME_LEN))) {
230 if (ah->device.active_out &= AUDIO_DEVICE_OUT_JACK)
231 modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_DUAL_MEDIA;
233 modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
234 } else if (!strncmp("ringtone", route_info->role, MAX_NAME_LEN)) {
235 if (ah->device.active_out)
236 modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_RINGTONE;
238 if (ah->device.active_in)
239 modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_CAMCORDING;
241 modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
243 audio_ret = _audio_ucm_set_modifiers (ah, verb, modifiers);
248 static audio_return_t _update_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
250 audio_return_t audio_ret = AUDIO_RET_OK;
251 const char *verb = mode_to_verb_str[VERB_VOICECALL];
253 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
254 /* if both params are 0, return error for invalid state,
255 * this error would be used to tizen-audio-modem.c */
256 AUDIO_RETURN_VAL_IF_FAIL((devices||num_of_devices), AUDIO_ERR_INVALID_STATE);
257 AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
259 AUDIO_LOG_INFO("update_route_voicecall++");
261 audio_ret = set_devices(ah, verb, devices, num_of_devices);
263 AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
267 if (ah->device.mode != VERB_VOICECALL) {
269 ah->device.mode = VERB_VOICECALL;
270 /* FIXME. Get network info and configure rate in pcm device */
276 static audio_return_t _update_route_voip(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
278 audio_return_t audio_ret = AUDIO_RET_OK;
279 const char *verb = mode_to_verb_str[VERB_NORMAL];
281 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
282 AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
284 AUDIO_LOG_INFO("update_route_voip++");
286 audio_ret = set_devices(ah, verb, devices, num_of_devices);
288 AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
291 /* FIXME. If necessary, set VERB_VOIP */
292 ah->device.mode = VERB_NORMAL;
294 /* TO DO: Set modifiers */
298 static audio_return_t _update_route_reset(audio_hal_t *ah, uint32_t direction)
300 audio_return_t audio_ret = AUDIO_RET_OK;
301 const char *active_devices[MAX_DEVICES] = {NULL,};
302 int i = 0, dev_idx = 0;
304 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
306 AUDIO_LOG_INFO("update_route_reset++, direction(0x%x)", direction);
308 if (direction == AUDIO_DIRECTION_OUT) {
309 ah->device.active_out &= 0x0;
310 if (ah->device.active_in) {
311 /* check the active in devices */
312 for (i = 0; i < inDeviceTypes[i].type; i++) {
313 if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[i].type)) {
314 active_devices[dev_idx++] = inDeviceTypes[i].name;
315 AUDIO_LOG_INFO("added for in : %s", inDeviceTypes[i].name);
320 ah->device.active_in &= 0x0;
321 if (ah->device.active_out) {
322 /* check the active out devices */
323 for (i = 0; i < outDeviceTypes[i].type; i++) {
324 if (ah->device.active_out & outDeviceTypes[i].type) {
325 active_devices[dev_idx++] = outDeviceTypes[i].name;
326 AUDIO_LOG_INFO("added for out : %s", outDeviceTypes[i].name);
331 if (ah->device.mode == VERB_VOICECALL) {
332 _voice_pcm_close(ah, direction);
333 if (!ah->device.active_in && !ah->device.active_out)
334 ah->device.mode = VERB_NORMAL;
335 _reset_voice_devices_info(ah);
336 COND_SIGNAL(ah->device.device_cond, "device_cond");
339 if (active_devices[0] == NULL) {
340 AUDIO_LOG_DEBUG("active device is NULL, no need to update.");
344 audio_ret = _audio_ucm_set_devices(ah, mode_to_verb_str[ah->device.mode], active_devices);
346 AUDIO_LOG_ERROR("Failed to set device: error = %d", audio_ret);
351 audio_return_t audio_update_route(void *audio_handle, audio_route_info_t *info)
353 audio_return_t audio_ret = AUDIO_RET_OK;
354 audio_hal_t *ah = (audio_hal_t *)audio_handle;
355 device_info_t *devices = NULL;
360 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
361 AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
363 AUDIO_LOG_INFO("role:%s", info->role);
365 devices = info->device_infos;
367 if (!strncmp("call-voice", info->role, MAX_NAME_LEN)) {
368 if (!ah->modem.is_connected) {
369 if (info->num_of_devices) {
370 if (!ah->device.num_of_call_devices) {
371 if ((ah->device.init_call_devices = (device_info_t*)calloc(info->num_of_devices, sizeof(device_info_t)))) {
372 memcpy(ah->device.init_call_devices, devices, info->num_of_devices*sizeof(device_info_t));
373 ah->device.num_of_call_devices = info->num_of_devices;
375 AUDIO_LOG_ERROR("failed to calloc");
376 audio_ret = AUDIO_ERR_RESOURCE;
379 } else if (ah->device.num_of_call_devices) {
380 prev_size = ah->device.num_of_call_devices;
381 if (prev_size == 2) {
382 /* There's a chance to be requested to change routing from user
383 * though two devices(for input/output) has already been set for call-voice routing.
384 * In this case, exchange an old device for a new device if it's direction is same as an old one's. */
385 for (i = 0; i < prev_size; i++) {
386 for (j = 0; j < info->num_of_devices; j++) {
387 if (devices[j].direction == ah->device.init_call_devices[i].direction &&
388 devices[j].id != ah->device.init_call_devices[i].id)
389 memcpy(&ah->device.init_call_devices[i], &devices[j], sizeof(device_info_t));
392 } else if (prev_size < 2) {
393 /* A device has already been added for call-voice routing,
394 * and now it is about to add a new device(input or output device). */
395 ah->device.num_of_call_devices += info->num_of_devices;
396 if ((ah->device.init_call_devices = (device_info_t*)realloc(ah->device.init_call_devices, sizeof(device_info_t)*ah->device.num_of_call_devices))) {
397 memcpy((void*)&(ah->device.init_call_devices[prev_size]), devices, info->num_of_devices*sizeof(device_info_t));
399 AUDIO_LOG_ERROR("failed to realloc");
400 audio_ret = AUDIO_ERR_RESOURCE;
404 AUDIO_LOG_ERROR("invaild previous num. of call devices");
405 audio_ret = AUDIO_ERR_INTERNAL;
410 AUDIO_LOG_ERROR("failed to do route for call-voice, num_of_devices is 0");
411 audio_ret = AUDIO_ERR_PARAMETER;
414 AUDIO_LOG_INFO("modem is not ready, skip...");
416 audio_ret = _update_route_voicecall(ah, devices, info->num_of_devices);
417 if (AUDIO_IS_ERROR(audio_ret)) {
418 AUDIO_LOG_WARN("set voicecall route return 0x%x", audio_ret);
420 COND_SIGNAL(ah->device.device_cond, "device_cond");
422 } else if (!strncmp("voip", info->role, MAX_NAME_LEN)) {
423 audio_ret = _update_route_voip(ah, devices, info->num_of_devices);
424 if (AUDIO_IS_ERROR(audio_ret)) {
425 AUDIO_LOG_WARN("set voip route return 0x%x", audio_ret);
427 } else if (!strncmp("reset", info->role, MAX_NAME_LEN)) {
428 audio_ret = _update_route_reset(ah, devices->direction);
429 if (AUDIO_IS_ERROR(audio_ret)) {
430 AUDIO_LOG_WARN("set reset return 0x%x", audio_ret);
433 /* need to prepare for "alarm","notification","emergency","voice-information","voice-recognition","ringtone" */
434 audio_ret = _update_route_ap_playback_capture(ah, info);
435 if (AUDIO_IS_ERROR(audio_ret)) {
436 AUDIO_LOG_WARN("set playback route return 0x%x", audio_ret);
444 audio_return_t audio_notify_stream_connection_changed(void *audio_handle, audio_stream_info_t *info, uint32_t is_connected)
446 audio_return_t audio_ret = AUDIO_RET_OK;
447 audio_hal_t *ah = (audio_hal_t *)audio_handle;
449 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
450 AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
452 AUDIO_LOG_INFO("role:%s, direction:%u, idx:%u, is_connected:%d", info->role, info->direction, info->idx, is_connected);
457 audio_return_t audio_update_route_option(void *audio_handle, audio_route_option_t *option)
459 audio_return_t audio_ret = AUDIO_RET_OK;
460 audio_hal_t *ah = (audio_hal_t *)audio_handle;
462 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
463 AUDIO_RETURN_VAL_IF_FAIL(option, AUDIO_ERR_PARAMETER);
465 AUDIO_LOG_INFO("role:%s, name:%s, value:%d", option->role, option->name, option->value);
470 static int __voice_pcm_set_params(audio_hal_t *ah, snd_pcm_t *pcm)
472 snd_pcm_hw_params_t *params = NULL;
474 unsigned int val = 0;
476 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
477 AUDIO_RETURN_VAL_IF_FAIL(pcm, AUDIO_ERR_PARAMETER);
479 /* Skip parameter setting to null device. */
480 if (snd_pcm_type(pcm) == SND_PCM_TYPE_NULL)
481 return AUDIO_ERR_IOCTL;
483 /* Allocate a hardware parameters object. */
484 snd_pcm_hw_params_alloca(¶ms);
486 /* Fill it in with default values. */
487 if (snd_pcm_hw_params_any(pcm, params) < 0) {
488 AUDIO_LOG_ERROR("snd_pcm_hw_params_any() : failed! - %s\n", snd_strerror(err));
492 /* Set the desired hardware parameters. */
493 /* Interleaved mode */
494 err = snd_pcm_hw_params_set_access(pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED);
496 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_access() : failed! - %s\n", snd_strerror(err));
499 err = snd_pcm_hw_params_set_rate(pcm, params, 8000, 0);
501 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() : failed! - %s\n", snd_strerror(err));
503 err = snd_pcm_hw_params(pcm, params);
505 AUDIO_LOG_ERROR("snd_pcm_hw_params() : failed! - %s\n", snd_strerror(err));
509 /* Dump current param */
510 snd_pcm_hw_params_get_access(params, (snd_pcm_access_t *) &val);
511 AUDIO_LOG_DEBUG("access type = %s\n", snd_pcm_access_name((snd_pcm_access_t)val));
513 snd_pcm_hw_params_get_format(params, (snd_pcm_format_t*)&val);
514 AUDIO_LOG_DEBUG("format = '%s' (%s)\n",
515 snd_pcm_format_name((snd_pcm_format_t)val),
516 snd_pcm_format_description((snd_pcm_format_t)val));
518 snd_pcm_hw_params_get_subformat(params, (snd_pcm_subformat_t *)&val);
519 AUDIO_LOG_DEBUG("subformat = '%s' (%s)\n",
520 snd_pcm_subformat_name((snd_pcm_subformat_t)val),
521 snd_pcm_subformat_description((snd_pcm_subformat_t)val));
523 snd_pcm_hw_params_get_channels(params, &val);
524 AUDIO_LOG_DEBUG("channels = %d\n", val);
532 static int _voice_pcm_open(audio_hal_t *ah)
536 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
538 AUDIO_LOG_INFO("open voice pcm handles");
540 /* Get playback voice-pcm from ucm conf. Open and set-params */
541 if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_out, VOICE_PCM_DEVICE, AUDIO_DIRECTION_OUT, 0)) < 0) {
542 AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
543 return AUDIO_ERR_IOCTL;
545 ret = __voice_pcm_set_params(ah, ah->device.pcm_out);
547 AUDIO_LOG_INFO("pcm playback device open success device(%s)", VOICE_PCM_DEVICE);
549 /* Get capture voice-pcm from ucm conf. Open and set-params */
550 if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_in, VOICE_PCM_DEVICE, AUDIO_DIRECTION_IN, 0)) < 0) {
551 AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
552 return AUDIO_ERR_IOCTL;
554 ret = __voice_pcm_set_params(ah, ah->device.pcm_in);
555 AUDIO_LOG_INFO("pcm captures device open success device(%s)", VOICE_PCM_DEVICE);
560 static int _voice_pcm_close(audio_hal_t *ah, uint32_t direction)
562 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
564 AUDIO_LOG_INFO("close voice pcm handles");
566 if (ah->device.pcm_out && (direction == AUDIO_DIRECTION_OUT)) {
567 audio_pcm_close((void *)ah, ah->device.pcm_out);
568 ah->device.pcm_out = NULL;
569 AUDIO_LOG_INFO("voice pcm_out handle close success");
570 } else if (ah->device.pcm_in && (direction == AUDIO_DIRECTION_IN)) {
571 audio_pcm_close((void *)ah, ah->device.pcm_in);
572 ah->device.pcm_in = NULL;
573 AUDIO_LOG_INFO("voice pcm_in handle close success");
579 static void _reset_pcm_devices(audio_hal_t *ah)
581 AUDIO_RETURN_IF_FAIL(ah);
583 if (ah->device.pcm_out) {
584 audio_pcm_close((void *)ah, ah->device.pcm_out);
585 ah->device.pcm_out = NULL;
586 AUDIO_LOG_INFO("pcm_out handle close success");
588 if (ah->device.pcm_in) {
589 audio_pcm_close((void *)ah, ah->device.pcm_in);
590 ah->device.pcm_in = NULL;
591 AUDIO_LOG_INFO("pcm_in handle close success");
597 static void _reset_voice_devices_info(audio_hal_t *ah)
599 AUDIO_RETURN_IF_FAIL(ah);
601 AUDIO_LOG_INFO("reset voice device info");
602 if (ah->device.init_call_devices) {
603 free(ah->device.init_call_devices);
604 ah->device.init_call_devices = NULL;
605 ah->device.num_of_call_devices = 0;
611 #ifdef __USE_TINYALSA__
612 static struct pcm *__tinyalsa_open_device(audio_pcm_sample_spec_t *ss, size_t period_size, size_t period_count, uint32_t direction)
614 struct pcm *pcm = NULL;
615 struct pcm_config config;
617 AUDIO_RETURN_NULL_IF_FAIL(ss);
619 config.channels = ss->channels;
620 config.rate = ss->rate;
621 config.period_size = period_size;
622 config.period_count = period_count;
623 config.format = ss->format;
624 config.start_threshold = period_size;
625 config.stop_threshold = 0xFFFFFFFF;
626 config.silence_threshold = 0;
628 AUDIO_LOG_INFO("direction %d, channels %d, rate %d, format %d, period_size %d, period_count %d", direction, ss->channels, ss->rate, ss->format, period_size, period_count);
630 pcm = pcm_open((direction == AUDIO_DIRECTION_OUT) ? PLAYBACK_CARD_ID : CAPTURE_CARD_ID,
631 (direction == AUDIO_DIRECTION_OUT) ? PLAYBACK_PCM_DEVICE_ID : CAPTURE_PCM_DEVICE_ID,
632 (direction == AUDIO_DIRECTION_OUT) ? PCM_OUT : PCM_IN,
634 if (!pcm || !pcm_is_ready(pcm)) {
635 AUDIO_LOG_ERROR("Unable to open device (%s)", pcm_get_error(pcm));
644 audio_return_t _audio_update_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
646 return _update_route_voicecall(ah, devices, num_of_devices);
649 audio_return_t audio_pcm_open(void *audio_handle, void **pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
651 #ifdef __USE_TINYALSA__
653 audio_pcm_sample_spec_t *ss;
656 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
657 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
658 AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
659 AUDIO_RETURN_VAL_IF_FAIL((period_size > 0), AUDIO_ERR_PARAMETER);
660 AUDIO_RETURN_VAL_IF_FAIL((periods > 0), AUDIO_ERR_PARAMETER);
662 ah = (audio_hal_t *)audio_handle;
663 ss = (audio_pcm_sample_spec_t *)sample_spec;
664 ss->format = _convert_format((audio_sample_format_t)ss->format);
666 *pcm_handle = __tinyalsa_open_device(ss, (size_t)period_size, (size_t)periods, direction);
667 if (*pcm_handle == NULL) {
668 AUDIO_LOG_ERROR("Error opening PCM device");
669 return AUDIO_ERR_RESOURCE;
672 if ((err = pcm_prepare((struct pcm *)*pcm_handle)) != 0) {
673 AUDIO_LOG_ERROR("Error prepare PCM device : %d", err);
676 ah->device.pcm_count++;
677 AUDIO_LOG_INFO("Opening PCM handle 0x%x", *pcm_handle);
681 char *device_name = NULL;
683 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
684 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
685 AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
686 AUDIO_RETURN_VAL_IF_FAIL((period_size > 0), AUDIO_ERR_PARAMETER);
687 AUDIO_RETURN_VAL_IF_FAIL((periods > 0), AUDIO_ERR_PARAMETER);
689 ah = (audio_hal_t *)audio_handle;
690 mode = SND_PCM_NONBLOCK | SND_PCM_NO_AUTO_RESAMPLE | SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_FORMAT;
692 if (direction == AUDIO_DIRECTION_OUT)
693 device_name = PLAYBACK_PCM_DEVICE;
694 else if (direction == AUDIO_DIRECTION_IN)
695 device_name = CAPTURE_PCM_DEVICE;
697 AUDIO_LOG_ERROR("Error get device_name, direction : %d", direction);
698 return AUDIO_ERR_RESOURCE;
701 if ((err = snd_pcm_open((snd_pcm_t **)pcm_handle, device_name, (direction == AUDIO_DIRECTION_OUT) ? SND_PCM_STREAM_PLAYBACK : SND_PCM_STREAM_CAPTURE, mode)) < 0) {
702 AUDIO_LOG_ERROR("Error opening PCM device %s : %s", device_name, snd_strerror(err));
703 return AUDIO_ERR_RESOURCE;
706 if ((err = audio_pcm_set_params(audio_handle, *pcm_handle, direction, sample_spec, period_size, periods)) != AUDIO_RET_OK) {
707 AUDIO_LOG_ERROR("Failed to set pcm parameters : %d", err);
711 ah->device.pcm_count++;
712 AUDIO_LOG_INFO("Opening PCM handle 0x%x, PCM device %s", *pcm_handle, device_name);
718 audio_return_t audio_pcm_start(void *audio_handle, void *pcm_handle)
722 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
723 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
725 #ifdef __USE_TINYALSA__
726 if ((err = pcm_start(pcm_handle)) < 0) {
727 AUDIO_LOG_ERROR("Error starting PCM handle : %d", err);
728 return AUDIO_ERR_RESOURCE;
731 if ((err = snd_pcm_start(pcm_handle)) < 0) {
732 AUDIO_LOG_ERROR("Error starting PCM handle : %s", snd_strerror(err));
733 return AUDIO_ERR_RESOURCE;
737 AUDIO_LOG_INFO("PCM handle 0x%x start", pcm_handle);
741 audio_return_t audio_pcm_stop(void *audio_handle, void *pcm_handle)
745 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
746 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
748 #ifdef __USE_TINYALSA__
749 if ((err = pcm_stop(pcm_handle)) < 0) {
750 AUDIO_LOG_ERROR("Error stopping PCM handle : %d", err);
751 return AUDIO_ERR_RESOURCE;
754 if ((err = snd_pcm_drop(pcm_handle)) < 0) {
755 AUDIO_LOG_ERROR("Error stopping PCM handle : %s", snd_strerror(err));
756 return AUDIO_ERR_RESOURCE;
760 AUDIO_LOG_INFO("PCM handle 0x%x stop", pcm_handle);
764 audio_return_t audio_pcm_close(void *audio_handle, void *pcm_handle)
766 audio_hal_t *ah = (audio_hal_t *)audio_handle;
769 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
770 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
772 AUDIO_LOG_INFO("Try to close PCM handle 0x%x", pcm_handle);
774 #ifdef __USE_TINYALSA__
775 if ((err = pcm_close(pcm_handle)) < 0) {
776 AUDIO_LOG_ERROR("Error closing PCM handle : %d", err);
777 return AUDIO_ERR_RESOURCE;
780 if ((err = snd_pcm_close(pcm_handle)) < 0) {
781 AUDIO_LOG_ERROR("Error closing PCM handle : %s", snd_strerror(err));
782 return AUDIO_ERR_RESOURCE;
787 ah->device.pcm_count--;
788 AUDIO_LOG_INFO("PCM handle close success (count:%d)", ah->device.pcm_count);
793 audio_return_t audio_pcm_avail(void *audio_handle, void *pcm_handle, uint32_t *avail)
795 #ifdef __USE_TINYALSA__
796 struct timespec tspec;
797 unsigned int frames_avail = 0;
800 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
801 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
802 AUDIO_RETURN_VAL_IF_FAIL(avail, AUDIO_ERR_PARAMETER);
804 err = pcm_get_htimestamp(pcm_handle, &frames_avail, &tspec);
806 AUDIO_LOG_ERROR("Could not get avail and timespec at PCM handle 0x%x : %d", pcm_handle, err);
807 return AUDIO_ERR_IOCTL;
811 AUDIO_LOG_DEBUG("avail = %d", frames_avail);
814 *avail = (uint32_t)frames_avail;
816 snd_pcm_sframes_t frames_avail;
818 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
819 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
820 AUDIO_RETURN_VAL_IF_FAIL(avail, AUDIO_ERR_PARAMETER);
822 if ((frames_avail = snd_pcm_avail(pcm_handle)) < 0) {
823 AUDIO_LOG_ERROR("Could not get avail at PCM handle 0x%x : %d", pcm_handle, frames_avail);
824 return AUDIO_ERR_IOCTL;
828 AUDIO_LOG_DEBUG("avail = %d", frames_avail);
831 *avail = (uint32_t)frames_avail;
837 audio_return_t audio_pcm_write(void *audio_handle, void *pcm_handle, const void *buffer, uint32_t frames)
839 #ifdef __USE_TINYALSA__
842 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
843 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
845 err = pcm_write(pcm_handle, buffer, pcm_frames_to_bytes(pcm_handle, (unsigned int)frames));
847 AUDIO_LOG_ERROR("Failed to write pcm : %d", err);
848 return AUDIO_ERR_IOCTL;
852 AUDIO_LOG_DEBUG("audio_pcm_write = %d", frames);
855 snd_pcm_sframes_t frames_written;
857 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
859 frames_written = snd_pcm_writei(pcm_handle, buffer, (snd_pcm_uframes_t) frames);
860 if (frames_written < 0) {
861 AUDIO_LOG_ERROR("Failed to write pcm : %d", frames_written);
862 return AUDIO_ERR_IOCTL;
866 AUDIO_LOG_DEBUG("audio_pcm_write = (%d / %d)", frames_written, frames);
873 audio_return_t audio_pcm_read(void *audio_handle, void *pcm_handle, void *buffer, uint32_t frames)
875 #ifdef __USE_TINYALSA__
878 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
879 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
881 err = pcm_read(pcm_handle, buffer, pcm_frames_to_bytes(pcm_handle, (unsigned int)frames));
883 AUDIO_LOG_ERROR("Failed to read pcm : %d", err);
884 return AUDIO_ERR_IOCTL;
888 AUDIO_LOG_DEBUG("audio_pcm_read = %d", frames);
891 snd_pcm_sframes_t frames_read;
893 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
894 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
896 frames_read = snd_pcm_readi(pcm_handle, buffer, (snd_pcm_uframes_t)frames);
897 if (frames_read < 0) {
898 AUDIO_LOG_ERROR("Failed to read pcm : %d", frames_read);
899 return AUDIO_ERR_IOCTL;
903 AUDIO_LOG_DEBUG("audio_pcm_read = (%d / %d)", frames_read, frames);
910 audio_return_t audio_pcm_get_fd(void *audio_handle, void *pcm_handle, int *fd)
912 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
913 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
914 AUDIO_RETURN_VAL_IF_FAIL(fd, AUDIO_ERR_PARAMETER);
915 /* we use an internal API of the (tiny)alsa library, so it causes warning message during compile */
916 #ifdef __USE_TINYALSA__
917 *fd = _pcm_poll_descriptor((struct pcm *)pcm_handle);
919 *fd = _snd_pcm_poll_descriptor((snd_pcm_t *)pcm_handle);
924 #ifdef __USE_TINYALSA__
925 static int __tinyalsa_pcm_recover(struct pcm *pcm, int err)
929 if (err == -EINTR) /* nothing to do, continue */
932 AUDIO_LOG_INFO("XRUN occurred");
933 err = pcm_prepare(pcm);
935 AUDIO_LOG_ERROR("Could not recover from XRUN occurred, prepare failed : %d", err);
940 if (err == -ESTRPIPE) {
941 /* tinyalsa does not support pcm resume, dont't care suspend case */
942 AUDIO_LOG_ERROR("Could not recover from suspend : %d", err);
949 audio_return_t audio_pcm_recover(void *audio_handle, void *pcm_handle, int revents)
953 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
954 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
956 if (revents & POLLERR)
957 AUDIO_LOG_DEBUG("Got POLLERR from ALSA");
958 if (revents & POLLNVAL)
959 AUDIO_LOG_DEBUG("Got POLLNVAL from ALSA");
960 if (revents & POLLHUP)
961 AUDIO_LOG_DEBUG("Got POLLHUP from ALSA");
962 if (revents & POLLPRI)
963 AUDIO_LOG_DEBUG("Got POLLPRI from ALSA");
964 if (revents & POLLIN)
965 AUDIO_LOG_DEBUG("Got POLLIN from ALSA");
966 if (revents & POLLOUT)
967 AUDIO_LOG_DEBUG("Got POLLOUT from ALSA");
969 #ifdef __USE_TINYALSA__
970 state = pcm_state(pcm_handle);
971 AUDIO_LOG_DEBUG("PCM state is %d", state);
975 if ((err = __tinyalsa_pcm_recover(pcm_handle, -EPIPE)) != 0) {
976 AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN : %d", err);
977 return AUDIO_ERR_IOCTL;
981 case PCM_STATE_SUSPENDED:
982 if ((err = __tinyalsa_pcm_recover(pcm_handle, -ESTRPIPE)) != 0) {
983 AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED : %d", err);
984 return AUDIO_ERR_IOCTL;
989 pcm_stop(pcm_handle);
990 if ((err = pcm_prepare(pcm_handle)) < 0) {
991 AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP with pcm_prepare() : %d", err);
992 return AUDIO_ERR_IOCTL;
996 state = snd_pcm_state(pcm_handle);
997 AUDIO_LOG_DEBUG("PCM state is %s", snd_pcm_state_name(state));
999 /* Try to recover from this error */
1002 case SND_PCM_STATE_XRUN:
1003 if ((err = snd_pcm_recover(pcm_handle, -EPIPE, 1)) != 0) {
1004 AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN : %d", err);
1005 return AUDIO_ERR_IOCTL;
1009 case SND_PCM_STATE_SUSPENDED:
1010 if ((err = snd_pcm_recover(pcm_handle, -ESTRPIPE, 1)) != 0) {
1011 AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED : %d", err);
1012 return AUDIO_ERR_IOCTL;
1017 snd_pcm_drop(pcm_handle);
1018 if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
1019 AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare() : %d", err);
1020 return AUDIO_ERR_IOCTL;
1026 AUDIO_LOG_DEBUG("audio_pcm_recover");
1027 return AUDIO_RET_OK;
1030 audio_return_t audio_pcm_get_params(void *audio_handle, void *pcm_handle, uint32_t direction, void **sample_spec, uint32_t *period_size, uint32_t *periods)
1032 #ifdef __USE_TINYALSA__
1033 audio_pcm_sample_spec_t *ss;
1034 unsigned int _period_size, _buffer_size, _periods, _format, _rate, _channels;
1035 unsigned int _start_threshold, _stop_threshold, _silence_threshold;
1036 struct pcm_config *config;
1038 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
1039 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
1040 AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
1041 AUDIO_RETURN_VAL_IF_FAIL(period_size, AUDIO_ERR_PARAMETER);
1042 AUDIO_RETURN_VAL_IF_FAIL(periods, AUDIO_ERR_PARAMETER);
1043 ss = (audio_pcm_sample_spec_t *)*sample_spec;
1045 /* we use an internal API of the tiny alsa library, so it causes warning message during compile */
1046 _pcm_config(pcm_handle, &config);
1048 *period_size = config->period_size;
1049 *periods = config->period_count;
1050 _buffer_size = config->period_size * config->period_count;
1051 ss->format = config->format;
1052 ss->rate = config->rate;
1053 ss->channels = config->channels;
1054 _start_threshold = config->start_threshold;
1055 _stop_threshold = config->stop_threshold;
1056 _silence_threshold = config->silence_threshold;
1058 AUDIO_LOG_DEBUG("audio_pcm_get_params (handle 0x%x, format %d, rate %d, channels %d, period_size %d, periods %d, buffer_size %d)", pcm_handle, config->format, config->rate, config->channels, config->period_size, config->period_count, _buffer_size);
1059 #else /* alsa-lib */
1061 audio_pcm_sample_spec_t *ss;
1063 snd_pcm_uframes_t _period_size, _buffer_size;
1064 snd_pcm_format_t _format;
1065 unsigned int _rate, _channels;
1066 snd_pcm_uframes_t _start_threshold, _stop_threshold, _silence_threshold, _avail_min;
1067 unsigned int _periods;
1068 snd_pcm_hw_params_t *hwparams;
1069 snd_pcm_sw_params_t *swparams;
1071 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
1072 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
1073 AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
1074 AUDIO_RETURN_VAL_IF_FAIL(period_size, AUDIO_ERR_PARAMETER);
1075 AUDIO_RETURN_VAL_IF_FAIL(periods, AUDIO_ERR_PARAMETER);
1076 ss = (audio_pcm_sample_spec_t *)*sample_spec;
1078 snd_pcm_hw_params_alloca(&hwparams);
1079 snd_pcm_sw_params_alloca(&swparams);
1081 if ((err = snd_pcm_hw_params_current(pcm_handle, hwparams)) < 0) {
1082 AUDIO_LOG_ERROR("snd_pcm_hw_params_current() failed : %d", err);
1083 return AUDIO_ERR_PARAMETER;
1086 if ((err = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
1087 (err = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0 ||
1088 (err = snd_pcm_hw_params_get_periods(hwparams, &_periods, &dir)) < 0 ||
1089 (err = snd_pcm_hw_params_get_format(hwparams, &_format)) < 0 ||
1090 (err = snd_pcm_hw_params_get_rate(hwparams, &_rate, &dir)) < 0 ||
1091 (err = snd_pcm_hw_params_get_channels(hwparams, &_channels)) < 0) {
1092 AUDIO_LOG_ERROR("snd_pcm_hw_params_get_{period_size|buffer_size|periods|format|rate|channels}() failed : %s", err);
1093 return AUDIO_ERR_PARAMETER;
1096 *period_size = _period_size;
1097 *periods = _periods;
1098 ss->format = _format;
1100 ss->channels = _channels;
1102 if ((err = snd_pcm_sw_params_current(pcm_handle, swparams)) < 0) {
1103 AUDIO_LOG_ERROR("snd_pcm_sw_params_current() failed : %d", err);
1104 return AUDIO_ERR_PARAMETER;
1107 if ((err = snd_pcm_sw_params_get_start_threshold(swparams, &_start_threshold)) < 0 ||
1108 (err = snd_pcm_sw_params_get_stop_threshold(swparams, &_stop_threshold)) < 0 ||
1109 (err = snd_pcm_sw_params_get_silence_threshold(swparams, &_silence_threshold)) < 0 ||
1110 (err = snd_pcm_sw_params_get_avail_min(swparams, &_avail_min)) < 0) {
1111 AUDIO_LOG_ERROR("snd_pcm_sw_params_get_{start_threshold|stop_threshold|silence_threshold|avail_min}() failed : %s", err);
1114 AUDIO_LOG_DEBUG("audio_pcm_get_params (handle 0x%x, format %d, rate %d, channels %d, period_size %d, periods %d, buffer_size %d)", pcm_handle, _format, _rate, _channels, _period_size, _periods, _buffer_size);
1117 return AUDIO_RET_OK;
1120 audio_return_t audio_pcm_set_params(void *audio_handle, void *pcm_handle, uint32_t direction, void *sample_spec, uint32_t period_size, uint32_t periods)
1122 #ifdef __USE_TINYALSA__
1123 /* Parameters are only acceptable in pcm_open() function */
1124 AUDIO_LOG_DEBUG("audio_pcm_set_params");
1125 #else /* alsa-lib */
1127 audio_pcm_sample_spec_t ss;
1128 snd_pcm_uframes_t _buffer_size;
1129 snd_pcm_hw_params_t *hwparams;
1130 snd_pcm_sw_params_t *swparams;
1132 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
1133 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
1134 AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
1135 AUDIO_RETURN_VAL_IF_FAIL(period_size, AUDIO_ERR_PARAMETER);
1136 AUDIO_RETURN_VAL_IF_FAIL(periods, AUDIO_ERR_PARAMETER);
1137 ss = *(audio_pcm_sample_spec_t *)sample_spec;
1139 snd_pcm_hw_params_alloca(&hwparams);
1140 snd_pcm_sw_params_alloca(&swparams);
1143 if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
1144 AUDIO_LOG_ERROR("snd_pcm_hw_params_any() failed : %d", err);
1145 return AUDIO_ERR_PARAMETER;
1148 if ((err = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) {
1149 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate_resample() failed : %d", err);
1150 return AUDIO_ERR_PARAMETER;
1153 if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
1154 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_access() failed : %d", err);
1155 return AUDIO_ERR_PARAMETER;
1158 ss.format = _convert_format((audio_sample_format_t)ss.format);
1159 if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, ss.format)) < 0) {
1160 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_format() failed : %d", err);
1161 return AUDIO_ERR_PARAMETER;
1164 if ((err = snd_pcm_hw_params_set_rate(pcm_handle, hwparams, ss.rate, 0)) < 0) {
1165 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() failed : %d", err);
1166 return AUDIO_ERR_PARAMETER;
1169 if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss.channels)) < 0) {
1170 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_channels(%u) failed : %d", err);
1171 return AUDIO_ERR_PARAMETER;
1174 if ((err = snd_pcm_hw_params_set_period_size(pcm_handle, hwparams, period_size, 0)) < 0) {
1175 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_period_size(%u) failed : %d", err);
1176 return AUDIO_ERR_PARAMETER;
1179 if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0)) < 0) {
1180 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_periods(%u) failed : %d", periods, err);
1181 return AUDIO_ERR_PARAMETER;
1184 _buffer_size = period_size * periods;
1185 if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, _buffer_size)) < 0) {
1186 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_buffer_size(%u) failed : %d", periods * periods, err);
1187 return AUDIO_ERR_PARAMETER;
1190 if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
1191 AUDIO_LOG_ERROR("snd_pcm_hw_params failed : %d", err);
1192 return AUDIO_ERR_IOCTL;
1196 if ((err = snd_pcm_sw_params_current(pcm_handle, swparams)) < 0) {
1197 AUDIO_LOG_ERROR("Unable to determine current swparams : %d", err);
1198 return AUDIO_ERR_PARAMETER;
1201 if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm_handle, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
1202 AUDIO_LOG_ERROR("Unable to enable time stamping : %d", err);
1203 return AUDIO_ERR_PARAMETER;
1206 if ((err = snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xFFFFFFFF)) < 0) {
1207 AUDIO_LOG_ERROR("Unable to set stop threshold : %d", err);
1208 return AUDIO_ERR_PARAMETER;
1211 if ((err = snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, period_size / 2)) < 0) {
1212 AUDIO_LOG_ERROR("Unable to set start threshold : %d", err);
1213 return AUDIO_ERR_PARAMETER;
1216 if ((err = snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, 1024)) < 0) {
1217 AUDIO_LOG_ERROR("snd_pcm_sw_params_set_avail_min() failed : %d", err);
1218 return AUDIO_ERR_PARAMETER;
1221 if ((err = snd_pcm_sw_params(pcm_handle, swparams)) < 0) {
1222 AUDIO_LOG_ERROR("Unable to set sw params : %d", err);
1223 return AUDIO_ERR_IOCTL;
1226 /* Prepare device */
1227 if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
1228 AUDIO_LOG_ERROR("snd_pcm_prepare() failed : %d", err);
1229 return AUDIO_ERR_IOCTL;
1232 AUDIO_LOG_DEBUG("audio_pcm_set_params (handle 0x%x, format %d, rate %d, channels %d, period_size %d, periods %d, buffer_size %d)", pcm_handle, ss.format, ss.rate, ss.channels, period_size, periods, _buffer_size);
1235 return AUDIO_RET_OK;