OMCS 开发手册(11) -- 深入摄像头、麦克风、扬声器

在开发类似视频聊天的应用时,我们经常需要获取音视频设备的相关信息;而在进行视频聊天时,我们可能还希望有一些动态的能力。比如,在不中断视频聊天的情况下,切换一个摄像头、或者修改摄像头采集的分辨率或编码质量、或者暂时屏蔽话筒的输出,等等。OMCS提供了很多有用的特性以支持上述需求。 

一.摄像头

1.枚举摄像头

我们如何得知当前的计算机有哪些摄像头了?

OMCS提供了一个工具类OMCS.Tools.Camera,来帮助我们获取这些信息。Camera有个静态方法GetCameras,用于枚举当前计算机上的所有摄像头。

  /// <summary>
  /// 枚举当前计算机上的所有摄像头设备。
  /// </summary>        
  public static List<CameraInformation> GetCameras()

CameraInformation封装了摄像头的基本信息,我们可以将GetCameras方法返回的列表直接绑定到Combox控件,效果如下所示: 

            

默认情况下,IMultimediaManager使用的摄像头的索引为0。如果索引为0的摄像头不可用,或者,用户指定使用其它的摄像头,则可以将指定摄像头的索引保存到配置文件。当客户端程序启动时,从配置文件中读取该索引值,并将其赋值给IMultimediaManager的CameraDeviceIndex属性。 

2.获取摄像头支持的分辨率

当选定了一个摄像头,我们如何知道该摄像头支持哪些采集分辨率、支持最高的帧频是多少了?

Camera提供了另一个静态方法GetCameraCapability,来获取目标摄像头的能力信息。  

  /// <summary>
  /// 获取目标摄像头的能力信息(分辨率、最大帧频)
  /// </summary>
  /// <param name="deviceIndex">目标摄像头的索引</param>        
  public static List<CameraCapability> GetCameraCapability(int deviceIndex)

CameraCapability类封装了摄像头的能力信息,我们可以将GetCameraCapability方法返回的列表直接绑定到Combox控件,效果如下所示: 

       

3.动态切换摄像头

下面我们设想一种情况,假设我的电脑上装有两个可用的摄像头, 我正在使用索引为0的摄像头和我的朋友视频聊天,某个时刻,我想在不中断视频聊天的情况下,切换到索引为1的摄像头。这种需求就称为动态切换摄像头。

OMCS支持动态切换摄像头,并且操作相当简单:我们只需要将IMultimediaManager的CameraDeviceIndex属性赋值为要切换到的摄像头的索引即可。切换会在OMCS内部自动进行,在很短的时间切换完成后,OMCS会将新摄像头采集的视频数据发送给各个guest。   

4.动态修改摄像头的分辨率

还记得QQ视频聊天有这种能力,我们可以在视频聊天的时候,选择使用大窗口模式。这实际上就是使用摄像头更高的分辨率来采集视频,比如原始的采集分辨率为320*240,可切换到更高的640*480

OMCS支持在不需要任何中断的情况下,修改正在使用的摄像头的采集分辨率。操作也是相当简单:我们只需要将IMultimediaManager的CameraVideoSize属性设置为目标分辨率大小即可。当然,如果设置的分辨率不被当前摄像头所支持,则将抛出NotSupportedException。另外要注意,在编码质量相同的情况下,视频的分辨率越高,所输出的码流就越大,所要求的带宽也越大。

为了避免设置不恰当的分辨率给CameraVideoSize属性,在赋值之前,我们可以通过OMCS.Tools.Camera的静态方法Support来判断目标摄像头是否支持指定的分辨率:

   /// <summary>
   /// 目标摄像头是否支持采集指定的分辨率。
   /// </summary>     
   public static bool Support(int deviceIndex, Size videoSize)

5.动态调节编码质量

在客户端运行的任何时候,我们都可以通过设置IMultimediaManager的CameraEncodeQuality属性,来实时调整摄像头采集的视频的编码质量。编码质量越高,CameraEncodeQuality取值越小,对带宽的要求就越高;反之亦然。

注意,如果IMultimediaManager的AutoAdjustCameraEncodeQuality属性被设置为true,则CameraEncodeQuality将会被OMCS自动调节以优先保证语音的清晰连贯,手动对CameraEncodeQuality的设置就不起作用了。如果我们将AutoAdjustCameraEncodeQuality设置为false,并且我们的应用自己能检测到网络状态的实时变化,那么,我们就可以根据当前的网络状态,来手动调整CameraEncodeQuality。 

6.控制视频输出

设想这样一种情况:我在进行视频会议时,某个时间出于某种原因,我不想让与会者看到我的视频,一段时间后,我又希望恢复原样。

从节省带宽的角度,最好的方式就是在这段时间内不输出视频帧。OMCS能简单地实现这种控制:我们只需将IMultimediaManager的OutputVideo属性设置为false,即可关闭视频帧的输出。 

7. 丢弃视频帧

下面要设想的场景稍微复杂一点:在视频会议时,我的视频会发送给与会的每个人,假设我与每个与会者之间都建立的是P2P通道,视频帧都经过P2P通道传送。现在的问题时,每个P2P通道的质量是不一样的,有的可能很快,有的可能很慢。我们假设到与会者A的通道非常慢,到其他与会者的通道质量都很好。那么,我们来分析一下在两种广播模式下,可能出现的情况。

(1)同步广播模式

在同步广播模式下,只有当某个视频帧在所有的通道上都发送完毕时,才会去发送下一个视频帧。这样就会出现因为与A之间的通道缓慢,而导致其他与会者看到自己的视频出现卡或不连贯的情况。

