Browse Source

[purejs demo] - 和 react 统一

kevin.song 6 years ago
parent
commit
812a74a77c

+ 3 - 0
examples/pureJS/.gitignore

@@ -15,3 +15,6 @@ yarn-error.log*
 
 yarn.lock
 package-lock.json
+
+# config
+js/config.js

+ 23 - 0
examples/pureJS/README.md

@@ -0,0 +1,23 @@
+# URTC-demo(纯 JS 版本)
+
+## 运行步骤
+
+1. 添加配置
+
+详见 js 目录下的 README
+
+2. 安装 npm 依赖包
+
+```
+npm install
+```
+
+3. 执行运行命令
+
+```
+npm start
+```
+
+4. 打开页面
+
+浏览器打开 http://localhost:3000

+ 40 - 0
examples/pureJS/css/index.css

@@ -0,0 +1,40 @@
+body {
+  margin: 0;
+  font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', 'Roboto', 'Oxygen',
+    'Ubuntu', 'Cantarell', 'Fira Sans', 'Droid Sans', 'Helvetica Neue',
+    sans-serif;
+  -webkit-font-smoothing: antialiased;
+  -moz-osx-font-smoothing: grayscale;
+}
+
+.App {
+  text-align: center;
+}
+
+.room {
+  max-width: 640px;
+  margin: 0 auto;
+}
+
+.room .local-stream,
+.room .remote-stream {
+  text-align: left;
+}
+
+.room button {
+  padding: 8px 0;
+  display: inline-block;
+  width: 100%;
+  border-radius: 6px;
+  cursor: pointer;
+  text-align: center;
+  ;
+}
+
+.room input:visited,
+.room button:focus,
+.room button:visited,
+.room button:hover,
+.room button:active {
+  outline: none;
+}

+ 13 - 0
examples/pureJS/css/mediaPlayer.css

@@ -0,0 +1,13 @@
+.media-player {
+  display: inline-block;
+  margin: 2px;
+  width: 300px;
+  text-align: left;
+  white-space: nowrap;
+  cursor: pointer;
+}
+
+.media-player video {
+  width: 100%;
+  height: 100%;
+}

+ 25 - 94
examples/pureJS/index.html

@@ -1,104 +1,35 @@
+<!DOCTYPE html>
 <html>
   <head>
     <meta charset="utf-8">
     <title> URTC DEMO PureJS </title>
-    <style type="text/css">
-      video {
-        margin: 6px;
-        width: 300px;
-        height: 200px;
-      }
-    </style>
+    <link type="text/css" rel="stylesheet" href="https://unpkg.com/browse/normalize.css@8.0.1/normalize.css"/>
+    <link type="text/css" rel="stylesheet" href="css/index.css"/>
+    <link type="text/css" rel="stylesheet" href="css/mediaPlayer.css"/>
   </head>
   <body>
-    <div>房间号:<span id="roomId"></span></div>
-    <div>当前用户ID:<span id="userId"></span></div>
-    <br/>
-    <div>本地音视频</div>
-    <div>
-      <video id="pusher" autoplay playsinline></video>
+    <div class="App">
+      <div class="room">
+        <label>房间号:<span id="roomId"></span>(<span id="roomStatus">未加入</span>)</label>
+        <p>当前选中的流:<span id="selectedStream">未选择</span></p>
+        <h3>本地(发布)流</h3>
+        <div id="pushers"></div>
+        <h3>远端(订阅)流</h3>
+        <div id="pullers"></div>
+        <h3>操作</h3>
+        <button id="joinRoomBtn">加入房间</button>
+        <button id="publishBtn">发布</button>
+        <button id="publishScreenBtn">屏幕共享</button>
+        <button id="unPublishBtn">取消发布/屏幕共享</button>
+        <button id="subscribeBtn">订阅</button>
+        <button id="unSubscribeBtn">取消订阅</button>
+        <button id="leaveRoomBtn">离开房间</button>
+      </div>
+      <br/>
+      <a href="https://github.com/ucloud/urtc-sdk-web" target="_blank">API 文档请看这里</a>
     </div>
