Browse Source

Merge branch 'feat-upgrade-demo'

kevin.song 5 years ago
parent
commit
a9079d3772

+ 4 - 4
examples/angular/src/components/stream-player/index.css

@@ -7,7 +7,7 @@
   cursor: pointer;
 }
 
-.media-player video {
-  width: 100%;
-  height: 100%;
-}
+.media-player .video-container {
+  position: relative;
+  height: 200px;
+}

+ 1 - 4
examples/angular/src/components/stream-player/index.html

@@ -7,9 +7,6 @@
   <div [hidden]="!stream.mediaStream" style="overflow: 'hidden'; text-overflow: 'ellipsis';">视频丢包率: {{stats.videoLost}}
     %
     &nbsp;&nbsp;&nbsp;&nbsp;网络延时: {{stats.rtt}} ms</div>
-  <div [hidden]="!stream.mediaStream">
-    <video webkit-playsinline autoplay playsinline [controls]="isIOS" #video>
-    </video>
-  </div>
+  <div class="video-container" [id]="stream.sid" [hidden]="!stream.mediaStream"></div>
   <p [hidden]="stream.mediaStream">unsubscribe</p>
 </div>

+ 17 - 17
examples/angular/src/components/stream-player/index.ts

@@ -6,8 +6,6 @@ import {
   OnDestroy,
   Input,
   SimpleChanges,
-  ViewChild,
-  ElementRef
 } from '@angular/core';
 import classnames from 'unique-classnames';
 
@@ -23,10 +21,6 @@ interface Stats {
   biggestRTT: number;
 }
 
-function isIOS(): boolean {
-  return /.*iphone.*/i.test(navigator.userAgent);
-}
-
 @Component({
   selector: 'app-stream-player',
   templateUrl: './index.html',
@@ -46,21 +40,17 @@ export class StreamPlayerComponent implements OnInit, OnDestroy, OnChanges, Afte
     videoLost: 0,
     biggestVideoLost: 0,
     rtt: 0,
-    biggestRTT: 0
+    biggestRTT: 0,
   };
 
   private volumeTimer: number;
   private stateTimer: number;
-  private isIOS: boolean;
-
-  @ViewChild('video', {static: true}) videoRef: ElementRef;
 
   private isComponentDestroyed: boolean;
 
   constructor() {
     this.volumeTimer = 0;
     this.stateTimer = 0;
-    this.isIOS = isIOS();
   }
 
   ngOnInit() {
@@ -73,19 +63,19 @@ export class StreamPlayerComponent implements OnInit, OnDestroy, OnChanges, Afte
     const currentValue: Stream = stream.currentValue;
     const previousValue: Stream = stream.previousValue;
     if (stream.firstChange && currentValue.mediaStream) {
-      this.play(currentValue.mediaStream);
+      this.play();
       return;
     }
     if (!currentValue.mediaStream) {
       this.stop();
     } else if (currentValue.mediaStream !== previousValue.mediaStream) {
-      this.play(currentValue.mediaStream);
+      this.play();
     }
   }
 
   ngAfterViewInit() {
     if (this.stream.mediaStream) {
-      this.play(this.stream.mediaStream);
+      this.play();
     }
   }
 
@@ -94,15 +84,25 @@ export class StreamPlayerComponent implements OnInit, OnDestroy, OnChanges, Afte
     this.isComponentDestroyed = true;
   }
 
