产品战略专家梁宁确认出席AICon北京站,分享AI时代下的商业逻辑与产品需求 了解详情
写点什么

基于 Agora SDK 实现 Web 端的多人视频互动

  • 2020-02-26
  • 本文字数:9231 字

    阅读完需:约 30 分钟

基于 Agora SDK 实现 Web 端的多人视频互动

根据本文指导快速集成 Agora Web SDK 并在你自己的 app 里实现音视频互动直播。


本文会详细介绍如何建立一个简单的项目并使用 Agora Web SDK 实现基础的互动直播。我们建议你阅读本文以快速了解 Agora 的核心方法。


互动直播和实时通话的区别在于,直播频道的用户有角色之分。你可以将角色设置为主播,或者观众,其中主播可以收、发流,观众只能收流。


由于浏览器的安全策略对除 127.0.0.1 以外的 HTTP 地址作了限制,Agora Web SDK 仅支持 HTTPS 协议或者 http://localhosthttp://127.0.0.1),请勿使用 HTTP 协议部署你的项目。

Demo 体验

我们在 GitHub 上提供一个开源的基础视频互动直播示例项目,在开始开发之前你可以通过该示例项目体验互动直播效果。

前提条件

  1. 安装一款 Agora Web SDK 支持的浏览器,如下表所示:

  2. 获得一个有效的 Agora 账号。(免费注册)

  3. 如果你的网络环境部署了防火墙,请根据声网文档中心的「应用企业防火墙限制」打开相关端口。

设置开发环境

你需要准备一个自己的项目并且将 Agora Web SDK 集成到其中。

创建 Web 项目

如果你已经有一个 Web 项目了,跳过该节,直接阅读集成 SDK。


我们提供的示例代码使用了一些第三方的库文件来实现页面的样式和布局,你可以在 Github repo 中查找一下文件,或者使用其他方式实现。


  • common.css

  • jquery.min.js

  • materialize.min.js

  • 这个项目只需要用到一个 HTML 文件。


  1. 新建一个 HTML 文件。这里我们将文件命名为 index.html(以下简称项目文件)。

  2. 用一个代码编辑器(例如 VS Code)打开该文件。

  3. 复制以下代码,粘贴到项目文件中。

  4. 该步骤会为你的项目创建前端页面的 UI,你也可以自定义你的 UI。以下是示例代码:


<!DOCTYPE html><html lang="en"><head>  <meta charset="UTF-8">  <meta http-equiv="X-UA-Compatible" content="ie=edge">  <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">  <title>Basic Live Broadcast</title>  <link rel="stylesheet" href="./assets/common.css" /></head><body class="agora-theme">  <div class="navbar-fixed">    <nav class="agora-navbar">      <div class="nav-wrapper agora-primary-bg valign-wrapper">        <h5 class="left-align">Basic Live Broadcast</h5>      </div>    </nav>  </div>  <form id="form" class="row col l12 s12">    <div class="row container col l12 s12">      <div class="col" style="min-width: 433px; max-width: 443px">        <div class="card" style="margin-top: 0px; margin-bottom: 0px;">          <div class="row card-content" style="margin-bottom: 0px;">              <div class="input-field">                <label for="appID" class="active">App ID</label>                <input type="text" placeholder="App ID" name="appID">              </div>              <div class="input-field">                <label for="channel" class="active">Channel</label>                <input type="text" placeholder="channel" name="channel">              </div>              <div class="input-field">                <label for="token" class="active">Token</label>                <input type="text" placeholder="token" name="token">              </div>              Host: <input id="role" type="checkbox" checked></input>              <div class="row" style="margin: 0">                <div class="col s12">                <button class="btn btn-raised btn-primary waves-effect waves-light" id="join">JOIN</button>                <button class="btn btn-raised btn-primary waves-effect waves-light" id="leave">LEAVE</button>                <button class="btn btn-raised btn-primary waves-effect waves-light" id="publish">PUBLISH</button>                <button class="btn btn-raised btn-primary waves-effect waves-light" id="unpublish">UNPUBLISH</button>                </div>              </div>          </div>        </div>      </div>      <div class="col s7">        <div class="video-grid" id="video">          <div class="video-view">            <div id="local_stream" class="video-placeholder"></div>            <div id="local_video_info" class="video-profile hide"></div>            <div id="video_autoplay_local" class="autoplay-fallback hide"></div>          </div>        </div>      </div>    </div>  </form><script src="vendor/jquery.min.js"></script><script src="vendor/materialize.min.js"></script></body></html>
复制代码

