blob: 439145d26f67c9ac17d2ee34e771aa541dfdc43f [file] [log] [blame]
/*
* Copyright (C) 2018 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"
//#define LOG_NDEBUG 0
#include <cutils/atomic.h>
#include <cutils/log.h>
#include <cutils/properties.h>
#include <cutils/str_parms.h>
#include <errno.h>
#include <fcntl.h>
#include <hardware/hardware.h>
#include <inttypes.h>
#include <linux/ioctl.h>
#include <math.h>
#include <pthread.h>
#include <stdint.h>
#include <stdlib.h>
#include <sys/prctl.h>
#include <sys/stat.h>
#include <sys/time.h>
#include <sys/system_properties.h>
#include <system/audio.h>
#include <time.h>
#include <utils/Timers.h>
#include <sys/ioctl.h>
#if ANDROID_PLATFORM_SDK_VERSION >= 25 // 8.0
#include <system/audio-base.h>
#endif
#include <hardware/audio.h>
#include <aml_data_utils.h>
#include "aml_config_data.h"
#include "aml_audio_stream.h"
#include "dtv_patch.h"
#include "audio_hw_profile.h"
#include "audio_hw_utils.h"
//#include "dtv_patch_out.h"
#include "aml_audio_resampler.h"
#if defined(MS12_V24_ENABLE) || defined(MS12_V26_ENABLE)
#include "audio_hw_ms12_v2.h"
#endif
#include "alsa_config_parameters.h"
#include "alsa_device_parser.h"
#include "dtv_patch_hal_avsync.h"
#include "aml_audio_spdifout.h"
#include "aml_audio_timer.h"
#include "aml_volume_utils.h"
#include "dmx_audio_es.h"
#include "aml_ddp_dec_api.h"
#include "dtv_patch_utils.h"
#include "audio_hw_ms12_common.h"
#include "audio_hw_resource_mgr.h"
#include "tv_patch.h"
#include "dtv_private_object.h"
#include "aml_dump_debug.h"
#include "audio_mediasync.h"
#include "device_patch.h"
#define cmd_str(cmd) dtvAudioCmd2Str(cmd)
#define state_str(state) dtvAudioState2Str(state)
static int create_dtv_output_stream_thread(dtv_path_t *path);
static int create_dtv_ad_output_stream_thread(dtv_path_t *path);
static int release_dtv_output_stream_thread(dtv_path_t *path);
static int dtv_path_cmd_process_thread(void *data);
static void dmx_enable_main(aml_demux_audiopara_t *demux_info, bool enable)
{
if (enable) {
struct aml_audio_device *aml_dev = (struct aml_audio_device *)adev_get_handle();
if (!aml_dev) {
AM_LOGE("get adev error");
return;
}
demux_info->is_multi_dmx = is_dtv_multi_demux(aml_dev);
Open_Dmx_Audio(&demux_info->demux_handle, demux_info, dtv_queue_es_info, aml_audio_get_debug_flag());
Init_Dmx_Main_Audio(demux_info->demux_handle, demux_info->main_fmt, demux_info->main_pid);
Start_Dmx_Main_Audio(demux_info->demux_handle);
} else {
Stop_Dmx_Main_Audio(demux_info->demux_handle);
Destroy_Dmx_Main_Audio(demux_info->demux_handle);
if (demux_info->ad_dmx_init) {
Stop_Dmx_AD_Audio(demux_info->demux_handle);
Destroy_Dmx_AD_Audio(demux_info->demux_handle);
demux_info->ad_dmx_init = false;
}
Close_Dmx_Audio(demux_info->demux_handle);
}
}
static int dmx_enable_ad(aml_demux_audiopara_t *demux_info)
{
if (demux_info && demux_info->demux_handle && VALID_PID(demux_info->ad_pid)) {
if (demux_info->is_multi_dmx) {
if (aml_audio_property_get_bool("vendor.media.dtv.pesmode", true)) {
if (VALID_AD_FMT_UK(demux_info->ad_fmt)) {
Init_Dmx_AD_Audio(demux_info->demux_handle, demux_info->ad_fmt, demux_info->ad_pid, 1);
} else {
Init_Dmx_AD_Audio(demux_info->demux_handle, demux_info->ad_fmt, demux_info->ad_pid, 0);
}
} else {
Init_Dmx_AD_Audio(demux_info->demux_handle, demux_info->ad_fmt, demux_info->ad_pid, 0);
}
} else {
Init_Dmx_AD_Audio(demux_info->demux_handle, demux_info->ad_fmt, demux_info->ad_pid, 1);
}
demux_info->ad_dmx_init = true;
return Start_Dmx_AD_Audio(demux_info->demux_handle);
}
return -1;
}
static bool check_ad_enable(dtv_path_t * path)
{
aml_demux_audiopara_t *demux_info = &path->demux_info;
if (demux_info && VALID_PID(demux_info->ad_pid) && demux_info->associate_audio_mixing_enable) {
return true;
} else {
return false;
}
}
static int audio_dtv_ad_start_dynamic(dtv_path_t *path)
{
aml_demux_audiopara_t *demux_info = &path->demux_info;
int ad_start_flag = -1;
if (demux_info && demux_info->demux_handle && (false == demux_info->ad_dmx_init) && check_ad_enable(path)) {
ad_start_flag = dmx_enable_ad(demux_info);
/*coverity[ATOMICITY]: just ALOGI print*/
AM_LOGI("[] dmx_handle %p, ad_pid:%d, ad_start_flag %d", demux_info->demux_handle, demux_info->ad_pid, ad_start_flag);
}
if (AM_AUDIO_Dmx_SUCCESS == ad_start_flag && path->ad_output_thread_created == 0) {
create_dtv_ad_output_stream_thread(path);
}
}
static int audio_dtv_output_start(dtv_path_t *path)
{
if (path && path->demux_info.demux_handle) {
create_dtv_output_stream_thread(path);
audio_dtv_ad_start_dynamic(path);
}
}
static int audio_dtv_output_pause(dtv_path_t *path, int cmd)
{
if (path) {
struct aml_stream_out *aml_out = path->dtv_aml_out;
if (aml_out && aml_out->avsync_ctx && (AVSYNC_TYPE_MEDIASYNC == aml_out->avsync_type) && aml_out->avsync_ctx->mediasync_ctx) {
if (cmd == AUDIO_DTV_PATCH_CMD_PAUSE) {
mediasync_wrap_setPause(aml_out->avsync_ctx->mediasync_ctx->handle, true);
AM_LOGI("now end pause the audio decoder");
} else if (cmd == AUDIO_DTV_PATCH_CMD_RESUME) {
mediasync_wrap_setPause(aml_out->avsync_ctx->mediasync_ctx->handle, false);
AM_LOGI("now end resume the audio decoder");
}
return 0;
}
AM_LOGE("aml_out is %p", aml_out);
return -1;
}
AM_LOGE("path is %p", path);
return -1;
}
static int audio_dtv_output_stop(dtv_path_t *path)
{
struct aml_audio_device *aml_dev = (struct aml_audio_device *)adev_get_handle();
if (!aml_dev || !path) {
AM_LOGE("get adev(%p) or path(%p) error", aml_dev, path);
return -1;
}
/*coverity[sleep]*/
dtv_do_ease_out(aml_dev);
release_dtv_output_stream_thread(path);
dtv_check_audio_reset();
}
static int path_thread_get_cmd(struct dtv_path *path, int *cmd, int *path_id)
{
if (path == NULL || path->dtv_cmd_list->initd == 0) {
return -1;
}
if (dtv_cmdlist_is_empty(path->dtv_cmd_list) == 1) {
return -1;
} else {
return dtv_cmdlist_get_cmd(path->dtv_cmd_list, cmd, path_id);
}
}
int dtv_patch_handle_event(struct audio_hw_device *dev,int cmd, int val) {
struct aml_audio_device *adev = (struct aml_audio_device *) dev;
struct aml_audio_patch *patch = get_dev_patch(adev);
struct dolby_ms12_desc *ms12 = &(adev->ms12);
float dtv_volume_switch = 1.0;
unsigned int path_id = val >> DVB_DEMUX_ID_BASE;
if (NULL == patch) {
AM_LOGE("patch NULL error, need create patch first!!");
goto exit;
}
if (path_id >= DVB_DEMUX_SUPPORT_MAX_NUM) {
AM_LOGW("path_id %d is invalid !",path_id);
goto exit;
}
dtv_path_t *path = &patch->dtv_path[path_id];
aml_demux_audiopara_t *demux_info = &path->demux_info;
void *demux_handle = demux_info->demux_handle;
val = val & ((1 << DVB_DEMUX_ID_BASE) - 1);
AM_LOGI("patch %p, path %p, path_id %d, cmd %d(%s), val %d", patch,path, path_id, cmd, cmd_str(cmd), val);
switch (cmd) {
case AUDIO_DTV_PATCH_CMD_SET_MEDIA_SYNC_ID:
demux_info->media_sync_id = val;
AM_LOGI("demux_info->media_sync_id %d", demux_info->media_sync_id);
break;
case AUDIO_DTV_PATCH_CMD_SET_OUTPUT_MODE:
AM_LOGI("DTV sound mode %d ", val);
adev->sound_track_mode = val;
break;
case AUDIO_DTV_PATCH_CMD_SET_MUTE:
AM_LOGE ("TV-Mute:%d.", val);
// adev->tv_mute = val;
adev->decoder_mute = val;
adev_update_decoder_mute_state(dev);
break;
case AUDIO_DTV_PATCH_CMD_SET_VOLUME:
dtv_volume_switch = (float)val / 100; // val range is [0, 100], conversion range is [0, 1]
if (get_dtv_volume(adev) != dtv_volume_switch && dtv_volume_switch >= 0.0f && dtv_volume_switch <= 1.0f) {
set_dtv_volume(adev, dtv_volume_switch);
AM_LOGI ("dtv set volume:%f(%f)", get_dtv_volume(adev), dtv_volume_switch);
if (path->dtv_aml_out) {
struct audio_stream_out *stream_out = (struct audio_stream_out *)path->dtv_aml_out;
stream_out->set_volume(stream_out, dtv_volume_switch, dtv_volume_switch);
}
} else {
AM_LOGE("dtv set volume error! volume:%f", dtv_volume_switch);
}
break;
case AUDIO_DTV_PATCH_CMD_SET_HAS_VIDEO:
demux_info->has_video = val;
AM_LOGI("has_video %d",demux_info->has_video);
break;
case AUDIO_DTV_PATCH_CMD_SET_DEMUX_INFO:
demux_info->demux_id = val;
AM_LOGI("demux_id %d",demux_info->demux_id);
break;
case AUDIO_DTV_PATCH_CMD_SET_SECURITY_MEM_LEVEL:
demux_info->security_mem_level = val;
AM_LOGI("security_mem_level set to %d", demux_info->security_mem_level);
break;
case AUDIO_DTV_PATCH_CMD_SET_PID:
demux_info->main_pid = val;
AM_LOGI("main_pid %d(0x%x)",demux_info->main_pid, val);
break;
case AUDIO_DTV_PATCH_CMD_SET_FMT:
demux_info->main_fmt = val;
AM_LOGI("main_fmt %d",demux_info->main_fmt);
break;
case AUDIO_DTV_PATCH_CMD_SET_AD_FMT:
demux_info->ad_fmt = val;
AM_LOGI("ad_fmt %d",demux_info->ad_fmt);
break;
case AUDIO_DTV_PATCH_CMD_SET_AD_PID:
demux_info->ad_pid = val;
AM_LOGI("ad_pid %d(0x%x)",demux_info->ad_pid, val);
break;
case AUDIO_DTV_PATCH_CMD_SET_AD_ENABLE:
demux_info->associate_audio_mixing_enable = val;
AM_LOGI("associate_audio_mixing_enable set to %d", demux_info->associate_audio_mixing_enable);
pthread_mutex_lock(&path->dtv_cmd_process_mutex);
dtv_cmdlist_add_cmd(path->dtv_cmd_list, AUDIO_DTV_PATCH_CMD_SET_AD_ENABLE, path_id);
pthread_cond_signal(&path->dtv_cmd_process_cond);
pthread_mutex_unlock(&path->dtv_cmd_process_mutex);
break;
case AUDIO_DTV_PATCH_CMD_SET_AD_VOL_LEVEL:
if (val < 0) {
/* coverity[deadcode]:this is just error checking and should not be executed here */
val = 0;
} else if (val > 100) {
val = 100;
}
demux_info->advol_level = val;
AM_LOGI("advol set to %d", demux_info->advol_level);
break;
case AUDIO_DTV_PATCH_CMD_SET_AD_MIX_LEVEL:
if (val < 0) {
/* coverity[deadcode]:this is just error checking and should not be executed here */
val = 0;
} else if (val > 100) {
val = 100;
}
demux_info->mixing_level = (val * 64 - 32 * 100) / 100; //[0,100] mapping to [-32,32]
AM_LOGI("mixing_level set to %d", demux_info->mixing_level);
if (path->dtv_aml_out) {
set_ms12_ad_mixing_level((struct audio_stream_out *)path->dtv_aml_out, demux_info->mixing_level);
}
break;
case AUDIO_DTV_PATCH_CMD_SET_MEDIA_PRESENTATION_ID:
demux_info->media_presentation_id = val;
AM_LOGI("media_presentation_id %d", demux_info->media_presentation_id);
if (path->dtv_aml_out) {
set_ms12_ac4_presentation_group_index((struct audio_stream_out *)path->dtv_aml_out, demux_info->media_presentation_id);
}
break;
case AUDIO_DTV_PATCH_CMD_SET_MEDIA_FIRST_LANG:
demux_info->media_first_lang = val;
char first_lang[4] = {0};
language_code_convert_to_string(demux_info->media_first_lang, first_lang);
AM_LOGI("media_first_lang %s,%x,%d",first_lang,val,val);
if (path->dtv_aml_out) {
set_ms12_ac4_1st_preferred_language_code((struct audio_stream_out *)path->dtv_aml_out, first_lang);
}
break;
case AUDIO_DTV_PATCH_CMD_SET_MEDIA_SECOND_LANG:
demux_info->media_second_lang = val;
char second_lang[4] = {0};
language_code_convert_to_string(demux_info->media_second_lang, second_lang);
AM_LOGI("media_second_lang %s,%x,%d",second_lang, val, val);
if (path->dtv_aml_out) {
set_ms12_ac4_2nd_preferred_language_code((struct audio_stream_out *)path->dtv_aml_out, second_lang);
}
break;
case AUDIO_DTV_PATCH_CMD_CONTROL:
if (val <= AUDIO_DTV_PATCH_CMD_NULL || val > AUDIO_DTV_PATCH_CMD_NUM) {
AM_LOGW("Unsupported dtv cmd:%d", val);
break;
}
AM_LOGI("Send dtv path(%d) cmd:%s, cmd_process create %d", path_id, cmd_str(val), path->cmd_process_thread_created);
if (val == AUDIO_DTV_PATCH_CMD_OPEN) {
if (!path->cmd_process_thread_created) {
path->cmd_process_thread_exit = 0;
int ret = pthread_create(&(path->audio_cmd_process_threadID), NULL,
(void *)dtv_path_cmd_process_thread, path);
if (ret != 0) {
AM_LOGE("Create process thread fail!");
goto exit;
}
path->cmd_process_thread_created = 1;
} else {
AM_LOGW("cmd_process already create %d!", path->cmd_process_thread_created);
}
}
if (path->cmd_process_thread_created) {
pthread_mutex_lock(&path->dtv_cmd_process_mutex);
dtv_cmdlist_add_cmd(path->dtv_cmd_list, val, path_id);
pthread_cond_signal(&path->dtv_cmd_process_cond);
pthread_mutex_unlock(&path->dtv_cmd_process_mutex);
} else {
AM_LOGW("no cmd_process thread %d, exit %d!", path->cmd_process_thread_created, path->cmd_process_thread_exit);
}
if (val == AUDIO_DTV_PATCH_CMD_CLOSE && path->cmd_process_thread_created) {
pthread_join(path->audio_cmd_process_threadID, NULL);
path->cmd_process_thread_created = 0;
}
break;
default:
AM_LOGI("invalid cmd %d", cmd);
}
return 0;
exit:
AM_LOGI("failed ");
return -1;
}
static void *audio_dtv_path_output_threadloop(void *data)
{
//0.prepare variable
dtv_path_t *path = (dtv_path_t *)data;
struct aml_audio_device *aml_dev = (struct aml_audio_device *)adev_get_handle();
if (!aml_dev || !path) {
AM_LOGE("get adev(%p) or path(%p) error", aml_dev, path);
goto exit_open;
}
struct audio_stream_out *stream_out = NULL;
struct aml_stream_out *aml_out = NULL;
struct audio_config stream_config;
int ret = -1, nRet = 0, sync_enable = 0;
struct mAudioEsDataInfo *mEsData = NULL;
aml_demux_audiopara_t *demux_info = (aml_demux_audiopara_t *)(&path->demux_info);
void *demux_handle = demux_info->demux_handle;
char thread_name[128] = { 0 };
//set name for this thread
snprintf(thread_name, 128, "dtv_output_data_%d", demux_info->main_pid);
prctl(PR_SET_NAME, (unsigned long)thread_name);
AM_LOGI("created. path %p, path_id %d, pid %d(0x%x), demux_handle %p, demux_info %p, thread id:%ld", path,
path->path_id, demux_info->main_pid, demux_info->main_pid, demux_handle, demux_info, pthread_self());
//1.prepare a output stream
stream_config.sample_rate = 48000;
stream_config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
stream_config.format = dmx_fmt_convert2_hal_fmt(demux_info->main_fmt);
if (aml_dev->hw_device.open_output_stream) {
ret = aml_dev->hw_device.open_output_stream((struct audio_hw_device *)aml_dev, 0,
AUDIO_DEVICE_OUT_SPEAKER, // devices_t
AUDIO_OUTPUT_FLAG_DIRECT | AUDIO_OUTPUT_FLAG_HW_AV_SYNC, // flags
&stream_config, &stream_out, "AML_DTV_SOURCE");
}
if (ret < 0 || !stream_out) {
AM_LOGE("open output stream fail, ret = %d, out = %p. open func: %p", ret, stream_out, aml_dev->hw_device.open_output_stream);
goto exit_open;
}
aml_out = (struct aml_stream_out *)stream_out;
path->dtv_aml_out = aml_out;
//init decoder-related param, they would be used when config dec later
aml_out->dec_param.ad_mix_enable = demux_info->associate_audio_mixing_enable;
aml_out->dec_param.advol_level = demux_info->advol_level;
aml_out->dec_param.mixing_level = demux_info->mixing_level;
if (aml_out->hal_format == AUDIO_FORMAT_AC4) {
aml_out->dec_param.ac4_presentation_id = demux_info->media_presentation_id;
language_code_convert_to_string(demux_info->media_first_lang, aml_out->dec_param.ac4_1st_lang);
language_code_convert_to_string(demux_info->media_second_lang, aml_out->dec_param.ac4_2nd_lang);
}
//init mediasync for this output stream
if (aml_out->avsync_ctx) {
aml_out->avsync_type = AVSYNC_TYPE_MEDIASYNC;
hwsync_mediasync_outset(aml_out, &sync_enable, demux_info->media_sync_id, demux_info->main_fmt);
if (NULL == aml_out->avsync_ctx->mediasync_ctx || NULL == aml_out->avsync_ctx->mediasync_ctx->handle) {
goto exit_sync;
}
} else {
AM_LOGE("aml_out->avsync_ctx NULL error!");
goto exit_sync;
}
AM_LOGI("create output stream(%p) success, thread_exit %d. sync_enable %d.avsync ctx %p, mediasync ctx %p, handle %p",
aml_out, path->output_thread_exit, sync_enable, aml_out->avsync_ctx, aml_out->avsync_ctx->mediasync_ctx, aml_out->avsync_ctx->mediasync_ctx->handle);
while (!path->output_thread_exit) {
if (path->dtv_decoder_state == AUDIO_DTV_PATCH_DECODER_STATE_PAUSE) {
usleep(1000);
continue;
}
//get data from es queue
nRet = Get_MainAudio_Es(demux_handle, &mEsData);
if (nRet != AM_AUDIO_Dmx_SUCCESS || !mEsData) {
AM_LOGI_IF(aml_dev->debug_flag, "nRet %d, mEsData %p", nRet, mEsData);
if (mEsData) {
path->pts_dts_flag = mEsData->pts_dts_flag;
}
usleep(5000);
goto free_data;
} else {
AM_LOGI_IF(aml_dev->debug_flag, "%p, main size %d, pts %"PRIx64"(%"PRIx64"), diff %"PRId64"ms, pts flag %d", mEsData, mEsData->size, mEsData->pts, path->last_valid_main_pts, (mEsData->pts - path->last_valid_main_pts)/90, mEsData->pts_dts_flag);
path->pts_dts_flag = mEsData->pts_dts_flag;
// if first package pts is invalid, we need drop it
if ((!path->dtv_first_apts_flag) && (NULL_INT64 == mEsData->pts)) {
AM_LOGE("first data pts is NULL_INT64");
goto free_data;
}
if ((!mEsData->data || !mEsData->size)) {
AM_LOGE("current data invalid");
goto free_data;
}
path->dtv_first_apts_flag = 1;
if (NULL_INT64 != mEsData->pts) {
path->last_valid_main_pts = mEsData->pts;
pthread_mutex_lock(&path->apts_cal_mutex);
pthread_cond_signal(&path->apts_cond);
pthread_mutex_unlock(&path->apts_cal_mutex);
} else {
mEsData->pts = path->last_valid_main_pts;
}
if (get_debug_value(AML_DUMP_AUDIOHAL_DTV)) {
aml_dump_audio_bitstreams("dtv_main_audio_dmx.es", mEsData->data, mEsData->size);
}
}
//apply pts
if ((aml_out->avsync_ctx) && (aml_out->avsync_ctx->mediasync_ctx)) {
pthread_mutex_lock(&(aml_out->avsync_ctx->lock));
aml_out->avsync_ctx->mediasync_ctx->in_apts = mEsData->pts;
pthread_mutex_unlock(&(aml_out->avsync_ctx->lock));
}
if (!aml_out->aml_dec && aml_out->hal_format == AUDIO_FORMAT_E_AC3 && aml_dev->dolby_lib_type == eDolbyDcvLib) {
aml_out->ad_substream_supported = is_ad_substream_supported((unsigned char *)mEsData->data, mEsData->size);
}
//decode data
ret = stream_out->write(stream_out, mEsData->data, mEsData->size);
if (ret < 0) {
AM_LOGE("stream_out->write ret %d, need check!!", ret);
}
if (aml_out->parser_frame_size) {
Set_Audio_ES_Frame_Size(demux_handle, aml_out->parser_frame_size);
}
free_data:
dtv_es_data_free(mEsData);
mEsData = NULL;
}
exit_sync:
AM_LOGI("path(%d) exit %d", path->path_id, path->output_thread_exit);
pthread_mutex_lock(&path->dtv_path_lock);
if (aml_out && aml_dev->hw_device.close_output_stream) {
aml_dev->hw_device.close_output_stream((struct audio_hw_device *)aml_dev, stream_out);
}
path->dtv_aml_out = NULL;
pthread_mutex_unlock(&path->dtv_path_lock);//as es read thread would also use out, so use lock.
exit_open:
AM_LOGI("--");
return ((void *)0);
}
#define QUEUE_AD_DATA_WHEN_START 1
static void *audio_dtv_path_ad_output_threadloop(void *data)
{
//0.prepare variable
dtv_path_t *path = (dtv_path_t *)data;
struct aml_audio_device *aml_dev = (struct aml_audio_device *)adev_get_handle();
if (!aml_dev || !path) {
AM_LOGE("get adev(%p) or path(%p) error", aml_dev, path);
goto exit_open;
}
struct audio_stream_out *ad_stream_out = NULL;
struct aml_stream_out *ad_aml_out = NULL;
struct aml_stream_out *main_aml_out = path->dtv_aml_out;
struct mAudioEsDataInfo *mAdEsData = NULL;
struct audio_config stream_config;
int ret = -1, ret_ad = 0, main_size_in_queue = 0, ad_size_in_queue = 0;
int associate_audio_mixing_enable = -1, mixing_level = 0, advol_level = 100;
struct timespec ts, watch_start_ts;
bool watch_flag = false, need_hold_data = false;
aml_demux_audiopara_t *demux_info = (aml_demux_audiopara_t *)(&path->demux_info);
void *demux_handle = demux_info->demux_handle;
char thread_name[32] = { 0 };
//set name for this thread
snprintf(thread_name, 32, "dtv_ad_output_data_%d", demux_info->ad_pid);
prctl(PR_SET_NAME, (unsigned long)thread_name);
AM_LOGI("created. pid %d, demux_handle %p, demux_info %p, thread id:%lu", demux_info->ad_pid, demux_handle, demux_info, pthread_self());
//1.prepare a output stream
stream_config.sample_rate = 48000;
stream_config.channel_mask = AUDIO_CHANNEL_OUT_STEREO;
stream_config.format = dmx_fmt_convert2_hal_fmt(demux_info->ad_fmt);
if (aml_dev->hw_device.open_output_stream) {
ret = aml_dev->hw_device.open_output_stream((struct audio_hw_device *)aml_dev, 0,
AUDIO_DEVICE_OUT_SPEAKER, // devices_t
AUDIO_OUTPUT_FLAG_DIRECT + AUDIO_OUTPUT_FLAG_AD_STREAM, // flags
&stream_config, &ad_stream_out, "AML_DTV_SOURCE");
}
if (ret < 0 || !ad_stream_out) {
AM_LOGE("live open ad output stream fail, ret = %d. open func: %p", ret, aml_dev->hw_device.open_output_stream);
goto exit_open;
}
ad_aml_out = (struct aml_stream_out *)ad_stream_out;
path->dtv_ad_aml_out = ad_aml_out;
AM_LOGI("create a AD output stream(%p) success now, ad_output_thread_exit %d. main stream %p", ad_aml_out, path->ad_output_thread_exit, main_aml_out);
while (!path->ad_output_thread_exit) {
main_aml_out = (struct aml_stream_out *)path->dtv_aml_out;
if (path->dtv_decoder_state == AUDIO_DTV_PATCH_DECODER_STATE_PAUSE || !main_aml_out ||
(aml_dev->dolby_lib_type == eDolbyMS12Lib && main_aml_out && !main_aml_out->ms12_dec_handle)) {
usleep(20000);
continue;
}
if (aml_dev->dolby_lib_type == eDolbyMS12Lib) {
ad_aml_out->ms12_dec_handle = main_aml_out->ms12_dec_handle;
}
#if QUEUE_AD_DATA_WHEN_START
/* as for DD_Disappearing-AA_ddp_DVB_h264_29fps.trp: first 10s has ad, medium 10s has no ad data, then last 10s has ad again.
from no_ad to has_ad, need to use start threshold to queue some data, to make sure ad has data continuously with main in mixer process*/
if (Get_Audio_AD_ES_Queue_Size(demux_handle, &ad_size_in_queue) == AM_AUDIO_Dmx_SUCCESS
&& ad_size_in_queue == 0 && !watch_flag) {//1.save the ts when there's no ad data.
clock_gettime(CLOCK_MONOTONIC, &watch_start_ts);
watch_flag = true;
}
Get_Audio_Main_ES_Queue_Size(demux_handle, &main_size_in_queue);
AM_LOGI_IF(aml_dev->debug_flag, "ad_num %d, main_num %d, watch_flag %d", ad_size_in_queue, main_size_in_queue, watch_flag);
if (watch_flag && ad_size_in_queue != 0) {
struct timespec cur_ts;
clock_gettime(CLOCK_MONOTONIC, &cur_ts);
int has_data_cost_ms = calc_time_interval_us(&watch_start_ts, &cur_ts) / 1000;
if (has_data_cost_ms > 1000) {//2.if the period time from no_data to has_data > 1s, need queue
need_hold_data = true;
}
watch_flag = false;
}
AM_LOGI_IF(aml_dev->debug_flag, "ad_num %d, main_num %d, watch_flag %d, need_hold_data %d", ad_size_in_queue, main_size_in_queue, watch_flag, need_hold_data);
//start threshold to make ad has enough data, avoid no ad when mix main data in ms12.
#define AD_START_THRESHOLD 2
if (ad_size_in_queue > AD_START_THRESHOLD && need_hold_data) {
need_hold_data = false;
} else if (need_hold_data) {
usleep(10000);
continue;
}
#endif
if (associate_audio_mixing_enable != demux_info->associate_audio_mixing_enable
|| advol_level != demux_info->advol_level
|| mixing_level != demux_info->mixing_level) {
associate_audio_mixing_enable = demux_info->associate_audio_mixing_enable;
advol_level = demux_info->advol_level;
mixing_level = demux_info->mixing_level;
if (eDolbyMS12Lib == aml_dev->dolby_lib_type) {
set_ms12_ad_mixing_enable(ad_stream_out, associate_audio_mixing_enable);
set_ms12_ad_mixing_level(ad_stream_out, mixing_level);
set_ms12_ad_vol(ad_stream_out, advol_level);
AM_LOGI("associate_audio_mixing_enable:%d, advol_level:%d, mixing_level:%d",
associate_audio_mixing_enable, advol_level, mixing_level);
}
if (false == associate_audio_mixing_enable) {
usleep(20000);
continue;
}
}
if (mAdEsData == NULL) {
ret_ad = Get_ADAudio_Es(demux_handle, &mAdEsData);
if (ret_ad != AM_AUDIO_Dmx_SUCCESS || !mAdEsData) {
AM_LOGE("Get_ADAudio_Es failed, ret %d, mAdEsData %p", ret_ad, mAdEsData);
usleep(10000);
goto free_data;
} else {
AM_LOGI_IF(aml_dev->debug_flag, "ad size %d pts %"PRIx64"(%"PRIx64"), diff %"PRId64"ms. ms12_dec %p", mAdEsData->size, mAdEsData->pts, path->last_valid_ad_pts, (mAdEsData->pts-path->last_valid_ad_pts)/90, ad_aml_out->ms12_dec_handle);
if (!mAdEsData->data || !mAdEsData->size) {
AM_LOGE("current data invalid");
goto free_data;
}
if (NULL_INT64 != mAdEsData->pts) {
path->last_valid_ad_pts = mAdEsData->pts;
} else {
mAdEsData->pts = path->last_valid_ad_pts;
}
if (get_debug_value(AML_DUMP_AUDIOHAL_DTV)) {
aml_dump_audio_bitstreams("dtv_ad_audio_dmx.es", mAdEsData->data, mAdEsData->size);
}
}
}
/* align ad and main data by pts compare */
pthread_mutex_lock(&path->apts_cal_mutex);
demux_info->ad_package_status = check_ad_package_status(path->last_valid_main_pts, mAdEsData->pts, demux_info);
if (demux_info->ad_package_status == AD_PACK_STATUS_DROP) {
pthread_mutex_unlock(&path->apts_cal_mutex);
AM_LOGI("drop ad data");
goto free_data;
} else if (demux_info->ad_package_status == AD_PACK_STATUS_HOLD) {
ts_wait_time(&ts, 100000);
ret = pthread_cond_timedwait(&path->apts_cond, &path->apts_cal_mutex, &ts);
pthread_mutex_unlock(&path->apts_cal_mutex);
if (path->ad_output_thread_exit) {
goto free_data;
}
continue;
}
pthread_mutex_unlock(&path->apts_cal_mutex);
struct audio_buffer abuffer_out = {0};
abuffer_out.buffer = mAdEsData->data;
abuffer_out.size = mAdEsData->size;
abuffer_out.pts = mAdEsData->pts;
ret_ad = ad_aml_out->write(ad_stream_out, &abuffer_out);
AM_LOGI_IF((aml_dev->debug_flag > 1), "fade %d, pan %d, mixing_level %d, advol %d, ret_ad %d",
mAdEsData->adfade, mAdEsData->adpan, demux_info->mixing_level, demux_info->advol_level, ret_ad);
if (eDolbyMS12Lib == aml_dev->dolby_lib_type &&
(ad_aml_out->hal_internal_format == AUDIO_FORMAT_HE_AAC_V1 || ad_aml_out->hal_internal_format == AUDIO_FORMAT_HE_AAC_V2)) {
struct dolby_ms12_desc *ms12 = &(aml_dev->ms12);
set_ms12_fade_pan(ad_stream_out, mAdEsData->adfade /* fade byte*/
, 0 /*gain_byte_center*/, 0 /*gain_byte_front */
, 0 /*gain_byte_surround*/, mAdEsData->adpan /*pan byte*/);
}
free_data:
dtv_es_data_free(mAdEsData);
mAdEsData = NULL;
}
AM_LOGI("path(%d) exit %d", path->path_id, path->ad_output_thread_exit);
if (ad_aml_out && aml_dev->hw_device.close_output_stream) {
aml_dev->hw_device.close_output_stream((struct audio_hw_device *)aml_dev, ad_stream_out);
path->dtv_ad_aml_out = NULL;
}
dtv_es_data_free(mAdEsData);
exit_open:
AM_LOGI("--");
return ((void *)0);
}
static int dtv_path_cmd_process_thread(void *data)
{
dtv_path_t *path = (dtv_path_t *)data;
struct aml_audio_device *aml_dev = (struct aml_audio_device *)adev_get_handle();
if (!aml_dev || !path) {
AM_LOGE("get adev(%p) or path(%p) error", aml_dev, path);
return -1;
}
aml_demux_audiopara_t *demux_info = &path->demux_info;
int cmd = AUDIO_DTV_PATCH_CMD_NUM, path_id = 0, cur_path_id = path->path_id;
path->dtv_decoder_state = AUDIO_DTV_PATCH_DECODER_STATE_NULL;
AM_LOGI("++ Enter, path(%p) id %d initial state: %s", path, cur_path_id, state_str(path->dtv_decoder_state));
prctl(PR_SET_NAME, (unsigned long)"dtv_process_thread");
while (!path->cmd_process_thread_exit ) {
pthread_mutex_lock(&path->dtv_cmd_process_mutex);
if (path_thread_get_cmd(path, &cmd, &path_id) != 0) {
pthread_cond_wait(&path->dtv_cmd_process_cond, &path->dtv_cmd_process_mutex);
pthread_mutex_unlock(&path->dtv_cmd_process_mutex);
continue;
}
switch (path->dtv_decoder_state) {
case AUDIO_DTV_PATCH_DECODER_STATE_NULL: {
if (cmd == AUDIO_DTV_PATCH_CMD_OPEN) {
path->dtv_decoder_state = AUDIO_DTV_PATCH_DECODER_STATE_INIT;/*** null to init ***/
AM_LOGI("[cmd_path %d, cur path %d] dmx_hanle %p, dmx_info %p. %s : %s", path_id, cur_path_id, demux_info->demux_handle, demux_info, cmd_str(cmd), state_str(path->dtv_decoder_state));
demux_info->priv_data = path;
dmx_enable_main(demux_info, true);
} else {
AM_LOGW("[cmd_path %d, cur path %d] state %s, unsupport cmd %s !", path_id, cur_path_id, state_str(path->dtv_decoder_state), cmd_str(cmd));
}
}
break;
case AUDIO_DTV_PATCH_DECODER_STATE_INIT:
if (cmd == AUDIO_DTV_PATCH_CMD_START) {
path->dtv_decoder_state = AUDIO_DTV_PATCH_DECODER_STATE_RUNNING;/*** init to running ***/
AM_LOGI("[cmd_path %d, cur path %d]dmx_handle:%p, %s : %s", path_id, cur_path_id, demux_info->demux_handle, cmd_str(cmd), state_str(path->dtv_decoder_state));
audio_dtv_output_start(path);
} else if (cmd == AUDIO_DTV_PATCH_CMD_CLOSE) {
path->dtv_decoder_state = AUDIO_DTV_PATCH_DECODER_STATE_NULL;/*** init to null ***/
AM_LOGI("[cmd_path %d, cur path %d] handle %p, dmx_info %p. %s : %s",
path_id, cur_path_id, demux_info->demux_handle, demux_info, cmd_str(cmd), state_str(path->dtv_decoder_state));
dmx_enable_main(demux_info, false);
dmx_info_clean(demux_info);
path->cmd_process_thread_exit = 1;
} else {
AM_LOGW("[cmd_path %d, cur path %d] state %s, unsupport cmd %s !", path_id, cur_path_id, state_str(path->dtv_decoder_state), cmd_str(cmd));
}
break;
case AUDIO_DTV_PATCH_DECODER_STATE_RUNNING:
if (cmd == AUDIO_DTV_PATCH_CMD_PAUSE) {
path->dtv_decoder_state = AUDIO_DTV_PATCH_DECODER_STATE_PAUSE;/*** running to pause ***/
AM_LOGI("[cmd_path %d, cur path %d] aml_out %p. %s : %s", path_id, cur_path_id, path->dtv_aml_out, cmd_str(cmd), state_str(path->dtv_decoder_state));
audio_dtv_output_pause(path, cmd);
} else if (cmd == AUDIO_DTV_PATCH_CMD_STOP) {
path->dtv_decoder_state = AUDIO_DTV_PATCH_DECODER_STATE_INIT;/*** running to init ***/
AM_LOGI("[cmd_path %d, cur path %d] %s : %s", path_id, cur_path_id, cmd_str(cmd), state_str(path->dtv_decoder_state));
audio_dtv_output_stop(path);
} else if (cmd == AUDIO_DTV_PATCH_CMD_SET_AD_ENABLE) {
AM_LOGI("[cmd_path %d, cur path %d] %s : %s", path_id, cur_path_id, cmd_str(cmd), state_str(path->dtv_decoder_state));
audio_dtv_ad_start_dynamic(path);
} else {
AM_LOGW("[cmd_path %d, cur path %d] state %s, unsupport cmd %s !", path_id, cur_path_id, state_str(path->dtv_decoder_state), cmd_str(cmd));
}
break;
case AUDIO_DTV_PATCH_DECODER_STATE_PAUSE:
if (cmd == AUDIO_DTV_PATCH_CMD_RESUME) {
path->dtv_decoder_state = AUDIO_DTV_PATCH_DECODER_STATE_RUNNING;/*** pause to running ***/
AM_LOGI("[cmd_path %d, cur path %d] aml_out %p. %s : %s", path_id, cur_path_id, path->dtv_aml_out, cmd_str(cmd), state_str(path->dtv_decoder_state));
audio_dtv_output_pause(path, cmd);
} else if (cmd == AUDIO_DTV_PATCH_CMD_STOP) {
path->dtv_decoder_state = AUDIO_DTV_PATCH_DECODER_STATE_INIT;/*** pause to init ***/
AM_LOGI("[cmd_path %d, cur path %d] %s : %s", path_id, cur_path_id, cmd_str(cmd), state_str(path->dtv_decoder_state));
audio_dtv_output_stop(path);
} else {
AM_LOGW("[cmd_path %d, cur path %d] state %s, unsupport cmd %s !", path_id, cur_path_id, state_str(path->dtv_decoder_state), cmd_str(cmd));
}
break;
default:
AM_LOGW("[cmd_path %d, cur path %d] state %s", path_id, cur_path_id, state_str(path->dtv_decoder_state));
break;
}
pthread_mutex_unlock(&path->dtv_cmd_process_mutex);
}
release_dtv_output_stream_thread(path);
dtv_check_audio_reset();
AM_LOGI("-- Exit, path(%p) id %d final state: %s", path, cur_path_id, state_str(path->dtv_decoder_state));
pthread_exit(NULL);
}
static int create_dtv_ad_output_stream_thread(dtv_path_t *path)
{
int ret = 0;
AM_LOGI("++ path(%d) %p, ad created:%u", path->path_id, path, path->ad_output_thread_created);
if (path->ad_output_thread_created == 0) {
path->ad_output_thread_exit = 0;
ret = pthread_create(&(path->audio_ad_output_threadID), NULL,
audio_dtv_path_ad_output_threadloop, path);
if (ret != 0) {
AM_LOGE("Create ad output thread fail!\n");
return -1;
}
path->ad_output_thread_created = 1;
}
AM_LOGI("--, threadID %ld", path->audio_ad_output_threadID);
return 0;
}
static int create_dtv_output_stream_thread(dtv_path_t *path)
{
int ret = 0;
AM_LOGI("++ path(%d) %p, main created:%u", path->path_id, path, path->output_thread_created);
if (path->output_thread_created == 0) {
path->output_thread_exit = 0;
ret = pthread_create(&(path->audio_output_threadID), NULL,
audio_dtv_path_output_threadloop, path);
if (ret != 0) {
AM_LOGE("Create main output thread fail!\n");
return -1;
}
path->output_thread_created = 1;
}
AM_LOGI("--, threadID %ld", path->audio_output_threadID);
return 0;
}
static int release_dtv_output_stream_thread(dtv_path_t *path)
{
int ret = 0;
AM_LOGI("++ path(%d) %p, main:%u, ad:%u\n", path->path_id, path, path->output_thread_created, path->ad_output_thread_created);
if (path->dtv_aml_out) {
path->dtv_aml_out->fast_quit = true;
AM_LOGI("aml_out:%p, set fast_quit:%d", path->dtv_aml_out, path->dtv_aml_out->fast_quit);
}
if (path->dtv_ad_aml_out) {
path->dtv_ad_aml_out->fast_quit = true;
AM_LOGI("aml_ad_out:%p, set fast_quit:%d", path->dtv_ad_aml_out, path->dtv_ad_aml_out->fast_quit);
}
if (path->ad_output_thread_created == 1) {
path->ad_output_thread_exit = 1;
pthread_cond_signal(&path->apts_cond);
pthread_join(path->audio_ad_output_threadID, NULL);
path->ad_output_thread_created = 0;
}
if (path->output_thread_created == 1) {
path->output_thread_exit = 1;
pthread_join(path->audio_output_threadID, NULL);
path->output_thread_created = 0;
}
AM_LOGI("--");
return 0;
}
static int create_dtv_patch_l(struct audio_hw_device *dev, audio_devices_t input,
audio_devices_t output __unused)
{
struct aml_audio_patch *patch;
struct aml_audio_device *aml_dev = (struct aml_audio_device *)dev;
int ret = 0;
if (get_dev_patch(aml_dev)) {
AM_LOGD("patch exists, first release it");
if (get_dev_patch(aml_dev)->is_dtv_src) {
return ret;
//release_dtv_patch_l(aml_dev);
} else {
release_patch_l(aml_dev);
}
}
patch = aml_audio_calloc(1, sizeof(*patch));
if (!patch) {
ret = -1;
goto err;
}
memset(patch, 0, sizeof(*patch));
// save dev to patch
patch->dev = dev;
patch->input_src = input;
patch->is_dtv_src = true;
for (int i = 0; i < DVB_DEMUX_SUPPORT_MAX_NUM; i++) {
patch->dtv_path[i].dtv_cmd_list = aml_audio_calloc(1, sizeof(struct cmd_node));
if (!patch->dtv_path[i].dtv_cmd_list) {
ret = -1;
goto err;
}
init_cmd_list(patch->dtv_path[i].dtv_cmd_list);
dmx_info_clean(&(patch->dtv_path[i].demux_info));
patch->dtv_path[i].path_id = i;
pthread_cond_init(&patch->dtv_path[i].apts_cond, NULL);
pthread_cond_init(&patch->dtv_path[i].dtv_cmd_process_cond, NULL);
pthread_mutex_init(&patch->dtv_path[i].dtv_cmd_process_mutex, NULL);
pthread_mutex_init(&patch->dtv_path[i].apts_cal_mutex, NULL);
pthread_mutex_init(&patch->dtv_path[i].dtv_path_lock, NULL);
}
pthread_mutex_lock(&aml_dev->dtv_patch_lock);
set_dev_patch(aml_dev, patch);
pthread_mutex_unlock(&aml_dev->dtv_patch_lock);
/* Use flag to indicate that patch struct is ready. TBD */
validate_dev_patch(aml_dev);
AM_LOGI("-- patch %p", patch);
return 0;
err:
if (patch) {
for (int i = 0; i < DVB_DEMUX_SUPPORT_MAX_NUM; i++) {
if (patch->dtv_path[i].dtv_cmd_list) {
deinit_cmd_list(patch->dtv_path[i].dtv_cmd_list);
}
}
aml_audio_free(patch);
}
set_dev_patch(aml_dev, NULL);
return ret;
}
static int _dtv_patch_release_resource(struct aml_audio_patch *patch)
{
for (int i = 0; i < DVB_DEMUX_SUPPORT_MAX_NUM; i++) {
dtv_path_t *path = &(patch->dtv_path[i]);
if (path->cmd_process_thread_created) {
pthread_mutex_lock(&path->dtv_cmd_process_mutex);
dtv_cmdlist_add_cmd(path->dtv_cmd_list, AUDIO_DTV_PATCH_CMD_STOP, path->path_id);
pthread_cond_signal(&path->dtv_cmd_process_cond);
pthread_mutex_unlock(&path->dtv_cmd_process_mutex);
pthread_mutex_lock(&path->dtv_cmd_process_mutex);
dtv_cmdlist_add_cmd(path->dtv_cmd_list, AUDIO_DTV_PATCH_CMD_CLOSE, path->path_id);
pthread_cond_signal(&path->dtv_cmd_process_cond);
pthread_mutex_unlock(&path->dtv_cmd_process_mutex);
pthread_join(path->audio_cmd_process_threadID, NULL);
path->cmd_process_thread_created = 0;
}
pthread_mutex_destroy(&path->dtv_path_lock);
pthread_mutex_destroy(&path->dtv_cmd_process_mutex);
pthread_cond_destroy(&path->dtv_cmd_process_cond);
pthread_cond_destroy(&path->apts_cond);
pthread_mutex_destroy(&path->apts_cal_mutex);
deinit_cmd_list(path->dtv_cmd_list);
}
}
static int release_dtv_patch_l(struct aml_audio_device *aml_dev)
{
if (aml_dev == NULL) {
AM_LOGE("aml_dev == NULL");
return 0;
}
struct aml_audio_patch *patch = get_dev_patch(aml_dev);
struct audio_hw_device *dev = (struct audio_hw_device *)aml_dev;
AM_LOGI("++ Enter, patch %p", patch);
if (patch == NULL) {
AM_LOGE("patch == NULL");
return 0;
}
/* Use flag to indicate that it will start to free patch struct. TBD */
invalidate_dev_patch(aml_dev);
_dtv_patch_release_resource(patch);
pthread_mutex_lock(&aml_dev->dtv_patch_lock);
aml_audio_free(patch);
set_dev_patch(aml_dev, NULL);
pthread_mutex_unlock(&aml_dev->dtv_patch_lock);
AM_LOGI("-- Exit");
return 0;
}
int create_dtv_patch(struct audio_hw_device *dev, audio_devices_t input,
audio_devices_t output)
{
struct aml_audio_device *aml_dev = (struct aml_audio_device *)dev;
int ret = 0;
pthread_mutex_lock(&aml_dev->patch_lock);
ret = create_dtv_patch_l(dev, input, output);
pthread_mutex_unlock(&aml_dev->patch_lock);
return ret;
}
int release_dtv_patch(struct aml_audio_device *aml_dev)
{
int ret = 0;
pthread_mutex_lock(&aml_dev->patch_lock);
if (is_same_patch_src(aml_dev, SRC_DTV)) {
ret = release_dtv_patch_l(aml_dev);
}
pthread_mutex_unlock(&aml_dev->patch_lock);
return ret;
}
int dtv_path_get_es_pts_dts_flag(int path_id)
{
struct aml_audio_device *aml_dev = (struct aml_audio_device *)adev_get_handle();
if (!aml_dev) {
AM_LOGE("get adev(%p) error", aml_dev);
return 0;
}
struct aml_audio_patch *patch = get_dev_patch(aml_dev);
if (patch == NULL) {
AM_LOGE("dtv patch == NULL");
return 0;
}
AM_LOGI("path_id %d pts_dts_flag %d", path_id, patch->dtv_path[path_id].pts_dts_flag);
return patch->dtv_path[path_id].pts_dts_flag;
}
int dtv_queue_es_info(void *info)
{
int ret = -1;
R_CHECK_POINTER_LEGAL(ret, info, "info");
struct es_queue_info *queue_info = (struct es_queue_info *) info;
struct aml_audio_device *adev = (struct aml_audio_device *)adev_get_handle();
dtv_path_t *dtv_path = (dtv_path_t *)queue_info->priv_data;
if (!adev || !dtv_path) {
AM_LOGE("get adev(%p) or path(%p) error", adev, dtv_path);
return ret;
}
pthread_mutex_lock(&dtv_path->dtv_path_lock);//lock because output thread may close output stream
if (dtv_path->dtv_aml_out) {
struct aml_stream_out *aml_out = dtv_path->dtv_aml_out;
if (aml_out->avsync_ctx) {
if (aml_out->avsync_ctx->mediasync_ctx) {
if (aml_out->avsync_ctx->mediasync_ctx->handle) {
struct mediasync_audio_queue_info audio_queue_info;
audio_queue_info.apts = queue_info->pts;
audio_queue_info.duration = 0;
audio_queue_info.size = queue_info->size;
audio_queue_info.isneedupdate = false;
audio_queue_info.isworkingchannel = true;
audio_queue_info.tunit = MEDIASYNC_UNIT_PTS;
mediasync_wrap_queueAudioFrame(aml_out->avsync_ctx->mediasync_ctx->handle, &audio_queue_info);
AM_LOGI_IF(adev->debug_flag, "path %p, aout %p, avsync_ctx %p, mediasync ctx %p, handle %p. pid %d, dmx_id %d:%d, pts:0x%"PRIx64", size:%d",
dtv_path, aml_out, aml_out->avsync_ctx, aml_out->avsync_ctx->mediasync_ctx, aml_out->avsync_ctx->mediasync_ctx->handle,
dtv_path->demux_info.main_pid, dtv_path->demux_info.demux_id, queue_info->demux_id, queue_info->pts, queue_info->size);
ret = 0;
} else {
AM_LOGI_IF(adev->debug_flag, "path %p(pid %d, dmx_id %d:%d), aml_out %p, avsync_ctx %p, mediasync ctx %p, handle %p", dtv_path, dtv_path->demux_info.main_pid,
dtv_path->demux_info.demux_id, queue_info->demux_id, aml_out, aml_out->avsync_ctx, aml_out->avsync_ctx->mediasync_ctx, aml_out->avsync_ctx->mediasync_ctx->handle);
}
} else {
AM_LOGI_IF(adev->debug_flag, "path %p(pid %d, dmx_id %d:%d), aml_out %p, avsync_ctx %p, mediasync ctx %p", dtv_path, dtv_path->demux_info.main_pid, dtv_path->demux_info.demux_id,
queue_info->demux_id, aml_out, aml_out->avsync_ctx, aml_out->avsync_ctx->mediasync_ctx);
}
} else {
AM_LOGI_IF(adev->debug_flag, "path %p(pid %d, dmx_id %d:%d), aml_out %p, avsync_ctx %p", dtv_path, dtv_path->demux_info.main_pid, dtv_path->demux_info.demux_id, queue_info->demux_id,
aml_out, aml_out->avsync_ctx);
}
} else {
AM_LOGI_IF(adev->debug_flag, "path %p(pid %d, dmx_id %d:%d), aml_out %p", dtv_path, dtv_path->demux_info.main_pid, dtv_path->demux_info.demux_id,
queue_info->demux_id, dtv_path->dtv_aml_out);
}
pthread_mutex_unlock(&dtv_path->dtv_path_lock);
return ret;
}