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 /* #define DEBUG_TIMING */
33 static device_type_t outDeviceTypes[] = {
34 { AUDIO_DEVICE_OUT_SPEAKER, "Speaker" },
35 { AUDIO_DEVICE_OUT_RECEIVER, "Earpiece" },
36 { AUDIO_DEVICE_OUT_JACK, "Headphones" },
37 { AUDIO_DEVICE_OUT_BT_SCO, "Bluetooth" },
41 static device_type_t inDeviceTypes[] = {
42 { AUDIO_DEVICE_IN_MAIN_MIC, "MainMic" },
43 { AUDIO_DEVICE_IN_SUB_MIC, "SubMic" },
44 { AUDIO_DEVICE_IN_JACK, "HeadsetMic" },
45 { AUDIO_DEVICE_IN_BT_SCO, "BT Mic" },
49 static int _voice_pcm_open(audio_hal_t *ah);
50 static int _voice_pcm_close(audio_hal_t *ah, uint32_t direction);
51 static void _reset_pcm_devices(audio_hal_t *ah);
52 static void _reset_voice_devices_info(audio_hal_t *ah);
54 static uint32_t convert_device_string_to_enum(const char* device_str, uint32_t direction)
58 if (!strncmp(device_str, "builtin-speaker", MAX_NAME_LEN)) {
59 device = AUDIO_DEVICE_OUT_SPEAKER;
60 } else if (!strncmp(device_str, "builtin-receiver", MAX_NAME_LEN)) {
61 device = AUDIO_DEVICE_OUT_RECEIVER;
62 } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
63 device = AUDIO_DEVICE_OUT_JACK;
64 } else if ((!strncmp(device_str, "bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_OUT)) {
65 device = AUDIO_DEVICE_OUT_BT_SCO;
66 } else if ((!strncmp(device_str, "builtin-mic", MAX_NAME_LEN))) {
67 device = AUDIO_DEVICE_IN_MAIN_MIC;
69 } else if ((!strncmp(device_str, "audio-jack", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
70 device = AUDIO_DEVICE_IN_JACK;
71 } else if ((!strncmp(device_str, "bt", MAX_NAME_LEN)) && (direction == AUDIO_DIRECTION_IN)) {
72 device = AUDIO_DEVICE_IN_BT_SCO;
74 device = AUDIO_DEVICE_NONE;
76 AUDIO_LOG_INFO("device type(%s), enum(0x%x)", device_str, device);
80 static audio_return_t set_devices(audio_hal_t *ah, const char *verb, device_info_t *devices, uint32_t num_of_devices)
82 audio_return_t audio_ret = AUDIO_RET_OK;
83 uint32_t new_device = 0;
84 const char *active_devices[MAX_DEVICES] = {NULL,};
85 int i = 0, j = 0, dev_idx = 0;
87 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
88 AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
89 AUDIO_RETURN_VAL_IF_FAIL(num_of_devices, AUDIO_ERR_PARAMETER);
91 if (num_of_devices > MAX_DEVICES) {
92 num_of_devices = MAX_DEVICES;
93 AUDIO_LOG_ERROR("error: num_of_devices");
94 return AUDIO_ERR_PARAMETER;
97 if ((devices[0].direction == AUDIO_DIRECTION_OUT) && ah->device.active_in) {
98 /* check the active in devices */
99 for (j = 0; j < inDeviceTypes[j].type; j++) {
100 if (((ah->device.active_in & (~AUDIO_DEVICE_IN)) & inDeviceTypes[j].type))
101 active_devices[dev_idx++] = inDeviceTypes[j].name;
103 } else if ((devices[0].direction == AUDIO_DIRECTION_IN) && ah->device.active_out) {
104 /* check the active out devices */
105 for (j = 0; j < outDeviceTypes[j].type; j++) {
106 if (ah->device.active_out & outDeviceTypes[j].type)
107 active_devices[dev_idx++] = outDeviceTypes[j].name;
111 for (i = 0; i < num_of_devices; i++) {
112 new_device = convert_device_string_to_enum(devices[i].type, devices[i].direction);
113 if (new_device & AUDIO_DEVICE_IN) {
114 for (j = 0; j < inDeviceTypes[j].type; j++) {
115 if (new_device == inDeviceTypes[j].type) {
116 active_devices[dev_idx++] = inDeviceTypes[j].name;
117 ah->device.active_in |= new_device;
121 for (j = 0; j < outDeviceTypes[j].type; j++) {
122 if (new_device == outDeviceTypes[j].type) {
123 active_devices[dev_idx++] = outDeviceTypes[j].name;
124 ah->device.active_out |= new_device;
130 if (active_devices[0] == NULL) {
131 AUDIO_LOG_ERROR("Failed to set device: active device is NULL");
132 return AUDIO_ERR_PARAMETER;
135 audio_ret = _audio_ucm_set_devices(ah, verb, active_devices);
137 AUDIO_LOG_ERROR("Failed to set device: error = %d", audio_ret);
142 audio_return_t _audio_device_init(audio_hal_t *ah)
144 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
146 ah->device.active_in = 0x0;
147 ah->device.active_out = 0x0;
148 ah->device.pcm_in = NULL;
149 ah->device.pcm_out = NULL;
150 ah->device.mode = VERB_NORMAL;
151 pthread_mutex_init(&ah->device.pcm_lock, NULL);
152 pthread_mutex_init(&ah->device.device_lock, NULL);
153 pthread_cond_init(&ah->device.device_cond, NULL);
154 ah->device.pcm_count = 0;
159 audio_return_t _audio_device_deinit(audio_hal_t *ah)
161 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
163 pthread_mutex_destroy(&ah->device.pcm_lock);
164 pthread_mutex_destroy(&ah->device.device_lock);
165 pthread_cond_destroy(&ah->device.device_cond);
169 static audio_return_t _do_route_ap_playback_capture(audio_hal_t *ah, audio_route_info_t *route_info)
171 audio_return_t audio_ret = AUDIO_RET_OK;
172 device_info_t *devices = NULL;
173 const char *verb = NULL;
174 #if 0 /* Disable setting modifiers, because driver does not support it yet */
176 const char *modifiers[MAX_MODIFIERS] = {NULL,};
179 if (ah->device.mode != VERB_NORMAL) {
180 if (ah->device.mode == VERB_CALL) {
181 _reset_voice_devices_info(ah);
182 COND_SIGNAL(ah->device.device_cond, "device_cond");
184 _reset_pcm_devices(ah);
185 ah->device.mode = VERB_NORMAL;
188 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
189 AUDIO_RETURN_VAL_IF_FAIL(route_info, AUDIO_ERR_PARAMETER);
191 devices = route_info->device_infos;
193 verb = AUDIO_USE_CASE_VERB_HIFI;
194 AUDIO_LOG_INFO("do_route_ap_playback_capture++ ");
196 audio_ret = set_devices(ah, verb, devices, route_info->num_of_devices);
198 AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
201 ah->device.mode = VERB_NORMAL;
203 #if 0 /* Disable setting modifiers, because driver does not support it yet */
205 if (!strncmp("voice_recognition", route_info->role, MAX_NAME_LEN)) {
206 modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_VOICESEARCH;
207 } else if ((!strncmp("alarm", route_info->role, MAX_NAME_LEN))||(!strncmp("notifiication", route_info->role, MAX_NAME_LEN))) {
208 if (ah->device.active_out &= AUDIO_DEVICE_OUT_JACK)
209 modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_DUAL_MEDIA;
211 modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
212 } else if (!strncmp("ringtone", route_info->role, MAX_NAME_LEN)) {
213 if (ah->device.active_out)
214 modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_RINGTONE;
216 if (ah->device.active_in)
217 modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_CAMCORDING;
219 modifiers[mod_idx++] = AUDIO_USE_CASE_MODIFIER_MEDIA;
221 audio_ret = _audio_ucm_set_modifiers (ah, verb, modifiers);
226 static audio_return_t _do_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
228 audio_return_t audio_ret = AUDIO_RET_OK;
229 const char *verb = AUDIO_USE_CASE_VERB_VOICECALL;
231 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
232 /* if both params are 0, return error for invalid state,
233 * this error would be used to tizen-audio-modem.c */
234 AUDIO_RETURN_VAL_IF_FAIL((devices||num_of_devices), AUDIO_ERR_INVALID_STATE);
235 AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
237 AUDIO_LOG_INFO("do_route_voicecall++");
239 audio_ret = set_devices(ah, verb, devices, num_of_devices);
241 AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
245 if (ah->device.mode != VERB_CALL) {
247 ah->device.mode = VERB_CALL;
248 /* FIXME. Get network info and configure rate in pcm device */
254 static audio_return_t _do_route_voip(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
256 audio_return_t audio_ret = AUDIO_RET_OK;
257 const char *verb = NULL;
258 verb = AUDIO_USE_CASE_VERB_HIFI;
260 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
261 AUDIO_RETURN_VAL_IF_FAIL(devices, AUDIO_ERR_PARAMETER);
263 AUDIO_LOG_INFO("do_route_voip++");
265 audio_ret = set_devices(ah, verb, devices, num_of_devices);
267 AUDIO_LOG_ERROR("Failed to set devices: error = 0x%x", audio_ret);
270 /* FIXME. If necessary, set VERB_VOIP */
271 ah->device.mode = VERB_NORMAL;
273 /* TO DO: Set modifiers */
277 static audio_return_t _do_route_reset(audio_hal_t *ah, uint32_t direction)
279 audio_return_t audio_ret = AUDIO_RET_OK;
281 /* FIXME: If you need to reset, set verb inactive */
282 /* const char *verb = NULL; */
283 /* verb = AUDIO_USE_CASE_VERB_INACTIVE; */
285 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
287 AUDIO_LOG_INFO("do_route_reset++, direction(0x%x)", direction);
289 if (direction == AUDIO_DIRECTION_OUT) {
290 ah->device.active_out &= 0x0;
292 ah->device.active_in &= 0x0;
294 if (ah->device.mode == VERB_CALL) {
295 _voice_pcm_close(ah, direction);
296 if (!ah->device.active_in && !ah->device.active_out)
297 ah->device.mode = VERB_NORMAL;
298 _reset_voice_devices_info(ah);
299 COND_SIGNAL(ah->device.device_cond, "device_cond");
302 /* TO DO: Set Inactive */
306 audio_return_t audio_do_route(void *audio_handle, audio_route_info_t *info)
308 audio_return_t audio_ret = AUDIO_RET_OK;
309 audio_hal_t *ah = (audio_hal_t *)audio_handle;
310 device_info_t *devices = NULL;
313 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
314 AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
316 AUDIO_LOG_INFO("role:%s", info->role);
318 devices = info->device_infos;
320 if (!strncmp("call-voice", info->role, MAX_NAME_LEN)) {
321 if (!ah->modem.is_connected) {
322 if (info->num_of_devices) {
323 if (!ah->device.num_of_call_devices) {
324 if ((ah->device.init_call_devices = (device_info_t*)calloc(info->num_of_devices, sizeof(device_info_t)))) {
325 memcpy(ah->device.init_call_devices, devices, info->num_of_devices*sizeof(device_info_t));
326 ah->device.num_of_call_devices = info->num_of_devices;
328 AUDIO_LOG_ERROR("failed to calloc");
329 audio_ret = AUDIO_ERR_RESOURCE;
332 } else if (ah->device.num_of_call_devices) {
333 prev_size = ah->device.num_of_call_devices;
334 ah->device.num_of_call_devices += info->num_of_devices;
335 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))) {
336 memcpy((void*)&(ah->device.init_call_devices[prev_size]), devices, info->num_of_devices*sizeof(device_info_t));
338 AUDIO_LOG_ERROR("failed to realloc");
339 audio_ret = AUDIO_ERR_RESOURCE;
344 AUDIO_LOG_ERROR("failed to do route for call-voice, num_of_devices is 0");
345 audio_ret = AUDIO_ERR_PARAMETER;
348 AUDIO_LOG_INFO("modem is not ready, skip...");
350 audio_ret = _do_route_voicecall(ah, devices, info->num_of_devices);
351 if (AUDIO_IS_ERROR(audio_ret)) {
352 AUDIO_LOG_WARN("set voicecall route return 0x%x", audio_ret);
354 COND_SIGNAL(ah->device.device_cond, "device_cond");
356 } else if (!strncmp("voip", info->role, MAX_NAME_LEN)) {
357 audio_ret = _do_route_voip(ah, devices, info->num_of_devices);
358 if (AUDIO_IS_ERROR(audio_ret)) {
359 AUDIO_LOG_WARN("set voip route return 0x%x", audio_ret);
361 } else if (!strncmp("reset", info->role, MAX_NAME_LEN)) {
362 audio_ret = _do_route_reset(ah, devices->direction);
363 if (AUDIO_IS_ERROR(audio_ret)) {
364 AUDIO_LOG_WARN("set reset return 0x%x", audio_ret);
367 /* need to prepare for "alarm","notification","emergency","voice-information","voice-recognition","ringtone" */
368 audio_ret = _do_route_ap_playback_capture(ah, info);
369 if (AUDIO_IS_ERROR(audio_ret)) {
370 AUDIO_LOG_WARN("set playback route return 0x%x", audio_ret);
378 audio_return_t audio_update_stream_connection_info(void *audio_handle, audio_stream_info_t *info, uint32_t is_connected)
380 audio_return_t audio_ret = AUDIO_RET_OK;
381 audio_hal_t *ah = (audio_hal_t *)audio_handle;
383 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
384 AUDIO_RETURN_VAL_IF_FAIL(info, AUDIO_ERR_PARAMETER);
386 AUDIO_LOG_INFO("role:%s, direction:%u, idx:%u, is_connected:%d", info->role, info->direction, info->idx, is_connected);
391 audio_return_t audio_update_route_option(void *audio_handle, audio_route_option_t *option)
393 audio_return_t audio_ret = AUDIO_RET_OK;
394 audio_hal_t *ah = (audio_hal_t *)audio_handle;
396 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
397 AUDIO_RETURN_VAL_IF_FAIL(option, AUDIO_ERR_PARAMETER);
399 AUDIO_LOG_INFO("role:%s, name:%s, value:%d", option->role, option->name, option->value);
404 static int __voice_pcm_set_params(audio_hal_t *ah, snd_pcm_t *pcm)
406 snd_pcm_hw_params_t *params = NULL;
408 unsigned int val = 0;
410 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
411 AUDIO_RETURN_VAL_IF_FAIL(pcm, AUDIO_ERR_PARAMETER);
413 /* Skip parameter setting to null device. */
414 if (snd_pcm_type(pcm) == SND_PCM_TYPE_NULL)
415 return AUDIO_ERR_IOCTL;
417 /* Allocate a hardware parameters object. */
418 snd_pcm_hw_params_alloca(¶ms);
420 /* Fill it in with default values. */
421 if (snd_pcm_hw_params_any(pcm, params) < 0) {
422 AUDIO_LOG_ERROR("snd_pcm_hw_params_any() : failed! - %s\n", snd_strerror(err));
426 /* Set the desired hardware parameters. */
427 /* Interleaved mode */
428 err = snd_pcm_hw_params_set_access(pcm, params, SND_PCM_ACCESS_RW_INTERLEAVED);
430 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_access() : failed! - %s\n", snd_strerror(err));
433 err = snd_pcm_hw_params_set_rate(pcm, params, 8000, 0);
435 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() : failed! - %s\n", snd_strerror(err));
437 err = snd_pcm_hw_params(pcm, params);
439 AUDIO_LOG_ERROR("snd_pcm_hw_params() : failed! - %s\n", snd_strerror(err));
443 /* Dump current param */
444 snd_pcm_hw_params_get_access(params, (snd_pcm_access_t *) &val);
445 AUDIO_LOG_DEBUG("access type = %s\n", snd_pcm_access_name((snd_pcm_access_t)val));
447 snd_pcm_hw_params_get_format(params, (snd_pcm_format_t*)&val);
448 AUDIO_LOG_DEBUG("format = '%s' (%s)\n",
449 snd_pcm_format_name((snd_pcm_format_t)val),
450 snd_pcm_format_description((snd_pcm_format_t)val));
452 snd_pcm_hw_params_get_subformat(params, (snd_pcm_subformat_t *)&val);
453 AUDIO_LOG_DEBUG("subformat = '%s' (%s)\n",
454 snd_pcm_subformat_name((snd_pcm_subformat_t)val),
455 snd_pcm_subformat_description((snd_pcm_subformat_t)val));
457 snd_pcm_hw_params_get_channels(params, &val);
458 AUDIO_LOG_DEBUG("channels = %d\n", val);
466 static int _voice_pcm_open(audio_hal_t *ah)
470 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
472 AUDIO_LOG_INFO("open voice pcm handles");
474 /* Get playback voice-pcm from ucm conf. Open and set-params */
475 if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_out, VOICE_PCM_DEVICE, AUDIO_DIRECTION_OUT, 0)) < 0) {
476 AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
477 return AUDIO_ERR_IOCTL;
479 ret = __voice_pcm_set_params(ah, ah->device.pcm_out);
481 AUDIO_LOG_INFO("pcm playback device open success device(%s)", VOICE_PCM_DEVICE);
483 /* Get capture voice-pcm from ucm conf. Open and set-params */
484 if ((err = snd_pcm_open((snd_pcm_t **)&ah->device.pcm_in, VOICE_PCM_DEVICE, AUDIO_DIRECTION_IN, 0)) < 0) {
485 AUDIO_LOG_ERROR("snd_pcm_open for %s failed. %s", VOICE_PCM_DEVICE, snd_strerror(err));
486 return AUDIO_ERR_IOCTL;
488 ret = __voice_pcm_set_params(ah, ah->device.pcm_in);
489 AUDIO_LOG_INFO("pcm captures device open success device(%s)", VOICE_PCM_DEVICE);
494 static int _voice_pcm_close(audio_hal_t *ah, uint32_t direction)
496 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
498 AUDIO_LOG_INFO("close voice pcm handles");
500 if (ah->device.pcm_out && (direction == AUDIO_DIRECTION_OUT)) {
501 audio_pcm_close((void *)ah, ah->device.pcm_out);
502 ah->device.pcm_out = NULL;
503 AUDIO_LOG_INFO("voice pcm_out handle close success");
504 } else if (ah->device.pcm_in && (direction == AUDIO_DIRECTION_IN)) {
505 audio_pcm_close((void *)ah, ah->device.pcm_in);
506 ah->device.pcm_in = NULL;
507 AUDIO_LOG_INFO("voice pcm_in handle close success");
513 static void _reset_pcm_devices(audio_hal_t *ah)
515 AUDIO_RETURN_IF_FAIL(ah);
517 if (ah->device.pcm_out) {
518 audio_pcm_close((void *)ah, ah->device.pcm_out);
519 ah->device.pcm_out = NULL;
520 AUDIO_LOG_INFO("pcm_out handle close success");
522 if (ah->device.pcm_in) {
523 audio_pcm_close((void *)ah, ah->device.pcm_in);
524 ah->device.pcm_in = NULL;
525 AUDIO_LOG_INFO("pcm_in handle close success");
531 static void _reset_voice_devices_info(audio_hal_t *ah)
533 AUDIO_RETURN_IF_FAIL(ah);
535 AUDIO_LOG_INFO("reset voice device info");
536 if (ah->device.init_call_devices) {
537 free(ah->device.init_call_devices);
538 ah->device.init_call_devices = NULL;
539 ah->device.num_of_call_devices = 0;
545 #ifdef __USE_TINYALSA__
546 static struct pcm *__tinyalsa_open_device(audio_pcm_sample_spec_t *ss, size_t period_size, size_t period_count, uint32_t direction)
548 struct pcm *pcm = NULL;
549 struct pcm_config config;
551 AUDIO_RETURN_NULL_IF_FAIL(ss);
553 config.channels = ss->channels;
554 config.rate = ss->rate;
555 config.period_size = period_size;
556 config.period_count = period_count;
557 config.format = ss->format;
558 config.start_threshold = period_size;
559 config.stop_threshold = 0xFFFFFFFF;
560 config.silence_threshold = 0;
562 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);
564 pcm = pcm_open((direction == AUDIO_DIRECTION_OUT) ? PLAYBACK_CARD_ID : CAPTURE_CARD_ID,
565 (direction == AUDIO_DIRECTION_OUT) ? PLAYBACK_PCM_DEVICE_ID : CAPTURE_PCM_DEVICE_ID,
566 (direction == AUDIO_DIRECTION_OUT) ? PCM_OUT : PCM_IN,
568 if (!pcm || !pcm_is_ready(pcm)) {
569 AUDIO_LOG_ERROR("Unable to open device (%s)", pcm_get_error(pcm));
578 audio_return_t _audio_do_route_voicecall(audio_hal_t *ah, device_info_t *devices, int32_t num_of_devices)
580 return _do_route_voicecall(ah, devices, num_of_devices);
583 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)
585 #ifdef __USE_TINYALSA__
587 audio_pcm_sample_spec_t *ss;
590 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
591 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
592 AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
593 AUDIO_RETURN_VAL_IF_FAIL((period_size > 0), AUDIO_ERR_PARAMETER);
594 AUDIO_RETURN_VAL_IF_FAIL((periods > 0), AUDIO_ERR_PARAMETER);
596 ah = (audio_hal_t *)audio_handle;
597 ss = (audio_pcm_sample_spec_t *)sample_spec;
598 ss->format = _convert_format((audio_sample_format_t)ss->format);
600 *pcm_handle = __tinyalsa_open_device(ss, (size_t)period_size, (size_t)periods, direction);
601 if (*pcm_handle == NULL) {
602 AUDIO_LOG_ERROR("Error opening PCM device");
603 return AUDIO_ERR_RESOURCE;
606 if ((err = pcm_prepare((struct pcm *)*pcm_handle)) != 0) {
607 AUDIO_LOG_ERROR("Error prepare PCM device : %d", err);
610 ah->device.pcm_count++;
611 AUDIO_LOG_INFO("Opening PCM handle 0x%x", *pcm_handle);
615 char *device_name = NULL;
617 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
618 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
619 AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
620 AUDIO_RETURN_VAL_IF_FAIL((period_size > 0), AUDIO_ERR_PARAMETER);
621 AUDIO_RETURN_VAL_IF_FAIL((periods > 0), AUDIO_ERR_PARAMETER);
623 ah = (audio_hal_t *)audio_handle;
624 mode = SND_PCM_NONBLOCK | SND_PCM_NO_AUTO_RESAMPLE | SND_PCM_NO_AUTO_CHANNELS | SND_PCM_NO_AUTO_FORMAT;
626 if (direction == AUDIO_DIRECTION_OUT)
627 device_name = PLAYBACK_PCM_DEVICE;
628 else if (direction == AUDIO_DIRECTION_IN)
629 device_name = CAPTURE_PCM_DEVICE;
631 AUDIO_LOG_ERROR("Error get device_name, direction : %d", direction);
632 return AUDIO_ERR_RESOURCE;
635 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) {
636 AUDIO_LOG_ERROR("Error opening PCM device %s : %s", device_name, snd_strerror(err));
637 return AUDIO_ERR_RESOURCE;
640 if ((err = audio_pcm_set_params(audio_handle, *pcm_handle, direction, sample_spec, period_size, periods)) != AUDIO_RET_OK) {
641 AUDIO_LOG_ERROR("Failed to set pcm parameters : %d", err);
645 ah->device.pcm_count++;
646 AUDIO_LOG_INFO("Opening PCM handle 0x%x, PCM device %s", *pcm_handle, device_name);
652 audio_return_t audio_pcm_start(void *audio_handle, void *pcm_handle)
656 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
657 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
659 #ifdef __USE_TINYALSA__
660 if ((err = pcm_start(pcm_handle)) < 0) {
661 AUDIO_LOG_ERROR("Error starting PCM handle : %d", err);
662 return AUDIO_ERR_RESOURCE;
665 if ((err = snd_pcm_start(pcm_handle)) < 0) {
666 AUDIO_LOG_ERROR("Error starting PCM handle : %s", snd_strerror(err));
667 return AUDIO_ERR_RESOURCE;
671 AUDIO_LOG_INFO("PCM handle 0x%x start", pcm_handle);
675 audio_return_t audio_pcm_stop(void *audio_handle, void *pcm_handle)
679 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
680 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
682 #ifdef __USE_TINYALSA__
683 if ((err = pcm_stop(pcm_handle)) < 0) {
684 AUDIO_LOG_ERROR("Error stopping PCM handle : %d", err);
685 return AUDIO_ERR_RESOURCE;
688 if ((err = snd_pcm_drop(pcm_handle)) < 0) {
689 AUDIO_LOG_ERROR("Error stopping PCM handle : %s", snd_strerror(err));
690 return AUDIO_ERR_RESOURCE;
694 AUDIO_LOG_INFO("PCM handle 0x%x stop", pcm_handle);
698 audio_return_t audio_pcm_close(void *audio_handle, void *pcm_handle)
700 audio_hal_t *ah = (audio_hal_t *)audio_handle;
703 AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
704 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
706 AUDIO_LOG_INFO("Try to close PCM handle 0x%x", pcm_handle);
708 #ifdef __USE_TINYALSA__
709 if ((err = pcm_close(pcm_handle)) < 0) {
710 AUDIO_LOG_ERROR("Error closing PCM handle : %d", err);
711 return AUDIO_ERR_RESOURCE;
714 if ((err = snd_pcm_close(pcm_handle)) < 0) {
715 AUDIO_LOG_ERROR("Error closing PCM handle : %s", snd_strerror(err));
716 return AUDIO_ERR_RESOURCE;
721 ah->device.pcm_count--;
722 AUDIO_LOG_INFO("PCM handle close success (count:%d)", ah->device.pcm_count);
727 audio_return_t audio_pcm_avail(void *audio_handle, void *pcm_handle, uint32_t *avail)
729 #ifdef __USE_TINYALSA__
730 struct timespec tspec;
731 unsigned int frames_avail = 0;
734 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
735 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
736 AUDIO_RETURN_VAL_IF_FAIL(avail, AUDIO_ERR_PARAMETER);
738 err = pcm_get_htimestamp(pcm_handle, &frames_avail, &tspec);
740 AUDIO_LOG_ERROR("Could not get avail and timespec at PCM handle 0x%x : %d", pcm_handle, err);
741 return AUDIO_ERR_IOCTL;
745 AUDIO_LOG_DEBUG("avail = %d", frames_avail);
748 *avail = (uint32_t)frames_avail;
750 snd_pcm_sframes_t frames_avail;
752 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
753 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
754 AUDIO_RETURN_VAL_IF_FAIL(avail, AUDIO_ERR_PARAMETER);
756 if ((frames_avail = snd_pcm_avail(pcm_handle)) < 0) {
757 AUDIO_LOG_ERROR("Could not get avail at PCM handle 0x%x : %d", pcm_handle, frames_avail);
758 return AUDIO_ERR_IOCTL;
762 AUDIO_LOG_DEBUG("avail = %d", frames_avail);
765 *avail = (uint32_t)frames_avail;
771 audio_return_t audio_pcm_write(void *audio_handle, void *pcm_handle, const void *buffer, uint32_t frames)
773 #ifdef __USE_TINYALSA__
776 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
777 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
779 err = pcm_write(pcm_handle, buffer, pcm_frames_to_bytes(pcm_handle, (unsigned int)frames));
781 AUDIO_LOG_ERROR("Failed to write pcm : %d", err);
782 return AUDIO_ERR_IOCTL;
786 AUDIO_LOG_DEBUG("audio_pcm_write = %d", frames);
789 snd_pcm_sframes_t frames_written;
791 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
793 frames_written = snd_pcm_writei(pcm_handle, buffer, (snd_pcm_uframes_t) frames);
794 if (frames_written < 0) {
795 AUDIO_LOG_ERROR("Failed to write pcm : %d", frames_written);
796 return AUDIO_ERR_IOCTL;
800 AUDIO_LOG_DEBUG("audio_pcm_write = (%d / %d)", frames_written, frames);
807 audio_return_t audio_pcm_read(void *audio_handle, void *pcm_handle, void *buffer, uint32_t frames)
809 #ifdef __USE_TINYALSA__
812 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
813 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
815 err = pcm_read(pcm_handle, buffer, pcm_frames_to_bytes(pcm_handle, (unsigned int)frames));
817 AUDIO_LOG_ERROR("Failed to read pcm : %d", err);
818 return AUDIO_ERR_IOCTL;
822 AUDIO_LOG_DEBUG("audio_pcm_read = %d", frames);
825 snd_pcm_sframes_t frames_read;
827 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
828 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
830 frames_read = snd_pcm_readi(pcm_handle, buffer, (snd_pcm_uframes_t)frames);
831 if (frames_read < 0) {
832 AUDIO_LOG_ERROR("Failed to read pcm : %d", frames_read);
833 return AUDIO_ERR_IOCTL;
837 AUDIO_LOG_DEBUG("audio_pcm_read = (%d / %d)", frames_read, frames);
844 audio_return_t audio_pcm_get_fd(void *audio_handle, void *pcm_handle, int *fd)
846 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
847 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
848 AUDIO_RETURN_VAL_IF_FAIL(fd, AUDIO_ERR_PARAMETER);
849 /* we use an internal API of the (tiny)alsa library, so it causes warning message during compile */
850 #ifdef __USE_TINYALSA__
851 *fd = _pcm_poll_descriptor((struct pcm *)pcm_handle);
853 *fd = _snd_pcm_poll_descriptor((snd_pcm_t *)pcm_handle);
858 #ifdef __USE_TINYALSA__
859 static int __tinyalsa_pcm_recover(struct pcm *pcm, int err)
863 if (err == -EINTR) /* nothing to do, continue */
866 AUDIO_LOG_INFO("XRUN occurred");
867 err = pcm_prepare(pcm);
869 AUDIO_LOG_ERROR("Could not recover from XRUN occurred, prepare failed : %d", err);
874 if (err == -ESTRPIPE) {
875 /* tinyalsa does not support pcm resume, dont't care suspend case */
876 AUDIO_LOG_ERROR("Could not recover from suspend : %d", err);
883 audio_return_t audio_pcm_recover(void *audio_handle, void *pcm_handle, int revents)
887 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
888 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
890 if (revents & POLLERR)
891 AUDIO_LOG_DEBUG("Got POLLERR from ALSA");
892 if (revents & POLLNVAL)
893 AUDIO_LOG_DEBUG("Got POLLNVAL from ALSA");
894 if (revents & POLLHUP)
895 AUDIO_LOG_DEBUG("Got POLLHUP from ALSA");
896 if (revents & POLLPRI)
897 AUDIO_LOG_DEBUG("Got POLLPRI from ALSA");
898 if (revents & POLLIN)
899 AUDIO_LOG_DEBUG("Got POLLIN from ALSA");
900 if (revents & POLLOUT)
901 AUDIO_LOG_DEBUG("Got POLLOUT from ALSA");
903 #ifdef __USE_TINYALSA__
904 state = pcm_state(pcm_handle);
905 AUDIO_LOG_DEBUG("PCM state is %d", state);
909 if ((err = __tinyalsa_pcm_recover(pcm_handle, -EPIPE)) != 0) {
910 AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN : %d", err);
911 return AUDIO_ERR_IOCTL;
915 case PCM_STATE_SUSPENDED:
916 if ((err = __tinyalsa_pcm_recover(pcm_handle, -ESTRPIPE)) != 0) {
917 AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED : %d", err);
918 return AUDIO_ERR_IOCTL;
923 pcm_stop(pcm_handle);
924 if ((err = pcm_prepare(pcm_handle)) < 0) {
925 AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP with pcm_prepare() : %d", err);
926 return AUDIO_ERR_IOCTL;
930 state = snd_pcm_state(pcm_handle);
931 AUDIO_LOG_DEBUG("PCM state is %s", snd_pcm_state_name(state));
933 /* Try to recover from this error */
936 case SND_PCM_STATE_XRUN:
937 if ((err = snd_pcm_recover(pcm_handle, -EPIPE, 1)) != 0) {
938 AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and XRUN : %d", err);
939 return AUDIO_ERR_IOCTL;
943 case SND_PCM_STATE_SUSPENDED:
944 if ((err = snd_pcm_recover(pcm_handle, -ESTRPIPE, 1)) != 0) {
945 AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP and SUSPENDED : %d", err);
946 return AUDIO_ERR_IOCTL;
951 snd_pcm_drop(pcm_handle);
952 if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
953 AUDIO_LOG_ERROR("Could not recover from POLLERR|POLLNVAL|POLLHUP with snd_pcm_prepare() : %d", err);
954 return AUDIO_ERR_IOCTL;
960 AUDIO_LOG_DEBUG("audio_pcm_recover");
964 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)
966 #ifdef __USE_TINYALSA__
967 audio_pcm_sample_spec_t *ss;
968 unsigned int _period_size, _buffer_size, _periods, _format, _rate, _channels;
969 unsigned int _start_threshold, _stop_threshold, _silence_threshold;
970 struct pcm_config *config;
972 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
973 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
974 AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
975 AUDIO_RETURN_VAL_IF_FAIL(period_size, AUDIO_ERR_PARAMETER);
976 AUDIO_RETURN_VAL_IF_FAIL(periods, AUDIO_ERR_PARAMETER);
977 ss = (audio_pcm_sample_spec_t *)*sample_spec;
979 /* we use an internal API of the tiny alsa library, so it causes warning message during compile */
980 _pcm_config(pcm_handle, &config);
982 *period_size = config->period_size;
983 *periods = config->period_count;
984 _buffer_size = config->period_size * config->period_count;
985 ss->format = config->format;
986 ss->rate = config->rate;
987 ss->channels = config->channels;
988 _start_threshold = config->start_threshold;
989 _stop_threshold = config->stop_threshold;
990 _silence_threshold = config->silence_threshold;
992 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);
995 audio_pcm_sample_spec_t *ss;
997 snd_pcm_uframes_t _period_size, _buffer_size;
998 snd_pcm_format_t _format;
999 unsigned int _rate, _channels;
1000 snd_pcm_uframes_t _start_threshold, _stop_threshold, _silence_threshold, _avail_min;
1001 unsigned int _periods;
1002 snd_pcm_hw_params_t *hwparams;
1003 snd_pcm_sw_params_t *swparams;
1005 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
1006 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
1007 AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
1008 AUDIO_RETURN_VAL_IF_FAIL(period_size, AUDIO_ERR_PARAMETER);
1009 AUDIO_RETURN_VAL_IF_FAIL(periods, AUDIO_ERR_PARAMETER);
1010 ss = (audio_pcm_sample_spec_t *)*sample_spec;
1012 snd_pcm_hw_params_alloca(&hwparams);
1013 snd_pcm_sw_params_alloca(&swparams);
1015 if ((err = snd_pcm_hw_params_current(pcm_handle, hwparams)) < 0) {
1016 AUDIO_LOG_ERROR("snd_pcm_hw_params_current() failed : %d", err);
1017 return AUDIO_ERR_PARAMETER;
1020 if ((err = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
1021 (err = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0 ||
1022 (err = snd_pcm_hw_params_get_periods(hwparams, &_periods, &dir)) < 0 ||
1023 (err = snd_pcm_hw_params_get_format(hwparams, &_format)) < 0 ||
1024 (err = snd_pcm_hw_params_get_rate(hwparams, &_rate, &dir)) < 0 ||
1025 (err = snd_pcm_hw_params_get_channels(hwparams, &_channels)) < 0) {
1026 AUDIO_LOG_ERROR("snd_pcm_hw_params_get_{period_size|buffer_size|periods|format|rate|channels}() failed : %s", err);
1027 return AUDIO_ERR_PARAMETER;
1030 *period_size = _period_size;
1031 *periods = _periods;
1032 ss->format = _format;
1034 ss->channels = _channels;
1036 if ((err = snd_pcm_sw_params_current(pcm_handle, swparams)) < 0) {
1037 AUDIO_LOG_ERROR("snd_pcm_sw_params_current() failed : %d", err);
1038 return AUDIO_ERR_PARAMETER;
1041 if ((err = snd_pcm_sw_params_get_start_threshold(swparams, &_start_threshold)) < 0 ||
1042 (err = snd_pcm_sw_params_get_stop_threshold(swparams, &_stop_threshold)) < 0 ||
1043 (err = snd_pcm_sw_params_get_silence_threshold(swparams, &_silence_threshold)) < 0 ||
1044 (err = snd_pcm_sw_params_get_avail_min(swparams, &_avail_min)) < 0) {
1045 AUDIO_LOG_ERROR("snd_pcm_sw_params_get_{start_threshold|stop_threshold|silence_threshold|avail_min}() failed : %s", err);
1048 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);
1051 return AUDIO_RET_OK;
1054 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)
1056 #ifdef __USE_TINYALSA__
1057 /* Parameters are only acceptable in pcm_open() function */
1058 AUDIO_LOG_DEBUG("audio_pcm_set_params");
1059 #else /* alsa-lib */
1061 audio_pcm_sample_spec_t ss;
1062 snd_pcm_uframes_t _buffer_size;
1063 snd_pcm_hw_params_t *hwparams;
1064 snd_pcm_sw_params_t *swparams;
1066 AUDIO_RETURN_VAL_IF_FAIL(audio_handle, AUDIO_ERR_PARAMETER);
1067 AUDIO_RETURN_VAL_IF_FAIL(pcm_handle, AUDIO_ERR_PARAMETER);
1068 AUDIO_RETURN_VAL_IF_FAIL(sample_spec, AUDIO_ERR_PARAMETER);
1069 AUDIO_RETURN_VAL_IF_FAIL(period_size, AUDIO_ERR_PARAMETER);
1070 AUDIO_RETURN_VAL_IF_FAIL(periods, AUDIO_ERR_PARAMETER);
1071 ss = *(audio_pcm_sample_spec_t *)sample_spec;
1073 snd_pcm_hw_params_alloca(&hwparams);
1074 snd_pcm_sw_params_alloca(&swparams);
1077 if ((err = snd_pcm_hw_params_any(pcm_handle, hwparams)) < 0) {
1078 AUDIO_LOG_ERROR("snd_pcm_hw_params_any() failed : %d", err);
1079 return AUDIO_ERR_PARAMETER;
1082 if ((err = snd_pcm_hw_params_set_rate_resample(pcm_handle, hwparams, 0)) < 0) {
1083 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate_resample() failed : %d", err);
1084 return AUDIO_ERR_PARAMETER;
1087 if ((err = snd_pcm_hw_params_set_access(pcm_handle, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
1088 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_access() failed : %d", err);
1089 return AUDIO_ERR_PARAMETER;
1092 ss.format = _convert_format((audio_sample_format_t)ss.format);
1093 if ((err = snd_pcm_hw_params_set_format(pcm_handle, hwparams, ss.format)) < 0) {
1094 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_format() failed : %d", err);
1095 return AUDIO_ERR_PARAMETER;
1098 if ((err = snd_pcm_hw_params_set_rate(pcm_handle, hwparams, ss.rate, 0)) < 0) {
1099 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() failed : %d", err);
1100 return AUDIO_ERR_PARAMETER;
1103 if ((err = snd_pcm_hw_params_set_channels(pcm_handle, hwparams, ss.channels)) < 0) {
1104 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_channels(%u) failed : %d", err);
1105 return AUDIO_ERR_PARAMETER;
1108 if ((err = snd_pcm_hw_params_set_period_size(pcm_handle, hwparams, period_size, 0)) < 0) {
1109 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_period_size(%u) failed : %d", err);
1110 return AUDIO_ERR_PARAMETER;
1113 if ((err = snd_pcm_hw_params_set_periods(pcm_handle, hwparams, periods, 0)) < 0) {
1114 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_periods(%u) failed : %d", periods, err);
1115 return AUDIO_ERR_PARAMETER;
1118 _buffer_size = period_size * periods;
1119 if ((err = snd_pcm_hw_params_set_buffer_size(pcm_handle, hwparams, _buffer_size)) < 0) {
1120 AUDIO_LOG_ERROR("snd_pcm_hw_params_set_buffer_size(%u) failed : %d", periods * periods, err);
1121 return AUDIO_ERR_PARAMETER;
1124 if ((err = snd_pcm_hw_params(pcm_handle, hwparams)) < 0) {
1125 AUDIO_LOG_ERROR("snd_pcm_hw_params failed : %d", err);
1126 return AUDIO_ERR_IOCTL;
1130 if ((err = snd_pcm_sw_params_current(pcm_handle, swparams)) < 0) {
1131 AUDIO_LOG_ERROR("Unable to determine current swparams : %d", err);
1132 return AUDIO_ERR_PARAMETER;
1135 if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm_handle, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
1136 AUDIO_LOG_ERROR("Unable to enable time stamping : %d", err);
1137 return AUDIO_ERR_PARAMETER;
1140 if ((err = snd_pcm_sw_params_set_stop_threshold(pcm_handle, swparams, 0xFFFFFFFF)) < 0) {
1141 AUDIO_LOG_ERROR("Unable to set stop threshold : %d", err);
1142 return AUDIO_ERR_PARAMETER;
1145 if ((err = snd_pcm_sw_params_set_start_threshold(pcm_handle, swparams, period_size / 2)) < 0) {
1146 AUDIO_LOG_ERROR("Unable to set start threshold : %d", err);
1147 return AUDIO_ERR_PARAMETER;
1150 if ((err = snd_pcm_sw_params_set_avail_min(pcm_handle, swparams, 1024)) < 0) {
1151 AUDIO_LOG_ERROR("snd_pcm_sw_params_set_avail_min() failed : %d", err);
1152 return AUDIO_ERR_PARAMETER;
1155 if ((err = snd_pcm_sw_params(pcm_handle, swparams)) < 0) {
1156 AUDIO_LOG_ERROR("Unable to set sw params : %d", err);
1157 return AUDIO_ERR_IOCTL;
1160 /* Prepare device */
1161 if ((err = snd_pcm_prepare(pcm_handle)) < 0) {
1162 AUDIO_LOG_ERROR("snd_pcm_prepare() failed : %d", err);
1163 return AUDIO_ERR_IOCTL;
1166 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);
1169 return AUDIO_RET_OK;