ブラウザでやります。
複数接続はこちら → webRTC for web vol2
成果物
環境
クロム
実装
wamp
ライブラリは autobahn
wampサーバのとりあえずの実装
wamp.js
/**
* @param {onReceiveAnswer, onReceiveOffer, onReceiveCandidate} callbacks
*/
let Wamp = function(callbacks){
this.callbacks = callbacks
}
Wamp.config = {
HandshakeEndpint: "wss://nakadoribooks-webrtc.herokuapp.com"
, Topic: {
Anser: "com.nakadoribook.webrtc.answer"
, Offer: "com.nakadoribook.webrtc.offer"
, Candidate: "com.nakadoribook.webrtc.candidate"
}
}
Wamp.prototype = {
// interface
connect: function(){
let connection = new autobahn.Connection({
url: Wamp.config.HandshakeEndpint
});
connection.onopen = (session, details) => { this.onOpen(session, details) }
connection.onclose = (reason, details) => { this.onClose(session, details) }
connection.open()
this.connection = connection
}
, publishOffer: function(sdp){
let str = JSON.stringify(sdp)
this.session.publish(Wamp.config.Topic.Offer, [str]);
}
, publishAnswer: function(sdp){
let str = JSON.stringify(sdp)
this.session.publish(Wamp.config.Topic.Anser, [str]);
}
, publishCandidate: function(candidate){
let str = JSON.stringify(candidate)
this.session.publish(Wamp.config.Topic.Candidate, [str]);
}
// implements
, onOpen: function(session, details){
this.session = session
// subscribe
session.subscribe(Wamp.config.Topic.Anser, (args, kwArgs)=>{ this.onReceiveAnswer(args, kwArgs) });
session.subscribe(Wamp.config.Topic.Offer, (args, kwArgs)=>{ this.onReceiveOffer(args, kwArgs) });
session.subscribe(Wamp.config.Topic.Candidate, (args, kwArgs)=>{ this.onReceiveCandidate(args, kwArgs) });
},
onClose: function(reason, details){
console.log("onClose")
console.log(reason)
}
, onReceiveAnswer: function(args){
let sdp = JSON.parse(args[0])
this.callbacks.onReceiveAnswer(sdp)
}
, onReceiveOffer: function(args){
let sdp = JSON.parse(args[0])
this.callbacks.onReceiveOffer(sdp)
}
, onReceiveCandidate: function(args){
let candidate = JSON.parse(args[0])
this.callbacks.onReceiveCandidate(candidate)
}
}
Webrtc
この辺りを参考に
https://developer.mozilla.org/ja/docs/Web/API/RTCPeerConnection
wamp.js
/**
* @param {onIceCandidate, onLocalStream, onAddedStream} callbacks
*/
let Webrtc = function(callbacks){
this.callbacks = callbacks
this.setupPeerConnection()
this.setupStream()
}
Webrtc.config = {
IceUrl: "stun:stun.l.google.com:19302"
}
Webrtc.prototype = {
// interface ------
createOffer: function(callback){
this.peerConnection.createOffer((descriptin) => {
this.peerConnection.setLocalDescription(descriptin);
callback(descriptin)
}, (error) => {
});
}
, receiveAnswer: function(sdp){
this.peerConnection.setRemoteDescription(sdp).then(()=>{
})
}
, receiveOffer: function(sdp, createdAnswer){
this.peerConnection.setRemoteDescription(sdp).then(()=>{
this.peerConnection.createAnswer().then((answerSdp) => {
this.peerConnection.setLocalDescription(answerSdp)
createdAnswer(answerSdp)
})
})
}
, receiveCandidate: function(candidate){
this.peerConnection.addIceCandidate(candidate)
}
// implements -------
, setupPeerConnection: function(){
let peerConnection = new RTCPeerConnection({iceServers: [{url: Webrtc.config.IceUrl}]});
this.peerConnection = peerConnection
peerConnection.onicecandidate = (event) => {
let candidate = event.candidate
if (candidate == null) {
return;
}
this.callbacks.onIceCandidate(candidate)
};
peerConnection.onaddstream = (event) => {
let stream = event.stream
if (stream == null){
return
}
this.callbacks.onAddedStream(stream)
};
peerConnection.onicegatheringstatechange = () =>{
switch(peerConnection.iceGatheringState){
case "complete":
this.callbacks.onGacheringComplete()
break;
}
}
}
, setupStream: function(){
navigator.mediaDevices.getUserMedia({ audio: true, video: true })
.then((stream) => {
this.stream = stream
this.peerConnection.addStream(this.stream)
this.callbacks.onLocalStream(stream)
})
.catch((err) => {
console.error(err)
});
}
}
アプリケーション
index.js
let App = function(){
this.init()
}
App.prototype = {
offered: false
, init: function(){
// wamp
this.wamp = new Wamp({
onReceiveAnswer: (sdp) => {
if (!this.offered) { return; }
this.webrtc.receiveAnswer(sdp)
}
, onReceiveOffer: (sdp) => {
if (this.offered) { return; }
this.webrtc.receiveOffer(sdp, (answerSdp)=>{
this.wamp.publishAnswer(answerSdp)
})
}
, onReceiveCandidate: (candidate) => {
if(this.offered){ return; }
this.webrtc.receiveCandidate(candidate)
}
})
// webrtc
this.webrtc = new Webrtc({
onIceCandidate: (candidate) => {
this.wamp.publishCandidate(candidate)
}
,onLocalStream: (stream)=>{
let localVideo = document.querySelector("#loacalVideo")
localVideo.src = window.URL.createObjectURL(stream);
localVideo.play()
}
,onAddedStream: (stream) => {
let remoteVideo = document.querySelector("#remoteVideo")
remoteVideo.src = window.URL.createObjectURL(stream);
remoteVideo.play()
}
})
// event
this.registerDomEvent()
// connet
this.wamp.connect()
},
registerDomEvent: function(){
document.querySelector("#offerButton").addEventListener("click", (event)=>{
this.offered = true
this.webrtc.createOffer((descriptin)=>{
this.wamp.publishOffer(descriptin)
})
}, false);
}
}
window.onload = function(){
let app = new App()
}
index.html
<html>
<body>
<div style="position:relative;">
<video id="remoteVideo" width="400" height="300"
style="background-color:#cccccc;"
></video>
<video id="loacalVideo" width="100" height="70"
style="background-color:#000000;position:absolute;top:0px;left:0px;"
></video>
</div>
<div>
<button id="offerButton">CreateOffer</button>
</div>
<script src="autobahn.min.js"></script>
<script src="wamp.js"></script>
<script src="webrtc.js"></script>
<script src="index.js"></script>
</body>
</html>