You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

368 lines
11 KiB

/*
* 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 <cutils/properties.h>
#include <securec.h>
#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);
}
}