前言

大家好,我是 @小曾同学,小伙伴们也可以叫我小曾~

如果你想实现一对一音视频通话和屏幕共享功能,不妨来看看这篇文章,保姆级教程,不需要从零实现,直接集成声网 SDK 即可轻松上手。

本文也分享了我在实践过程中遇到的一些问题,帮助小伙伴们避坑。如果文章知识点有错误的地方,还请大家指正,让我们一起学习,一起进步~


01 背景介绍

声网提供了各端丰富的音视频 SDK,本文将要使用的是 Web 端 SDK。

本篇文章主要给小伙伴们分享如何使用声网 SDK 实现 Web 端音视频通话及屏幕共享功能,其中也会涵盖在实践过程中遇到的一些问题,以此记录防止小伙伴们踩坑,同时也希望通过从 0 到 1 实战的分享,能够帮助更多的小伙伴。

02 前期准备

在实战之前,需要有以下准备条件:

• Npm & Node.js
• 前端开发基础,如 html & CSS & JavaScript
• 注册声网账号,申请声网APPID、临时Token ,详见开始使用声网平台。

如果你还没有声网账号,可以通过这里免费注册,每个账户每月都有10000分钟免费额度。如果是个人学习/调试,时长完全够用。

我个人的开发环境,具体信息如下:

• MacBook Pro
• Visual Studio Code:v1.75.1
• Npm:v8.19.3
• Node.js:v16.19.0
• 声网 SDK:v4.2.1 ,sdk的下载可查看这里。
• Google Chrome :v110.0.5481.177

03 实战环节

通过[前期准备],我们已经完成了相关配置,已经拥有了 App ID、Channel、临时 Token、声网 SDK,在本次实战中,主要详细讲解两个 demo,分别是音视频通话及屏幕共享连麦。

3.1 实现音视频通话

在开始实战之前,先声明下 Demo 组成架构,

创建一个文件夹名为 Agora_VideoCall,文件夹中包含五个文件,分别是:

• index.html:用于设计 Web 应用的用户界面
• index.css:用于设计网页样式
• basicVideoCall.js:实现音视频通话逻辑代码,主要通过 AgoraRTCClient 实现
• AgoraRTC_N-4.2.1.js:声网音视频SDK
• assets:第三方库,主要用于设计用户界面

在 index.html 文件中导入声网SDK,具体内容可查看详细代码,接下来主要详细讲解音视频通话及屏幕共享实现逻辑。

<script src="./AgoraRTC-N-4.2.1.js"></script>

3.1.1 实现音视频通话逻辑

以下代码均在 basicVideoCall.js 文本中写入

1)首先调用 AgoraRTC.createClient 方法创建一个 client 对象,也就是创建客户端对象

var client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });

2)定义变量 App ID,Token、Channel、User ID,并使用箭头函数实现当页面被调用时用于加入音视频通话通道。

var options = {appid: null,channel: null,uid: null,token: null
};$(() => {var urlParams = new URL(location.href).searchParams;options.appid = urlParams.get("appid");options.channel = urlParams.get("channel");options.token = urlParams.get("token");options.uid = urlParams.get("uid");if (options.appid && options.channel) {$("#uid").val(options.uid);$("#appid").val(options.appid);$("#token").val(options.token);$("#channel").val(options.channel);$("#join-form").submit();}
})

3)加入频道

定义 join 函数主要是将本地音视频 track 加入一个 RTC 频道,此时需要在函数中传入 App ID,Token、Channel、User ID。加入房间后,需要发布音视频track,所以还需要创建音视频 track,并调用 publish 方法将这些本地音视频track对象当作参数发布到频道中。

注意注意,在创建音视频 track 时需要先调用 createMicrophoneAudioTrack :通过麦克风采集的音频创建本地音频轨道对象;再调用 createCameraVideoTrack :通过摄像头采集的视频创建本地视频轨道对象。(如果先调用createCameraVideoTrack ,那么页面中将不会显示本地视频预览画面)

