Avalonia 实现跨平台的视频聊天、屏幕分享(源码,支持Win、银河麒麟、统信UOS)

       现在最火的.NET跨平台UI框架莫过于Avalonia了。Avalonia 基于.NET Core,因此它可以运行在任何支持.NET Core的平台上。之前基于CPF跨平台UI框架写过一个视频聊天的demo,而现在看来Avalonia是大势所趋,于是,我再写一个Avalonia版本的Demo来供大家参考,它可以在Windows和Linux(包括国产OS,如银河麒麟、统信UOS)上运行。

       下图是视频聊天Demo的Avalonia客户端在国产统信UOS上的运行的截图:

 一.功能介绍 

      客户端登录成功后,运行的主界面如下图所示:  

1. 视频聊天

(1)每个登录的用户都可向其他任意在线用户发送视频聊天请求。

(2)当收到来自其他在线用户的视频聊天邀请时,可接受或拒绝对方的请求。

(3)当接受其他在线用户的视频聊天邀请时,即可开启视频聊天。 

2. 远程桌面

(1)每个登录的用户都可向其他任意在线用户发送远程桌面请求;当对方未响应时,可主动取消远程桌面请求。

(2)当收到来自其他在线用户请求控制桌面时,可接受或拒绝对方的请求。

(3)当发送方收到其他在线用户同意控制其电脑时,即可开启远程桌面连接。

(4)被控端和主控端都可主动断开远程桌面连接。 

二.开发环境

1.开发工具:

Visual Studio 2022 

2. 开发框架: 

.NET Core 3.1

3.开发语言:

C#

4.其它框架:

Avalonia UI 框架(版本:0.10.22)、OMCS 语音视频框架 (版本:8.0)

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

三.具体实现

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

