/* * 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 #include #include #include #include #include #include #include #include #include #include #include "aml_audio_log.h" #include #include #include #include #if ANDROID_PLATFORM_SDK_VERSION >= 25 // 8.0 #include #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; }