-    <br/>
-    <div>远端音视频</div>
-    <div id="pullers"></div>
-    <br/>
-    <a href="https://github.com/ucloud/urtc-sdk-web" target="_blank">API 文档请看这里</a>
     <script type="text/javascript" src="https://ucloud.github.io/urtc-sdk-web/lib/index.js"></script>
-    <script>
-      window.onload = function() {
-        const pusherElem = document.querySelector('#pusher');
-        const pullersElem = document.querySelector('#pullers');
-        const roomElem = document.querySelector('#roomId');
-        const userElem = document.querySelector('#userId');
-
-        const appId = '';   // "urtc-xxxxxx";
-        const appKey = '';  // "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
-        const roomId = "xxxx";  // "xxxx"
-        const userId = Math.floor(Math.random() * 1000000).toString();
-        if (!appId || !appKey) {
-          alert('请先设置 AppId 和 AppKey');
-          return;
-        }
-        if (!roomId) {
-          alert('请先设置roomId');
-          return;
-        }
-
-        roomElem.innerHTML = roomId;
-        userElem.innerHTML = userId;
-
-        console.log('UCloudRTC Version: ', UCloudRTC.version);
-
-        const token = UCloudRTC.generateToken(appId, appKey, roomId, userId);
-        const client = new UCloudRTC.Client(appId, token, {type: 'rtc', role: 'push-and-pull'});
-
-        // 监听 publish 成功的事件
-        client.on('stream-published', function(stream) {
-          console.log('成功发布流 ', stream);
-          pusherElem.srcObject = stream.mediaStream;
-        });
-        // 监听 subscribe 成功的事件
-        client.on('stream-subscribed', function(stream) {
-          console.log('成功订阅流 ', stream);
-          const pullerElem = document.createElement('video')
-          pullerElem.id = stream.sid;
-          pullerElem.autoplay = true;
-          pullerElem.playsinline = true;
-          pullerElem.srcObject = stream.mediaStream;
-          pullersElem.append(pullerElem);
-        });
-        // 监听有远端流加入的事件
-        client.on('stream-added', function(stream) {
-          // 当有新的远端流加入后,就订阅该流
-          client.subscribe(stream.sid, function(s) {
-            console.log(`已订阅用户${stream.uid}的流${stream.sid} `, s);
-          }, function(e) {
-            console.log(`订阅用户${stream.uid}的流${stream.sid}失败 `, e);
-          });
-        });
-        client.on('stream-removed', function(stream) {
-          const pullerElem = document.querySelector('#' + stream.sid);
-          pullerElem.srcObject = null;
-          pullersElem.removeChild(pullerElem);
-        });
-
-        // 加入房间
-        client.joinRoom(roomId, userId, function() {
-          console.log('加入房间成功');
-
-          // 加入房间成功后,就发布本地流
-          client.publish(function(e) {
-            console.log(`发布流失败 `, e);
-          });
-        }, function(e) {
-          console.log('加入房间失败 ', e);
-        });
-
-        window.onunload = function () {
-          // 离开页面前,先离开房间
-          client.leaveRoom();
-        }
-      }
-    </script>
+    <script type="text/javascript" src="js/config.js"></script>
+    <script type="text/javascript" src="js/index.js"></script>
   </body>
 </html>

+ 13 - 0
examples/pureJS/js/README.md

@@ -0,0 +1,13 @@
+本目录中需要创建 config.js 文件,并配置 AppId 和 AppKey,示例代码:
+
+```
+window.config = {
+  AppId: 'urtc-xxxxxxxx',
+  AppKey: 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
+}
+```
+
+> 注:
+> 
+> 1. AppId 和 AppKey 可从 URTC 产品中获取
+> 2. AppKey 不可暴露于公网,建议生产环境时,由后端进行保存并由前端调 API 获取

+ 338 - 0
examples/pureJS/js/index.js

@@ -0,0 +1,338 @@
+window.onload = function () {
+  const {
+    AppId,
+    AppKey
+  } = window.config || {};
+
+  // 此处使用固定的房间号的随机的用户ID,请自行替换
+  const RoomId = "ssss02";
+  const UserId = Math.floor(Math.random() * 1000000).toString();
+
+  if (!AppId || !AppKey) {
+    alert('请先设置 AppId 和 AppKey');
+    return;
+  }
+  if (!RoomId) {
+    alert('请先设置 RoomId');
+    return;
+  }
+
+  console.log('UCloudRTC sdk version: ', UCloudRTC.version);
+
+  // 用于维护应用内的状态
+  const App = {
+    state: {
+      roomId: RoomId,
+      userId: UserId,
+      isJoinedRoom: false,
+      selectedStream: null,
+      localStreams: [],
+      remoteStreams: []
+    },
+    client: null,
+    setState: function (key, value) {
+      const keys = Object.keys(this.state);
+      if (keys.includes(key)) {
+        this.state[key] = value;
+      }
+      switch (key) {
+        case 'roomId':
+          this.renderRoomId();
+          break;
+        case 'isJoinedRoom':
+          this.renderRoomStatus();
+          break;
+        case 'selectedStream':
+          this.renderSelectedStream();
+          break;
+        case 'localStream-add':
+          this.loadStream(value, 'pusher');
+          break;
+        case 'localStream-remove':
+          this.unloadStream(value, 'pusher');
+          break;
+        case 'remoteStream-add':
+          this.loadStream(value, 'puller');
+          break;
+        case 'remoteStream-remove':
+          this.unloadStream(value, 'puller');
+          break;
+        case 'remoteStream-update':
+          this.rerenderStream(value);
+          break;
+        default:
+      }
+    },
+    renderRoomId: function () {
+      const { roomId } = this.state;
+      const roomElem = document.querySelector('#roomId');
+      roomElem.innerHTML = roomId;
+    },
+    renderRoomStatus: function () {
+      const { isJoinedRoom } = this.state;
+      const roomStatusElem = document.querySelector('#roomStatus');
+      if (isJoinedRoom) {
+        roomStatusElem.innerHTML = "已加入";
+      } else {
+        roomStatusElem.innerHTML = "未加入";
+      }
+    },
+    renderSelectedStream: function () {
+      const { selectedStream } = this.state;
+      const selectedStreamElem = document.querySelector('#selectedStream');
+      if (selectedStream) {
+        selectedStreamElem.innerHTML = selectedStream.sid;
+      } else {
+        selectedStreamElem.innerHTML = "未选择";
+      }
+    },
+    loadStream: function (stream, type) {
+      let parent;
+      let isPuller;
+      switch (type) {
+        case 'pusher':
+          parent = document.querySelector('#pushers');
+          break;
+        case 'puller':
+          parent = document.querySelector('#pullers');
+          isPuller = true;
+          break;
+        default:
+          return;
+      }
+      const player = document.createElement('div');
+      player.className = 'media-player';
+      player.id = stream.sid;
+      const uIDElem = document.createElement('div');
+      uIDElem.innerHTML = `用户ID:${stream.uid}`;
+      uIDElem.style = 'overflow: hidden; text-overflow: ellipsis;';
+      const sIDElem = document.createElement('div');
+      sIDElem.innerHTML = `流ID:${stream.sid}`;
+      sIDElem.style = 'overflow: hidden; text-overflow: ellipsis;';
+      player.append(uIDElem);
+      player.append(sIDElem);
+      if (isPuller) {
+        const pElem = document.createElement('p');
+        pElem.innerHTML = 'unsubscribe';
+        player.append(pElem);
+      } else {
+        const videoElem = document.createElement('video');
+        videoElem.autoplay = true;
+        videoElem.playsinline = true;
+        videoElem.srcObject = stream.mediaStream;
+        player.append(videoElem);
+      }
+      player.addEventListener('click', function() {
+        this.handleSelectStream(stream);
+      }.bind(this));
+      parent.append(player);
+    },
+    unloadStream: function (stream, type) {
+      let parent;
+      switch (type) {
+        case 'pusher':
+          parent = document.querySelector('#pushers');
+          break;
+        case 'puller':
+          parent = document.querySelector('#pullers');
+          break;
+        default:
+          return;
+      }
+      const player = document.querySelector('#' + stream.sid);
+      parent.removeChild(player);
+    },
+    rerenderStream: function (stream) {
+      const player = document.querySelector('#' + stream.sid);
+      if (stream.mediaStream) {
+        const videoElem = document.createElement('video');
+        videoElem.autoplay = true;
+        videoElem.playsinline = true;
+        videoElem.srcObject = stream.mediaStream;
+        const pElem = player.querySelector('p');
+        player.removeChild(pElem);
+        player.appendChild(videoElem);
+      } else {
+        const videoElem = player.querySelector('video');
+        const pElem = document.createElement('p');
+        pElem.innerHTML = 'unsubscribe';
+        player.removeChild(videoElem);
+        player.appendChild(pElem);
+      }
+    },
+    init: function () {
+      const token = UCloudRTC.generateToken(AppId, AppKey, RoomId, UserId);
+      this.client = new UCloudRTC.Client(AppId, token);
+
+      // 监听 publish 成功的事件
+      this.client.on('stream-published', (localStream) => {
+        console.info('stream-published: ', localStream);
+        const { localStreams } = this.state;
+        localStreams.push(localStream);
+        this.setState('localStream-add', localStream);
+      });
+      this.client.on('stream-added', (remoteStream) => {
+        console.info('stream-added: ', remoteStream);
+        const { remoteStreams } = this.state;
+        remoteStreams.push(remoteStream);
+        // 自动订阅
+        this.client.subscribe(remoteStream.sid, (err) => {
+          console.error('自动订阅失败:', err);
+        });
+        this.setState('remoteStream-add', remoteStream);
+      });
+      this.client.on('stream-subscribed', (remoteStream) => {
+        console.info('stream-subscribed: ', remoteStream);
+        const { remoteStreams } = this.state;
+        const idx = remoteStreams.findIndex(item => item.sid === remoteStream.sid);
+        if (idx >= 0) {
+          remoteStreams.splice(idx, 1, remoteStream);
+        }
+        this.setState('remoteStream-update', remoteStream);
+      });
+      this.client.on('stream-removed', (remoteStream) => {
+        console.info('stream-removed: ', remoteStream);
+        const { remoteStreams } = this.state;
+        const idx = remoteStreams.findIndex(item => item.sid === remoteStream.sid);
+        if (idx >= 0) {
+          const p = remoteStreams.splice(idx, 1)[0];
+          this.setState('remoteStream-remove', p);
+        }
+      });
+
+      document.querySelector('#joinRoomBtn').addEventListener('click', this.handleJoinRoom.bind(this));
+      document.querySelector('#publishBtn').addEventListener('click', this.handlePublish.bind(this));
+      document.querySelector('#publishScreenBtn').addEventListener('click', this.handlePublishScreen.bind(this));
+      document.querySelector('#unPublishBtn').addEventListener('click', this.handleUnpublish.bind(this));
+      document.querySelector('#subscribeBtn').addEventListener('click', this.handleSubscribe.bind(this));
+      document.querySelector('#unSubscribeBtn').addEventListener('click', this.handleUnsubscribe.bind(this));
+      document.querySelector('#leaveRoomBtn').addEventListener('click', this.handleLeaveRoom.bind(this));
+
+      window.addEventListener('beforeunload', this.handleLeaveRoom.bind(this));
+    },
+    // 操作
+    handleJoinRoom: function () {
+      const {
+        roomId,
+        userId,
+        isJoinedRoom
+      } = this.state;
+      if (isJoinedRoom) {
+        alert('已经加入了房间');
+        return;
+      }
+      if (!roomId) {
+        alert('请先填写房间号');
+        return;
+      }
+      this.client.joinRoom(roomId, userId, () => {
+        console.info('加入房间成功');
+        this.setState('isJoinedRoom', true);
+      }, (err) => {
+        console.error('加入房间失败: ', err);
+      });
+    },
+    handlePublish: function () {
+      this.client.publish(err => {
+        console.error('发布失败:', err);
+      });
+    },
+    handlePublishScreen: function () {
+      this.client.publish({
+        audio: true,
+        video: false,
+        screen: true
+      }, err => {
+        console.error('发布失败:', err);
+      });
+    },
+    handleUnpublish: function () {
+      const {
+        selectedStream
+      } = this.state;
+      if (!selectedStream) {
+        alert('未选择需要取消发布的本地流');
+        return;
+      }
+      this.client.unpublish(selectedStream.sid, (stream) => {
+        console.info('取消发布本地流成功:', stream);
+        const {
+          localStreams
+        } = this.state;
+        const idx = localStreams.findIndex(item => item.sid === stream.sid);
+        if (idx >= 0) {
+          const p = localStreams.splice(idx, 1)[0];
+          this.setState('selectedStream', null);
+          this.setState('localStream-remove', p);
+        }
+      }, (err) => {
+        console.error('取消发布本地流失败:', err);
+      })
+    },
+    handleSubscribe: function () {
+      const {
+        selectedStream
+      } = this.state;
+      if (!selectedStream) {
+        alert('未选择需要订阅的远端流');
+        return;
+      }
+      this.client.subscribe(selectedStream.sid, (err) => {
+        console.error('订阅失败:', err);
+      });
+    },
+    handleUnsubscribe: function () {
+      const {
+        selectedStream
+      } = this.state;
+      if (!selectedStream) {
+        alert('未选择需要取消订阅的远端流');
+        return;
+      }
+      this.client.unsubscribe(selectedStream.sid, (stream) => {
+        console.info('取消订阅成功:', stream);
+        const {
+          remoteStreams
+        } = this.state;
+        const idx = remoteStreams.findIndex(item => item.sid === stream.sid);
+        if (idx >= 0) {
+          remoteStreams.splice(idx, 1, stream);
+          this.setState('remoteStream-update', stream);
+        }
+      }, (err) => {
+        console.error('订阅失败:', err);
+      });
+    },
+    handleLeaveRoom: function () {
+      const {
+        isJoinedRoom
+      } = this.state;
+      if (!isJoinedRoom) {
+        return;
+      }
+      this.client.leaveRoom(() => {
+        console.info('离开房间成功');
+        this.setState('selectedStream', null);
+        const {
+          localStreams,
+          remoteStreams
+        } = this.state;
+        localStreams.forEach(item => {
+          this.setState('localStream-remove', item);
+        });
+        remoteStreams.forEach(item => {
+          this.setState('remoteStream-remove', item);
+        });
+        this.setState('isJoinedRoom', false);
+      }, (err) => {
+        console.error('离开房间失败:', err);
+      });
+    },
+    handleSelectStream: function (stream) {
+      console.log('select stream: ', stream);
+      this.setState('selectedStream', stream);
+    }
+  }
+
+  App.init();
+}

+ 1 - 1
examples/pureJS/package.json

@@ -3,7 +3,7 @@
   "version": "1.0.0",
   "description": "UCloud RTC 纯 JS 版本的 demo",
   "scripts": {
-    "start": "npx serve . -p 3001"
+    "start": "npx serve . -p 3000"
   },
   "author": "",
   "license": "MIT",