Upgrade to Pro — share decks privately, control downloads, hide ads and more …

DataChannel を利用した ホワイトボードアプリ開発事例

DataChannel を利用した ホワイトボードアプリ開発事例

hidekuni KAJITA

October 09, 2018
Tweet

More Decks by hidekuni KAJITA

Other Decks in Programming

Transcript

  1. 2 おしながき • Linkup の概要 • Linkup の機能 • Linkup

    の構成 • DataChannel の活用 • 画面共有 • 各クライアントの表示名 • ココさす • ホワイトボード
  2. 4 永和システムマネジメント 管理部 未来企画室 組込み技術 センター 金融システム 事業部 ITサービス 事業部

    医療システム 事業部 アジャイル 事業部 事業本部 永和システム マネジメント 【社員数】216名 【事業内容】・情報システム開発および構築       ・パッケージの開発および販売       ・コンピュータ、周辺機器の販売       ・開発技術コンサルティング、教育  【所在地】本社:福井県福井市問屋町3丁目111番地       支社:東京都千代田区神田須田町2丁目3番地1号       沖縄:沖縄県那覇市泊2丁目1-18T&C泊ビル 【在宅勤務制度】: 多くの社員が利用している 【リモートワーク】: 石川、富山に1名ずつ
  3. 6

  4. Linkup のコンセプト • Web に和じゃを作りたい • 執務室内中央のセミオープンな会議スペース • ディスプレイ、ホワイトボードがある •

    オフィスのセミオープンな会議スペースに人が 集って議論をすぐスタートできる • 全員が見えるディスプレイ • ホワイトボードが利用できる • 人が集ったことが分かる • リモート(低帯域/低浸透性) から対面(広帯域/高 浸透性)のコミュニケーション 9
  5. Linkup の機能 • ビデオチャット • 多人数での双方向チャット • ホワイトボード • 図や絵を描いてのイメージ共有

    • 画面共有 • ココがさせる • チャット連携 • idobata/slack へのルーム状況の通知 • オープンスペース(実現予定) • ルームに入らずに、ホワイトボード、話している人が分かる • あいづち/うなずき(実現予定) 11
  6. Linkup の技術要素 • フロントエンド • React • Canvas(fabric.js) • SkyWay

    • CloudFront • バックエンド(API) • Ruby on Rails • GraphQL • ECS(Fargate) • インフラ • Terraform 18
  7. 画面共有での利用 1. skyway-screenshare を利用してstreamオブジェクトを取得 2. 画面共有を始めたことを Data Channel で通知 3.

    通知を受けた側から接続を開始する `peer.call` 4. 画面共有側で stream を設定して、接続を完了する 21
  8. ココさす • 画面共有の領域にCanvasを用 意、クリックした位置を取得 • video の表示しているサイズから 相対位置を割り出し送信する (HTMLVideoElement.videoHeight ,

    videoWidth) • 受信側で相手のvideoサイズと自 分のvideoサイズから位置を割り 出しアニメーションを描画する 23
  9. SkyWayでのデータ送信 const peer = new Peer({ key: SKYWAY_KEY, debug: LOG_LEVEL

    }) const room = peer.joinRoom(roomName, { mode: 'sfu', stream: stream }) room.send({data: 'send data'}) 31
  10. SkyWayでのデータ受信 const peer = new Peer({ key: SKYWAY_KEY, debug: LOG_LEVEL

    }) const room = peer.joinRoom(roomName, { mode: 'sfu', stream: stream }) room.on('data', (data) => { console.log(data) }) 32
  11. 受信時のイベントハンドリング room.on('data', dataObject => { if (dataObject.data.action === 'START_SCREEN_SHARE') {

    } else if (dataObject.data.action === 'STOP_SCREEN_SHARE') { } else if (dataObject.data.action === 'REQUEST_DISPLAY_NAME') { } else if (dataObject.data.action === 'UPDATE_WHITEBOARD') { const { id, payload, operation, uuid } = dataObject.data update(id, operation, uuid, payload) ... }) 34
  12. ホワイトボード更新イベント受信 room.on('data', dataObject => { if (dataObject.data.action === 'START_SCREEN_SHARE') {

    } else if (dataObject.data.action === 'STOP_SCREEN_SHARE') { } else if (dataObject.data.action === 'REQUEST_DISPLAY_NAME') { } else if (dataObject.data.action === 'UPDATE_WHITEBOARD') { const { id, payload, operation, uuid } = dataObject.data update(id, operation, uuid, payload) }) 37
  13. オブジェクトの移動 1. Objectの移動 2. Objectの削除情報を各クライア ントと同期 3. 削除情報をサーバへ送信 4. 移動後のObjectをシリアライズし

    てJSONにする 5. JSONをサーバへ送信 6. 各Peerと同期 39 send remove on(data) 1. 削除イベント受信 2. UUIDの一致するObjectを削除 3. 移動後の追加データ受信 4. JSONからObjectへ 5. Canvasに描画 send add on(data)
  14. ホワイトボード更新イベント受信 room.on('data', dataObject => { if (dataObject.data.action === 'START_SCREEN_SHARE') {

    } else if (dataObject.data.action === 'STOP_SCREEN_SHARE') { } else if (dataObject.data.action === 'REQUEST_DISPLAY_NAME') { } else if (dataObject.data.action === 'UPDATE_WHITEBOARD') { const { id, payload, operation, uuid } = dataObject.data update(id, operation, uuid, payload) }) 41
  15. ホワイトボード更新イベント受信 room.on('data', dataObject => { if (dataObject.data.action === 'START_SCREEN_SHARE') {

    } else if (dataObject.data.action === 'STOP_SCREEN_SHARE') { } else if (dataObject.data.action === 'REQUEST_DISPLAY_NAME') { } else if (dataObject.data.action === 'UPDATE_WHITEBOARD') { const { id, payload, operation, uuid } = dataObject.data update(id, operation, uuid, payload) }) 44