介绍 FreeRTOS 下如何使用 rtplayer 的接口来开发播放器应用程序,方便播放器开发人员快速正确地开发,以及播放器测试人员如何根据该文档对 rtplayer 播放器进行验证测试。
这张状态转换图清晰地描述了 rtlayer 的各个状态,也列举了主要的方法的调用时序,每种方法只能在一些特定的状态下使用,否则会出错。另外,只有在 Prepared、Started、Paused、Play‑backCompleted 这四种状态下可以进行 seekTo() 操作,并且 seekTo() 之后,状态不变。
Idle 状态:当调用 player_init() 创建一个 rtplayer 或者调用了其 reset() 方法时,rtplayer 处于 idle状态。
这个状态比较简单,调用 setDateSource_url() 方法就进入 Initialized 状态,表示此时要播放的文件已经设置好了
调用 prepare() 函数还没返回或者是调用 prepareAsync() 并且还没收到 RTPLAYER_NOTIFY_PREPARED 这个回调消息的时候就处于 Preparing 状态
调用 prepare() 函数已经返回或者是调用 prepareAsync() 并且已经收到 RTPLAYER_NOTIFY_PREPARED 这个回调消息之后的状态就处于 Prepared 状态。在这个状态下说明所有的资源都已经就绪了,调用 start() 函数就可以播放了。
rtplayer 一旦 prepare 完成,就可以调用 start() 方法,这样 rtplayer 就处于 Started 状态,这表明 rtplayer 正在播放文件过程中。可以使用 XPlayerIsPlaying() 测试 rtplayer 是否处于了 Started 状态。如果播放完毕,而又设置了循环播放,则 rtplayer 仍然会处于 Started 状态。
Started 状态下可以调用 pause_l() 方法暂停 rtplayer,从而进入 Paused 状态,rtplayer 暂停后再次调用 start() 则可以继续 TPlayer 的播放,转到 Started 状态。
Started 或者 Paused 状态下均可调用 stop() 停止 rtplayer,而处于 Stop 状态的 rtplayer 要想重新播放,需要通过 prepareAsync() 和 prepare() 回到先前的 Prepared 状态重新开始才可以。
文件正常播放完毕,而又没有设置循环播放的话就进入该状态,并且会通过 RTPLAYER_NOTIFY_PLAYBACK_COMPLETE 这个消息回调给应用。此时可以调用 start() 方法重新从头播放文件,也可以 stop() 停止 rtplayer,或者也可以 seekTo() 来重新定位播放位置。
由于某种原因 rtplayer 出现了错误,就会进入该状态,并且会通过 RTPLAYER_NOTIFY_MEDIA_ERROR 这个消息回调给应用。如果 rtplayer 进入了 Error 状态,可以通过调用 reset() 来恢复,使得 rtplayer 重新返回到 Idle 状态。
通过 plater_deinit() 的方法可以进入 End 状态,只要 rtplayer 不再被使用,就应当尽快将其 destroy 掉。
函数原型
uint32_t player_init(void)
参数:
返回值:
函数原型
void player_deinit(void* handle)
参数:
返回值:
函数原型
void registerCallback(void* handle, void* userData, player_callback_t fn)
参数:
返回值:
创建完 rtplayer 播放器之后,就要调用该函数设置回调消息处理函数。
可以是本地文件也可以是网络源
函数原型
status_t setDataSource_url(void* handle,void* userData, const char * url, int id)
参数:
返回值:
函数原型
status_t prepare(void* handle)
参数:
返回值:
函数原型
status_t prepareAsync(void* handle)
参数:
返回值:
该函数是非阻塞函数,需要等到 RTPLAYER_NOTIFY_P‑ REPARED 消息回调之后才能调 start() 函数进行播放,而且 start() 函数不能在回调函数中调用
函数原型
status_t start(void* handle)
参数:
返回值:
函数原型
status_t pause_l(void* handle)
参数:
返回值:
函数原型
status_t stop(void* handle)
参数:
返回值:
函数原型
status_t reset(void* handle)
参数:
返回值:
在任何状态下都可以调用该函数,每次播放不同的音频之前,都需要调用该函数重置播放器,另外,一般收到 RTPLAYER_NOTIFY_MEDIA_ERROR 这个消息的时候,也需要通过调用该函数来重置播放器。但是不能在回调函数中调用该函数,否则会出现死锁
函数原型
status_t seekTo(void* handle, int sec)
参数:
返回值:
函数原型
status_t getCurrentPosition(void* handle, int * sec)
参数:
返回值:
函数原型
status_t getDuration(void* handle, int * sec)
参数:
返回值:
需要在 prepared 状态之后才可以调用该函数
函数原型
MediaInfo* getMediaInfo(void* handle)
参数:
返回值:
需要在 prepared 状态之后才可以调用该函数
函数原型
status_t setLooping(void* handle, int loop)
参数:
返回值:
函数原型
XPlayer* XPlayerCreate()
参数:
返回值:
函数原型
int XPlayerSetNotifyCallback(XPlayer* p, XPlayerNotifyCallback notifier, void* pUserData)
参数:
返回值:
Xplayer 将接收来自下层的回调通知,进行相应的操作
函数原型
SoundCtrl* RTSoundDeviceCreate(int card)
参数:
返回值:
函数原型
int XPlayerSetDataSourceUrl(XPlayer* p, const char* pUrl, void* httpService, const CdxKeyedVectorT* pHeaders)
参数:
返回值:
调用说明: 发送 SetDataSource 命令,获取需要播放的音频数据内容
函数原型
int XPlayerPrepare(XPlayer* p)
参数:
返回值:
该函数是阻塞函数,调用完返回之后就进入了 Prepared 状态,此时可调 XPlayerStart() 函数进行播放
函数原型
int XPlayerPrepareAsync(XPlayer* p)
参数:
返回值:
网络播放源一般采用 PrepareAsync,而不是 Prepare 命令,PrepareAsync 命令的返回值为 0 时说明响应成功,播放器准备工作已经完成可以开始播放,为‑1 时说明响应失败
函数原型
int XPlayerStart(XPlayer* p)
参数:
返回值:
Start 命令的返回值为 0 时说明响应成功,为‑1 时说明响应失败
函数原型
int XPlayerPause(XPlayer* p)
参数:
返回值:
在 XPlayer 处于 start 状态时可调用此接口,Pause 命令的返回值为 0 时说明响应成功,为‑1 时说明响应失败
函数原型
int XPlayerStop(XPlayer* p)
参数:
返回值:
将相关变量复位,并销毁各模块,如音频解码模块、音频解码数据接收模块等
函数原型
int XPlayerReset(XPlayer* p)
参数:
返回值:
Reset 命令的返回值为 0 时说明响应成功,为‑1 时说明响应失败
函数原型
int XPlayerGetDuration(XPlayer* p, int *msec)
参数:
返回值:
在 XPlayer 处于 PREPARED、STARTED、PAUSED、STOPPED 或 COMPLETE 状态下才可调用此接口,否则操作无效
函数原型
int XPlayerSeekTo(XPlayer* p, int nSeekTimeMs)
参数:
返回值:
如果跳转前播放处于暂停状态,则跳转后将保持在暂停状态
函数原型
int XPlayerGetDuration(XPlayer* p, int *msec)
参数:
返回值:
需要在 prepared 状态之后才可以调用该函数
在 XPlayer 处于 PREPARED、STARTED、PAUSED、STOPPED 或 COMPLETE 状态下才可调用此接口,否则操作无效,在 complete 状态下,可能会调用 prepare 方法并更改媒体信息,获取的播放时间以 ms 为单位
函数原型
int XPlayerGetCurrentPosition(XPlayer* p, int* msec)
参数:
返回值:
函数原型
MediaInfo* XPlayerGetMediaInfo(XPlayer* p)
参数:
返回值:
需要在 prepared 状态之后才可以调用该函数
函数原型
int XPlayerSetLooping(XPlayer* p, int loop)
参数:
返回值:
函数原型
int XPlayerIsPlaying(XPlayer* p)
参数:
返回值:
函数原型
void XPlayerDestroy(XPlayer* p)
参数:
返回值:
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include "FreeRTOS_POSIX/utils.h"
#include "rtplayer.h"
#include "xplayer.h"
#define PAUSE_CMD 'P'
#define PING_CMD 'p'
#define STOP_CMD 'S'
#define SEEK_TO_CMD 's'
#define SEEK_TO_CMD2 'j'
#define BACKGROUND_CMD 'b'
#define SHOW_BUFFER_CMD 'B'
#define QUIT_CMD 'q'
#define LOOP_CMD 'l'
#define GET_DURATION_CMD 'G'
#define GET_POSITION_CMD 'g'
#define HELP_CMD 'h'
#define INFO_CMD 'i'
#define REPLAY_CMD 'r'
#define RETRY_CMD 256
#define USE_PREPARE_ASYNC 0
#define LOGD(msg, arg...) //printf("[PLAYER_DBG] <%s : %d> " msg "\n", __func__, __LINE__, ##arg)
#define LOGI(msg, arg...) //printf("[PLAYER_INFO] <%s : %d> " msg "\n", __func__, __LINE__, ##arg)
#define LOGW(msg, arg...) printf("[PLAYER_WRN] <%s : %d> " msg "\n", __func__, __LINE__, ##arg)
#define LOGE(msg, arg...) printf("[PLAYER_ERR] <%s : %d> " msg "\n", __func__, __LINE__, ##arg)
typedef struct DemoPlayerContext
{
RTPlayer* mRTplayer;
sem_t mPreparedSem;
mqd_t mRTplayerMq;
pthread_t mThreadId;
char *pUrl;
int mSeekable;
char isPlayingFlag;
char mError;
int inputMode;
int isSetLoop;
char quitFlag;//no_shell_input mode quitFlag
int testMode;
MediaInfo* mMediaInfo;
int SoundCard;
}DemoPlayerContext;
typedef struct DemoPlayerMsg
{
int msg;
int data;
}DemoPlayerMsg;
#define INVALID_MQD ( ( mqd_t ) -1 )
#define DEFAULT_MODE 0600
static const char *pcRTplayerMqName = "/rtplayerMq";
static volatile mqd_t mRTplayerMq = INVALID_MQD;
static int mRTplayerUserInput = 0;
static struct mq_attr xRTplayerMqAttr =
{
.mq_flags = 0,
.mq_maxmsg = 3,
.mq_msgsize = sizeof(DemoPlayerMsg),
.mq_curmsgs = 0
};
static void showHelp(){
printf("\n");
printf("**************************\n");
printf("* This is a simple audio player, when it is started, you can input commands to tell\n");
printf("* what you want it to do.\n");
printf("* Usage: \n");
printf("* tplayer_demo /data/test.mp3 : this means play test.mp3\n");
printf("* P :this will Pause if in playing status,or Play in paused status \n");
printf("* S :this means Stop \n");
printf("* s :this means seek to 10s \n");
printf("* B :show buffer \n");
printf("* b :this means player will run in the background \n");
printf("* q :this means quit the player \n");
printf("* l :this means loop play \n");
printf("* G :this means Get duration \n");
printf("* g :this means get position \n");
printf("* i :this means show media info \n");
printf("* h :this means show the help information \n");
printf("* r : replay the current audio\n");
printf("**************************\n");
}
static int rtplayer_clear_cmd(mqd_t mq){
struct timespec cur, delay, abstime;
clock_gettime( CLOCK_REALTIME, &cur );
delay.tv_sec = 0;
delay.tv_nsec = 5*1000*1000;
UTILS_TimespecAdd(&cur, &delay, &abstime);
DemoPlayerMsg msg;
while(mq_timedreceive(mq, (char *)&msg, sizeof(msg), NULL, &abstime)!=-1);
return 0;
}
static int rtplayer_send_cmd(mqd_t mq, int msg, int data){
DemoPlayerMsg pmsg = {msg, data};
struct timespec tsn, ts;
clock_gettime(CLOCK_REALTIME, &tsn);
UTILS_TimespecAddNanoseconds(&tsn, 20*1000*1000, &ts);
int status = mq_timedsend(mq, (char *)&pmsg, sizeof(pmsg), 0, &ts);
if(status)
LOGE("send cmd %c,%d failed!", pmsg.msg, pmsg.data);
return status;
}
static int rtplayer_send_cmd_force(mqd_t mq, int msg, int data){
int try_times = 0;
DemoPlayerMsg pmsg = {msg, data};
struct timespec tsn, ts;
int status;
try_send:
clock_gettime(CLOCK_REALTIME, &tsn);
UTILS_TimespecAddNanoseconds(&tsn, 20*1000*1000, &ts);
status = mq_timedsend(mq, (char *)&pmsg, sizeof(pmsg), 0, &ts);
if(status){
try_times++;
if(try_times<5){
LOGE("send cmd %c,%d failed, retry...", pmsg.msg, pmsg.data);
goto try_send;
}
else if(try_times<10){
DemoPlayerMsg tmp;
LOGE("send cmd %c,%d failed, retry...", pmsg.msg, pmsg.data);
clock_gettime(CLOCK_REALTIME, &tsn);
UTILS_TimespecAddNanoseconds(&tsn, 20*1000*1000, &ts);
status = mq_timedreceive(mq, (char *)&tmp, sizeof(tmp), NULL, &ts);
if(status<0){
LOGE("mq_receive fail %d", status);
goto fail_exit;
}
LOGW("drop: %c, %d", tmp.msg, tmp.data);
goto try_send;
}
goto fail_exit;
}
return status;
fail_exit:
LOGE("send cmd %c,%d failed!\n", pmsg.msg, pmsg.data);
return status;
}
static void callbackFromRTplayer(void* userData,int msg, int id, int ext1, int ext2);
static void* RTplayerThread(void* arg){
DemoPlayerContext* demoPlayer = (DemoPlayerContext*)arg;
char quitFlag = 0;
if(demoPlayer->inputMode)
{
while(1)
{
if(demoPlayer->quitFlag)
{
if(demoPlayer->mRTplayer != NULL)
{
printf("player finsh, quit the rtplayer\n");
mRTplayerMq = INVALID_MQD;
#if USE_PREPARE_ASYNC
sem_destroy(&demoPlayer->mPreparedSem);
#endif
player_deinit(demoPlayer->mRTplayer);
free(demoPlayer->pUrl);
free(demoPlayer);
}
break;
}
usleep(50*1000);
}
return NULL;
}
while(!quitFlag){
int cRxed = 0;
int data = 0;
DemoPlayerMsg msg;
ssize_t status;
if(demoPlayer->mRTplayerMq!=INVALID_MQD){
usleep(50*1000);
ssize_t status = mq_receive(demoPlayer->mRTplayerMq, (char *)&msg, sizeof(msg), NULL);
if(status<=-1){
LOGE("mq_receive fail %d", status);
usleep(1*1000*1000);
continue;
}
printf("receive %c,%d\n", msg.msg, msg.data);
cRxed = msg.msg;
data = msg.data;
}
else{
cRxed = QUIT_CMD;
}
switch(cRxed){
case PAUSE_CMD:
{
if(demoPlayer->isPlayingFlag){
printf("pause the rtplayer\n");
pause_l(demoPlayer->mRTplayer);
demoPlayer->isPlayingFlag = 0;
}else{
printf("play the rtplayer\n");
start(demoPlayer->mRTplayer);
demoPlayer->isPlayingFlag = 1;
}
break;
}
case STOP_CMD:
{
printf("stop the rtplayer\n");
stop(demoPlayer->mRTplayer);
demoPlayer->isPlayingFlag = 0;
break;
}
case SEEK_TO_CMD:
{
printf("rtplayer seek to 10 second\n");
seekTo(demoPlayer->mRTplayer,10);
break;
}
case SEEK_TO_CMD2:
{
printf("rtplayer seek to %d second\n", data);
seekTo(demoPlayer->mRTplayer,data);
break;
}
case QUIT_CMD:
{
printf("quit the rtplayer\n");
mRTplayerMq = INVALID_MQD;
//mq_close(demoPlayer->mRTplayerMq);
#if USE_PREPARE_ASYNC
sem_destroy(&demoPlayer->mPreparedSem);
#endif
player_deinit(demoPlayer->mRTplayer);
free(demoPlayer->pUrl);
free(demoPlayer);
quitFlag = 1;
break;
}
case LOOP_CMD:
{
printf("let the rtplayer loop play\n");
demoPlayer->isSetLoop = 1;
setLooping(demoPlayer->mRTplayer,1);
break;
}
case GET_DURATION_CMD:
{
printf("get the audio duration\n");
int duration;
getDuration(demoPlayer->mRTplayer,&duration);
printf("duration:%d s\n",duration);
break;
}
case GET_POSITION_CMD:
{
printf("get the current position\n");
int position;
getCurrentPosition(demoPlayer->mRTplayer,&position);
printf("current position:%d s\n",position);
break;
}
case HELP_CMD:
{
printf("show the help information\n");
showHelp();
break;
}
case INFO_CMD:
{
printf("**************************\n");
printf("* show media information:\n");
MediaInfo* mi = NULL;
demoPlayer->mMediaInfo = getMediaInfo(demoPlayer->mRTplayer);
if(demoPlayer->mMediaInfo != NULL){
mi = demoPlayer->mMediaInfo;
printf("* file size = %lld KB\n",mi->nFileSize/1024);
printf("* duration = %lld ms\n",mi->nDurationMs);
printf("* bitrate = %d Kbps\n",mi->nBitrate/1024);
printf("* container type = %d\n",mi->eContainerType);
printf("* audio stream num = %d\n",mi->nAudioStreamNum);
if(mi->pAudioStreamInfo != NULL){
printf("* audio codec tpye = %d\n",mi->pAudioStreamInfo->eCodecFormat);
printf("* audio channel num = %d\n",mi->pAudioStreamInfo->nChannelNum);
printf("* audio BitsPerSample = %d\n",mi->pAudioStreamInfo->nBitsPerSample);
printf("* audio sample rate = %d\n",mi->pAudioStreamInfo->nSampleRate);
}
printf("**************************\n");
}
break;
}
case SHOW_BUFFER_CMD:
{
printf("**************************\n");
printf("* show buffer information:\n");
player_show_buffer();
printf("**************************\n");
break;
}
case REPLAY_CMD:
{
printf("replay %s\n", demoPlayer->pUrl);
int ret;
if(demoPlayer->testMode){
printf("test mode: destroy & create instead of reset\n");
player_deinit(demoPlayer->mRTplayer);
usleep(50*1000);
demoPlayer->mRTplayer = (RTPlayer*)(uintptr_t)player_init();
printf("demoPlayer.mRTplayer = %p\n",demoPlayer->mRTplayer);
if(!demoPlayer->mRTplayer){
printf("init rtplayer fail\n");
free(demoPlayer->pUrl);
free(demoPlayer);
quitFlag = 1;
continue;
}
registerCallback(demoPlayer->mRTplayer, demoPlayer, callbackFromRTplayer);
}
else
reset(demoPlayer->mRTplayer);
ret = setDataSource_url(demoPlayer->mRTplayer, demoPlayer, demoPlayer->pUrl, 0);
if(ret){
printf("setDataSource_url failed\n");
break;
}
ret = prepare(demoPlayer->mRTplayer);
if(ret){
printf("prepare failed\n");
break;
}
start(demoPlayer->mRTplayer);
demoPlayer->isPlayingFlag = 1;
if(demoPlayer->isSetLoop)
{
setLooping(demoPlayer->mRTplayer,1);
}
break;
}
case RETRY_CMD:
{
int position = data;
if(data==-1)
getCurrentPosition(demoPlayer->mRTplayer,&position);
printf("retry %s\n", demoPlayer->pUrl);
int ret;
if(demoPlayer->testMode){
printf("test mode: destroy & create instead of reset\n");
player_deinit(demoPlayer->mRTplayer);
usleep(50*1000);
demoPlayer->mRTplayer = (RTPlayer*)(uintptr_t)player_init();
printf("demoPlayer.mRTplayer = %p\n",demoPlayer->mRTplayer);
if(!demoPlayer->mRTplayer){
LOGE("init rtplayer fail");
free(demoPlayer->pUrl);
free(demoPlayer);
quitFlag = 1;
continue;
}
registerCallback(demoPlayer->mRTplayer, demoPlayer, callbackFromRTplayer);
}
else
reset(demoPlayer->mRTplayer);
ret = setDataSource_url(demoPlayer->mRTplayer, demoPlayer, demoPlayer->pUrl, 0);
if(ret){
LOGE("setDataSource_url failed");
rtplayer_send_cmd_force(demoPlayer->mRTplayerMq, RETRY_CMD, position);
usleep(500*1000);
break;
}
ret = prepare(demoPlayer->mRTplayer);
if(ret){
LOGE("prepare failed");
rtplayer_send_cmd_force(demoPlayer->mRTplayerMq, RETRY_CMD, position);
usleep(500*1000);
break;
}
start(demoPlayer->mRTplayer);
demoPlayer->isPlayingFlag = 1;
//seekTo(demoPlayer->mRTplayer, position);
if(demoPlayer->isSetLoop)
setLooping(demoPlayer->mRTplayer,1);
break;
}
default:
{
LOGW("warning: unknown command,cmd = %d",cRxed);
break;
}
}
if(quitFlag){
return NULL;
}
}
return NULL;
}
static void callbackFromRTplayer(void* userData,int msg, int id, int ext1, int ext2){
LOGI("call back from RTplayer,msg = %d,id = %d,ext1 = %d,ext2 = %d\n",msg,id,ext1,ext2);
DemoPlayerContext* pDemoPlayer = (DemoPlayerContext*)userData;
switch(msg)
{
case RTPLAYER_NOTIFY_PREPARED:
{
printf("RTPLAYER_NOTIFY_PREPARED:has prepared.\n");
#if USE_PREPARE_ASYNC
sem_post(&pDemoPlayer->mPreparedSem);
pDemoPlayer->mPreparedFlag = 1;
#endif
break;
}
case RTPLAYER_NOTIFY_PLAYBACK_COMPLETE:
{
printf("RTPLAYER_NOTIFY_PLAYBACK_COMPLETE:play complete\n");
pDemoPlayer->isPlayingFlag = 0;
if(pDemoPlayer->inputMode)
{
pDemoPlayer->quitFlag = 1;
}
break;
}
case RTPLAYER_NOTIFY_SEEK_COMPLETE:
{
printf("RTPLAYER_NOTIFY_SEEK_COMPLETE:seek ok\n");
break;
}
case RTPLAYER_NOTIFY_MEDIA_ERROR:
{
switch (ext1)
{
case RTPLAYER_MEDIA_ERROR_UNKNOWN:
{
printf("erro type:TPLAYER_MEDIA_ERROR_UNKNOWN\n");
break;
}
case RTPLAYER_MEDIA_ERROR_UNSUPPORTED:
{
printf("erro type:TPLAYER_MEDIA_ERROR_UNSUPPORTED\n");
break;
}
case RTPLAYER_MEDIA_ERROR_IO:
{
printf("erro type:TPLAYER_MEDIA_ERROR_IO\n");
break;
}
}
printf("RTPLAYER_NOTIFY_MEDIA_ERROR\n");
pDemoPlayer->mError = 1;
#if USE_PREPARE_ASYNC
if(pDemoPlayer->mPreparedFlag == 0){
printf("recive err when preparing\n");
sem_post(&pDemoPlayer->mPreparedSem);
}
#endif
if( pDemoPlayer->mRTplayerMq!=INVALID_MQD ){
rtplayer_send_cmd_force(pDemoPlayer->mRTplayerMq, RETRY_CMD, -1);
}
else{
printf("io error, mqueue not exist\n");
}
break;
}
case RTPLAYER_NOTIFY_NOT_SEEKABLE:
{
pDemoPlayer->mSeekable = 0;
printf("info: media source is unseekable.\n");
break;
}
case RTPLAYER_NOTIFY_DETAIL_INFO:
{
int flag = *(int *)(uintptr_t)ext2;
//printf("detail info: %d\n", flag);
break;
}
default:
{
printf("warning: unknown callback from RTplayer.\n");
break;
}
}
}
int cmd_rtplayer_test(int argc, char ** argv)
{
int inputMode = 0;
int testMode = 0;
/*
printf("argc = %d\n",argc);
for(int i=0; i < argc;i++){
printf("argv[%d]=%s\n",i,argv[i]);
}
*/
printf("rtplayer source:%s\n", argv[1]);
if(argc == 3){
if( !strncmp("no_shell_input", argv[2], sizeof("no_shell_input")-1) ){
argc--;
inputMode = 1;
}
else if( !strncmp("test_mode", argv[2], sizeof("test_mode")-1) ){
argc--;
testMode = 1;
}
}
if(argc != 2){
LOGW("the parameter is error,usage is as following:");
showHelp();
goto rtp_failed;
}
#if USE_PREPARE_ASYNC
int waitErr = 0;
#endif
DemoPlayerContext* demoPlayer = (DemoPlayerContext*)malloc(sizeof(DemoPlayerContext));
if(demoPlayer == NULL){
LOGE("malloc DemoPlayerContext fail");
goto rtp_failed;
}
memset(demoPlayer, 0, sizeof(DemoPlayerContext));
demoPlayer->mSeekable = 1;
demoPlayer->mRTplayerMq = INVALID_MQD;
demoPlayer->inputMode = inputMode;
demoPlayer->testMode = testMode;
demoPlayer->quitFlag = 0;
demoPlayer->mMediaInfo = NULL;
if(strlen(argv[1])<=0){
LOGE("url error");
goto rtp_url_failed;
}
demoPlayer->pUrl = malloc(strlen(argv[1])+1);
if(!demoPlayer->pUrl){
LOGE("pUrl malloc fail");
goto rtp_url_failed;
}
memset(demoPlayer->pUrl, 0, strlen(argv[1]));
strcpy(demoPlayer->pUrl, argv[1]);
#if USE_PREPARE_ASYNC
sem_init(&demoPlayer->mPreparedSem, 0, 0);
#endif
demoPlayer->mRTplayer = (RTPlayer*)(uintptr_t)player_init();
LOGI("demoPlayer.mRTplayer = %p",demoPlayer->mRTplayer);
if(!demoPlayer->mRTplayer){
LOGE("init rtplayer fail");
goto rtp_init_failed;
}
registerCallback(demoPlayer->mRTplayer, demoPlayer, callbackFromRTplayer);
status_t ret = setDataSource_url(demoPlayer->mRTplayer,demoPlayer,demoPlayer->pUrl, 0);
if(ret){
LOGE("set DataSource url fail");
goto rtp_prepare_failed;
}
#if USE_PREPARE_ASYNC
demoPlayer->mPreparedFlag = 0;
if(prepareAsync(demoPlayer->mRTplayer) != 0)
{
printf("TPlayerPrepareAsync() return fail.\n");
}else{
printf("preparing...\n");
}
struct timespec t;
t.tv_nsec = 0;
t.tv_sec = 30;
waitErr = sem_timedwait(&demoPlayer->mPreparedSem, &t);
if(waitErr == -1){
printf("prepare timeout,has wait %d s\n",t.tv_sec);
sem_destroy(&demoPlayer->mPreparedSem);
goto rtp_prepare_failed;
}else if(demoPlayer.mError == 1){
printf("prepare fail\n");
sem_destroy(&demoPlayer->mPreparedSem);
goto rtp_prepare_failed;
}
printf("prepared ok\n");
#else
ret = prepare(demoPlayer->mRTplayer);
if(ret){
LOGE("prepare fail");
goto rtp_prepare_failed;
}
#endif
start(demoPlayer->mRTplayer);
demoPlayer->isPlayingFlag = 1;
if( mRTplayerMq==INVALID_MQD ){
mRTplayerMq = mq_open( pcRTplayerMqName, O_CREAT | O_RDWR, DEFAULT_MODE, &xRTplayerMqAttr );
if(mRTplayerMq==INVALID_MQD){
LOGE("mq_open fail");
}
}
demoPlayer->mRTplayerMq = mRTplayerMq;
rtplayer_clear_cmd(demoPlayer->mRTplayerMq);
pthread_attr_t attr;
pthread_attr_init(&attr);
struct sched_param sched;
sched.sched_priority = 4;
pthread_attr_setschedparam(&attr, &sched);
pthread_attr_setstacksize(&attr, 32768);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if( pthread_create(&demoPlayer->mThreadId, &attr, RTplayerThread, demoPlayer) ){
LOGE("pthread_create failed, quit the rtplayer");
mRTplayerMq = INVALID_MQD;
//mq_close(demoPlayer->mRTplayerMq);
#if USE_PREPARE_ASYNC
sem_destroy(&demoPlayer->mPreparedSem);
#endif
goto rtp_prepare_failed;
}
pthread_setname_np(demoPlayer->mThreadId, "RTplayerThread");
if(demoPlayer->inputMode)
goto rtp_succeed;
while(1){
char cRxed = getchar();
if(cRxed==BACKGROUND_CMD){
printf("shell input exit, rtplayer will run in the background\n");
break;
}
rtplayer_send_cmd(demoPlayer->mRTplayerMq, cRxed, 0);
if(cRxed==QUIT_CMD)
break;
usleep(50*1000);
}
rtp_succeed:
return 0;
rtp_prepare_failed:
player_deinit(demoPlayer->mRTplayer);
rtp_init_failed:
free(demoPlayer->pUrl);
rtp_url_failed:
free(demoPlayer);
rtp_failed:
return -1;
}
FINSH_FUNCTION_EXPORT_CMD(cmd_rtplayer_test, rtplayer_test, test the rtplayer);
static int cmd_rtplayer_controller(int argc, char ** argv){
if(mRTplayerMq==INVALID_MQD){
printf("mRTplayerMq = INVALID_MQD!\n");
return -1;
}
if( (argc!=2) && (argc!=3) ){
printf("usage:rtpc [data]\n" );
return -1;
}
int data = 0;
if(argc==3)
data = atoi(argv[2]);
rtplayer_send_cmd(mRTplayerMq, argv[1][0], data);
return 0;
}
FINSH_FUNCTION_EXPORT_CMD(cmd_rtplayer_controller, rtpc, control the rtplayer);
目前 rtplayer/xplayer 仅支持音频解码,且不支持对视频文件进行解封装,因此 rtplayer 播放器应用只支持音频文件的播放。
void registerCallback(void* handle, void* userData, player_callback_t fn)
函数必须要调用,而且 fn 不能为 NULL。
回调函数中不能调用 rtplayer 的任何一个接口,如:reset、stop、start 等这些接口不能在回调函数中调用。
播放本地文件的情况下,set url 时,XPlayer 会进行一次同步 prepare,用于提前获取信息给 parser,因此异步 prepare 前,应对 XPlayerSetDataSourceUrl 的返回值进行判断。
改变播放器的状态,应满足状态图中的对应的函数调用流程,如播放结束后需要播放下一首歌,应调用 reset 清空信息,进入 idle 状态,再调用 setDataSource_Url 进行填充下一首歌到播放器中
采取异步 prepare 时(prepareAsync),应注意添加信号量进行同步。
原贴链接:https://bbs.aw-ol.com/topic/4374/
资源获取、问题讨论可以到全志在线开发者社区进行:https://www.aw-ol.com
全志及开发者最新动态可以关注全志在线微信公众号