视频通话以及音频截取

560 阅读2分钟

技术栈Vue+webRtc+webSocket

webRtc(网页实时通讯)

MediaStream(通过设备的摄像头及话筒获得视频、音频的同步流)

var p = navigator.mediaDevices.getUserMedia({ audio: true, video: true })
    p.then(function (mediaStream) {
      var video = document.querySelector('video')
      video.srcObject = mediaStream
      video.onloadedmetadata = function (e) {
        // Do something with the video here.
      }
    })
    p.catch(function (err) {
      console.log(err.name)
    })

在某些情况下webrtc受限带宽传输,可以使用低帧率

var constraints = { video: { frameRate: { ideal: 10, max: 15 } } };

在移动设备(电话)上,前置或者后置摄像头

var front = false;
document.getElementById('flip-button').onclick = function() { front = !front; };

var constraints = { video: { facingMode: (front? "user" : "environment") } };

RTCPeerConnection(建立远端连接)

呼叫方发送一个offer,被呼叫方发出一个answer

//offer
   var pc = new PeerConnection();
       if (pc.addTrack !== undefined) {
         pc.ontrack = (ev) => {
           ev.streams.forEach((stream) => doAddStream(stream))
         }
       } else {
         pc.onaddstream = (ev) => {
           doAddStream(ev.stream)
         }
       }
       pc.createOffer(function(desc){
         pc.setLocalDescription(desc, function() {
           // send the offer to a server that can negotiate with a remote client
         })
       });
//answer
   var pc = new PeerConnection();
       pc.setRemoteDescription(new RTCSessionDescription(offer), function() {
         pc.createAnswer(function(answer) {
           pc.setLocalDescription(answer, function() {
             // send the answer to the remote connection
           })
         })
       });

通过peerconnection建立一条数据信道,用于发送非视频音频信息。

    var pc = new PeerConnection();
    var channel = pc.createDataChannel("Mydata");
    channel.onopen = function(event) {
      channel.send('sending a message');
    }
    channel.onmessage = function(event) { console.log(event.data); }

通过RTCDataChannel接收和发送数据

    <button id="connectButton" name="connectButton" class="buttonleft">
      连接
    </button>
    <button id="disconnectButton" name="disconnectButton" class="buttonright" disabled>
      断开
    </button>
    <div class="messagebox">
        <label for="message">输入的消息:
          <input type="text" name="message" id="message" placeholder="Message text"
                  inputmode="latin" size=60 maxlength=120 disabled>
        </label>
        <button id="sendButton" name="sendButton" class="buttonright" disabled>
          发送
        </button>
  </div>
  <div class="messagebox" id="receivebox">
      <p>收到的消息</p>
  </div>
//设置事件监听
  function startup() {
      connectButton = document.getElementById('connectButton');
      disconnectButton = document.getElementById('disconnectButton');
      sendButton = document.getElementById('sendButton');
      messageInputBox = document.getElementById('message');
      receiveBox = document.getElementById('receivebox');
    
      // Set event listeners for user interface widgets
    
      connectButton.addEventListener('click', connectPeers, false);
      disconnectButton.addEventListener('click', disconnectPeers, false);
      sendButton.addEventListener('click', sendMessage, false);
    }
//建立本地连接
    localConnection = new RTCPeerConnection();
    sendChannel = localConnection.createDataChannel("sendChannel");
    sendChannel.onopen = handleSendChannelStatusChange;
    sendChannel.onclose = handleSendChannelStatusChange;
//建立远程连接
    remoteConnection = new RTCPeerConnection();
    remoteConnection.ondatachannel = receiveChannelCallback;
    
//设置多个连接
    localConnection.onicecandidate = e => !e.candidate
        || remoteConnection.addIceCandidate(e.candidate)
        .catch(handleAddCandidateError);
    remoteConnection.onicecandidate = e => !e.candidate
        || localConnection.addIceCandidate(e.candidate)
        .catch(handleAddCandidateError);
        
//尝试连接
    localConnection.createOffer()
    .then(offer => localConnection.setLocalDescription(offer))
    .then(() => remoteConnection.setRemoteDescription(localConnection.localDescription))
    .then(() => remoteConnection.createAnswer())
    .then(answer => remoteConnection.setLocalDescription(answer))
    .then(() => localConnection.setRemoteDescription(remoteConnection.localDescription))
    .catch(handleCreateDescriptionError);
    
//处理成功的连接
  function handleLocalAddCandidateSuccess() {
    connectButton.disabled = true;
  }
  function handleRemoteAddCandidateSuccess() {
    disconnectButton.disabled = false;
  }

//连接数据通道
  function receiveChannelCallback(event) {
    receiveChannel = event.channel;
    receiveChannel.onmessage = handleReceiveMessage;
    receiveChannel.onopen = handleReceiveChannelStatusChange;
    receiveChannel.onclose = handleReceiveChannelStatusChange;
  }

//处理频道的更改
function handleSendChannelStatusChange(event) {
    if (sendChannel) {
      var state = sendChannel.readyState;
    
      if (state === "open") {
        messageInputBox.disabled = false;
        messageInputBox.focus();
        sendButton.disabled = false;
        disconnectButton.disabled = false;
        connectButton.disabled = true;
      } else {
        messageInputBox.disabled = true;
        sendButton.disabled = true;
        connectButton.disabled = false;
        disconnectButton.disabled = true;
      }
    }
  }
  function handleReceiveChannelStatusChange(event) {
    if (receiveChannel) {
      console.log("Receive channel's status has changed to " +
                  receiveChannel.readyState);
    }
  }
  
//传送消息
    function sendMessage() {
        var message = messageInputBox.value;
        sendChannel.send(message);
        
        messageInputBox.value = "";
        messageInputBox.focus();
      }
      
//接收消息
    function handleReceiveMessage(event) {
    var el = document.createElement("p");
    var txtNode = document.createTextNode(event.data);
    
    el.appendChild(txtNode);
    receiveBox.appendChild(el);
  }
 
//断开连接
    function disconnectPeers() {
 
    // Close the RTCDataChannels if they're open.
    
    sendChannel.close();
    receiveChannel.close();
    
    // Close the RTCPeerConnections
    
    localConnection.close();
    remoteConnection.close();

    sendChannel = null;
    receiveChannel = null;
    localConnection = null;
    remoteConnection = null;
    
    // Update user interface elements
    
    connectButton.disabled = false;
    disconnectButton.disabled = true;
    sendButton.disabled = true;
    
    messageInputBox.value = "";
    messageInputBox.disabled = true;
  }