-
-
Save n0bisuke/904997957304cd0a8edfa9c3edaeeced to your computer and use it in GitHub Desktop.
webrtcをwebsocketサーバーでシグナリングする
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
'use strict'; | |
// RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection; | |
let localVideo = document.querySelector('#local_video'); | |
let remoteVideo = document.querySelector('#remote_video'); | |
let localStream = null; | |
let peerConnection = null; | |
let textForSendSdp = document.querySelector('#text_for_send_sdp'); | |
let textToReceiveSdp = document.querySelector('#text_for_receive_sdp'); | |
//スタートビデオが押された時 | |
let startBtn = document.querySelector('#start_btn'); | |
startBtn.addEventListener('click', startVideo, false); | |
// getUserMediaでカメラ、マイクにアクセス | |
function startVideo() { | |
navigator.mediaDevices.getUserMedia({video: true, audio: true}) | |
.then((stream) => { // success | |
console.log(stream); | |
playVideo(localVideo, stream); | |
localStream = stream; | |
}).catch((error) => { // error | |
console.error('mediaDevice.getUserMedia() error:', error); | |
return; | |
} | |
); | |
} | |
// Videoの再生を開始する | |
function playVideo(element, stream) { | |
if ('srcObject' in element) { | |
element.srcObject = stream; | |
} | |
else { | |
element.src = window.URL.createObjectURL(stream); | |
} | |
element.play(); | |
} | |
/** | |
* step2 | |
*/ | |
// Connectボタンが押されたら処理を開始 | |
function connect() { | |
if (! peerConnection) { | |
console.log('make Offer'); | |
makeOffer(); | |
} | |
else { | |
console.warn('peer already exist.'); | |
} | |
} | |
// WebRTCを利用する準備をする | |
function prepareNewConnection() { | |
let RTCPeerConnection = window.RTCPeerConnection || window.webkitRTCPeerConnection; | |
// RTCPeerConnectionを初期化する | |
let pc_config = {"iceServers":[ {"url":"stun:stun.skyway.io:3478"} ]}; | |
let peer = new RTCPeerConnection(pc_config); | |
// リモートのストリームを受信した場合のイベントをセット | |
if ('ontrack' in peer) { | |
peer.ontrack = function(event) { | |
console.log('-- peer.ontrack()'); | |
let stream = event.streams[0]; | |
playVideo(remoteVideo, stream); | |
}; | |
} | |
else { | |
peer.onaddstream = function(event) { | |
console.log('-- peer.onaddstream()'); | |
let stream = event.stream; | |
playVideo(remoteVideo, stream); | |
}; | |
} | |
// ICE Candidateを収集したときのイベント | |
// peer.onicecandidate = function (evt) { | |
// if (evt.candidate) { | |
// console.log(evt.candidate); | |
// } else { | |
// console.log('empty ice event'); | |
// sendSdp(peer.localDescription); | |
// } | |
// }; | |
// | |
//↓修正 | |
peer.onicecandidate = function (evt) { | |
if (evt.candidate) { | |
console.log(evt.candidate); | |
sendIceCandidate(evt.candidate); | |
} else { | |
console.log('empty ice event'); | |
// sendSdp(peer.localDescription); | |
} | |
}; | |
// ICEのステータスが変更になったときの処理 | |
peer.oniceconnectionstatechange = function() { | |
console.log('ICE connection Status has changed to ' + peer.iceConnectionState); | |
switch (peer.iceConnectionState) { | |
case 'closed': | |
case 'failed': | |
// ICEのステートが切断状態または異常状態になったら切断処理を実行する | |
if (peerConnection) { | |
hangUp(); | |
} | |
break; | |
case 'dissconnected': | |
break; | |
} | |
}; | |
// ローカルのストリームを利用できるように準備する | |
if (localStream) { | |
console.log('Adding local stream...'); | |
peer.addStream(localStream); | |
} | |
else { | |
console.warn('no local stream, but continue.'); | |
} | |
return peer; | |
} | |
// 手動シグナリングのための処理を追加する | |
// function sendSdp(sessionDescription) { | |
// console.log('---sending sdp ---'); | |
// textForSendSdp.value = sessionDescription.sdp; | |
// textForSendSdp.focus(); | |
// textForSendSdp.select(); | |
// } | |
// | |
// ↓シグナリングサーバー経由での処理に変更 | |
function sendSdp(sessionDescription) { | |
console.log('---sending sdp ---'); | |
textForSendSdp.value = sessionDescription.sdp; | |
let message = JSON.stringify(sessionDescription); | |
console.log('sending SDP=' + message); | |
ws.send(message); | |
} | |
// Offer SDPを生成する | |
// function makeOffer() { | |
// peerConnection = prepareNewConnection(); | |
// peerConnection.onnegotiationneeded = function(){ | |
// peerConnection.createOffer() | |
// .then(function (sessionDescription) { | |
// console.log('createOffer() succsess in promise'); | |
// return peerConnection.setLocalDescription(sessionDescription); | |
// }).then(function() { | |
// console.log('setLocalDescription() succsess in promise'); | |
// }).catch(function(err) { | |
// console.error(err); | |
// }); | |
// } | |
// } | |
//↓ | |
// Offer SDPを生成する | |
function makeOffer() { | |
peerConnection = prepareNewConnection(); | |
peerConnection.onnegotiationneeded = function(){ | |
peerConnection.createOffer() | |
.then(function (sessionDescription) { | |
console.log('createOffer() succsess in promise'); | |
return peerConnection.setLocalDescription(sessionDescription); | |
}).then(function() { | |
console.log('setLocalDescription() succsess in promise'); | |
sendSdp(peerConnection.localDescription); | |
}).catch(function(err) { | |
console.error(err); | |
}); | |
} | |
} | |
/** | |
* | |
*/ | |
// Answer SDPを生成する | |
// function makeAnswer() { | |
// console.log('sending Answer. Creating remote session description...' ); | |
// if (! peerConnection) { | |
// console.error('peerConnection NOT exist!'); | |
// return; | |
// } | |
// peerConnection.createAnswer() | |
// .then(function (sessionDescription) { | |
// console.log('createAnswer() succsess in promise'); | |
// return peerConnection.setLocalDescription(sessionDescription); | |
// }).then(function() { | |
// console.log('setLocalDescription() succsess in promise'); | |
// }).catch(function(err) { | |
// console.error(err); | |
// }); | |
// } | |
//↓ | |
// Answer SDPを生成する | |
function makeAnswer() { | |
console.log('sending Answer. Creating remote session description...' ); | |
if (! peerConnection) { | |
console.error('peerConnection NOT exist!'); | |
return; | |
} | |
peerConnection.createAnswer() | |
.then(function (sessionDescription) { | |
console.log('createAnswer() succsess in promise'); | |
return peerConnection.setLocalDescription(sessionDescription); | |
}).then(function() { | |
console.log('setLocalDescription() succsess in promise'); | |
sendSdp(peerConnection.localDescription); | |
}).catch(function(err) { | |
console.error(err); | |
}); | |
} | |
/** | |
* | |
*/ | |
// SDPのタイプを判別しセットする | |
function onSdpText() { | |
let text = textToReceiveSdp.value; | |
if (peerConnection) { | |
// Offerした側が相手からのAnserをセットする場合 | |
console.log('Received answer text...'); | |
let answer = new RTCSessionDescription({ | |
type : 'answer', | |
sdp : text, | |
}); | |
setAnswer(answer); | |
} | |
else { | |
// Offerを受けた側が相手からのOfferをセットする場合 | |
console.log('Received offer text...'); | |
let offer = new RTCSessionDescription({ | |
type : 'offer', | |
sdp : text, | |
}); | |
setOffer(offer); | |
} | |
textToReceiveSdp.value =''; | |
} | |
// Offer側のSDPをセットした場合の処理 | |
function setOffer(sessionDescription) { | |
if (peerConnection) { | |
console.error('peerConnection alreay exist!'); | |
} | |
peerConnection = prepareNewConnection(); | |
peerConnection.onnegotiationneeded = function () { | |
peerConnection.setRemoteDescription(sessionDescription) | |
.then(function() { | |
console.log('setRemoteDescription(offer) succsess in promise'); | |
makeAnswer(); | |
}).catch(function(err) { | |
console.error('setRemoteDescription(offer) ERROR: ', err); | |
}); | |
} | |
} | |
// Answer側のSDPをセットした場合の処理 | |
function setAnswer(sessionDescription) { | |
if (! peerConnection) { | |
console.error('peerConnection NOT exist!'); | |
return; | |
} | |
peerConnection.setRemoteDescription(sessionDescription) | |
.then(function() { | |
console.log('setRemoteDescription(answer) succsess in promise'); | |
}).catch(function(err) { | |
console.error('setRemoteDescription(answer) ERROR: ', err); | |
}); | |
} | |
/** | |
* 切断処理追加 | |
*/ | |
// WebRTCを利用する準備をする | |
// function prepareNewConnection() { | |
// // ICEのステータスが変更になったときの処理 | |
// peer.oniceconnectionstatechange = function() { | |
// console.log('ICE connection Status has changed to ' + peer.iceConnectionState); | |
// switch (peer.iceConnectionState) { | |
// case 'closed': | |
// case 'failed': | |
// // ICEのステートが切断状態または異常状態になったら切断処理を実行する | |
// if (peerConnection) { | |
// hangUp(); | |
// } | |
// break; | |
// case 'dissconnected': | |
// break; | |
// } | |
// }; | |
// } | |
// P2P通信を切断する | |
// function hangUp(){ | |
// if (peerConnection) { | |
// if(peerConnection.iceConnectionState !== 'closed'){ | |
// peerConnection.close(); | |
// peerConnection = null; | |
// cleanupVideoElemet(remoteVideo); | |
// textForSendSdp.value = ''; | |
// textToReceiveSdp.value = ''; | |
// return; | |
// } | |
// } | |
// console.log('peerConnection is closed.'); | |
// } | |
//↓ | |
// P2P通信を切断する | |
function hangUp(){ | |
if (peerConnection) { | |
if(peerConnection.iceConnectionState !== 'closed'){ | |
peerConnection.close(); | |
peerConnection = null; | |
let obj = { type: 'close' }; | |
let message = JSON.stringify(obj); | |
console.log('sending close message'); | |
ws.send(message); | |
cleanupVideoElemet(remoteVideo); | |
textForSendSdp.value = ''; | |
textToReceiveSdp.value = ''; | |
return; | |
} | |
} | |
console.log('peerConnection is closed.'); | |
} | |
// ビデオエレメントを初期化する | |
function cleanupVideoElemet(element) { | |
element.pause(); | |
if ('srcObject' in element) { | |
element.srcObject = null; | |
} | |
else { | |
if (element.src && (element.src !== '') ) { | |
window.URL.revokeObjectURL(element.src); | |
} | |
element.src = ''; | |
} | |
} | |
// シグナリングサーバへ接続する | |
let wsUrl = 'ws://localhost:3001/'; | |
let ws = new WebSocket(wsUrl); | |
ws.onopen = function(evt) { | |
console.log('ws open()'); | |
}; | |
ws.onerror = function(err) { | |
console.error('ws onerror() ERR:', err); | |
}; | |
ws.onmessage = function(evt) { | |
console.log('ws onmessage() data:', evt.data); | |
let message = JSON.parse(evt.data); | |
if (message.type === 'offer') { | |
// offer 受信時 | |
console.log('Received offer ...'); | |
textToReceiveSdp.value = message.sdp; | |
let offer = new RTCSessionDescription(message); | |
setOffer(offer); | |
} | |
else if (message.type === 'answer') { | |
// answer 受信時 | |
console.log('Received answer ...'); | |
textToReceiveSdp.value = message.sdp; | |
let answer = new RTCSessionDescription(message); | |
setAnswer(answer); | |
} | |
else if (message.type === 'candidate') { | |
// ICE candidate 受信時 | |
console.log('Received ICE candidate ...'); | |
let candidate = new RTCIceCandidate(message.ice); | |
console.log(candidate); | |
addIceCandidate(candidate); | |
} | |
}; | |
// ICE candaidate受信時にセットする | |
function addIceCandidate(candidate) { | |
if (peerConnection) { | |
peerConnection.addIceCandidate(candidate); | |
} | |
else { | |
console.error('PeerConnection not exist!'); | |
return; | |
} | |
} | |
// ICE candidate生成時に送信する | |
function sendIceCandidate(candidate) { | |
console.log('---sending ICE candidate ---'); | |
let obj = { type: 'candidate', ice: candidate }; | |
let message = JSON.stringify(obj); | |
console.log('sending candidate=' + message); | |
ws.send(message); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment