OMCS 开发手册(01) -- 多媒体设备管理器

       我们在前面一篇文章中提到:任何一个OMCS的Client都有两种身份,Owner和Guest。多媒体设备管理器就是工作于OMCS客户端,并以Owner的身份管理本地所有的多媒体设备的。多媒体设备管理器对象是OMCS在客户端的核心对象,它会根据guest的请求自动启动或停止某个多媒体设备。

一.多媒体设备

       像本地的摄像头、麦克风、电子白板等都属于多媒体设备,多媒体设备的类型使用枚举MultimediaDeviceType表示: 

    /// <summary>
    /// 多媒体设备的类型。
    /// </summary>
    public enum MultimediaDeviceType
    {
        /// <summary>
        /// 摄像头。
        /// </summary>
        Camera = 0,
        /// <summary>
        /// 话筒。
        /// </summary>
        Microphone,
        /// <summary>
        /// 桌面。
        /// </summary>
        Desktop,      
        /// <summary>	
        /// 电子白板。
        /// </summary>
        WhiteBoard
    }

       目前的OMCS支持MultimediaDeviceType定义的4种多媒体设备类型,所有的多媒体设备都由多媒体管理器IMultimediaManager统一管理。

(1) 客户端以Owner身份提供本地的多媒体设备供其它客户端访问。

(2) 各种类型的多媒体设备对应的类Class都是internal的,属于OMCS的内部对象,开发人员不需要对其进行任何编程。取而代之的是,开发人员可以通过IMultimediaManager来间接获取多媒体设备的有关状态和信息。

(3)如何获取当前电脑的摄像头、麦克风、声卡的硬件设备信息了?OMCS提供了工具类,具体可参考 OMCS 开发手册(11) -- 深入摄像头、麦克风、扬声器

二.多媒体设备管理器详解

       作为OMCS客户端的核心对象,多媒体管理器的主要职责为:

(1)管理本地的所有多媒体设备实例,设置设备参数,以及在合适的时间启动或停止某个多媒体设备。

(2)与OMCS服务器通信,并管理与OMCS服务器之间连接的状态。

(3)创建P2P通道。在多媒体连接器发起到目标设备的连接请求时,同时异步创建到目标Owner的双向P2P通道。

       上述这些职责,可以通过多媒体设备管理器的接口OMCS.Passive.IMultimediaManager的定义体现出来。

