Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
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
1.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
41
NVIDIABroadcast便利
hidenba
0
150
レバーレスアケコンを作った話
hidenba
0
91
「冒険できる社会」を実現する “あしたのチーム”
hidenba
0
180
すぐできるDocker
hidenba
0
1.4k
リズムから生まれるアジャイルな開発
hidenba
0
630
Other Decks in Programming
See All in Programming
GraphRAGのKnowledge Graphを 直接!見る/View-GraphRAG's-KnowledgeGraph-directly!
tyumugi1113
1
380
Java 27新機能 / Java 27 new features
kishida
2
160
技術的負債を組織課題として解く-増えすぎたマイクロサービスとの戦い-
reimaru
1
2.3k
Kiroで創り、AgentCoreで繋ぐ!AWSで実践する「AI-DLC」から「AIエージェント統合」までの最新地図
licux
4
750
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
300
巨大モノリシックアプリ モダン化大作戦
ktcryomm
1
1.1k
技術的負債の返済は、AI時代の複利で効く投資 — 経営としての意思決定とその遂行
curekoshimizu
0
1.7k
JRuby: Past, Present, and Future
headius
0
180
スマート反転とウェブアクセシビリティ
camiha
0
210
Omarchy Tokyo やると聞いて UMPC 買ってセットアップしてきた
mtsmfm
0
160
LoopHub - ローカルで動く GitHub で、AI と共同開発
jugyo
1
560
動作中のプログラムの中身をリアルタイムに覗く / Realtime Debugger for CSharp with Roslyn
prota
1
910
Featured
See All Featured
Primal Persuasion: How to Engage the Brain for Learning That Lasts
tmiket
0
470
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.2k
Building Adaptive Systems
keathley
44
3.2k
The Spectacular Lies of Maps
axbom
PRO
1
1k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.8k
YesSQL, Process and Tooling at Scale
rocio
174
15k
First, design no harm
axbom
PRO
2
1.3k
4 Signs Your Business is Dying
shpigford
187
23k
Claude Code どこまでも/ Claude Code Everywhere
nwiizo
67
58k
Site-Speed That Sticks
csswizardry
13
1.5k
How to make the Groovebox
asonas
2
2.4k
It's Worth the Effort
3n
188
29k
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 チーム名を決めて試してみて下さい