创建之后即可调用 play 方法展示本地预览,并调用 publish 方法发布到 RTC 频道中。注意 play 和 publish 方法的使用没有先后顺序,谁在前在后没有什么影响。

async function join() {[ options.uid, localTracks.audioTrack, localTracks.videoTrack ] = await Promise.all([// 加入频道client.join(options.appid, options.channel, options.token || null, options.uid || null),// 创建本地音视频track//AgoraRTC.createCameraVideoTrack(),AgoraRTC.createMicrophoneAudioTrack(),AgoraRTC.createCameraVideoTrack()]);localTracks.videoTrack.play("local-player");$("#local-player-name").text(`localVideo(${options.uid})`);await client.publish(Object.values(localTracks));console.log("publish success");
}

4)在频道中添加或移除远端用户逻辑

实现将同频道的远端用户添加到本地接口,当远端用户取消发布时,则从本地将用户移除。

function handleUserPublished(user, mediaType) {const id = user.uid;remoteUsers[id] = user;subscribe(user, mediaType);
}function handleUserUnpublished(user, mediaType) {if (mediaType === 'video') {const id = user.uid;delete remoteUsers[id];$(`#player-wrapper-${id}`).remove();}
}

5)订阅远端音视频逻辑

当远端用户发布音视频时,本地用户需要对其订阅,从而实现音视频通话,在 subscribe 函数中需要传入两个参数,分别是同频道远端用户 user id 和远端 mediaType,并调用 play 方法,播放远端用户音视频,从而实现一对一连麦。

async function subscribe(user, mediaType) {const uid = user.uid;// 订阅远端用户await client.subscribe(user, mediaType);console.log("subscribe success");if (mediaType === 'video') {const player = $(`<div id="player-wrapper-${uid}"><p class="player-name">remoteUser(${uid})</p><div id="player-${uid}" class="player"></div></div>`);$("#remote-playerlist").append(player);user.videoTrack.play(`player-${uid}`);}if (mediaType === 'audio') {user.audioTrack.play();}
}

6)监听事件

当远端用户发布或者取消发布音视频 track 时,本地还需要对其监听,在 join 函数中,监听 client.on(“user-published”, handleUserPublished) 事件和 client.on(“user-unpublished”, handleUserUnpublished) 事件,具体如下

client.on("user-published", handleUserPublished);
client.on("user-unpublished", handleUserUnpublished);


7)离开频道

当用户点击 leave 按钮时,则将 stop 本地和远端音视频 track。

async function leave() {for (trackName in localTracks) {var track = localTracks[trackName];if(track) {track.stop();track.close();localTracks[trackName] = undefined;}}

3.1.2 Demo展示

接下来可以运行我们的 Demo 啦,输入 APPID、Token、Channel、Userid,点击 join,即可看到自己本地的画面,如果想和别人连麦,可以再复制一下网址,输入相同的 APPID、Token、Channel,即可实现连麦,赶快试试吧。

3.2 屏幕共享连麦

屏幕共享就是将本地用户的屏幕内容,以视频画面的方式分享给其他远端用户观看。其工作原理实际上是通过 createScreenVideoTrack 创建一个屏幕共享的视频轨道对象来实现。采集屏幕的过程中浏览器会询问需要共享哪些屏幕,根据终端用户的选择去获取屏幕信息。

在上述音视频 demo 的基础上实现屏幕共享功能。

3.2.1 添加屏幕共享UI

在 index.html 页面中添加屏幕共享(ScreenShare)button

3.2.2 屏幕共享实现逻辑

以下代码均在 basicVideoCall.js 文本中写入

1)实现 share 函数

和上述 join 函数功能类似,主要用于开启屏幕共享,使用 createScreenVideoTrack 创建屏幕共享的视频轨道对象,同时也可以对视频编码进行一些简单的配置。函数中同样也需要添加监听事件。