1.属性

       IMultimediaManager接口中所有的属性定义如下: 

         /// <summary>
        /// 已连接的多媒体服务器的地址。
        /// </summary>
        AgileIPEndPoint ServerIPE {get; }            

        /// <summary>
        /// 当前登录用户的ID。
        /// </summary>
        string CurrentUserID { get; }

        /// <summary>
        /// 当前多媒体管理器是否可用?(与OMCS服务器成功连接?并且设备管理器已经初始化完成?)
        /// </summary>
        bool Available { get; }

        /// <summary>
        /// 当前多媒体管理器是否正在工作?
        /// 如果没有任何guest连接到本地多媒体设备,并且自己也没有连接到别人的设备,则返回false。否则返回true。
        /// </summary>      
        bool Working { get; }

        /// <summary>
        /// 掉线后,是否自动重连。(如果要set该属性,则必须在调用Initialize方法之前设置才有效。)
        /// </summary>
        bool AutoReconnect { get; set; }

         /// <summary>
        /// 设备访问控制器,用于控制哪些guest能访问自己的设备(麦克风、摄像头、桌面)。如果不需要控制,则设置为null。默认值:null。
        /// </summary>
        IAccessController AccessController { get; set; }

        /// <summary>
        /// 语音视频聊天组入口。(只有多媒体管理器初始化成功之后,该属性才有效)
        /// </summary>
        IChatGroupEntrance ChatGroupEntrance { get; }
        
        /// <summary>
        /// 语音消息控制器。在当前多媒体设备管理器初始化成功之前,该属性将返回null。
        /// 注意:在正式使用语音消息控制器之前,先要调用IAudioMessageController的Initialize方法将其初始化。
        /// </summary>
        IAudioMessageController AudioMessageController { get; }

        /// <summary>
        /// OMCS高级控制选项。如果要修改AdvancedOptions的某些属性值,必须在调用Initialize方法之前设置才有效。
        /// </summary>
        AdvancedOptions Advanced { get; }

        /// <summary>
        /// 用于注入自定义的声音采集器工厂。(必须在调用Initialize方法之前设置才有效。)
        /// </summary>
        IAudioCapturerFactory AudioCapturerFactory { get; set; }

        /// <summary>
        /// 要使用的麦克风的索引。可以在运行时动态修改。
        /// </summary>
        int MicrophoneDeviceIndex { get; set; }

        /// <summary>
        /// 要使用的扬声器的索引。可以在运行时动态修改。
        /// </summary>
        int SpeakerIndex { get; set; }

        /// <summary>
        /// 是否将话筒采集到的音频输出给Guest。(必须在初始化完成之后设置才有效,可动态修改。)
        /// 如果为true,表示输出;否则,表示将采集到的音频数据丢弃,不发送给guest。默认值为true。(比如在视频会议中,只将发言人的OutputAudio设为true,以减少带宽和避免杂音)
        /// </summary>       
        bool OutputAudio { get; set; }

        /// <summary>
        /// 输出音量的放大系数。取值范围1~10。默认值1(表示不放大)。可以在运行时动态修改。
        /// </summary>
        int VolumeAmplifyFactor { get; set; }    

        /// <summary>
        /// 是否静音(来自任何owner的声音都不播放)。
        /// </summary>
        bool Mute { get; set; }
         
        /// <summary>
        /// OMCS使用的音源输入模式。默认值为OnlyMicrophone。
        /// </summary>
        AudioInputMode AudioInputMode { get; set; }

        /// <summary>
        /// 当AudioInputMode为BothSoundcardAndMicrophone或BothExtendAndMicrophone时,用于控制声卡或自定义扩展音源的声音的放大系数。默认值为0.5。(一般声卡或自定义扩展音源播放的是作为背景音乐存在的)
        /// </summary>
        float SoundcardVolumeCoef { get; set; }

        /// <summary>
        /// 刚刚播放的音频帧(10ms的PCM数据)。
        /// </summary>
        event CbGeneric<byte[]> AudioPlayed;

        /// <summary>
        /// 刚刚从麦克风或自定义声音采集器采集的音频帧(10ms的PCM数据)。
        /// </summary>
        event CbGeneric<byte[]> AudioCaptured;

        /// <summary>
        /// 如果连接到了多个人的麦克风,此事件用于定时通知最大声音的说话者。参数:SpeakerID - 声音的分贝值。
        /// 当没有人说话时,SpeakerID 为 null。
        /// 注:只有当Advanced.AudioMixedStrategy的值不是AudioMixedStrategy.All时,才会触发此事件。
        /// </summary>
        event CbGeneric<string, int> MaxVoiceSpeakerNotified;
        
        /// <summary>
        /// 用于注入自定义的视频采集器工厂。(必须在调用Initialize方法之前设置才有效。)
        /// </summary>
        IVideoCapturerFactory VideoCapturerFactory { set; }

        /// <summary>
        /// 要使用的摄像头的索引。默认值0。可以在运行时动态修改。
        /// 【如果在初始化之前将CameraDeviceIndex设置为0,那么框架将自动选择第一个有效的摄像头,这意味着初始化完成后,CameraDeviceIndex的值可能不再是0。】
        /// </summary>
        int CameraDeviceIndex { get; set; }       

        /// <summary>
        /// 摄像头采集视频的大小。如果当前摄像头不支持指定的尺寸,则会自动匹配到最相近的分辨率。可以在运行时动态修改。
        /// </summary>
        Size CameraVideoSize { get; set; }

         /// <summary>
        /// 摄像头的最大帧频。默认值:15。(必须在调用Initialize方法之前设置才有效。)
        /// </summary>
        int MaxCameraFrameRate { get; set; }

        /// <summary>
        /// 摄像头采集的视频的编码质量。取值0~31,取值越小,质量越高。可以在运行时动态修改。
        /// </summary>
        int CameraEncodeQuality { get; set; }

        /// <summary>
        /// [从Owner的角度]是否根据音频反馈以及视频丢帧情况自动调整视频编码质量。默认值为true。(以保证音频连贯性)。可以在运行时动态修改。
        /// </summary>
        bool AutoAdjustCameraEncodeQuality { get; set; }

        /// <summary>
        /// 是否将摄像头集到的视频输出给Guest。 默认值为true。(必须在初始化完成之后设置才有效,可动态修改。)
        /// 如果为true,表示输出;否则,表示将采集到的视频数据丢弃,不发送给guest。默认值为true。
        /// </summary> 
        bool OutputVideo { get; set; }

        /// <summary>
        /// 当摄像头切换完成以后,触发此事件。参数为:切换之前摄像头索引 - 切换后的摄像头索引
        /// </summary>
        event CbGeneric<int, int> CameraIndexChanged;

        /// <summary>
        /// 切换摄像头【异步调用】。如果切换成功,将触发CameraIndexChanged事件。
        /// </summary>
        /// <param name="deviceIndex">要切换到的目标摄像头的索引</param>
        void ChangeCameraDeviceAsyn(int deviceIndex);      
  
        /// <summary>
        /// 桌面的最大帧频。默认值:10。(必须在调用Initialize方法之前设置才有效。)
        /// </summary>
        int MaxDesktopFrameRate { get; set; } 

        /// <summary>
        /// 是否将桌面图像输出给Guest。默认值为true。(必须在初始化完成之后设置才有效,可动态修改。) 
        /// </summary>
        bool OutputDesktop { get; set; }

        /// <summary>
        /// 允许guest操作桌面。默认值为true。(必须在初始化完成之后设置才有效,可动态修改。)    
        /// </summary>
        bool AllowControlDesktop { get; set; }

        /// <summary>
        /// 本地桌面的编码质量。取值0~31,取值越小,越清晰。可以在运行时动态修改。
        /// </summary>       
        int DesktopEncodeQuality { get; set; }

        /// <summary>
        /// 要捕捉的屏幕的区域。
        /// 如果set为null,则表示捕捉整个屏幕。可以在运行时动态修改。【桌面采集器会将长和宽修正为8的整数倍】
        /// </summary>
        Rectangle? DesktopRegion { get; set; }       
        
        /// <summary>
        /// 用于缓存白板课件的根目录。默认值为运行目录下的"Coursewares"文件夹。
        /// </summary>
        string CoursewaresRootPath { get; set; }

        /// <summary>
        /// 用于注入自定义的图片转换器工厂。(必须在调用Initialize方法之前设置才有效。)
        /// </summary>
        IImageConverterFactory ImageConverterFactory { get; set; }

        /// <summary>
        /// [从Owner的角度]Owner发送帧数据给Guest时,通道的选择模型。默认值为P2PChannelFirst。必须在初始化前设置才有效。
        /// </summary>
        ChannelMode ChannelMode { get; set; }   
      
        /// <summary>
        /// 记录OMCS日志的文件路径,默认值为在运行目录下的OmcsLog.txt文件。(运行目录下可能没有写权限)。设为null(且OmcsLogger也设为null),表示不记录任何日志。
        /// </summary>
        string OmcsLogPath { get; set; }

        /// <summary>
        /// 如果被赋非null值,则OmcsLogPath属性将无效。(必须在调用Initialize方法之前设置才有效。)
        /// </summary>
        IAgileLogger OmcsLogger { set; }

        /// <summary>
        /// 是否记录安全日志。默认值为false。
        /// </summary>
        bool SecurityLogEnabled { get; set; }                                

