1、设置conference->video_floor_holder成员的函数
conference_set_video_floor_holder(conference_obj_t *conference, conference_member_t *member, switch_bool_t force)
- 前提是检查到该member有video视频功能。
- 关键是函数内设置conference对象的成员这一句:
conference->video_floor_holder = member;
。 - 若传入的member参数为NULL,则会遍历会议中成员链表将第一个(链表是头插法故链表第一个往往是最后一个进入会议中的成员)非原video_floor_holder的成员设为新的video_floor_holder。
- 若传入的第三参数force为true,则会设置floor锁定标志
switch_set_flag(conference, CFLAG_VID_FLOOR_LOCK)
,若是其他地方要更改video_floor_holder则必须是在检查非锁定状态下才可以更改。 - 函数中默认会打印DEBUG1类型的日志通知旧的和新的video_floor_holder更新。可换成INFO或者NOTIFY类型日志,更容易看到。
- 函数末尾还会生成用户自定义事件CUSTOM::conference::maintenance下发新旧video_floor_holder更新的通知,可用事件订阅的方式获取。
2、设置conference->floor_holder成员的函数
conference_set_floor_holder(conference_obj_t *conference, conference_member_t *member)
- 适用于任何有无视频功能的member。
- 首先会检查该member是否支持video视频,若是,则也会调用
conference_set_video_floor_holder
函数去设置video_floor_holder。 - 若传入的member参数为NULL,则将floor_holder也设为NULL。
- 其他打印日志和下发事件通知功能同上。
3、通过api去修改floor拥有者
- 控制台api命令:
conference 3000 floor member-id
conference 3000 vid-floor member-id [force]
若是加了force则锁定该video_floor
conference 3000 clear-vid-floor
- 模块内函数调用逻辑:
conf_api_sub_floor =》conference_set_floor_holder
conf_api_sub_vid_floor =》conference_set_video_floor_holder
conf_api_sub_clear_vid_floor =》switch_clear_flag(conference, CFLAG_VID_FLOOR_LOCK),即解除video_floor锁定
4、通过dtmf键控去修改floor拥有者
- 可在配置文件conference.conf.xml中设置某个按键对应
vid-floor-force
,然后再模块源码中有一个映射表,将vid-floor-force
动作对应到一个函数conference_loop_fn_vid_floor_force
,该函数内部实际调用上面的conf_api_sub_vid_floor
函数。
5、根据声音能量member->score_iir切换floor_holder
- score_iir在代码开头使用宏定义设置
SCORE_IIR_SPEAKING_MAX 300
,SCORE_IIR_SPEAKING_MIN 100
,意思是一个已经获取floor的用户只有在score_iir值小于100时才会失去floor控制权,否则会先保持而不是说有其他member的值比它的大就切换。而其他用户想要获取floor,则至少要自身score_iir值大于300。这两个条件同时满足才会因为声音能量去切换floor_holder。 - 证明,在
conference_thread_run
函数中对每一个收到的语音包检查(imember->score_iir > SCORE_IIR_SPEAKING_MAX && (floor_holder->score_iir < SCORE_IIR_SPEAKING_MIN)
若满足条件,则会切换floor_holder。当然,若是没有旧的floor_hoder则第一个检查的member就是。 - 关于score_iir声音能量值的修改是在函数
conference_loop_input
中会对每个接收的语音数据包进行分析,然后统计出声音能量值,再更新这一个member对应的score_iir成员值
member->score_iir = (int) (((1.0 - SCORE_DECAY) * (float) member->score) + (SCORE_DECAY * (float) member->score_iir));
。其中的member->score = energy / samples;
而energy是对接收到的语音数据包的data的每个short两字节数据取绝对值然后统计求和,而samples是一个对应于这条channel的采样值。 - 具体切换,也是调用
conference_set_floor_holder
函数。
针对项目问题解决方案:
- 已在conference_set_video_floor_holder函数中旧的和新的video_floor_holder更新时打印INFO类型日志。可看到切换时打印的用户账号名(%s)和用户声音能量值(%d)。代码在2555行左右:
丢弃旧的"===================================Dropping video floor %s, score_iir=%d\n"
增加新的"===================================Adding video floor %s, score_iir=%d\n" - 若是video_floor_holder一直不切换,也就是视频会议一直只显示一个人的视频,那就让其他用户使用按键’#’去强制获取video_floor_holder,然后就会触发调用上面这个函数打印出以上日志。然后就可以看到一直占据video_floor_holder的用户是谁,以及他的声音能量score_iir是多少,若是该能量值一直是高于100的,那么就符合逻辑,因为只有在该能量值低于100并且同时其他会议成员的能量值高于300时才会引发切换。
-
方案一:
若是因为score_iir值一直高于100,那就只能想办法从客户端那边将话机不讲话时的score_iir控制在100以下。 -
方案二:
或者也可以通过观察打印出的日志,看看话机不讲话时score_iir的值在什么水平范围,假设一直在150左右不高于160,那么也可以在服务器的会议模块代码mod_conference.c中设置将该能量低阈值从100设置为160。具体设置很简单,只需要将代码第91行的宏定义修改为:
#define SCORE_IIR_SPEAKING_MIN 160
然后在mod_conference.c所在文件目录位置,执行make install 命令,重新编译安装mod_conference.c文件,并在服务器中重新加载会议模块或者重启服务器。