混音器:视频会议录制不可或缺的组件

     在定制开发视频会议系统时,有客户需要将视频会议的过程录制下来。一个视频会议是多个用户参与的,每个用户都有自己的视频和声音。录制视频会议就需要将他们的视频和声音录制到一个mp4文件中。

     这个时候,在视频方面就涉及到图像的合成,在声音方面就涉及到混音。所谓混音,就是将多路声音数据经过混音算法计算后,合成一路输出。其示意图如下所示:

  

     有的视频会议系统项目要求在客户端录制,有的则需要在服务器端录制,这两种情况,对于所采用的混音器会有所区别。

   OMCS提供的两种混音器组件:AudioInOutMixer 和 MicrophoneConnectorMixer,分别用于支持这两种情况。

     AudioInOutMixer 用于在客户端录制时使用,MicrophoneConnectorMixer 用于在服务端录制时使用。     

一. 在客户端录制视频会议

       在客户端录制时,一般需要录制当前用户所参与的语音视频会话。 OMCS.Passive.Audio.AudioInOutMixer 的作用就是将本地话筒设备的输入数据以及本地声音播放的输出数据进行混音。

       AudioInOutMixer  接口定义如下所示:

     public classIAudioInOutMixer
    {
        /// <summary>
        /// 本地话筒设备采集的一帧音频数据以及本地扬声器播放的一帧输出数据进行混音。(音频数据长度:10ms)
        /// </summary>
        event CbGeneric<byte[]> AudioMixed;

        /// <summary>
        /// 初始化
        /// </summary>
        /// <param name="mgr"></param>
        void Initialize(IMultimediaManager mgr);

        /// <summary>
        /// 释放混音器。
        /// </summary>
        void Dispose();        
    }

(1)调用Initialize 初始化混音器后,混音器变开始正常工作。

(2)AudioMixed 会每隔10ms触发一次,每次输出10ms的混音数据。

(3)当使用完毕后,需要调用混音器的Dispose方法释放混音器。     

二. 在服务端录制视频会议

      在服务端录制与在客户端录制是非常不一样的,差别在于:

(1)一般在客户端只需要录制一个会话,即当前登录用户参与的那个会话。而在服务端,通常需要同时录制多个会话。

(2)客户端录制时,只需要将麦克风的声音与喇叭播放的声音混音,就是全部了。

          而在服务端录制时,需要拿到参与目标会话的所有用户的声音数据进行混音。而且,还要考虑到用户动态地加入或退出目标会话的情况。

      在服务端录制时,每个录制任务都需要new一个对应的OMCS.Passive.Audio.MicrophoneConnectorMixer 

      MicrophoneConnectorMixer 用于将多个MicrophoneConnector的声音数据进行混音。 

      MicrophoneConnectorMixer 接口定义如下:

    public class MicrophoneConnectorMixer
    {
        /// <summary>
        /// 每隔20毫秒触发一次,输出混音数据。参数:声音最大的发言人UserID - data。
        /// 如果此时无人发言,则UserID参数为null,data为静音数据。
        /// </summary>
        event CbGeneric<string, byte[]> AudioMixed;

        /// <summary>
        /// 添加要参与混音的MicrophoneConnector。
        /// </summary>        
        void AddMicrophoneConnector(MicrophoneConnector mc);

        /// <summary>
        /// 移除参与混音的MicrophoneConnector。
        /// </summary>        
        void RemoveMicrophoneConnector(string ownerID);

        /// <summary>
        /// 释放混音器。
        /// </summary>
        void Dispose();        
    }

(1)调用AddMicrophoneConnector、RemoveMicrophoneConnector 可以动态添加和移除用户。

(2)请特别注意: 混音器仅仅是从MicrophoneConnector 获取声音数据,并不会调用其 BeginConnector 或 Disconnect 方法。

          MicrophoneConnector 必须要连接成功后,才调用AddMicrophoneConnector将其加入到混音器中。

(3)使用完毕时,切记要调用Dispose方法释放混音器。   

三. 混音器优化

  在混音器实际使用的过程中,为了达到最佳的混音效果,还有一些可以优化的地方。

(1)当很多人都同时在发言时,如果将所有的声音都加入到混音,可想而知,混音的结果就是乱哄哄的。

         这种情况下,我们可以只混音发言音量最大1~3个人。

(2)在腾讯视频会议里,有个很人性化的功能,就是当某个人发言时(或其音量最大时),其视频图像会放大,以将用户的注意力焦点集中在发言人身上。

  这两种优化都是在混音器里实现的,其底层的实现原理大致是这样的:

(1)将多路语音帧在混音之前,先分别计算每个帧的分贝值。(通过傅里叶变换就可以计算出声音的分贝值)

(2)将计算出的多个分贝值进行排序,从大到小排列。

(3)只将分贝值最大的前1~3的语音帧提交给混音算法。

(4)在输出混音结果时,同时将分贝值最大的用户的ID也同时输出。

   通过设置IMultimediaManager的Advanced的AudioMixedStrategy属性,即可指定需要将分贝值最大的前几个混音。

    /// <summary>
    /// 混音策略。
    /// </summary>
    public enum AudioMixedStrategy
    {
        /// <summary>
        /// 只要有声音数据的line,都参与混音。
        /// </summary>
        All = 0,
        /// <summary>
        /// 只混音分贝值排名第一的line。
        /// </summary>
        DecibelTop1,
        /// <summary>
        /// 只混音分贝值排名前二的line。
        /// </summary>
        DecibelTop2,
        /// <summary>
        /// 只混音分贝值排名前三的line。
        /// </summary>
        DecibelTop3
    }

  我们再看MicrophoneConnectorMixer 的 AudioMixed事件,它不仅输出了混音数据,而且还输出了发言声音最大音量的那个用户的ID。

       经过上述优化后,混音器输出的数据就非常好用了,可以满足当前视频会议项目实际的录制需求了。