async function share() {client.on("user-published", handleUserPublished);client.on("user-unpublished", handleUserUnpublished);let screenTrack;[options.uid, localTracks.audioTrack, screenTrack] = await Promise.all([client.join(options.appid, options.channel, options.token || null, options.uid || null),AgoraRTC.createMicrophoneAudioTrack(),AgoraRTC.createScreenVideoTrack({encoderConfig: {framerate: 15,height: 720,width: 1280}}, "auto")]);

2)添加屏幕共享音视频轨道,并调用 play 方法播放本地屏幕共享的视频。

if(screenTrack instanceof Array){localTracks.screenVideoTrack = screenTrack[0]localTracks.screenAudioTrack = screenTrack[1]}else{localTracks.screenVideoTrack = screenTrack}localTracks.screenVideoTrack.play("local-player");$("#local-player-name").text(`localVideo(${options.uid})`);

3)发布屏幕共享

发布本地音频和屏幕共享画面至 RTC 频道中。

if(localTracks.screenAudioTrack == null){await client.publish([localTracks.screenVideoTrack, localTracks.audioTrack]);}else{await client.publish([localTracks.screenVideoTrack, localTracks.audioTrack, localTracks.screenAudioTrack]);}

4)在 share 函数实现逻辑中需要绑定 “track-ended” 事件,当屏幕共享停止时,会有一个警报通知最终用户。

localTracks.screenVideoTrack.on("track-ended", () => {alert(`Screen-share track ended, stop sharing screen ` + localTracks.screenVideoTrack.getTrackId());localTracks.screenVideoTrack && localTracks.screenVideoTrack.close();localTracks.screenAudioTrack && localTracks.screenAudioTrack.close();localTracks.audioTrack && localTracks.audioTrack.close();});

3.2.3 Demo 展示

当点击 ScreenShare 时,会提示用户选择哪一个 page 进行分享,同时也有一个默认音频选项,点击分享之后,即可发布屏幕共享。

