电子说
介绍 FreeRTOS 下如何使用 xrecorder 的接口来开发录制应用程序,方便录制应用开发人员快速正确地开发,以及录制应用测试人员如何根据该文档对基于 xrecord 的录制应用进行验证测试。
目前 RTOS 平台多媒体编码应用支持的编码格式分别为:pcm、amr、mp3、speex、opus。
其中 pcm、amr、mp3 可通过 xrecorder 进行编码以及录制;speex 和 opus 可通过第三方示例工程进行编码。
这张状态转换图清晰地描述了 xrecorder 的各个状态,也列举了主要的方法的调用时序,每种方法只能在一些特定的状态下使用,否则会出错。
Idle 状态:当调用 XRecordCreate() 创建一个 xrecord 时,处于 idle 状态。
调用 XRecordPrepare() 函数并返回后,xrecorder 处于 Prepared 状态。在这个状态下说明所有的资源都已经就绪了,调用 XRecordStart() 函数就可以进行录制。
xrecorder prepare 完成后,调用 XRecordStart() 进行录制,当应用开始录制后,xrecorder 就处于 Started 状态,这表明 xrecorder 正在录制文件。
Started 状态下均可调用 XrecordStop() 停止 xrecorder,而处于 Stop 状态的 xrecorder 要想重新录制,需要通过 XRecorderPrepare() 回到先前的 Prepared 状态重新开始才可以。
通过 XRecordDestroy() 的方法可以进入 Destroyed 状态,只要 xrecorder 不再被使用,就应当尽快将其 destroy 掉。
XRecord *XRecordCreate()
参数:
返回值:
int XRecordSetAudioEncodeType(XRecord *p, XRECODER_AUDIO_ENCODE_TYPE type, XRecordConfig *config)
参数:
返回值:
获取指向音频设备管理模块的指针,用于录制音频
void XRecordSetAudioCap(XRecord* p, const CaptureCtrl* audioSrc)
参数:
返回值:
audioSrc 可在上层应用通过调用 cedarx 的音频设备管理模块的 RTCaptureDeviceCreate 来创建。
int XRecordSetDataDstUrl(XRecord* p, const char* pUrl, void* arg, const CdxKeyedVectorT* pHeaders)
参数:
返回值:
int XRecordPrepare(XRecord* p)
参数:
返回值:
int XRecordStart(XRecord* p)
参数:
返回值:
int XRecordStop(XRecord* p)
参数:
返回值:
提供接口给下层编码模块,将编码数据放进缓存队列中等待封装
int onAudioDataEnc(XRecord* app, CdxMuxerPacketT* buff)
参数:
返回值:
int XRecordDestroy(XRecord* p)
参数:
返回值:
XRecordCreate()
//创建一个录制应用XRecordSetAudioCap()
//设置音频采集设备;可先调用 RTCaptureDeviceCreate
创建。XRecordSetDataDstUrl()
//设置录制后文件保存位置XRecordSetAudioEncodeType()
//设置音频数据的编码格式XRecordPrepare()
//设置 Muxer,让 xrecorder 进入准备状态XRecordStart()
//开始录制XRecordStop()
//停止录制XRecordDestroy()
//当不需要进行录制的时候,销毁 xrecorderRTCaptureDeviceCreate
来创建句柄。#include < stdio.h >
#include < stdlib.h >
#include < stdbool.h >
#include < string.h >
#include < aw_common.h >
#include < console.h >
#include "vfs.h"
#include "xrecord.h"
#define RECORDER_LOGD(msg, arg...) printf("[RECORDER_DBG] < %s : %d > " msg "n", __func__, __LINE__, ##arg)
#define RECORDER_LOGI(msg, arg...) printf("[RECORDER_INFO] < %s : %d > " msg "n", __func__, __LINE__, ##arg)
#define RECORDER_LOGW(msg, arg...) printf("[RECORDER_WRN] < %s : %d > " msg "n", __func__, __LINE__, ##arg)
#define RECORDER_LOGE(msg, arg...) printf("[RECORDER_ERR] < %s : %d > " msg "n", __func__, __LINE__, ##arg)
typedef struct recorder_base recorder_base;
typedef struct rec_cfg
{
XRECODER_AUDIO_ENCODE_TYPE type;
int sample_rate;
int chan_num;
int bitrate;
int sampler_bits;
} rec_cfg;
struct recorder_base
{
int (*start)(recorder_base *base, const char *url, const rec_cfg *cfg);
int (*stop)(recorder_base *base);
};
struct ExampleCustomerWriterImpl
{
CdxWriterT base;
vfs_file_t *vfs;
};
typedef struct recorder
{
recorder_base base;
XRecord *xrecorder;
CaptureCtrl *cap;
} recorder;
recorder_base *recorder_create();
int recorder_destroy(recorder_base *base);
/* Example Customer Writer */
static int __CdxExampleConnect(CdxWriterT *writer)
{
struct ExampleCustomerWriterImpl *impl;
impl = (struct ExampleCustomerWriterImpl *)writer;
vfs_unlink("data/record/2.amr");
impl- >vfs = vfs_open("data/record/2.amr", VFS_RDWR | VFS_CREAT);
if (impl- >vfs == NULL) {
return -1;
}
return 0;
}
static int __CdxExampleRead(CdxWriterT *writer, void *buf, int size)
{
return 0;
}
static int __CdxExampleWrite(CdxWriterT *writer, void *buf, int size)
{
uint32_t write_len;
struct ExampleCustomerWriterImpl *impl;
impl = (struct ExampleCustomerWriterImpl *)writer;
write_len = vfs_write(impl- >vfs, buf, size);
return write_len;
}
static long __CdxExampleSeek(CdxWriterT *writer, long moffset, int mwhere)
{
return 0;
}
static long __CdxExampleTell(CdxWriterT *writer)
{
return 0;
}
static int __CdxExampleClose(CdxWriterT *writer)
{
struct ExampleCustomerWriterImpl *impl;
impl = (struct ExampleCustomerWriterImpl *)writer;
vfs_close(impl- >vfs);
free(impl);
return 0;
}
static const struct CdxWriterOps exampleCustomerWriteOps =
{
.cdxConnect = __CdxExampleConnect,
.cdxRead = __CdxExampleRead,
.cdxWrite = __CdxExampleWrite,
.cdxSeek = __CdxExampleSeek,
.cdxTell = __CdxExampleTell,
.cdxClose = __CdxExampleClose
};
CdxWriterT *ExampleCustomerWriterCreat()
{
struct ExampleCustomerWriterImpl *impl;
impl = malloc(sizeof(*impl));
if (impl == NULL) {
printf("example customer writer create fail.n");
return NULL;
}
memset(impl, 0, sizeof(*impl));
impl- >base.ops = &exampleCustomerWriteOps;
return &impl- >base;
}
/* Main App */
static void showHelp(){
printf("n");
printf("**************************n");
printf("* This is a simple audio recoder, when it is started, you can input commands to telln");
printf("* what you want it to do.n");
printf("* Usage: n");
printf("* cedarx_record amr 10 : this means record 10s amr musicn");
printf("* cedarx_record pcm 10 : this means record 10s pcm musicn");
printf("**************************n");
}
recorder *recorder_singleton = NULL;
static int record_start(recorder_base *base, const char *url, const rec_cfg *cfg)
{
recorder *impl = container_of(base, recorder, base);
XRecordConfig audioConfig;
if (cfg- >type == XRECODER_AUDIO_ENCODE_PCM_TYPE)
{
audioConfig.nChan = cfg- >chan_num;
audioConfig.nSamplerate = cfg- >sample_rate;
audioConfig.nSamplerBits = cfg- >sampler_bits;
audioConfig.nBitrate = cfg- >bitrate;
}
else if (cfg- >type == XRECODER_AUDIO_ENCODE_AMR_TYPE)
{
audioConfig.nChan = 1;
audioConfig.nSamplerate = 8000;//amr-nb 8000Hz amr-wb 16000Hz
audioConfig.nSamplerBits = 16;
audioConfig.nBitrate = 12200;//amr-nb 12200 amr-wb 23850
} else {
audioConfig.nChan = cfg- >chan_num;
audioConfig.nSamplerate = cfg- >sample_rate;
audioConfig.nSamplerBits = cfg- >sampler_bits;
audioConfig.nBitrate = cfg- >bitrate;
}
XRecordSetDataDstUrl(impl- >xrecorder, url, NULL, NULL);
XRecordSetAudioEncodeType(impl- >xrecorder, cfg- >type, &audioConfig);
XRecordPrepare(impl- >xrecorder);
XRecordStart(impl- >xrecorder);
RECORDER_LOGI("record start");
return 0;
}
static int record_stop(recorder_base *base)
{
recorder *impl = container_of(base, recorder, base);
XRecordStop(impl- >xrecorder);
return 0;
}
extern CaptureCtrl* RTCaptureDeviceCreate();
recorder_base *recorder_create()
{
if (recorder_singleton != NULL)
return &recorder_singleton- >base;
recorder *impl = malloc(sizeof(*impl));
if (impl == NULL)
return NULL;
memset(impl, 0, sizeof(*impl));
impl- >xrecorder = XRecordCreate();
if (impl- >xrecorder == NULL)
goto failed;
impl- >cap = (void *)(uintptr_t)RTCaptureDeviceCreate();
if (impl- >cap == NULL)
goto failed;
XRecordSetAudioCap(impl- >xrecorder, impl- >cap);
impl- >base.start = record_start;
impl- >base.stop = record_stop;
recorder_singleton = impl;
return &impl- >base;
failed:
RECORDER_LOGE("recorder create failed");
if (impl- >xrecorder)
XRecordDestroy(impl- >xrecorder);
if (impl)
free(impl);
return NULL;
}
int recorder_destroy(recorder_base *base)
{
recorder *impl = container_of(base, recorder, base);
if (impl- >xrecorder) {
XRecordDestroy(impl- >xrecorder);
}
free(impl);
recorder_singleton = NULL;
return 0;
}
static int cedarx_record_test(int argc, char **argv)
{
recorder_base *recorder;
rec_cfg cfg;
char music_url[64];
char file_url[64];
CdxWriterT *writer;
memset(file_url, 0, 64);
if(argc == 3){
if( !strncmp("amr", argv[1], sizeof("amr")-1) ){
cfg.type = XRECODER_AUDIO_ENCODE_AMR_TYPE;
snprintf(file_url, 64, "file://data/%ds.amr", atoi(argv[2]));
cfg.sample_rate = 8000;//8000
cfg.chan_num = 1;//1
cfg.bitrate = 12200;
cfg.sampler_bits = 16;
}
else if( !strncmp("pcm", argv[1], sizeof("pcm")-1) ){
cfg.type = XRECODER_AUDIO_ENCODE_PCM_TYPE;
snprintf(file_url, 64, "file://data/%ds.pcm", atoi(argv[2]));
cfg.sample_rate = 8000;//8000
cfg.chan_num = 1;//1
cfg.bitrate = 12200;
cfg.sampler_bits = 16;
}
else if( !strncmp("mp3", argv[1], sizeof("mp3")-1) ){
cfg.type = XRECODER_AUDIO_ENCODE_MP3_TYPE;
snprintf(file_url, 64, "file://data/%ds.mp3", atoi(argv[2]));
cfg.sample_rate = 16000;
cfg.chan_num = 1;
cfg.bitrate = 32000;
cfg.sampler_bits = 16;
} else {
printf("now support!n");
return -1;
}
}else{
printf("the parameter is error,usage is as following:n");
showHelp();
return -1;
}
recorder = recorder_create();
if (recorder == NULL) {
printf("recorder create fail, exitn");
return -1;
}
printf("===start record %s now, last for %d s===n", argv[1], atoi(argv[2]));
recorder- >start(recorder, file_url, &cfg);
sleep(atoi(argv[2]));
recorder- >stop(recorder);
printf("record %s over.n", argv[1]);
exit:
return recorder_destroy(recorder);
}
FINSH_FUNCTION_EXPORT_CMD(cedarx_record_test, cedarx_record, cedarx record test demo);
全部0条评论
快来发表一下你的评论吧 !