luckfox-pico-sdk/sysdrv/source/mcu/rt-thread/components/aupipe/basics/filesrc.c
luckfox-eng29 8f34c2760d project:build.sh: Added fastboot support; custom modifications to U-Boot and kernel implemented using patches.
project:cfg:BoardConfig_IPC: Added fastboot BoardConfig file and firmware post-scripts, distinguishing between
the BoardConfigs for Luckfox Pico Pro and Luckfox Pico Max. project:app: Added fastboot_client and rk_smart_door
for quick boot applications; updated rkipc app to adapt to the latest media library. media:samples: Added more
usage examples. media:rockit: Fixed bugs; removed support for retrieving data frames from VPSS. media:isp:
Updated rkaiq library and related tools to support connection to RKISP_Tuner. sysdrv:Makefile: Added support for
compiling drv_ko on Luckfox Pico Ultra W using Ubuntu; added support for custom root filesystem.
sysdrv:tools:board: Updated Buildroot optional mirror sources, updated some software versions, and stored device
tree files and configuration files that undergo multiple modifications for U-Boot and kernel separately.
sysdrv:source:mcu: Used RISC-V MCU SDK with RT-Thread system, mainly for initializing camera AE during quick
boot. sysdrv:source:uboot: Added support for fastboot; added high baud rate DDR bin for serial firmware upgrades.
sysdrv:source:kernel: Upgraded to version 5.10.160; increased NPU frequency for RV1106G3; added support for
fastboot.

Signed-off-by: luckfox-eng29 <eng29@luckfox.com>
2024-10-14 09:47:04 +08:00

304 lines
7.5 KiB
C

