LoginSignup
1
0

More than 5 years have passed since last update.

[webRTC for web vol1] まずは1対1で接続

Last updated at Posted at 2017-07-15

ブラウザでやります。

複数接続はこちら → 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>
1
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
0