├── AutoPlay.md
├── Manual.md
├── README.md
├── examples
├── angular
│ ├── .editorconfig
│ ├── .gitignore
│ ├── README.md
│ ├── angular.json
│ ├── browserslist
│ ├── e2e
│ │ ├── protractor.conf.js
│ │ ├── src
│ │ │ ├── app.e2e-spec.ts
│ │ │ └── app.po.ts
│ │ └── tsconfig.json
│ ├── karma.conf.js
│ ├── package.json
│ ├── src
│ │ ├── App.css
│ │ ├── App.ts
│ │ ├── assets
│ │ │ └── .gitkeep
│ │ ├── components
│ │ │ └── stream-info
│ │ │ │ ├── index.html
│ │ │ │ └── index.ts
│ │ ├── config
│ │ │ └── README.md
│ │ ├── environments
│ │ │ ├── environment.prod.ts
│ │ │ └── environment.ts
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── main.ts
│ │ ├── pages
│ │ │ └── room
│ │ │ │ ├── index.css
│ │ │ │ ├── index.html
│ │ │ │ └── index.ts
│ │ ├── polyfills.ts
│ │ ├── styles.css
│ │ └── test.ts
│ ├── tsconfig.app.json
│ ├── tsconfig.json
│ ├── tsconfig.spec.json
│ └── tslint.json
├── pureJS
│ ├── .gitignore
│ ├── README.md
│ ├── css
│ │ ├── index.css
│ │ └── mediaPlayer.css
│ ├── index.html
│ ├── js
│ │ ├── README.md
│ │ └── index.js
│ ├── lib
│ │ └── index.js
│ └── package.json
├── react-ts
│ ├── .gitignore
│ ├── README.md
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ └── robots.txt
│ ├── src
│ │ ├── App.css
│ │ ├── App.test.tsx
│ │ ├── App.tsx
│ │ ├── config
│ │ │ └── README.md
│ │ ├── index.css
│ │ ├── index.tsx
│ │ ├── logo.svg
│ │ ├── react-app-env.d.ts
│ │ ├── serviceWorker.ts
│ │ └── setupTests.ts
│ └── tsconfig.json
├── react
│ ├── .gitignore
│ ├── README.md
│ ├── config-overrides.js
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ ├── index.html
│ │ ├── logo192.png
│ │ ├── logo512.png
│ │ ├── manifest.json
│ │ └── robots.txt
│ └── src
│ │ ├── App.css
│ │ ├── App.js
│ │ ├── App.test.js
│ │ ├── components
│ │ └── StreamInfo
│ │ │ └── index.jsx
│ │ ├── config
│ │ └── README.md
│ │ ├── index.js
│ │ ├── logo.svg
│ │ ├── pages
│ │ └── room
│ │ │ ├── index.css
│ │ │ └── index.jsx
│ │ └── setupTests.js
└── vue
│ ├── .browserslistrc
│ ├── .editorconfig
│ ├── .eslintignore
│ ├── .eslintrc.js
│ ├── .gitignore
│ ├── README.md
│ ├── babel.config.js
│ ├── package.json
│ ├── public
│ ├── favicon.ico
│ └── index.html
│ └── src
│ ├── App.vue
│ ├── assets
│ └── logo.png
│ ├── components
│ └── StreamInfo.vue
│ ├── config
│ └── README.md
│ ├── main.js
│ └── pages
│ └── Room.vue
├── lib
├── index.d.ts
└── index.js
└── package.json
/AutoPlay.md:
--------------------------------------------------------------------------------
1 | # 关于浏览器的自动播放问题的说明及处理
2 |
3 | ---
4 |
5 | ## 问题说明
6 |
7 | 出于用户体验考虑,为了防止网页在用户非自愿的情况下主动播放声音,浏览器对 audio 或 video 标签的自动播放(autoplay)功能做了限制:需要在用户交互操作之前不允许有声音的媒体播放。
8 |
9 |
10 | ## 具体表现
11 |
12 | 不同浏览器告警或报错信息不同,基本可以归纳为两类:
13 |
14 | 1. 调用 audio 或 video 的 play 方法时,会报类似于 `DOMException: play() failed because the user didn’t interact with the document first.` 的错误信息。
15 |
16 | 2. 开启 audio 或 video 的 autoplay 时,即标签上填有 'autoplay' 属性,如 ``,浏览器控制台会有类似于 `The AudioContext was not allowed to start` 的告警信息。此时,如果页面中使用的是 video 标签,一般会处于 `白屏` 状态。
17 |
18 |
19 | ## 解决方法
20 |
21 | 1. 调用 `play` 方法播放失败时,绕开 autoplay 的限制
22 |
23 | 此时可引导用户点击页面上的某个位置,譬如模态框上的确定按钮,再在该 `click` 事件的监听函数里调用 `resume` 方法。示例代码:
24 |
25 | ```js
26 | client.play({
27 | streamId: 'xxx',
28 | container: 'xxx',
29 | }, (err) => {
30 | if (err) {
31 | console.log('播放失败', err);
32 | client.resume('xxx', (err) => {
33 | if (err) {
34 | console.log('恢复播放失败', err);
35 | }
36 | });
37 | }
38 | });
39 | ```
40 |
41 | > 注:在调用 URTC sdk 的 `play` 方法失败时,会自动显示音视频播放元素的控制面板,面板里会有播放按钮等操作工具,您也可以不调用 `resume` 方法,仅提示用户点击音视频播放元素的控制面板上的播放按钮进行播放。
42 |
43 | 2. 直接绕开 autoplay 的限制
44 |
45 | 由于浏览器限制的是声音的自动播放,在以静音状态进行播放时,是不受 autoplay 的限制的,此时可在调用 `play` 方法时,传的参数中携带 mute: true,并在页面中提示用户,由用户来决定是否与页面进行交互并调用 `resume` 方法来恢复播放声音。示例代码:
46 |
47 | ```html
48 |
49 | ```
50 |
51 | ```js
52 | let unmuteBtn = document.querySelector('#unmuteBtn');
53 | client.play({
54 | streamId: 'xxx',
55 | container: 'xxx,
56 | mute: true
57 | }, (err) => {
58 | if (err) {
59 | console.log('播放失败', err);
60 | }
61 | });
62 | unmuteBtn.onclick = function() {
63 | client.resume('xxx', (err) => {
64 | if (err) {
65 | console.log('恢复播放失败', err);
66 | }
67 | });
68 | }
69 | ```
70 |
71 | 3. 提前检测浏览器是否能自动播放
72 |
73 | 在用 URTC 创建 client 前,可使用 [can-autoplay](https://www.npmjs.com/package/can-autoplay) 第三方库进行检测,若不支持,可引导用户点击页面上的某个位置(譬如模态框上的确定按钮)来触发用户与页面的交互(即解锁 `the user didn’t interact with the document first`),然后再用 URTC 创建 client 并 joinRoom。示例代码:
74 |
75 | ```js
76 | canAutoplay.video().then(res => {
77 | const { result } = res;
78 | if (!result) {
79 | // 弹出模态框提示用户点击
80 | }
81 | });
82 | ```
83 |
84 | FAQ
85 |
86 | Q: 为什么有时可以播放,有时不行?
87 | A: 1. 部分浏览器会有自动播放的限制(如 Chrome 70 及以上和 Safari 浏览器)。2.因为页面不是 100% 被 Autoplay 限制,随着用户使用这个页面的次数增加,部分浏览器会把这个页面加入自己的 Autoplay 白名单列表中。3. 在推+拉流时,若客户端先推流(读取麦克风设备),再拉流,可以绕开 autoplay 的限制。
88 |
89 | Q: 为什么别的产品可以自动播放,URTC 却不可以?
90 | A: 排查问题时可先确定客户端是不是先推流再拉流(参考上面的问题)。如果是仅拉流,由于这是浏览器级别的限制,所有同类产品都会受到这个 autoplay 限制的影响,解决办法无外乎上面几种。
--------------------------------------------------------------------------------
/Manual.md:
--------------------------------------------------------------------------------
1 | # SDK 使用说明 - 简单步骤
2 |
3 | ## 1. 创建一个 URTC Client
4 |
5 | 有两种方式:
6 |
7 | - 使用 npm 安装,并将 sdk 使用 ES6 语法作为模块引入,具体步骤:
8 |
9 | 1)使用 [npm](https://www.npmjs.com/) 或 [Yarn](https://yarnpkg.com/) 安装 sdk:
10 |
11 | ```
12 | npm install --save urtc-sdk
13 | ```
14 |
15 | 或
16 |
17 | ```
18 | yarn add urtc-sdk
19 | ```
20 |
21 | 2)项目中引入并创建 client
22 |
23 | ```
24 | import { Client } from 'urtc-sdk';
25 |
26 | const client = new Client(appId, token); // 默认为连麦模式(小班课),若为直播模式(大班课)时,需要传入第三个参数 { type: 'live' },更多配置见 sdk API 说明
27 | ```
28 |
29 | - 直接在页面中用 script 标签将 sdk 引入,此时会有全局对象 UCloudRTC,具体步骤:
30 |
31 | 1)直接将 sdk 中 lib 目录下的 index.js 使用 script 标签引入
32 |
33 | ```
34 |
34 |
35 |
36 |
37 |