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

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

时间:2023-11-20 09:58:02浏览次数:39  
标签:视频 const string int 跨平台 源码 IM public Avalonia

      在 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,请联系我们免费获取。  

 

标签:视频,const,string,int,跨平台,源码,IM,public,Avalonia
From: https://www.cnblogs.com/shawshank/p/17817414.html

相关文章

  • Netty源码学习4——服务端是处理新连接的&netty的reactor模式
    系列文章目录和关于我零丶引入在前面的源码学习中,梳理了服务端的启动,以及NioEventLoop事件循环的工作流程,并了解了Netty处理网络io重要的Channel,ChannelHandler,ChannelPipeline。这一篇将学习服务端是如何构建新的连接。一丶网络包接收流程当客户端发送的网络数据帧通过网......
  • [转]手把手教你如何用golang实现一个timewheel时间轮
     转,原文:https://lk668.github.io/2021/04/05/2021-04-05-%E6%89%8B%E6%8A%8A%E6%89%8B%E6%95%99%E4%BD%A0%E5%A6%82%E4%BD%95%E7%94%A8golang%E5%AE%9E%E7%8E%B0%E4%B8%80%E4%B8%AAtimewheel/-------------------------- 手把手教你如何用golang实现一个timewheel时间轮202......
  • 解决UnboundLocalError: local variable 'time' referenced before assignment
    解决UnboundLocalError:localvariable'time'referencedbeforeassignment介绍在Python开发中,经常会遇到UnboundLocalError:localvariable'xxx'referencedbeforeassignment的错误。这个错误通常发生在在一个函数内部,尝试访问一个在函数内定义的局部变量之前。这篇文章将......
  • 【Python进阶】近200页md文档14大体系知识点,第4篇:linux命令和vim使用
    本文从14大模块展示了python高级用的应用。分别有Linux命令,多任务编程、网络编程、Http协议和静态Web编程、html+css、JavaScript、jQuery、MySql数据库的各种用法、python的闭包和装饰器、mini-web框架、正则表达式等相关文章的详细讲述。全套Python进阶笔记地址:请移步这里共......
  • 命令式编程(Imperative Programming)和声明式编程(Declarative Programming)的区别
    命令式编程(ImperativeProgramming)和声明式编程(DeclarativeProgramming)都是计算机编程的范式,它们有着不同的特点和适用场景。首先,我们讨论命令式编程。在命令式编程中,程序员需要明确地告诉计算机需要执行哪些步骤来达到预期的结果。我们可以把这种范式比作烹饪食谱:食谱会明确地......
  • vim配置(编辑~/.vimrc文件)
    主要配置如下setnumbersetnocompatiblesyntaxonsetshowmodesetencoding=utf-8filetypeindentonsetautoindentsettabstop=4setshiftwidth=4setexpandtabsetshowmatchsethlsearchsetincsearchsetsmartcasesetnobackupsetnoswapfilesetnoundofile......
  • 【论文阅读】TimeGPT-1
    原始题目:TimeGPT-1中文翻译:TimeGPT-1发表时间:2023年10月05日平台:arXiv文章链接:http://arxiv.org/abs/2310.03589开源代码:无摘要在本文中,我们介绍了TimeGPT,这是第一个用于时间序列的基础模型,能够为训练过程中看不到的各种数据集生成准确的预测。我们根据已建立的统计、机......
  • 【论文阅读】Improving language understanding by generative pre-training
    原始题目:Improvinglanguageunderstandingbygenerativepre-training中文翻译:通过生成预训练提高语言理解能力发表时间:2018年平台:Preprint文章链接:https://www.mikecaptain.com/resources/pdf/GPT-1.pdf开源代码:https://paperswithcode.com/paper/improving-language-und......
  • 拼多多订单生成器手机版,支持淘宝京东截图生成,E4A源码,仅供娱乐学习
    闲着用E4A对接了JAVA类库制作了一个订单生成器,当然我叫了水印,这个软件或者里面的截图做不了啥坏事,仅仅用来学习娱乐装逼用的,下面是框架和代码。框架图1:  框架图2:  JAVa代码库:======================================================//商品类classProduct{St......
  • (STM32)TIM输出比较
    TIM输出比较(OC):主要功能输出PWM波形,PWM波形是驱动电机的必要条件,所以信息TIM输出比较就等于学习PWMCNT:计数器,计数自增,CCR:捕获比较寄存器,程序员给定的一个值当CNT,大于、小于、大于CCR时,输出就会置0,置1,置0....,一个不断跳变的pwm的波形每个高级定时器和通用定时器都拥......