789 lines
30 KiB
C
789 lines
30 KiB
C
/*
|
|||
|
|
* Copyright 2023 Amlogic Inc. 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.
|
||
|
|
*/
|
||
|
|
|
||
|
|
#define LOG_TAG "audio_hw_input_tv"
|
||
|
|
//#define LOG_NDEBUG 0
|
||
|
|
|
||
|
|
#include <math.h>
|
||
|
|
#include <errno.h>
|
||
|
|
#include <pthread.h>
|
||
|
|
#include <stdint.h>
|
||
|
|
#include <stdlib.h>
|
||
|
|
#include <fcntl.h>
|
||
|
|
#include <time.h>
|
||
|
|
#include <inttypes.h>
|
||
|
|
#include <sys/time.h>
|
||
|
|
#include <sys/stat.h>
|
||
|
|
#include <sys/prctl.h>
|
||
|
|
#include "aml_audio_log.h"
|
||
|
|
#include <cutils/atomic.h>
|
||
|
|
#include <hardware/audio.h>
|
||
|
|
#include <aml_data_utils.h>
|
||
|
|
#include <audio_utils/channels.h>
|
||
|
|
#if ANDROID_PLATFORM_SDK_VERSION >= 25 // 8.0
|
||
|
|
#include <system/audio-base.h>
|
||
|
|
#endif
|
||
|
|
|
||
|
|
#include "audio_hw.h"
|
||
|
|
#include "aml_audio_stream.h"
|
||
|
|
#include "audio_hw_utils.h"
|
||
|
|
#include "aml_audio_timer.h"
|
||
|
|
#include "alsa_config_parameters.h"
|
||
|
|
#include "tv_patch_avsync.h"
|
||
|
|
#include "aml_ng.h"
|
||
|
|
#include "alsa_device_parser.h"
|
||
|
|
#include "audio_hw_ms12_v2.h"
|
||
|
|
#include "tv_patch_ctrl.h"
|
||
|
|
#include "audio_hw_resource_mgr.h"
|
||
|
|
#include "device_patch_mgr.h"
|
||
|
|
#include "component_picture_mode.h"
|
||
|
|
#include "tv_private_object.h"
|
||
|
|
#include "dolby_lib_api.h"
|
||
|
|
#include "amlAudioMixer.h"
|
||
|
|
#include "aml_audio_output.h"
|
||
|
|
#include "tv_patch.h"
|
||
|
|
#include "aml_audio_property.h"
|
||
|
|
|
||
|
|
#define INVALID_TYPE -1
|
||
|
|
#define MINUS_3_DB_IN_FLOAT M_SQRT1_2 // -3dB = 0.70710678
|
||
|
|
#define HDMIIN_MULTICH_DOWNMIX
|
||
|
|
|
||
|
|
/*==================================input commands=========================================*/
|
||
|
|
|
||
|
|
/* expand channels or contract channels*/
|
||
|
|
int input_stream_channels_adjust(struct aml_audio_patch *patch, void* buffer, size_t bytes)
|
||
|
|
{
|
||
|
|
int norminal_channel_cnt = 0;
|
||
|
|
int ret = -1;
|
||
|
|
|
||
|
|
if (!buffer || !bytes)
|
||
|
|
return ret;
|
||
|
|
|
||
|
|
int channel_count = 2;
|
||
|
|
|
||
|
|
if (!channel_count)
|
||
|
|
return ret;
|
||
|
|
|
||
|
|
norminal_channel_cnt = patch->in_channel_count;
|
||
|
|
|
||
|
|
if (patch->input_device & AUDIO_DEVICE_IN_HDMI_ARC) {
|
||
|
|
if (patch->arc_layout_b) {
|
||
|
|
norminal_channel_cnt = 8;
|
||
|
|
patch->tv_param.read_mul_factor = EAC3_MULTIPLIER;
|
||
|
|
} else if (patch->in_sample_rate > 96000) {
|
||
|
|
patch->tv_param.read_mul_factor = HBR_MULTIPLIER;
|
||
|
|
} else if (patch->in_sample_rate > 48000) {
|
||
|
|
patch->tv_param.read_mul_factor = EAC3_MULTIPLIER;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
size_t read_bytes = norminal_channel_cnt * bytes / channel_count;
|
||
|
|
if (!patch->input_tmp_buffer || patch->input_tmp_buffer_size < read_bytes) {
|
||
|
|
patch->input_tmp_buffer = aml_audio_realloc(patch->input_tmp_buffer, read_bytes);
|
||
|
|
if (!patch->input_tmp_buffer) {
|
||
|
|
AM_LOGE("aml_audio_realloc is fail");
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
patch->input_tmp_buffer_size = read_bytes;
|
||
|
|
}
|
||
|
|
|
||
|
|
ret = audio_input_read(patch->input_type, patch->input_tmp_buffer, read_bytes);
|
||
|
|
if (ret >= 0) {
|
||
|
|
read_bytes = ret;
|
||
|
|
if (patch->in_format == AUDIO_FORMAT_PCM_16_BIT)
|
||
|
|
adjust_channels(patch->input_tmp_buffer, norminal_channel_cnt,
|
||
|
|
buffer, channel_count, 2, read_bytes);
|
||
|
|
else if (patch->in_format == AUDIO_FORMAT_PCM_32_BIT)
|
||
|
|
adjust_channels(patch->input_tmp_buffer, norminal_channel_cnt,
|
||
|
|
buffer, channel_count, 4, read_bytes);
|
||
|
|
}
|
||
|
|
return ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
static int eArcIn_audio_format_detection(struct aml_audio_patch *patch)
|
||
|
|
{
|
||
|
|
struct aml_audio_device *adev = patch->dev;
|
||
|
|
int type = eArcIn_coding_type_detection(&adev->alsa_mixer);
|
||
|
|
|
||
|
|
return earc_coding_type_to_codec(type);
|
||
|
|
}
|
||
|
|
bool is_earc_in_status_change(struct aml_audio_patch *patch)
|
||
|
|
{
|
||
|
|
struct aml_audio_device *adev = patch->dev;
|
||
|
|
int stable = 0, type = 0;
|
||
|
|
|
||
|
|
stable = is_earcrx_stable(&adev->alsa_mixer);
|
||
|
|
if (!stable) {
|
||
|
|
ALOGV("%s() amixer %s get %d\n", __func__, "HDMIIN audio stable", stable);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
type = eArcIn_audio_format_detection(patch);
|
||
|
|
if (type == NOT_READY) {
|
||
|
|
AM_LOGV("in type is not ready yet");
|
||
|
|
//patch->arc_layout_b = patch->last_layout_b;
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
if (type != patch->spdif_fmt_hw) {
|
||
|
|
AM_LOGI("in type changed from %d to %d", patch->spdif_fmt_hw, type);
|
||
|
|
patch->spdif_fmt_hw = type;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
bool signal_status_check(struct aml_audio_patch *patch, int *mute_time) {
|
||
|
|
struct aml_audio_device *adev = patch->dev;
|
||
|
|
audio_devices_t in_device = patch->input_device;
|
||
|
|
bool ret = true;
|
||
|
|
|
||
|
|
switch (in_device) {
|
||
|
|
case AUDIO_DEVICE_IN_HDMI:
|
||
|
|
case AUDIO_DEVICE_IN_HDMI1:
|
||
|
|
{
|
||
|
|
bool hw_stable = is_hdmi_in_stable_hw(patch);
|
||
|
|
int is_hdmi1 = patch->input_device == AUDIO_DEVICE_IN_HDMI1 ? 1 : 0;
|
||
|
|
bool is_audio_packet_changed = false;
|
||
|
|
hdmiin_audio_packet_t last_audio_packet = patch->tv_param.last_audio_packet_type;
|
||
|
|
hdmiin_audio_packet_t cur_audio_packet = get_hdmiin_audio_packet(&adev->alsa_mixer, is_hdmi1);
|
||
|
|
|
||
|
|
is_audio_packet_changed = (((cur_audio_packet == AUDIO_PACKET_AUDS) || (cur_audio_packet == AUDIO_PACKET_HBR)) &&
|
||
|
|
(last_audio_packet != cur_audio_packet));
|
||
|
|
|
||
|
|
if ((!hw_stable) || is_audio_packet_changed) {
|
||
|
|
*mute_time = 300;
|
||
|
|
patch->tv_param.last_audio_packet_type = cur_audio_packet;
|
||
|
|
ret = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case AUDIO_DEVICE_IN_FM_TUNER:
|
||
|
|
if (!is_atv_in_stable_hw(patch)) {
|
||
|
|
*mute_time = 1000;
|
||
|
|
ret = false;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case AUDIO_DEVICE_IN_SPDIF:
|
||
|
|
if (!is_spdif_in_stable_hw(patch)) {
|
||
|
|
*mute_time = 1000;
|
||
|
|
ret = false;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case AUDIO_DEVICE_IN_HDMI_ARC:
|
||
|
|
if (!is_earc_in_status_change(patch)) {
|
||
|
|
*mute_time = 1000;
|
||
|
|
ret = false;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
case AUDIO_DEVICE_IN_LINE:
|
||
|
|
if (!is_av_in_stable_hw(patch)) {
|
||
|
|
*mute_time = 1500;
|
||
|
|
if (patch->av_audio_only) {
|
||
|
|
// for av audio only case, we need output audio, so set stable_flag to true
|
||
|
|
bool stable = !Stop_watch(patch->patch_start_ts, 1500);
|
||
|
|
*mute_time = 2000;
|
||
|
|
ret = stable;
|
||
|
|
} else {
|
||
|
|
ret = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
|
||
|
|
return ret;
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
bool check_tv_stream_signal(struct aml_audio_patch *patch)
|
||
|
|
{
|
||
|
|
int in_mute = 0;
|
||
|
|
bool stable = true;
|
||
|
|
|
||
|
|
stable = signal_status_check(patch, &patch->mute_mdelay);
|
||
|
|
if (!stable) {
|
||
|
|
if (patch->mute_log_cntr == 0)
|
||
|
|
AM_LOGI("audio is unstable, mute channel");
|
||
|
|
if (patch->mute_log_cntr++ >= 100)
|
||
|
|
patch->mute_log_cntr = 0;
|
||
|
|
clock_gettime(CLOCK_MONOTONIC, &patch->mute_start_ts);
|
||
|
|
patch->mute_flag = true;
|
||
|
|
}
|
||
|
|
if (patch->mute_flag) {
|
||
|
|
in_mute = Stop_watch(patch->mute_start_ts, patch->mute_mdelay);
|
||
|
|
if (!in_mute) {
|
||
|
|
if (patch->input_device == AUDIO_DEVICE_IN_LINE) {
|
||
|
|
if (patch->av_audio_only) {
|
||
|
|
audio_patch_set_av_sync_status(patch, false);
|
||
|
|
AM_LOGI("audio only AV doesn't need to do av sync,set av sync to false");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
ALOGI("unmute audio since audio signal is stable,device(%x) mute_mdelay(%dms)", patch->input_device, patch->mute_mdelay);
|
||
|
|
/* The data of ALSA has not been read for a long time in the muted state,
|
||
|
|
* resulting in the accumulation of data. So, cache of capture needs to be cleared.
|
||
|
|
*/
|
||
|
|
audio_input_stop(patch->input_type);
|
||
|
|
patch->mute_log_cntr = 0;
|
||
|
|
patch->mute_flag = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/*if need mute input source, don't read data from hardware anymore*/
|
||
|
|
if (in_mute) {
|
||
|
|
return false;
|
||
|
|
} else {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool check_digital_in_stream_signal(struct aml_audio_patch *patch)
|
||
|
|
{
|
||
|
|
audio_type_parse_t *audio_type_status = (audio_type_parse_t *)patch->audio_parse_para;
|
||
|
|
enum audio_type cur_audio_type = LPCM;
|
||
|
|
|
||
|
|
/* parse thread may have exited ,add the code to avoid NULL point visit*/
|
||
|
|
if (audio_type_status == NULL) {
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (audio_type_status->soft_parser != 1) {
|
||
|
|
if (patch->spdif_fmt_hw == SPDIFIN_AUDIO_TYPE_PAUSE) {
|
||
|
|
ALOGV("%s(), hw detect iec61937 PAUSE packet, mute input", __func__);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
cur_audio_type = audio_parse_get_audio_type_direct(patch->audio_parse_para);
|
||
|
|
if (cur_audio_type == PAUSE || cur_audio_type == MUTE) {
|
||
|
|
ALOGV("%s(), soft parser iec61937 %s packet, mute input", __func__,
|
||
|
|
cur_audio_type == PAUSE ? "PAUSE" : "MUTE");
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
int reconfig_read_param_through_hdmiin(struct aml_audio_patch *patch, ring_buffer_t *ringbuffer, int buffer_size)
|
||
|
|
{
|
||
|
|
struct aml_audio_device *aml_dev = NULL;
|
||
|
|
int ring_buffer_size = buffer_size;
|
||
|
|
int last_channel_count = 2;
|
||
|
|
int s32Ret = 0;
|
||
|
|
bool is_channel_changed = false;
|
||
|
|
bool is_audio_packet_changed = false;
|
||
|
|
bool is_sample_rate_changed = false;
|
||
|
|
bool is_audio_format_changed = false;
|
||
|
|
hdmiin_audio_packet_t last_audio_packet = AUDIO_PACKET_AUDS;
|
||
|
|
audio_format_t format = AUDIO_FORMAT_PCM_SUB_16_BIT;
|
||
|
|
int is_hdmi1 = 0;
|
||
|
|
int current_channel = 2;
|
||
|
|
|
||
|
|
if (!patch || !patch->dev) {
|
||
|
|
AM_LOGE("error parameters!!");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
audio_type_parse_t *audio_type_status = (audio_type_parse_t *)patch->audio_parse_para;
|
||
|
|
is_hdmi1 = patch->input_device == AUDIO_DEVICE_IN_HDMI1 ? 1 : 0;
|
||
|
|
aml_dev = patch->dev;
|
||
|
|
|
||
|
|
last_channel_count = patch->in_channel_count;
|
||
|
|
last_audio_packet = patch->tv_param.audio_packet_type;
|
||
|
|
|
||
|
|
if (audio_is_linear_pcm(patch->aformat)) {
|
||
|
|
format = (aml_dev->audio_process_bitwidth == 32) ? AUDIO_FORMAT_PCM_32_BIT: AUDIO_FORMAT_PCM_16_BIT;
|
||
|
|
} else {
|
||
|
|
format = AUDIO_FORMAT_PCM_16_BIT;
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
int sr_index = get_hdmiin_sample_rate_index(&aml_dev->alsa_mixer, is_hdmi1);
|
||
|
|
int current_sample_rate = get_hdmiin_samplerate(sr_index);
|
||
|
|
if (is_hdmi_in_stable_hw(patch)) {
|
||
|
|
current_channel = get_hdmiin_channel(&aml_dev->alsa_mixer, is_hdmi1);
|
||
|
|
}
|
||
|
|
|
||
|
|
hdmiin_audio_packet_t cur_audio_packet = get_hdmiin_audio_packet(&aml_dev->alsa_mixer, is_hdmi1);
|
||
|
|
if (AUDIO_PACKET_HBR == cur_audio_packet) {
|
||
|
|
current_channel = 8;
|
||
|
|
//When audio packet is HBR, set format to 16 bits PCM
|
||
|
|
//Otherwise, the following parameters will cause alsa to fail to open
|
||
|
|
//The failed log is as follows:
|
||
|
|
//[aml_alsa_input_open:129] ALSA open configs: channels 8 format 1(32 bits) period_count 4 period_size 4096 rate 48000
|
||
|
|
//[aml_alsa_input_open:131] ALSA open configs: threshold start 0 stop 16384 silence 0 silence_size 2147483647 avail_min 0
|
||
|
|
//pcm_open: pcm(0xa8c00660) flag = 10000010, card = 0, device = 1
|
||
|
|
//pcm_open, pcm open fail. cannot set hw params: Invalid argument
|
||
|
|
//[aml_alsa_input_open:136] open device failed: cannot set hw params: Invalid argument
|
||
|
|
format = AUDIO_FORMAT_PCM_16_BIT;
|
||
|
|
}
|
||
|
|
|
||
|
|
//debug code
|
||
|
|
//current_channel = aml_audio_property_get_int("vendor.media.audiohal.hdmi.channel.debug", 2);
|
||
|
|
//AM_LOGI("current_channel:%d", current_channel);
|
||
|
|
|
||
|
|
is_channel_changed = ((current_channel > 0) && last_channel_count != current_channel);
|
||
|
|
is_audio_packet_changed = (((cur_audio_packet == AUDIO_PACKET_AUDS) || (cur_audio_packet == AUDIO_PACKET_HBR)) &&
|
||
|
|
(last_audio_packet != cur_audio_packet));
|
||
|
|
is_audio_format_changed = (patch->in_format != format);
|
||
|
|
|
||
|
|
/* here check the hdmirx->earc multich passthrough change */
|
||
|
|
if (aml_audio_earctx_get_type(aml_dev) == ATTEND_TYPE_EARC && (aml_dev->active_outport & OUTPORT_HDMI_ARC) != 0
|
||
|
|
&& aml_dev->hdmi_format == BYPASS && audio_is_linear_pcm(patch->aformat)) {
|
||
|
|
if (audio_type_status && audio_type_status->hdmi_earc_passthrough_mode != true) {
|
||
|
|
AM_LOGD("hdmi_earc_passthrough_mode change to TRUE\n");
|
||
|
|
audio_type_status->hdmi_earc_passthrough_mode = true;
|
||
|
|
enable_HW_resample(&aml_dev->alsa_mixer, HW_RESAMPLE_DISABLE, audio_type_status->input_dev);
|
||
|
|
}
|
||
|
|
patch->hdmi_earc_passthrough_mode = true;
|
||
|
|
patch->in_sample_rate = current_sample_rate;
|
||
|
|
} else {
|
||
|
|
if (audio_type_status && audio_type_status->hdmi_earc_passthrough_mode != false) {
|
||
|
|
AM_LOGD("hdmi_earc_passthrough_mode change to FALSE, format(%x)\n", patch->aformat);
|
||
|
|
if (audio_is_linear_pcm(patch->aformat)) {
|
||
|
|
enable_HW_resample(audio_type_status->mixer_handle, sr_index, audio_type_status->input_dev);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
patch->hdmi_earc_passthrough_mode = false;
|
||
|
|
if (audio_type_status) {
|
||
|
|
audio_type_status->hdmi_earc_passthrough_mode = false;
|
||
|
|
}
|
||
|
|
if (audio_is_linear_pcm(patch->aformat)) {
|
||
|
|
patch->in_sample_rate = 48000;
|
||
|
|
} else {
|
||
|
|
patch->in_sample_rate = current_sample_rate;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
//check whether hw resample needs to be reset
|
||
|
|
if (audio_is_linear_pcm(patch->aformat) && current_sample_rate > 0 && patch->hdmi_sample_rate != current_sample_rate) {
|
||
|
|
ALOGI("PCM sr change: [sr pre:%d->cur:%d]", patch->hdmi_sample_rate, current_sample_rate);
|
||
|
|
is_sample_rate_changed = true;
|
||
|
|
patch->hdmi_sample_rate = current_sample_rate;
|
||
|
|
if (!patch->hdmi_earc_passthrough_mode) { // Don't bypass mch and audio type is PCM.When sr changes,reset hw resample.
|
||
|
|
enable_HW_resample(&aml_dev->alsa_mixer, sr_index, audio_type_status->input_dev);
|
||
|
|
//patch->hdmi_sample_rate = 48000;
|
||
|
|
AM_LOGD("Reset audio resample sr to %d\n", sr_index);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
//If any of the following conditions are met,reconfig input stream and buffer
|
||
|
|
// 1.HBR and AUDS audio switching
|
||
|
|
// 2.channel num changed
|
||
|
|
// 3.game mode changed
|
||
|
|
// 4.sample rate changed in mch bypass mode
|
||
|
|
if ((is_channel_changed) || is_audio_packet_changed || is_audio_format_changed
|
||
|
|
|| aml_dev->low_latency_mode_changed ||
|
||
|
|
(patch->hdmi_earc_passthrough_mode && is_sample_rate_changed)) {
|
||
|
|
int buf_size = ring_buffer_size;
|
||
|
|
audio_input_config_t * config = &patch->input_config;
|
||
|
|
int channel = 2;
|
||
|
|
|
||
|
|
config->format = format;
|
||
|
|
config->period_size = AUDIO_INPUT_DEFAULT_PERIOD_SIZE;
|
||
|
|
config->period_count = AUDIO_INPUT_DEFAULT_PERIOD_COUNT;
|
||
|
|
config->sample_rate = AUDIO_INPUT_DEFAULT_SAMPLE_RATE;
|
||
|
|
|
||
|
|
patch->is_game_mode = is_low_latency_mode(aml_dev);
|
||
|
|
|
||
|
|
AM_LOGI("Reopen hdmi in alsa[audio_packet pre:%d->cur:%d changed:%d] [channel pre:%d->cur:%d changed:%d] [format pre:%x->cur:%x(%x) changed:%d] [game mode changed changed:%d cur:%d]",
|
||
|
|
last_audio_packet, cur_audio_packet, is_audio_packet_changed, last_channel_count, current_channel, is_channel_changed,
|
||
|
|
patch->in_format, format, patch->aformat, is_audio_format_changed, aml_dev->low_latency_mode_changed, patch->is_game_mode);
|
||
|
|
|
||
|
|
if (patch->is_game_mode) {
|
||
|
|
config->period_size = AUDIO_INPUT_LOW_LATENCY_PERIOD_SIZE;
|
||
|
|
channel = current_channel;
|
||
|
|
} else {
|
||
|
|
if (cur_audio_packet == AUDIO_PACKET_HBR || (audio_is_linear_pcm(patch->aformat) && current_channel > 2)) {
|
||
|
|
// if it is high bitrate bitstream, use PAO and increase the buffer size
|
||
|
|
config->period_size = AUDIO_INPUT_DEFAULT_PERIOD_SIZE * 4;
|
||
|
|
// increase the buffer size
|
||
|
|
buf_size = ring_buffer_size * 8;
|
||
|
|
channel = 8;
|
||
|
|
} else if (cur_audio_packet == AUDIO_PACKET_AUDS) {
|
||
|
|
|
||
|
|
if (8 == current_channel) {//8ch PCM
|
||
|
|
config->period_size = AUDIO_INPUT_DEFAULT_PERIOD_SIZE * 2;
|
||
|
|
buf_size = ring_buffer_size * 8;
|
||
|
|
} else {
|
||
|
|
config->period_size = AUDIO_INPUT_DEFAULT_PERIOD_SIZE;
|
||
|
|
// reset to original one
|
||
|
|
buf_size = ring_buffer_size;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (current_channel > 0) {
|
||
|
|
channel = current_channel;
|
||
|
|
}
|
||
|
|
AM_LOGI("channel:%d current_channel:%d buf_size:%d(%d)", channel, current_channel, buf_size, ring_buffer_size);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (ringbuffer) {
|
||
|
|
ring_buffer_reset_size(ringbuffer, buf_size);
|
||
|
|
}
|
||
|
|
|
||
|
|
// do_input_standby will close pcm, so must call hdmiin_gamemode_audio_stream_deinit before do_input_standby
|
||
|
|
hdmiin_gamemode_audio_stream_deinit(aml_dev);
|
||
|
|
|
||
|
|
s32Ret = audio_input_close(patch->input_type);
|
||
|
|
|
||
|
|
if (2 == channel) {
|
||
|
|
config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
|
||
|
|
} else if (6 == channel) {
|
||
|
|
config->channel_mask = AUDIO_CHANNEL_IN_5POINT1;
|
||
|
|
} else if (8 == channel) {
|
||
|
|
config->channel_mask = AUDIO_CHANNEL_IN_7POINT1;
|
||
|
|
} else {
|
||
|
|
AM_LOGW("unsupport channel count %d, use stereo", channel);
|
||
|
|
config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
|
||
|
|
channel = 2;
|
||
|
|
}
|
||
|
|
AM_LOGD("open input type:%d, period_count:%d, period_size:%d, format:%d, sample_rate:%d, ch:%d",
|
||
|
|
patch->input_type, config->period_count, config->period_size, config->format, config->sample_rate, channel);
|
||
|
|
s32Ret = audio_input_open(patch->input_type, config);
|
||
|
|
patch->input_open_counter ++;
|
||
|
|
|
||
|
|
if (patch->is_game_mode) {
|
||
|
|
hdmiin_gamemode_audio_stream_init(aml_dev, channel);
|
||
|
|
}
|
||
|
|
aml_dev->low_latency_mode_changed = false;
|
||
|
|
patch->tv_param.audio_packet_type = cur_audio_packet;
|
||
|
|
patch->in_format = format;
|
||
|
|
patch->in_channel_count = channel;
|
||
|
|
patch->in_chanmask = config->channel_mask;
|
||
|
|
}
|
||
|
|
return s32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
int reconfig_read_param_for_arc_spdif(struct aml_audio_patch *patch, ring_buffer_t *ringbuffer, int buffer_size)
|
||
|
|
{
|
||
|
|
struct aml_audio_device *aml_dev = NULL;
|
||
|
|
int ring_buffer_size = buffer_size;
|
||
|
|
int s32Ret = 0;
|
||
|
|
int last_input_type = NOT_READY;
|
||
|
|
bool is_input_type_changed = false;
|
||
|
|
bool is_audio_format_changed = false;
|
||
|
|
bool is_sample_rate_changed = false;
|
||
|
|
|
||
|
|
audio_format_t format = AUDIO_FORMAT_PCM_SUB_16_BIT;
|
||
|
|
|
||
|
|
if (!patch || !patch->dev) {
|
||
|
|
AM_LOGE("error parameters!!");
|
||
|
|
return -1;
|
||
|
|
}
|
||
|
|
aml_dev = patch->dev;
|
||
|
|
|
||
|
|
last_input_type = patch->last_parser_type;
|
||
|
|
|
||
|
|
if (audio_is_linear_pcm(patch->aformat)) {
|
||
|
|
format = (aml_dev->audio_process_bitwidth == 32) ? AUDIO_FORMAT_PCM_SUB_32_BIT:AUDIO_FORMAT_PCM_SUB_16_BIT;
|
||
|
|
} else {
|
||
|
|
format = AUDIO_FORMAT_PCM_SUB_16_BIT;
|
||
|
|
}
|
||
|
|
|
||
|
|
int current_sample_rate = audio_parse_get_audio_samplerate(patch->audio_parse_para);
|
||
|
|
int current_input_type = audio_parse_get_audio_type_direct(patch->audio_parse_para);
|
||
|
|
|
||
|
|
is_audio_format_changed = (patch->in_format != format);
|
||
|
|
is_input_type_changed = (last_input_type != current_input_type);
|
||
|
|
is_sample_rate_changed = (patch->in_sample_rate != current_sample_rate);
|
||
|
|
//reconfig input stream and buffer when HBR and AUDS audio switching or channel num changed or game mode changed
|
||
|
|
if (is_input_type_changed || is_audio_format_changed || is_sample_rate_changed) {
|
||
|
|
int period_size = AUDIO_INPUT_DEFAULT_PERIOD_SIZE;
|
||
|
|
int buf_size = 0;
|
||
|
|
int channel = 2;
|
||
|
|
int period_count = AUDIO_INPUT_DEFAULT_PERIOD_COUNT;
|
||
|
|
audio_input_config_t * config = &patch->input_config;
|
||
|
|
|
||
|
|
config->channel_mask = AUDIO_CHANNEL_IN_STEREO;
|
||
|
|
|
||
|
|
ALOGI("Reopen arc alsa [input type pre:%d->cur:%d changed:%d] [format pre:%x->cur:%x(%x) changed:%d] [sample rate pre:%d->cur:%d changed:%d]",
|
||
|
|
last_input_type, current_input_type, is_input_type_changed,
|
||
|
|
patch->in_format, format, patch->aformat, is_audio_format_changed,
|
||
|
|
patch->in_sample_rate, current_sample_rate, is_sample_rate_changed);
|
||
|
|
|
||
|
|
if (current_input_type == MULTICH_LPCM) {
|
||
|
|
config->channel_mask = AUDIO_CHANNEL_IN_7POINT1;
|
||
|
|
channel = 8;
|
||
|
|
buf_size = patch->in_buf_size * 3;
|
||
|
|
if (patch->in_sample_rate > 96000) {
|
||
|
|
period_size = AUDIO_INPUT_DEFAULT_PERIOD_SIZE * 4;
|
||
|
|
} else if (patch->in_sample_rate > 48000) {
|
||
|
|
period_size = AUDIO_INPUT_DEFAULT_PERIOD_SIZE * 2;
|
||
|
|
}
|
||
|
|
} else if (current_input_type == LPCM) {
|
||
|
|
buf_size = AUDIO_INPUT_DEFAULT_PERIOD_SIZE * AUDIO_INPUT_DEFAULT_PERIOD_COUNT * 4;
|
||
|
|
} else if (current_input_type == MAT) {
|
||
|
|
buf_size = ring_buffer_size * 8;
|
||
|
|
period_count = 16;
|
||
|
|
} else {
|
||
|
|
period_count = 16;
|
||
|
|
buf_size = ring_buffer_size;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (ringbuffer) {
|
||
|
|
ring_buffer_reset_size(ringbuffer, buf_size);
|
||
|
|
}
|
||
|
|
|
||
|
|
s32Ret = audio_input_close(patch->input_type);
|
||
|
|
|
||
|
|
config->period_count = period_count;
|
||
|
|
config->period_size = period_size;
|
||
|
|
config->format = format;
|
||
|
|
config->sample_rate = current_sample_rate;
|
||
|
|
AM_LOGD("open input type:%d, period_count:%d, period_size:%d, format:%d, sample_rate:%d",
|
||
|
|
patch->input_type, config->period_count, config->period_size, config->format, config->sample_rate);
|
||
|
|
s32Ret = audio_input_open(patch->input_type, config);
|
||
|
|
patch->input_open_counter ++;
|
||
|
|
patch->last_parser_type = current_input_type;
|
||
|
|
patch->in_sample_rate = current_sample_rate;
|
||
|
|
patch->in_channel_count = channel;
|
||
|
|
patch->in_chanmask = config->channel_mask;
|
||
|
|
}
|
||
|
|
return s32Ret;
|
||
|
|
}
|
||
|
|
|
||
|
|
//check no-pcm to pcm change,such as non pcm file pause, no pcm file stop play in HDMI source
|
||
|
|
void audio_raw_data_continuous_check(struct aml_audio_patch* patch, audio_type_parse_t *status, char *buffer, int size)
|
||
|
|
{
|
||
|
|
audio_type_parse_t *audio_type_status = status;
|
||
|
|
if (status == NULL) {
|
||
|
|
ALOGE("[%s:%d] status is NULL", __FUNCTION__, __LINE__);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
int sync_word_offset = find_61937_sync_word(buffer, size);
|
||
|
|
if (sync_word_offset >= 0) {
|
||
|
|
patch->sync_offset = sync_word_offset;
|
||
|
|
if (patch->start_mute) {
|
||
|
|
patch->start_mute = false;
|
||
|
|
patch->mdelay = 0;
|
||
|
|
}
|
||
|
|
if (patch->read_size > 0) {
|
||
|
|
patch->read_size = 0;
|
||
|
|
}
|
||
|
|
if (!patch->read_size) {
|
||
|
|
patch->read_size = size;
|
||
|
|
patch->read_size -= sync_word_offset;
|
||
|
|
}
|
||
|
|
} else if (patch->sync_offset >= 0) {
|
||
|
|
if ((patch->read_size < audio_type_status->package_size) && ((patch->read_size + size) > audio_type_status->package_size)) {
|
||
|
|
ALOGI("[%s:%d] find pcm data, read_size(%d) size(%d) package_size(%d)(%d)", __FUNCTION__, __LINE__,
|
||
|
|
patch->read_size, size, audio_type_status->package_size, patch->read_size + size);
|
||
|
|
clock_gettime(CLOCK_MONOTONIC, &patch->start_ts);
|
||
|
|
patch->start_mute = true;
|
||
|
|
patch->read_size = 0;
|
||
|
|
patch->mdelay = 900;
|
||
|
|
} else {
|
||
|
|
if (patch->start_mute) {
|
||
|
|
int flag = Stop_watch(patch->start_ts, patch->mdelay);
|
||
|
|
if (!flag) {
|
||
|
|
patch->sync_offset = -1;
|
||
|
|
patch->start_mute = false;
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
patch->read_size += size;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
bool is_hdmi_in_stable_hw(struct aml_audio_patch* patch)
|
||
|
|
{
|
||
|
|
int stable = 0;
|
||
|
|
struct aml_audio_device *adev = patch->dev;
|
||
|
|
int mixer_id = AML_MIXER_ID_HDMI_IN_AUDIO_STABLE;
|
||
|
|
|
||
|
|
if (patch->input_device == AUDIO_DEVICE_IN_HDMI1) {
|
||
|
|
mixer_id = AML_MIXER_ID_HDMI_IN1_AUDIO_STABLE;
|
||
|
|
}
|
||
|
|
stable = aml_mixer_ctrl_get_int (&adev->alsa_mixer, mixer_id);
|
||
|
|
if (!stable) {
|
||
|
|
ALOGV("%s() amixer %s get %d\n", __func__, "HDMIIN audio stable", stable);
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
bool is_atv_in_stable_hw (struct aml_audio_patch *patch)
|
||
|
|
{
|
||
|
|
struct aml_audio_device *aml_dev = patch->dev;
|
||
|
|
int stable = 0;
|
||
|
|
|
||
|
|
stable = aml_mixer_ctrl_get_int (&aml_dev->alsa_mixer, AML_MIXER_ID_ATV_IN_AUDIO_STABLE);
|
||
|
|
if (!stable)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
bool is_av_in_stable_hw(struct aml_audio_patch *patch)
|
||
|
|
{
|
||
|
|
struct aml_audio_device *aml_dev = patch->dev;
|
||
|
|
int stable = 0;
|
||
|
|
|
||
|
|
stable = aml_mixer_ctrl_get_int (&aml_dev->alsa_mixer, AML_MIXER_ID_AV_IN_AUDIO_STABLE);
|
||
|
|
if (!stable)
|
||
|
|
return false;
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
int is_earcrx_stable(struct aml_mixer_handle *alsa_mixer)
|
||
|
|
{
|
||
|
|
return aml_mixer_ctrl_get_int(alsa_mixer, AML_MIXER_ID_EARCRX_STABLE);
|
||
|
|
}
|
||
|
|
|
||
|
|
bool is_spdif_in_stable_hw(struct aml_audio_patch *patch)
|
||
|
|
{
|
||
|
|
struct aml_audio_device *adev = patch->dev;
|
||
|
|
int type = aml_mixer_ctrl_get_int (&adev->alsa_mixer, AML_MIXER_ID_SPDIFIN_AUDIO_TYPE);
|
||
|
|
|
||
|
|
if (type > PAUSE || type < LPCM) {
|
||
|
|
AM_LOGV("in type is not ready yet");
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
if (type != patch->spdif_fmt_hw) {
|
||
|
|
AM_LOGI ("in type changed from %d to %d", patch->spdif_fmt_hw, type);
|
||
|
|
patch->spdif_fmt_hw = type;
|
||
|
|
return false;
|
||
|
|
}
|
||
|
|
|
||
|
|
return true;
|
||
|
|
}
|
||
|
|
|
||
|
|
int game_mode_data_read(struct aml_audio_device *adev, bool drop_enable, void* buffer, int bytes)
|
||
|
|
{
|
||
|
|
int ret = 0;
|
||
|
|
int frame_size = 4;// 16bits 2ch
|
||
|
|
int total_bytes = 0;
|
||
|
|
int reset_frames_threshold;
|
||
|
|
if (!adev || !buffer || !bytes) {
|
||
|
|
AM_LOGE("Param error: adev:%p buffer:%p bytes:%d", adev, buffer, bytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
if (32 == adev->audio_process_bitwidth) {
|
||
|
|
frame_size = 8;// 32bits 2ch
|
||
|
|
}
|
||
|
|
|
||
|
|
pthread_mutex_lock (&adev->low_latency_param_lock);
|
||
|
|
struct aml_low_latency_param* game_mode_param = &(adev->low_latency_param);
|
||
|
|
//only read from HDMI. For HDMI 1, to do ...
|
||
|
|
if (game_mode_param->is_game_mode_inited && game_mode_param->is_signal_stable) {
|
||
|
|
if (drop_enable) {
|
||
|
|
ret = audio_input_flush(AUDIO_INPUT_TYPE_HDMI);
|
||
|
|
if (ret < 0) {
|
||
|
|
AM_LOGE("cannot flush!");
|
||
|
|
}
|
||
|
|
goto read_end;
|
||
|
|
}
|
||
|
|
|
||
|
|
total_bytes = game_mode_param->input_channel * bytes / 2;
|
||
|
|
reset_frames_threshold = total_bytes / frame_size;// reset_frames_threshold is same as read frames
|
||
|
|
memset((void*)buffer, 0, bytes);
|
||
|
|
if (aml_audio_check_and_realloc(&(game_mode_param->tmp_buf), (size_t*)&(game_mode_param->tmp_buf_size), total_bytes) != 0) {
|
||
|
|
AM_LOGE("aml_audio_realloc is fail. bytes:%d", bytes);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
//For the instability of water level control in submix, when the alsa output delay is greater than 13ms, flush data
|
||
|
|
if (adev->useSubMix) {
|
||
|
|
uint64_t out_delay_frame = aml_audio_pcm_out_get_delayframe(adev, false);
|
||
|
|
if (out_delay_frame / 48 > 13) {
|
||
|
|
AM_LOGI("ALSA out delay %"PRIu64"ms is large, flush data", out_delay_frame / 48);
|
||
|
|
aml_audio_pcm_out_flush(adev);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
{
|
||
|
|
int frames = audio_input_get_delay(AUDIO_INPUT_TYPE_HDMI);
|
||
|
|
if (get_debug_value(AML_DEBUG_AUDIOHAL_GAME_MODE)) {
|
||
|
|
uint64_t in_delay_frame = frames;
|
||
|
|
uint64_t out_delay_frame = aml_audio_pcm_out_get_delayframe(adev, false);
|
||
|
|
AM_LOGW("Total delay:%"PRIu64"ms(in:%"PRIu64"ms out:%"PRIu64"ms) read_frames:%d bytes:%d",
|
||
|
|
in_delay_frame/48 + out_delay_frame/48, in_delay_frame/48, out_delay_frame/48, reset_frames_threshold, bytes);
|
||
|
|
}
|
||
|
|
if (frames > reset_frames_threshold) {
|
||
|
|
AM_LOGW("delay frames:%d reset_frames_threshold:%d bytes:%d, reset alsa", frames, reset_frames_threshold, bytes);
|
||
|
|
ret = audio_input_flush(AUDIO_INPUT_TYPE_HDMI);
|
||
|
|
if (ret < 0) {
|
||
|
|
AM_LOGE("cannot flush!");
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (audio_input_read(AUDIO_INPUT_TYPE_HDMI, game_mode_param->tmp_buf, total_bytes) != total_bytes) {
|
||
|
|
AM_LOGE("cannot read enough data!");
|
||
|
|
}
|
||
|
|
|
||
|
|
if (16 == adev->audio_process_bitwidth) {
|
||
|
|
adjust_channels(game_mode_param->tmp_buf, game_mode_param->input_channel, buffer, 2, 2, total_bytes);
|
||
|
|
} else if (32 == adev->audio_process_bitwidth) {
|
||
|
|
adjust_channels(game_mode_param->tmp_buf, game_mode_param->input_channel, buffer, 2, 4, total_bytes);
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
if (get_debug_value(AML_DUMP_AUDIOHAL_TV)) {
|
||
|
|
aml_dump_audio_bitstreams("/data/vendor/audiohal/tv_read_of_game_mode.raw", buffer, bytes);
|
||
|
|
}
|
||
|
|
} else {
|
||
|
|
if (get_debug_value(AML_DEBUG_AUDIOHAL_GAME_MODE)) {
|
||
|
|
AM_LOGW("is_game_mode_inited:%d, can't read data from alsa is_signal_stable:%d", game_mode_param->is_game_mode_inited,
|
||
|
|
game_mode_param->is_signal_stable);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
read_end:
|
||
|
|
pthread_mutex_unlock (&adev->low_latency_param_lock);
|
||
|
|
return total_bytes;
|
||
|
|
}
|
||
|
|
|
||
|
|
int hdmiin_gamemode_audio_stream_init(struct aml_audio_device *adev, int channels)
|
||
|
|
{
|
||
|
|
pthread_mutex_lock (&adev->low_latency_param_lock);
|
||
|
|
struct aml_low_latency_param* low_latency_param = &(adev->low_latency_param);
|
||
|
|
if (!low_latency_param->is_game_mode_inited) {
|
||
|
|
memset(low_latency_param, 0x00, sizeof(struct aml_low_latency_param));
|
||
|
|
low_latency_param->is_game_mode_inited = true;
|
||
|
|
low_latency_param->is_reading_data = false;
|
||
|
|
low_latency_param->input_channel = channels;
|
||
|
|
aml_enter_hdmi_game_mode(adev);
|
||
|
|
AM_LOGI("Init game mode. channels:%d", channels);
|
||
|
|
} else {
|
||
|
|
AM_LOGE("Already init game mode");
|
||
|
|
}
|
||
|
|
pthread_mutex_unlock (&adev->low_latency_param_lock);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|
||
|
|
int hdmiin_gamemode_audio_stream_deinit(struct aml_audio_device *adev)
|
||
|
|
{
|
||
|
|
pthread_mutex_lock (&adev->low_latency_param_lock);
|
||
|
|
struct aml_low_latency_param* low_latency_param = &(adev->low_latency_param);
|
||
|
|
if (low_latency_param->is_game_mode_inited) {
|
||
|
|
low_latency_param->is_game_mode_inited = false;
|
||
|
|
low_latency_param->is_reading_data = false;
|
||
|
|
aml_exit_hdmi_game_mode(adev);
|
||
|
|
AM_LOGI("Deinit game mode");
|
||
|
|
} else {
|
||
|
|
AM_LOGE("Game mode is not inited");
|
||
|
|
}
|
||
|
|
pthread_mutex_unlock (&adev->low_latency_param_lock);
|
||
|
|
return 0;
|
||
|
|
}
|
||
|
|
|