Avalonia 实现跨平台的IM即时通讯、语音视频通话(源码,支持信创国产OS,统信、银河麒麟)

在 Avalonia 如火如荼的现在,之前使用CPF实现的简单IM,非常有必要基于 Avalonia 来实现了。Avalonia 在跨平台上的表现非常出色,对信创国产操作系统(像银河麒麟、统信UOS、Deepin等)也很不错。

现在,我们就来使用 Avalonia 实现一个跨平台的简单IM,除了文字聊天外,还可以语音视频通话。废话不多说,我们开始吧!

下图是这个简单IM的Avalonia客户端在国产统信UOS上的运行的截图:

一. IM 即时通讯系统主要功能

这个简单的IM系统实现了以下功能:

1.基础功能、文字聊天

(1)客户端用户上下线时,通知其他在线用户。

(2)当客户端与服务端网络断开时,进行自动重连,当网络恢复后,重连成功。

(3)所有在线用户之间可以进行文字聊天(支持表情,支持撤回消息、删除消息)。

(4)文件传送。

2.语音视频聊天、远程桌面

(1)一方发起视频对话请求,对方同意后,即可开始视频对话。

(2)在对话的过程中,任何一方都可以挂断,以终止对话。

(3)在对话的过程中,任何一方掉线,都会自动终止对话。

(4)双击视频窗口,会全屏显示视频,按esc退出全屏。

(5)远程桌面或远程协助功能,也是跟视频聊天同样的流程,不再赘述。

二.开发环境

1.开发工具:

Visual Studio 2022

2. 开发框架:

.NET Core 3.1

3.开发语言:

C#

4.其它框架:

Avalonia UI 框架(版本:0.10.22)、ESFramework 通信框架 (版本:7.2)

注:建议 Avalonia 使用0.10.*的版本,精简而且很稳定,而最新的11.0的版本太庞大了。

三.具体实现

下面我们讲一下Demo中核心的代码实现,大家从文末下载源码并对照着源码看,会更清楚些。

1.自定义消息类型 InformationTypes

若要实现上述功能列表中列出来的所有功能,我们先要定义相应的通信消息的消息类型,如下所示:

复制代码
    public static class InformationTypes
    {
        /// <summary>
        /// 文字(表情)聊天信息
        /// </summary>
        public const int TextChat = 0;

        /// <summary>
        /// 文字(表情)聊天信息 (由服务端转发给消息接收方)
        /// </summary>
        public const int TextChat4Transit = 1;

        /// <summary>
        /// 图片聊天信息
        /// </summary>
        public const int ImageChat = 2;

        /// <summary>
        /// 收到消息发送者 撤回消息请求
        /// </summary>
        public const int RecallMsg = 3;

        /// <summary>
        /// 客户端异步调用服务端
        /// </summary>
        public const int ClientSyncCallServer = 4;

        /// <summary>
        /// 视频请求 5
        /// </summary>
        public const int VideoRequest = 5;

        /// <summary>
        /// 回复视频请求的结果 6
        /// </summary>
        public const int VideoResult = 6;

        /// <summary>
        /// 通知对方 挂断 视频连接 7
        /// </summary>
        public const int CloseVideo = 7;

        /// <summary>
        /// 通知好友 网络原因,导致 视频中断 8
        /// </summary>
        public const int NetReasonCloseVideo = 8;

        /// <summary>
        /// 通知对方(忙线中) 挂断 视频连接 9
        /// </summary>
        public const int BusyLine = 9;

        /// <summary>
        /// 收到远程协助请求
        /// </summary>
        public const int AssistReceive = 10;

        /// <summary>
        /// 协助方拒绝远程协助
        /// </summary>
        public const int AssistGusetReject = 11;

        /// <summary>
        /// 协助方同意远程协助
        /// </summary>
        public const int AssistGusetAgree = 12;

        /// <summary>
        /// 请求方关闭远程协助
        /// </summary>
        public const int AssistOwnerClose = 13;

        /// <summary>
        /// 协助方关闭远程协助
        /// </summary>
        public const int AssistGusetClose = 14;
    }

在约定好消息类型之后,我们就可以实现业务逻辑功能了。

2.定义协议类

信息类型定义好后,我们接下来定义信息协议。

对于聊天消息(InformationTypes.EmotionTextChat),专门定义了一个协议类:ChatMessageRecord。

