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

331 lines
15 KiB
C

/*
* Copyright (C) 2021 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_hal_mediasync"
#define LOG_NDEBUG 0
#include <errno.h>
#include <pthread.h>
#include <sys/time.h>
#include <stdlib.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
#include <stdint.h>
#include <inttypes.h>
#include <unistd.h>
#include "aml_audio_log.h"
#include <string.h>
#include <errno.h>
#include <sys/utsname.h>
#include "audio_hw_utils.h"
#include "aml_audio_spdifout.h"
#include "audio_hw.h"
#include "alsa_config_parameters.h"
#include "audio_hwsync.h"
#include "audio_mediasync.h"
#include "amlAudioMixer.h"
#include "aml_audio_output.h"
#define DD_MUTE_FRAME_SIZE 1536
#define EAC3_IEC61937_FRAME_SIZE 24576
#define MS12_MAT_RAW_LENGTH (0x0f7e)
#define SYNC_BUF_SIZE (DEFAULT_PLAYBACK_PERIOD_SIZE * PLAYBACK_PERIOD_COUNT * EAC3_MULTIPLIER)
const unsigned int hwm_mute_dd_frame[] = {
0x5d9c770b, 0xf0432014, 0xf3010713, 0x2020dc62, 0x4842020, 0x57100404, 0xf97c3e1f, 0x9fcfe7f3, 0xf3f97c3e, 0x3e9fcfe7, 0xe7f3f97c, 0x7c3e9fcf, 0xcfe7f3f9, 0xfb7c3e9f, 0xf97c75fe, 0x9fcfe7f3,
0xf3f97c3e, 0x3e9fcfe7, 0xe7f3f97c, 0x7c3e9fcf, 0xcfe7f3f9, 0xfb7c3e9f, 0x3e5f9dff, 0xe7f3f97c, 0x7c3e9fcf, 0xcfe7f3f9, 0xf97c3e9f, 0x9fcfe7f3, 0xf3f97c3e, 0x3e9fcfe7, 0x48149ff2, 0x2091,
0x361e0000, 0x78bc6ddb, 0xbbbbe3f1, 0xb8, 0x0, 0x0, 0x0, 0x77770700, 0x361e8f77, 0x359f6fdb, 0xd65a6bad, 0x5a6badb5, 0x6badb5d6, 0xa0b5d65a, 0x1e000000, 0xbc6ddb36,
0xbbe3f178, 0xb8bb, 0x0, 0x0, 0x0, 0x77070000, 0x1e8f7777, 0x9f6fdb36, 0x5a6bad35, 0xa6b5d6, 0x0, 0xb66de301, 0x1e8fc7db, 0x80bbbb3b, 0x0, 0x0,
0x0, 0x0, 0x78777777, 0xb66de3f1, 0xd65af3f9, 0x5a6badb5, 0x6badb5d6, 0xadb5d65a, 0x5a6b, 0x6de30100, 0x8fc7dbb6, 0xbbbb3b1e, 0x80, 0x0, 0x0, 0x0,
0x77777700, 0x6de3f178, 0x5af3f9b6, 0x6badb5d6, 0x605a, 0x1e000000, 0xbc6ddb36, 0xbbe3f178, 0xb8bb, 0x0, 0x0, 0x0, 0x77070000, 0x1e8f7777, 0x9f6fdb36, 0x5a6bad35,
0x6badb5d6, 0xadb5d65a, 0xb5d65a6b, 0xa0, 0x6ddb361e, 0xe3f178bc, 0xb8bbbb, 0x0, 0x0, 0x0, 0x7000000, 0x8f777777, 0x6fdb361e, 0x6bad359f, 0xa6b5d65a, 0x0,
0x6de30100, 0x8fc7dbb6, 0xbbbb3b1e, 0x80, 0x0, 0x0, 0x0, 0x77777700, 0x6de3f178, 0x5af3f9b6, 0x6badb5d6, 0xadb5d65a, 0xb5d65a6b, 0x5a6bad, 0xe3010000, 0xc7dbb66d,
0xbb3b1e8f, 0x80bb, 0x0, 0x0, 0x0, 0x77770000, 0xe3f17877, 0xf3f9b66d, 0xadb5d65a, 0x605a6b, 0x0, 0x6ddb361e, 0xe3f178bc, 0xb8bbbb, 0x0, 0x0,
0x0, 0x7000000, 0x8f777777, 0x6fdb361e, 0x6bad359f, 0xadb5d65a, 0xb5d65a6b, 0xd65a6bad, 0xa0b5, 0xdb361e00, 0xf178bc6d, 0xb8bbbbe3, 0x0, 0x0, 0x0, 0x0,
0x77777707, 0xdb361e8f, 0xad359f6f, 0xb5d65a6b, 0x10200a6, 0x0, 0xdbb6f100, 0x8fc7e36d, 0xc0dddd1d, 0x0, 0x0, 0x0, 0x0, 0xbcbbbb3b, 0xdbb6f178, 0x6badf97c,
0xadb5d65a, 0xb5d65a6b, 0xd65a6bad, 0xadb5, 0xb6f10000, 0xc7e36ddb, 0xdddd1d8f, 0xc0, 0x0, 0x0, 0x0, 0xbbbb3b00, 0xb6f178bc, 0xadf97cdb, 0xb5d65a6b, 0x4deb00ad
};
const unsigned int hwm_mute_ddp_frame[] = {
0x7f01770b, 0x20e06734, 0x2004, 0x8084500, 0x404046c, 0x1010104, 0xe7630001, 0x7c3e9fcf, 0xcfe7f3f9, 0xf97c3e9f, 0x9fcfe7f3, 0xf3f97c3e, 0x3e9fcfe7, 0xe7f3f97c, 0xce7f9fcf, 0x7c3e9faf,
0xcfe7f3f9, 0xf97c3e9f, 0x9fcfe7f3, 0xf3f97c3e, 0x3e9fcfe7, 0xe7f3f97c, 0xf37f9fcf, 0x9fcfe7ab, 0xf3f97c3e, 0x3e9fcfe7, 0xe7f3f97c, 0x7c3e9fcf, 0xcfe7f3f9, 0xf97c3e9f, 0x53dee7f3, 0xf0e9,
0x6d3c0000, 0xf178dbb6, 0x7777c7e3, 0x70, 0x0, 0x0, 0x0, 0xeeee0e00, 0x6d3c1eef, 0x6b3edfb6, 0xadb5d65a, 0xb5d65a6b, 0xd65a6bad, 0x406badb5, 0x3c000000, 0x78dbb66d,
0x77c7e3f1, 0x7077, 0x0, 0x0, 0x0, 0xee0e0000, 0x3c1eefee, 0x3edfb66d, 0xb5d65a6b, 0x20606bad, 0x0, 0xdbb66d3c, 0xc7e3f178, 0x707777, 0x0, 0x0,
0x0, 0xe000000, 0x1eefeeee, 0xdfb66d3c, 0xd65a6b3e, 0x5a6badb5, 0x6badb5d6, 0xadb5d65a, 0x406b, 0xb66d3c00, 0xe3f178db, 0x707777c7, 0x0, 0x0, 0x0, 0x0,
0xefeeee0e, 0xb66d3c1e, 0x5a6b3edf, 0x6badb5d6, 0x2060, 0x6d3c0000, 0xf178dbb6, 0x7777c7e3, 0x70, 0x0, 0x0, 0x0, 0xeeee0e00, 0x6d3c1eef, 0x6b3edfb6, 0xadb5d65a,
0xb5d65a6b, 0xd65a6bad, 0x406badb5, 0x3c000000, 0x78dbb66d, 0x77c7e3f1, 0x7077, 0x0, 0x0, 0x0, 0xee0e0000, 0x3c1eefee, 0x3edfb66d, 0xb5d65a6b, 0x20606bad, 0x0,
0xdbb66d3c, 0xc7e3f178, 0x707777, 0x0, 0x0, 0x0, 0xe000000, 0x1eefeeee, 0xdfb66d3c, 0xd65a6b3e, 0x5a6badb5, 0x6badb5d6, 0xadb5d65a, 0x406b, 0xb66d3c00, 0xe3f178db,
0x707777c7, 0x0, 0x0, 0x0, 0x0, 0xefeeee0e, 0xb66d3c1e, 0x5a6b3edf, 0x6badb5d6, 0x2060, 0x6d3c0000, 0xf178dbb6, 0x7777c7e3, 0x70, 0x0, 0x0,
0x0, 0xeeee0e00, 0x6d3c1eef, 0x6b3edfb6, 0xadb5d65a, 0xb5d65a6b, 0xd65a6bad, 0x406badb5, 0x3c000000, 0x78dbb66d, 0x77c7e3f1, 0x7077, 0x0, 0x0, 0x0, 0xee0e0000,
0x3c1eefee, 0x3edfb66d, 0xb5d65a6b, 0x20606bad, 0x0, 0xdbb66d3c, 0xc7e3f178, 0x707777, 0x0, 0x0, 0x0, 0xe000000, 0x1eefeeee, 0xdfb66d3c, 0xd65a6b3e, 0x5a6badb5,
0x6badb5d6, 0xadb5d65a, 0x406b, 0xb66d3c00, 0xe3f178db, 0x707777c7, 0x0, 0x0, 0x0, 0x0, 0xefeeee0e, 0xb66d3c1e, 0x5a6b3edf, 0x6badb5d6, 0x40, 0x7f227c55,
};
bool nonms12_insertpcm(struct audio_stream_out *stream, audio_format_t format, int time_ms)
{
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
struct aml_audio_device *adev = aml_out->dev;
int insert_size = 0;
size_t out_buf_size = SYNC_BUF_SIZE;
static char out_buf[SYNC_BUF_SIZE];
int t1 = 0;
ALOGI("insert time_ms=%d ms", time_ms);
insert_size = 192 * time_ms;
memset(out_buf, 0, out_buf_size);
if (insert_size <= out_buf_size) {
aml_hw_mixer_mixing(&adev->hw_mixer, out_buf, insert_size, format);
out_write_direct_pcm(stream, out_buf, insert_size);
return true;
}
if (out_buf_size != 0)
t1 = insert_size / out_buf_size;
else {
ALOGI("fatal error out_buf_size is 0\n");
return false;
}
ALOGI("set t1=%d\n", t1);
for (int i = 0; i < t1; i++) {
aml_hw_mixer_mixing(&adev->hw_mixer, out_buf, out_buf_size, format);
out_write_direct_pcm(stream, out_buf, out_buf_size);
}
return true;
}
int mediasync_nonms12_process_insert(struct audio_stream_out *stream,struct mediasync_audio_policy *p_policy)
{
int insert_time_ms = 0;
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
aml_dec_t *aml_dec = aml_out->aml_dec;
if (!aml_dec) {
ALOGI("aml_dec is null, return -1\n");
return -1;
}
insert_time_ms = p_policy->param1/1000;
ALOGI("before insert :%d\n", insert_time_ms);
do {
nonms12_insertpcm(stream, AUDIO_FORMAT_PCM_16_BIT, 32);
insert_time_ms -= 32;
} while (insert_time_ms > 0);
ALOGI("after insert time\n");
return 0;
}
int mediasync_get_policy(struct audio_stream_out *stream)
{
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
struct mediasync_audio_policy m_audiopolicy;
int debug_flag = get_debug_value(AML_DEBUG_AUDIOHAL_MEDIA_SYNC);
memset(&m_audiopolicy, 0, sizeof(m_audiopolicy));
audio_mediasync_t *p_mediasync = aml_out->avsync_ctx->mediasync_ctx;
if (p_mediasync == NULL) {
AM_LOGE("p_mediasync is NULL, out %p", aml_out);
return 0;
}
do {
if (true == aml_out->will_pause || true == aml_out->pause_status || true == aml_out->will_flush) {
break;
}
int ret = mediasync_wrap_AudioProcess(p_mediasync->handle, p_mediasync->out_start_apts, p_mediasync->cur_outapts, MEDIASYNC_UNIT_PTS, &m_audiopolicy);
if (!ret) {
AM_LOGE("mediasync_wrap_AudioProcess fail.");
break;
}
if (debug_flag || m_audiopolicy.audiopolicy != MEDIASYNC_AUDIO_NORMAL_OUTPUT) {
ALOGI("[%p]m_audiopolicy=%d=%s, param1=%u, param2=%u, org_pts=0x%"PRIx64", cur_pts=0x%"PRIx64"", p_mediasync->handle,
m_audiopolicy.audiopolicy, mediasyncAudiopolicyType2Str(m_audiopolicy.audiopolicy),
m_audiopolicy.param1, m_audiopolicy.param2,
p_mediasync->out_start_apts, p_mediasync->cur_outapts);
}
} while (0);
p_mediasync->apolicy.audiopolicy= (audio_policy)m_audiopolicy.audiopolicy;
p_mediasync->apolicy.param1 = m_audiopolicy.param1;
p_mediasync->apolicy.param2 = m_audiopolicy.param2;
return 0;
}
sync_process_res mediasync_nonms12_process(struct audio_stream_out *stream)
{
struct aml_stream_out *aml_out = (struct aml_stream_out *) stream;
struct aml_audio_device *adev = aml_out->dev;
aml_dec_t *aml_dec = aml_out->aml_dec;
sync_process_res ret = ESSYNC_AUDIO_OUTPUT;
if (aml_out->avsync_ctx == NULL || aml_out->avsync_ctx->mediasync_ctx == NULL) {
return ret;
}
pthread_mutex_lock(&(aml_out->avsync_ctx->lock));
struct mediasync_audio_policy *async_policy = &(aml_out->avsync_ctx->mediasync_ctx->apolicy);
bool alsa_status = false;
if (aml_audio_pcm_out_get_alsa_status(adev, &alsa_status)) {
AM_LOGI("alsa_running_status %d", alsa_status);
mediasync_wrap_setParameter(aml_out->avsync_ctx->mediasync_ctx->handle, MEDIASYNC_KEY_ALSAREADY, &alsa_status);
aml_audio_pcm_out_clear_alsa_status_changed_flag(adev);
}
re_get_policy:
mediasync_get_policy(stream);
switch (async_policy->audiopolicy)
{
case MEDIASYNC_AUDIO_DROP_PCM:
aml_out->avsync_ctx->mediasync_ctx->cur_outapts = aml_dec->out_frame_pts;
ret = ESSYNC_AUDIO_DROP;
break;
case MEDIASYNC_AUDIO_INSERT:
mediasync_nonms12_process_insert(stream, async_policy);
break;
case MEDIASYNC_AUDIO_HOLD:
{
if (-1 == async_policy->param1) {
/* coverity[sleep] */
usleep(15000);
} else if (1000000 < async_policy->param1) {
AM_LOGE("Invalid hold parameter, m_audiopolicy.param1:%d, change sleep to 1s now!", async_policy->param1);
/* coverity[sleep] */
usleep(1000000);
} else {
/* coverity[sleep] */
usleep(async_policy->param1);
}
/*coverity[missing_lock]: aml_out->fast_quit does not need to be lock*/
if (true == aml_out->fast_quit) {
AM_LOGI("fast_quit, break now.");
ret = ESSYNC_AUDIO_EXIT;
break;
}
if ((true == aml_out->will_pause) || (true == aml_out->pause_status)) {
AM_LOGI("pause, break now.");
break;
}
goto re_get_policy;
}
case MEDIASYNC_AUDIO_ADJUST_CLOCK:
//aml_dtvsync_ms12_adjust_clock(stream_out, async_policy->param1);
//enable_dtv_underrun_mute(adev, false);
break;
case MEDIASYNC_AUDIO_RESAMPLE:
{
float rate = (float)async_policy->param1/(float)(async_policy->param2);
AM_LOGI("MEDIASYNC_AUDIO_RESAMPLE, param1=%u, param2=%u, rate=%f", async_policy->param1, async_policy->param2, rate);
if (true == aml_out->enable_scaletempo)
{
if (NULL == aml_out->scaletempo) {
hal_scaletempo_init(&aml_out->scaletempo);
}
hal_scaletempo_update_rate(aml_out->scaletempo, rate);
}
break;
}
case MEDIASYNC_AUDIO_NORMAL_OUTPUT:
//enable_dtv_underrun_mute(adev, false);
break;
default :
AM_LOGE("unknown policy:%d error!", async_policy->audiopolicy);
break;
}
pthread_mutex_unlock(&(aml_out->avsync_ctx->lock));
return ret;
}
int hwsync_mediasync_outset(struct aml_stream_out *out, int* sync_enable, int hw_sync_id, int format)
{
if ((NULL == out->avsync_ctx) || (AVSYNC_TYPE_MEDIASYNC != out->avsync_type))
{
AM_LOGE("Error: out->avsync_ctx:%p, out->avsync_type:%d", out->avsync_ctx, out->avsync_type);
return -1;
}
struct aml_audio_device *aml_dev = (struct aml_audio_device *)adev_get_handle();
if (!aml_dev) {
AM_LOGE("get adev error");
return -1;
}
pthread_mutex_lock(&(out->avsync_ctx->lock));
if (NULL == out->avsync_ctx->mediasync_ctx) {
out->avsync_ctx->mediasync_ctx = mediasync_ctx_init();
if (NULL == out->avsync_ctx->mediasync_ctx) {
AM_LOGE("mediasync_ctx_init error");
pthread_mutex_unlock(&(out->avsync_ctx->lock));
return -1;
}
}
audio_mediasync_t *mediasync_ctx = out->avsync_ctx->mediasync_ctx;
if (NULL == mediasync_ctx->handle) {
mediasync_ctx->handle = mediasync_wrap_create();
} else {
//media sync seek call the out_flush ,add for flush
mediasync_wrap_destroy(mediasync_ctx->handle);
mediasync_ctx->handle = mediasync_wrap_create();
}
if (mediasync_ctx->handle == NULL) {
AM_LOGE("mediasync create failed");
}
bool ret_set_id = false;
int has_audio = 1;
int audio_sync_mode = 0;
struct mediasync_audio_format audio_format={0};
bool alsa_status = false;
mediasync_ctx->mediasync_id = hw_sync_id;
mediasync_wrap_setParameter(mediasync_ctx->handle, MEDIASYNC_KEY_ISOMXTUNNELMODE, &audio_sync_mode);
ret_set_id = mediasync_wrap_bindInstance(mediasync_ctx->handle, hw_sync_id, MEDIA_AUDIO);
mediasync_wrap_setParameter(mediasync_ctx->handle, MEDIASYNC_KEY_HASAUDIO, &has_audio);
audio_format.format = format;
mediasync_wrap_setParameter(mediasync_ctx->handle, MEDIASYNC_KEY_AUDIOFORMAT, &audio_format);
mediasync_av_scenario scene = MEDIA_WORK_DEFAULT;
if (out->flags & AUDIO_OUTPUT_FLAG_HBBTV) {
scene = MEDIA_AUDIO_WORK_MM;
mediasync_wrap_setParameter(mediasync_ctx->handle, MEDIASYNC_KEY_AV_WORK_SCENARIO, &scene);
} else if (out->source_type == DTV_SRC) {
scene = MEDIA_AUDIO_WORK_DTV;
mediasync_wrap_setParameter(mediasync_ctx->handle, MEDIASYNC_KEY_AV_WORK_SCENARIO, &scene);
}
aml_audio_pcm_out_get_alsa_status(aml_dev, &alsa_status);
mediasync_wrap_setParameter(mediasync_ctx->handle, MEDIASYNC_KEY_ALSAREADY, &alsa_status);
aml_audio_pcm_out_clear_alsa_status_changed_flag(aml_dev);
out->output_speed = 1.0f;
*sync_enable = ret_set_id ? 1 : 0;
if (out->tv_src_stream && DTV_SRC == out->source_type) {
out->with_header = false;
} else {
out->with_header = true;
}
out->avsync_ctx->get_tuning_latency = get_latency_pts;
AM_LOGI("The current sync type: MediaSync %d,%d,%x, mediasync_handle:%p, out->with_header:%d, alsa_status %d",
*sync_enable, hw_sync_id, format, mediasync_ctx->handle, out->with_header, alsa_status);
pthread_mutex_unlock(&(out->avsync_ctx->lock));
return 0;
}