934 lines
31 KiB
C
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;
|
|
}
|
|
|