集成 SDK

选择如下任意一种方法获取 Agora Web SDK:


方法 1. 使用 npm 获取 SDK


使用该方法需要先安装 npm,详见 npm 快速入门。


  1. 运行安装命令


npm install agora-rtc-sdk
复制代码


  1. 在你的项目的 Javascript 代码中添加一行:


import AgoraRTC from 'agora-rtc-sdk'
复制代码


方法 2. 使用 CDN 方法获取 SDK


该方法无需下载安装包。在项目文件中,将以下代码添加到上一行:</p><pre><code>&lt;script&nbsp;src=&quot;https://cdn.agora.io/sdk/release/AgoraRTCSDK-3.0.0.js&quot;&gt;&lt;/script&gt;<br/></code></pre><p>方法 3. 从官网获取 SDK</p><ol><li>下载最新版 Agora Web SDK 软件包。</li><li>将下载下来的软件包中的 AgoraRTCSDK-3.0.0.js 文件保存到项目文件所在的目录下。</li><li>在项目文件中,将如下代码添加到<style>上一行:</li></ol><pre><code>&lt;script&nbsp;src=&quot;./AgoraRTCSDK-3.0.0.js&quot;&gt;&lt;/script&gt;<br/></code></pre><p>为方便起见,这里我们选择第二种方法,直接使用 CDN 链接。<br/>现在,我们已经将 Agora Web SDK 集成到项目中了。接下来我们要通过调用 Agora Web SDK 提供的核心 API 实现基础的互动直播功能。</p><h2>实现互动直播</h2><p>本节介绍如何使用 Agora Web SDK 实现互动直播。</p><p>在使用 Agora Web SDK 时,你会经常用到以下两种对象:</p><ul><li>Client 对象,代表一个本地客户端。Client 类的方法提供了音视频通话的主要功能,例如加入频道、发布音视频流等。</li><li>Stream 对象,代表本地和远端的音视频流。Stream 类的方法用于定义音视频流对象的行为,例如流的播放控制、音视频的编码配置等。调用 Stream 方法时,请注意区分本地流和远端流对象。<br/>下图展示了基础互动直播的 API 调用。注意图中的方法是对不同的对象调用的。</li></ul><p><img src="https://static001.infoq.cn/resource/image/94/47/94f50891c80418c172345becaedcf647.jpg" alt=""/></p><blockquote><p>本文只介绍 Agora Web SDK 最基础的方法和回调。完整的 API 方法和回调详见 Web API 参考。</p></blockquote><p>为方便起见,我们为下面要用到的示例代码定义了两个变量。此步骤不是必须的,你可以根据你的项目有其他的实现。</p><pre><code>//&nbsp;rtc&nbsp;object<br/>var&nbsp;rtc&nbsp;=&nbsp;{<br/>&nbsp;&nbsp;client:&nbsp;null,<br/>&nbsp;&nbsp;joined:&nbsp;false,<br/>&nbsp;&nbsp;published:&nbsp;false,<br/>&nbsp;&nbsp;localStream:&nbsp;null,<br/>&nbsp;&nbsp;remoteStreams:&nbsp;[],<br/>&nbsp;&nbsp;params:&nbsp;{}<br/>};<br/><br/>//&nbsp;Options&nbsp;for&nbsp;joining&nbsp;a&nbsp;channel<br/>var&nbsp;option&nbsp;=&nbsp;{<br/>&nbsp;&nbsp;appID:&nbsp;&quot;Your&nbsp;App&nbsp;ID&quot;,<br/>&nbsp;&nbsp;channel:&nbsp;&quot;Channel&nbsp;name&quot;,<br/>&nbsp;&nbsp;uid:&nbsp;null,<br/>&nbsp;&nbsp;token:&nbsp;&quot;Your&nbsp;token&quot;<br/>}<br/></code></pre><p>初始化客户端</p><p>加入频道前,我们需要先创建并初始化一个客户端对象。</p><pre><code>&nbsp;//&nbsp;Create&nbsp;a&nbsp;client<br/>&nbsp;rtc.client&nbsp;=&nbsp;AgoraRTC.createClient({mode:&nbsp;&quot;rtc&quot;,&nbsp;codec:&nbsp;&quot;h264&quot;});<br/><br/>&nbsp;//&nbsp;Initialize&nbsp;the&nbsp;client<br/>&nbsp;rtc.client.init(option.appID,&nbsp;function&nbsp;()&nbsp;{<br/>&nbsp;&nbsp;&nbsp;console.log(&quot;init&nbsp;success&quot;);<br/>&nbsp;&nbsp;&nbsp;},&nbsp;(err)&nbsp;=&gt;&nbsp;{<br/>&nbsp;&nbsp;&nbsp;console.error(err);<br/>&nbsp;});<br/></code></pre><p>在 AgoraRTC.createClient 方法中,需注意 mode 和 codec 这两个参数的设置:</p><ul><li>mode 用于设置频道模式。一对一或多人通话中,建议设为 “rtc” ,使用通信模式;互动直播中,建议设为 “live”,使用直播模式。</li><li>codec 用于设置浏览器使用的编解码格式。如果你需要使用 Safari 12.1 及之前版本,将该参数设为 “h264”;如果你需要在手机上使用 Agora Web SDK,请参考移动端使用 Web SDK。<br/>你需要在该步骤中填入项目的 App ID。请参考如下步骤在控制台创建 Agora 项目并获取 App ID。</li></ul><ol><li>登录控制台,点击左侧导航栏的项目管理图标 。</li><li>点击创建,按照屏幕提示设置项目名,选择一种鉴权机制,然后点击提交。</li><li>在项目管理页面,你可以获取该项目的 App ID。<br/>设置用户角色</li></ol><p>直播频道有两种用户角色:主播和观众,其中默认的角色为观众。设置频道模式为直播后,你可以在 App 中参考如下步骤设置用户角色:</p><ol><li>让用户选择自己的角色是主播(“host”)还是观众(“audience”)。</li><li>调用 setClientRole 方法,传入用户选择的角色。</li></ol><pre><code>//&nbsp;The&nbsp;value&nbsp;of&nbsp;role&nbsp;can&nbsp;be&nbsp;&quot;host&quot;&nbsp;or&nbsp;&quot;audience&quot;.<br/>rtc.client.setClientRole(role);&nbsp;<br/></code></pre><p>直播频道内的用户,只能看到主播的画面、听到主播的声音。加入频道后,如果你想切换用户角色,也可以调用 setClientRole 方法。</p><p>加入频道</p><p>在 Client.init 的 onSuccess 回调中调用 Client.join 加入频道。</p><pre><code>&nbsp;//&nbsp;Join&nbsp;a&nbsp;channel<br/>&nbsp;rtc.client.join(option.token&nbsp;?&nbsp;option.token&nbsp;:&nbsp;null,&nbsp;option.channel,&nbsp;option.uid&nbsp;?&nbsp;+option.uid&nbsp;:&nbsp;null,&nbsp;function&nbsp;(uid)&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(&quot;join&nbsp;channel:&nbsp;&quot;&nbsp;+&nbsp;option.channel&nbsp;+&nbsp;&quot;&nbsp;success,&nbsp;uid:&nbsp;&quot;&nbsp;+&nbsp;uid);<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rtc.params.uid&nbsp;=&nbsp;uid;<br/>&nbsp;&nbsp;&nbsp;},&nbsp;function(err)&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.error(&quot;client&nbsp;join&nbsp;failed&quot;,&nbsp;err)<br/>&nbsp;})<br/></code></pre><p>在 Client.join 中注意以下参数的设置:</p><ul><li>token: 该参数为可选。如果你的 Agora 项目开启了 App 证书,你需要在该参数中传入一个 Token,详见 使用 Token。</li><li>在测试环境,我们推荐使用控制台生成临时 Token,详见获取临时 Token。</li><li>在生产环境,我们推荐你在自己的服务端生成 Token,详见 生成 Token.</li><li>channel: 频道名,长度在 64 字节以内的字符串。</li><li>uid: 用户 ID,频道内每个用户的 UID 必须是唯一的。如果你将 uid 设为 null,Agora 会自动分配一个 UID 并在 onSuccess 回调中返回。<br/>更多的参数设置注意事项请参考 Client.join 接口中的参数描述。</li></ul><h3>发布本地流</h3><p>如果用户角色设置为主播,我们需要创建并发布本地流。</p><ol><li>在 Client.join 的 onSuccess 回调中调用 AgoraRTC.createStream 方法创建一个本地音视频流。<br/>在创建流时,通过设置 audio 和 video 参数来控制是否发布音频和视频。</li></ol><pre><code>//&nbsp;Create&nbsp;a&nbsp;local&nbsp;stream<br/>rtc.localStream&nbsp;=&nbsp;AgoraRTC.createStream({<br/>&nbsp;&nbsp;streamID:&nbsp;rtc.params.uid,<br/>&nbsp;&nbsp;audio:&nbsp;true,<br/>&nbsp;&nbsp;video:&nbsp;true,<br/>&nbsp;&nbsp;screen:&nbsp;false,<br/>})<br/>2.&nbsp;调用 &nbsp;Stream.init&nbsp;方法初始化创建的流。<br/>//&nbsp;Initialize&nbsp;the&nbsp;local&nbsp;stream<br/>rtc.localStream.init(function&nbsp;()&nbsp;{<br/>&nbsp;&nbsp;console.log(&quot;init&nbsp;local&nbsp;stream&nbsp;success&quot;);<br/>},&nbsp;function&nbsp;(err)&nbsp;{<br/>&nbsp;&nbsp;console.error(&quot;init&nbsp;local&nbsp;stream&nbsp;failed&nbsp;&quot;,&nbsp;err);<br/>})<br/></code></pre><p>在初始化流时,浏览器会跳出弹窗要求摄像头和麦克风权限,请确保授权。<br/>3. 在 Stream.init 的 onSuccess 回调中调用 Client.publish 方法,发布本地流。</p><pre><code>//&nbsp;Publish&nbsp;the&nbsp;local&nbsp;stream<br/>rtc.client.publish(rtc.localStream,&nbsp;function&nbsp;(err)&nbsp;{<br/>&nbsp;&nbsp;console.log(&quot;publish&nbsp;failed&quot;);<br/>&nbsp;&nbsp;console.error(err);<br/>})<br/></code></pre><h3>订阅远端流</h3><p>当远端流加入频道时,会触发 stream-added 事件,我们需要通过 Client.on 监听该事件并在回调中订阅新加入的远端流。</p><p>建议在创建客户端对象之后立即监听事件。</p><ol><li>监听 “stream-added” 事件,当有远端流加入时订阅该流。</li></ol><pre><code>rtc.client.on(&quot;stream-added&quot;,&nbsp;function&nbsp;(evt)&nbsp;{&nbsp;&nbsp;<br/>&nbsp;&nbsp;var&nbsp;remoteStream&nbsp;=&nbsp;evt.stream;<br/>&nbsp;&nbsp;var&nbsp;id&nbsp;=&nbsp;remoteStream.getId();<br/>&nbsp;&nbsp;if&nbsp;(id&nbsp;!==&nbsp;rtc.params.uid)&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;rtc.client.subscribe(remoteStream,&nbsp;function&nbsp;(err)&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;console.log(&quot;stream&nbsp;subscribe&nbsp;failed&quot;,&nbsp;err);<br/>&nbsp;&nbsp;&nbsp;&nbsp;})<br/>&nbsp;&nbsp;}<br/>&nbsp;&nbsp;console.log('stream-added&nbsp;remote-uid:&nbsp;',&nbsp;id);<br/>});<br/></code></pre><ol start="2"><li>监听 “stream-subscribed” 事件,订阅成功后播放远端流。</li></ol><pre><code>rtc.client.on(&quot;stream-subscribed&quot;,&nbsp;function&nbsp;(evt)&nbsp;{<br/>&nbsp;&nbsp;var&nbsp;remoteStream&nbsp;=&nbsp;evt.stream;<br/>&nbsp;&nbsp;var&nbsp;id&nbsp;=&nbsp;remoteStream.getId();<br/>&nbsp;&nbsp;//&nbsp;Add&nbsp;a&nbsp;view&nbsp;for&nbsp;the&nbsp;remote&nbsp;stream.<br/>&nbsp;&nbsp;addView(id);<br/>&nbsp;&nbsp;//&nbsp;Play&nbsp;the&nbsp;remote&nbsp;stream.<br/>&nbsp;&nbsp;remoteStream.play(&quot;remote_video_&quot;&nbsp;+&nbsp;id);<br/>&nbsp;&nbsp;console.log('stream-subscribed&nbsp;remote-uid:&nbsp;',&nbsp;id);<br/>})<br/></code></pre><p>受浏览器策略影响,在 Chrome 70+ 和 Safari 浏览器上,Stream.play 方法必须由用户手势触发,详情请在声网文档中心搜索、参考 Autoplay Policy Changes。<br/>3. 监听 “stream-removed” 事件,当远端流被移除时(例如远端用户调用了 Stream.unpublish), 停止播放该流并移除它的画面。</p><pre><code>rtc.client.on(&quot;stream-removed&quot;,&nbsp;function&nbsp;(evt)&nbsp;{<br/>&nbsp;&nbsp;var&nbsp;remoteStream&nbsp;=&nbsp;evt.stream;<br/>&nbsp;&nbsp;var&nbsp;id&nbsp;=&nbsp;remoteStream.getId();<br/>&nbsp;&nbsp;//&nbsp;Stop&nbsp;playing&nbsp;the&nbsp;remote&nbsp;stream.<br/>&nbsp;&nbsp;remoteStream.stop(&quot;remote_video_&quot;&nbsp;+&nbsp;id);<br/>&nbsp;&nbsp;//&nbsp;Remove&nbsp;the&nbsp;view&nbsp;of&nbsp;the&nbsp;remote&nbsp;stream.&nbsp;<br/>&nbsp;&nbsp;removeView(id);<br/>&nbsp;&nbsp;console.log('stream-removed&nbsp;remote-uid:&nbsp;',&nbsp;id);<br/>})<br/></code></pre><p>你需要自己实现 addView 和 removeView 的功能,可以参考以下示例代码。</p><pre><code>function&nbsp;addView&nbsp;(id,&nbsp;show)&nbsp;{<br/>&nbsp;&nbsp;if&nbsp;(!(&quot;#&quot;&nbsp;+&nbsp;id)[0])&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;(&quot;&lt;div/&gt;&quot;,&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id:&nbsp;&quot;remote_video_panel_&quot;&nbsp;+&nbsp;id,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class:&nbsp;&quot;video-view&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;}).appendTo(&quot;#video&quot;);<br/>&nbsp;&nbsp;&nbsp;&nbsp;(&quot;&lt;div/&gt;&quot;,&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id:&nbsp;&quot;remote_video_&quot;&nbsp;+&nbsp;id,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class:&nbsp;&quot;video-placeholder&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;}).appendTo(&quot;#remote_video_panel_&quot;&nbsp;+&nbsp;id);<br/>&nbsp;&nbsp;&nbsp;&nbsp;(&quot;&lt;div/&gt;&quot;,&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id:&nbsp;&quot;remote_video_info_&quot;&nbsp;+&nbsp;id,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class:&nbsp;&quot;video-profile&nbsp;&quot;&nbsp;+&nbsp;(show&nbsp;?&nbsp;&quot;&quot;&nbsp;:&nbsp;&nbsp;&quot;hide&quot;),<br/>&nbsp;&nbsp;&nbsp;&nbsp;}).appendTo(&quot;#remote_video_panel_&quot;&nbsp;+&nbsp;id);<br/>&nbsp;&nbsp;&nbsp;&nbsp;(&quot;&lt;div/&gt;&quot;,&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;id:&nbsp;&quot;video_autoplay_&quot;+&nbsp;id,<br/>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;class:&nbsp;&quot;autoplay-fallback&nbsp;hide&quot;,<br/>&nbsp;&nbsp;&nbsp;&nbsp;}).appendTo(&quot;#remote_video_panel_&quot;&nbsp;+&nbsp;id);<br/>&nbsp;&nbsp;}<br/>}<br/>function&nbsp;removeView&nbsp;(id)&nbsp;{<br/>&nbsp;&nbsp;if&nbsp;((&quot;#remote_video_panel_&quot;&nbsp;+&nbsp;id)[0])&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;$(&quot;#remote_video_panel_&quot;+id).remove();<br/>&nbsp;&nbsp;}<br/>}<br/></code></pre><h3>离开频道</h3><p>调用 Client.leave 方法离开频道。</p><pre><code>//&nbsp;Leave&nbsp;the&nbsp;channel<br/>rtc.client.leave(function&nbsp;()&nbsp;{<br/>&nbsp;&nbsp;//&nbsp;Stop&nbsp;playing&nbsp;the&nbsp;local&nbsp;stream<br/>&nbsp;&nbsp;rtc.localStream.stop();<br/>&nbsp;&nbsp;//&nbsp;Close&nbsp;the&nbsp;local&nbsp;stream<br/>&nbsp;&nbsp;rtc.localStream.close();<br/>&nbsp;&nbsp;//&nbsp;Stop&nbsp;playing&nbsp;the&nbsp;remote&nbsp;streams&nbsp;and&nbsp;remove&nbsp;the&nbsp;views<br/>&nbsp;&nbsp;while&nbsp;(rtc.remoteStreams.length&nbsp;&gt;&nbsp;0)&nbsp;{<br/>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;stream&nbsp;=&nbsp;rtc.remoteStreams.shift();<br/>&nbsp;&nbsp;&nbsp;&nbsp;var&nbsp;id&nbsp;=&nbsp;stream.getId();<br/>&nbsp;&nbsp;&nbsp;&nbsp;stream.stop();<br/>&nbsp;&nbsp;&nbsp;&nbsp;removeView(id);<br/>&nbsp;&nbsp;}<br/>&nbsp;&nbsp;console.log(&quot;client&nbsp;leaves&nbsp;channel&nbsp;success&quot;);<br/>},&nbsp;function&nbsp;(err)&nbsp;{<br/>&nbsp;&nbsp;console.log(&quot;channel&nbsp;leave&nbsp;failed&quot;);<br/>&nbsp;&nbsp;console.error(err);<br/>})<br/><br/></code></pre><h3>运行你的 app</h3><p>我们建议在本地 Web 服务器上测试你的 app。这里我们用 npm 的 live-server 设置一个本地服务器。</p><p>在本地服务器(localhost)运行 web app 仅作为测试用途。部署生产环境时,请确保使用 HTTPS 协议。</p><ol><li>安装 live-server。</li></ol><pre><code>npm&nbsp;i&nbsp;live-server&nbsp;-g<br/></code></pre><ol start="2"><li><p>在命令行中进入你的项目所在的目录。</p></li><li><p>运行 app。</p></li></ol><pre><code>live-server&nbsp;.<br/></code></pre><p>现在你的浏览器应该会自动打开你的 web app 页面。</p><ol start="4"><li><p>输入频道名,选择用户角色,点击 JOIN 开始通话。<br/>你可能需要给浏览器摄像头和麦克风权限。如果在创建本地流时打开了视频且选择主播角色,你现在应该可以看到自己的视频画面。</p></li><li><p>在浏览器中打开另一个页面,输入相同的 URL 地址。点击 JOIN 按钮。现在你应该可以看到两个视频画面。</p></li></ol><p>如果页面没有正常工作,可以打开浏览器的控制台查看错误信息进行排查。常见的错误信息包括:</p><ul><li><p>INVALID_VENDOR_KEY:App ID 错误,检查你填写的 App ID。</p></li><li><p>ERR_DYNAMIC_USE_STATIC_KE:你的 Agora 项目启用了 App 证书,需要在加入频道时填写 Token。</p></li><li><p>Media access:NotFoundError:检查你的摄像头和麦克风是否正常工作。</p></li><li><p>MEDIA_NOT_SUPPORT:请使用 HTTPS 协议 或者 localhost。</p></li></ul><p><strong>本文转载自 声网 Agora 公众号。</strong></p><p><strong>原文链接:</strong><a href="https://mp.weixin.qq.com/s/bK6bwE4rPXGFNx7sfAftrA">https://mp.weixin.qq.com/s/bK6bwE4rPXGFNx7sfAftrA</a></p>


