Files
BPI-CM9-Linux/aml-comp/multimedia/aml_audio_hal/input/tv_patch_ctrl.c
T

789 lines
30 KiB
C
Raw Normal View History

2026-08-13 11:28:40 +08:00
/*
* 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;
}