1309 lines
57 KiB
C
1309 lines
57 KiB
C
/*
|
|
* 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 "aml_audio_log.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 <system/audio.h>
|
|
#include <time.h>
|
|
#include <sys/ioctl.h>
|
|
#include <unistd.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)
|
|
#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"
|
|
#include "aml_audio_property.h"
|
|
#include "aml_audio_parser.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 dtv_update_ad_vol_parameter(dtv_path_t *path);
|
|
static void dtv_update_pan_fade_parameter(dtv_path_t *path);
|
|
static void dtv_update_decoder_params(dtv_path_t *path);
|
|
static int dtv_create_ad_mixbuf(struct aml_stream_out *aml_out);
|
|
static void dtv_release_ad_mixbuf(struct aml_stream_out *aml_out);
|
|
|
|
|
|
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->main_fmt == ACODEC_FMT_AC4 || demux_info->ad_fmt == ACODEC_FMT_AC4) {
|
|
return -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 (demux_info->ad_dmx_init && path->ad_output_thread_created == 0) {
|
|
create_dtv_ad_output_stream_thread(path);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
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);
|
|
}
|
|
return 0;
|
|
}
|
|
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);
|
|
return 0;
|
|
}
|
|
|
|
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_by_source(adev, SRC_DTV);
|
|
|
|
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;
|
|
|
|
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:
|
|
adev->hbbtvsync_info.sync_id = demux_info->media_sync_id = val;
|
|
for (int i = 0; i < STREAM_NUM_MAX; i++) {
|
|
struct aml_stream_out *aml_out = adev->active_outputs[i];
|
|
if (aml_out && aml_out->flags & AUDIO_OUTPUT_FLAG_HBBTV && aml_out->avsync_ctx) {
|
|
if (aml_out->avsync_ctx->mediasync_ctx && val > 0 &&
|
|
(val != aml_out->avsync_ctx->mediasync_ctx->mediasync_id || !aml_out->avsync_ctx->mediasync_ctx->handle)) {
|
|
int sync_enable = 0;
|
|
AM_LOGI("hbbtv out %p, old id %d", aml_out, aml_out->avsync_ctx->mediasync_ctx->mediasync_id);
|
|
hwsync_mediasync_outset(aml_out, &sync_enable, val, aml_out->hal_format);
|
|
}
|
|
}
|
|
}
|
|
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);
|
|
demux_info->mute = val;
|
|
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 (dtv_volume_switch >= 0.0f && dtv_volume_switch <= 1.0f) {
|
|
demux_info->volume = dtv_volume_switch;
|
|
AM_LOGI ("dtv set volume:%f", 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;
|
|
}
|
|
adev->advol_level = val;
|
|
AM_LOGI("advol set to %d", adev->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;
|
|
}
|
|
adev->mixing_level = (val * 64 - 32 * 100) / 100; //[0,100] mapping to [-32,32]
|
|
AM_LOGI("mixing_level set to %d", adev->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 && eDolbyMS12Lib == adev->dolby_lib_type) {
|
|
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 && eDolbyMS12Lib == adev->dolby_lib_type) {
|
|
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 && eDolbyMS12Lib == adev->dolby_lib_type) {
|
|
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;
|
|
case AUDIO_DTV_PATCH_CMD_SET_DECODER_ID:
|
|
path->dtv_path_decoder_id = val;
|
|
if (path->dtv_aml_out) {
|
|
path->dtv_aml_out->decoder_id = val;
|
|
AM_LOGI ("set audio stream(%p) decoder_id:%d ", path->dtv_aml_out, path->dtv_aml_out->decoder_id);
|
|
} else {
|
|
path->pending_decoder_id = true;
|
|
AM_LOGI ("stream is not open, set decoder_id after stream is opened.");
|
|
}
|
|
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 };
|
|
struct aml_hw_mixer mixer_handle = {0};
|
|
struct mixer_buf mixer_buffer = {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());
|
|
|
|
aml_set_thread_priority(thread_name, path->audio_output_threadID, 3);
|
|
|
|
//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;
|
|
|
|
if (path->pending_decoder_id) {
|
|
aml_out->decoder_id = path->dtv_path_decoder_id;
|
|
path->pending_decoder_id = false;
|
|
AM_LOGI("set stream(%p) deocer_id:%d", aml_out, path->dtv_path_decoder_id);
|
|
}
|
|
|
|
//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 = aml_dev->advol_level;//to init ms12 and dcv decoder
|
|
aml_out->dec_param.mixing_level = aml_dev->mixing_level;
|
|
if (eDolbyMS12Lib != aml_dev->dolby_lib_type && aml_out->hal_format != AUDIO_FORMAT_AC3 && aml_out->hal_format != AUDIO_FORMAT_E_AC3) {
|
|
aml_out->dec_param.dec_gain = demux_info->associate_audio_mixing_enable ? dtv_ad_mixlevel_vol_convert_to_gain(aml_out) : 1.0;//to init mp3/aac decoder gain
|
|
}
|
|
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 (aml_out->external_mute != aml_dev->dtv_mute) {
|
|
out_set_stream_mute((struct audio_stream_out *)aml_out, aml_dev->patch_mute, true);
|
|
}
|
|
if (path->dtv_decoder_state == AUDIO_DTV_PATCH_DECODER_STATE_PAUSE) {
|
|
usleep(1000);
|
|
continue;
|
|
}
|
|
if (demux_info->associate_audio_mixing_enable && VALID_AD_FMT(demux_info->main_fmt)) {
|
|
if (aml_out->mix_buf == NULL) {
|
|
aml_out->mix_buf = &mixer_buffer;
|
|
dtv_create_ad_mixbuf(aml_out);
|
|
}
|
|
if (eDolbyMS12Lib != aml_dev->dolby_lib_type && aml_out->hal_format != AUDIO_FORMAT_AC3 && aml_out->hal_format != AUDIO_FORMAT_E_AC3) {
|
|
if (aml_out->mixer_handle == NULL) {
|
|
aml_out->mixer_handle = &mixer_handle;
|
|
aml_hw_mixer_init(aml_out->mixer_handle);
|
|
}
|
|
}
|
|
}
|
|
|
|
//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 = aml_out->next_parsered_pts;
|
|
}
|
|
if (get_debug_value(AML_DUMP_AUDIOHAL_DTV)) {
|
|
aml_dump_audio_bitstreams_with_id("dtv_main_audio_dmx.es", mEsData->data, mEsData->size, aml_out->unique_ID);
|
|
}
|
|
}
|
|
|
|
//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);
|
|
}
|
|
dtv_update_decoder_params(path);
|
|
|
|
|
|
//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);
|
|
if (aml_out->mixer_handle) {
|
|
aml_hw_mixer_deinit(aml_out->mixer_handle);
|
|
aml_out->mixer_handle = NULL;
|
|
}
|
|
if (aml_out->mix_buf) {
|
|
dtv_release_ad_mixbuf(aml_out);
|
|
aml_out->mix_buf = NULL;
|
|
}
|
|
|
|
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, ad_size_in_queue = 0, ad_render_start = 0;
|
|
struct timespec last_getdata_ts, ts;
|
|
bool data_come_soon = false, first_ad_flag = false, ad_need_sync = 0, addata_timeout = 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,
|
|
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;
|
|
if (eDolbyMS12Lib != aml_dev->dolby_lib_type && ad_aml_out->hal_format != AUDIO_FORMAT_AC3 && ad_aml_out->hal_format != AUDIO_FORMAT_E_AC3) {
|
|
ad_aml_out->dec_param.dec_gain = dtv_ad_mixlevel_vol_convert_to_gain(ad_aml_out);//to init mp3/aac decoder gain
|
|
}
|
|
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) {
|
|
if (ad_aml_out->external_mute != aml_dev->dtv_mute) {
|
|
out_set_stream_mute((struct audio_stream_out *)ad_aml_out, aml_dev->patch_mute, true);
|
|
}
|
|
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 ||
|
|
!main_aml_out->mix_buf || !main_aml_out->mix_buf->mix_buffer.buffer || (!path->dtv_first_apts_flag)) {
|
|
usleep(10000);
|
|
continue;
|
|
}
|
|
if (ad_aml_out->mix_buf == NULL) {
|
|
ad_aml_out->mix_buf = main_aml_out->mix_buf;
|
|
}
|
|
#define AD_START_THRESHOLD 2
|
|
Get_Audio_AD_ES_Queue_Size(demux_handle, &ad_size_in_queue);
|
|
if (ad_size_in_queue > AD_START_THRESHOLD && need_hold_data) {
|
|
need_hold_data = false;
|
|
} else if (need_hold_data) {
|
|
usleep(10000);
|
|
continue;
|
|
}
|
|
|
|
dtv_update_ad_vol_parameter(path);
|
|
if (0 == demux_info->associate_audio_mixing_enable) {
|
|
usleep(20000);
|
|
ad_render_start = 0;
|
|
continue;
|
|
}
|
|
|
|
if (mAdEsData == NULL) {
|
|
ret_ad = Get_ADAudio_Es(demux_handle, &mAdEsData);
|
|
if (ret_ad != AM_AUDIO_Dmx_SUCCESS || !mAdEsData) {
|
|
AM_LOGI_IF(aml_dev->debug_flag, "Get_ADAudio_Es failed, ret %d, mAdEsData %p", ret_ad, mAdEsData);
|
|
usleep(5000);
|
|
if (first_ad_flag) {
|
|
data_come_soon = Stop_watch(last_getdata_ts, DATA_TIMEOUT);
|
|
if (!data_come_soon) {
|
|
addata_timeout = true;
|
|
need_hold_data = true;
|
|
ad_render_start = 0;
|
|
AM_LOGI_IF(aml_dev->debug_flag, "no data for %dms!!", DATA_TIMEOUT);
|
|
}
|
|
}
|
|
goto free_data;
|
|
} else {
|
|
clock_gettime(CLOCK_MONOTONIC, &last_getdata_ts);
|
|
AM_LOGI_IF(aml_dev->debug_flag, "ad size %d pts %"PRIx64"(%"PRIx64"), diff %"PRId64"ms. ms12_dec %p. timeout %d, first_flag %d",
|
|
mAdEsData->size, mAdEsData->pts, path->last_valid_ad_pts, (mAdEsData->pts-path->last_valid_ad_pts)/90, ad_aml_out->ms12_dec_handle, addata_timeout, first_ad_flag);
|
|
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;
|
|
ad_need_sync = 1;
|
|
addata_timeout = false;
|
|
first_ad_flag = true;
|
|
} else {
|
|
if (addata_timeout || !first_ad_flag) {// if first pts is invalid, we need drop it
|
|
aml_audio_parser_reset(ad_aml_out->aml_parser);// if first pts after timeout is invalid, we need drop it and flush the remain data in parser
|
|
goto free_data;
|
|
}
|
|
mAdEsData->pts = path->last_valid_ad_pts;
|
|
ad_need_sync = 0;
|
|
}
|
|
if (get_debug_value(AML_DUMP_AUDIOHAL_DTV)) {
|
|
aml_dump_audio_bitstreams_with_id("dtv_ad_audio_dmx.es", mAdEsData->data, mAdEsData->size, ad_aml_out->unique_ID);
|
|
}
|
|
}
|
|
}
|
|
/* align ad and main data by pts compare */
|
|
pthread_mutex_lock(&path->apts_cal_mutex);
|
|
if (ad_need_sync) {
|
|
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_IF(aml_dev->debug_flag, "drop ad data");
|
|
goto free_data;
|
|
} else if (demux_info->ad_package_status == AD_PACK_STATUS_HOLD && ad_render_start == 0) {//after render, not hold ad here
|
|
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;
|
|
abuffer_out.channel = 2;
|
|
abuffer_out.sample_rate = 48000;
|
|
abuffer_out.format = abuffer_out.original_format = stream_config.format;
|
|
demux_info->ad_fade = mAdEsData->adfade;
|
|
demux_info->ad_pan = mAdEsData->adpan;
|
|
ad_render_start = 1;
|
|
|
|
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, aml_dev->mixing_level, aml_dev->advol_level, ret_ad);
|
|
|
|
dtv_update_pan_fade_parameter(path);
|
|
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;
|
|
path->ad_fade = path->ad_pan = 0;
|
|
}
|
|
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);
|
|
/*coverity[LOCK_EVASION]: There will be no competition here*/
|
|
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);
|
|
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)
|
|
{
|
|
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);
|
|
if (path->dtv_ad_aml_out && path->dtv_ad_aml_out->mix_buf)
|
|
pthread_cond_signal(&path->dtv_ad_aml_out->mix_buf->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 aml_audio_device *aml_dev, struct aml_audio_patch ** apatch)
|
|
{
|
|
struct aml_audio_patch *patch;
|
|
int ret = 0;
|
|
AM_LOGI("++");
|
|
|
|
patch = aml_audio_calloc(1, sizeof(*patch));
|
|
if (!patch) {
|
|
ret = -1;
|
|
goto err;
|
|
}
|
|
memset(patch, 0, sizeof(*patch));
|
|
|
|
// save dev to patch
|
|
patch->dev = aml_dev;
|
|
patch->patch_src = SRC_DTV;
|
|
patch->input_device = AUDIO_DEVICE_IN_TV_TUNER;
|
|
patch->aformat = AUDIO_FORMAT_PCM_16_BIT;
|
|
|
|
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);
|
|
pthread_mutex_unlock(&aml_dev->dtv_patch_lock);
|
|
/* Use flag to indicate that patch struct is ready. TBD */
|
|
//validate_dev_patch(aml_dev);
|
|
*apatch = patch;
|
|
|
|
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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static int release_dtv_patch_l(struct aml_audio_device *aml_dev, struct aml_audio_patch *apatch)
|
|
{
|
|
if (aml_dev == NULL || apatch == NULL) {
|
|
AM_LOGE("aml_dev == NULL");
|
|
return 0;
|
|
}
|
|
struct aml_audio_patch *patch = apatch;
|
|
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);
|
|
pthread_mutex_unlock(&aml_dev->dtv_patch_lock);
|
|
|
|
AM_LOGI("-- Exit");
|
|
|
|
return 0;
|
|
}
|
|
|
|
int create_dtv_patch(struct aml_audio_device *dev, void ** apatch)
|
|
{
|
|
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, (struct aml_audio_patch **)apatch);
|
|
pthread_mutex_unlock(&aml_dev->patch_lock);
|
|
|
|
return ret;
|
|
}
|
|
|
|
int release_dtv_patch(struct aml_audio_device *aml_dev, void *apatch)
|
|
{
|
|
int ret = 0;
|
|
pthread_mutex_lock(&aml_dev->patch_lock);
|
|
ret = release_dtv_patch_l(aml_dev, (struct aml_audio_patch *)apatch);
|
|
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_by_source(aml_dev, SRC_DTV);
|
|
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_path_get_mediasync_id(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_by_source(aml_dev, SRC_DTV);
|
|
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].media_sync_id);
|
|
return patch->dtv_path[path_id].media_sync_id;
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
static void dtv_set_decoder_gain(dtv_path_t *path, struct audio_stream_out *stream) {
|
|
R_CHECK_POINTER_LEGAL(, stream, "");
|
|
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
|
|
struct aml_audio_device *adev = (struct aml_audio_device *)adev_get_handle();
|
|
float gain = 1.0;
|
|
if (eDolbyMS12Lib != adev->dolby_lib_type) {//when ms12, ad vol & mix level would be set to ms12
|
|
if ((aml_out->stream_type == STREAM_MAIN_INPUT && aml_out->dec_param.ad_mix_enable) || aml_out->stream_type == STREAM_AD_INPUT)
|
|
gain = dtv_ad_mixlevel_vol_convert_to_gain(aml_out);
|
|
}
|
|
if (aml_out->stream_type == STREAM_MAIN_INPUT) {
|
|
float fade_coef = 1.0;
|
|
if (path->ad_fade && aml_out->dec_param.ad_mix_enable)
|
|
fade_coef = DbToAmpl(path->ad_fade * (-0.3f));
|
|
AM_LOGI("[main]fade %d fade_coef %f; mix level: %d, gain: %f", path->ad_fade, fade_coef, adev->mixing_level, gain);
|
|
aml_out->dec_config.dec_left_gain = gain * fade_coef;
|
|
aml_out->dec_config.dec_right_gain = aml_out->dec_config.dec_left_gain;
|
|
} else if (aml_out->stream_type == STREAM_AD_INPUT) {
|
|
float left_vol = 1.0, right_vol = 1.0;
|
|
if (path->ad_pan > 0 && path->ad_pan < 0xFF) {
|
|
get_left_right_volume(path->ad_pan, &left_vol, &right_vol);
|
|
}
|
|
AM_LOGI("[ad]pan %d(L %f, R %f); ad vol %d, mix level: %d, gain: %f", path->ad_pan, left_vol, right_vol, adev->advol_level, adev->mixing_level, gain);
|
|
aml_out->dec_config.dec_left_gain = left_vol * gain;
|
|
aml_out->dec_config.dec_right_gain = right_vol * gain;
|
|
}
|
|
aml_decoder_set_config(aml_out->aml_dec, AML_DEC_CONFIG_LEFT_GAIN, &aml_out->dec_config);
|
|
aml_decoder_set_config(aml_out->aml_dec, AML_DEC_CONFIG_RIGHT_GAIN, &aml_out->dec_config);
|
|
return;
|
|
}
|
|
|
|
static void dtv_update_decoder_params(dtv_path_t *path) {
|
|
struct aml_stream_out *main_aml_out = path->dtv_aml_out;
|
|
aml_demux_audiopara_t *demux_info = (aml_demux_audiopara_t *)(&path->demux_info);
|
|
static float vol = 1.0;
|
|
if (main_aml_out->hal_format == AUDIO_FORMAT_AC4 || main_aml_out->ad_substream_supported) {
|
|
dtv_update_ad_vol_parameter(path);
|
|
}
|
|
if (main_aml_out->internal_mute != demux_info->mute) {
|
|
main_aml_out->internal_mute = demux_info->mute;
|
|
if (main_aml_out->internal_mute) {
|
|
vol = main_aml_out->volume_l_org;
|
|
main_aml_out->stream.set_volume(&main_aml_out->stream, 0, 0);
|
|
} else {
|
|
main_aml_out->stream.set_volume(&main_aml_out->stream, vol, vol);
|
|
}
|
|
}
|
|
if (main_aml_out->volume_l_org != demux_info->volume) {
|
|
vol = main_aml_out->volume_l_org = demux_info->volume;
|
|
if (!main_aml_out->internal_mute) {
|
|
main_aml_out->stream.set_volume(&main_aml_out->stream, vol, vol);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void dtv_update_ad_vol_parameter(dtv_path_t *path) {
|
|
struct aml_stream_out *main_aml_out = path->dtv_aml_out;
|
|
struct aml_stream_out *ad_aml_out = path->dtv_ad_aml_out;
|
|
struct aml_audio_device *aml_dev = (struct aml_audio_device *)adev_get_handle();
|
|
aml_demux_audiopara_t *demux_info = (aml_demux_audiopara_t *)(&path->demux_info);
|
|
|
|
if (main_aml_out->dec_param.ad_mix_enable != demux_info->associate_audio_mixing_enable) {
|
|
main_aml_out->dec_param.ad_mix_enable = demux_info->associate_audio_mixing_enable;
|
|
if (eDolbyMS12Lib == aml_dev->dolby_lib_type) {
|
|
set_ms12_ad_mixing_enable((struct audio_stream_out *)main_aml_out, demux_info->associate_audio_mixing_enable);//set to ms12
|
|
} else if (main_aml_out->hal_format == AUDIO_FORMAT_AC3 || main_aml_out->hal_format == AUDIO_FORMAT_E_AC3) {
|
|
main_aml_out->dec_config.ad_mixing_enable = demux_info->associate_audio_mixing_enable;
|
|
aml_decoder_set_config(main_aml_out->aml_dec, AML_DEC_CONFIG_MIXING_ENABLE, &main_aml_out->dec_config);//set to dcv
|
|
} else {
|
|
dtv_set_decoder_gain(path, (struct audio_stream_out *)main_aml_out);//mp3/aac use decoder gain
|
|
}
|
|
}
|
|
if (main_aml_out->dec_param.advol_level != aml_dev->advol_level) {
|
|
main_aml_out->dec_param.advol_level = aml_dev->advol_level;
|
|
if (eDolbyMS12Lib == aml_dev->dolby_lib_type) {
|
|
set_ms12_ad_vol((struct audio_stream_out *)main_aml_out, aml_dev->advol_level);//set to ms12
|
|
} else if (main_aml_out->hal_format == AUDIO_FORMAT_AC3 || main_aml_out->hal_format == AUDIO_FORMAT_E_AC3) {
|
|
main_aml_out->dec_config.advol_level = aml_dev->advol_level;
|
|
aml_decoder_set_config(main_aml_out->aml_dec, AML_DEC_CONFIG_AD_VOL, &main_aml_out->dec_config);//set to dcv
|
|
} else {
|
|
dtv_set_decoder_gain(path, (struct audio_stream_out *)ad_aml_out);//mp3/aac use decoder gain
|
|
}
|
|
}
|
|
if (main_aml_out->dec_param.mixing_level != aml_dev->mixing_level) {
|
|
main_aml_out->dec_param.mixing_level = aml_dev->mixing_level;
|
|
if (eDolbyMS12Lib == aml_dev->dolby_lib_type) {////set to ms12
|
|
set_ms12_ad_mixing_level((struct audio_stream_out *)main_aml_out, aml_dev->mixing_level);
|
|
} else if (main_aml_out->hal_format == AUDIO_FORMAT_AC3 || main_aml_out->hal_format == AUDIO_FORMAT_E_AC3) {
|
|
main_aml_out->dec_config.mixer_level = aml_dev->mixing_level;
|
|
aml_decoder_set_config(main_aml_out->aml_dec, AML_DEC_CONFIG_MIXER_LEVEL, &main_aml_out->dec_config);//set to dcv
|
|
} else {
|
|
dtv_set_decoder_gain(path, (struct audio_stream_out *)ad_aml_out);//mp3/aac use decoder gain
|
|
dtv_set_decoder_gain(path, (struct audio_stream_out *)main_aml_out);
|
|
}
|
|
}
|
|
}
|
|
|
|
static void dtv_update_pan_fade_parameter(dtv_path_t *path) {
|
|
struct aml_stream_out *main_aml_out = path->dtv_aml_out;
|
|
struct aml_stream_out *ad_aml_out = path->dtv_ad_aml_out;
|
|
struct aml_audio_device *aml_dev = (struct aml_audio_device *)adev_get_handle();
|
|
aml_demux_audiopara_t *demux_info = (aml_demux_audiopara_t *)(&path->demux_info);
|
|
|
|
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)) {
|
|
set_ms12_fade_pan((struct audio_stream_out *)main_aml_out, demux_info->ad_fade, 0, 0, 0, demux_info->ad_pan);//set to ms12
|
|
} else if (demux_info->ad_fade != path->ad_fade && main_aml_out->aml_dec) {
|
|
path->ad_fade = demux_info->ad_fade;
|
|
dtv_set_decoder_gain(path, (struct audio_stream_out *)main_aml_out);//mp3/aac use decoder gain
|
|
} else if (demux_info->ad_pan != path->ad_pan && ad_aml_out->aml_dec) {
|
|
path->ad_pan = demux_info->ad_pan;
|
|
dtv_set_decoder_gain(path, (struct audio_stream_out *)ad_aml_out);//mp3/aac use decoder gain
|
|
}
|
|
}
|
|
|
|
static int dtv_create_ad_mixbuf(struct aml_stream_out *aml_out) {
|
|
if (!aml_out || !aml_out->mix_buf) {
|
|
return -1;
|
|
}
|
|
|
|
aml_out->mix_buf->consumed = true;
|
|
int ret = pthread_mutex_init(&aml_out->mix_buf->lock, NULL);
|
|
if (ret != 0) {
|
|
AM_LOGE("pthread_mutex_init err %d", ret);
|
|
return -1;
|
|
}
|
|
ret = pthread_cond_init(&aml_out->mix_buf->cond, NULL);
|
|
if (ret != 0) {
|
|
AM_LOGE("pthread_cond_init err %d", ret);
|
|
return -1;
|
|
}
|
|
|
|
aml_out->mix_buf->buf_size = 4096;
|
|
aml_out->mix_buf->mix_buffer.buffer = (char *)aml_audio_calloc(1, aml_out->mix_buf->buf_size);
|
|
if (!aml_out->mix_buf->mix_buffer.buffer) {
|
|
AM_LOGE("malloc mixed_buffer buf error");
|
|
goto malloc_fail;
|
|
} else {
|
|
AM_LOGI("buffer:%p create success", aml_out->mix_buf->mix_buffer.buffer);
|
|
}
|
|
|
|
return 0;
|
|
malloc_fail:
|
|
if (aml_out->mix_buf) {
|
|
pthread_mutex_destroy(&aml_out->mix_buf->lock);
|
|
pthread_cond_destroy(&aml_out->mix_buf->cond);
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static void dtv_release_ad_mixbuf(struct aml_stream_out *aml_out) {
|
|
if (aml_out->mix_buf) {
|
|
if (aml_out->mix_buf->mix_buffer.buffer) {
|
|
AM_LOGD("free buffer %p", aml_out->mix_buf->mix_buffer.buffer);
|
|
aml_audio_free(aml_out->mix_buf->mix_buffer.buffer);
|
|
aml_out->mix_buf->mix_buffer.buffer = NULL;
|
|
}
|
|
pthread_mutex_destroy(&aml_out->mix_buf->lock);
|
|
pthread_cond_destroy(&aml_out->mix_buf->cond);
|
|
}
|
|
}
|
|
|
|
|