Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
DataChannel を利用した ホワイトボードアプリ開発事例
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
hidekuni KAJITA
October 09, 2018
Programming
1k
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
DataChannel を利用した ホワイトボードアプリ開発事例
hidekuni KAJITA
October 09, 2018
More Decks by hidekuni KAJITA
See All by hidekuni KAJITA
あれのその後.pdf
hidenba
0
34
NVIDIABroadcast便利
hidenba
0
140
レバーレスアケコンを作った話
hidenba
0
85
「冒険できる社会」を実現する “あしたのチーム”
hidenba
0
170
すぐできるDocker
hidenba
0
1.3k
リズムから生まれるアジャイルな開発
hidenba
0
620
Other Decks in Programming
See All in Programming
php-fpmのプロセスが枯渇した日-調査・対処・そして本当にやるべきだったこと-
shibuchaaaan
0
120
AIエージェントで 変わるAndroid開発環境
takahirom
2
710
Prismを使った型安全な暗号化_関数型まつり2026
_fhhmm
0
150
yield再入門 #phpcon
o0h
PRO
0
710
霧の中の代数的エフェクト
funnyycat
1
410
SREは、MCPとSRE Agentをこう使え!
kazumax55
0
150
ビデオ通話が繋がる0.2秒で何が起きているのか
supurazako
2
150
全PRの83%がAIレビューだけでマージできるようになった開発組織はその後どうなったか
athug
0
280
AI時代のPHPer生存戦略 ~「言語、もうなんでもよくない?」に本気で向き合う~
vivion
0
140
共通化で考えるべきは、実装より公開する型だった
codeegg
0
270
はてなアカウント基盤 State of the Union
cockscomb
1
1.3k
分散システム、なんですぐ死んでしまうん?耐障害性を高めたいあなたのためのレジリエンスパターン入門
mshibuya
7
6.7k
Featured
See All Featured
Measuring Dark Social's Impact On Conversion and Attribution
stephenakadiri
2
240
Crafting Experiences
bethany
1
230
Agile Leadership in an Agile Organization
kimpetersen
PRO
0
190
Build The Right Thing And Hit Your Dates
maggiecrowley
39
3.3k
We Analyzed 250 Million AI Search Results: Here's What I Found
joshbly
1
1.6k
Agile that works and the tools we love
rasmusluckow
331
22k
Technical Leadership for Architectural Decision Making
baasie
3
440
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.5k
Fireside Chat
paigeccino
42
4k
What Being in a Rock Band Can Teach Us About Real World SEO
427marketing
0
1.1k
Building Flexible Design Systems
yeseniaperezcruz
330
40k
Reflections from 52 weeks, 52 projects
jeffersonlam
356
21k
Transcript
DataChannel を利用した ホワイトボードアプリ開発事例 2018/10/9 WebRTC Meetup Tokyo #19 永和システムマネジメント @kunitoo
@hide_nba
2 おしながき • Linkup の概要 • Linkup の機能 • Linkup
の構成 • DataChannel の活用 • 画面共有 • 各クライアントの表示名 • ココさす • ホワイトボード
自己紹介 • 名前: 伊藤邦彦 • 所属: 永和システムマネジメント • 在住: 富山県
• Twitter: @kunitoo • GitHub: @kunitoo 3
4 永和システムマネジメント 管理部 未来企画室 組込み技術 センター 金融システム 事業部 ITサービス 事業部
医療システム 事業部 アジャイル 事業部 事業本部 永和システム マネジメント 【社員数】216名 【事業内容】・情報システム開発および構築 ・パッケージの開発および販売 ・コンピュータ、周辺機器の販売 ・開発技術コンサルティング、教育 【所在地】本社:福井県福井市問屋町3丁目111番地 支社:東京都千代田区神田須田町2丁目3番地1号 沖縄:沖縄県那覇市泊2丁目1-18T&C泊ビル 【在宅勤務制度】: 多くの社員が利用している 【リモートワーク】: 石川、富山に1名ずつ
5 Linkup の概要
6
Linkup • チームのためのリモートコラボレーションツール • 2017年9月頃から事業部の10%ルールとしてスタート • 顔を見ながら画面共有したい • 2018年4月頃から本格始動 •
ホワイトボードに書きながらビデオチャットしたい • 9月20日にオープンβとしてリリース • https://linkup.world/ 7
8 チーム名を決めて試してみて下さい
Linkup のコンセプト • Web に和じゃを作りたい • 執務室内中央のセミオープンな会議スペース • ディスプレイ、ホワイトボードがある •
オフィスのセミオープンな会議スペースに人が 集って議論をすぐスタートできる • 全員が見えるディスプレイ • ホワイトボードが利用できる • 人が集ったことが分かる • リモート(低帯域/低浸透性) から対面(広帯域/高 浸透性)のコミュニケーション 9
Linkup の機能 10
Linkup の機能 • ビデオチャット • 多人数での双方向チャット • ホワイトボード • 図や絵を描いてのイメージ共有
• 画面共有 • ココがさせる • チャット連携 • idobata/slack へのルーム状況の通知 • オープンスペース(実現予定) • ルームに入らずに、ホワイトボード、話している人が分かる • あいづち/うなずき(実現予定) 11
Linkup の利用シーン • チームの朝会 • チャット連携 • チーム内の相談やミーティング • ホワイトボード
• 画面共有 • ここがさせる • ふりかえり • 付箋 12
朝会 • Webhook を設定して おく • メンバー集る • 集っている様子が チャットで分かる
13 Webhook を設定 Idobta のチャット通知例
チーム内の相談やミーティング • チャットで呼びかける • 話題をホワイトボード に書き出す • 画面共有をする 14
チーム内の相談やミーティング • チャットで呼びかける • 話題をホワイトボード に書き出す • 画面共有をする 15
ふりかえり • 手元の付箋に書き溜 めることができる • ホワイトボードに張り つけてチームに共有す る 16
Linkup の構成 17
Linkup の技術要素 • フロントエンド • React • Canvas(fabric.js) • SkyWay
• CloudFront • バックエンド(API) • Ruby on Rails • GraphQL • ECS(Fargate) • インフラ • Terraform 18
DataChannel の活用 19
DataChannel の活用 • 画面共有 • 各クライアントの表示名 • ココさす • ホワイトボード
20
画面共有での利用 1. skyway-screenshare を利用してstreamオブジェクトを取得 2. 画面共有を始めたことを Data Channel で通知 3.
通知を受けた側から接続を開始する `peer.call` 4. 画面共有側で stream を設定して、接続を完了する 21
クライアント情報の共有 1. stream を受信したとき名前を送り、相手の名前を要求 する(REQUEST_DISPLAY_NAME) 2. 名前の要求が来たら、 a. 要求相手の名前を peerId
を元にカメラ stream と 紐付ける b. 自分の名前を送信する(DISPLAY_NAME) 22
ココさす • 画面共有の領域にCanvasを用 意、クリックした位置を取得 • video の表示しているサイズから 相対位置を割り出し送信する (HTMLVideoElement.videoHeight ,
videoWidth) • 受信側で相手のvideoサイズと自 分のvideoサイズから位置を割り 出しアニメーションを描画する 23
demo 24
交代 25
自己紹介 • 名前: かじたひでくに • 所属: 永和システムマネジメント • Twitter: @hide_nba
• GitHub: @hidenba 26
ホワイトボードで出来ること • 手書き 27
ホワイトボードで出来ること • 付箋 28
ホワイトボードで出来ること • 画像のアップロード/ダウンロード 29
demo 30
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
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
送受信しているデータの構造 { action: 'UPDATE_WHITEBOARD', data1: dataobject, data2: dataobject, data3: dataobject
} 33
受信時のイベントハンドリング 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
オブジェクトの追加 1. Objectの追加 2. Objectをシリアライズして JSONにする 3. JSONをサーバへ送信 4. Roomに接続しているPeer
と同期 35 send add on(data) 1. データ受信 2. JSONからObjectへ 3. Canvasに描画
追加操作の送信 const objectPayload = JSON.stringify(fabricObject) request(`${LINKUP_API_URL}/graphql`, query) room.send({ action: 'UPDATE_WHITEBOARD',
payload: objectPayload, operation: 'add', uuid: uuid }) 36
ホワイトボード更新イベント受信 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
ホワイトボード更新 switch (operation) { case 'add': this.addObjectFromJson(data) break case 'remove':
this.removeActionByUUID(prevOperation.uuid) break ... } 38
オブジェクトの移動 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)
削除操作の送信 const objectPayload = JSON.stringify(fabricObject) request(`${LINKUP_API_URL}/graphql`, query) room.send({ action: 'UPDATE_WHITEBOARD',
operation: 'remove', uuid: uuid }) 40
ホワイトボード更新イベント受信 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
ホワイトボード更新 switch (operation) { case 'add': this.addObjectFromJson(data) break case 'remove':
this.removeActionByUUID(uuid) break ... } 42
追加操作の送信 const objectPayload = JSON.stringify(fabricObject) request(`${LINKUP_API_URL}/graphql`, query) room.send({ action: 'UPDATE_WHITEBOARD',
payload: objectPayload, operation: 'add', uuid: uuid }) 43
ホワイトボード更新イベント受信 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
ホワイトボード更新 switch (operation) { case 'add': this.addObjectFromJson(data) break case 'remove':
this.removeActionByUUID(prevOperation.uuid) break ... } 45
46 チーム名を決めて試してみて下さい