WebRTCはブラウザ同士で直接動画や音声などのリアルタイムなコミュニケーションを実現するAPIの定義になります。基本的にはICEサーバーを使って自分の情報を取得し、相手のブラウザにそれを認識させる事によってブラウザ同士の通信を実現します。
WebRTCの仕組み
WebRTCではICEサーバーという特殊なサーバーを用います。ブラウザ同士の通信にはNATがあるため、ICEサーバーを使ってこの問題を解決します。ICEサーバーにはSTUN、TURNというものがあります。
Googleなども無料でSTUNを公開していますが、今回はSkyWayを使うので、そこはあまり意識しなくてもいいかもしれません。
ICEサーバーでは自分の情報を取得することができます。
そしてその取得した情報を相手に伝えないといけません。
その情報を相手に伝える為にシグナリングサーバーというサーバーを使います。
このサーバーは相手に情報を教えてあげる仲介をしてくれます。
自分はNode.js + socket.ioで実装しました。
実際にはシグナリングサーバーは必須ではありません。
例えば自分のIDを相手にメールやチャットなどで伝える事で自分のブラウザへ入力する事で通信を開始する事ができます。
実際にシグナリングさせる
実装
今回はNuxt.jsを用いて実装しました。
ソースコードは長くなってしまうので抜粋しています。
挙動としては、発信側が通信を開始し、受信側が承認することで開始するイメージです。
server
const io = socketio.listen(server)
io.on('connection', socket => {
socket.on('send peer id', id => {
io.emit('emit peer id', id)
})
socket.on('answer peer id', id => {
io.emit('answer peer id', id)
})
socket.on('disconnect', () => {
console.log('disconnected')
})
})
cliant(発信側)
async created() {
this.company = services.find(
service => service.slug === this.$route.params.company
)
this.inquiry = this.$route.params.inquiry || 'hoge'
const constraints = { audio: true, video: true }
const stream = await navigator.mediaDevices.getUserMedia(constraints)
this.user.stream = stream
},
mounted() {
this.socket = io()
this.socket.on('answer peer id', id => {
this.peer.call(id, this.user.stream)
})
this.peer = new Peer({
key: this.APIKey,
debug: 3
})
this.peer.on('call', call => {
call.answer(this.user.stream)
call.on('stream', stream => {
this.operatorStream = stream
const el = document.getElementById('video1')
el.srcObject = stream
el.play()
})
})
},
methods: {
call() {
this.socket.emit('send peer id', this.peer.id)
}
}
cliant(受信側)
async created() {
const constraints = { audio: true, video: true }
const stream = await navigator.mediaDevices.getUserMedia(constraints)
this.localStream = stream
},
mounted() {
this.socket = io()
this.socket.on('emit peer id', id => this.user.id = id)
this.peer = new Peer({
key: this.APIKey,
debug: 3
})
this.peer.on('call', call => {
call.answer(this.localStream)
call.on('stream', stream => {
this.userStream = stream
const el = document.getElementById('videoUser')
el.srcObject = stream
el.play()
})
})
},
methods: {
answered() {
const call = this.peer.call(this.user.id , this.localStream);
call.on('stream', stream => {
this.socket.emit('answer peer id', this.peer.id)
});
},
},
videoタグをrefs
で取得てsrcObject
に入れたかったのですが、うまく取得できなかったのでid
で取得しています。その他にもtemplateで<video :srcObject='stream'>
もやってみましたがダメでした。
最後に
WebRTCを取り扱うのであれば、今回のようなSkyWayやPeer.jsを使うと簡単に実現できます。
実運用を考えるとSTUNサーバーを自前で用意したり、フロントエンドの技術だけではまかないきれない部分も出て来ますが、試してみるにはよいのではと思います。(有料プランもありだと思います)