(1)基础属性

       ServerIPE 只读属性显示了当前多媒体管理器连接的OMCS服务器的地址。 

       CurrentUserID 只读属性可以获取当前登录的用户的UserID。只有在多媒体管理器初始化(Initialize方法)成功之后,该属性才有效。     

       Available 属性显示了当前多媒体管理器是否与OMCS服务器成功建立了连接并完成了初始化,而处于可用状态。只有该属性为true时,多媒体管理器才可以正常使用。

       AudioMessageController 属性是语音消息控制器,在使用之前,先要调用IAudioMessageController的Initialize方法将其初始化。具体可参见:OMCS 开发手册(10) -- 语音消息

        OmcsLogPath 多媒体管理器会捕获内部产生的所有异常,并将其记录到OmcsLogPath指定的日志文件。其默认是运行目录下的OmcsLog.txt文件,但是,如果我们将基于OMCS的客户端程序安装在C盘,那么在win7下以普通身份运行起来后,是没有权限写运行目录的,这时,我们通常将日志路径设在“我的文档”的目录下面。  

        ChannelMode 属性用于控制通道选择模型。即当存在P2P通道时,那么多媒体数据传送的路径就有两种:经服务器中转、或直接经P2P通道传送。ChannelMode用于控制使用哪条通道传送多媒体数据。       

