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
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);
|
|
}
|
|
}
|