1.自定义消息类型 InformationTypes

    public static class InformationTypes{/// <summary>/// 视频请求 0/// </summary>public const int VideoRequest = 0;/// <summary>/// 回复视频请求的结果 1/// </summary>public const int VideoResult = 1;/// <summary>/// 通知对方 挂断 视频连接 2/// </summary>public const int CloseVideo = 2;/// <summary>/// 通知好友 网络原因,导致 视频中断 3/// </summary>public const int NetReasonCloseVideo = 3;/// <summary>/// 通知对方(忙线中) 挂断 视频连接 4/// </summary>public const int BusyLine = 4;/// <summary>/// 远程桌面请求 5/// </summary>public const int DesktopRequest = 5;/// <summary>/// 回复远程桌面请求的结果 6/// </summary>public const int DesktopResult = 6;/// <summary>///  主动取消远程桌面请求 7/// </summary>public const int CancelDesktop = 7;/// <summary>///  对方(主人端)主动断开远程桌面 8/// </summary>public const int OwnerCloseDesktop = 8;/// <summary>/// 客人端断开远程桌面连接 9/// </summary>public const int GuestCloseDesktop = 9;}

2. 发送视频请求

(1)当发起视频聊天时,将显示视频聊天窗口 

    /// <summary>/// 打开视频通话窗口/// </summary>/// <param name="destID">对方ID</param>/// <param name="isWorking">false表示主动发起视频通话邀请</param>internal void OpenVideoChat(string destID,bool isWorking){if (!this.VideoInvokeVerdict(destID)){return;}App.Multimedia.OutputAudio = true;VideoChatWindow videoChatWindow = new VideoChatWindow(destID, isWorking);videoChatWindow.EndTheCalled += VideoChatWindow_EndTheCalled;objectManager.Add(destID, videoChatWindow);videoChatWindow.Show();}

(2)连接自己的摄像头 

    public VideoChatWindow(string destID,bool isWorking){this.DestID = destID;this.IsWorking = isWorking;InitializeComponent();//连接自己的摄像头this.selfCamera.Core.DisplayVideoParameters = true;this.selfCamera.Core.VideoDrawMode = VideoDrawMode.ScaleToFill;this.selfCamera.BeginConnect(MainWindow.CurrentID);this.Title = this.title.Text = this.RepeatedCallTip(false);this.timer = new System.Timers.Timer();this.timer.Interval = 1000;this.timer.Elapsed += Timer_Elapsed;if (IsWorking){ this.BeginConnect();}}

(3)发送视频通话请求

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

3. 回复对方视频请求

(1)当收到对方的视频聊天邀请时,将显示视频邀请窗口  

 (2)发送回复视频聊天请求消息 

 protected override void OnClosed(EventArgs e){base.OnClosed(e);if (this.EndTheCalled != null){this.EndTheCalled(this.DestID);}if (this.NotifyOther){  //回复对方的视频通话请求byte[] bytes = BitConverter.GetBytes(replyResult);VideoController.Singleton.SendMessage(this.DestID, InformationTypes.VideoResult, bytes);}if (this.replyResult){VideoController.Singleton.OpenVideoChat(DestID,true);}}

4. 收到对方视频请求的回复 

    /// <summary>/// 视频通话,收到对方回复/// </summary> internal void TargerReply(string destID, CommunicationStateType type){ICommunicationAid aid = this.objectManager.Get(destID);if(aid == null){return;} switch (type){case CommunicationStateType.Agree:VideoChatWindow videoChatWindow = (VideoChatWindow)aid;videoChatWindow.BeginConnect();break;case CommunicationStateType.Reject: aid.CloseWindow(false);break;case CommunicationStateType.HangUp: aid.CloseWindow(false);break;default:break;}}

当对方回复同意时,将连接到对方的麦克风和摄像头,开始视频聊天会话: 

  /// <summary>/// 连接对方设备/// </summary>internal void BeginConnect(){UiSafeInvoker.ActionOnUI(() =>{this.IsWorking = 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);this.NotifyOther = true;});}

5. 实现远程桌面

      远程桌面的请求/应答逻辑几乎与视频聊天请求/应答逻辑是一模一样的。这里就不再罗列响应的代码了。

(1)当收到对方的远程桌面控制请求时,将显示请求窗口。

(2)当同意对方的控制请求时,对方就可以控制请求方的电脑了。

四.源码下载     

     .NetCore服务端 + Avalonia客户端:VideoChatMini.Avalonia.rar  

      在Windows上部署运行服务端和客户端很容易,大家也都很熟悉了。下面讲一下如何在Linux上部署运行这个视频聊天程序的服务端和客户端。

     在Linux上部署运行说明

       在部署之前,需要在linux服务端和客户端上分别安装 .Net core 3.1版本,命令行安装命令如下:

 yum install dotnet-sdk-3.1

  检查版本安装情况

 dotnet --version

   运行:

(1)在CentOS上启动VideoChatMini.ServerNetcore服务端:

  拷贝Oraycn.VideoChatMini.ServerNetcore项目下的Debug文件夹,到CentOS操作系统上,打开Debug -> netcoreapp3.1目录 ,在目录下打开终端,执行以下命令启动服务端   

dotnet Oraycn.VideoChatMini.ServerNetcore.dll

(2)在麒麟或统信UOS、Ubuntu上运行VideoChatMini.ClientAvalonia客户端:

  拷贝Oraycn.VideoChatMini.ClientAvalonia项目下的Debug文件夹,到麒麟或统信UOS、Ubuntu操作系统上,打开Debug -> netcoreapp3.1目录 ,在目录下打开终端,执行以下命令启动客户端

dotnet Oraycn.VideoChatMini.ClientAvalonia.dll

       命令执行成功后,就会出现之前截图的客户端主界面。        

        Avalonia 支持在X64和ARM64架构的Linux上运行,Demo的运行目录下放的是X64架构的so,如果需要ARM64架构的so,可留下邮箱获取。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/160045.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

基于区块链与联邦学习技术的数据交易平台

目录 基于区块链与联邦学习技术的数据交易平台 基于区块链与联邦学习技术的数据交易平台 联邦学习与区块链的集成的优势在于能够确认参与各方的身份并实现学习过程追溯。 首先&#xff0c;通过的身份认证系统与定制化的联邦学习协议来解决交易各方身份确认的问题。 如图1所示…

Q-learning如何与ABC等一些元启发式算法能够结合在一起?

1、出现的问题 Q-learning能和元启发式算法&#xff08;如ABC、PSO、GA、SSA等&#xff09;结合在一起&#xff0c;实现工作流调度问题&#xff1f; Q-learning和ABC (Artificial Bee Colony) 等元启发式算法可以结合在一起以解决特定类型的问题。Q-learning是一种强化学习算法…

QTday1

#include "mywidget.h"MyWidget::MyWidget(QWidget *parent): QWidget(parent) {this->resize(430,330);this->setWindowTitle("QQ");this->setWindowIcon(QIcon("E:\\桌面\\qq.png"));this->setWindowFlag(Qt::FramelessWindowHint…

Windows工业三防平板全功能NFC近距离感应一维/二维扫描

Windows系统工业三防平板电脑是一种在智慧工厂仓储物流、MES数采、车载设备、设备检测、自动化控制等领域广泛应用的先进设备。此外&#xff0c;它还在公共服务领域&#xff0c;如高速交通、物流运输、电力检测、公务执法、银行金融、船舶装备、户外勘测、建筑工程、汽车检测、…

【python高级】设计模式、类工厂、对象工厂

一、说明 最近试着读Design pattern&#xff0c; 不过有些概念实在太抽象了&#xff0c; 整理一下自己所学抽象工厂的精神&#xff0c;就是要有abstract class&#xff08;not implement&#xff09;&#xff0c;而所有不同种类的对象&#xff0c;都是继承这个abstract class&a…

unordered_set unordered_map 的封装

目录 1. 哈希的概念 1.1. 哈希冲突 1.2. 哈希函数&#xff1a; 1. 直接定址法 2. 除留余数法 1.3. 闭散列实现哈希 1.4. 开散列实现哈希 2. 哈希的应用 2.1 位图的概念 2.1.1. 问题&#xff1a; 2.2.1. set ​编辑 2.2.2. reset 2.2.3. test() 2.2. 位图的实现…

使用解构赋值简化axios返回对象属性元素的提取

axios返回的response通常都会进行一层封装&#xff0c;把响应的数据封装到了data这个对象&#xff0c;所以提取数据起来不太方便&#xff0c;往往需要res.data.xxx这样获取里面的数据&#xff0c; 具体可以参考下面的数据结构&#xff1a; 假如data的数据是下面的结构&#xf…

【Unity引擎核心-Object,序列化,资产管理,内存管理】

文章目录 整体介绍Native & Managed Objects什么是序列化序列化用来做什么Editor和运行时序列化的区别脚本序列化针对序列化的使用建议 Unity资产管理导入Asset Process为何要做引擎资源文件导入Main-Assets和 Sub-Assets资产的导入管线Hook&#xff0c;AssetPostprocessor…

傅里叶变换和其图像处理中的应用

以下部分文字资料整合于网络&#xff0c;本文仅供自己学习用&#xff01; 一、为什么要在频域进行图像处理&#xff1f; 一些在空间域表述困难的增强任务&#xff0c;在频率域中变得非常普通 滤波在频率域更为直观&#xff0c;你想想嘛&#xff0c;所谓滤波&#xff0c;就是…

Spring Boot Bean 注入的常用方式教程

Spring Boot Bean 注入是一种将依赖对象引入到应用程序组件中的机制&#xff0c;它有助于实现松耦合和可测试的代码。这种注入方式允许我们将依赖关系委托给 Spring 容器来管理&#xff0c;从而提高了代码的可维护性和可读性。Spring Boot 提供了多种 Bean 注入方式&#xff0c…

Linux-CentOS8-Oracle19c 安装详解

Linux-CentOS8-Oracle19c安装图解 文章目录 Linux-CentOS8-Oracle19c安装图解预备1. Oracle19c 安装手册&#xff1a;2. 安装虚拟机&#xff1a;4G内存&#xff0c;2*2核心&#xff0c;30G3. 下载CentOS8镜像。4. 开始准备预安装5. 修改Oracle账户密码6. 修改SELINUX值在文件&a…

AWS SAP-C02教程2--存储资源

存储资源在架构设计中是一个少不了的环节,而在AWS中有不同类型的存储资源,对应会有不同用途不同价格,SAP考试中考察各种存储是少不了,以下是涉及到的存储 目录 1 非结构化存储1.1 EBS(块存储)1.1.1 基本限制1.1.2 类型1.1.3 RAID 配置选项1.1.4 Snapshot1.2 Local Insta…

thinkphp6 入门(8)-- Session

开启Session Session功能默认是没有开启的&#xff08;API应用通常不需要使用Session&#xff09; think\middleware\SessionInit// 添加引用 use think\facade\Session; 赋值 Session::set(name, thinkphp);取值 // 如果值不存在&#xff0c;返回null Session::get(name)…

CSS的布局 Day03

一、显示模式&#xff1a; 网页中HTML的标签多种多样&#xff0c;具有不同的特征。而我们学习盒子模型、使用定位和弹性布局把内容分块&#xff0c;利用CSS布局使内容脱离文本流&#xff0c;使用定位或弹性布局让每块内容摆放在想摆放的位置&#xff0c;让网站页面布局更合理、…

ESP32-IPS彩屏ST7789-Arduino-简单驱动

目的&#xff1a; 使ESP32能够驱动点亮ST7789显示屏 前提条件&#xff1a; ESP32 ST7789 &#xff08;240 x240&#xff0c;IPS&#xff09; 杜邦线 Arduino 过程&#xff1a; 0x00--接线 0x01--驱动&#xff1a; 彩屏驱动库 针对不同的彩屏驱动芯片&#xff0c;常用的 Arduino…

如何实现 Es 全文检索、高亮文本略缩处理(封装工具接口极致解耦)

如何实现 Es 全文检索、高亮文本略缩处理 前言技术选型JAVA 常用语法说明全文检索开发高亮开发Es Map 转对象使用核心代码 Trans 接口&#xff08;支持父类属性的复杂映射&#xff09;Trans 接口可优化的点高亮全局配置类如下真实项目落地效果为什么不用 numOfFragments、fragm…

深度强化学习 第 3 章 强化学习基本概念

本章讲解强化学习的基本概念。第 3.1 节介绍马尔可夫决策过程&#xff08;Markov decision process&#xff0c;简称 MDP&#xff09;&#xff0c;它是最常见的对强化学习建模的方法。第 3.2 节定义策略函数&#xff0c;包括随机策略和确定策略。第 3.3 节分析强化学习中的随机…

element树形控件编辑节点组装节点

需求功能&#xff1a; 编辑树节点&#xff0c;组装节点 <el-scrollbar class"scrollbar-wrapper"><el-tree :data"nodeList" ref"tree" :props"defaultProps" :expand-on-click-node"false"><template slot…

十三、队列的特性

1、队列(Queue)概述 队列可以用于"任务到任务"、"任务到中断"、"中断到任务"直接传输信息。队列涉及内容如下: 怎么创建、清楚、删除队列队列中消息如何保存怎么向队列发送数据、怎么从队列读取数据、怎么覆盖队列的数据在队列上阻塞式什么意思…

计算机毕业设计-开题报告答辩常见问题!Javaweb项目答辩

&#x1f34a;作者&#xff1a;计算机编程-吉哥 &#x1f34a;简介&#xff1a;专业从事JavaWeb程序开发&#xff0c;微信小程序开发&#xff0c;定制化项目、 源码、代码讲解、文档撰写、ppt制作。做自己喜欢的事&#xff0c;生活就是快乐的。 &#x1f34a;心愿&#xff1a;点…