(2)语音视频相关

       CameraDeviceIndex、MicrophoneDeviceIndex、SpeakerIndex 属性用于分别设置要使用的本地摄像头、麦克风、以及扬声器的索引。

       如果当前机器接有多个摄像头或者话筒设备,则可以通过这几个属性来明确指定要使用哪个设备。在大多数情况下,这两个属性设为0即可,其默认值也是0。       

       OutputAudio和OutputVideo 属性用于控制是否输出采集到的音频/视频数据给guest。

       比如在视频会议中,我们可以只将当前发言人的OutputAudio设为true,而将其它成员的OutputAudio设为false,以减少带宽和避免杂音。

       CameraVideoSize 用于设定摄像头采集视频的大小,现在的摄像头通常都支持很多种视频采集尺寸,后面的文章会详细介绍如何获取摄像头所支持的视频尺寸列表。

       CameraEncodeQuality 属性用于设定摄像头视频的编码质量。我们可以根据网络状态动态调节它们的值,以控制带宽的使用。

       AutoAdjustCameraEncodeQuality属性用于控制是否开启视频质量自动调节功能。

       AudioInputMode 属性用于设定OMCS使用的音源输入模式。

       SoundcardVolumeCoef  属性用于控制声卡或自定义扩展音源的声音的放大系数。  当AudioInputMode设置为BothSoundcardAndMicrophone或BothExtendAndMicrophone时,才有效。  

       OMCS内部内置了一套音频/视频优化策略,其可以根据音频反馈以及视频丢帧的情况自动调整视频编码质量,以优先保证音频的清晰与流畅。如果该属性设为true,将开启这套内置策略。如果该属性开启,则CameraEncodeQuality属性的设置,将不再有效;但是我们仍然可以通过CameraEncodeQuality属性读取到当前视频的编码质量。          

       AudioCapturerFactory、VideoCapturerFactory 属性分别用于注入自定义的音频/视频采集器,比如视频图像来自于网络摄像头或者特殊的视频采集卡(如AV-878采集卡)。具体可参见:OMCS 开发手册(07) -- 扩展音视频输入

       MaxCameraFrameRate 属性用于设定摄像头的最大帧频。只有在多媒体管理器初始化(Initialize方法)之前设置,该属性才有效。

       ChatGroupEntrance 属性用于对多人语音/视频聊天组进行直接支持。具体可参见:OMCS 开发手册(08) -- 多人语音/视频

       上述的很多属性可以在运行的过程中进行修改,这就提供了类似动态切换设备的能力,具体可参考 OMCS 开发手册(11) -- 深入摄像头、麦克风、扬声器。  

(3)远程桌面相关

       OutputDesktop 同 OutputAudio和OutputVideo 属性的作用一样。

       AllowControlDesktop 是对Guest操作当前Owner桌面的总控制,如果AllowControlDesktop为false,即使Guest端的桌面连接器的WatchingOnly为false,Guest仍然不能操作桌面。

        DesktopEncodeQuality 是桌面视频的编码质量。同CameraEncodeQuality不一样,DesktopEncodeQuality不会根据网络状况自动调节。

       DesktopRegion 属性允许我们只共享桌面的一部分(比如,仅仅共享某个应用程序的窗口)给Guest,这样可以节省带宽。      

       MaxDesktopFrameRate 属性用于设定桌面的最大帧频,只有在多媒体管理器初始化(Initialize方法)之前设置,该属性才有效。

(4)电子白板相关          

      CoursewaresRootPath和ImageConverterFactory用于电子白板的课件功能。

      当客户端从服务器下载课件文件时,CoursewaresRootPath指定了用于存储这些白板课件文件的根目录。

      ImageConverterFactory 用于注入自定义的图片转换器工厂,OMCS通过它可以将目标类型的课件转换成图片以供电子白板使用。

      关于如何实现ImageConverterFactory接口,可参考 OMCS 使用技巧 -- 扩展电子白板支持课件的类型:word、pdf、ppt 。        

2.方法

       IMultimediaManager接口中所有的方法定义如下:

        /// <summary>
        /// 与多媒体服务器建立连接,并初始化本地多媒体管理器。
        /// 如果与服务器连接失败,将抛出网络异常。       
        /// </summary>     
        /// <param name="userID">当前登录的用户ID。</param>
        /// <param name="password">当前登录的用户的密码。</param>
        /// <param name="serverIP">OMCS服务器IP</param>
        /// <param name="serverPort">OMCS服务器端口</param>
        void Initialize(string userID,string password, string serverIP, int serverPort);

        /// <summary>
        /// 主动断开来访者guest到本地多媒体设备的连接。
        /// </summary>
        /// <param name="guestID">来访者的用户ID</param>
        /// <param name="deviceType">设备类型</param>
        /// <param name="notifyGuest">是否通知对方。如果通知对方,对方的连接器将触发Disconnected事件。</param>
        void DisconnectGuest(string guestID, MultimediaDeviceType deviceType ,bool notifyGuest);

        /// <summary>
        /// 主动断开所有来访者到本地多媒体设备的连接。
        /// </summary>       
        /// <param name="notifyGuest">是否通知对方。如果通知对方,对方的连接器将触发Disconnected事件。</param>
        void DisconnectGuest(bool notifyGuest);

        /// <summary>
        /// 获取所有连接到当前多媒体设备的Guest列表。
        /// </summary>
        List<string> GetGuests(MultimediaDeviceType deviceType);

        /// <summary>
        /// 查看已经连接了哪些用户的指定设备?
        /// </summary>       
        List<string> GetOwners(MultimediaDeviceType deviceType);

        /// <summary>
        /// 查询本地的某设备是否正在工作?
        /// </summary>        
        /// <param name="deviceType">设备类型</param>
        /// <returns>工作中?</returns>
        bool DeviceIsWorking(MultimediaDeviceType deviceType);     
  
        /// <summary>
        /// 和目标用户之间是否打通了P2P通道?
        /// </summary>
        /// <param name="destUserID">目标用户的ID</param>       
        bool IsP2PChannelExist(string destUserID);
       
         /// <summary>
        /// 目标用户是否在线
        /// </summary>
        /// <param name="userID">目标用户的ID</param>      
        bool IsUserOnline(string userID);

        /// <summary>
        /// 切换摄像头【异步调用】。如果切换成功,将触发CameraIndexChanged事件。
        /// </summary>
        /// <param name="deviceIndex">要切换到的目标摄像头的索引</param>
        void ChangeCameraDeviceAsyn(int deviceIndex);

        在使用多媒体管理器之前,首先要调用Initialize方法将其进行初始化,初始化将做如下几件事情:

(1)与目标OMCS服务器建立连接。

(2)使用参数传入的帐号密码进行登录。

(3)如果登录成功,则初始化本地的各个多媒体设备。

        注意,如果与服务器连接失败,或者帐号密码错误,则将抛出相应的异常。只有Initialize方法成功返回后,其它的方法才能被正常调用。 

         DisconnectGuest 方法用于Owner主动断开某个guest或所有guest到本地某设备的连接,该方法为Owner提供了一种主动性的权利。   

         IsP2PChannelExis方法用于检查和目标用户之间是否打通了P2P通道,如果P2P通道存在,则后续的音视频数据将直接走P2P通道,而不是经过服务器中转。   

         IsUserOnline方法用于检查目标用户是否在线。

         ChangeCameraDeviceAsyn 方法用于切换摄像头。切换成功触发CameraIndexChanged事件。

        剩下的几个方法,像DeviceIsWorking、GetGuests、GetOwners等,比较容易理解,就不再赘述。

3.事件 

       IMultimediaManager接口中所有的事件定义如下: 

        /// <summary>
        /// 当与目标媒体服务器的连接断开时,触发此事件。事件参数:目标多媒体服务器的地址。
        /// </summary>
        event CbGeneric<IPEndPoint> ConnectionInterrupted;

        /// <summary>
        /// 当与目标媒体服务器重连成功时,触发此事件。事件参数:目标多媒体服务器的地址。
        /// </summary>
        event CbGeneric<IPEndPoint> ConnectionRebuildSucceed;       

        /// <summary>
        /// 当某个guest连接到当前设备时,触发此事件。参数为guestID - MultimediaDeviceType
        /// </summary>
        event CbGeneric<string, MultimediaDeviceType> DeviceConnected;

        /// <summary>
        /// 当某个guest从当前设备断开时,触发此事件。参数为guestID - MultimediaDeviceType
        /// </summary>
        event CbGeneric<string, MultimediaDeviceType> DeviceDisconnected;

        /// <summary>
        /// 当本地多媒体设备报错时,会触发该事件。参数为 MultimediaDeviceType - DeviceIndex - 错误描述
        /// </summary>
        event CbGeneric<MultimediaDeviceType, int, string> DeviceErrorOccurred;

        /// <summary>
        /// 当连接器与目标设备之间的连接断开时,触发此事件。参数为: 断开的连接器 - 断开的原因
        /// </summary>
        event CbGeneric<IMultimediaConnector, ConnectorDisconnectedType> ConnectorDisconnected;

        /// <summary>
        /// 当多媒体管理器关闭并释放时,触发此事件。
        /// </summary>
        event CbGeneric Disposed;
  
        /// <summary>
        /// 刚刚播放的音频帧(10ms的PCM数据)。
        /// </summary>
        event CbGeneric<byte[]> AudioPlayed;

        /// <summary>
        /// 刚刚从麦克风或自定义声音采集器采集的音频帧(10ms的PCM数据)。
        /// </summary>
        event CbGeneric<byte[]> AudioCaptured;

        /// <summary>
        /// 如果连接到了多个人的麦克风,此事件用于定时通知最大声音的说话者。参数:SpeakerID - 声音的分贝值。
        /// 当没有人说话时,SpeakerID 为 null。
        /// 注:只有当Advanced.AudioMixedStrategy的值不是AudioMixedStrategy.All时,才会触发此事件。
        /// </summary>
        event CbGeneric<string, int> MaxVoiceSpeakerNotified;

        /// <summary>
        /// 当摄像头切换完成以后,触发此事件。参数为:切换之前摄像头索引 - 切换后的摄像头索引
        /// </summary>
        event CbGeneric<int, int> CameraIndexChanged;

       多媒体管理器初始化成功后,与OMCS服务器的长连接就建立了。当与OMCS服务器的连接断开时,将触发ConnectionInterrupted事件。特别要注意:当ConnectionInterrupted事件触发时,本地的所有多媒体设备都将停止工作。

       多媒体管理器内部自动使用了断线重连机制,当网络恢复后,会自动重连OMCS服务器,如果重连成功,将会触发ConnectionRebuildSucceed事件。我们可以通过ConnectionInterrupted事件、ConnectionRebuildSucceed事件、以及Available属性来监控多媒体管理器与OMCS服务器之间的连接状态。

       当本地多媒体设备报错时,会触发事件DeviceErrorOccurred。并通过事件第三个参数 来查找错误原因。

       当多媒体连接器与目标设备之间的连接断开时,会触发事件ConnectorDisconnected。并通过参数 ConnectorDisconnectedType> 来查找断开原因。

       当多媒体管理器关闭并释放时,触发Disposed事件。

       AudioPlayed事件用于暴露刚刚播放的音频帧。

       AudioCaptured事件用于暴露刚刚从麦克风或自定义声音采集器采集的音频帧。

       MaxVoiceSpeakerNotified事件。  如果连接到了多个人的麦克风,此事件用于定时通知最大声音的说话者。只有当Advanced.AudioMixedStrategy的值不是AudioMixedStrategy.All时,才会触发此事件。

       CameraIndexChanged 当摄像头切换完成以后,触发此事件。

       当某个guest连接到本地的某多媒体设备时,将触发DeviceConnected事件;当某个guest与本地的某多媒体设备断开时,将触发DeviceDisconnected事件。这两个事件的参数都指明了设备的类型和guest的UserID。

