/* * audio-hal * * Copyright (c) 2022 Samsung Electronics Co., Ltd. All rights reserved. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * */ #ifdef HAVE_CONFIG_H #include #endif #include #include #include #include #include #include "tizen-audio-internal.h" #define MAX_LINE_LENGTH 256 #define MAX_KEY_LENGTH 64 #define MAX_VALUE_LENGTH 128 typedef struct { char key[MAX_KEY_LENGTH]; char value[MAX_VALUE_LENGTH]; } key_value_pair_t; struct _dictionary { key_value_pair_t *pairs; int count; }; typedef struct _dictionary dictionary_t; /* ------ dump helper -------- */ #define MAX(a, b) ((a) > (b) ? (a) : (b)) #ifdef __USE_TINYALSA__ static const uint32_t g_format_convert_hal_table[] = { [AUDIO_SAMPLE_U8] = PCM_FORMAT_S8, [AUDIO_SAMPLE_S16LE] = PCM_FORMAT_S16_LE, [AUDIO_SAMPLE_S32LE] = PCM_FORMAT_S32_LE, [AUDIO_SAMPLE_S24_32LE] = PCM_FORMAT_S24_LE }; static const uint32_t g_format_convert_native_table[] = { [PCM_FORMAT_S8] = AUDIO_SAMPLE_U8, [PCM_FORMAT_S16_LE] = AUDIO_SAMPLE_S16LE, [PCM_FORMAT_S32_LE] = AUDIO_SAMPLE_S32LE, [PCM_FORMAT_S24_LE] = AUDIO_SAMPLE_S24_32LE }; #else static const uint32_t g_format_convert_hal_table[] = { [AUDIO_SAMPLE_U8] = SND_PCM_FORMAT_U8, [AUDIO_SAMPLE_ALAW] = SND_PCM_FORMAT_A_LAW, [AUDIO_SAMPLE_ULAW] = SND_PCM_FORMAT_MU_LAW, [AUDIO_SAMPLE_S16LE] = SND_PCM_FORMAT_S16_LE, [AUDIO_SAMPLE_S16BE] = SND_PCM_FORMAT_S16_BE, [AUDIO_SAMPLE_FLOAT32LE] = SND_PCM_FORMAT_FLOAT_LE, [AUDIO_SAMPLE_FLOAT32BE] = SND_PCM_FORMAT_FLOAT_BE, [AUDIO_SAMPLE_S32LE] = SND_PCM_FORMAT_S32_LE, [AUDIO_SAMPLE_S32BE] = SND_PCM_FORMAT_S32_BE, [AUDIO_SAMPLE_S24LE] = SND_PCM_FORMAT_S24_3LE, [AUDIO_SAMPLE_S24BE] = SND_PCM_FORMAT_S24_3BE, [AUDIO_SAMPLE_S24_32LE] = SND_PCM_FORMAT_S24_LE, [AUDIO_SAMPLE_S24_32BE] = SND_PCM_FORMAT_S24_BE }; static const snd_pcm_format_t g_format_convert_native_table[] = { [SND_PCM_FORMAT_U8] = AUDIO_SAMPLE_U8, [SND_PCM_FORMAT_A_LAW] = AUDIO_SAMPLE_ALAW, [SND_PCM_FORMAT_MU_LAW] = AUDIO_SAMPLE_ULAW, [SND_PCM_FORMAT_S16_LE] = AUDIO_SAMPLE_S16LE, [SND_PCM_FORMAT_S16_BE] = AUDIO_SAMPLE_S16BE, [SND_PCM_FORMAT_FLOAT_LE] = AUDIO_SAMPLE_FLOAT32LE, [SND_PCM_FORMAT_FLOAT_BE] = AUDIO_SAMPLE_FLOAT32BE, [SND_PCM_FORMAT_S32_LE] = AUDIO_SAMPLE_S32LE, [SND_PCM_FORMAT_S32_BE] = AUDIO_SAMPLE_S32BE, [SND_PCM_FORMAT_S24_3LE] = AUDIO_SAMPLE_S24LE, [SND_PCM_FORMAT_S24_3BE] = AUDIO_SAMPLE_S24BE, [SND_PCM_FORMAT_S24_LE] = AUDIO_SAMPLE_S24_32LE, [SND_PCM_FORMAT_S24_BE] = AUDIO_SAMPLE_S24_32BE }; #endif static snd_pcm_format_t __convert_to_hal_format(audio_sample_format_s format) { return g_format_convert_hal_table[format]; } static uint32_t __convert_to_native_format(snd_pcm_format_t format) { return g_format_convert_native_table[format]; } /* src is pa_sample_spec which pulseaudio uses */ void convert_hal_format_from_sample_spec(void *src, audio_pcm_sample_spec_s *dst) { audio_sample_format_s format; assert(src); assert(dst); memcpy(dst, src, sizeof(audio_pcm_sample_spec_s)); format = ((audio_pcm_sample_spec_s *)src)->format; dst->format = __convert_to_hal_format(format); } /* dst is pa_sample_spec which pulseaudio uses */ void convert_hal_format_to_sample_spec(audio_pcm_sample_spec_s *src, void *dst) { assert(src); assert(dst); memcpy(dst, src, sizeof(audio_pcm_sample_spec_s)); ((audio_pcm_sample_spec_s *)dst)->format = __convert_to_native_format(src->format); } dump_data_t* _audio_dump_new(int length) { dump_data_t* dump = NULL; if ((dump = malloc(sizeof(dump_data_t)))) { memset(dump, 0, sizeof(dump_data_t)); if ((dump->strbuf = malloc(length))) { dump->p = &dump->strbuf[0]; dump->left = length; } else { free(dump); dump = NULL; } } return dump; } void _audio_dump_add_str(dump_data_t *dump, const char *fmt, ...) { int len; va_list ap; if (!dump) return; va_start(ap, fmt); len = vsnprintf(dump->p, dump->left, fmt, ap); va_end(ap); dump->p += MAX(0, len); dump->left -= MAX(0, len); } char* _audio_dump_get_str(dump_data_t *dump) { return (dump) ? dump->strbuf : NULL; } void _audio_dump_free(dump_data_t *dump) { if (dump) { if (dump->strbuf) free(dump->strbuf); free(dump); } } /* ------ dump helper -------- */ /* ------ volume table parse -------- */ char *rtrim(char *s) { char* back = s + strlen(s); while(isspace(*--back)); *(back+1) = '\0'; return s; } dictionary_t *parser_load(const char *filename) { FILE *file = NULL; dictionary_t *dict = NULL; char line[MAX_LINE_LENGTH]; file = fopen(filename, "r"); if (!file) { AUDIO_LOG_ERROR("Failed to open file: %s", filename); return NULL; } dict = (dictionary_t *)malloc(sizeof(dictionary_t)); if (!dict) { AUDIO_LOG_ERROR("failed to alloc memory"); goto fail; } dict->pairs = NULL; dict->count = 0; while (fgets(line, MAX_LINE_LENGTH, file)) { char* saveptr; char *key = strtok_r(line, "=", &saveptr); char *value = strtok_r(NULL, "\n", &saveptr); if (key && value) { key_value_pair_t pair; strncpy(pair.key, key, MAX_KEY_LENGTH - 1); rtrim(pair.key); pair.key[MAX_KEY_LENGTH - 1] = '\0'; strncpy(pair.value, value, MAX_VALUE_LENGTH - 1); pair.value[MAX_VALUE_LENGTH - 1] = '\0'; dict->pairs = (key_value_pair_t *)realloc(dict->pairs, sizeof(key_value_pair_t) * (dict->count + 1)); if (!dict->pairs) { AUDIO_LOG_ERROR("failed to alloc memory"); goto fail; } dict->pairs[dict->count++] = pair; } } fclose(file); return dict; fail: if (file) fclose(file); if (dict) parser_freedict(dict); return NULL; } const char *parser_getstring(const dictionary_t *dict, const char *key, const char *default_value) { if (!dict || !key) { return default_value; } for (int i = 0; i < dict->count; i++) { if (strcmp(dict->pairs[i].key, key) == 0) { return dict->pairs[i].value; } } return default_value; } void parser_freedict(dictionary_t *dict) { if (!dict) return; if (dict->pairs) free(dict->pairs); free(dict); } void dump_dictionary(const dictionary_t *dict) { if (!dict) { AUDIO_LOG_ERROR("dictionary is NULL"); return; } AUDIO_LOG_INFO("dictionary contents:"); for (int i = 0; i < dict->count; i++) AUDIO_LOG_INFO("Key: %-16s Value: %s", dict->pairs[i].key, dict->pairs[i].value); }