これは HoloLens Advent Calendar 2017 の 15 日目の記事です.
はじめに
HoloLens に搭載されている Microsoft Edge で音声の双方向通信がしたい.そこで WebRTC を使おうと思っていたのですが問題がありました.WebRTC を使用するための API が実装されていなかったのです.
WebRTC が実装されていない
現在のデスクトップ版の Edge は全く関係がありません.例えば WebRTC を使用したサービスである appear.in – one click video conversations もデスクトップ版の Edge であれば問題なく動作します.同じバージョンの HoloLens 版の Windows に搭載されている Edge で,この問題が起こります.
WinJS で WebRTC を動かすサンプルもあります.ですが WinJS 自体が裏で Edge を使用しているのか HoloLens 上では同様に WebRTC の API を使用することができません.同じアプリケーションであっても動作させる環境によって差異があります.
音声の双方向通信を実装する
WebSocket ではバイナリを送信することができます.音声のデータを WebSocket を介してやりとりすることで快適にとまではいかずとも擬似的に実装できます.
WebSocket のサーバには Node.js を使います.HoloLens の Edge でも getUserMedia や AudioContext は使うことができるためこれらを使用して音声の取得を行います.その後 WebSocket で音声のデータをサーバに送信し,そこから他のブラウザにも送信するようにします.
WebSocket のサーバは ws というライブラリを使用しました.以下のように,ブラウザ側から受け取った音声のデータを,そのまま他のブラウザに送信するようにしています.
const Server = require( 'ws' ).Server
...
const wss = new Server( {
server: server
} )
let connections = []
wss.on( 'connection', ws => {
connections.push( ws )
...
ws.on( 'message', audio => {
console.log( audio )
connections.filter( connection => connection !== ws ).forEach( connection => {
connection.send( audio )
} )
} )
} )
ブラウザ側では音声のデータを取得して,WebSocket を介してサーバに送信しています.
const ws = new WebSocket( 'ws://' + window.document.location.host )
const send = binary => {
ws.binaryType = 'arraybuffer'
ws.send( binary )
}
navigator.mediaDevices.getUserMedia( {
audio: true,
video: false
} )
.then( stream => {
const context = new AudioContext()
const source = context.createMediaStreamSource( stream )
const processor = context.createScriptProcessor( 1024, 1, 1 )
source.connect( processor )
processor.connect( context.destination )
processor.onaudioprocess = e => {
send( e.inputBuffer.getChannelData( 0 ) )
}
} )
また,WebSocket を介して受け取った音声のデータから音声を再生を行います.
const audioContext = new AudioContext()
ws.onmessage = buffer => {
const data = new Float32Array( buffer.data )
const source = audioContext.createBufferSource()
const audioBuffer = audioContext.createBuffer( 1, 1024, audioContext.sampleRate )
audioBuffer.getChannelData( 0 ).set( data )
source.buffer = audioBuffer
source.connect( audioContext.destination )
source.start()
}
まとめ
擬似的にではありますが,HoloLens とその他のブラウザで音声のやりとりを行うことができました.