![](https://img-blog.csdnimg.cn/8ae0e6be7c084d19ab11f518e2e9a30d.jpeg

04 小结

如果你想实现音视频和屏幕共享的 Web 应用,完全可以借鉴本篇文章 + 声网SDK,如果不是很熟悉的话,可以先看声网给出的「快速开始 - 实现音视频通话」。

在实践过程中需要注意的是:在创建音视频 track 时需要先调用 createMicrophoneAudioTrack ,再调用 createCameraVideoTrack ,如果先调用 createCameraVideoTrack 那么页面中将不会显示本地视频预览画面。

Generally,本篇文章给出的 demo 比较简单,如果想要添加其他的功能比如,虚拟背景、AI降噪等,可以在此基础上继续添加功能。

(正文完)

参考资料

• 注册声网账号
• 相关 SDK 下载
• 快速开始 - 实现音视频通话

保姆级教程!基于声网 Web SDK实现音视频通话及屏幕共享相关推荐

  1. 神奇,声网Web SDK还能这么实现直播中美颜功能

    前言 本篇文章是通过使用声网Web SDK来实现直播中美颜效果的深度体验文章,其中发现了屏幕共享并本地合图多个视频.图片,声网美颜插件等功能特性十分强大和专业,特为此做一个技术+体验的分享,毕竟好技术 ...

  2. 基于声网 Flutter SDK 实现多人视频通话

    前言 本文是由声网社区的开发者"小猿"撰写的Flutter基础教程系列中的第一篇.本文除了讲述实现多人视频通话的过程,还有一些 Flutter 开发方面的知识点.该系列将基于声网 ...

  3. Frp内网穿透保姆级教程 windows内网穿透

    Frp内网穿透保姆级教程 windows内网穿透 准备工作 一台具有公网ip的云服务器(我的是ubuntu) frp程序 流程 将frps放到具有公网ip的服务器上 将frpc放到需要内网穿透机器上, ...

  4. 基于声网 Flutter SDK 实现互动直播

    前言 互动直播是实现很多热门场景的基础,例如直播带货.秀场直播,还有类似抖音的直播 PK等.本文是由声网社区的开发者"小猿"撰写的Flutter基础教程系列中的第二篇,他将带着大家 ...

  5. 基于声网 iOS SDK 实现视频直播应用

    视频互动直播是当前比较热门的玩法,我们经常见到有PK 连麦.直播答题.一起 KTV.电商直播.互动大班课.视频相亲等.本文将演示如何通过声网视频 SDK 在 iOS 端实现一个视频直播应用.话不多说, ...

  6. 【宝塔面板部署nodeJs项目】网易云nodeJs部署在云服务器上,保姆级教程,写网易云接口用自己的接口不受制于人

    看了很多部署的,要么少步骤,要么就是写的太简洁,对新手不友好 文章目录 前言 一.下载网易云nodejs项目 1. git clone下载,两种方式 2. 运行项目 二.使用步骤 1. 先在本地运行 ...

  7. Unity Metaverse(八)、RTC Engine 基于Agora声网SDK实现音视频通话

    文章目录 简介 创建应用 构建应用场景 API调用与回调事件 测试 简介 本文介绍如何在Unity中接入声网SDK,它可以应用的场景有许多,例如直播.电商.游戏.社交等,音视频通话是其实时互动的基础能 ...

  8. 保姆级教程——如何访问内网NAS

    在讲解如何访问NAS之前,我先来说下为什么需要访问内网NAS. 首先处于成本考虑,很多NAS系统都是部署在企业内网的,离开公司就无法访问,现在是高效率办公的时代,可能随时随地都需要用到NAS内部的文件 ...

  9. 基于声网的音视频SDK和FreeSWITCH开发WebRTC2SIP Gateway 方案和思路

    为什么做这个? 今年初接到一个项目任务,客户要求在自己的音视频平台系统中集成webrtc功能(原系统是基于SIP协议开发的,已经稳定运行多年,有很多客户).在比对了多家RTC产品的效果后,.他们对声网 ...

最新文章

  1. Vagrant 管理部署 VirtualBox (推荐使用)
  2. VC++实现恢复SSDT
  3. mysql查阅建立的库_MySQL - 建库、建表、查询
  4. JSTracker:前端异常数据采集
  5. Node.js实现基于TCP与UDP的数据通信
  6. java char 打印_Java中char[]输出不是内存地址的原因详解
  7. webview布局适配实践
  8. 刚毕业,师傅推荐的书单
  9. 事业编,突然接到换岗通知,作为个人能怎么办?能拒绝换岗吗?拒绝的后果是什么?
  10. html canvas drawrect 变形,canvas图形变换
  11. 产品经理数据分析入门
  12. 极点五笔常用操作及快捷键功能描述(v6.5)
  13. SCI文章下载网址收藏
  14. 「大数据干货」基于Hadoop的大数据平台实施——整体架构设计
  15. [SUCTF 2018]GetShell
  16. 电磁流量计应用的局限性
  17. Go避免使用大堆造成的高GC开销
  18. GPS学习之二:AGPS,GPS,DGPS 认识
  19. 演出经纪人考试大纲、演出经纪人考试资料是什么?
  20. 保护个人信息,才能享受大数据的时代成果

热门文章

  1. miui怎么用第三方图标包_MIUI上线全新动态图标主题,锁屏功能超级多且好用
  2. 第四讲:各种形态的描述
  3. 统计学真的有那么可怕吗?这儿有可以手算的效能分析
  4. 恒温空调plc控制电路_为什么我的智能恒温器会一直关闭空调?
  5. 计算机信息管理专业学ps吗,计算机信息管理专业个人技能怎么写
  6. 安徽二本院校 计算机专业,安徽合肥二本大学排名
  7. Defy刷魔趣2.3.7包~
  8. git简单上传/修改上传
  9. matlab三相电路基波图形,毕业设计基于matlab的三相交流调压电路的设计与仿真.doc...
  10. 连享会-Python爬虫与文本分析专题 (2019.5.17-19)