复制代码
    public class ChatMessageRecord
    {
        public string Guid { get; set; }

        public DateTime MessageTime { get; set; }

        public string SpeakerID { get; set; }

        public string ListenerID { get; set; }

        public ChatMessageType ChatMessageType { get; set; }

        public string ContentStr { get; set; }

        public byte[] ImgData { get; set; }

        public string FilePath { get; set; }
    }

对于同步调用(InformationTypes.ClientSyncCallServer),我们示例的是向服务器请求加法运算的结果,协议类用的是MathModel。

3.实现自定义信息处理器

客户端的MainForm实现了ICustomizeHandler接口,其主要实现HandleInformation方法,来处理收到的聊天信息和振动提醒。

复制代码
  void HandleInformation(string sourceUserID, int informationType, byte[] info);

服务端的CustomizeHandler实现了服务端的ICustomizeHandler接口,其主要实现HandleQuery方法来处理来自客户端的同步调用(InformationTypes.ClientCallServer)。

复制代码
  byte[] HandleQuery(string sourceUserID, int informationType, byte[] info);

4.服务端验证用户登录的帐号

服务端的BasicHandler类实现IBasicHandler接口,以验证登录用户的账号密码。

复制代码
    public class BasicHandler : IBasicHandler
    { 
        /// <summary>
        /// 此处验证用户的账号和密码。返回true表示通过验证。
        /// </summary>  
        public bool VerifyUser(ClientType clientType, string systemToken, string userID, string password, out string failureCause)
        {
            failureCause = "";
            return true;
        }

        public string HandleQueryBeforeLogin(AgileIPE clientAddr, int queryType, string query)
        {
            return "";
        }
    }

本demo中,假设所有的验证都通过,所以验证方法直接返回true。

5.客户端实现文字聊天功能

通过IRapidPassiveEngine的 CustomizeOutter 的 Send 方法来发送文字表情聊天消息。

在发送文字聊天消息时,有两个发送按钮,"发送1"和"发送2",分别演示了两种发送消息给对方的方式:

(1)直接发给对方。(若P2P通道存在,则经由P2P通道发送)

复制代码
        internal static void SendTextMsgToClient(ChatMessageRecord record)
        {
            try
            {
                string cont = JsonConvert.SerializeObject(record);
                byte[] recordInfo = Encoding.UTF8.GetBytes(cont);
                //使用Tag携带 接收者的ID
                App.PassiveEngine.CustomizeOutter.Send(record.ListenerID, InformationTypes.TextChat4Transit, recordInfo);
            }
            catch (Exception e)
            {
                logger.Log(e, "GlobalHelper.SendTextMsgToClient", ErrorLevel.Standard);
            }
        }

聊天消息 ChatMessageRecord 对象先由JSON序列化成字符串,然后在使用UTF-8转成字节数组,然后通过通信引擎的CustomizeOutter发送出去。

(2)先发给服务器,再由服务器转发给对方。

具体实现,大家去参看源码,这里就不再赘述了。

6.客户端实现语音视频通话功能

语音视频通话实际运行起来后的效果如下所示:

我们先简单描述一下实现视频对话流程的要点,更详细的细节请查阅源代码。

(1)发起方发送InformationTypes.VideoRequest类型的信息给对方,以请求视频对话。

程序中是在 VideoChatWindow 窗口显示的时候,来做这件事的:

复制代码
        protected override void OnInitialized()
        {
            base.OnInitialized(); 
            this.SetWindowStats();
            if (!this.IsWorking)
            {
                VideoController.Singleton.SendMessage(this.DestID, InformationTypes.VideoRequest, null);
                CommonHelper.AddSystemMsg(this.DestID, "向对方发起视频通话邀请");
            }
        }

(2)接收方收到请求后,界面提示用户是同意还是拒绝,用户选择后,将发送InformationTypes.VideoResult类型的信息给请求方,信息的内容是一个bool值,true表示同意,false表示拒绝。

(3)发起方收到回复,如果回复为拒绝,则界面给出对应的提示;如果回复为同意,则进入(4)。

(4)先说接收方,如果同意视频,则发送回复后,立即调用DynamicCameraConnector和MicrophoneConnector的Connect方法,连接到对方的摄像头、麦克风。

