混音器:視頻會議錄製不可或缺的組件

     在定製開發視頻會議系統時,有客戶需要將視頻會議的過程錄製下來。一個視頻會議是多個用戶參與的,每個用戶都有自己的視頻和聲音。錄製視頻會議就需要將他們的視頻和聲音錄製到一個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。

       經過上述優化後,混音器輸出的數據就非常好用了,可以滿足當前視頻會議項目實際的錄製需求了。