使用Uni-app实现语音视频聊天(Android、iOS)

news/2025/2/26 1:00:42

使用Uni-app开发手机端APP已经变得很普遍,同一套代码就可以打包成Android App 和 iOS App,相比原生开发,可以节省客观的人力成本。那么如何使用Uni-app来开发视频聊天软件或视频会议软件了?本文将详细介绍在Uni-app中,如何基于OMCS来快速搭建视频聊天程序。

一、准备工作

1.在Uni-app项目的根目录下新建如下目录结构,用来存储Android和iOS原生插件。

2.插件目录说明

android:在插件android目录下新建libs目录,将OMCS原生插件中使用的OMCS非托管库及jar包放入该目录下。将OMCS原生插件arr包放入android目录下

ios:将OMCS原生插件中使用的OMCSFramework.framework及OMCS原生插件OMCSPlugin.framework放到ios目录下

3.插件配置文件:nativeplugins根目录下新建package.json文件,详细配置说明及模版请参考uni官网uni小程序SDK

(1)修改package.json配置文件中插件的name及id为omcs-plugin

(2)android插件配置

(3)ios插件配置

4.uni-app项目配置文件manifest.json中将OMCS原生插件加入项目中

注意:修改配置后,需要重新打包app基座才能生效

二、正式开发

首先,我们在uni-app项目中引入OMCS-Uni.js文件,然后在依照如下步骤操作。

1.构造并初始化OMCS多媒体设备管理器。如果要设置一些配置参数,可以在调用初始化方法之前通过设置 multimediaManager 的相关属性来完成。

const multimediaManager = MultimediaManagerFactory.GetSingleton();  
multimediaManager.initialize(
    this.userID,
    this.password,
    this.serverIP,
    this.serverPort,
    (res)=>{
        if(res == 'OMCS登录成功' || res == '登录成功'){}
    }
);

2.本demo中,我们定义了一个简单的客户端home页面:home.vue ,用于展示OMCS提供的各个功能。在home页面的onLoad方法中,我们请求了android音视频权限:

onLoad(options) {
    this.query = options;
    this.loginId = this.query.loginid;
    MultimediaManagerFactory.GetSingleton().checkPermission();
},

在home页面的onUnload方法中,我们主动断开了OMCS的连接:

onUnload() {
    MultimediaManagerFactory.GetSingleton().close();
},

home页界面如下所示:

页面上的各个按钮,用于演示OMCS提供的各个多媒体连接器的功能。我们以视讯功能为例,当摄像头和话筒的checkbox都勾选上时,表示连接到目标用户的摄像头和麦克风设备。点击“语音视频”按钮,将跳转至video页面:

注意:必须勾选摄像头,并进入video页面后(此时将看到自己摄像头的预览画面),其他人才可以连接到自己的摄像头。

 3.开始连接

(1)当点击【开始连接对方】按钮时,将连接到对方摄像头和麦克风

(2)我们封装了一个组件UniCameraPanel.nvue,其中使用了OMCS原生控件OMCSSurfaceView作为存放对方视频图像的容器,OMCS原生控件CameraSurfaceView作为存放自己视频预览的容器:

<template>
	<CameraSurfaceView
		ref="camera_self_panel_view" 
		v-if="isSelf" 
		class="selfVideoView"
		></CameraSurfaceView>
	<OMCSSurfaceView 
		ref="camera_other_panel_view" 
		v-if="!isSelf" 
		class="otherVideoView"
		></OMCSSurfaceView>
</template>

 (3)video页面使用了UniCameraPanel.nvue控件,根据isSelf属性判断是否为自己预览的摄像头:

<div class="otherView" v-if="isVideo"  @click.stop="changeShowIcon">
    <UniCameraPanelVue
        :isSelf="false" 
        ref="otherCameraPanel"
        class="otherVideoView"
    ></UniCameraPanelVue>
</div>
<div class="selfView"  v-if="isVideo" >
    <UniCameraPanelVue
        :isSelf="true" 
        ref="selfVideoView"
        class="selfVideoView"
    ></UniCameraPanelVue>
</div>

注意:video页面必须为nvue页面才能使用UniCameraPanel.nvue控件

(4)在video页面OnLoad初始化方法中,我们分别定义了CameraConnectorMicrophoneConnector连接器用于连接目标用户的摄像头和话筒,并通过setConnectorEventListener预定了CameraConnectorMicrophoneConnector的连接结束事件和连接断开事件

onLoad(options) {
    this.query = options;
    this.othername = this.query.destUserID;
    this.username = this.query.username;
    this.isAndroid = uni.getSystemInfoSync().platform == 'android';
    this.isVideo = Boolean(Number(this.query.openCamera));
    if(this.isVideo){
        this.cameraConnector = new CameraConnector(this.query.destUserID);
        this.cameraConnector.setConnectorEventListener(
            this.CameraConnector_ConnectEnded,
            this.CameraConnector_DisConnected
        );
        this.cameraConnector.setVideoDrawMode(VideoDrawMode.Scale);
    };
    if(Boolean(Number(this.query.openMic))){
        this.microphoneConnector = new MicrophoneConnector(this.query.destUserID);
        this.microphoneConnector.setConnectorEventListener(
            this.MicrophoneConnector_ConnectEnded,
            this.MicrophoneConnector_DisConnected
        );
    };
}

注意:CameraConnector连接器需要在OnLoad初始化时创建