复制代码
        internal void BeginConnect()
        {
            UiSafeInvoker.ActionOnUI(() =>
            {
                string tip = this.IsWorking ? "已同意对方的视频通话" : "对方同意了你的视频通话请求";
                CommonHelper.AddSystemMsg(this.DestID, tip);
                this.IsWorking = true;
                this.NotifyOther = true;
                this.Title = this.title.Text = this.RepeatedCallTip(false);
                this.startTime = DateTime.Now;
                this.timer.Start();
                this.otherCamera.Core.DisplayVideoParameters = true;
                this.otherCamera.Core.VideoDrawMode = VideoDrawMode.ScaleToFill;
                this.otherCamera.Core.ConnectEnded += DynamicCameraConnector_ConnectEnded;
                this.otherCamera.Core.Disconnected += DynamicCameraConnector_Disconnected;
                this.microphoneConnector.ConnectEnded += MicrophoneConnector_ConnectEnded;
                this.microphoneConnector.Disconnected += MicrophoneConnector_Disconnected;
                this.otherCamera.BeginConnect(this.DestID);
                this.microphoneConnector.BeginConnect(this.DestID);
            });
        }

(5)对于发起方,当收到对方同意的回复后,也立即调用DynamicCameraConnector和MicrophoneConnector的Connect方法,连接到接收方的摄像头、麦克风。

(6)当一方点击挂断的按钮时,就会发送InformationTypes.CloseVideo类型的信息给对方,并调用DynamicCameraConnector和MicrophoneConnector的Disconnect方法断开到对方设备的连接。

(7)另一方接收到InformationTypes.CloseVideo类型的信息时,也会调用DynamicCameraConnector和MicrophoneConnector的Disconnect方法以断开连接。

复制代码
        protected override void OnClosing(CancelEventArgs e)
        {
            base.OnClosing(e);
            this.otherCamera?.Disconnect();
            this.otherCamera?.Dispose();

            this.microphoneConnector?.Disconnect();
            this.microphoneConnector?.Dispose();

            this.selfCamera?.Disconnect();
            this.selfCamera?.Dispose();
        }

(8)如果接收到自己掉线的事件或好友掉线的事件,也采用类似挂断对话的处理。

四.下载

Avalonia 版本即时通讯源码:IM_VideoChat.Avalonia.rar

该源码中包括如下项目:

(1)Oraycn.Demos.VideoChat.LinuxServer : 该Demo的Linux服务端(基于.NetCore)。

(2)Oraycn.Demos.VideoChat.ClientAvalonia : 该Demo的 Avalonia 客户端。

注: Linux客户端内置的是x86/x64非托管so库,若需要其它架构的so,请联系我们免费获取。

相关推荐
sdszoe49222 天前
Windows server远程桌面管理
远程桌面·windows server·远程服务·远程用户
jeff聊企业数字化2 天前
私有化即时通讯选型指南:兼顾安全与高效
go·业界资讯·即时通讯
恒拓高科WorkPlus2 天前
BeeWorks 私有化安全协作平台白皮书(2026 版)
即时通讯·白皮书·协作平台·协作平台白皮书·即时通讯白皮书
恒拓高科WorkPlus8 天前
团队协作和即时通讯一体化的软件,目前哪个用户体验最好?
即时通讯·私有化的企业 im·企业 im
恒拓高科WorkPlus9 天前
信创即时通讯怎么选?BeeWorks 的全栈适配与安全实践
即时通讯·信创即时通讯
恒拓高科WorkPlus10 天前
私有化视频会议怎么选?BeeWorks Meet 的安全与高效之道
私有化部署·即时通讯·视频会议
hellojackjiang201112 天前
社交场景下的统一即时通讯im消息流交互层模块化技术实践
即时通讯·im开发·架构设计
Ops菜鸟(Xu JieHao)16 天前
Linux 内网远程桌面Xrdp ~保姆级教程
linux·运维·服务器·windows·远程桌面·远程·xrdp
豆豆19 天前
高校网站群集约化建设与运营解决方案
大数据·cms·信创·解决方案·网站管理系统·站群cms·高校站群
小小ken21 天前
windows远程桌面连接报错:发生身份验证错误。要求的函数不受支持,这可能是因为在远程计算机上阻止 NTLM 身份验证。
windows·远程桌面·windows server