time: 2010-12-14 9:43:18
<-------主题:三个声音驱动------->
/wifo/phapi/phmedia-portaudio.c -- ph_pa_driver
/wifo/phapi/phmedia-audio-file.c--ph_phadfile_audio_driver
/wifo/phapi/phmedia-winmm.c -- ph_winmm_driver
time: 2010-12-14 10:4:49
<-------主题:会话开始时使用的驱动是pa驱动------->
会话开始时使用的驱动是pa驱动
2011-6-27补充详细说明:
---------------------------------------
phapi的声音驱动ph_audio_driver是一系列保存在结构体中的函数指针,这些函数定义了对音频流操作的标准接口。
phapi通过这些标准的接口从麦克风中读取数据以及写入数据到喇叭
---------------------------------------
驱动列表保存在全局变量:ph_snd_driver_map[MAX_SOUND_DRIVERS]
注册驱动到驱动列表的函数:void ph_register_audio_driver(struct ph_audio_driver *d)
将所选音频驱动作为为当前使用的驱动,参数为驱动名:int ph_activate_audio_driver(const char *name)(见下文@2$2处)
当前活动的驱动保存在全局变量:struct ph_audio_driver ph_snd_driver;
@1、从mic中读取数据和写入speaker的过程(高层逻辑)
---------------------------------------
$1、从mic中读取一块数据,默认640Bytes
#define audio_stream_read(as, buf, len) ph_snd_driver.snd_stream_read(as, buf, len)
ph_audio_io_thread()==>ph_handle_audio_data()==>audio_stream_read()
$2、从网络数据包(Rtp)中读取一块数据并播放,大小因codec而异
#define audio_stream_write(as, buf, len) ph_snd_driver.snd_stream_write(as, buf, len)
ph_audio_io_thread()==>ph_handle_network_data()==>audio_stream_write()
默认情况下ph_audio_io_thread()每隔20ms被调用一次(定时器保存在全局变量winmm_impl)。
file:qutecom/wifo/phapi/phmedia-audio.c
stream->ms.media_io_timer_impl->timer_set_callback(stream->ms.media_io_timer,ph_audio_io_thread);
@2、选择pa(PortAudio音频库)为驱动的过程
----------------------------------------
$1、owplAudioSetConfigString(const char* szAudioConfig)==>strncpy(phcfg.audio_dev, "pa:", sizeof(phcfg.audio_dev));
注意这个phcfg.audio_dev保存了音频设备(音频驱动)的名字。
$2、ph_call_media_start()==>ph_msession_start()或者ph_msession_resume()==>ph_msession_audio_start()
==>ph_msession_audio_stream_start()==>select_audio_device()==>ph_activate_audio_driver()
$3、portAudio的驱动注册在qutecom/wifo/phapi/phmedia-portaudio.c
ph_pa_driver_init(void)==>ph_register_audio_driver(&ph_pa_driver);
ph_pa_driver是保存了PortAudio驱动接口的全局变量,调用了ph_register_audio_driver后,pa驱动即被保存在ph_snd_driver中
@3、PortAudio从mic中读取数据和写入speaker过程(底层实现)
-----------------------------------------
这部分代码在工程PortAudio中。PortAudio是一个可靠的库,一般不需要更改它的代码。相关接口google搜索PortAudio有很多介绍。
@4、注意PortAudio声音驱动没有主动的read/write函数
结构体的
ph_audio_write *snd_stream_write;
ph_audio_read *snd_stream_read;
两个函数指针都为空。
PortAudio通过传入一个回调函数定时从mic读出数据和(或)将数据写入到speaker.具体参见PortAudio文档。phapi从PortAudio读取和写入媒体流数据的流程在《Qutecom手记:phapi发送和接收音频数据的流程简介》中介绍。
PS:
事实上选择使用PortAudio的回调机制就废除了声音驱动的定时器机制。 意味着无法通过声音驱动去读写音频数据。这里Phapi绕了一个小弯。但是这样并不会引起冲突,见一下代码(读过程,见@1$1):
注意i=audio_stream_read(stream, data_out, internal_framesize);
这里由于使用了没有read的PortAudio驱动,因此总是i==0。自然不会调用ph_audio_rec_cbk处理mic的数据(PortAudio设定的回调函数最终也是调用ph_audio_rec_cbk处理)。
写入speaker的过程ph_handle_network_data()也同理。