基于 Web SDK 实现视频通话场景 | 声网 SDK 教程

article/2025/10/13 7:25:43

图片

声网视频 SDK 被广泛应用于多种实时互动场景中,例如视频会议、视频通话、音视频社交、在线教育等。为了让刚刚接触声网 SDK 的开发者,可以更顺畅地实现基础的视频通话功能,我们基于声网 Web SDK 4.x 版本梳理了本篇教程。

在本文末,会提供相应 Demo 、文档地址供大家参考使用。同时,欢迎点击此处注册声网账号体验。声网每个月会为开发者提供 10000 分钟的免费额度。

本文为「声网 SDK 教程」系列内容

01 Demo 体验

我们在 GitHub 上提供一个开源的基础视频通话示例项目,在开始开发之前你可以通过该示例项目体验音视频通话效果。同时,声网官方还提供了Demo 与线上体验地址。

以下这些资料、文档,你可能会在动手实践过程中会用到:

1.Github 源码

https://github.com/AgoraIO/API-Examples-Web/tree/main/Demo/basicVideoCall

2.线上体验Demo(注意,由于体验 Demo 需要填写 appID,所以需要先注册声网账号)

https://webdemo.agora.io/basicVideoCall/index.html

3.注册声网账号

https://sso2.agora.io/cn/v4/signup/with-sms

4.声网文档中心

https://docs.agora.io/cn/Video/downloads?platform=Web

02 动手实践

实践任务

从 Web 前端页面引入声网 SDK,发起视频通话。

开发环境

声网 SDK 的兼容性良好,对硬件设备和软件系统的要求不高,开发环境和测试环境满足以下条件即可:

  • Chrome
  • Firefox
  • Safari
  • Edge

以下是本文的开发环境和测试环境:

开发环境

  • MacBook Pro (13-inch, M1, 2020)
  • Visual Studio Code (1.67.1)

测试环境

  • Chrome (101.0.4951.64)

如果你此前还未接触过声网 SDK,那么你还需要做以下准备工作:

  • 注册一个声网账号,进入后台创建 AppID、获取 Token;
  • 下载声网官方最新的 视频 SDK。

项目设置

文件组织结构

实现视频通话之前,参考如下步骤设置你的项目:

如需创建新项目,可以在 Visual Studio Code 里 File > New Window,创建 Web 项目。完整的目录结构如下,根据个人经验会有所变化。

.
├── index.css # 用于设计 Web 应用的用户界面样式
├── index.html # 用于设计 Web 应用的用户界面
├── index.js # 通过 AgoraRTCClient 实现具体应用逻辑的代码。
└── vendor # 第三方前端插件,辅助页面布局和交互,本教程中是下载到本地使用,你也可以使用 CDN 的方式├── bootstrap.bundle.min.js├── bootstrap.min.css└── jquery-3.4.1.min.js

集成声网 SDK

可以下载到本地使用,也可以直接使用声网的 CDN 引入, 本文推荐使用 CDN 方式集成声网 SDK。

在 index.html 中添加以下代码

<!DOCTYPE html>
...<link rel="stylesheet" href="./vendor/bootstrap.min.css"><link rel="stylesheet" href="./index.css">
...<script src="./vendor/jquery-3.4.1.min.js"></script><script src="./vendor/bootstrap.bundle.min.js"></script><script src="https://download.agora.io/sdk/release/AgoraRTC_N.js"></script><script src="./index.js"></script>
...

最终完整代码为

可以直接复制运行。

