写点什么

基于 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:501342

评论

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

智能量化对冲搬砖套利交易软件APP系统开发

系统开发

Java 程序经验小结:剖析@SuppressWarinings注解

后台技术汇

28天写作

生产者与消费者模式,数组阻塞队列(ArrayBlockingQueue)

李尚智

Java 学习 架构 并发编程

Volcano架构设计与原理介绍

华为云原生团队

大数据 AI 云原生 高性能 批量计算

物流快递公司APP架构设计

jorden wang

架构师训练营W13作业

Geek_f06ede

「产品经理训练营」第一章作业

Sòrγy_じò ぴé

产品经理训练营

在数据分析、挖掘方面,有哪些ETL工具值得推荐?

敏捷调度TASKCTL

大数据 kettle 海豚调度 批量任务 ETL

面试阿里Java岗,技术总监真正关心的核心能力是什么?

Java架构追梦

Java 编程 架构

Soul 网关源码阅读(一) 概览

Java 源码阅读 网关

一文解析DDD中台和微服务设计

欧创新

中台 微服务 领域驱动设计 DDD

当音乐学博士搞起编程...

程序猿DD

Spring Frame

DevSecOps安全检查清单

啸天

安全 DevSecOps 应用安全

区块链十年与传统金融的变化

CECBC

区块链 金融

为什么我认为 Deno 是一个迈向错误方向的 JavaScript 运行时?

hylerrix

typescript rust nodejs deno V8

敏捷里为何倡导固定迭代周期?

万事ONES

敏捷开发 研发管理 迭代

特斯拉自建ERP的背后

明道云

矿机挖矿APP系统模式开发平台

v16629866266

Soul 网关源码阅读(二)代码初步运行

Java 源码阅读 网关

Soul 网关源码阅读(三)请求处理概览

Java 源码阅读 网关

Soul 网关源码阅读(四)Dubbo请求概览

Java 源码阅读 网关

一文带你探究Sentinel的独特初始化

华为云开发者联盟

redis sentinel 框架

“反垄断”来袭,对产业区块链有什么启发

CECBC

市场垄断

区块链科普系列:区块链是什么?

CECBC

区块链

解读容器的 2020:寻找云原生的下一站

阿里巴巴云原生

Docker 云计算 Serverless 容器 云原生

初识ClickHouse——安装与入门

Simon

Clickhouse

iOS性能优化 — 五、App启动优化

iOSer

ios 性能优化 性能分析

从CPU到XPU进化,英特尔对业界放了什么大招?

E科讯

用AI「驯服」人类幼崽,手头有娃的可以试试

博文视点Broadview

人工智能 联邦学习 强化学习 集成学习 技术宅

不同公司产品经理岗位对比

LouisN

即构小程序直播组件集成教程

ZEGO即构

基于 Agora SDK 实现 Web 端的多人视频互动_行业深度_RTE开发者社区_InfoQ精选文章