406 lines
13 KiB
C
406 lines
13 KiB
C
/*
|
|
* Copyright (C) 2018 Amlogic Corporation.
|
|
*
|
|
* 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.
|
|
*/
|
|
#define LOG_TAG "audio_hw_hal_dtv"
|
|
//#define LOG_NDEBUG 0
|
|
|
|
#include <cutils/atomic.h>
|
|
#include "aml_audio_log.h"
|
|
#include <cutils/str_parms.h>
|
|
#include <errno.h>
|
|
#include <fcntl.h>
|
|
#include <hardware/hardware.h>
|
|
#include <inttypes.h>
|
|
#include <linux/ioctl.h>
|
|
#include <math.h>
|
|
#include <pthread.h>
|
|
#include <stdint.h>
|
|
#include <stdlib.h>
|
|
#include <sys/prctl.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/time.h>
|
|
#include <system/audio.h>
|
|
#include <time.h>
|
|
#include <unistd.h>
|
|
#include "aml_malloc_debug.h"
|
|
#include "dtv_patch_utils.h"
|
|
#include "audio_hw_utils.h"
|
|
|
|
int dtv_package_list_flush(package_list *list)
|
|
{
|
|
pthread_mutex_lock(&(list->tslock));
|
|
struct package * dtv_package = NULL;
|
|
while (list->pack_num && list->first) {
|
|
dtv_package = list->first;
|
|
list->first = list->first->next;
|
|
if (dtv_package->data) {
|
|
aml_audio_free(dtv_package->data);
|
|
dtv_package->data = NULL;
|
|
}
|
|
aml_audio_free(dtv_package);
|
|
/*coverity[unused_value]:set to NULL after free*/
|
|
dtv_package = NULL;
|
|
list->pack_num--;
|
|
}
|
|
pthread_mutex_unlock(&(list->tslock));
|
|
return 0;
|
|
}
|
|
|
|
int dtv_package_list_init(package_list *list)
|
|
{
|
|
list->first = NULL;
|
|
list->pack_num = 0;
|
|
list->current = NULL;
|
|
pthread_mutex_init(&list->tslock, NULL);
|
|
return 0;
|
|
}
|
|
int dtv_package_add(package_list *list, struct package *p)
|
|
{
|
|
pthread_mutex_lock(&list->tslock);
|
|
if (list->pack_num == INPUT_PACKAGE_MAXCOUNT) { //enough
|
|
AM_LOGI("list->pack_num %d",list->pack_num);
|
|
pthread_mutex_unlock(&(list->tslock));
|
|
return -2;
|
|
}
|
|
if (list->pack_num == 0) { //first package
|
|
list->first = p;
|
|
list->current = p;
|
|
list->pack_num = 1;
|
|
} else {
|
|
list->current->next = p;
|
|
list->current = p;
|
|
list->pack_num++;
|
|
}
|
|
pthread_mutex_unlock(&list->tslock);
|
|
return 0;
|
|
}
|
|
|
|
struct package * dtv_package_get(package_list *list)
|
|
{
|
|
pthread_mutex_lock(&(list->tslock));
|
|
if (list->pack_num == 0) {
|
|
pthread_mutex_unlock(&list->tslock);
|
|
return NULL;
|
|
}
|
|
struct package *p = list->first;
|
|
if (list->pack_num == 1) {
|
|
list->first = NULL;
|
|
list->pack_num = 0;
|
|
list->current = NULL;
|
|
} else if (list->pack_num > 1) {
|
|
list->first = list->first->next;
|
|
list->pack_num--;
|
|
}
|
|
pthread_mutex_unlock(&list->tslock);
|
|
return p;
|
|
}
|
|
|
|
bool dtv_package_is_full(package_list *list)
|
|
{
|
|
bool ret = false;
|
|
pthread_mutex_lock(&list->tslock);
|
|
ret = list->pack_num == INPUT_PACKAGE_MAXCOUNT;
|
|
pthread_mutex_unlock(&list->tslock);
|
|
return ret;
|
|
}
|
|
bool dtv_package_is_empty(package_list *list)
|
|
{
|
|
bool ret = false;
|
|
pthread_mutex_lock(&list->tslock);
|
|
ret = list->pack_num == 0;
|
|
pthread_mutex_unlock(&list->tslock);
|
|
return ret;
|
|
}
|
|
|
|
void init_cmd_list(struct cmd_node *dtv_cmd_list)
|
|
{
|
|
dtv_cmd_list->next = NULL;
|
|
dtv_cmd_list->cmd = -1;
|
|
dtv_cmd_list->cmd_num = 0;
|
|
dtv_cmd_list->used = 0;
|
|
dtv_cmd_list->initd = 1;
|
|
pthread_mutex_init(&dtv_cmd_list->dtv_cmd_mutex, NULL);
|
|
}
|
|
|
|
void deinit_cmd_list(struct cmd_node *dtv_cmd_list)
|
|
{
|
|
struct cmd_node *cmd_list = dtv_cmd_list;
|
|
pthread_mutex_destroy(&dtv_cmd_list->dtv_cmd_mutex);
|
|
while (cmd_list != NULL) {
|
|
dtv_cmd_list = dtv_cmd_list->next;
|
|
aml_audio_free(cmd_list);
|
|
cmd_list = dtv_cmd_list;
|
|
}
|
|
}
|
|
|
|
int dtv_cmdlist_add_cmd(struct cmd_node *dtv_cmd_list,int cmd, int path_id)
|
|
{
|
|
struct cmd_node *list = NULL;
|
|
struct cmd_node *new_cmd_node = NULL;
|
|
|
|
if (!dtv_cmd_list || dtv_cmd_list->initd == 0) {
|
|
return 0;
|
|
}
|
|
pthread_mutex_lock(&dtv_cmd_list->dtv_cmd_mutex);
|
|
new_cmd_node = aml_audio_malloc(sizeof(struct cmd_node));
|
|
if (!new_cmd_node ) {
|
|
ALOGE("new_cmd_node aml_audio_malloc failed");
|
|
pthread_mutex_unlock(&dtv_cmd_list->dtv_cmd_mutex);
|
|
return -1;
|
|
}
|
|
new_cmd_node->cmd = cmd;
|
|
new_cmd_node->path_id = path_id;
|
|
new_cmd_node->next = NULL;
|
|
new_cmd_node->used = 1;
|
|
list = dtv_cmd_list;
|
|
while (list->next != NULL) {
|
|
list = list->next;
|
|
}
|
|
list->next = new_cmd_node;
|
|
dtv_cmd_list->cmd_num++;
|
|
pthread_mutex_unlock(&dtv_cmd_list->dtv_cmd_mutex);
|
|
AM_LOGI("add by live dtv_patch_add_cmd the cmd is %d \n", cmd);
|
|
return 0;
|
|
}
|
|
|
|
int dtv_cmdlist_get_cmd(struct cmd_node *dtv_cmd_list,int *cmd, int *path_id)
|
|
{
|
|
struct cmd_node *dtv_cmd = NULL;
|
|
AM_LOGV("enter dtv_patch_get_cmd function now\n");
|
|
pthread_mutex_lock(&dtv_cmd_list->dtv_cmd_mutex);
|
|
dtv_cmd = dtv_cmd_list->next;
|
|
if (dtv_cmd != NULL) {
|
|
dtv_cmd_list->next = dtv_cmd->next;
|
|
dtv_cmd_list->cmd_num--;
|
|
} else {
|
|
pthread_mutex_unlock(&dtv_cmd_list->dtv_cmd_mutex);
|
|
return -1;
|
|
}
|
|
|
|
dtv_cmd->used = 0;
|
|
*cmd = dtv_cmd->cmd;
|
|
*path_id = dtv_cmd->path_id;
|
|
aml_audio_free(dtv_cmd);
|
|
pthread_mutex_unlock(&dtv_cmd_list->dtv_cmd_mutex);
|
|
AM_LOGV("leave dtv_patch_get_cmd the cmd is %d path %d\n", *cmd, *path_id);
|
|
return 0;
|
|
}
|
|
|
|
int dtv_cmdlist_is_empty(struct cmd_node *dtv_cmd_list)
|
|
{
|
|
pthread_mutex_lock(&dtv_cmd_list->dtv_cmd_mutex);
|
|
if (dtv_cmd_list->next == NULL) {
|
|
pthread_mutex_unlock(&dtv_cmd_list->dtv_cmd_mutex);
|
|
return 1;
|
|
}
|
|
pthread_mutex_unlock(&dtv_cmd_list->dtv_cmd_mutex);
|
|
return 0;
|
|
}
|
|
|
|
int dtv_get_demuxidbase() {
|
|
return DVB_DEMUX_ID_BASE;
|
|
}
|
|
|
|
audio_format_t dmx_fmt_convert2_hal_fmt (int input_fmt)
|
|
{
|
|
struct aml_audio_device *aml_dev = (struct aml_audio_device *)adev_get_handle();
|
|
if (!aml_dev) {
|
|
AM_LOGE("get adev error");
|
|
return -1;
|
|
}
|
|
|
|
if (input_fmt == ACODEC_FMT_AC3) {
|
|
return AUDIO_FORMAT_AC3;
|
|
} else if (input_fmt == ACODEC_FMT_EAC3) {
|
|
return AUDIO_FORMAT_E_AC3;
|
|
} else if (input_fmt == ACODEC_FMT_DTS) {
|
|
return AUDIO_FORMAT_DTS;
|
|
} else if (input_fmt == ACODEC_FMT_AAC ) {
|
|
if (eDolbyMS12Lib == aml_dev->dolby_lib_type_last)
|
|
return AUDIO_FORMAT_HE_AAC_V2;
|
|
else
|
|
return AUDIO_FORMAT_AAC;
|
|
} else if (input_fmt == ACODEC_FMT_AAC_LATM) {
|
|
if (eDolbyMS12Lib == aml_dev->dolby_lib_type_last)
|
|
return AUDIO_FORMAT_HE_AAC_V1;
|
|
else
|
|
return AUDIO_FORMAT_AAC_LATM;
|
|
} else if (input_fmt == ACODEC_FMT_MPEG ) {
|
|
return AUDIO_FORMAT_MP3;
|
|
} else if (input_fmt == ACODEC_FMT_MPEG1) {
|
|
return AUDIO_FORMAT_MP2;/* audio-base.h no define mpeg1 format */
|
|
} else if (input_fmt == ACODEC_FMT_MPEG2) {
|
|
return AUDIO_FORMAT_MP2;
|
|
} else if (input_fmt == ACODEC_FMT_AC4) {
|
|
return AUDIO_FORMAT_AC4;
|
|
} else if (input_fmt == ACODEC_FMT_MHAS) {
|
|
return AUDIO_FORMAT_MPEGH;
|
|
} else {
|
|
return AUDIO_FORMAT_PCM_16_BIT;
|
|
}
|
|
}
|
|
|
|
void dtv_do_ease_out(struct aml_audio_device *aml_dev)
|
|
{
|
|
if (eDolbyMS12Lib != aml_dev->dolby_lib_type) {
|
|
AM_LOGE("%s(), TODO: need do ease out here", __func__);
|
|
if (is_TV(aml_dev))
|
|
usleep(AUDIO_FADEOUT_TV_DURATION_US);
|
|
else
|
|
usleep(AUDIO_FADEOUT_STB_DURATION_US);
|
|
}
|
|
}
|
|
|
|
float dtv_ad_mixlevel_vol_convert_to_gain(struct aml_stream_out *aml_out) {
|
|
struct aml_audio_device *adev = (struct aml_audio_device *)adev_get_handle();
|
|
float gain = 1.0;
|
|
if (aml_out->stream_type == STREAM_MAIN_INPUT) {
|
|
if (adev->mixing_level == 32) {
|
|
gain = 0.0;
|
|
} else if (adev->mixing_level > 0) {
|
|
gain = DbToAmpl((-1.0) * adev->mixing_level);
|
|
}
|
|
} else if (aml_out->stream_type == STREAM_AD_INPUT) {
|
|
if (adev->mixing_level == -32) {
|
|
gain = 0.0;
|
|
} else if (adev->mixing_level < 0) {
|
|
gain = DbToAmpl(adev->mixing_level);
|
|
}
|
|
gain *= (adev->advol_level / 100.0f);
|
|
}
|
|
AM_LOGI("aout %p, mix level:%d, vol %d, gain %f", aml_out, adev->mixing_level, adev->advol_level, gain);
|
|
return gain;
|
|
}
|
|
|
|
void dtv_es_data_free(struct mAudioEsDataInfo *mEsData)
|
|
{
|
|
if (mEsData) {
|
|
if (mEsData->data) {
|
|
aml_audio_free(mEsData->data);
|
|
mEsData->data = NULL;
|
|
}
|
|
aml_audio_free(mEsData);
|
|
}
|
|
}
|
|
void dmx_info_clean(aml_demux_audiopara_t *demux_info) {
|
|
memset(demux_info, 0, sizeof(aml_demux_audiopara_t));
|
|
demux_info->main_pid = -1;
|
|
demux_info->media_presentation_id = -1;
|
|
demux_info->media_first_lang = -1;
|
|
demux_info->media_second_lang = -1;
|
|
demux_info->volume = 1.0;
|
|
demux_info->mute = false;
|
|
}
|
|
|
|
AD_PACK_STATUS_T check_ad_package_status(int64_t main_pts, int64_t ad_pts, aml_demux_audiopara_t *demux_info)
|
|
{
|
|
struct aml_audio_device *aml_dev = (struct aml_audio_device *)adev_get_handle();
|
|
if (!aml_dev) {
|
|
AM_LOGE("get adev error");
|
|
return -1;
|
|
}
|
|
|
|
int timems_diff = llabs(main_pts - ad_pts) / 90;
|
|
if (timems_diff >= AD_PACK_STATUS_FREERUN_THRESHOLD_MS) {
|
|
AM_LOGI("main_pts %"PRId64" ad_pts %"PRId64" timems_diff %dms is impossible so freerun ad data ", main_pts, ad_pts, timems_diff);
|
|
return AD_PACK_STATUS_NORMAL;
|
|
}
|
|
if (timems_diff > AD_PACK_STATUS_UNNORMAL_THRESHOLD_MS) {
|
|
AM_LOGI("main_pts %"PRId64" ad_pts %"PRId64" timems_diff %d it is impossible so drop ad data ", main_pts, ad_pts, timems_diff);
|
|
return AD_PACK_STATUS_DROP;
|
|
}
|
|
AD_PACK_STATUS_T ad_status = demux_info->ad_package_status;
|
|
int drop_threshold_ms,drop_start_threshold_ms,hold_start_threshold_ms,hold_threshold_ms;
|
|
|
|
drop_threshold_ms = AD_PACK_STATUS_DROP_THRESHOLD_MS;
|
|
drop_start_threshold_ms = AD_PACK_STATUS_DROP_START_THRESHOLD_MS;
|
|
hold_threshold_ms = AD_PACK_STATUS_HOLD_THRESHOLD_MS;
|
|
hold_start_threshold_ms = AD_PACK_STATUS_HOLD_START_THRESHOLD_MS;
|
|
|
|
switch (ad_status) {
|
|
case AD_PACK_STATUS_NORMAL:
|
|
if (main_pts >= ad_pts) {
|
|
timems_diff = (main_pts - ad_pts) / 90;
|
|
if ( timems_diff > drop_threshold_ms) {
|
|
AM_LOGI_IF(aml_dev->debug_flag, "main and ad timems_diff %d ms need drop ", timems_diff);
|
|
ad_status = AD_PACK_STATUS_DROP;
|
|
} else if (timems_diff < hold_start_threshold_ms) {
|
|
AM_LOGI_IF(aml_dev->debug_flag, "main and ad timems_diff %d ms need hold ", timems_diff);
|
|
ad_status = AD_PACK_STATUS_HOLD;
|
|
}
|
|
} else {
|
|
timems_diff = (ad_pts - main_pts) / 90;
|
|
AM_LOGI_IF(aml_dev->debug_flag, "ad ahead of main timems_diff %d ", timems_diff);
|
|
ad_status = AD_PACK_STATUS_HOLD;
|
|
}
|
|
|
|
break;
|
|
case AD_PACK_STATUS_DROP:
|
|
if (main_pts > ad_pts) {
|
|
timems_diff = (main_pts - ad_pts) / 90;
|
|
if (timems_diff > drop_start_threshold_ms) {
|
|
AM_LOGI_IF(aml_dev->debug_flag, "main and ad timems_diff %d ms need drop ", timems_diff);
|
|
ad_status = AD_PACK_STATUS_DROP;
|
|
} else {
|
|
ad_status = AD_PACK_STATUS_NORMAL;
|
|
}
|
|
|
|
} else {
|
|
ad_status = AD_PACK_STATUS_HOLD;
|
|
}
|
|
break;
|
|
|
|
case AD_PACK_STATUS_HOLD:
|
|
|
|
if (main_pts < ad_pts) {
|
|
timems_diff = (ad_pts - main_pts) / 90;
|
|
AM_LOGI_IF(aml_dev->debug_flag, "ad ahead of main timems_diff %d ", timems_diff);
|
|
ad_status = AD_PACK_STATUS_HOLD;
|
|
} else {
|
|
timems_diff = (main_pts - ad_pts) / 90;
|
|
if (timems_diff > hold_start_threshold_ms
|
|
&& timems_diff < hold_threshold_ms) {
|
|
ad_status = AD_PACK_STATUS_NORMAL;
|
|
} else if (timems_diff >= hold_threshold_ms) {
|
|
ad_status = AD_PACK_STATUS_DROP;
|
|
AM_LOGI_IF(aml_dev->debug_flag, "timems_diff %d, drop!", timems_diff);
|
|
} else {
|
|
ad_status = AD_PACK_STATUS_NORMAL;
|
|
}
|
|
}
|
|
break;
|
|
default:
|
|
AM_LOGI("invalid status %d ", ad_status);
|
|
|
|
}
|
|
AM_LOGI_IF(aml_dev->debug_flag, "main_pts %"PRId64" ad_pts %"PRId64" ad_status %d timems_diff %d", main_pts, ad_pts, ad_status, timems_diff);
|
|
|
|
return ad_status;
|
|
}
|
|
|
|
bool check_ad_buffer_available(struct audio_stream_out *stream) {
|
|
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
|
|
|
if (aml_out && aml_out->source_type == DTV_SRC &&
|
|
aml_out->mix_buf &&
|
|
aml_out->mix_buf->mix_buffer.buffer &&
|
|
aml_out->mix_buf->consumed == false) {
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|