<!DOCTYPE html>
<html lang="en">
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"><meta http-equiv="X-UA-Compatible" content="ie=edge"><title>Basic Video Call -- Agora</title><link rel="stylesheet" href="./vendor/bootstrap.min.css"><link rel="stylesheet" href="./index.css">
</head>
<body><div class="container-fluid banner"><p class="banner-text">Basic Video Call</p><a style="color: rgb(255, 255, 255);fill: rgb(255, 255, 255);fill-rule: evenodd; position: absolute; right: 10px; top: 4px;"class="Header-link " href="https://github.com/AgoraIO-Community/AgoraWebSDK-NG/tree/master/Demo"><svg class="octicon octicon-mark-github v-align-middle" height="32" viewBox="0 0 16 16" version="1.1" width="32" aria-hidden="true"><path fill-rule="evenodd" d="M8 0C3.58 0 0 3.58 0 8c0 3.54 2.29 6.53 5.47 7.59.4.07.55-.17.55-.38 0-.19-.01-.82-.01-1.49-2.01.37-2.53-.49-2.69-.94-.09-.23-.48-.94-.82-1.13-.28-.15-.68-.52-.01-.53.63-.01 1.08.58 1.23.82.72 1.21 1.87.87 2.33.66.07-.52.28-.87.51-1.07-1.78-.2-3.64-.89-3.64-3.95 0-.87.31-1.59.82-2.15-.08-.2-.36-1.02.08-2.12 0 0 .67-.21 2.2.82.64-.18 1.32-.27 2-.27.68 0 1.36.09 2 .27 1.53-1.04 2.2-.82 2.2-.82.44 1.1.16 1.92.08 2.12.51.56.82 1.27.82 2.15 0 3.07-1.87 3.75-3.65 3.95.29.25.54.73.54 1.48 0 1.07-.01 1.93-.01 2.2 0 .21.15.46.55.38A8.013 8.013 0 0016 8c0-4.42-3.58-8-8-8z"></path></svg></a></div><div id="success-alert" class="alert alert-success alert-dismissible fade show" role="alert"><strong>Congratulations!</strong><span> You can invite others join this channel by click </span><a href="" target="_blank">here</a><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div><div id="success-alert-with-token" class="alert alert-success alert-dismissible fade show" role="alert"><strong>Congratulations!</strong><span> Joined room successfully. </span><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div><div id="success-alert-with-token" class="alert alert-success alert-dismissible fade show" role="alert"><strong>Congratulations!</strong><span> Joined room successfully. </span><button type="button" class="close" data-dismiss="alert" aria-label="Close"><span aria-hidden="true">&times;</span></button></div><div class="container"><form id="join-form"><div class="row join-info-group"><div class="col-sm"><p class="join-info-text">AppID</p><input id="appid" type="text" placeholder="enter appid" required><p class="tips">If you don`t know what is your appid, checkout <a href="https://docs.agora.io/en/Agora%20Platform/terms?platform=All%20Platforms#a-nameappidaapp-id">this</a></p></div><div class="col-sm"><p class="join-info-text">Token(optional)</p><input id="token" type="text" placeholder="enter token"><p class="tips">If you don`t know what is your token, checkout <a href="https://docs.agora.io/en/Agora%20Platform/terms?platform=All%20Platforms#a-namekeyadynamic-key">this</a></p></div><div class="col-sm"><p class="join-info-text">Channel</p><input id="channel" type="text" placeholder="enter channel name" required><p class="tips">If you don`t know what is your channel, checkout <a href="https://docs.agora.io/en/Agora%20Platform/terms?platform=All%20Platforms#channel">this</a></p></div></div><div class="button-group"><button id="join" type="submit" class="btn btn-primary btn-sm">Join</button><button id="leave" type="button" class="btn btn-primary btn-sm" disabled>Leave</button></div></form><div class="row video-group"><div class="col"><p id="local-player-name" class="player-name"></p><div id="local-player" class="player"></div></div><div class="w-100"></div><div class="col"><div id="remote-playerlist"></div></div></div></div><script src="./vendor/jquery-3.4.1.min.js"></script><script src="./vendor/bootstrap.bundle.min.js"></script><script src="https://download.agora.io/sdk/release/AgoraRTC_N.js"></script><script src="./index.js"></script>
</body>
</html>

视频通话逻辑

实现视频通话逻辑

下图展示视频通话的 API 调用时序,注意图中的方法是对不同的对象调用的。

图片

参考以下步骤实现音视频通话的逻辑:

1.调用 createClient 方法创建 AgoraRTCClient 对象。

2.调用 join 方法加入一个 RTC 频道,你需要在该方法中传入 App ID 、用户 ID、Token、频道名称。

3.先调用 createMicrophoneAudioTrack 通过麦克风采集的音频创建本地音频轨道对象,调用 createCameraVideoTrack 通过摄像头采集的视频创建本地视频轨道对象;然后调用 publish 方法,将这些本地音视频轨道对象当作参数即可将音视频发布到频道中。

4.当一个远端用户加入频道并发布音视频轨道时:

a.监听 client.on(“user-published”) 事件。当 SDK 触发该事件时,在这个事件回调函数的参数中你可以获取远端用户 AgoraRTCRemoteUser 对象 。

b.调用 subscribe 方法订阅远端用户 AgoraRTCRemoteUser 对象,获取远端用户的远端音频轨道 RemoteAudioTrack 和远端视频轨道 RemoteVideoTrack 对象。

c.调用 play 方法播放远端音视频轨道。

注:以下代码都将在 index.js 中添加**

初始化client

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

加入RTC 频道并创建本地音频轨道

// Join a channel and create local tracks. Best practice is to use Promise.all and run them concurrently.
[ options.uid, localTracks.audioTrack, localTracks.videoTrack ] = await Promise.all([// Join the channel.client.join(options.appid, options.channel, options.token || null, options.uid || null),// Create tracks to the local microphone and camera.AgoraRTC.createMicrophoneAudioTrack(),AgoraRTC.createCameraVideoTrack()
]);

播放本地视频

// Play the local video track to the local browser and update the UI with the user ID.
localTracks.videoTrack.play("local-player");

发布本地音视频到频道中

// Publish the local video and audio tracks to the channel.
await client.publish(Object.values(localTracks));

监听远端用户音视频

// Add an event listener to play remote tracks when remote user publishes.
client.on("user-published", handleUserPublished);
client.on("user-unpublished", handleUserUnpublished);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();}
}async function subscribe(user, mediaType) {const uid = user.uid;// subscribe to a remote userawait 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();}
}

离开频道

async function leave() {for (trackName in localTracks) {var track = localTracks[trackName];if(track) {track.stop();track.close();localTracks[trackName] = undefined;}}// Remove remote users and player views.remoteUsers = {};$("#remote-playerlist").html("");// leave the channelawait client.leave();}

最终完整的代码

// create Agora client
var client = AgoraRTC.createClient({ mode: "rtc", codec: "vp8" });var localTracks = {videoTrack: null,audioTrack: null
};
var remoteUsers = {};
// Agora client options
var options = {appid: null,channel: null,uid: null,token: null
};// the demo can auto join channel with params in url
$(() => {var urlParams = new URL(location.href).searchParams;options.appid = urlParams.get("appid");options.channel = urlParams.get("channel");options.token = urlParams.get("token");if (options.appid && options.channel) {$("#appid").val(options.appid);$("#token").val(options.token);$("#channel").val(options.channel);$("#join-form").submit();}
})$("#join-form").submit(async function (e) {e.preventDefault();$("#join").attr("disabled", true);try {options.appid = $("#appid").val();options.token = $("#token").val();options.channel = $("#channel").val();await join();if(options.token) {$("#success-alert-with-token").css("display", "block");} else {$("#success-alert a").attr("href", `index.html?appid=${options.appid}&channel=${options.channel}&token=${options.token}`);$("#success-alert").css("display", "block");}} catch (error) {console.error(error);} finally {$("#leave").attr("disabled", false);}
})$("#leave").click(function (e) {leave();
})async function join() {// add event listener to play remote tracks when remote user publishs.client.on("user-published", handleUserPublished);client.on("user-unpublished", handleUserUnpublished);// join a channel and create local tracks, we can use Promise.all to run them concurrently[ options.uid, localTracks.audioTrack, localTracks.videoTrack ] = await Promise.all([// join the channelclient.join(options.appid, options.channel, options.token || null),// create local tracks, using microphone and cameraAgoraRTC.createMicrophoneAudioTrack(),AgoraRTC.createCameraVideoTrack()]);// play local video tracklocalTracks.videoTrack.play("local-player");$("#local-player-name").text(`localVideo(${options.uid})`);// publish local tracks to channelawait client.publish(Object.values(localTracks));console.log("publish success");
}async function leave() {for (trackName in localTracks) {var track = localTracks[trackName];if(track) {track.stop();track.close();localTracks[trackName] = undefined;}}// remove remote users and player viewsremoteUsers = {};$("#remote-playerlist").html("");// leave the channelawait client.leave();$("#local-player-name").text("");$("#join").attr("disabled", false);$("#leave").attr("disabled", true);console.log("client leaves channel success");
}async function subscribe(user, mediaType) {const uid = user.uid;// subscribe to a remote userawait 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();}
}function handleUserPublished(user, mediaType) {const id = user.uid;remoteUsers[id] = user;subscribe(user, mediaType);
}function handleUserUnpublished(user) {const id = user.uid;delete remoteUsers[id];$(`#player-wrapper-${id}`).remove();
}

