来源: https://blog.csdn.net/gregcheng/article/details/5800564
媒体端口(Media Port)提供抽象和可扩展的框架(framework)来实现媒体端点。基本上,媒体端口接口有以下属性:
--媒体端口属性信息(pjmedia_port_info):描述媒体端口的属性,如采样频率(sampling rate)、通道数量(number of channels)等。
--指向从媒体端口获取语音帧的get_frame函数指针,这个函数将由公共API函数pjmedia_port_get_frame()调用。
--指向向媒体端口发送语音帧的put_frame函数指针,这个函数将由公共API函数pjmedia_port_put_frame()调用。
媒体端口都是被动"对象",应用程序或其他PJMEDIA组件必须手动调用pjmedia_port_get_frame()和pjmedia_port_put_frame()来从这个对象中获取或向这个对象发送语音帧。
一些媒体端口,如PJMEDIA_CONF、PJMEDIA_RESAMPLE_PORT可以从内部相互连接,而另一些端口代表语音帧的最终接收者或最初的发送者(终结者或始作者)。
例如,假设应用程序想一个WAV文件的采样频率转换为另一个频率,则应该创建并按照以下方式安排端口的连接:
应用程序使用下面的伪代码创建并设置媒体端口:
pjmedia_port *player, *resample, *writer;
pj_status_t status;
// Create the file player port.
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);
// Create the resample port with specifying the target sampling rate,
// and with the file port as the source. This will effectively
// connect the resample port with the player port.
status = pjmedia_resample_port_create( pool, player, 8000,
0, &resample);
PJ_ASSERT_RETURN(status==PJ_SUCCESS, PJ_SUCCESS);
// Create the file writer, specifying the resample port's configuration
// as the WAV parameters.
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);
// Get the frame from resample port.
status = pjmedia_port_get_frame(resample, &frame);
if (status != PJ_SUCCESS || frame.type == PJMEDIA_FRAME_TYPE_NONE) {
// End-of-file, end the conversion.
break;
}
// Put the frame to write port.
status = pjmedia_port_put_frame(writer, &frame);
if (status != PJ_SUCCESS) {
// Error in writing the file.
break;
}
}
完成转换后,应用程序要销毁媒体端口:
// Note: by default, destroying resample port will destroy the
// the downstream port too.
pjmedia_port_destroy(resample);
pjmedia_port_destroy(writer);
对于这个简单的WAV文件采样频率转换的例子,以上步骤就足够了。但是其他更为复杂的目的,读和写语音帧的过程可能需要以定时的方式进行,例如发送RTP包到一个远程的流对象。更进一步,随着应用程序规模的逐渐增大,手动读写语音帧的操作越来越频繁,如果PJMEDIA提供自动处理这个过程的机制,这样可能会更好。
事实上,PJMEDIA已经提供了使媒体流在媒体端口之间自动地流动的机制,在PJMEDIA_PORT_CLOCK 节描述这样的机制。