(5)在video页面【开始连接对方】按钮点击事件中调用了CameraConnectorMicrophoneConnector连接器的beginConnect方法:

contentOtherBtnClick(){
    if(Boolean(Number(this.query.openCamera))){
        this.cameraConnector.beginConnect();
    };
    if(Boolean(Number(this.query.openMic))){
        this.microphoneConnector.beginConnect();
    };
}

注意:

在调用CameraConnector连接器的beginConnect方法之前需要执行UniCameraPanel控件的SetVideo方法:

SetVideo(_cameraConnector){
    try{
        if(_cameraConnector){
            if(this.isSelf){
                this.$refs.camera_self_panel_view.setVideo();
            }else{
                this.cameraConnector = _cameraConnector;
                const userID = this.cameraConnector.destUserID;
                this.videoDrawMode = this.cameraConnector.videoDrawMode;
                this.$refs.camera_other_panel_view.setVideo({destUserID:userID});
            }
        }
    }catch(e){
        console.log(e)
    }
}

4.当退出video页面或者主动断开连接时,需要调用CameraConnector连接器MicrophoneConnector连接器disconnect方法,并且通过removeConnectorEventListener方法取消预定的事件,最后还需要调用多媒体管理器的closeCamera方法断开自己的预览摄像头

closeVideo(){
    if(this.cameraConnector){
        this.cameraConnector.disconnect();
        this.cameraConnector.removeConnectorEventListener();
        this.cameraConnector = null;
    }
    if(this.microphoneConnector){
        this.microphoneConnector.disconnect();
        this.microphoneConnector.removeConnectorEventListener();
        this.microphoneConnector = null;
    }
    this.isShowVideo = false;
    MultimediaManagerFactory.GetSingleton().closeCamera();
},

三、源码下载

该Demo的源码下载地址如下:OMCS.UniappDemo.rar   (Android、iOS)

至于服务端,我们已经打包好了exe文件,可以下载后直接双击运行:

OMCS 服务端可执行程序(解压后,双击exe即可运行)

Uniapp版本的Demo还可以与PC版本(Windows、银河麒麟、统信UOS)的Demo进行音视频通话,PC版可以转到此处下载。


http://www.niftyadmin.cn/n/5867010.html

相关文章

存储引擎、索引(MySQL笔记第四期)

p.s.这是萌新自己自学总结的笔记&#xff0c;如果想学习得更透彻的话还是请去看大佬的讲解 目录 存储引擎概念InnoDB存储引擎MyISAM存储引擎Memory存储引擎存储引擎的选择 索引三种索引索引分类语法(创建/查看/删除)性能分析工具SQL执行频率慢查询日志profile详情explain执行计…

力扣hot100刷题——11~20

文章目录 11.滑动窗口最大值题目描述思路&#xff1a;滑动窗口单调队列code 12.最小覆盖子串题目描述思路&#xff1a;双指针/滑动窗口哈希code Ⅰcode Ⅱ 13.最大子数组和题目描述思路&#xff1a;dp/贪心code 14.合并区间题目描述思路&#xff1a;贪心code 15.轮转数组题目描…

SpringSecurity处理器:登录成功处理器、登录失败处理器、无权限处理器、注销成功处理器

在 Spring Security 中,你可以通过实现特定的接口或扩展某些类来自定义各种处理器,例如登录成功处理器、登录失败处理器、无权限处理器和登出成功处理器。 以下是每种处理器的具体实现方法: 【示例】首先创建统一的响应结果类和响应结果编码枚举,方便后续示例中使用。 (…

2025-skywalking组件

历史版本下载地址&#xff1a;Apache Archive Distribution Directory 官网&#xff1a;Apache SkyWalking 目录 . webapp: UI前端(web 监控页面)的jar包和配置文件; . oap-libs:后台应用的jar包&#xff0c;以及它的依赖jar包&#xff0c;里边有一个server-starter-*.jar就是…

API返回的数据结构包含哪些字段?

淘宝商品详情API返回的数据结构较为复杂&#xff0c;具体字段会根据API的版本和请求参数有所不同。以下是基于最新搜索结果的API返回值字段说明&#xff1a; 基础字段 num_iid&#xff1a;商品的唯一标识ID。 title&#xff1a;商品标题&#xff0c;用于描述商品名称或特点。…

C++:pthread线程分离和线程属性

在 C 的多线程编程中&#xff0c;pthread 库提供了强大的功能来管理线程。其中&#xff0c;线程分离和线程属性是两个重要的概念&#xff0c;它们对于优化线程的行为和资源管理有着关键作用。 线程分离 1.1 什么是线程分离 在 pthread 库中&#xff0c;线程有两种状态&#…

从零开始的网站搭建(以照片/文本/视频信息通信网站为例)

本文面向已经有一些编程基础&#xff08;会至少一门编程语言&#xff0c;比如python&#xff09;&#xff0c;但是没有搭建过web应用的人群&#xff0c;会写得尽量细致。重点介绍流程和部署云端的步骤&#xff0c;具体javascript代码怎么写之类的&#xff0c;这里不会涉及。 搭…

【Qt之QQuickWidget】QML嵌入QWidget中

由于我项目开始使用Widgets,换公司后直接使用QML开发&#xff0c;没有了解过如何实现widget到qml过渡&#xff0c;恰逢面试时遇到一家公司希望从widget迁移到qml开发&#xff0c;询问相关实现&#xff0c;一时语塞&#xff0c;很尴尬&#xff0c;粗略研究并总结下。 对qwidget嵌…