运行效果

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qHpzqvtR-1658572023354)(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)]在浏览器开两个tab运行网页,使用两个用户加入同一个频道,如果能看见两个自己,说明你成功了。

03 完整代码下载

访问声网文档中心,根据下图所示路径,下载对应 SDK 压缩包。压缩包中包含完整代码。
图片

参考链接

1.Github 源码

https://github.com/AgoraIO/API-Examples-Web/tree/main/Demo/basicVideoCall

2.线上体验Demo(注意,由于体验 Demo 需要填写 appID,所以需要先注册声网账号)

https://webdemo.agora.io/basicVideoCall/index.html

3.注册声网账号

https://sso2.agora.io/cn/v4/signup/with-sms

4.声网文档中心

https://docs.agora.io/cn/Video/downloads?platform=Web


http://chatgpt.dhexx.cn/article/3EdgFtrM.shtml

相关文章

如何基于 Agora Android SDK 在应用中实现视频通话?

在很多产品&#xff0c;实时视频通话已经不是新鲜的功能了&#xff0c;例如视频会议、社交应用、在线教育&#xff0c;甚至也可能出现在一些元宇宙的场景中。 本文将教你如何通过声网Agora 视频 SDK 在 Android 端实现一个视频通话应用。声网 SDK 每个月会提供 10000 分钟的免…

Android uni-app实现音视频通话

前言 上一篇讲解了怎么实现Android uni-app封装原生插件&#xff0c;这篇讲解一下&#xff0c;把anyRTC的RTC&#xff08;音视频通讯&#xff09;封装uni-app 实现音视频通话。 不了解anyRTC的小伙伴&#xff0c;可以点击下面链接&#xff1a; 开发者官网 1.效果图 先上图&a…

使用 Agora SDK 开发 React Native 视频通话 App

在 React Native 的应用中&#xff0c;从头开始添加视频通话功能是很复杂的。要保证低延迟、负载平衡&#xff0c;还要注意管理用户事件状态&#xff0c;非常繁琐。除此之外&#xff0c;还必须保证跨平台的兼容性。 当然有个简单的方法可以做到这一点。在本次的教程中&#xf…

MySQL联合索引底层数据结构是怎样的

目录 1. 联合索引数据结构图 2.联合索引是如何进行排序的 3. 联合索引查询特点 1. 联合索引数据结构图 如下图所示联合索引的数据结构, 通过name&#xff0c;age&#xff0c;position三个字典进行一个联合索引&#xff0c;构建B树索引结构。 2.联合索引是如何进行排序的 B树…

MySQL联合索引在B+树如何存储以及寻址

文章目录 引入Innodb B树联合索引存储以及寻址总结 引入 最近找工作&#xff0c; 去一家三方支付公司面试&#xff0c;前面得过程还挺好&#xff0c;所有的提都回答对了&#xff08;心里暗自窃喜应该能拿到高工资offer&#xff0c;迎娶白富美&#xff0c;然后走向人生巅峰&…

MySQL联合索引生效规则

最近项目中一张表数量测试达到千万级别&#xff0c;考虑加索引&#xff0c;对于单列索引及联合索引&#xff08;复合索引&#xff09;简单学习了下&#xff0c;做一下笔记。 联合索引生效前提&#xff1a;因为联合索引有顺序讲究&#xff0c;联合索引的第一个字段是引导列&…

mysql联合索引的数据结构

一、本文主要讲解的内容有&#xff1a; 联合索引在B树上的存储结构联合索引的查找方式为什么会有最左前缀匹配原则 在分享这篇文章之前&#xff0c;我在网上查了关于MySQL联合索引在B树上的存储结构这个问题&#xff0c;翻阅了很多博客和技术文章&#xff0c;其中有几篇讲述的…

mysql联合索引有效和失效的情况分析

关于mysql的索引&#xff0c;是mysql优化一个非常重要的方面。那么关于索引是否有效就是非常关键了。很多人设计了索引&#xff0c;但是发现依旧很慢。那么这个时候就判断sql的索引执行情况非常重要了。网上有大量的博主也写过不少类似的文章&#xff0c;但是关于联合索引的具体…

MySQL联合索引(abc)命中规则

