phapi发送和接收音频数据的流程简介。
通过ortp库(完整的源代码在ortp工程中)实现。
oRTP协议将在另外一篇中介绍,这里只要知道它是用来发送和接收媒体流(音频和视频)的协议。
本篇只记录使用ortp发送、接收音频数据的流程。
@1 phapi使用ortp的简单流程:
-----------------------------------------------
$1、初始化库
在整个程序的生命周期中只初始化一次ortp库
qutecom/wifo/phapi/phmedia.c
ph_media_init()==>ortp_init()
$2、初始化一个RTP会话以及设置RTP会话的参数
qutecom/wifo/phapi/phmedia-audio.c
ph_msession_audio_stream_hardstart()函数
LINE 3019:session = rtp_session_new(RTP_SESSION_SENDRECV);
至
LINE 3242:rtp_session_signal_connect(session, "cng_packet", (RtpCallback)ph_on_cng_packet, s);
$3、接收一个RTP数据包
e:/works/qutecom/wifo/phapi/phmedia-audio.c
ph_audio_play_cbk()==>ph_media_retrieve_decoded_frame()==>rtp_session_recvm_with_ts()
$4、发送一个RTP数据包
qutecom/wifo/phapi/phmedia-audio.c
ph_audio_rec_cbk()==>ph_encode_and_send_audio_frame()==>rtp_session_sendm_with_ts()||rtp_session_send_with_ts()
$5、销毁一个RTP会话
e:/works/qutecom/wifo/phapi/phmedia-audio.c
ph_msession_audio_stream_stop()==>rtp_session_destroy()
@2 从PortAudio获取音频数据到ortp发送音频数据的流程。
----------------------------------------------
$1、PortAudio在phapi中的驱动封装
struct ph_audio_driver ph_pa_driver = {
"pa",
PH_SNDDRVR_REC_CALLBACK|PH_SNDDRVR_PLAY_CALLBACK,
0, pa_stream_start, pa_stream_open,
NULL, NULL,
pa_stream_get_out_space,
pa_stream_get_avail_data,
pa_stream_close, NULL, NULL
};
注意:结构体的第6、7项为NULL,这两个地方是放从mic读取和写入speaker的接口的地方。PortAudio不提供获取音频/写入音频的接口而是采用回调方式。
portAudio要求使用者提供一个回调函数,PortAudio根据对它的设定,定时获得mic数据或者写入speaker时自动调用该函数。该回调函数必须在打开portaudio (Pa_OpenStream)时指定。Phapi中该回调函数是ph_pa_callback
File:/qutecom/wifo/phapi/phmedia-portaudio.c
static intph_pa_callback(const void *input, void *output,
unsigned long frameCount,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData ){
phastream_t *as = (phastream_t *) userData;
int outCount = (int) frameCount * 2;
int needMore;
ADEV(as)->cbk(as, (void *) input, (int) frameCount * 2, output, &outCount);
needMore = frameCount * 2 - outCount;
if (needMore > 0) {
memset(outCount + (char *)output, 0, needMore);
}
return as->ms.running ? paContinue : paAbort;
}
注意:
ADEV(as)->cbk(as, (void *) input, (int) frameCount * 2, output, &outCount);
这个cbk指向:ph_audio_callback() (pa_stream_open()函数的最后一个参数设置这个cbk)
File:/qutecom/wifo/phapi/phmedia-audio.c
/**
* @brief callback used by the audio subsystems to communicate with the phapi audio engine
* @param stream the concerned audio stream
* @param recbuf buffer that has just been recorded by the subsystem
* @param recbufsize size of the recorded buffer (maybe 0)
* @param playbuf
* @param playbufsize
*/
static int
ph_audio_callback(phastream_t *stream, void *recbuf, int recbufsize, void *playbuf, int *playbufsize)
{
int i = 0;
if (stream->ms.running)
{
if (recbuf && recbufsize > 0)
{
ph_audio_rec_cbk(stream, recbuf, recbufsize);
}
if ((playbuf != 0) && playbufsize && (*playbufsize > 0))
{
i = ph_audio_play_cbk(stream, playbuf, *playbufsize);
*playbufsize = i;
}
}
return 0;
}
代码中分别调用了ph_audio_rec_cbk和ph_audio_play_cbk两个函数,结合上面@1($3$4)的流程就构成了一个从portAudio获取数据到使用RTP接收和发送数据的完整流程。