2020-02-26 15:50917

评论

发布
暂无评论
发现更多内容

MySQL如何选择主键

架构精进之路

MySQL 3月日更

C++线程池ThreadPoolExecutor实现原理

Linux服务器开发

c++ 后端 线程池 Linux服务器开发 Linux后台开发

配置引起事故复盘

风翱

3月日更

基于SpringCloud,支持安卓、IOS、包含前后端等等完整网约车项目

Java架构追梦

Java 架构 面试 SpringCloud 网约车项目

《Redis 核心技术与实战》学习笔记 05

escray

redis 学习 28天写作 3月日更 Redis 核心技术与实战

十步输出设计文档

鲁米

设计实践

我在阿里实习做开源

apache/dubbo-go

微服务 程序人生 云原生 dubbo dubbogo

一口气面了腾讯两个部门!

我是程序员小贱

3月日更

一些人的某些目标

sadhu

生涯规划 职业规划 个人提升

好想做个女孩子,编程第一步,女装身上穿

GitHub指北

《码农歌》

臧萌

加班

TCP 三次握手与四次挥手

insight

TCP 3月日更

苹果笔记本充不进电的解决方案

石云升

电脑故障 28天写作 3月日更

GitOps | 一种云原生的持续交付模型

xcbeyond

CI/CD gitops 3月日更