三.Singleton模式

       可以想象,一般在一个进程中,我们只需要一个多媒体管理器实例。那么,我们可以以Singleton模式来使用多媒体管理器。

       在设计OMCS时,IMultimediaManager接口的实现类MultimediaManager是internal的,在OMCS外部,我们看不到它的存在,所以也就没有办法new一个MultimediaManager实例。OMCS已经为我们提供了MultimediaManagerFactory静态类,让我们更方便地以单件模式使用多媒体管理器实例,其GetSingleton方法直接返回这个单件。  

      本文主要从作为设备的Owner的角度出发,讨论了多媒体设备管理器有哪些职责,以及其提供的API是如何工作的。下篇文章,我们将从作为Guest的角度触发,讨论如何使用多媒体连接器

 

相关内容:语音视频设备详解语音视频设备测试 

下一篇:OMCS 开发手册(02) -- 多媒体连接器

上一篇:OMCS 开发手册(00) -- 概述

--------------------------------------------------------------------------------------------------------------------  

下载免费版本的OMCS以及 demo源码

阅读 更多OMCS开发手册系列文章

Q Q:168757008

官网: www.oraycn.com

导航

首页

官方网站

联系我们

站内搜索

OrayTalk 企业即时通讯系统

傲瑞通官网

详细说明

客户端下载

OrayMeeting 视频会议系统

详细说明

客户端下载

ESFramework 通信框架

详细说明

SDK与Demo下载

ESFramework FAQ

版本变更记录

OMCS 语音视频框架

详细说明

SDK与Demo下载

OMCS FAQ

版本变更记录

OVCS 视频会议Demo

详细说明

源码下载

傲瑞实用组件

SDK下载

H5Media 纯网页音视频交互

NPusher 推流组件

MCapture 语音视频采集组件

MFile 语音视频录制组件

MPlayer 语音视频播放组件

OAUS 自动升级系统

StriveEngine 轻量级的通信引擎

傲瑞组件 FAQ

授权

授权流程

产品选购指南

授权方案说明

授权SDK使用说明

其它

支持信创国产化

SDK使用技巧

联系我们