/**
* Copyright (c) 2023 Rockchip Electronics Co., Ltd
*
* SPDX-License-Identifier: Apache-2.0
******************************************************************************
* @file filesrc.c
* @author Jun Zeng
* @version V0.1
* @date 10-03-2023
* @brief filesrc for rksoc
*
******************************************************************************
*/
#include "aupipe.h"
#ifdef RT_USING_AUPIPE_FILESRC
#include "drv_heap.h"
#include "rk_audio.h"
#undef DBG_SECTION_NAME
#define DBG_SECTION_NAME "FILESRC"
#define ID_RIFF 0x46464952
#define ID_WAVE 0x45564157
#define ID_FMT 0x20746d66
#define ID_DATA 0x61746164
#define FILESRC(obj) ((ApFileSrc *)(obj))
typedef struct riff_chunk
{
uint32_t chunk_id;
uint32_t chunk_size;
uint32_t format;
} RiffChunk;
typedef struct sub_chunk
{
uint32_t chunk_id;
uint32_t chunk_size;
} SubChunk;
typedef struct fmt_chunk
{
uint16_t audio_format;
uint16_t num_channels;
uint32_t sample_rate;
uint32_t byte_rate;
uint16_t block_align;
uint16_t bits_per_sample;
} FmtChunk;
typedef struct filesrc_object
{
ApObject base;
ApPad *src_pad;
int offset;
int channels;
int samplebits;
int samplerate;
rt_sem_t sem;
rt_thread_t loop;
int loop_running;
FILE *fp;
SubChunk sub_chunk;
FmtChunk fmt_chunk;
RiffChunk riff_chunk;
} ApFileSrc;
static int filesrc_init(ApObject *obj, void *arg)
{
ApFileSrc *object = FILESRC(obj);
int status = 0;
int more_chunks = 1;
char *filename = NULL;
char *parameters = (char *)arg;
Aupipe *aupipe = obj->parent;
status |= aupipe_find_property(parameters, "filename",
VALUE_TYPE_STRING, &filename);
status |= aupipe_find_property(parameters, "channels",
VALUE_TYPE_INT, &object->channels);
if (status != RT_EOK)
{
LOG_E("%s plug-in parameter initialization failed", object->base.name);
return -RT_ERROR;
}
object->fp = fopen(filename, "rb");
if (!object->fp)
{
rt_kprintf("Unable to open file %s\n", filename);
return -RT_ERROR;
}
fread(&object->riff_chunk, sizeof(RiffChunk), 1, object->fp);
if ((object->riff_chunk.chunk_id != ID_RIFF) ||
(object->riff_chunk.format != ID_WAVE))
{
object->offset = 0;
fseek(object->fp, 0, SEEK_SET);
object->samplebits = aupipe->bits;
object->samplerate = aupipe->rate;
}
else
{
do
{
fread(&object->sub_chunk, sizeof(SubChunk), 1, object->fp);
switch (object->sub_chunk.chunk_id)
{
case ID_FMT:
fread(&object->fmt_chunk, sizeof(FmtChunk), 1, object->fp);
/* If the format header is larger, skip the rest */
if (object->sub_chunk.chunk_size > sizeof(FmtChunk))
fseek(object->fp, object->sub_chunk.chunk_size - sizeof(FmtChunk), SEEK_CUR);
break;
case ID_DATA:
/* Stop looking for chunks */
more_chunks = 0;
break;
default:
/* Unknown chunk, skip bytes */
fseek(object->fp, object->sub_chunk.chunk_size, SEEK_CUR);
}
}
while (more_chunks);
object->offset = ftell(object->fp);
object->channels = object->fmt_chunk.num_channels;
object->samplerate = object->fmt_chunk.sample_rate;
if (object->samplerate != aupipe->rate)
{
LOG_E("Music file samplerate does not match the aupipe samplerate");
return -RT_ERROR;
}
object->samplebits = object->fmt_chunk.bits_per_sample;
if (object->samplebits != aupipe->bits)
{
LOG_E("Music file samplebits does not match the aupipe samplebits");
return -RT_ERROR;
}
}
object->src_pad = aupipe_pad_new(obj, object->channels);
RT_ASSERT(object->src_pad != NULL);
object->sem = rt_sem_create("filesrc", 0, RT_IPC_FLAG_FIFO);
RT_ASSERT(object->sem != NULL);
rt_free(filename);
return RT_EOK;
}
static int filesrc_deinit(ApObject *obj)
{
ApFileSrc *object = FILESRC(obj);
fclose(object->fp);
rt_free(object->src_pad);
rt_sem_delete(object->sem);
return RT_EOK;
}
static void do_playfile(void *arg)
{
ApFileSrc *obj = FILESRC(arg);
Aupipe *aupipe = obj->base.parent;
int read_byte = 0;
int bit_width = obj->samplebits >> 3;
int period_byte = aupipe->period_size * bit_width;
int total_period_byte = period_byte * obj->channels;
char *file_buffer = rt_malloc(total_period_byte);
while (obj->loop_running)
{
read_byte = fread(file_buffer, 1, total_period_byte, obj->fp);
if (read_byte < total_period_byte)
{
memset(file_buffer + read_byte, 0x00, (total_period_byte - read_byte));
fseek(obj->fp, obj->offset, SEEK_SET);
}
for (int i = 0; i < obj->channels; i++)
{
if (obj->src_pad[i].peer == RT_NULL)
continue;
ApBuffer *buffer = aupipe_buffer_new(DATA_TYPE_AUDIO, period_byte);
if (!buffer)
{
LOG_E("%s malloc %d failed", obj->base.name, period_byte);
break;
}
for (int j = 0; j < aupipe->period_size; j++)
{
rt_memcpy(buffer->data + bit_width * j, file_buffer +
bit_width * (obj->channels * j + i), bit_width);
}
buffer = aupipe_buffer_ref(buffer);
aupipe_pad_push(&obj->src_pad[i], buffer);
}
}
rt_free(file_buffer);
rt_sem_release(obj->sem);
obj->loop_running = 0;
}
static int filesrc_set_state(ApObject *obj, int state)
{
ApFileSrc *object = FILESRC(obj);
switch (state)
{
case STATE_NULL_TO_READY:
LOG_I("STATE_NULL_TO_READY");
object->loop = rt_thread_create("filesrc", do_playfile, object,
4096, RT_THREAD_PRIORITY_MAX / 2, 10);
if (!object->loop)
{
LOG_E("do_playfile thread create failed");
return -RT_ERROR;
}
break;
case STATE_PAUSED_TO_PLAYING:
LOG_I("STATE_PAUSED_TO_PLAYING");
object->loop_running = 1;
rt_thread_startup(object->loop);
break;
case STATE_PLAYING_TO_PAUSED:
LOG_I("STATE_PLAYING_TO_PAUSED");
if (object->loop_running == 1)
{
/* loop still running */
object->loop_running = 0;
if (rt_sem_take(object->sem, 3000))
{
/* Timeout, force delete */
LOG_W("Timeout");
rt_thread_delete(object->loop);
}
}
break;
case STATE_READY_TO_NULL:
LOG_I("STATE_READY_TO_NULL");
break;
default:
break;
}
return RT_EOK;
}
static int filesrc_set_property(ApObject *obj, char *name, void *arg)
{
return RT_EOK;
}
static int filesrc_get_property(ApObject *obj, char *name, void *arg)
{
return RT_EOK;
}
static ApPad *filesrc_get_pad(ApObject *obj, int type, int id)
{
ApFileSrc *object = FILESRC(obj);
if (type == PAD_TYPE_SINK)
{
LOG_E("%s plug-in has no sink pad", obj->name);
return NULL;
}
return &object->src_pad[id];
}
OBJECT_BASE_DEFINE(filesrc, ApFileSrc);
#endif