/* * Copyright (C) 2017 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_input_dtv" #include #include #include #include "aml_audio_log.h" #ifdef BUILD_LINUX #include "atomic.h" #endif #include "audio_hw.h" #include "aml_audio_stream.h" #include "audio_hw_resource_def.h" #include "device_patch_mgr.h" #include "device_patch.h" #include "dtv_patch.h" #include "tv_patch.h" #include "aml_ng.h" #include "audio_hw_utils.h" #include "audio_hw_resource_mgr.h" #include "alsa_device_parser.h" #include "aml_noise_gate.h" #include "dtv_private_object.h" #include "tv_private_object.h" #include "tv_patch.h" #include "tv_patch_avsync.h" #include "aml_audio_log.h" #include "aml_audio_output.h" #include "tv_patch_ctrl.h" struct patch_manager; typedef int (*create_patch_t)(struct patch_manager * manager, unsigned int num_sources, const struct audio_port_config *sources, unsigned int num_sinks, const struct audio_port_config *sinks, audio_patch_handle_t *handle); typedef int (*release_patch_t)(struct patch_manager *, audio_patch_handle_t); #define PATCH_TYPE_TO_OFFSET(type) (type) struct audio_patch_set { struct listnode list; struct audio_patch patch; void *aml_patch; }; typedef struct patch_manager { struct aml_audio_device *adev; volatile int32_t next_unique_ID; /* list head for audio_patch */ struct listnode patch_list; // number of patch instance int count; // patch running flag //bool audio_patching; // used only for real TV source //enum patch_source patch_src; // Which HW inport is selected for data source //bool valid; pthread_mutex_t lock; // operations of patch manger create_patch_t create_patch; release_patch_t release_patch; //object from adev only used by dtv case struct dtv_private_object *dtv_obj; //object from adev only used by tv case struct tv_private_object *tv_obj; // Others not directly related to patch from adev struct component_noise_gate noise_gate; bool tv_have_exit; bool atv_dtv_switch; } patch_manager; static struct audio_patch_set *get_patch_set_by_handle(struct patch_manager *patch_mgr, audio_patch_handle_t handle); //Patch manger APIs static inline void acquire_patch_mgr_lock(struct patch_manager *patch_mgr) { pthread_mutex_lock(&patch_mgr->lock); } static inline void release_patch_mgr_lock(struct patch_manager *patch_mgr) { pthread_mutex_unlock(&patch_mgr->lock); } bool is_patch_exist_mgr(struct patch_manager *patch_mgr) { struct audio_patch_set *patch_set = NULL; struct listnode *node = NULL; bool is_patch_exist = false; /* find aml_patch in patch_set list */ list_for_each(node, &patch_mgr->patch_list) { patch_set = node_to_item(node, struct audio_patch_set, list); if (patch_set && patch_set->aml_patch) { is_patch_exist = true; break; } } return is_patch_exist; } /*static inline bool is_patch_valid_mgr(struct patch_manager *patch_mgr) { return (patch_mgr->valid ? true : false); }*/ /*static inline bool is_patch_running_mgr(struct patch_manager *patch_mgr) { return (patch_mgr->audio_patching ? true : false); } static inline void set_patch_running_mgr(struct patch_manager *patch_mgr, bool enable) { patch_mgr->audio_patching = enable; } static inline void set_patch_source_mgr(struct patch_manager *patch_mgr, enum patch_source patch_src) { patch_mgr->patch_src = patch_src; } static inline enum patch_source get_patch_source_mgr(struct patch_manager *patch_mgr) { return patch_mgr->patch_src; } static inline void invalidate_patch_mgr(struct patch_manager *patch_mgr) { patch_mgr->valid = false; } static inline void validate_patch_mgr(struct patch_manager *patch_mgr) { patch_mgr->valid = true; }*/ void do_patch_source_routing(struct patch_manager *patch_mgr, audio_devices_t input_device) { enum input_source input_src = android_input_dev_convert_to_hal_input_src(input_device); int ret = 0; ret = do_input_device_routing(patch_mgr->adev, input_device, true); //select source signal for selected in port if (input_src != SRC_NA) { set_audio_source_routing(patch_mgr->adev, input_src); } } static void dump_audio_port_config (const struct audio_port_config *port_config) { if (port_config == NULL) return; ALOGI (" -%s port_config(%p)", __FUNCTION__, port_config); ALOGI ("\t-id(%d), role(%s), type(%s)", port_config->id, audio_port_role_to_str(port_config->role), audio_port_type_to_str(port_config->type)); ALOGV ("\t-config_mask(%#x)", port_config->config_mask); ALOGI ("\t-sample_rate(%d), channel_mask(%#x), format(%#x)", port_config->sample_rate, port_config->channel_mask, port_config->format); ALOGV ("\t-gain.index(%#x)", port_config->gain.index); ALOGV ("\t-gain.mode(%#x)", port_config->gain.mode); ALOGV ("\t-gain.channel_mask(%#x)", port_config->gain.channel_mask); ALOGI ("\t-gain.value0(%d)", port_config->gain.values[0]); ALOGI ("\t-gain.value1(%d)", port_config->gain.values[1]); ALOGI ("\t-gain.value2(%d)", port_config->gain.values[2]); ALOGV ("\t-gain.ramp_duration_ms(%d)", port_config->gain.ramp_duration_ms); switch (port_config->type) { case AUDIO_PORT_TYPE_DEVICE: ALOGI ("\t-port device: type(%#x) addr(%s)", port_config->ext.device.type, port_config->ext.device.address); break; case AUDIO_PORT_TYPE_MIX: ALOGI ("\t-port mix: iohandle(%d)", port_config->ext.mix.handle); break; default: break; } } void dump_audio_patch_set (struct audio_patch_set *patch_set) { struct audio_patch *patch = NULL; unsigned int i = 0; if (!patch_set) return; patch = &patch_set->patch; if (!patch) return; ALOGI (" - %s(), id: %d", __func__, patch->id); for (i = 0; i < patch->num_sources; i++) dump_audio_port_config (&patch->sources[i]); for (i = 0; i < patch->num_sinks; i++) dump_audio_port_config (&patch->sinks[i]); } /* add new audio patch to dev list */ static struct audio_patch_set *register_audio_patch(struct patch_manager *patch_mgr, unsigned int num_sources, const struct audio_port_config *sources, unsigned int num_sinks, const struct audio_port_config *sinks, audio_patch_handle_t *handle) { /* init audio patch */ struct audio_patch_set *patch_set_new = NULL; struct audio_patch *patch_new = NULL; audio_patch_handle_t patch_handle; patch_set_new = aml_audio_calloc(1, sizeof (*patch_set_new) ); if (!patch_set_new) { ALOGE("%s(): no memory", __func__); return NULL; } patch_new = &patch_set_new->patch; #ifdef BUILD_LINUX patch_handle = (audio_patch_handle_t) atomic_inc((atomic_t *)(&patch_mgr->next_unique_ID)); #else patch_handle = (audio_patch_handle_t) android_atomic_inc(&patch_mgr->next_unique_ID); #endif *handle = patch_handle; /* init audio patch new */ patch_new->id = patch_handle; patch_new->num_sources = num_sources; memcpy(patch_new->sources, sources, num_sources * sizeof(struct audio_port_config)); patch_new->num_sinks = num_sinks; memcpy(patch_new->sinks, sinks, num_sinks * sizeof (struct audio_port_config)); #ifdef DEBUG_PATCH_SET AM_LOGD("patch set new to register:"); dump_audio_patch_set(patch_set_new); #endif /* add new patch set to dev patch list */ /* coverity[use_after_free]:use aml_dev->patch_list.next is ok*/ list_add_head(&patch_mgr->patch_list, &patch_set_new->list); AM_LOGI("after registering new patch, patch sets will be:"); //dump_aml_audio_patch_sets(dev); return patch_set_new; } /* remove audio patch from dev list */ static int unregister_audio_patch(struct patch_manager *patch_mgr __unused, struct audio_patch_set *patch_set) { ALOGD("%s: enter", __func__); if (!patch_set) return -EINVAL; #ifdef DEBUG_PATCH_SET dump_audio_patch_set(patch_set); #endif list_remove(&patch_set->list); aml_audio_free(patch_set); ALOGD("%s: exit", __func__); return 0; } static int create_patch_internal(struct patch_manager *patch_mgr, unsigned int num_sources, const struct audio_port_config *sources, unsigned int num_sinks, const struct audio_port_config *sinks, audio_patch_handle_t *handle) { int ret = 0; int inport; struct audio_patch_set * patch_set = NULL; audio_devices_t src_device = sources->ext.device.type; enum patch_source patch_source = SRC_INVAL; acquire_patch_mgr_lock(patch_mgr); patch_mgr->tv_have_exit = false; patch_mgr->atv_dtv_switch = false; patch_source = get_patch_source(src_device, PATCH_ROUTE_DEV_DEV); //to remove //patch_mgr->patch_src = patch_source; android_dev_convert_to_hal_dev(src_device, (int *)&inport); patch_set = register_audio_patch(patch_mgr, num_sources, sources, num_sinks, sinks, handle); if (NULL == patch_set) { AM_LOGW("patch_set is null, create fail."); release_patch_mgr_lock(patch_mgr); return -ENOMEM; } set_input_device_avail(patch_mgr->adev, src_device, true); if (SRC_DTV == patch_source) { #ifdef USE_DTV ret = create_dtv_patch(patch_mgr->adev, &patch_set->aml_patch); #endif } else { do_patch_source_routing(patch_mgr, src_device); ret = create_tv_patch(patch_mgr->adev, src_device, &patch_set->aml_patch); } if (ret == 0) { //set_patch_running_mgr(patch_mgr, true); AM_LOGI("create [%s] patch success!", patchSrc2Str(patch_source)); } else { AM_LOGE("create patch error!"); unregister_audio_patch(patch_mgr, patch_set); } //The noise gate is initialized when creating the analog signal patch. if (src_device == AUDIO_DEVICE_IN_LINE || src_device == AUDIO_DEVICE_IN_FM_TUNER) { struct component_noise_gate *noise_gate = &patch_mgr->noise_gate; if (noise_gate->aml_ng_enable) { aml_noise_gate_init(noise_gate); } } release_patch_mgr_lock(patch_mgr); return ret; } int release_patch_internal(struct patch_manager *patch_mgr, audio_patch_handle_t handle) { int ret = 0; struct aml_audio_patch *aml_patch = NULL; struct audio_patch_set *patch_set = NULL; bool is_game_mode = false; ALOGI("++%s: handle(%d)", __func__, handle); acquire_patch_mgr_lock(patch_mgr); patch_set = get_patch_set_by_handle(patch_mgr, handle); if (!patch_set) { AM_LOGE("Can't get patch in list"); ret = -EINVAL; goto exit; } aml_patch = (struct aml_audio_patch *)patch_set->aml_patch; is_game_mode = aml_patch->is_game_mode; AM_LOGI("patch_src: %s is_game_mode: %d", patchSrc2Str(aml_patch->patch_src), is_game_mode); if (aml_patch->patch_src == SRC_DTV) { #ifdef USE_DTV release_dtv_patch(patch_mgr->adev, patch_set->aml_patch); #endif } else { do_input_device_routing(patch_mgr->adev, aml_patch->input_device, false); /*coverity[sleep]*/ ret = release_tv_patch(patch_mgr->adev, patch_set->aml_patch); } unregister_audio_patch(patch_mgr, patch_set); //after release patch, game mode may change if (is_game_mode) { hdmiin_gamemode_audio_stream_deinit(patch_mgr->adev); } //deinit noise gate when release av patch. aml_noise_gate_deinit(&patch_mgr->noise_gate); AM_LOGI(" --exit "); exit: release_patch_mgr_lock(patch_mgr); return ret; } int patch_mgr_set_decoder_id(struct patch_manager *patch_mgr, int patch_id, int decoder_id) { struct audio_patch_set *patch_set = NULL; acquire_patch_mgr_lock(patch_mgr); patch_set = get_patch_set_by_handle (patch_mgr, patch_id); if (NULL == patch_set) { AM_LOGI("can't find the corresponding patch_set."); } else { struct aml_audio_patch *aml_patch = (struct aml_audio_patch *)(patch_set->aml_patch); if (NULL == aml_patch) { AM_LOGI("can't find the corresponding audio_patch."); } else { aml_patch->decoder_id = decoder_id; if (aml_patch->stream_out != NULL) { struct aml_stream_out *out= (struct aml_stream_out *)aml_patch->stream_out; out->decoder_id = decoder_id; } else { AM_LOGI("stream not opened.pending"); } } } AM_LOGI("path_id:%d decoder_id:%d", patch_id, decoder_id); release_patch_mgr_lock(patch_mgr); return 0; } static struct audio_patch_set *get_patch_set_by_handle(struct patch_manager *patch_mgr, audio_patch_handle_t handle) { if (list_empty(&patch_mgr->patch_list)) { ALOGE("No patch in list"); return NULL; } struct audio_patch_set *patch_set = NULL; struct audio_patch *patch = NULL; struct listnode *node = NULL; /* find audio_patch in patch_set list */ list_for_each(node, &patch_mgr->patch_list) { patch_set = node_to_item(node, struct audio_patch_set, list); patch = &patch_set->patch; if (patch && patch->id == handle) { AM_LOGI("patch set found id %d, patchset %p", patch->id, patch_set); break; } else { patch_set = NULL; patch = NULL; } } return patch_set; } /****************************************** * patch APIs wrap for adev ********************************************/ struct component_noise_gate *get_noise_gate_instance(struct aml_audio_device *adev) { if (NULL == adev || NULL == adev->patch_manager) { AM_LOGE("adev or adev->patch_manager is NULL, needs check it!!"); return NULL; } return &adev->patch_manager->noise_gate; } struct dtv_private_object *get_dtv_object(struct aml_audio_device *adev) { struct dtv_private_object *dtv_obj = adev->patch_manager->dtv_obj; if (!dtv_obj) { dtv_obj = aml_audio_calloc(1, sizeof(struct dtv_private_object)); adev->patch_manager->dtv_obj = dtv_obj; if (!dtv_obj) { ALOGE("%s() error, No memory!", __func__); } } return dtv_obj; } struct tv_private_object *get_tv_object(struct aml_audio_device *adev) { struct tv_private_object *tv_obj = adev->patch_manager->tv_obj; if (!tv_obj) { tv_obj = aml_audio_calloc(1, sizeof(struct tv_private_object)); adev->patch_manager->tv_obj = tv_obj; if (!tv_obj) { ALOGE("%s() Error, No memory!", __func__); } } return tv_obj; } bool is_dev_patch_exist(struct aml_audio_device *adev) { return is_patch_exist_mgr(adev->patch_manager); } bool is_dtv_patch_exist(struct aml_audio_device *adev) { struct aml_audio_patch * dtv_patch = get_dev_patch_by_source(adev, SRC_DTV); if (dtv_patch) { return true; } else { return false; } } struct aml_audio_patch *get_dev_patch_by_source(struct aml_audio_device *adev, enum patch_source patch_src) { struct aml_audio_patch *aml_patch = NULL; struct audio_patch_set *patch_set = NULL; struct listnode *node = NULL; /* find aml_patch in patch_set list */ list_for_each(node, &adev->patch_manager->patch_list) { patch_set = node_to_item(node, struct audio_patch_set, list); aml_patch = (struct aml_audio_patch *)patch_set->aml_patch; if (aml_patch && aml_patch->patch_src == patch_src) { //AM_LOGI("aml_patch(%p) found, patch_src %s, patchset %p", aml_patch, patchSrc2Str(patch_src), patch_set); break; } else { patch_set = NULL; aml_patch = NULL; } } //if (NULL == aml_patch) { //AM_LOGI("patch_src %s does not exist in path list!", patchSrc2Str(patch_src)); //} return aml_patch; } /*bool is_dev_patch_running(struct aml_audio_device *adev) { return is_patch_running_mgr(adev->patch_manager); } void set_dev_patch_running(struct aml_audio_device *adev, bool enable) { set_patch_running_mgr(adev->patch_manager, enable); } void set_dev_patch_src(struct aml_audio_device *adev, enum patch_source patch_src) { set_patch_source_mgr(adev->patch_manager, patch_src); } int get_dev_patch_src(struct aml_audio_device *adev) { return get_patch_source_mgr(adev->patch_manager); };*/ /*bool is_dev_patch_valid(struct aml_audio_device *adev) { return is_patch_valid_mgr(adev->patch_manager); } void invalidate_dev_patch(struct aml_audio_device *adev) { invalidate_patch_mgr(adev->patch_manager); } void validate_dev_patch(struct aml_audio_device *adev) { validate_patch_mgr(adev->patch_manager); }*/ void acquire_dev_patch_lock(struct aml_audio_device *adev) { acquire_patch_mgr_lock(adev->patch_manager); } void release_dev_patch_lock(struct aml_audio_device *adev) { release_patch_mgr_lock(adev->patch_manager); } enum patch_source get_patch_source(audio_devices_t src_device, int route_type __unused) { enum patch_source patch_source; int inport; int ret; ret = android_dev_convert_to_hal_dev(src_device, (int *)&inport); if (ret < 0) { ALOGD("%s() Not support src_device:0x%x return!", __func__, src_device); return SRC_INVAL; } if (inport == INPORT_DTV) { patch_source = SRC_DTV; } else if (inport == INPORT_ATV) { patch_source = SRC_ATV; } else if (inport != INPORT_ECHO_REFERENCE && inport != INPORT_BUILTIN_MIC) { patch_source = android_input_dev_convert_to_hal_patch_src(src_device); } else { patch_source = SRC_INVAL; ALOGW("%s() Warning! Not support inport:%s", __func__, inputPort2Str(inport)); } return patch_source; } //impl but not used int get_patch_type(struct aml_audio_device *adev __unused, int inport, enum patch_source patch_src, enum patch_route_e route_type) { int patch_type; switch (route_type) { case PATCH_ROUTE_DEV_DEV: if ((inport != INPORT_TUNER) || ((inport == INPORT_TUNER) && (patch_src == SRC_ATV))) { patch_type = PATCH_TYPE_TV; } else if ((inport == INPORT_TUNER) && (patch_src == SRC_DTV)) { patch_type = PATCH_TYPE_DTV; } else { patch_type = PATCH_TYPE_INVAL; } break; case PATCH_ROUTE_DEV_MIX: if (inport == INPORT_HDMIIN || inport == INPORT_HDMIIN1 || inport == INPORT_ARCIN || inport == INPORT_SPDIF || inport == INPORT_LINEIN || ((inport == INPORT_TUNER) && (patch_src == SRC_ATV))) { patch_type = PATCH_TYPE_TV; } else if ((inport == INPORT_TUNER) && (patch_src == SRC_DTV)){ patch_type = PATCH_TYPE_DTV; } else { patch_type = PATCH_TYPE_INVAL; } break; default: ALOGI("Warning, unsupport route_type:%d ", route_type); patch_type = PATCH_TYPE_INVAL; break; } return patch_type; } struct patch_manager *get_patch_manager(struct aml_audio_device *adev) { if (adev->patch_manager == NULL) { struct patch_manager *mgr = aml_audio_calloc(1, sizeof(struct patch_manager)); adev->patch_manager = mgr; } return adev->patch_manager; } int init_patch_manager(struct aml_audio_device *adev) { int ret = 0; struct patch_manager *patch_mgr = get_patch_manager(adev); if (!patch_mgr) { ALOGW("%s() error! patch_mgr = NULL!", __func__); return -EINVAL; } //new & init tv_private_object ret = init_tv_object(adev); if (ret != 0) { goto err_exit; } ret = init_dtv_object(adev); if (ret != 0) { goto err_exit; } patch_mgr->adev = adev; //patch_mgr->audio_patching = false; //patch_mgr->patch_src = SRC_INVAL; //patch_mgr->valid = false; patch_mgr->create_patch = create_patch_internal; patch_mgr->release_patch = release_patch_internal; patch_mgr->next_unique_ID = 1; list_init(&patch_mgr->patch_list); pthread_mutex_init(&patch_mgr->lock, NULL); AM_LOGI("OK"); return 0; err_exit: destroy_tv_object(adev); destroy_dtv_object(adev); aml_audio_free(patch_mgr); adev->patch_manager = NULL; ALOGE("%s() Fail!", __func__); return -EINVAL; } void destroy_patch_manager(struct aml_audio_device *adev) { struct patch_manager *patch_mgr = get_patch_manager(adev); if (!patch_mgr) { ALOGW("%s() error! patch_mgr = NULL!", __func__); return; } destroy_tv_object(adev); destroy_dtv_object(adev); //patch_mgr->valid = false; //patch_mgr->audio_patching = false; pthread_mutex_destroy(&patch_mgr->lock); aml_audio_free(patch_mgr->tv_obj); patch_mgr->tv_obj = NULL; aml_audio_free(patch_mgr); adev->patch_manager = NULL; ALOGI("%s() done!", __func__); } int patch_mgr_create_patch(struct aml_audio_device *adev, unsigned int num_sources, const struct audio_port_config *sources, unsigned int num_sinks, const struct audio_port_config *sinks, audio_patch_handle_t *handle) { int ret = 0; patch_manager *patch_mgr = adev->patch_manager; ret = patch_mgr->create_patch(patch_mgr, num_sources, sources, num_sinks, sinks, handle); return ret; } int patch_mgr_release_patch(struct aml_audio_device *adev, audio_patch_handle_t handle) { int ret = 0; patch_manager *patch_mgr = adev->patch_manager; ret = patch_mgr->release_patch(patch_mgr, handle); return ret; } int set_tv_source_switch_parameters(struct audio_hw_device *dev, struct str_parms *parms) { struct aml_audio_device *adev = (struct aml_audio_device *)dev; int ret = -1; char value[64] = {'\0'}; if (!adev->patch_manager) { goto exit; } ret = str_parms_get_str (parms, "hal_param_tuner_in", value, sizeof (value) ); // tuner_in=atv: tuner_in=dtv if (ret >= 0 && is_TV(adev)) { AM_LOGE("don't support %s!!", value); goto exit; } /* * This is a work around when plug in HDMI-DVI connector * first time application only recognize it as HDMI input device * then it can know it's DVI in ,and send "audio=linein" message to audio hal */ ret = str_parms_get_str(parms, "audio", value, sizeof(value)); if (ret >= 0) { AM_LOGE("don't support %s!! it needs review the design of tv server, tv server should release old patch and create a new one!!", value); } exit: return ret; } /************************ dump patch info ***************************/ //1.1 dump one registered audio patch information void aml_audio_port_config_dump(struct audio_port_config *port_config, int fd) { if (port_config == NULL) return; dprintf(fd, "\t-id(%d), role(%s), type(%s)\n", port_config->id, audioPortRole2Str(port_config->role), audioPortType2Str(port_config->type)); switch (port_config->type) { case AUDIO_PORT_TYPE_DEVICE: dprintf(fd, "\t-port device: type(%#x) addr(%s)\n", port_config->ext.device.type, port_config->ext.device.address); break; case AUDIO_PORT_TYPE_MIX: dprintf(fd, "\t-port mix: io handle(%d)\n", port_config->ext.mix.handle); break; default: break; } } void audio_patch_dump(struct audio_patch *patch, int fd) { int i = 0; if (NULL == patch) { dprintf(fd, "\n-------------[AML_HAL] patch is NULL-----------\n"); return; } dprintf(fd, " handle patch_id: %d\n", patch->id); for (i = 0; i < patch->num_sources; i++) { dprintf(fd, " [src %d]\n", i); aml_audio_port_config_dump(&patch->sources[i], fd); } for (i = 0; i < patch->num_sinks; i++) { dprintf(fd, " [sink %d]\n", i); aml_audio_port_config_dump(&patch->sinks[i], fd); } } //2. dump amlogic audio patch (device to device) information void aml_device_patch_dump(struct aml_audio_patch* pstPatch, int fd) { if (NULL == pstPatch) { dprintf(fd, "\n-------------[AML_HAL] audio device patch [not create]-----------\n"); return; } dprintf(fd, "\n-------------[AML_HAL] audio device patch [%p]---------------\n", pstPatch); dprintf(fd, "[AML_HAL] decoder_id : %d\n", pstPatch->decoder_id); if (pstPatch->aml_ringbuffer.size != 0) { int u32FreeBuffer = get_buffer_write_space(&pstPatch->aml_ringbuffer); dprintf(fd, "[AML_HAL] RingBuf size: %10d Byte| UnusedBuf:%10d Byte(%d%%)\n", pstPatch->aml_ringbuffer.size, u32FreeBuffer, u32FreeBuffer* 100 / pstPatch->aml_ringbuffer.size); } else { dprintf(fd, "[AML_HAL] patch RingBuf : buffer size is 0\n"); } if (pstPatch->audio_parse_para) { int s32AudioType = ((audio_type_parse_t*)pstPatch->audio_parse_para)->audio_type; dprintf(fd, "[AML_HAL] Hal audio Type: [0x%x]%-10s| Src Format:%#10x\n", s32AudioType, audio_type_convert_to_string(s32AudioType), pstPatch->aformat); } dprintf(fd, "[AML_HAL] patch_src : %s\n", patchSrc2Str(pstPatch->patch_src)); dprintf(fd, "[AML_HAL] stable : %d, need do avsync: %d\n", pstPatch->input_signal_stable, pstPatch->need_do_avsync); dprintf(fd, "[AML_HAL] IN_Device : %#10x | OUT_Device :%#10x\n", pstPatch->input_device, pstPatch->output_device); dprintf(fd, "[AML_HAL] IN_Format : %#10x | OUT_Format:%#10x\n", pstPatch->aformat, pstPatch->out_format); dprintf(fd, "[AML_HAL] pcm in sr : %10d | pcm out sr:%10d\n", pstPatch->in_sample_rate, pstPatch->out_sample_rate); dprintf(fd, "[AML_HAL] pcm in ch : %10d | pcm out ch :%10d\n", pstPatch->in_channel_count, pstPatch->out_channel_count); dprintf(fd, "[AML_HAL] earc mch pcm bypass: %10d | pcm sr before hw src:%10d\n", pstPatch->hdmi_earc_passthrough_mode, pstPatch->hdmi_sample_rate); } void audio_patch_list_dump(struct aml_audio_device* adev, int fd) { patch_manager *patch_mgr = adev->patch_manager; struct audio_patch_set *patch_set = NULL; struct listnode *node = NULL; int i = 0; dprintf(fd, "\n-------------[AML_HAL] audio patch info------------------\n"); //dprintf(fd, "AML Audio Patches:\n"); list_for_each(node, &patch_mgr->patch_list) { patch_set = node_to_item (node, struct audio_patch_set, list); if (patch_set) { dprintf(fd, "patch_set index: %d\n", i); audio_patch_dump(&patch_set->patch, fd); aml_device_patch_dump(patch_set->aml_patch, fd); } i++; } } //only apply hdmi in source int audio_patch_get_current_video_latency(struct aml_audio_device* adev) { struct aml_audio_patch *patch = NULL; struct audio_patch_set *patch_set = NULL; struct listnode *node = NULL; int v_ltcy = 0; /* find aml_patch in patch_set list */ list_for_each(node, &adev->patch_manager->patch_list) { patch_set = node_to_item(node, struct audio_patch_set, list); patch = (struct aml_audio_patch *)patch_set->aml_patch; if (patch && (SRC_HDMIIN == patch->patch_src || SRC_HDMIIN1 == patch->patch_src)) { v_ltcy = aml_dev_sample_video_path_latency(patch); break; } } AM_LOGI("patch(%p) v_ltcy(%d)", patch, v_ltcy); return v_ltcy; } //only apply hdmi in source int audio_patch_get_current_audio_latency(struct aml_audio_device* adev) { struct aml_audio_patch *patch = NULL; struct audio_patch_set *patch_set = NULL; struct listnode *node = NULL; int a_ltcy = 0; /* find aml_patch in patch_set list */ list_for_each(node, &adev->patch_manager->patch_list) { patch_set = node_to_item(node, struct audio_patch_set, list); patch = (struct aml_audio_patch *)patch_set->aml_patch; if (patch && (SRC_HDMIIN == patch->patch_src || SRC_HDMIIN1 == patch->patch_src)) { aml_dev_sample_audio_path_latency(patch, NULL); a_ltcy = patch->audio_latency.total_latency; } } AM_LOGI("patch(%p) a_ltcy(%d)", patch, a_ltcy); return a_ltcy; } int aml_dev_dump_latency(struct aml_audio_device *aml_dev, int fd) { dprintf(fd, "\n-------------[AML_HAL] audio patch Latency-----------------------\n"); struct aml_audio_patch *patch = NULL; struct audio_patch_set *patch_set = NULL; struct listnode *node = NULL; /* find aml_patch in patch_set list */ list_for_each(node, &aml_dev->patch_manager->patch_list) { patch_set = node_to_item(node, struct audio_patch_set, list); patch = (struct aml_audio_patch *)patch_set->aml_patch; if (patch) { aml_dev_sample_audio_path_latency(patch, NULL); dprintf(fd, "\n-------------[AML_HAL] patch_src=%s-----------------------\n", patchSrc2Str(patch->patch_src)); dprintf(fd, "[AML_HAL] audio patch latency : %6d ms\n", patch->audio_latency.ringbuffer_latency); dprintf(fd, "[AML_HAL] audio spk tuning latency : %6d ms\n", patch->audio_latency.user_tune_latency); dprintf(fd, "[AML_HAL] MS12 buffer latency : %6d ms\n", patch->audio_latency.ms12_latency); dprintf(fd, "[AML_HAL] Submix in latency : %6d ms\n", patch->audio_latency.submix_in_latency); dprintf(fd, "[AML_HAL] alsa out hw i2s latency : %6d ms\n", patch->audio_latency.alsa_i2s_out_latency); dprintf(fd, "[AML_HAL] alsa out hw spdif latency : %6d ms\n", patch->audio_latency.alsa_spdif_out_latency); dprintf(fd, "[AML_HAL] alsa in hw latency : %6d ms\n\n", patch->audio_latency.alsa_in_latency); dprintf(fd, "[AML_HAL] audio total latency :%6d ms\n", patch->audio_latency.total_latency); int v_ltcy = aml_dev_sample_video_path_latency(patch); int max_v_ltcy = aml_mixer_ctrl_get_int(&aml_dev->alsa_mixer, AML_MIXER_ID_TVIN_VIDEO_MAX_DELAY); int min_v_ltcy = aml_mixer_ctrl_get_int(&aml_dev->alsa_mixer, AML_MIXER_ID_TVIN_VIDEO_MIN_DELAY); int av_diff =patch->audio_latency.total_latency - v_ltcy; dprintf(fd, "[AML_HAL] video path total latency : %6d ms\n", v_ltcy); dprintf(fd, "[AML_HAL] Audio - Video : %6d ms\n", av_diff); dprintf(fd, "[AML_HAL] video path min latency : %6d ms\n", min_v_ltcy); dprintf(fd, "[AML_HAL] video path max latency : %6d ms\n", max_v_ltcy); picture_mode_t mode = get_dev_pic_mode(); dprintf(fd, "[AML_HAL] Device picture mode : %s \n", mode == PQ_GAME ? "Game Mode":"Standard Mode"); } } return 0; }