当前位置: 首页 > 工具软件 > QuteCom > 使用案例 >

QuteCom手记:phapi的声音驱动

通鸿风
2023-12-01


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()也同理。

 

 

 类似资料: