331 lines
15 KiB
C
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;
|
|
}
|
|
|