Wireshark数据包分析学习笔记Day17

穿过生命散发芬芳

Wireshark 数据包分析 3月日更

避免失控:谈谈人与人交往中的恶

boshi

职场 心理 七日更

正则表达式的使用与匹配原理解析

Guanngxu

正则表达式

寻找被遗忘的勇气(二十)

Changing Lin

3月日更

2021年Java春招高级面试指南(1到5年Java面试者必备)

比伯

Java 编程 架构 面试 程序人生

打通Jira与钉钉和企业微信不再难

跟YY哥学Jira

钉钉 Jira 企业微信 automation

蚂蚁二面:MQ消费端遇到瓶颈除了横向扩容外还有其他解决办法?

中间件兴趣圈

面试 RocketMQ 消息中间件

所谓生产力

ES_her0

3月日更

源码分析-Netty: 高性能之道

程序员架构进阶

Netty RPC 源码剖析 28天写作 3月日更

分享18个常用的ECMAScript 6代码片段

devpoint

reduce URL参数解析 Form表单数据解析

【LeetCode】逆波兰表达式求值Java题解

Albert

算法 LeetCode 28天写作 3月日更

这些面试题你会吗?6年菜鸟开发面试字节跳动安卓研发岗,复习指南

欢喜学安卓

android 程序员 面试 移动开发

初识Golang之调用方法

Kylin

3月日更 Go 语言

远程协助软件向日葵分析

lenka

3月日更

这份1307页Android面试全套真题解析,源码+原理+手写框架

欢喜学安卓

android 程序员 面试 移动开发

数据库备份真的很重要!很重要!很重要!

xiezhr

oracle sql MySQL 运维 数据备份

还有高仿项目吗

GitHub指北

基于 Agora SDK 实现 Web 端的多人视频互动_行业深度_声网_InfoQ精选文章