iT邦幫忙

0

無法使用WebRTC傳送CANVAS畫面

大家好!想請教大家有關WebRTC的一些問題
我想製作一個當兩端使用者開啟相同網址,便會建立一個會議空間
雙方則可進行視訊及共用白板
而我原先計畫其實只有視訊,是到後期才加入白板功能
爬了WebRTC官方文件後,發現可以使用captureStream這個API達到效果
但實作後還是沒辦法如其運作...
後來認為共用白板的製作太難達到,所以先以達到一端使用 一端觀看為主
目前還是仍無法成功傳輸CANVAS畫面QQ (視訊已可以運作)

window.onload裡是放白板本地端白板的行為
其餘則是實現WebRTC

window.onload = function () {
  // Definitions
  canvas = document.getElementById("paint-canvas");
  var context = canvas.getContext("2d");
  var boundings = canvas.getBoundingClientRect();

  // Specifications
  var mouseX = 0;
  var mouseY = 0;
  context.strokeStyle = 'black'; // initial brush color
  context.lineWidth = 1; // initial brush width
  var isDrawing = false;


  
  // Handle Colors
  var colors = document.getElementsByClassName('colors')[0];

  colors.addEventListener('click', function(event) {
    context.strokeStyle = event.target.value || 'black';
  });

  // Handle Brushes
  var brushes = document.getElementsByClassName('brushes')[0];

  brushes.addEventListener('click', function(event) {
    context.lineWidth = event.target.value || 1;
  });

  // Mouse Down Event
  canvas.addEventListener('mousedown', function(event) {
    setMouseCoordinates(event);
    isDrawing = true;

    // Start Drawing
    context.beginPath();
    context.moveTo(mouseX, mouseY);
  });

  // Mouse Move Event
  canvas.addEventListener('mousemove', function(event) {
    setMouseCoordinates(event);

    if(isDrawing){
      context.lineTo(mouseX, mouseY);
      context.stroke();
    }});

  // Mouse Up Event
  canvas.addEventListener('mouseup', function(event) {
    setMouseCoordinates(event);
    isDrawing = false;
  });


  // Handle Mouse Coordinates
  function setMouseCoordinates(event) {
    mouseX = event.clientX - boundings.left;
    mouseY = event.clientY - boundings.top;
  }

  // Handle Clear Button
  var clearButton = document.getElementById('clear');

  clearButton.addEventListener('click', function() {
    context.clearRect(0, 0, canvas.width, canvas.height);
  });

  // Handle Save Button
  var saveButton = document.getElementById('save');

  saveButton.addEventListener('click', function() {
    var imageName = prompt('Please enter image name');
    var canvasDataURL = canvas.toDataURL();
    var a = document.createElement('a');
    a.href = canvasDataURL;
    a.download = imageName || 'drawing';
    a.click();

  });
};

var strUrl = location.search;
var getPara, ParaVal;
var vaule = [];

if (strUrl.indexOf("?") != -1) {
  var getSearch = strUrl.split("?");
  getPara = getSearch[1].split("&");
  for (i = 0; i < getPara.length; i++) {
    ParaVal = getPara[i].split(" ");
    vaule.push(ParaVal[0]);
    vaule[ParaVal[0]] = ParaVal[1];
  }
}


if (!location.hash) {
  location.hash =vaule.toString(16);
}

const roomHash = location.hash.substring(1);

// TODO: Replace with your own channel ID
const drone = new ScaleDrone('yiS12Ts5RdNhebyM');
// Room name needs to be prefixed with 'observable-'
const roomName = 'observable-' + roomHash;
const configuration = {
  iceServers: [{
    urls: 'stun:stun.l.google.com:19302'
  }]
};

let room;
let pc;

function onSuccess() {};
function onError(error) {
  console.error(error);
};

drone.on('open', error => {
  if (error) {
    return console.error(error);
  }
  room = drone.subscribe(roomName);
  room.on('open', error => {
    if (error) {
      onError(error);
    }
  });
  // We're connected to the room and received an array of 'members'
  // connected to the room (including us). Signaling server is ready.
  room.on('members', members => {
    console.log('MEMBERS', members);
    // If we are the second user to connect to the room we will be creating the offer
    const isOfferer = members.length === 2;
    startWebRTC(isOfferer);
  });
});

// Send signaling data via Scaledrone
function sendMessage(message) {
  drone.publish({
    room: roomName,
    message
  });
}

function startWebRTC(isOfferer) {
  pc = new RTCPeerConnection(configuration);

  // 'onicecandidate' notifies us whenever an ICE agent needs to deliver a
  // message to the other peer through the signaling server
  pc.onicecandidate = event => {
    if (event.candidate) {
      sendMessage({'candidate': event.candidate});
    }
  };

  // If user is offerer let the 'negotiationneeded' event create the offer
  if (isOfferer) {
    pc.onnegotiationneeded = () => {
      pc.createOffer().then(localDescCreated).catch(onError);
    }
  }

  const stream = canvas.captureStream();
  remoteCanvas.srcObject = stream; 
  stream.getTracks().forEach(track => pc.addTrack(track, stream));


  // When a remote stream arrives display it in the #remoteVideo element
  pc.ontrack = event => {
    const stream = event.streams[0];
    if (!remoteVideo.srcObject || remoteVideo.srcObject.id !== stream.id) {
      remoteVideo.srcObject = stream;
    }
  };

 
  navigator.mediaDevices.getUserMedia({
    audio: true,
    video: true,
  }).then(stream => {
    // Display your local video in #localVideo element
    localVideo.srcObject = stream;          
    // Add your stream to be sent to the conneting peer
    stream.getTracks().forEach(track => pc.addTrack(track, stream));
  }, onError);
  


  // Listen to signaling data from Scaledrone
  room.on('data', (message, client) => {
    // Message was sent by us
    if (client.id === drone.clientId) {
      return;
    }

    if (message.sdp) {
      // This is called after receiving an offer or answer from another peer
      pc.setRemoteDescription(new RTCSessionDescription(message.sdp), () => {
        // When receiving an offer lets answer it
        if (pc.remoteDescription.type === 'offer') {
          pc.createAnswer().then(localDescCreated).catch(onError);
        }
      }, onError);
    } else if (message.candidate) {
      // Add the new ICE candidate to our connections remote description
      pc.addIceCandidate(
        new RTCIceCandidate(message.candidate), onSuccess, onError
        );
    }
  });


}

function localDescCreated(desc) {
  pc.setLocalDescription(
    desc,
    () => sendMessage({'sdp': pc.localDescription}),
    onError
    );
}


而這段是主要的部分
remoteCanvas是video標籤,用來顯示canvas的畫面

  const stream = canvas.captureStream();
  remoteCanvas.srcObject = stream; 
  stream.getTracks().forEach(track => pc.addTrack(track, stream));

希望大家可以給我一點提示
非常謝謝 !
/images/emoticon/emoticon41.gif

froce iT邦大師 4 級 ‧ 2019-05-07 14:35:50 檢舉
https://webrtc.github.io/samples/src/content/capture/canvas-pc/
沒辦法給你提示,因為我也沒寫到。
不過之前有研究過這塊。
fillano iT邦超人 1 級 ‧ 2019-05-08 09:48:23 檢舉
我之前鐵人賽有寫共享白板,可以多方輸入。雖然是透過WebSocket來傳送資訊。不過還是可以參考一下共享白板的思路。

尚未有邦友回答

立即登入回答