媒体端口(pjmedia_port)框架~~PJMEDIA的基础概念
媒体端口(也可以称作pjmedia_port“类”)提供一个通用和可扩展实现媒体要素的框架。媒体要素分为:源要素、目标要素、处理要素。媒体端口界面提供下列基础属性:
-媒体端口信息(pjmedia_port_info)####用于描述采样率、通道数量等媒体属性
-可选项(媒体端口如果只上传流,则无此项)回调函数get_frame()被pjmedia_port_get_frame()函数调用,从端口获得多帧数据。
-可选项(媒体端口如果只下载流,则无此项)回调函数put_frame()被pjmedia_port_put_frame()函数调用,从端口推送多帧数据。只要实现get_frame()和put_frame()回调内容,即可引导接口实现各媒体端口(源、目标、处理)发出/取得的媒体帧。
媒体端口是被动对象。缺省的媒体流程运行不需要工作线程的支持。应用程序或PJMEDIA媒体组件,想从媒体端口取得/推送数据,必须不断地调用pjmedia_port_get_frame()或pjmedia_port_put_frame()函数。
一些媒体端口,例如PJMEDIA_CONF(会议)和PJMEDIA_RESAMPLE_PORT(更换采样率端口),要封装为与其它端口互联,以调用其它端口的协作任务,直至其最终源/目标端口终止媒体。端口互联意味着:上传流媒体端口要先调用get_frame()取帧数据,并调用put_frame()给它的下载端口传帧数据。上述过程的前提条件: 上下行的媒体端口必须具有相同的格式。格式是采样格式、时钟速率、通道个数、每次采样比特数、每帧采样数等等音频媒体相关参数的组合。
示例程序port_clock_ex1,用于手工处理重采样。此例子中,假设应用程序将要读取一个WAV文件数据,转换采样率后写入其它WAV文件,下图展示了应用程序创建和安置多个媒体端口的方式
应用程序将使用下列伪码设置多个媒体端口:
pjmedia_port *player, *resample, *writer;
pj_status_t status;
//创建文件播放端口
status = pjmedia_wav_player_port_create(pool,
"Input.WAV", //file name
20, // ptime.
PJMEDIA_FILE_NO_LOOP, // flags
0, // buffer size
NULL, // user data.
&player );
PJ_ASSERT_RETURN(status==PJ_SUCCESS, PJ_SUCCESS);
//以player端口为源要素,使用设定的目标采样速率创建重采样端口,建立resample端口与player端口的有效连接。
status = pjmedia_resample_port_create( pool, player, 8000,0, &resample);
PJ_ASSERT_RETURN(status==PJ_SUCCESS, PJ_SUCCESS);
//按resample端口设置创建文件写入WAV参数。
status pjmedia_wav_writer_port_create(pool,
"Output.WAV", // file name.
resample->info.clock_rate,
resample->info.channel_count,
resample->info.samples_per_frame,
resample->info.bits_per_sample,
0, //flags
0, //buffer size
NULL, //user data.
&writer);
全部端口设置完成后,应用程序在循环中调用转换处理:
pj_int16_t samplebuf[MAX_FRAME];
while (1) {
pjmedia_frame frame;
pj_status_t status;
frame.buf = samplebuf;
frame.size = sizeof(samplebuf);
//从resample端口取帧数据
status = pjmedia_port_get_frame(resample,&frame);
if (status != PJ_SUCCESS || frame.type ==PJMEDIA_FRAME_TYPE_NONE) {
//读到文件结束时,停止转换
break;
}
//推帧数据到writer端口
status = pjmedia_port_put_frame(writer,&frame);
if (status != PJ_SUCCESS) {
//写文件错误处理
break;
}
}
出于完整性的考虑,重采样处理完成后,应用程序将要销毁创建的全部端口:
//注意:resample端口被销毁时,也会缺省地销毁给它推帧数据的端口(player端口)
pjmedia_port_destroy(resample);
pjmedia_port_destroy(writer);
对于这个简单的WAV文件采样频率转换的例子,以上步骤就足够了。但是其他更为复杂的目的,读和写语音帧的过程需要以定时的方式进行,例如发送RTP包到一个远程的流对象。更进一步,随着应用程序规模的逐渐增大,手动读写语音帧的操作越来越频繁,如果PJMEDIA提供自动处理这个过程的机制,这样会更好些。其实,PJMEDIA已经提供了使媒体流在媒体端口之间自行流动的机制,在 PJMEDIA_PORT_CLOCK 节中予以阐明。