OMCS开发手册(01) -- 多媒体设备管理器 一文,我们从Owner的角度详细描述了多媒体设备管理器的使用,本文我们将站在Guest的角度,描述OMCS中另一类组件/控件:多媒体连接器。多媒体连接器用于连接到任何一个在线的OMCS客户端所提供的多媒体设备。所有的连接器都是以Windows控件或组件的方式呈现的,且都实现了IMultimediaConnector接口。

一.IMultimediaConnector 接口

多媒体连接器的接口定义如下所示:

    public interface IMultimediaConnector
    {
        /// <summary>
        /// 设备主人的UserID。
         /// </summary>
        string OwnerID { get; }

        /// <summary>
        /// 与目标设备是否已连接?
         /// </summary>
        bool Connected { get; }

        /// <summary>
        /// 当调用BeginConnect连接Owner的设备时,如果Owner不在线,则等待对方上线的最长时间。
/// 单位:秒。默认值0。 /// </summary> int WaitOwnerOnlineSpanInSecs { get; set; } /// <summary> /// 目标多媒体设备的类型。 /// </summary> MultimediaDeviceType MultimediaDeviceType { get; } /// <summary> /// 尝试连接目标多媒体设备。 /// </summary> /// <param name="destUserID">目标用户的UserID</param> void BeginConnect(string destUserID); /// <summary> /// 与目标用户的多媒体设备断开连接,并释放通道。 /// </summary> void Disconnect(); /// <summary> /// 当连接目标多媒体设备的尝试(由BeginConnect发起)结束时,触发此事件。事件参数说明了连接的结果。 /// </summary> event CbGeneric<ConnectResult> ConnectEnded; /// <summary> /// 当与目标多媒体设备的连接断开时,触发该事件。 /// </summary> event CbGeneric<ConnectorDisconnectedType> Disconnected; }

1.连接

当使用连接器对象时,通常首先是将对应的控件/组件拖到窗体上,然后调用其BeginConnect方法尝试与目标用户的多媒体设备进行连接。连接结束时,无论是成功还是失败,都会触发ConnectEnded事件。我们可以根据ConnectEnded事件参数ConnectResult得知本次连接是成功还是失败。ConnectResult枚举定义如下:

    public enum ConnectResult
    {
        Succeed,
        /// <summary>
        /// 等待回复超时
         /// </summary>
        Timeout,
        /// <summary>
        /// 目标用户不在线
         /// </summary>
        TargetUserOffline,
        /// <summary>
        /// 对方拒绝
         /// </summary>
        Denied,
        /// <summary>
        /// 设备不存在或出错
         /// </summary>
        DeviceInvalid ,
        /// <summary>
        /// Owner的设备管理器还未完成初始化
         /// </summary>
        MultimediaManagerNotInitialized,
        /// <summary>
        /// 出现异常
         /// </summary>
        ExceptionOccured,
    }

注意,如果多媒体设备未被授权、或多媒体管理器未成功初始化、或当前连接器正在工作、或目标多媒体设备已经被连接,则BeginConnect方法将抛出相应的异常。

如果要连接的目标设备的Owner还未上线,WaitOwnerOnlineSpanInSecs属性则允许我们等它一段时间。在某些情况下,这可能是很有用的。我们来设想一下,通常基于OMCS开发的多媒体应用系统,除了有OMCS提供多媒体的部分,还会有其它业务逻辑,也就是说,除了有OMCS服务器存在,还会有处理业务逻辑的应用服务器存在。就像OMCS开发手册(00) -- 概述中的那个图所示的情况:

此时,客户端将有两个连接,一个连接指向OMCS服务器,另一个连接指向应用服务器。通常,客户端应该在成功登录了应用服务器之后,才会去连接OMCS服务器,这样就可能存在一个时间间隙 -- 即应用服务器已经连接成功,而OMCS服务器还未连接。如果在这个时候,其它Guest要访问当前客户端的多媒体设备,就会返回TargetUserOffline的结果而连接失败。如果将连接器的WaitOwnerOnlineSpanInSecs设置大于0,则连接器会在这段时间内不断轮询,等待Owner连上OMCS服务器。当Owner上线的时候,再去连接其多媒体设备。这样就解决了问题。当然,如果由于某些意外,导致Owner在WaitOwnerOnlineSpanInSecs时间内都还未连上OMCS服务器,则在等待时间结束时,连接器仍然返回TargetUserOffline的结果。

2.状态信息

MultimediaDeviceType 属性表示当前连接器要连接的目标多媒体设备的类型。

Connected 属性反应了当前连接器与多媒体设备之间的连接状态。

如果连接成功,OwnerID属性表示当前连接的是哪个用户的多媒体设备。

3.断开连接

我们可以调用Disconnect方法主动断开与目标多媒体设备的连接。当然,除了主动断开连接外,还有其它几种方式也会导致连接器到目标设备的连接断开(比如,网络断开)。而只要连接器与目标多媒体设备之间的连接断开,就会触发Disconnected事件,事件的参数ConnectorDisconnectedType说明了连接断开的原因。

    public enum ConnectorDisconnectedType
    {
        /// <summary>
        /// Guest(连接器)掉线。
         /// </summary>
        GuestOffline = 0,
        /// <summary>
        /// Owner(设备)掉线。
         /// </summary>
        OwnerOffline,
        /// <summary>
        /// Guest(连接器)主动断开到设备的连接。
         /// </summary>
        GuestActiveDisconnect,
        /// <summary>
        /// Owner(设备)主动断开Guest(连接器)到设备连接。
         /// </summary>
        OwnerActiveDisconnect
    }

多媒体连接器断开共有四种原因:Guest掉线、Owner掉线、Guest主动断开、Owner主动断开。

当我们在正常工作的连接器实例上调用其Disconnect方法时,触发Disconnected事件的参数就是ConnectorDisconnectedType.GuestActiveDisconnect。

还记得在介绍多媒体设备管理器时,IMultimediaManager有重载的DisconnectGuest方法,如果Owner调用这个DisconnectGuest方法,那么在Guest这一方对应的连接器实例就会断开到目标设备的连接,而断开的原因就正是ConnectorDisconnectedType.OwnerActiveDisconnect。

二.四种多媒体连接器

OMCS提供了四种多媒体连接器:MicrophoneConnector(麦克风连接器)、CameraConnector/DynamicCameraConnector(摄像头连接器)、DesktopConnector/DynamicDesktopConnector(远程桌面连接器)、WhiteBoardConnector(电子白板连接器)。所有这些连接器都实现了IMultimediaConnector接口,所以,IMultimediaConnector定义的功能它们都是拥有的。

我们可以将这些连接器组件/控件添加到工具箱中:在VS的工具箱的空白地方右键快捷菜单 => 选择项,在弹出的“选择工具箱项”的窗体上,点击“浏览”按钮,选中OMCS.dll文件,再点击“确定”就可以了。

1.麦克风连接器

MicrophoneConnector是一个组件,没有UI元素,当然,它也不需要UI显示。

2.摄像头连接器

OMCS提供了两个摄像头连接器:CameraConnector和DynamicCameraConnector。它们的区别在于,CameraConnector是一个UI控件,直接在当前的UI上显示目标摄像头采集到的视频;DynamicCameraConnector是一个组件(没有UI),可以通过SetViewer方法动态地为其设置要在哪个UI上绘制。

        /// <summary>
        /// 设置要显示视频的控件。必须要在UI线程中调用该方法。
         /// </summary>
        /// <param name="newPanel">要绘制视频的控件。可以为null。</param>
        void SetViewer(Control newPanel);

像我们经常看到的视频聊天中的全屏显示功能,就可以采用DynamicCameraConnector实现,当用户点击全屏按钮时,将DynamicCameraConnector要绘制的表面设置为最前(Top)的窗体的表面就可以了。

除此之外,CameraConnector和DynamicCameraConnector还提供了以下特性:

        /// <summary>
        /// 被绘制控件的背景色。
         /// </summary>
        Color PanelColor { get; set; }

        /// <summary>
        /// 是否自动保持视频与音频同步。默认值为true。可以在运行时动态修改。
         /// </summary>
        bool AutoSynchronizeVideoToAudio { get; set; }

        /// <summary>
        /// 连续多长时间没有新的帧绘制,就显示黑屏。单位:秒。
         /// </summary>
        int MaxIdleSpan4BlackScreen { get; set; }

        /// <summary>
        /// 获取当前正在绘制的图像。
         /// </summary>
        Bitmap GetCurrentImage();

PanelColor:用于设置被绘制控件的背景色,当没有视频图像显示时,将显示这种背景色。默认值为黑色。

MaxIdleSpan4BlackScreen:连续多长时间没有接收到新的视频帧时,就显示PanelColor所设置的背景色。默认值为5秒。这种情况经常在网络缓慢而导致视频帧延迟很大或连续被丢弃时出现。

GetCurrentImage:该方法可以将当前显示的视频帧保存为位图。使用该方法可以实现拍照功能。

AutoSynchronizeVideoToAudio:如果当前客户端连接了同一个Owner的摄像头和话筒,那么,CameraConnector/DynamicCameraConnector在播放视频时是否自动与音频保持同步。

一般,在网络非常顺畅的情况下,视频帧与音频帧按是照接收就立即播放的模式来进行的,这本来就是同步的。

但是,当网络存在抖动时,OMCS内部会自动启用抖动缓冲区(Jitter Buffer),这样就使得音频比视频的播放要稍慢一点(可能是几毫秒或几十毫秒,取决于网络抖动的幅度),而导致出现声音与画面不同步的情况。如果将AutoSynchronizeVideoToAudio设置为true,则OMCS会控制视频帧的播放,使其与音频始终保持一致。

3.远程桌面连接器

同摄像头连接器一样,OMCS也提供了两种远程桌面连接器:DesktopConnector和DynamicDesktopConnector。它们的区别也与两种摄像头连接器的区别一样。它的扩展特性有以下两个:

        /// <summary>
        /// 被绘制控件的背景色。
         /// </summary>
        Color PanelColor { get; set; }

        /// <summary>
        /// 是否仅仅允许查看远程桌面,但是不能进行操作。默认值为true。
         /// </summary>
        bool WatchingOnly { get; set; }

        /// <summary>
        /// 是否在远程桌面上显示Owner的鼠标光标。默认值为true。
         /// </summary>
        bool ShowMouseCursor { get; set; }

        /// <summary>
        /// 连续多长时间没有新的帧绘制,就显示黑屏。单位:秒。
         /// </summary>
        int MaxIdleSpan4BlackScreen { get; set; }

        /// <summary>
        /// 获取当前正在绘制的图像。
         /// </summary>
        Bitmap GetCurrentImage();

PanelColor、MaxIdleSpan4BlackScreen属性以及GetCurrentImage方法的含义与摄像头连接器的一样,不再重复。

WatchingOnly 属性用于控制guest是否可以操作远程桌面。将其设为false,就可以实现类似QQ的远程协助的功能。

ShowMouseCursor 属性用于控制是否在远程桌面上显示Owner的鼠标光标。比如,在远程教学系统中,可以将该属性设置为true,这样,每个guest都可以看到Owner鼠标指示的地方了。

4.电子白板连接器

OMCS的电子白板提供了常用的视图元素:像直线、曲线、箭头、矩形、三角形、椭圆、文字等;可修改边框颜色和填充颜色;可插入图片、截屏,可将整个白板保存为位图;并且支持激光笔等功能。

首先要强调一点,电子白板这个设备与其它的几个设备有个重要的区别:Owner的身份对于电子白板而言,更像是一个标志,而不是像前面三种设备一样,是实际设备的持有者。

就像一栋大楼一样,里面有很多个房间,而Owner的ID只是这个房间的门牌号码。如果多个guest连到了同一个Owner的电子白板,意味着多个guest进入了同一个房间,可以在同一个电子白板上相互协作。这些guest看到的是完全相同的内容,当一个guest修改电子白板的内容时,其它的guest可以同时看到这种改变。

基于此,所以Owner的掉线不会导致Guest的电子白板连接器断开,也就是说,WhiteBoardConnector的Disconnected事件的ConnectorDisconnectedType参数的值永远不会是OwnerOffline。但是,为了能找到目标房间在哪栋楼里(在OMCS服务器群集环境中,需要定位owner位于哪台服务器),电子白板连接器在连接Owner时,Owner必须在线,这一点与其它几个连接器是一致的。

电子白板连接器WhiteBoardConnector的扩展特性有以下三个:

        /// <summary>
        /// 仅仅允许查看白板,但是不能进行操作。默认值为false。
         /// </summary>
        bool WatchingOnly { get; set; }

        /// <summary>
        /// 是否开启自动重连的功能。默认值为true。
         /// </summary>
        bool AutoReconnect { get; set; }

        /// <summary>
        /// 在白板的左上角位置插入图片。
         /// </summary>
        /// <param name="img">被插入的图片</param>
        void InsertImage(Image img);

WatchingOnly 属性用于控制guest是否可以在电子白板上绘图等操作,还是只能观看。在现在流行的电子课堂中,通常只有老师可以操作电子白板,而学生只能观看电子白板。

AutoReconnect 是电子白板连接器特有的一个功能,以支持断线自动重连。当断线重连成功后,电子白板会从服务器下载最新的白板内容,并显示,以保证电子白板的实时性。

我们除了可以以Ctrl+V的方式向电子白板中插入图片外,还可以以编程的方式调用InsertImage方法向其中插入图片。比如,我们可以将CameraConnector的GetCurrentImage方法返回的图片插入到电子白板中。

OMCS开发手册(02) -- 多媒体连接器的更多相关文章

  1. OMCS开发手册(04) -- 二次开发流程

    在掌握了前面几篇关于OMCS的详细介绍后,我们就可以正式基于OMCS进行二次开发了.下面我们就从服务端和客户端的角度分别介绍开发的步骤. 一.服务端开发 抛开具体的业务逻辑而言,就OMCS的服务端的开 ...

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

    我们在前面一篇文章中提到:任何一个OMCS的Client都有两种身份,Owner和Guest.多媒体设备管理器工作于OMCS客户端,并以Owner的身份管理本地所有的多媒体设备.多媒体设备管理器对象是 ...

  3. OMCS开发手册(03) -- 多媒体服务器

    前面我们已经详细介绍了基于OMCS开发网络多媒体应用的客户端程序所必需掌握的内容,现在我们来看一下OMCS服务端的开发.对于使用者而言,OMCS的服务端就非常简单了,只要实现一个用户验证的接口,挂接到 ...

  4. 2019.05.26 周日--《阿里巴巴 Java 开发手册》精华摘要

    一.写在开头 Java作为一个编程界最流行的语言之一,有着很强的生命力.代码的编写规范也是不容忽视的,今天,我就把自己阅读的国内的互联网巨头阿里巴巴的<阿里巴巴 Java 开发手册>一些精 ...

  5. SAP PI开发手册-ERP发布服务供外围系统调用(RFC类型)

    1转自:https://www.cnblogs.com/fanjb/p/10677018.html 8年进入国网项目后陆陆续续做了一些接口,按实现方法去分有RFC和代理类sproxy类型,按服务提供方 ...

  6. 解析一下阿里出品的泰山版 Java 开发手册

    说起华山,我就想起岳不群,不,令狐冲:说起泰山,我就想起司马迁,他的那句名言"人总有一死,或重于泰山,或轻于鸿毛",真的发人深省啊.这就意味着,阿里出品的泰山版 Java 开发手册 ...

  7. 2020阿里最新出品的泰山版Java开发手册,告别垃圾代码

    说起华山,我就想起岳不群,不,令狐冲:说起泰山,我就想起司马迁,他的那句名言"人总有一死,或重于泰山,或轻于鸿毛",真的发人深省啊.这就意味着,阿里出品的泰山版 Java 开发手册 ...

  8. 阿里出品的最新版 Java 开发手册,嵩山版,扫地僧

    说起嵩山,我就想起乔峰,想起慕容复,以及他们两位老爹在少林寺大战的场景.当然了,最令我印象深刻的就是那位默默无闻,却一鸣惊人的扫地僧啊.这次,阿里出品的嵩山版 Java 开发手册的封面就有一个扫地僧, ...

  9. 阿里巴巴开发手册强制使用SLF4J作为门面担当的秘密,我搞清楚了

    之前已经详细.全面地介绍了 Log4j,相信小伙伴们已经完全掌握了.那我在读嵩山版的阿里巴巴开发手册(没有的小伙伴,记着找我要)的时候,就发现了一条「强制」性质的日志规约: 应用中不可以直接使用日志系 ...

随机推荐

  1. nio简介

    上一篇  Java I/O演进与Linux网络I/O模型 一.传统BIO java传统bio编程概念: http://www.cnblogs.com/carl10086/p/6034563.html# ...

  2. 问题记录1:The VMware Authorization Service is not running.

    问题 VMware Workstation cannot connect to the virtual machine. Make sure you have rights to run the pr ...

  3. centos7 install rvm

    不管其他,先按要求更新一下包 yum install -y gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel li ...

  4. offsetLeft

    offsetLeft 获取的是相对于父对象的左边距,且返回值为数字: left 获取或设置相对于 具有定位属性(position定义为relative)的父对象 的左边距,且返回值是字符串eg:10p ...

  5. 使用python修改QQ密保(脚本)

    一.基于以下目的: 1.为了增加对Http协议理解能力,对QQ密保修改的请求进行了分析 2.为了锻炼python的编写能力 3.对web综合知识的理解 花了点时间写了这个脚本,下面介绍脚本的过程 二. ...

  6. 怎么 得到 DBGrid选中行的数据

    转自:https://zhidao.baidu.com/question/1694035814426308148.html 一般是你鼠标点到哪一行,其DataSet的指针就指到了什么位置你可以直接通过 ...

  7. SAP HANA 能做什么

    HANA不是一个数据仓库,而是一个平台,在这个平台之上用户可以构建数据仓库或集市.报表和仪表盘等. HANA能做的,首先是作为内存数据库,提供数据插入.修改和高效的查询功能. 其次,作为一个平台,在H ...

  8. 【类不类二】Python的类变量与实例变量

    在研究类的时候,难免会有很多疑问,C论坛和博客园高手如云(不知道是不是也美女如云), 搜到了这篇博文,是介绍Python的类变量和实例变量的 ! 刚好在下对self.***这种形式的实例变 量不是很理 ...

  9. javsscript总结

  10. dpkg -P <pkg>

    http://www.linuxquestions.org/questions/debian-26/how-do-i-get-rid-of-those-rc-packages-as-seen-in-d ...