-  play(mediaStream: MediaStream) {
-    this.videoRef.nativeElement.srcObject = mediaStream;
+  play() {
+    const { client, stream } = this;
+    const mirror: boolean = stream.type === 'publish';
+    client.play({
+      streamId: stream.sid,
+      container: stream.sid,
+      mirror
+    }, (err) => {
+      if (err) {
+        console.log(`播放失败 ${err}`);
+        alert(`播放失败 ${err}`);
+      }
+    });
     this.startGetVolume();
     this.startGetState();
   }
   stop() {
     this.stopGetVolume();
     this.stopGetState();
-    this.videoRef.nativeElement.srcObject = null;
   }
 
   startGetVolume() {

+ 5 - 12
examples/angular/src/pages/room/index.ts

@@ -98,18 +98,11 @@ export class RoomComponent implements OnInit, AfterContentInit, AfterViewInit, O
     });
     this.client.on('stream-reconnected', ({ previous, current }) => {
       console.log(`流已断开重连`);
-      if (previous.type === 'publish') {
-        const { localStreams } = this;
-        const idx = localStreams.findIndex(item => item.sid === previous.sid);
-        if (idx >= 0) {
-          localStreams.splice(idx, 1, current);
-        }
-      } else {
-        const { remoteStreams } = this;
-        const idx = remoteStreams.findIndex(item => item.sid === previous.sid);
-        if (idx >= 0) {
-          remoteStreams.splice(idx, 1, current);
-        }
+      const isLocalStream = previous.type === 'publish';
+      const streams = isLocalStream ? this.localStreams : this.remoteStreams;
+      const idx = streams.findIndex(item => item.sid === previous.sid);
+      if (idx >= 0) {
+        streams.splice(idx, 1, current);
       }
     });
 

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

@@ -2,6 +2,7 @@
   display: inline-block;
   margin: 2px;
   width: 300px;
+  height: 200px;
   text-align: left;
   white-space: nowrap;
   cursor: pointer;

File diff suppressed because it is too large
+ 0 - 23
examples/pureJS/js/can-autoplay.min.js


+ 129 - 154
examples/pureJS/js/index.js

@@ -19,15 +19,80 @@ window.onload = function () {
 
   console.log('UCloudRTC sdk version: ', UCloudRTC.version);
 
-  canAutoplay.video().then(res => {
-    if (!res.result) {
-      const pullerElm = document.querySelector('#pullers-title');
-      const hintElm = document.createElement('p');
-      hintElm.className = 'hint';
-      hintElm.textContent = '当前浏览器不支持自动播放视频,订阅远端流成功后,可点击对应的视频区域进行播放'
-      pullerElm.appendChild(hintElm);
+  const Player = function(client, stream, selectFunc) {
+    this.client = client;
+    this.stream = stream;
+    this.element = document.createElement('div');
+
+    // userId
+    const uIDElem = document.createElement('div');
+    uIDElem.innerHTML = `用户ID:${stream.uid}`;
+    uIDElem.style = 'overflow: hidden; text-overflow: ellipsis;';
+    this.element.appendChild(uIDElem);
+
+    // streamId
+    const sIDElem = document.createElement('div');
+    sIDElem.innerHTML = `流ID:${stream.sid}`;
+    sIDElem.style = 'overflow: hidden; text-overflow: ellipsis;';
+    this.element.appendChild(sIDElem);
+
+    // hint - unsubscribe
+    const hintElem = document.createElement('p');
+    hintElem.innerHTML = 'unsubscribe';
+    hintElem.style = 'display: none;';
+    this.hint = hintElem;
+    this.element.appendChild(hintElem);
+
+    // container
+    const container = document.createElement('div');
+    container.className = 'media-player';
+    container.id = stream.sid;
+    this.container = container;
+    this.element.appendChild(container);
+
+    this.handleSelect = function() {
+      selectFunc(this.stream);
+    }.bind(this);
+    this.element.addEventListener('click', this.handleSelect);
+
+    if (stream.mediaStream) {
+      this.play();
+    }
+  }
+  Player.prototype.play = function() {
+    const isLocalStream = this.stream.type === 'publish';
+    this.hint.style.display = 'none';
+    this.container.style.display = 'inline-block';
+    this.client.play({
+      streamId: this.stream.sid,
+      container: this.container,
+      mirror: isLocalStream
+    }, (err) => {
+      if (err) {
+        console.log(`自动播放失败 ${err}`);
+        alert(`自动播放失败 ${err}`);
+      }
+    })
+  }
+  Player.prototype.stop = function() {
+    const isLocalStream = this.stream.type === 'publish';
+    this.container.style.display = 'none';
+    if (!isLocalStream) {
+      this.hint.style.display = 'block';
     }
-  });
+  }
+  Player.prototype.updateStream = function(stream) {
+    this.stream = stream;
+    if (stream.mediaStream) {
+      this.play();
+    } else {
+      this.stop();
+    }
+  }
+  Player.prototype.destroy = function() {
+    this.element.removeEventListener('click', this.handleSelect);
+    this.element.parentNode.removeChild(this.element);
+  }
 
   // 用于维护应用内的状态
   const App = {
@@ -37,58 +102,23 @@ window.onload = function () {
       isJoinedRoom: false,
       selectedStream: null,
       localStreams: [],
-      remoteStreams: []
+      remoteStreams: [],
+      players: [],
     },
     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;
+    renderRoomId: function (roomId) {
       const roomElem = document.querySelector('#roomId');
       roomElem.innerHTML = roomId;
     },
-    renderRoomStatus: function () {
-      const { isJoinedRoom } = this.state;
+    renderRoomStatus: function (status) {
       const roomStatusElem = document.querySelector('#roomStatus');
-      if (isJoinedRoom) {
+      if (status) {
         roomStatusElem.innerHTML = "已加入";
       } else {
         roomStatusElem.innerHTML = "未加入";
       }
     },
-    renderSelectedStream: function () {
-      const { selectedStream } = this.state;
+    renderSelectedStream: function (selectedStream) {
       const selectedStreamElem = document.querySelector('#selectedStream');
       if (selectedStream) {
         selectedStreamElem.innerHTML = selectedStream.sid;
@@ -96,89 +126,39 @@ window.onload = function () {
         selectedStreamElem.innerHTML = "未选择";
       }
     },
-    loadStream: function (stream, type) {
+    renderStream: function (stream) {
+      const isLocalStream = stream.type === 'publish';
       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 = 's' + 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);
+      if (isLocalStream) {
+        parent = document.querySelector('#pushers');
       } else {
-        const videoElem = document.createElement('video');
-        videoElem.autoplay = true;
-        videoElem.playsInline = true;
-        videoElem['webkit-playsinline'] = 'true';
-        videoElem.srcObject = stream.mediaStream;
-        player.append(videoElem);
+        parent = document.querySelector('#pullers');
       }
-      player.addEventListener('click', function() {
-        this.handleSelectStream(stream);
-      }.bind(this));
-      parent.append(player);
+      const player = new Player(this.client, stream, this.handleSelectStream.bind(this));
+      // todo - handleSelectStream
+      this.state.players.push(player);
+      parent.appendChild(player.element);
     },
-    unloadStream: function (stream, type) {
-      let parent;
-      switch (type) {
-        case 'pusher':
-          parent = document.querySelector('#pushers');
-          break;
-        case 'puller':
-          parent = document.querySelector('#pullers');
-          break;
-        default:
-          return;
+    unrenderStream: function (stream) {
+      const idx = this.state.players.findIndex(item => item.stream.sid === stream.sid);
+      if (idx < 0) {
+        console.log('unrender stream - stream not found');
+        return;
       }
-      const player = document.querySelector('#s' + stream.sid);
-      parent.removeChild(player);
+      const player = this.state.players[idx];
+      this.state.players.splice(idx, 1);
+      player.destroy();
     },
     rerenderStream: function (stream) {
-      const player = document.querySelector('#s' + stream.sid);
-      if (stream.mediaStream) {
-        const videoElem = document.createElement('video');
-        videoElem.autoplay = true;
-        videoElem.playsInline = true;
-        videoElem['webkit-playsinline'] = 'true';
-        videoElem.srcObject = stream.mediaStream;
-        const pElem = player.querySelector('p');
-        player.removeChild(pElem);
-        player.appendChild(videoElem);
-        videoElem.addEventListener('click', function() {
-          if (videoElem.paused) {
-            videoElem.play();
-          }
-        });
-      } else {
-        const videoElem = player.querySelector('video');
-        const pElem = document.createElement('p');
-        pElem.innerHTML = 'unsubscribe';
-        player.removeChild(videoElem);
-        player.appendChild(pElem);
+      const player = this.state.players.find(item => item.stream.sid === stream.sid);
+      if (!player) {
+        console.log('rerender stream - stream not found');
+        return;
       }
+      player.updateStream(stream);
     },
     init: function () {
-      this.renderRoomId();
+      this.renderRoomId(RoomId);
 
       const token = UCloudRTC.generateToken(AppId, AppKey, RoomId, UserId);
       this.client = new UCloudRTC.Client(AppId, token);
@@ -188,17 +168,17 @@ window.onload = function () {
         console.info('stream-published: ', localStream);
         const { localStreams } = this.state;
         localStreams.push(localStream);
-        this.setState('localStream-add', localStream);
+        this.renderStream(localStream);
       });
       this.client.on('stream-added', (remoteStream) => {
         console.info('stream-added: ', remoteStream);
         const { remoteStreams } = this.state;
         remoteStreams.push(remoteStream);
+        this.renderStream(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);
@@ -207,15 +187,16 @@ window.onload = function () {
         if (idx >= 0) {
           remoteStreams.splice(idx, 1, remoteStream);
         }
-        this.setState('remoteStream-update', remoteStream);
+        this.rerenderStream(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);
+          const p = remoteStreams[idx];
+          remoteStreams.splice(idx, 1);
+          this.unrenderStream(p);
         }
       });
       this.client.on('connection-state-change', ({ previous, current }) => {
@@ -223,24 +204,15 @@ window.onload = function () {
       });
       this.client.on('stream-reconnected', ({previous, current}) => {
         console.log(`流已断开重连`);
-        if (previous.type === 'publish') {
-          const { localStreams } = this.state;
-          const idx = localStreams.findIndex(item => item.sid === previous.sid);
-          if (idx >= 0) {
-            const oldStream = localStreams.splice(idx, 1, current)[0];
-            this.setState('localStream-remove', oldStream);
-            localStreams.push(current);
-            this.setState('localStream-add', current);
-          }
-        } else {
-          const { remoteStreams } = this.state;
-          const idx = remoteStreams.findIndex(item => item.sid === previous.sid);
-          if (idx >= 0) {
-            const oldStream = remoteStreams.splice(idx, 1, current)[0];
-            this.setState('remoteStream-remove', oldStream);
-            remoteStreams.push(current);
-            this.setState('remoteStream-add', current);
-          }
+        const isLocalStream = previous.type === 'publish';
+        const streams = isLocalStream ? this.state.localStreams : this.state.remoteStreams;
+        const idx = streams.findIndex(item => item.sid === previous.sid);
+        if (idx >= 0) {
+          // 更新流的信息
+          const oldStream = streams.splice(idx, 1, current)[0];
+          this.unrenderStream(oldStream);
+          streams.push(current);
+          this.renderStream(current);
         }
       });
 
@@ -271,7 +243,7 @@ window.onload = function () {
       }
       this.client.joinRoom(roomId, userId, () => {
         console.info('加入房间成功');
-        this.setState('isJoinedRoom', true);
+        this.renderRoomStatus(true);
       }, (err) => {
         console.error('加入房间失败: ', err);
       });
@@ -302,8 +274,9 @@ window.onload = function () {
         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);
+          this.state.selectedStream = null;
+          this.renderSelectedStream();
+          this.unrenderStream(p);
         }
       }, (err) => {
         console.error('取消发布本地流失败:', err);
@@ -337,7 +310,7 @@ window.onload = function () {
         const idx = remoteStreams.findIndex(item => item.sid === stream.sid);
         if (idx >= 0) {
           remoteStreams.splice(idx, 1, stream);
-          this.setState('remoteStream-update', stream);
+          this.rerenderStream(stream);
         }
       }, (err) => {
         console.error('订阅失败:', err);
@@ -352,25 +325,27 @@ window.onload = function () {
       }
       this.client.leaveRoom(() => {
         console.info('离开房间成功');
-        this.setState('selectedStream', null);
+        this.state.selectedStream = null;
+        this.renderSelectedStream();
         const {
           localStreams,
           remoteStreams
         } = this.state;
         localStreams.forEach(item => {
-          this.setState('localStream-remove', item);
+          this.unrenderStream(item);
         });
         remoteStreams.forEach(item => {
-          this.setState('remoteStream-remove', item);
+          this.unrenderStream(item);
         });
-        this.setState('isJoinedRoom', false);
+        this.renderRoomStatus(false);
       }, (err) => {
         console.error('离开房间失败:', err);
       });
     },
     handleSelectStream: function (stream) {
       console.log('select stream: ', stream);
-      this.setState('selectedStream', stream);
+      this.state.selectedStream = stream;
+      this.renderSelectedStream(stream);
     }
   }
 

+ 0 - 1
examples/react/package.json

@@ -3,7 +3,6 @@
   "version": "1.0.0",
   "description": "UCloud RTC react 版本的 demo",
   "dependencies": {
-    "can-autoplay": "^3.0.0",
     "react": "^16.12.0",
     "react-dom": "^16.12.0",
     "unique-classnames": "^1.0.6",

+ 1 - 0
examples/react/src/components/MediaPlayer/index.css

@@ -9,6 +9,7 @@
 
 .media-player .video-container {
   position: relative;
+  height: 200px;
 }
 
 .media-player .muted-mask,

+ 38 - 40
examples/react/src/components/MediaPlayer/index.jsx

@@ -1,5 +1,4 @@
 import React, { Component, Fragment } from 'react';
-import canAutoplay from 'can-autoplay';
 import PropTypes from 'prop-types';
 import classnames from 'unique-classnames';
 import './index.css';
@@ -32,32 +31,26 @@ export default class MediaPlayer extends Component {
         biggestVideoLost: 0,
         rtt: 0,
         biggestRTT: 0,
-        canAutoplay: true
       },
+      showPlayMask: false
     }
     this.volumeTimer = 0;
     this.stateTimer = 0;
-    this.videoElem = React.createRef();
   }
 
   componentDidMount() {
     this.isComponentMounted = true;
     const { stream } = this.props;
     if (stream.mediaStream) {
-      this.play(stream.mediaStream);
+      this.play();
     }
-    canAutoplay.video().then(res => {
-      this.setState({
-        canAutoplay: res.result
-      });
-    });
   }
 
   componentWillReceiveProps(nextProps) {
     if (!nextProps.stream.mediaStream) {
       this.stop();
     } else if (nextProps.stream.mediaStream !== this.props.stream.mediaStream) {
-      this.play(nextProps.stream.mediaStream);
+      this.play();
     }
   }
 
@@ -66,15 +59,26 @@ export default class MediaPlayer extends Component {
     this.isComponentMounted = false;
   }
 
-  play(mediaStream) {
-    this.videoElem.current.srcObject = mediaStream;
+  play() {
+    const { client, stream } = this.props;
+    const mirror = stream.type === 'publish';
+    client.play({
+      streamId: stream.sid,
+      container: stream.sid,
+      mirror: mirror
+    }, (err) => {
+      if (err) {
+        this.setState({
+          showPlayMask: true
+        });
+      }
+    });
     this.startGetVolume();
     this.startGetState();
   }
   stop() {
     this.stopGetVolume();
     this.stopGetState();
-    this.videoElem.current.srcObject = null;
   }
 
   startGetVolume() {
@@ -159,29 +163,29 @@ export default class MediaPlayer extends Component {
   }
 
   handlePlay = () => {
-    if (this.videoElem.current && this.videoElem.current.paused) {
-      this.videoElem.current.play();
-    }
+    const { client, stream } = this.props;
+    client.resume(stream.sid, (err) => {
+      if (err) {
+        console.log(`播放失败 ${err}`);
+        alert(`播放失败 ${err}`);
+      } else {
+        this.setState({
+          showPlayMask: false
+        });
+      }
+    });
   }
 
   renderVideoMask = () => {
-    const { stream } = this.props;
-    if (!stream || stream.type !== 'subscribe') {
-      return null;
-    }
-    if (this.videoElem.current && this.videoElem.current.paused) {
-      if (!this.state.canAutoplay) {
-        return (
-          <div className="play-mask">
-            <div className="mask-content">
-              <div className="hint">由于当前浏览器不支持视频自动播放,请点击下面的按钮来播放</div>
-              <button onClick={this.handlePlay}>播放</button>
-            </div>
-          </div>
-        )
-      }
-    }
-    return null;
+    const { showPlayMask } = this.state;
+    return showPlayMask ? (
+      <div className="play-mask">
+        <div className="mask-content">
+          <div className="hint">由于当前浏览器不支持视频自动播放,请点击下面的按钮来播放</div>
+          <button onClick={this.handlePlay}>播放</button>
+        </div>
+      </div>
+    ) : null;
   }
 
   render() {
@@ -195,13 +199,7 @@ export default class MediaPlayer extends Component {
         <div style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>用户ID: {stream.uid}</div>
         <div style={{ overflow: 'hidden', textOverflow: 'ellipsis' }}>流ID: {stream.sid}</div>
         { this.renderStats() }
-        <div className="video-container" style={{ display: hasMediaStream ? 'block' : 'none' }}>
-          <video
-            ref={this.videoElem}
-            webkit-playsinline="true"
-            autoPlay
-            playsInline>
-          </video>
+        <div className="video-container" id={stream.sid} style={{ display: hasMediaStream ? 'block' : 'none' }}>
           { this.renderVideoMask() }
         </div>
         <p style={{ display: hasMediaStream ? 'none' : 'block' }}> unsubscribe </p>

+ 10 - 13
examples/react/src/pages/room/index.jsx

@@ -80,20 +80,17 @@ export default class Room extends Component {
     });
     this.client.on('stream-reconnected', ({previous, current}) => {
       console.log(`流已断开重连`);
-      if (previous.type === 'publish') {
-        const { localStreams } = this.state;
-        const idx = localStreams.findIndex(item => item.sid === previous.sid);
-        if (idx >= 0) {
-          localStreams.splice(idx, 1, current);
-          this.setState({ localStreams });
-        }
+      const isLocalStream = previous.type === 'publish';
+      const streams = isLocalStream ? this.state.localStreams : this.state.remoteStreams;
+      const idx = streams.findIndex(item => item.sid === previous.sid);
+      if (idx >= 0) {
+        // 更新流的信息
+        streams.splice(idx, 1, current);
+      }
+      if (isLocalStream) {
+        this.setState({ localStreams: streams });
       } else {
-        const { remoteStreams } = this.state;
-        const idx = remoteStreams.findIndex(item => item.sid === previous.sid);
-        if (idx >= 0) {
-          remoteStreams.splice(idx, 1, current);
-          this.setState({ remoteStreams });
-        }
+        this.setState({ remoteStreams: streams });
       }
     });
 

+ 0 - 1
examples/vue/package.json

@@ -8,7 +8,6 @@
     "lint": "vue-cli-service lint"
   },
   "dependencies": {
-    "can-autoplay": "^3.0.0",
     "core-js": "^3.4.3",
     "unique-classnames": "^1.0.6",
     "urtc-sdk": "latest",

+ 26 - 36
examples/vue/src/components/MediaPlayer.vue

@@ -4,13 +4,7 @@
     <div style="overflow: 'hidden'; text-overflow: 'ellipsis';">流ID: {{stream.sid}}</div>
     <div v-show="stream.mediaStream" style="overflow: 'hidden'; text-overflow: 'ellipsis';">音量: {{volume}} % &nbsp;&nbsp;&nbsp;&nbsp;音频丢包率: {{stats.audioLost}} %</div>
     <div v-show="stream.mediaStream" style="overflow: 'hidden'; text-overflow: 'ellipsis';">视频丢包率: {{stats.videoLost}} % &nbsp;&nbsp;&nbsp;&nbsp;网络延时: {{stats.rtt}} ms</div>
-    <div class="video-container" v-show="stream.mediaStream">
-      <video
-        ref="video"
-        webkit-playsinline
-        autoplay
-        playsinline>
-      </video>
+    <div class="video-container" :id="stream.sid" v-show="stream.mediaStream">
       <div class="play-mask" v-show="showPlayMask">
         <div class="mask-content">
           <div class="hint">由于当前浏览器不支持视频自动播放,请点击下面的按钮来播放</div>
@@ -24,7 +18,6 @@
 
 <script>
 import classnames from 'unique-classnames';
-import canAutoplay from 'can-autoplay';
 
 export default {
   name: 'MediaPlayer',
@@ -42,8 +35,7 @@ export default {
         rtt: 0,
         biggestRTT: 0
       },
-      canAutoplay: true,
-      paused: false
+      showPlayMask: false
     };
   },
   props: {
@@ -75,15 +67,8 @@ export default {
   mounted: function () {
     this.isComponentDestroyed = false;
     if (this.stream.mediaStream) {
-      this.play(this.stream.mediaStream);
+      this.play();
     }
-    this.$refs.video.onplay = (e) => {
-      this.paused = e.target.paused;
-    };
-    this.paused = this.$refs.video.paused;
-    canAutoplay.video().then(res => {
-      this.canAutoplay = res.result;
-    });
   },
   beforeDestroy: function () {
     this.stop();
@@ -95,22 +80,31 @@ export default {
     'stream.mediaStream': function (val, oldVal) {
       console.log('media stream changed: ', val, oldVal);
       if (val) {
-        this.play(val);
+        this.play();
       } else {
         this.stop();
       }
     }
   },
   methods: {
-    play: function (mediaStream) {
-      this.$refs.video.srcObject = mediaStream;
+    play: function () {
+      const { client, stream } = this;
+      const mirror = stream.type === 'publish';
+      client.play({
+        streamId: stream.sid,
+        container: stream.sid,
+        mirror: mirror
+      }, (err) => {
+        if (err) {
+          this.showPlayMask = true;
+        }
+      });
       this.startGetVolume();
       this.startGetState();
     },
     stop: function () {
       this.stopGetVolume();
       this.stopGetState();
-      this.$refs.video.srcObject = null;
     },
     startGetVolume: function () {
       const { client, stream } = this;
@@ -176,20 +170,15 @@ export default {
       onClick && onClick(stream);
     },
     handlePlay: function () {
-      if (this.$refs.video && this.paused) {
-        this.$refs.video.play();
-      }
-    }
-  },
-  computed: {
-    showPlayMask: function () {
-      if (this.stream && this.stream.type !== 'subscribe') {
-        return false;
-      }
-      if (!this.canAutoplay && this.paused) {
-        return true;
-      }
-      return false;
+      const { client, stream } = this;
+      client.resume(stream.sid, (err) => {
+        if (err) {
+          console.log(`播放失败 ${err}`);
+          alert(`播放失败 ${err}`);
+        } else {
+          this.showPlayMask = false;
+        }
+      });
     }
   }
 };
@@ -208,6 +197,7 @@ export default {
 
 .media-player .video-container {
   position: relative;
+  height: 200px;
 }
 
 .media-player .muted-mask,

+ 6 - 12
examples/vue/src/pages/Room.vue

@@ -105,18 +105,12 @@ export default {
     });
     this.client.on('stream-reconnected', ({ previous, current }) => {
       console.log(`流已断开重连`);
-      if (previous.type === 'publish') {
-        const { localStreams } = this;
-        const idx = localStreams.findIndex(item => item.sid === previous.sid);
-        if (idx >= 0) {
-          localStreams.splice(idx, 1, current);
-        }
-      } else {
-        const { remoteStreams } = this;
-        const idx = remoteStreams.findIndex(item => item.sid === previous.sid);
-        if (idx >= 0) {
-          remoteStreams.splice(idx, 1, current);
-        }
+      const isLocalStream = previous.type === 'publish';
+      const streams = isLocalStream ? this.localStreams : this.remoteStreams;
+      const idx = streams.findIndex(item => item.sid === previous.sid);
+      if (idx >= 0) {
+        // 更新流的信息
+        streams.splice(idx, 1, current);
       }
     });