1.建表 mysql创建一张表&#xff0c;表名&#xff1a;‘test_models’ id列为 主键&#xff0c;int类型 &#xff0c;自增a,b,c,d,e 全部是int&#xff08;11&#xff09;为&#xff08;a,b,c&#xff09;添加一个联合索引 index_abc 执行语句&#xff1a; CREATE TABLE te…

mysql联合索引

mysql联合索引的使用 命名规则&#xff1a;表名_字段名 1、需要加索引的字段&#xff0c;要在where条件中 2、数据量少的字段不需要加索引 3、如果where条件中是OR关系&#xff0c;加索引不起作用 4、符合最左原则 以下是我的建表语句 CREATE TABLE test ( id int(11) uns…

mysql 联合索引结构与索引匹配原则

联合索引结构与索引匹配原则 最左前缀匹配原则&#xff1a;在MySQL建立联合索引时会遵守最左前缀匹配原则&#xff0c;即最左优先&#xff0c;在检索数据时从联合索引的最左边开始匹配。 要想理解联合索引的最左匹配原则&#xff0c;先来理解下索引的底层原理。索引的底层是一…

详解MySQL联合索引

引言 本文预计分为两个部分:(1)联合索引部分的基础知识 在这个部分&#xff0c;我们温习一下联合索引的基础(2)联合索引部分的实战题 在这个部分&#xff0c;列举几个我认为算是实战中的代表题&#xff0c;挑出来说说。 正文 基础 讲联合索引&#xff0c;一定要扯最左匹配!…

mysql联合索引的使用

这篇笔记主要记录联合索引的使用 设置了shopId、userId、relationId三个字段&#xff0c;作为联合索引&#xff0c;这三个字段&#xff0c;都是long类型的&#xff0c;也就是bigint 分别验证以下几个场景&#xff1a; 场景一&#xff1a;explain select * from testIndex wher…

MySQL联合索引的原理

面试中被问到了联合索引&#xff0c;突然就涉及到了知识盲区&#xff0c;对不起&#xff0c;我只知道B树&#xff0c;B树&#xff0c;哈希索引&#xff0c;聚簇索引&#xff0c;非聚簇索引&#xff0c;联合索引的原理&#xff1f;。。 对不起涉及到了我的知识盲区了。 这里对联…

Mysql 联合索引

联合索引底层数据结构 MySQL可以使用多个字段同时建立一个索引,叫做联合索引。上文中讲到索引的底层结构就是一个二叉树&#xff0c;联合索引也是一样&#xff0c;它的非叶子节点中存的就不只是一个列&#xff0c;是索引的所有列&#xff0c;并且它的排序就是根据索引列的先后顺…

mysql联合索引详解

比较简单的是单列索引&#xff08;btree&#xff09;。遇到多条件查询时&#xff0c;不可避免会使用到多列索引。联合索引又叫复合索引。 btree结构如下&#xff1a; 每一个磁盘块在mysql中是一个页&#xff0c;页大小是固定的&#xff0c;mysql innodb的默认的页大小是16k&a…

MySQL索引详解

本文主要介绍MySQL索引底层原理及优化&#xff0c;理解SQL是如何执行&#xff0c;MySQL如何选择合适的索引以及时间都消耗在哪些地方&#xff0c;再加上一些优化的知识&#xff0c;可以帮助大家更好的理解MySQL&#xff0c;理解常见优化技巧背后的原理。希望本文中的原理、示例…

MySQL索引之联合索引

目录 1. 联合索引1.1. 联合索引的存储结构1.2. 联合索引的查询流程1.3. 最左前缀匹配原则1.3.1. 最左前缀匹配原则说明 2. 索引下推2.1. 无索引下推的执行流程2.2. 有索引下推的执行流程 1. 联合索引 在平时开发中&#xff0c;我们最常见的是聚集索引&#xff0c;但在我们需要…

jedis和redisTemplate

使用原生jedis和spring的redisTemplate调用连接池&#xff0c;发现差别巨大&#xff1a; redis配置&#xff1a; redis:database: 0host: 127.0.0.1port: 6379password: 123456timeout: 5000lettuce:shutdown-timeout: 200pool:max-active: 500max-idle: 100min-idle: 50max-w…

16.Jedis

目录 一、Jedis知识点总览。 二、连接池配置&#xff1a; 三、测试类&#xff1a; 一、Jedis知识点总览。 public class ProvinceServiceImpl implements ProvinceService {private ProvinceDao dao new ProvinceDaoImpl();Overridepublic List<Province> findAll(…