/* * Copyright (c) Hisilicon Technologies Co., Ltd. Technologies Co., Ltd. 2020-2020. All rights reserved. * Description: audio hal cast in source file. * Author: yinyingcai * Create: 2020-05-11 * Notes: NA * History: 2020-05-11 yinyingcai for CodingStyle */ #define LOG_TAG "audio_hal_hci" #define LOG_NDEBUG 0 #include "hci.h" #include #include #include "vnaudio_dbg.h" #include "aiao_wrap.h" #include "audio_custom.h" #define VERY_VERY_VERBOSE_LOGGING #ifdef VERY_VERY_VERBOSE_LOGGING #define ALOGVV ALOGV #else #define ALOGVV(a...) do { } while (0) #endif #define CAST_PCM_FRAME_MAXNUM 4 #define CAST_DEFAULE_SAMPLERATE 48000 #define CAST_SLEEP_MS 10 #define CAST_BYTE_BIT 8 #define BYTES_PER_SAMPLE 4 #define CAST_DEFAULT_DEC_DB 0 #define CAST_DEFAULT_INT_DB 0 #define SND_EXT_DELAY_MS 190 /* Compensate A2DP output delay */ int hci_create(struct hci_data **pphci) { int ret; struct hci_data* hci = (struct hci_data *)malloc(sizeof(struct hci_data)); if (hci == NULL) { ALOGE("%s: malloc failed", __func__); return -ENOMEM; } ALOGD("in function %s", __func__); ret = memset_s(hci, sizeof(struct hci_data), 0, sizeof(struct hci_data)); if (ret != 0) { ALOGE("memset_s hci failed(0x%x)", ret); free(hci); return ret; } hci->fd = NULL; hci->hCast = INVALID_HANDLE; hci->cacheBufSize = 0; hci->mute_cnt = CAST_MAX_MUTE_CNT; *pphci = hci; return 0; } void hci_destroy(struct hci_data* hci) { ALOGD("in function %s", __func__); if (hci->fd != NULL) { fclose(hci->fd); hci->fd = NULL; } free(hci); } static void hci_config_sink_delay(struct hci_data *hci) { uint32_t sink_delay; int ret = wraper_get_sink_delay(&hci->pre_sink_delay); if (ret != 0) { ALOGE("call wraper_get_sink_delay failed(0x%x)", ret); hci->pre_sink_delay = 0; } sink_delay = (hci->in->adev->device_attr.patch_sink_device == SINK_A2DP) ? SND_EXT_DELAY_MS : 0; ALOGD("patch_sink_device: %d set Sink delay: %d", hci->in->adev->device_attr.patch_sink_device, sink_delay); ret = wraper_set_sink_delay(sink_delay); if (ret != 0) { ALOGE("call wraper_set_sink_delay failed(0x%x)", ret); } } static void hci_set_cast_volume(const struct audio_device *adev, uint32_t hCast) { int ret; ret = wraper_set_cast_volume(hCast, adev->device_attr.cast_integer_gain, adev->device_attr.cast_decimal_gain); if (ret != 0) { ALOGE("%s: wraper_set_cast_volume failed(0x%x)", __func__, ret); return; } ALOGD("%s: set cast volume integer(%d) decimal_gain(%d)", __func__, adev->device_attr.cast_integer_gain, adev->device_attr.cast_decimal_gain); ret = wraper_set_cast_mute(hCast, adev->cast_muted); ALOGD("%s: Set cast Mute(%d) ret(0x%x)", __func__, adev->cast_muted, ret); } static int hci_create_cast(struct hci_data *hci) { int32_t ret; hal_snd_cast_attr cast_attr = {0}; cast_attr.add_mute = TD_TRUE; cast_attr.pcm_frame_max_num = CAST_PCM_FRAME_MAXNUM; cast_attr.pcm_samples = hci->in->config.period_size; ALOGD("Cast PcmSamplesPerFrame: %d", cast_attr.pcm_samples); ALOGD("Cast PcmFrameMaxNum: %d", cast_attr.pcm_frame_max_num); ret = wraper_open_cast(cast_attr, &hci->hCast); if (ret != 0) { ALOGE("wraper_open_hci failed(0x%x)", ret); return ret; } /* mute all port in vnaudioservice */ hci->cacheBufSize = 0; return 0; } static void hci_save_device_attr(const struct hci_data *hci) { int port_num; struct audio_device *adev = hci->in->adev; for (port_num = 0; port_num < MAX_AUDIO_PORTS_NUM; port_num++) { if (adev->device_attr.cast[port_num] == INVALID_HANDLE) { adev->device_attr.cast[port_num] = hci->hCast; adev->device_attr.device_type[port_num] = AUDIO_DEVICE_IN_TV_TUNER; break; } } if (port_num == MAX_AUDIO_PORTS_NUM) { ALOGE("no ports left to save information"); } } int hci_open(struct hci_data *hci) { int32_t ret; char value[PROPERTY_VALUE_MAX] = {0}; struct audio_device *adev = hci->in->adev; ALOGD("config channels:%d rate:%d period_size=%d period_count=%d format=%x", hci->in->config.channels, hci->in->config.rate, hci->in->config.period_size, hci->in->config.period_count, hci->in->config.format); ALOGD("%s: cast(0x%x) to create", __func__, hci->hCast); if (hci->in->config.rate == 0) { ALOGD("Invalid rate: 0\n"); return TD_FAILURE; } hci_config_sink_delay(hci); ret = hci_create_cast(hci); if (ret != 0) { ALOGE("call hci_create_cast failed(0x%x)", ret); return ret; } property_get(PROPERTY_FILE_HCI_RECORD, value, ""); if (strncmp(value, "true", sizeof("true")) == 0) { if (hci->fd == NULL) { hci->fd = fopen(HCI_RECORD_FILE, "ab"); if (hci->fd != NULL) { ALOGD("%s: enable save %s", __func__, HCI_RECORD_FILE); } else { ALOGD("%s: %s can not be created!", __func__, HCI_RECORD_FILE); } } } else { if (hci->fd != NULL) { fclose(hci->fd); hci->fd = NULL; } } hci_save_device_attr(hci); hci_set_cast_volume(adev, hci->hCast); return 0; } int hci_close(struct hci_data *hci) { struct audio_device *adev = hci->in->adev; ALOGD("%s: cast(0x%x)\n", __func__, hci->hCast); if (hci->hCast != INVALID_HANDLE) { int ret; ret = wraper_close_cast(hci->hCast); if (ret != 0) { ALOGE("wraper_close_hci failed(0x%x)\n", ret); return ret; } } ALOGD("restore Sinkdelay: %d", hci->pre_sink_delay); int ret = wraper_set_sink_delay(hci->pre_sink_delay); if (ret != 0) { ALOGE("call wraper_set_sink_delay failed(0x%x)", ret); } if (hci->fd != NULL) { fclose(hci->fd); hci->fd = NULL; } hci->hCast = INVALID_HANDLE; hci->cacheBufSize = 0; for (int i = 0; i < MAX_AUDIO_PORTS_NUM; i++) { if (adev->device_attr.device_type[i] == AUDIO_DEVICE_IN_TV_TUNER) { adev->device_attr.cast[i] = INVALID_HANDLE; adev->device_attr.device_type[i] = AUDIO_DEVICE_NONE; break; } } return 0; } static int read_cast_data(struct hci_data *hci) { int32_t s32Ret; s32Ret = wraper_read_cast(hci->hCast, &hci->cacheBufSize, hci->cacheBuf); if (s32Ret != 0) { ALOGE("%s byte read failed(0x%x)", __func__, s32Ret); return s32Ret; } if (hci->mute_cnt > 0) { /* After cast created, mute 5 times data of cast to optimize cast underrun problem */ s32Ret = memset_s(hci->cacheBuf, HCI_CACHE_BUFFER_SIZE, 0, hci->cacheBufSize); if (s32Ret != EOK) { ALOGE("%s: memset_s hci buffer failed(0x%x)", __func__, s32Ret); return s32Ret; } hci->mute_cnt--; } return 0; } int hci_read(struct hci_data *hci, const uint8_t *buffer, size_t bytes) { int32_t s32Ret; if (hci->hCast == INVALID_HANDLE) { ALOGE("%s: cast not inited", __func__); return -1; } if (bytes > HCI_CACHE_BUFFER_SIZE / 2) { // buffer should can hold 2 times data ALOGE("%s: byte(%d) too large(%d)", __func__, bytes, HCI_CACHE_BUFFER_SIZE); return -1; } if (bytes > hci->cacheBufSize) { s32Ret = read_cast_data(hci); if (s32Ret != 0) { return s32Ret; } } if (bytes <= hci->cacheBufSize) { s32Ret = memcpy_s((void *)buffer, HCI_CACHE_BUFFER_SIZE, hci->cacheBuf, bytes); if (s32Ret != 0) { ALOGE("memcpy_s buffer failed(0x%x)", s32Ret); return s32Ret; } if (hci->fd != NULL) { size_t count; count = fwrite((char *)hci->cacheBuf, 1, bytes, hci->fd); if (count < bytes) { ALOGE("%s: not save all data! expect=%d actual=%d", __func__, bytes, bytes); } } hci->cacheBufSize -= bytes; hci->frames_read += bytes / BYTES_PER_SAMPLE; if (hci->cacheBufSize > 0) { s32Ret = memmove_s(hci->cacheBuf, HCI_CACHE_BUFFER_SIZE, hci->cacheBuf + bytes, hci->cacheBufSize); if (s32Ret != 0) { ALOGE("memmove_s hci->cacheBuf failed(0x%x)", s32Ret); return s32Ret; } } return 0; } ALOGE("%s: Data(%d) not enough for %d", __func__, hci->cacheBufSize, bytes); return -1; } void hci_init_device_attr(struct hci_device_attr *device_attr) { for (int i = 0; i < MAX_AUDIO_PORTS_NUM; i++) { device_attr->cast[i] = INVALID_HANDLE; device_attr->device_type[i] = AUDIO_DEVICE_NONE; } device_attr->cast_integer_gain = CAST_DEFAULT_DEC_DB; device_attr->cast_decimal_gain = CAST_DEFAULT_INT_DB; device_attr->patch_sink_device = SINK_NONE; } void hci_set_patch_sink_device(struct hci_device_attr *device_attr, int32_t device) { if (device == AUDIO_DEVICE_OUT_USB_HEADSET) { device_attr->patch_sink_device = SINK_USB; } else if (device == AUDIO_DEVICE_OUT_BLUETOOTH_A2DP) { device_attr->patch_sink_device = SINK_A2DP; } else { device_attr->patch_sink_device = SINK_NONE; } } void hci_set_audiopatch_src_volume(struct audio_device *adev, int32_t index) { int32_t ret; uint32_t hCast = INVALID_HANDLE; bool muted = false; int32_t integer_gain = 0; int32_t decimal_gain = 0; if (adev == NULL) { ALOGE("%s: adev pointer is null", __func__); return; } for (int i = 0; i < MAX_AUDIO_PORTS_NUM; i++) { if (adev->device_attr.device_type[i] == AUDIO_DEVICE_IN_TV_TUNER) { hCast = adev->device_attr.cast[i]; } } custom_calc_extdev_patchsrc_volume(index, &integer_gain, &decimal_gain); ALOGD("%s: get custom volume curve index(%d) integer_gain(%d), decimal_gain(%d)", __func__, index, integer_gain, decimal_gain); adev->device_attr.cast_decimal_gain = decimal_gain; adev->device_attr.cast_integer_gain = integer_gain; adev->gain = (double)integer_gain + (double)decimal_gain / 1000; /* use 1000 covert to float */ adev->vol_index = index; muted = adev->cast_muted; adev->cast_muted = (index > 0) ? false : true; if (hCast == INVALID_HANDLE) { ALOGE("cast not init volume set fail"); return; } ret = wraper_set_cast_volume(hCast, adev->device_attr.cast_integer_gain, adev->device_attr.cast_decimal_gain); if (ret != 0) { ALOGE("wraper_set_cast_volume failed(0x%x)", ret); return; } ALOGD("%s: set cast volume integer(%d) decimal_gain(%d)", __func__, adev->device_attr.cast_integer_gain, adev->device_attr.cast_decimal_gain); if (muted != adev->cast_muted) { ret = wraper_set_cast_mute(hCast, adev->cast_muted); ALOGD("Set cast Mute(%d) ret(0x%x)", adev->cast_muted, ret); } }