こちらはSkyWay Advent Calendar 2018の最終日、25日目の記事です。
【前編】は、IoTLT Advent Calendar 2018の24日目の記事になります。
昨晩プレゼントをもらえたみなさまも、サンタクロースをやっていたみなさまも、おはようございます。
この記事は、Webリアルタイムクリスマスツリーをつくり、ローカルPCのブラウザからリモートのPCを経由してクリスマスツリーのLEDを制御し、そのリアルタイム映像をWebRTCを経由して虚ろに眺めるというプロダクトの後編となります。(長い)
いきなりこちらに来た方は、まずはじめに【前編】をご覧ください。
なにをつくるんだっけ
組み込みWebRTCに心が折れ、WebBluetoothに浮気して、最終的にこんな感じにしたくなったのでした↓
前編の記事では、WebからBluetoothでクリスマスツリーを操作するところまでできました。
では次にWebRTCとつなげるところからはじめましょう。
SkyWayで簡単にWebRTCを試す
SkyWayとは、WebRTCにおけるサーバサイドを全部なんとかしてくれる素敵なシステムです。
知らなかった方は以下をどうぞ。
SkyWay - Enterprise Cloud WebRTC Platform
ところで、僕はSkyWay Advent Calendar 2018の23日目にも1つ記事を書かせてもらっております。
書くことになった経緯は忘れたのですが、Qiitaから通知があって思い出して頑張って書きました。
そうしたら、こんなにもWebRTCって簡単にできるのか?という気持ちになり、じゃあクリスマスツリーぐらいリアルタイムできるよね🎄🎉となって今に至るわけです。
さて、上述の記事を要約すると
- サンプルプログラムには「ビデオチャット」と「テキストチャット」がある
- しかしビデオとテキストの両方を同時に送るサンプルがない
- 作った
というものになります。
つまり、この時点ですでに
- 映像・音声・文字列が同時に送受信できる
→制御コマンドの送信と、相手の映像の受信が同時にできる
ということになります。これはもう勝ったも同然ですね🍷🍾
テキスト送受信機能つきビデオチャットを改造する
まずは拙作のこちらのリポジトリのソースをもとに改良を加えてゆきます。
GitHub: ukkz/skyway-video-and-text-chat
HTML
<!-- Video area -->
<div class="pure-u-2-3" id="video-container">
<div style="text-align:left;">
BLE Local Connection: <span id="ble_dev_name">none</span> <button id="btn_ble_ctrl">Connect</button><br>
Command destination: <button id="command_send_to">LOCAL</button><br>
<br>
Mouse - X <input type="text" id="mouse_x" size="20"> Diff: <input type="text" id="mouse_x_diff" size="20"><br>
Mouse - Y <input type="text" id="mouse_y" size="20"> Diff: <input type="text" id="mouse_y_diff" size="20"><br>
Moving: <input type="text" id="mouse_moving" size="20"> State: 🎄<span class="tree_state" hidden>✨</span><br>
</div>
<div id="their-videos"></div>
<video id="my-video" muted="true" autoplay playsinline></video>
</div>
もともとのHTMLのビデオ表示部分に、以下の項目を追加しました。
- BLEデバイス接続・切断ボタン
- コマンド送信先選択(このブラウザにつながったデバイスか、WebRTCのPeerに送信するか)
- マウスポインタX座標と移動差分
- マウスポインタY座標と移動差分
- XY移動速度の積とツリーLED発火インジケータ
前編記事の最後では、マウスを動かすとツリーに直接コマンドが送られるように作りましたが
そのUI部分を移植したものになります。
JS
JavaScriptについては、WebBluetooth部分と、WebRTC(SkyWay SDK)部分にわけました。
WebUI部分
// コマンド送信先切り替え
// 表示だけ切り替えて、あとは実際に送信の直前に参照
$('#command_send_to').on('click', () => {
if ($('#command_send_to').text() == 'LOCAL') {
$('#command_send_to').text('PEERS');
} else {
$('#command_send_to').text('LOCAL');
}
});
コマンド送信先選択ボタンは、単純にDOMのテキストをtoggleしているだけです。
実際に送信する前に参照してどちらに送るか決めています。
// マウス位置取得
$(window).mousemove(function() {
// 差分取得
var diffX = posX-event.clientX;
var diffY = posY-event.clientY;
var moving = diffX * diffY;
// Aチャンネル
if (diffX >= 50)
sendCommandWithSwitch('A0');
else if (diffX <= -50)
sendCommandWithSwitch('A1');
// Bチャンネル
if (diffY >= 50)
sendCommandWithSwitch('B0');
else if (diffY <= -50)
sendCommandWithSwitch('B1');
// Cチャンネル
if (moving >= 150)
sendCommandWithSwitch('C0');
else if (moving <= -150)
sendCommandWithSwitch('C1');
else
sendCommandWithSwitch('X0');
// ブラウザ側の表示を更新
$('#mouse_x_diff').val(diffX);
$('#mouse_y_diff').val(diffY);
$('#mouse_x').val(event.clientX);
$('#mouse_y').val(event.clientY);
$('#mouse_moving').val(moving);
posX = event.clientX;
posY = event.clientY;
});
マウスが動くたびに発火するイベントはWebRTCスクリプト側に記述しました。
イベントの発火レートの上限がどこまであるか、というか一定であるかすらわからないので、まさかずっとゼロのままなのでは…… と思いながら試してみたらそれなりに差分は抽出できました。詳しい人教えてくださいな。
コマンドの送信
// 送信先切り替え用
function sendCommandWithSwitch(code) {
// ボタンの文字列を参照してLOCALかPEERSで切り替える
if ($('#command_send_to').text() == 'LOCAL') {
// LOCALのとき:通常コマンドを使う
sendToLocalTree(code);
} else {
// PEERSのとき:コマンド用の接頭辞をつけて送信する
room.send('COMMAND_' + code);
}
}
こちらの関数では、先ほどの送信先切り替えボタンのtextを読んで、ローカルに接続されたBLEに送るか、それともWebRTCで送るか、を判断しています。
WebRTCで送るときはRoomオブジェクトでroom.send()
をするだけでOKですが、テキストチャットの通常メッセージと区別するために、COMMAND_
を先頭に付加しています。
コマンドの受信
room.on('data', message => {
if (message.data.substring(0,8) == 'COMMAND_') {
// COMMAND_ で始まるメッセージはコマンド扱い
// ツリー操作に利用する
sendToLocalTree(message.data.substring(8)); // コマンド部分のみ送る
} else {
// ふつうのメッセージ
messages.prepend('<div><span class="peer">' + message.src.substr(0,8) + '</span>: ' + message.data + '</div>');
}
});
room.on('data', コールバック)
の部分で、まずmessage.data
の先頭8文字がCOMMAND_
であるかどうかで制御コマンドかどうか判定します。で、到着メッセージをそのままDOMに追加していくとコマンド文字列まみれでえらいことになるので、コマンドじゃない場合にのみDOMにprependするようにします。
できた
こんな画面になりました。
使い方としては、自分のPCと、クリスマスツリーの前に別のPCをもう一つ用意し、両方からこのページをブラウザで開いて同じルームに参加します。
クリスマスツリー前PCは、WebBluetoothでNefryに接続し、コマンド送信先をその接続したNefry宛て(LOCAL)にしておきます。ツリーを眺めるための自分のPCは、WebBluetoothは接続しませんが、コマンド送信先をPEERにしておくことで、マウスカーソルの動きがデータとしてWebRTCでツリー前PCに送信されます。
試してみた動画
WebRealTimeChristmastree at holy night - YouTube
クリスマスの夜に、部屋を真っ暗にして撮ってみました。
みんなもNefryBTやSkyWayでレッツクリスマスナイッ🎄✨
サンプル
まずお手持ちのNefry BTに以下のスケッチを書き込んでください。
ピン配置などはお手持ちのクリスマスツリーにあわせて適宜変更してくださいねー
NefryXmasSkyWay.ino
あとはこちらのページを2台のPCで表示して、クリスマスツリーとの対話を楽しんでください。
GitHub Pages
まとめ
- クリスマスツリーはWebでリアルタイムになれる!!!!!(?)
- WebRTC畑の方も、SkyWayな方も、ぜひマイコンボードとかWebBluetoothにも触れてみてください。
- IoT勢のみなさんも、SkyWayがなかなか簡単で楽しいので、ハードウェア監視などにいかがでしょうか。
- ここまで読んでいただき非常にメリークリスマスです🍖🍺よいお年をお過ごし下さいませ🎍