(2)异步广播模式

在异步广播模式下,视频帧在所有的通道上都是异步发送的,这样A通道的缓慢不会影响到其它的与会者。OMCS采用的就是这种模式。

但是,由于通道A的缓慢,生产视频帧的速度远大于通道A消费视频帧的速度,这就导致了需要使用更多的内存来缓存那些来不及发送的视频帧。就客户端进程看来,其所占用的内存会不断增加,就像内存泄漏一样。如何解决这个问题了?OMCS给出的方案是可以选择在通道繁忙时丢弃帧。通过将IMultimediaManager的 Advanced 属性的 AllowDiscardFrameWhenBroadcast 属性设置为true,便可启用这种方案。

AllowDiscardFrameWhenBroadcast被启用后,当一个新的视频帧要通过某个P2P通道发送给对应的与会者时,会先检测一下该P2P通道是否繁忙,如果繁忙,就取消该视频帧在这个通道上的发送。这样,就避免了内存无线增长的情况。但在这种方案下,那些通道比较慢的与会者,因为丢弃视频帧的原因,看到别人的视频可能就会出现马赛克、卡、不连续的现象。 

二.麦克风

1.枚举麦克风

我们如何得知当前的计算机配有哪些麦克风设备了?

OMCS提供了一个工具类OMCS.Tools.SoundDevice,来帮助我们获取这些信息。SoundDevice有个静态方法GetMicrophones,用于枚举当前计算机上的所有麦克风。 

     /// <summary>
    /// 枚举当前计算机上的所有麦克风设备。
    /// </summary>        
    public static List<MicrophoneInformation> GetMicrophones()

MicrophoneInformation封装了麦克风的基本信息,我们可以将GetMicrophones方法返回的列表直接绑定到Combox控件,效果如下所示:

   

默认情况下,IMultimediaManager使用的麦克风的索引为0。如果索引为0的麦克风不可用,或者,用户指定使用其它的麦克风,则可以将指定麦克风的索引保存到配置文件。当客户端程序启动时,从配置文件中读取该索引值,并将其赋值给IMultimediaManager的MicrophoneDeviceIndex属性。 

2.控制声音输出

设想这样一种情况:我在进行视频会议时,某个时间出于某种原因,我不想让与会者听到我的声音,一段时间后,我又希望恢复原样。

从节省带宽的角度,最好的方式就是在这段时间内不输出声音数据。OMCS能简单地实现这种控制:我们只需将IMultimediaManager的OutputAudio属性设置为false,即可关闭视音帧数据的输出。 

三.扬声器

1.枚举扬声器

我们如何得知当前的计算机配有哪些扬声器设备了?

OMCS.Tools.SoundDevice有个静态方法GetSpeakers,用于枚举当前计算机上的所有扬声器。 

    /// <summary>
    /// 枚举当前计算机上的所有扬声器设备。
    /// </summary>        
    public static List<SpeakerInformation> GetSpeakers()

SpeakerInformation封装了扬声器的基本信息,我们可以将GetSpeakers方法返回的列表直接绑定到Combox控件,效果如下所示:    

             

默认情况下,IMultimediaManager使用的扬声器的索引为0。如果索引为0的扬声器不可用,或者,用户指定使用其它的扬声器,则可以将指定扬声器的索引保存到配置文件。当客户端程序启动时,从配置文件中读取该索引值,并将其赋值给IMultimediaManager的SpeakerIndex属性。 

2.声卡是否安装

OMCS.Tools.SoundDevice的静态方法IsSoundCardInstalled,用于判断当前计算机的声卡是否正常安装。 

    /// <summary>
    /// 当前计算机是否安装了声卡。
    /// </summary>        
    public static bool IsSoundCardInstalled()

3.音量放大

如果已经将计算机的音量调到最大,还是觉得MicrophoneConnector播放的声音很小,那么,可以通过设置IMultimediaManager的VolumeAmplifyFactor来放大声音。 

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

4.静音

如果希望某个MicrophoneConnector不播放声音,则可以将MicrophoneConnector的Mute属性设为true。

    /// <summary>
    /// 是否静音。默认值false。
    /// </summary>
    bool Mute { get; set; }

四.设备报错

当第一个guest连接到Owner的某设备时,该设备会自动启动运行,如果启动时设备发生错误,则Owner方和Guest方都能得到相应的通知。

Owner方:IMultimediaManager的DeviceErrorOccurred事件会触发。 

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

Guest方:相应的多媒体连接器的ConnectEnded事件触发,表明连接失败,且其事件参数通常为ConnectResult.DeviceInvalid。

 

 

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

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

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

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

Q Q:168757008

官网:www.oraycn.com

导航

首页

官方网站

立即咨询 

站内搜索

ESFramework 通信框架

详细说明

SDK下载

ESFramework FAQ

版本变更记录

OMCS 语音视频框架

详细说明

SDK下载

OMCS FAQ

版本变更记录

OrayTalk 企业即时通讯系统

详细说明

客户端下载

傲瑞实用组件

SDK下载

NPush 消息推送组件

StriveEngine 轻量级的通信引擎

MFile 语音视频录制组件

MCapture 语音视频采集组件

MPlayer 语音视频播放组件

OAUS 自动升级系统

傲瑞组件 FAQ

授权

授权流程

产品授权说明

产品选购指南

授权SDK使用说明

其它

SDK使用技巧

联系我们

电话:027-87638960

Q Q:168757008

邮件:master@oraycn.com