You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
827 lines
21 KiB
827 lines
21 KiB
/*
|
|
* Copyright (c) Hisilicon Technologies Co., Ltd. 2019-2019. All rights reserved.
|
|
* Description: MPI function file for Huanglong audio vir capture
|
|
* Author: audio
|
|
* Create: 2019-05-30
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <unistd.h>
|
|
#include <pthread.h>
|
|
|
|
#include "mpi_ao_debug.h"
|
|
#include "mpi_ao_vir.h"
|
|
|
|
#include "securec.h"
|
|
#include "mpi_memory_ext.h"
|
|
#include "soc_math.h"
|
|
|
|
#ifdef __cplusplus
|
|
#if __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
#endif /* __cplusplus */
|
|
|
|
#define virtrack_lock(mutex) (td_void)pthread_mutex_lock(&(mutex))
|
|
#define virtrack_unlock(mutex) (td_void)pthread_mutex_unlock(&(mutex))
|
|
#define VIR_BUF_PCM_SAMPLES_NUMBER 1024
|
|
|
|
#define VT_INVALID_PTS 0xffffffff
|
|
#define MS_TO_US_RATE 1000
|
|
#define pts_us_to_ms(pts) (td_u32)((pts) / MS_TO_US_RATE)
|
|
#define pts_ms_to_us(pts) ((td_s64)(pts) * MS_TO_US_RATE)
|
|
|
|
static inline td_u32 vt_input_pts(td_s64 pts)
|
|
{
|
|
return ((pts < 0) || (pts == TD_INVALID_PTS)) ? VT_INVALID_PTS : pts_us_to_ms(pts);
|
|
}
|
|
|
|
static inline td_s64 vt_output_pts(td_u32 pts)
|
|
{
|
|
return (pts == VT_INVALID_PTS) ? TD_INVALID_PTS : pts_ms_to_us(pts);
|
|
}
|
|
|
|
typedef struct {
|
|
pthread_mutex_t mutex;
|
|
td_u32 track_flag;
|
|
td_void *track[AO_MAX_VIRTUAL_TRACK_NUM];
|
|
} vir_track_rs_state;
|
|
|
|
static vir_track_rs_state g_vir_track = {
|
|
.mutex = PTHREAD_MUTEX_INITIALIZER,
|
|
.track_flag = 0,
|
|
};
|
|
|
|
/* add x and y, saturate to saturation */
|
|
static inline td_u32 saturate_add(td_u32 x, td_u32 y, td_u32 saturation)
|
|
{
|
|
td_u32 res = x + y;
|
|
|
|
return (res >= saturation) ? (res - saturation) : res;
|
|
}
|
|
|
|
static inline td_u32 vir_track_buf_size(const vir_buffer *buf)
|
|
{
|
|
return buf->end - buf->start;
|
|
}
|
|
|
|
static inline td_u32 vir_track_buf_data_size(const vir_buffer *buf)
|
|
{
|
|
td_u32 size = vir_track_buf_size(buf);
|
|
|
|
return (buf->write >= buf->read) ? (buf->write - buf->read) : (size - buf->read + buf->write);
|
|
}
|
|
|
|
static inline td_u32 vir_track_buf_free_size(const vir_buffer *buf)
|
|
{
|
|
return vir_track_buf_size(buf) - vir_track_buf_data_size(buf);
|
|
}
|
|
|
|
static td_u32 vir_track_buf_write_data(const vir_buffer *buf, const td_u8 *from,
|
|
td_u32 len, td_u32 off)
|
|
{
|
|
errno_t ret;
|
|
td_u32 size = vir_track_buf_size(buf);
|
|
td_u32 l = min2(len, size - off);
|
|
|
|
ret = memcpy_s(buf->buf_base + off, size - off, from, l);
|
|
if (ret != EOK) {
|
|
return 0;
|
|
}
|
|
|
|
if (len - l == 0) {
|
|
return len;
|
|
}
|
|
|
|
ret = memcpy_s(buf->buf_base, buf->read, from + l, len - l);
|
|
if (ret != EOK) {
|
|
return 0;
|
|
}
|
|
|
|
return len;
|
|
}
|
|
|
|
static td_u32 vir_track_buf_write(vir_buffer *buf, const td_u8 *from, td_u32 len)
|
|
{
|
|
if (vir_track_buf_write_data(buf, from, len, buf->write) != len) {
|
|
return 0;
|
|
}
|
|
|
|
buf->write = saturate_add(buf->write, len, vir_track_buf_size(buf));
|
|
return len;
|
|
}
|
|
|
|
static td_u32 ao_frame_pcm_data_size(const ext_ao_frame *ao_frame)
|
|
{
|
|
if (ao_frame->bit_depth == EXT_BIT_DEPTH_16) {
|
|
return ao_frame->pcm_samples * ao_frame->channels * sizeof(td_s16);
|
|
} else {
|
|
return ao_frame->pcm_samples * ao_frame->channels * sizeof(td_s32);
|
|
}
|
|
}
|
|
|
|
static td_void vt_mutex_lock(td_void)
|
|
{
|
|
if (pthread_mutex_lock(&g_vir_track.mutex) != 0) {
|
|
soc_log_err("Lock mutex failed\n");
|
|
}
|
|
}
|
|
|
|
static td_void vt_mutex_unlock(td_void)
|
|
{
|
|
if (pthread_mutex_unlock(&g_vir_track.mutex) != 0) {
|
|
soc_log_err("Unlock mutex failed\n");
|
|
}
|
|
}
|
|
|
|
static td_void vt_free(td_void *buf)
|
|
{
|
|
if (buf == TD_NULL) {
|
|
return;
|
|
}
|
|
|
|
free(buf);
|
|
}
|
|
|
|
static td_void *vt_malloc(td_u32 size)
|
|
{
|
|
td_s32 ret;
|
|
td_void *buffer = TD_NULL;
|
|
|
|
if (size == 0) {
|
|
soc_log_err("invalid size\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
buffer = malloc(size);
|
|
if (buffer == TD_NULL) {
|
|
soc_log_err("call malloc( failed\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
ret = memset_s(buffer, size, 0, size);
|
|
if (ret != EOK) {
|
|
soc_err_print_call_fun_err(memset_s, ret);
|
|
free(buffer);
|
|
return TD_NULL;
|
|
}
|
|
|
|
return buffer;
|
|
}
|
|
|
|
static td_void vir_reset_pts_que(vir_pts_que *pts_que)
|
|
{
|
|
pts_que->read = 0;
|
|
pts_que->write = 0;
|
|
pts_que->last_pts_ms = VT_INVALID_PTS;
|
|
}
|
|
|
|
static td_void vir_find_pts(const vir_buffer *buf, td_u32 *p_found_pts, td_u32 *p_found_pos)
|
|
{
|
|
td_u32 found_pos;
|
|
td_u32 found_pts = VT_INVALID_PTS;
|
|
td_u32 read_ptr = buf->read;
|
|
const vir_pts_que *pts_que = &(buf->pts_que);
|
|
const vir_pts *pts = pts_que->pts_arry;
|
|
td_u32 rd_pos = pts_que->read;
|
|
td_u32 wt_pos = pts_que->write;
|
|
|
|
for (found_pos = rd_pos; found_pos != wt_pos; found_pos = (found_pos + 1) % VIR_MAX_STORED_PTS_NUM) {
|
|
if (pts[found_pos].beg_ptr < pts[found_pos].end_ptr) {
|
|
if ((pts[found_pos].beg_ptr <= read_ptr) && (pts[found_pos].end_ptr >= read_ptr)) {
|
|
found_pts = pts[found_pos].pts_ms;
|
|
break;
|
|
}
|
|
} else {
|
|
if ((pts[found_pos].beg_ptr <= read_ptr) || (pts[found_pos].end_ptr >= read_ptr)) {
|
|
found_pts = pts[found_pos].pts_ms;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (found_pos == wt_pos) {
|
|
found_pos = (td_u32)-1;
|
|
}
|
|
|
|
*p_found_pos = found_pos;
|
|
*p_found_pts = found_pts;
|
|
}
|
|
|
|
static td_u32 vir_acquire_pts(const vir_buffer *buf, td_u32 pcm_samples,
|
|
td_u32 pcm_sample_rate)
|
|
{
|
|
td_u32 pts_ms = VT_INVALID_PTS;
|
|
td_u32 found_pos = 0;
|
|
td_u32 found_pts = 0;
|
|
const vir_pts_que *pts_que = &buf->pts_que;
|
|
|
|
vir_find_pts(buf, &found_pts, &found_pos);
|
|
|
|
if (found_pts != VT_INVALID_PTS) {
|
|
return found_pts;
|
|
}
|
|
|
|
/* can not find a valid PTS */
|
|
if (pts_que->last_pts_ms != VT_INVALID_PTS) {
|
|
td_u32 delta;
|
|
|
|
if (pcm_sample_rate == 0) {
|
|
return VT_INVALID_PTS;
|
|
}
|
|
|
|
delta = (pcm_samples * 1000) / pcm_sample_rate; /* this 1000 for s to ms */
|
|
pts_ms = pts_que->last_pts_ms + delta;
|
|
if (pts_ms == VT_INVALID_PTS) {
|
|
pts_ms = 0;
|
|
}
|
|
}
|
|
|
|
return pts_ms;
|
|
}
|
|
|
|
static td_void vir_release_pts(vir_buffer *buf, td_u32 pts_ms)
|
|
{
|
|
td_u32 found_pos = 0;
|
|
td_u32 found_pts = VT_INVALID_PTS;
|
|
vir_pts_que *pts_que = &buf->pts_que;
|
|
vir_pts *pts = pts_que->pts_arry;
|
|
|
|
pts_que->last_pts_ms = pts_ms;
|
|
vir_find_pts(buf, &found_pts, &found_pos);
|
|
|
|
if (found_pos < VIR_MAX_STORED_PTS_NUM) {
|
|
pts[found_pos].pts_ms = VT_INVALID_PTS;
|
|
pts_que->read = (found_pos + 1) % VIR_MAX_STORED_PTS_NUM;
|
|
}
|
|
}
|
|
|
|
static td_void vir_store_pts(vir_buffer *buf, td_u32 pts_ms, td_u32 size)
|
|
{
|
|
vir_pts_que *pts_que = &(buf->pts_que);
|
|
vir_pts *pts_array = pts_que->pts_arry;
|
|
td_u32 calc_end_ptr;
|
|
|
|
/* make sure there are space to store */
|
|
if ((pts_que->write + 1) % VIR_MAX_STORED_PTS_NUM == pts_que->read) {
|
|
soc_log_warn("not enough PTS buffer, discard current PTS(%d)\n", pts_ms);
|
|
return;
|
|
}
|
|
|
|
if ((buf->write + size) < buf->end) {
|
|
calc_end_ptr = buf->write + size;
|
|
} else {
|
|
calc_end_ptr = (((buf->write) + size) - ((buf->end) - (buf->start)));
|
|
}
|
|
|
|
pts_array[pts_que->write].pts_ms = pts_ms;
|
|
pts_array[pts_que->write].beg_ptr = buf->write;
|
|
pts_array[pts_que->write].end_ptr = calc_end_ptr;
|
|
pts_que->write = (pts_que->write + 1) % VIR_MAX_STORED_PTS_NUM;
|
|
}
|
|
|
|
static td_s32 vir_init_buf(vir_buffer *buf, td_u32 size)
|
|
{
|
|
if ((size < VIR_MIN_OUTBUF_SIZE) || (size > VIR_MAX_OUTBUF_SIZE)) {
|
|
soc_log_err(" invalid input buffer size(%d) minsize(%d) maxsize(%d)!\n", size,
|
|
VIR_MIN_OUTBUF_SIZE, VIR_MAX_OUTBUF_SIZE);
|
|
return SOC_ERR_AO_INVALID_PARA;
|
|
}
|
|
|
|
buf->buf_base = (td_u8 *)vt_malloc(size + VIR_MAX_FRAME_SIZE);
|
|
if (buf->buf_base == TD_NULL) {
|
|
soc_log_fatal("vt_malloc failed\n");
|
|
return SOC_ERR_AO_MALLOC_FAILED;
|
|
}
|
|
|
|
buf->start = 0;
|
|
buf->end = size;
|
|
buf->read = 0;
|
|
buf->write = 0;
|
|
buf->bit_depth = EXT_BIT_DEPTH_16;
|
|
buf->sample_rate = EXT_SAMPLE_RATE_48K;
|
|
buf->channel = EXT_AUDIO_CH_STEREO;
|
|
buf->pcm_samples = VIR_BUF_PCM_SAMPLES_NUMBER;
|
|
|
|
vir_reset_pts_que(&buf->pts_que);
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_void vir_deinit_buf(vir_buffer *buf)
|
|
{
|
|
if (buf->buf_base != TD_NULL) {
|
|
vt_free(buf->buf_base);
|
|
buf->buf_base = TD_NULL;
|
|
}
|
|
|
|
vt_free(buf);
|
|
}
|
|
|
|
static td_void vir_flush_buf(vir_buffer *buf)
|
|
{
|
|
buf->write = buf->read;
|
|
vir_reset_pts_que(&(buf->pts_que));
|
|
}
|
|
|
|
static td_u32 vir_get_free_id(td_void)
|
|
{
|
|
td_u32 i;
|
|
|
|
for (i = 0; i < AO_MAX_VIRTUAL_TRACK_NUM; i++) {
|
|
if (!((g_vir_track.track_flag & ((td_u32)1L << i)) != 0)) {
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return AO_MAX_VIRTUAL_TRACK_NUM;
|
|
}
|
|
|
|
static td_u32 vir_track2_vir_id(td_handle h_track)
|
|
{
|
|
return ((h_track & AO_TRACK_CHNID_MASK) - AO_MAX_REAL_TRACK_NUM);
|
|
}
|
|
|
|
static vir_track_state *vir_track_find_by_handle(td_handle h_track)
|
|
{
|
|
td_u32 id;
|
|
vir_track_state *track = TD_NULL;
|
|
|
|
id = vir_track2_vir_id(h_track);
|
|
if (id >= AO_MAX_VIRTUAL_TRACK_NUM) {
|
|
soc_log_err("invalid virtual track ID!\n");
|
|
return TD_NULL;
|
|
}
|
|
|
|
track = (vir_track_state *)g_vir_track.track[id];
|
|
if ((track == TD_NULL) || (track->buf == TD_NULL)) {
|
|
soc_log_err("virtual track(%d) is null!\n", id);
|
|
return TD_NULL;
|
|
}
|
|
|
|
return track;
|
|
}
|
|
|
|
td_void vir_init_rs(td_void)
|
|
{
|
|
td_u32 i;
|
|
|
|
vt_mutex_lock();
|
|
|
|
g_vir_track.track_flag = 0;
|
|
|
|
for (i = 0; i < AO_MAX_VIRTUAL_TRACK_NUM; i++) {
|
|
g_vir_track.track[i] = TD_NULL;
|
|
}
|
|
|
|
vt_mutex_unlock();
|
|
}
|
|
|
|
td_void vir_de_init_rs(td_void)
|
|
{
|
|
td_u32 i;
|
|
|
|
vt_mutex_lock();
|
|
|
|
g_vir_track.track_flag = 0;
|
|
|
|
for (i = 0; i < AO_MAX_VIRTUAL_TRACK_NUM; i++) {
|
|
g_vir_track.track[i] = TD_NULL;
|
|
}
|
|
|
|
vt_mutex_unlock();
|
|
}
|
|
|
|
static td_s32 virtual_track_state_init(const ext_ao_track_attr *track_attr, vir_track_state *vir)
|
|
{
|
|
td_s32 ret;
|
|
|
|
ret = memcpy_s(&vir->track_attr, sizeof(vir->track_attr),
|
|
track_attr, sizeof(*track_attr));
|
|
if (ret != EOK) {
|
|
soc_err_print_call_fun_err(memcpy_s, ret);
|
|
return ret;
|
|
}
|
|
|
|
vir->buf_size = track_attr->output_buf_size;
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 virtual_track_buf_init(vir_track_state *vir)
|
|
{
|
|
td_s32 ret;
|
|
|
|
vir->buf = (vir_buffer *)vt_malloc(sizeof(vir_buffer));
|
|
if (vir->buf == TD_NULL) {
|
|
return SOC_ERR_AO_MALLOC_FAILED;
|
|
}
|
|
|
|
ret = vir_init_buf(vir->buf, vir->buf_size);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_err_print_call_fun_err(vir_init_buf, ret);
|
|
goto out;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
|
|
out:
|
|
vt_free(vir->buf);
|
|
return ret;
|
|
}
|
|
|
|
static td_s32 virtual_track_create(const ext_ao_track_attr *track_attr, td_handle *ph_track)
|
|
{
|
|
td_s32 ret;
|
|
vir_track_state *vir = TD_NULL;
|
|
td_u32 vir_id;
|
|
|
|
vir_id = vir_get_free_id();
|
|
if (vir_id == AO_MAX_VIRTUAL_TRACK_NUM) {
|
|
soc_log_err("vir_get_free_id failed\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
vir = (vir_track_state *)vt_malloc(sizeof(vir_track_state));
|
|
if (vir == TD_NULL) {
|
|
soc_log_err("vt_malloc failed\n");
|
|
return SOC_ERR_AO_MALLOC_FAILED;
|
|
}
|
|
|
|
ret = virtual_track_state_init(track_attr, vir);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_err_print_call_fun_err(virtual_track_state_init, ret);
|
|
goto out0;
|
|
}
|
|
|
|
ret = virtual_track_buf_init(vir);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_err_print_call_fun_err(virtual_track_buf_init, ret);
|
|
goto out0;
|
|
}
|
|
|
|
g_vir_track.track_flag |= (td_u32)1L << vir_id;
|
|
g_vir_track.track[vir_id] = (td_void *)vir;
|
|
|
|
*ph_track = (SOC_ID_AO << 16) | /* this 16 is shift number */
|
|
(SOC_ID_MASTER_SLAVE_TRACK << 8) | /* this 8 is shift number */
|
|
(AO_MAX_REAL_TRACK_NUM + vir_id);
|
|
|
|
return TD_SUCCESS;
|
|
|
|
out0:
|
|
vt_free(vir);
|
|
return ret;
|
|
}
|
|
|
|
td_s32 vir_create_track(const ext_ao_track_attr *track_attr, td_handle *track)
|
|
{
|
|
td_s32 ret;
|
|
|
|
check_ao_null_ptr(track);
|
|
check_ao_null_ptr(track_attr);
|
|
|
|
vt_mutex_lock();
|
|
ret = virtual_track_create(track_attr, track);
|
|
vt_mutex_unlock();
|
|
if (ret != TD_SUCCESS) {
|
|
soc_err_print_call_fun_err(virtual_track_create, ret);
|
|
return ret;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
td_s32 vir_destroy_track(td_handle track)
|
|
{
|
|
vir_track_state *vir = TD_NULL;
|
|
td_u32 vir_id;
|
|
|
|
check_track(track);
|
|
|
|
vt_mutex_lock();
|
|
|
|
vir_id = vir_track2_vir_id(track);
|
|
if (vir_id >= AO_MAX_VIRTUAL_TRACK_NUM) {
|
|
soc_log_err("invalid virtual track ID!\n");
|
|
vt_mutex_unlock();
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
vir = (vir_track_state *)g_vir_track.track[vir_id];
|
|
if (vir == TD_NULL) {
|
|
soc_log_err("virtual track(%d) is null!\n", vir_id);
|
|
vt_mutex_unlock();
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
if (vir->buf != TD_NULL) {
|
|
vir_deinit_buf(vir->buf);
|
|
vir->buf = TD_NULL;
|
|
}
|
|
|
|
vt_free(vir);
|
|
g_vir_track.track[vir_id] = TD_NULL;
|
|
g_vir_track.track_flag &= ~((td_u32)1L << vir_id);
|
|
|
|
vt_mutex_unlock();
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 vir_track_get_attr(td_handle h_track, ext_ao_track_attr *attr)
|
|
{
|
|
td_s32 ret;
|
|
vir_track_state *track = TD_NULL;
|
|
|
|
track = vir_track_find_by_handle(h_track);
|
|
if (track == TD_NULL) {
|
|
soc_log_err("Call vir_track_find_by_handle failed\n");
|
|
return SOC_ERR_AO_INVALID_PARA;
|
|
}
|
|
|
|
ret = memcpy_s(attr, sizeof(*attr),
|
|
&track->track_attr, sizeof(ext_ao_track_attr));
|
|
if (ret != EOK) {
|
|
soc_err_print_call_fun_err(memcpy_s, ret);
|
|
return ret;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
td_s32 vir_get_attr(td_handle track, ext_ao_track_attr *attr)
|
|
{
|
|
td_s32 ret;
|
|
|
|
check_track(track);
|
|
|
|
vt_mutex_lock();
|
|
ret = vir_track_get_attr(track, attr);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_err_print_call_fun_err(vir_track_get_attr, ret);
|
|
}
|
|
vt_mutex_unlock();
|
|
return ret;
|
|
}
|
|
|
|
static td_bool ao_frame_not_change(const ext_ao_frame *ao_frame, const vir_buffer *buf)
|
|
{
|
|
return (buf->channel == ao_frame->channels) &&
|
|
(buf->bit_depth == ao_frame->bit_depth) &&
|
|
(buf->sample_rate == ao_frame->sample_rate);
|
|
}
|
|
|
|
static td_void vir_track_check_ao_frame(const ext_ao_frame *ao_frame, vir_buffer *buf)
|
|
{
|
|
if (ao_frame_not_change(ao_frame, buf) == TD_TRUE) {
|
|
return;
|
|
}
|
|
|
|
/* channel, sample rate or bit depth changed, reset track buffer */
|
|
vir_flush_buf(buf);
|
|
buf->channel = ao_frame->channels;
|
|
buf->bit_depth = ao_frame->bit_depth;
|
|
buf->sample_rate = ao_frame->sample_rate;
|
|
}
|
|
|
|
static td_s32 vir_track_convert_ao_frame(const ext_ao_frame *ao_frame_in, ext_ao_frame *ao_frame_out)
|
|
{
|
|
td_s32 ret;
|
|
|
|
ret = memcpy_s(ao_frame_out, sizeof(*ao_frame_out),
|
|
ao_frame_in, sizeof(*ao_frame_in));
|
|
if (ret != EOK) {
|
|
soc_err_print_call_fun_err(memcpy_s, ret);
|
|
return ret;
|
|
}
|
|
|
|
if (ao_frame_out->pcm_samples == 0) {
|
|
soc_log_warn("no pcm data in ao frame\n");
|
|
return SOC_ERR_AO_NOTSUPPORT;
|
|
}
|
|
|
|
if (ao_frame_out->sample_rate == 0) {
|
|
soc_log_warn("invalid sample rate in ao frame\n");
|
|
return SOC_ERR_AO_INVALID_INFRAME;
|
|
}
|
|
|
|
ao_frame_out->channels = min2(ao_frame_out->channels, EXT_AUDIO_CH_STEREO);
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 vir_track_save_ao_frame_data(vir_buffer *buf, const ext_ao_frame *ao_frame)
|
|
{
|
|
td_u32 size;
|
|
|
|
size = ao_frame_pcm_data_size(ao_frame);
|
|
if (vir_track_buf_free_size(buf) <= size) {
|
|
soc_log_info("track buf is full\n");
|
|
return SOC_ERR_AO_OUT_BUF_FULL;
|
|
}
|
|
|
|
if (vir_track_buf_write(buf, (td_u8 *)ao_frame->pcm_buffer, size) != size) {
|
|
soc_log_err("call vir_track_buf_write failed\n");
|
|
return TD_FAILURE;
|
|
}
|
|
|
|
vir_store_pts(buf, vt_input_pts(ao_frame->pts), size);
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 vir_track_send_data(td_handle h_track, const ext_ao_frame *ao_frame)
|
|
{
|
|
td_s32 ret;
|
|
ext_ao_frame frame;
|
|
vir_track_state *track = TD_NULL;
|
|
|
|
track = vir_track_find_by_handle(h_track);
|
|
if (track == TD_NULL) {
|
|
soc_log_err("Call vir_track_find_by_handle failed\n");
|
|
return SOC_ERR_AO_INVALID_PARA;
|
|
}
|
|
|
|
check_ao_null_ptr(track->buf);
|
|
|
|
ret = vir_track_convert_ao_frame(ao_frame, &frame);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_warn_print_call_fun_err(vir_track_convert_ao_frame, ret);
|
|
return ret;
|
|
}
|
|
|
|
vir_track_check_ao_frame(&frame, track->buf);
|
|
|
|
return vir_track_save_ao_frame_data(track->buf, &frame);
|
|
}
|
|
|
|
td_s32 vir_send_data(td_handle track, const ext_ao_frame *ao_frame)
|
|
{
|
|
td_s32 ret;
|
|
|
|
check_track(track);
|
|
vt_mutex_lock();
|
|
ret = vir_track_send_data(track, ao_frame);
|
|
vt_mutex_unlock();
|
|
|
|
return ret;
|
|
}
|
|
|
|
static td_void vir_track_init_ao_frame(const vir_buffer *buf, ext_ao_frame *ao_frame)
|
|
{
|
|
ao_frame->sample_rate = buf->sample_rate;
|
|
ao_frame->bit_depth = buf->bit_depth;
|
|
ao_frame->channels = buf->channel;
|
|
ao_frame->pcm_samples = buf->pcm_samples;
|
|
ao_frame->pcm_buffer = TD_NULL;
|
|
ao_frame->pts = TD_INVALID_PTS;
|
|
|
|
ao_frame->interleaved = TD_TRUE;
|
|
ao_frame->frame_index = 0;
|
|
ao_frame->bits_bytes = 0;
|
|
ao_frame->bits_buffer = TD_NULL;
|
|
ao_frame->iec_data_type = 0;
|
|
}
|
|
|
|
static td_s32 vir_track_build_linear_frame(const vir_buffer *buf, td_u32 acquire_size)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 tail_size;
|
|
|
|
if (buf->write >= buf->read) {
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
tail_size = buf->end - buf->read;
|
|
if (acquire_size <= tail_size) {
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
ret = memcpy_s(buf->buf_base + buf->end, VIR_MAX_FRAME_SIZE,
|
|
buf->buf_base + buf->start, acquire_size - tail_size);
|
|
if (ret != EOK) {
|
|
soc_err_print_call_fun_err(memcpy_s, ret);
|
|
return ret;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 vir_track_acquire_data(const vir_buffer *buf, ext_ao_frame *ao_frame)
|
|
{
|
|
td_s32 ret;
|
|
td_u32 acquire_size;
|
|
td_u32 pts_ms;
|
|
|
|
check_ao_null_ptr(buf->buf_base);
|
|
|
|
acquire_size = ao_frame_pcm_data_size(ao_frame);
|
|
if (vir_track_buf_data_size(buf) < acquire_size) {
|
|
return SOC_ERR_AO_VIRTUALBUF_EMPTY;
|
|
}
|
|
|
|
ao_frame->pcm_buffer = (td_s32 *)(buf->buf_base + (buf->read - buf->start));
|
|
|
|
ret = vir_track_build_linear_frame(buf, acquire_size);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_err_print_call_fun_err(vir_track_build_linear_frame, ret);
|
|
return ret;
|
|
}
|
|
|
|
pts_ms = vir_acquire_pts(buf, ao_frame->pcm_samples, ao_frame->sample_rate);
|
|
ao_frame->pts = vt_output_pts(pts_ms);
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 vir_track_acquire_frame(td_handle h_track, ext_ao_frame *ao_frame)
|
|
{
|
|
td_s32 ret;
|
|
vir_track_state *track = TD_NULL;
|
|
|
|
track = vir_track_find_by_handle(h_track);
|
|
if (track == TD_NULL) {
|
|
soc_log_err("Call vir_track_find_by_handle failed\n");
|
|
return SOC_ERR_AO_INVALID_PARA;
|
|
}
|
|
|
|
check_ao_null_ptr(track->buf);
|
|
|
|
vir_track_init_ao_frame(track->buf, ao_frame);
|
|
|
|
ret = vir_track_acquire_data(track->buf, ao_frame);
|
|
if (ret != TD_SUCCESS) {
|
|
soc_warn_print_call_fun_err(vir_track_acquire_data, ret);
|
|
return ret;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
td_s32 vir_acquire_frame(td_handle track, ext_ao_frame *ao_frame)
|
|
{
|
|
td_s32 ret;
|
|
|
|
check_track(track);
|
|
|
|
vt_mutex_lock();
|
|
ret = vir_track_acquire_frame(track, ao_frame);
|
|
vt_mutex_unlock();
|
|
if (ret != TD_SUCCESS) {
|
|
soc_warn_print_call_fun_err(vir_track_acquire_frame, ret);
|
|
return ret;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
static td_s32 vir_track_release_frame(td_handle h_track, const ext_ao_frame *ao_frame)
|
|
{
|
|
vir_track_state *track = TD_NULL;
|
|
vir_buffer *buf = TD_NULL;
|
|
|
|
track = vir_track_find_by_handle(h_track);
|
|
if (track == TD_NULL) {
|
|
soc_log_err("Call vir_track_find_by_handle failed\n");
|
|
return SOC_ERR_AO_INVALID_PARA;
|
|
}
|
|
|
|
buf = track->buf;
|
|
check_ao_null_ptr(buf);
|
|
|
|
if ((buf->channel != ao_frame->channels) ||
|
|
(buf->bit_depth != ao_frame->bit_depth) ||
|
|
(buf->sample_rate != ao_frame->sample_rate)) {
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
vir_release_pts(buf, vt_input_pts(ao_frame->pts));
|
|
|
|
buf->read = saturate_add(buf->read, ao_frame_pcm_data_size(ao_frame),
|
|
vir_track_buf_size(buf));
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
td_s32 vir_release_frame(td_handle track, const ext_ao_frame *ao_frame)
|
|
{
|
|
td_s32 ret;
|
|
|
|
check_track(track);
|
|
|
|
vt_mutex_lock();
|
|
ret = vir_track_release_frame(track, ao_frame);
|
|
vt_mutex_unlock();
|
|
if (ret != TD_SUCCESS) {
|
|
soc_err_print_call_fun_err(vir_track_release_frame, ret);
|
|
return ret;
|
|
}
|
|
|
|
return TD_SUCCESS;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
#if __cplusplus
|
|
}
|
|
#endif
|
|
#endif /* __cplusplus */
|