Files
2026-08-24 10:03:24 +08:00

934 lines
31 KiB
C

/*
* 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 <sys/types.h>
#include <sys/errno.h>
#include <pthread.h>
#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;
}