Revise codes - add null checking codes, change variable names, remove unused codes...
[platform/adaptation/spreadtrum/audio-hal-sc7727.git] / tizen-audio-util.c
1 /*
2  * audio-hal
3  *
4  * Copyright (c) 2000 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
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
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
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.
17  *
18  */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include <pthread.h>
28
29 #include "tizen-audio-internal.h"
30
31 audio_return_t _audio_util_init(audio_hal_t *ah)
32 {
33     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
34
35     pthread_mutex_init(&(ah->mixer.mutex), NULL);
36     return AUDIO_RET_OK;
37 }
38
39 audio_return_t _audio_util_deinit(audio_hal_t *ah)
40 {
41     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
42
43     pthread_mutex_destroy(&(ah->mixer.mutex));
44     return AUDIO_RET_OK;
45 }
46
47 #ifdef __MIXER_PARAM_DUMP
48
49 static void __dump_mixer_param(char *dump, long *param, int size)
50 {
51     int i, len;
52
53     for (i = 0; i < size; i++) {
54         len = sprintf(dump, "%ld", *param);
55         if (len > 0)
56             dump += len;
57         if (i != size -1) {
58             *dump++ = ',';
59         }
60
61         param++;
62     }
63     *dump = '\0';
64 }
65
66 #endif
67
68 audio_return_t _audio_mixer_control_set_param(audio_hal_t *ah, const char* ctl_name, snd_ctl_elem_value_t* param, int size)
69 {
70     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
71
72     /* TODO. */
73     return AUDIO_RET_OK;
74 }
75
76 audio_return_t audio_mixer_control_get_value(audio_hal_t *ah, const char *ctl_name, int *val)
77 {
78     audio_return_t audio_ret = AUDIO_RET_OK;
79
80     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
81
82     audio_ret = _audio_mixer_control_get_value(ah, ctl_name, val);
83     return audio_ret;
84 }
85
86 audio_return_t _audio_mixer_control_get_value(audio_hal_t *ah, const char *ctl_name, int *val)
87 {
88     snd_ctl_t *handle;
89     snd_ctl_elem_value_t *control;
90     snd_ctl_elem_id_t *id;
91     snd_ctl_elem_info_t *info;
92     snd_ctl_elem_type_t type;
93
94     int ret = 0, count = 0, i = 0;
95
96     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
97
98     pthread_mutex_lock(&(ah->mixer.mutex));
99
100     ret = snd_ctl_open(&handle, ALSA_DEFAULT_CARD, 0);
101     if (ret < 0) {
102         AUDIO_LOG_ERROR ("snd_ctl_open error, %s\n", snd_strerror(ret));
103         pthread_mutex_unlock(&(ah->mixer.mutex));
104         return AUDIO_ERR_IOCTL;
105     }
106
107     // Get Element Info
108
109     snd_ctl_elem_id_alloca(&id);
110     snd_ctl_elem_info_alloca(&info);
111     snd_ctl_elem_value_alloca(&control);
112
113     snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
114     snd_ctl_elem_id_set_name(id, ctl_name);
115
116     snd_ctl_elem_info_set_id(info, id);
117     if(snd_ctl_elem_info(handle, info) < 0 ) {
118         AUDIO_LOG_ERROR ("Cannot find control element: %s\n", ctl_name);
119         goto close;
120     }
121     snd_ctl_elem_info_get_id(info, id);
122
123     type = snd_ctl_elem_info_get_type(info);
124     count = snd_ctl_elem_info_get_count(info);
125
126     snd_ctl_elem_value_set_id(control, id);
127
128     if(snd_ctl_elem_read(handle, control) < 0) {
129         AUDIO_LOG_ERROR ("snd_ctl_elem_read failed \n");
130         goto close;
131 }
132
133     switch (type) {
134     case SND_CTL_ELEM_TYPE_BOOLEAN:
135         *val = snd_ctl_elem_value_get_boolean(control, i);
136         break;
137     case SND_CTL_ELEM_TYPE_INTEGER:
138         for (i = 0; i < count; i++)
139         *val = snd_ctl_elem_value_get_integer(control, i);
140         break;
141     case SND_CTL_ELEM_TYPE_ENUMERATED:
142         for (i = 0; i < count; i++)
143         *val = snd_ctl_elem_value_get_enumerated(control, i);
144         break;
145     default:
146         AUDIO_LOG_WARN ("unsupported control element type\n");
147         goto close;
148     }
149
150     snd_ctl_close(handle);
151
152 #ifdef AUDIO_DEBUG
153     AUDIO_LOG_INFO("get mixer(%s) = %d success", ctl_name, *val);
154 #endif
155
156     pthread_mutex_unlock(&(ah->mixer.mutex));
157     return AUDIO_RET_OK;
158
159 close:
160     AUDIO_LOG_ERROR ("Error\n");
161     snd_ctl_close(handle);
162     pthread_mutex_unlock(&(ah->mixer.mutex));
163     return AUDIO_ERR_UNDEFINED;
164 }
165
166 audio_return_t _audio_mixer_control_set_value(audio_hal_t *ah, const char *ctl_name, int val)
167 {
168     snd_ctl_t *handle;
169     snd_ctl_elem_value_t *control;
170     snd_ctl_elem_id_t *id;
171     snd_ctl_elem_info_t *info;
172     snd_ctl_elem_type_t type;
173
174     char *card_name = NULL;
175     int ret = 0, count = 0, i = 0;
176
177     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
178     AUDIO_RETURN_VAL_IF_FAIL(ctl_name, AUDIO_ERR_PARAMETER);
179
180     pthread_mutex_lock(&(ah->mixer.mutex));
181
182     ret = snd_ctl_open(&handle, ALSA_DEFAULT_CARD, 0);
183     if (ret < 0) {
184         AUDIO_LOG_ERROR("snd_ctl_open error, card: %s: %s", card_name, snd_strerror(ret));
185         pthread_mutex_unlock(&(ah->mixer.mutex));
186         return AUDIO_ERR_IOCTL;
187     }
188
189     // Get Element Info
190
191     snd_ctl_elem_id_alloca(&id);
192     snd_ctl_elem_info_alloca(&info);
193     snd_ctl_elem_value_alloca(&control);
194
195     snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
196     snd_ctl_elem_id_set_name(id, ctl_name);
197
198     snd_ctl_elem_info_set_id(info, id);
199     if(snd_ctl_elem_info(handle, info) < 0 ) {
200         AUDIO_LOG_ERROR("Cannot find control element: %s", ctl_name);
201         goto close;
202     }
203     snd_ctl_elem_info_get_id(info, id);
204
205     type = snd_ctl_elem_info_get_type(info);
206     count = snd_ctl_elem_info_get_count(info);
207
208     snd_ctl_elem_value_set_id(control, id);
209
210     snd_ctl_elem_read(handle, control);
211
212     switch (type) {
213     case SND_CTL_ELEM_TYPE_BOOLEAN:
214         for (i = 0; i < count; i++)
215             snd_ctl_elem_value_set_boolean(control, i, val);
216         break;
217     case SND_CTL_ELEM_TYPE_INTEGER:
218         for (i = 0; i < count; i++)
219             snd_ctl_elem_value_set_integer(control, i,val);
220         break;
221     case SND_CTL_ELEM_TYPE_ENUMERATED:
222         for (i = 0; i < count; i++)
223             snd_ctl_elem_value_set_enumerated(control, i,val);
224         break;
225
226     default:
227         AUDIO_LOG_WARN("unsupported control element type");
228         goto close;
229     }
230
231     snd_ctl_elem_write(handle, control);
232
233     snd_ctl_close(handle);
234
235     AUDIO_LOG_INFO("set mixer(%s) = %d success", ctl_name, val);
236
237     pthread_mutex_unlock(&(ah->mixer.mutex));
238     return AUDIO_RET_OK;
239
240 close:
241     AUDIO_LOG_ERROR("Error");
242     snd_ctl_close(handle);
243     pthread_mutex_unlock(&(ah->mixer.mutex));
244     return AUDIO_ERR_UNDEFINED;
245 }
246
247 audio_return_t _audio_mixer_control_set_value_string(audio_hal_t *ah, const char* ctl_name, const char* value)
248 {
249     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
250     AUDIO_RETURN_VAL_IF_FAIL(ctl_name, AUDIO_ERR_PARAMETER);
251
252     /* TODO. */
253     return AUDIO_RET_OK;
254 }
255
256
257 audio_return_t _audio_mixer_control_get_element(audio_hal_t *ah, const char *ctl_name, snd_hctl_elem_t **elem)
258 {
259     AUDIO_RETURN_VAL_IF_FAIL(ah, AUDIO_ERR_PARAMETER);
260     AUDIO_RETURN_VAL_IF_FAIL(ctl_name, AUDIO_ERR_PARAMETER);
261     AUDIO_RETURN_VAL_IF_FAIL(elem, AUDIO_ERR_PARAMETER);
262
263     /* TODO. */
264     return AUDIO_RET_OK;
265 }
266
267 #ifdef __USE_TINYALSA__
268 /* Convert pcm format from pulse to alsa */
269 static const uint32_t g_format_convert_table[] = {
270     [AUDIO_SAMPLE_U8]        = PCM_FORMAT_S8,
271     [AUDIO_SAMPLE_S16LE]     = PCM_FORMAT_S16_LE,
272     [AUDIO_SAMPLE_S32LE]     = PCM_FORMAT_S32_LE,
273     [AUDIO_SAMPLE_S24_32LE]  = PCM_FORMAT_S24_LE
274 };
275 #else  /* alsa-lib */
276 /* Convert pcm format from pulse to alsa */
277 static const uint32_t g_format_convert_table[] = {
278     [AUDIO_SAMPLE_U8]        = SND_PCM_FORMAT_U8,
279     [AUDIO_SAMPLE_ALAW]      = SND_PCM_FORMAT_A_LAW,
280     [AUDIO_SAMPLE_ULAW]      = SND_PCM_FORMAT_MU_LAW,
281     [AUDIO_SAMPLE_S16LE]     = SND_PCM_FORMAT_S16_LE,
282     [AUDIO_SAMPLE_S16BE]     = SND_PCM_FORMAT_S16_BE,
283     [AUDIO_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE,
284     [AUDIO_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE,
285     [AUDIO_SAMPLE_S32LE]     = SND_PCM_FORMAT_S32_LE,
286     [AUDIO_SAMPLE_S32BE]     = SND_PCM_FORMAT_S32_BE,
287     [AUDIO_SAMPLE_S24LE]     = SND_PCM_FORMAT_S24_3LE,
288     [AUDIO_SAMPLE_S24BE]     = SND_PCM_FORMAT_S24_3BE,
289     [AUDIO_SAMPLE_S24_32LE]  = SND_PCM_FORMAT_S24_LE,
290     [AUDIO_SAMPLE_S24_32BE]  = SND_PCM_FORMAT_S24_BE
291 };
292 #endif
293
294 uint32_t _convert_format(audio_sample_format_t format)
295 {
296     return g_format_convert_table[format];
297 }
298
299 /* Generic snd pcm interface APIs */
300 audio_return_t _audio_pcm_set_hw_params(snd_pcm_t *pcm, audio_pcm_sample_spec_t *sample_spec, uint8_t *use_mmap, snd_pcm_uframes_t *period_size, snd_pcm_uframes_t *buffer_size)
301 {
302     audio_return_t ret = AUDIO_RET_OK;
303     snd_pcm_hw_params_t *hwparams;
304     int err = 0;
305     int dir;
306     unsigned int val = 0;
307     snd_pcm_uframes_t _period_size = period_size ? *period_size : 0;
308     snd_pcm_uframes_t _buffer_size = buffer_size ? *buffer_size : 0;
309     uint8_t _use_mmap = use_mmap && *use_mmap;
310     uint32_t channels = 0;
311
312     AUDIO_RETURN_VAL_IF_FAIL(pcm, AUDIO_ERR_PARAMETER);
313
314     snd_pcm_hw_params_alloca(&hwparams);
315
316     /* Skip parameter setting to null device. */
317     if (snd_pcm_type(pcm) == SND_PCM_TYPE_NULL)
318         return AUDIO_ERR_IOCTL;
319
320     /* Allocate a hardware parameters object. */
321     snd_pcm_hw_params_alloca(&hwparams);
322
323     /* Fill it in with default values. */
324     if(snd_pcm_hw_params_any(pcm, hwparams) < 0) {
325         AUDIO_LOG_ERROR("snd_pcm_hw_params_any() : failed! - %s\n", snd_strerror(err));
326         goto error;
327     }
328
329     /* Set the desired hardware parameters. */
330
331     if (_use_mmap) {
332
333         if (snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_MMAP_INTERLEAVED) < 0) {
334
335             /* mmap() didn't work, fall back to interleaved */
336
337             if ((ret = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
338                 AUDIO_LOG_DEBUG("snd_pcm_hw_params_set_access() failed: %s", snd_strerror(ret));
339                 goto error;
340             }
341
342             _use_mmap = 0;
343         }
344
345     } else if ((ret = snd_pcm_hw_params_set_access(pcm, hwparams, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
346         AUDIO_LOG_DEBUG("snd_pcm_hw_params_set_access() failed: %s", snd_strerror(ret));
347         goto error;
348     }
349     AUDIO_LOG_DEBUG("setting rate - %d", sample_spec->rate);
350     err = snd_pcm_hw_params_set_rate(pcm, hwparams, sample_spec->rate, 0);
351     if (err < 0) {
352         AUDIO_LOG_ERROR("snd_pcm_hw_params_set_rate() : failed! - %s\n", snd_strerror(err));
353     }
354
355     err = snd_pcm_hw_params(pcm, hwparams);
356     if (err < 0) {
357         AUDIO_LOG_ERROR("snd_pcm_hw_params() : failed! - %s\n", snd_strerror(err));
358         goto error;
359     }
360
361     /* Dump current param */
362
363     if ((ret = snd_pcm_hw_params_current(pcm, hwparams)) < 0) {
364         AUDIO_LOG_INFO("snd_pcm_hw_params_current() failed: %s", snd_strerror(ret));
365         goto error;
366     }
367
368     if ((ret = snd_pcm_hw_params_get_period_size(hwparams, &_period_size, &dir)) < 0 ||
369         (ret = snd_pcm_hw_params_get_buffer_size(hwparams, &_buffer_size)) < 0) {
370         AUDIO_LOG_INFO("snd_pcm_hw_params_get_{period|buffer}_size() failed: %s", snd_strerror(ret));
371         goto error;
372     }
373
374     snd_pcm_hw_params_get_access(hwparams, (snd_pcm_access_t *) &val);
375     AUDIO_LOG_DEBUG("access type = %s\n", snd_pcm_access_name((snd_pcm_access_t)val));
376
377     snd_pcm_hw_params_get_format(hwparams, &sample_spec->format);
378     AUDIO_LOG_DEBUG("format = '%s' (%s)\n",
379                     snd_pcm_format_name((snd_pcm_format_t)sample_spec->format),
380                     snd_pcm_format_description((snd_pcm_format_t)sample_spec->format));
381
382     snd_pcm_hw_params_get_subformat(hwparams, (snd_pcm_subformat_t *)&val);
383     AUDIO_LOG_DEBUG("subformat = '%s' (%s)\n",
384                     snd_pcm_subformat_name((snd_pcm_subformat_t)val),
385                     snd_pcm_subformat_description((snd_pcm_subformat_t)val));
386
387     snd_pcm_hw_params_get_channels(hwparams, &channels);
388     sample_spec->channels = (uint8_t)channels;
389     AUDIO_LOG_DEBUG("channels = %d\n", sample_spec->channels);
390
391     if (buffer_size)
392         *buffer_size = _buffer_size;
393
394     if (period_size)
395         *period_size = _period_size;
396
397     if (use_mmap)
398         *use_mmap = _use_mmap;
399
400     return AUDIO_RET_OK;
401
402 error:
403     return AUDIO_ERR_RESOURCE;
404 }
405
406 audio_return_t _audio_pcm_set_sw_params(snd_pcm_t *pcm, snd_pcm_uframes_t avail_min, uint8_t period_event)
407 {
408     snd_pcm_sw_params_t *swparams;
409     snd_pcm_uframes_t boundary;
410     int err;
411
412     AUDIO_RETURN_VAL_IF_FAIL(pcm, AUDIO_ERR_PARAMETER);
413
414     snd_pcm_sw_params_alloca(&swparams);
415
416     if ((err = snd_pcm_sw_params_current(pcm, swparams) < 0)) {
417         AUDIO_LOG_WARN("Unable to determine current swparams: %s\n", snd_strerror(err));
418         goto error;
419     }
420     if ((err = snd_pcm_sw_params_set_period_event(pcm, swparams, period_event)) < 0) {
421         AUDIO_LOG_WARN("Unable to disable period event: %s\n", snd_strerror(err));
422         goto error;
423     }
424     if ((err = snd_pcm_sw_params_set_tstamp_mode(pcm, swparams, SND_PCM_TSTAMP_ENABLE)) < 0) {
425         AUDIO_LOG_WARN("Unable to enable time stamping: %s\n", snd_strerror(err));
426         goto error;
427     }
428     if ((err = snd_pcm_sw_params_get_boundary(swparams, &boundary)) < 0) {
429         AUDIO_LOG_WARN("Unable to get boundary: %s\n", snd_strerror(err));
430         goto error;
431     }
432     if ((err = snd_pcm_sw_params_set_stop_threshold(pcm, swparams, boundary)) < 0) {
433         AUDIO_LOG_WARN("Unable to set stop threshold: %s\n", snd_strerror(err));
434         goto error;
435     }
436     if ((err = snd_pcm_sw_params_set_start_threshold(pcm, swparams, (snd_pcm_uframes_t) avail_min)) < 0) {
437         AUDIO_LOG_WARN("Unable to set start threshold: %s\n", snd_strerror(err));
438         goto error;
439     }
440     if ((err = snd_pcm_sw_params_set_avail_min(pcm, swparams, avail_min)) < 0) {
441         AUDIO_LOG_WARN("snd_pcm_sw_params_set_avail_min() failed: %s", snd_strerror(err));
442         goto error;
443     }
444     if ((err = snd_pcm_sw_params(pcm, swparams)) < 0) {
445         AUDIO_LOG_WARN("Unable to set sw params: %s\n", snd_strerror(err));
446         goto error;
447     }
448     return AUDIO_RET_OK;
449 error:
450     return err;
451 }