Skip to content

Commit 97e38b9

Browse files
authored
Merge pull request #230 from nttcom/call-example
Add call example
2 parents 9434b0d + 21097c1 commit 97e38b9

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

73 files changed

+6856
-1262
lines changed

.gitignore

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,16 +9,23 @@ target/
99
# MSVC Windows builds of rustc generate these, which store debugging information
1010
*.pdb
1111

12+
node_modules/*
1213
js/node_modules/*
14+
js/examples/*/node_modules/*
1315
js/dist/*
1416
js/pkg/*
17+
js/examples/*/dist/*
1518
# Added by cargo
1619

1720
/target
1821
*.log
1922
*.pem
2023
.DS_Store
2124

25+
26+
2227
log/*
2328

29+
30+
2431
cargo-flamegraph.trace/*

.vscode/settings.json

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
"[javascript]": {
44
"editor.defaultFormatter": "esbenp.prettier-vscode"
55
},
6+
"[typescript]": {"editor.defaultFormatter": "esbenp.prettier-vscode"},
7+
"[typescriptreact]": {"editor.defaultFormatter": "esbenp.prettier-vscode"},
8+
"[javascriptreact]": {"editor.defaultFormatter": "esbenp.prettier-vscode"},
9+
"[json]": {"editor.defaultFormatter": "esbenp.prettier-vscode"},
10+
"[css]": {"editor.defaultFormatter": "esbenp.prettier-vscode"},
11+
"[markdown]": {"editor.defaultFormatter": "esbenp.prettier-vscode"},
612
"[rust]": {
713
"editor.defaultFormatter": "rust-lang.rust-analyzer",
814
"editor.inlayHints.enabled": "on"

js/examples/call/README.md

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
# MoQT Video Call Application
2+
3+
MoQT (Media over QUIC Transport) を使用したビデオ通話アプリケーションです。
4+
5+
## 概要
6+
7+
このアプリケーションは、draft-ietf-moq-transport-10 に準拠した MoQT プロトコルを使用して、リアルタイムのビデオ通話機能を提供します。
8+
9+
### 主な機能
10+
11+
- **Room & User 管理**: Room Name と User Name を入力してルームに参加
12+
- **参加者グリッド表示**: ルーム内の他の参加者を一覧表示
13+
- **選択的購読**: 参加者を選択して映像・音声を購読
14+
- **メディア配信**: カメラ、マイク、画面共有を選択して配信
15+
16+
## MoQT プロトコルフロー
17+
18+
### TrackName Space 構造
19+
20+
- **TrackName Space**: `/{RoomName}/{UserName}`
21+
- **Video TrackName**: `video`
22+
- **Audio TrackName**: `audio`
23+
24+
### メッセージシーケンス
25+
26+
1. **接続とセットアップ**
27+
- `SETUP` メッセージでサーバーと接続を確立
28+
29+
2. **ルーム参加**
30+
- `SUBSCRIBE_ANNOUNCES``/{RoomName}/` のANNOUNCEを購読
31+
- 既存参加者と新規参加者のANNOUNCEを受信
32+
33+
3. **メディア配信**
34+
- カメラ/マイクを選択
35+
- `ANNOUNCE` メッセージで `/{RoomName}/{UserName}` を通知
36+
- 他の参加者から `SUBSCRIBE` メッセージを受信
37+
- `SUBSCRIBE_OK` を返して配信開始
38+
- `OBJECT` メッセージでメディアデータを送信
39+
40+
4. **メディア受信**
41+
- 参加者カードで「Subscribe」ボタンをクリック
42+
- `SUBSCRIBE` メッセージで `/{RoomName}/{UserName}/video``/{RoomName}/{UserName}/audio` を購読
43+
- `OBJECT` メッセージでメディアデータを受信
44+
45+
## セットアップ
46+
47+
### 依存関係のインストール
48+
49+
```bash
50+
cd ../../
51+
npm install
52+
```
53+
54+
### 開発サーバーの起動
55+
56+
```bash
57+
npm run dev
58+
```
59+
60+
ブラウザで http://localhost:5173/examples/call/ を開いてください。
61+
62+
### ビルド
63+
64+
```bash
65+
npm run build
66+
```
67+
68+
## プロジェクト構造
69+
70+
```
71+
src/
72+
├── components/
73+
│ ├── ui/ # shadcn/ui コンポーネント
74+
│ │ ├── button.tsx
75+
│ │ ├── card.tsx
76+
│ │ ├── input.tsx
77+
│ │ └── label.tsx
78+
│ ├── JoinRoomForm.tsx # ルーム参加フォーム
79+
│ ├── CallRoom.tsx # 通話ルームメイン画面
80+
│ ├── ParticipantCard.tsx # 参加者カード
81+
│ └── PublishMediaPanel.tsx # メディア配信パネル
82+
├── hooks/
83+
│ └── useLocalSession.ts # MoQT セッション管理フック
84+
├── types/
85+
│ └── moqt.ts # 型定義
86+
├── lib/
87+
│ └── utils.ts # ユーティリティ関数
88+
├── App.tsx # メインアプリケーション
89+
└── main.tsx # エントリーポイント
90+
```
91+
92+
## TODO: WASM統合
93+
94+
現在、MoQT クライアントの実装は `src/hooks/useLocalSession.ts` でスタブ化されています。
95+
実際の WASM モジュール (`moqt-client-sample`) を統合するには、以下を実施してください:
96+
97+
1. WASM モジュールのビルド
98+
99+
```bash
100+
cd ../../../moqt-client-sample
101+
wasm-pack build --target web --features web_sys_unstable_apis
102+
```
103+
104+
2. `useLocalSession.ts` 内のコメントアウトされたコードを有効化
105+
- `import init, { MOQTClient }` のインポート
106+
- `init()` の呼び出し
107+
- `MOQTClient` インスタンスの作成
108+
109+
3. エンコーダー/デコーダーワーカーの実装
110+
- 既存の `media/publisher``media/subscriber` のコードを参考に実装
111+
112+
## 技術スタック
113+
114+
- **React 19**: UI フレームワーク
115+
- **TypeScript**: 型安全な開発
116+
- **Tailwind CSS**: スタイリング
117+
- **shadcn/ui**: UIコンポーネントライブラリ
118+
- **Vite**: ビルドツール
119+
- **MoQT (WASM)**: Media over QUIC Transport プロトコル実装

js/examples/call/index.html

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<!doctype html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8" />
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
6+
<title>MoQT Video Call</title>
7+
</head>
8+
<body>
9+
<div id="root"></div>
10+
<script type="module" src="./src/main.tsx"></script>
11+
</body>
12+
</html>

js/examples/call/src/App.css

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
@import 'tailwindcss';
2+
3+
:root {
4+
--background: 0 0% 100%;
5+
--foreground: 222.2 84% 4.9%;
6+
--card: 0 0% 100%;
7+
--card-foreground: 222.2 84% 4.9%;
8+
--popover: 0 0% 100%;
9+
--popover-foreground: 222.2 84% 4.9%;
10+
--primary: 221.2 83.2% 53.3%;
11+
--primary-foreground: 210 40% 98%;
12+
--secondary: 210 40% 96.1%;
13+
--secondary-foreground: 222.2 47.4% 11.2%;
14+
--muted: 210 40% 96.1%;
15+
--muted-foreground: 215.4 16.3% 46.9%;
16+
--accent: 210 40% 96.1%;
17+
--accent-foreground: 222.2 47.4% 11.2%;
18+
--destructive: 0 84.2% 60.2%;
19+
--destructive-foreground: 210 40% 98%;
20+
--border: 214.3 31.8% 91.4%;
21+
--input: 214.3 31.8% 91.4%;
22+
--ring: 221.2 83.2% 53.3%;
23+
--radius: 0.5rem;
24+
}
25+
26+
.dark {
27+
--background: 222.2 84% 4.9%;
28+
--foreground: 210 40% 98%;
29+
--card: 222.2 84% 4.9%;
30+
--card-foreground: 210 40% 98%;
31+
--popover: 222.2 84% 4.9%;
32+
--popover-foreground: 210 40% 98%;
33+
--primary: 217.2 91.2% 59.8%;
34+
--primary-foreground: 222.2 47.4% 11.2%;
35+
--secondary: 217.2 32.6% 17.5%;
36+
--secondary-foreground: 210 40% 98%;
37+
--muted: 217.2 32.6% 17.5%;
38+
--muted-foreground: 215 20.2% 65.1%;
39+
--accent: 217.2 32.6% 17.5%;
40+
--accent-foreground: 210 40% 98%;
41+
--destructive: 0 62.8% 30.6%;
42+
--destructive-foreground: 210 40% 98%;
43+
--border: 217.2 32.6% 17.5%;
44+
--input: 217.2 32.6% 17.5%;
45+
--ring: 224.3 76.3% 48%;
46+
}
47+
48+
* {
49+
border-color: hsl(var(--border));
50+
}
51+
52+
body {
53+
background-color: hsl(var(--background));
54+
color: hsl(var(--foreground));
55+
}

js/examples/call/src/App.tsx

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
import { useState } from 'react'
2+
import './App.css'
3+
import { JoinRoomForm } from './components/JoinRoomForm'
4+
import { CallRoom } from './components/CallRoom'
5+
import { useLocalSession } from './hooks/useLocalSession'
6+
7+
function App() {
8+
const [joinError, setJoinError] = useState<Error | null>(null)
9+
const { session, connect, disconnect, isInitializing } = useLocalSession()
10+
11+
const handleJoin = async (roomName: string, userName: string) => {
12+
try {
13+
await connect(roomName, userName)
14+
setJoinError(null)
15+
} catch (error) {
16+
console.error('Failed to join room:', error)
17+
const err = error instanceof Error ? error : new Error('Failed to join room')
18+
setJoinError(err)
19+
}
20+
}
21+
22+
const handleLeave = async () => {
23+
try {
24+
await disconnect()
25+
} catch (error) {
26+
console.error('Failed to leave room:', error)
27+
}
28+
}
29+
30+
return (
31+
<>
32+
{!session ? (
33+
<>
34+
<JoinRoomForm onJoin={handleJoin} />
35+
{joinError && <p className="text-red-500 text-center mt-4">{joinError.message}</p>}
36+
{isInitializing && <p className="text-blue-500 text-center mt-2">Connecting to MoQT relay...</p>}
37+
</>
38+
) : (
39+
<CallRoom session={session} onLeave={handleLeave} />
40+
)}
41+
</>
42+
)
43+
}
44+
45+
export default App

0 commit comments

Comments
 (0)