ブログとか
ブログとか
2025-06-23
アスキーアートのビデオチャットを作った。 サイトのURLは /pages/aachat/ 。
AA電話は、WebRTCを使用してリアルタイムでビデオをASCIIアートに変換し、相手と通信するWebアプリケーション。
音声は普通に通話できるけど、通常の映像を無駄にテキストに変換して表示します。
処理的には普通に映像を表示するほうが楽だが、を敢えてAAで表示することにより、低解像度であることを誤魔化しつつ帯域を節約することができる。
使ってみるとわかるが、相手の表情がわからないため、ずっと喋ってないと不安になる。
%%{init: {'theme':'dark', 'themeVariables': { 'primaryColor': '#4a90e2', 'primaryTextColor': '#ffffff', 'primaryBorderColor': '#6bb6ff', 'lineColor': '#8cc8ff', 'background': '#2d3748', 'mainBkg': '#2d3748', 'secondBkg': '#4a5568'}}}%%
graph TB
subgraph "ブラウザA (ホスト)"
A1[カメラ/マイク] --> A2[MediaStream]
A2 --> A3[Canvas処理]
A3 --> A4[ASCII変換]
A4 --> A5[表示]
A2 --> A6[PeerConnection]
end
subgraph "Public Piping Server(※)"
S1[シグナリング]
end
subgraph "ブラウザB (ゲスト)"
B1[カメラ/マイク] --> B2[MediaStream]
B2 --> B3[Canvas処理]
B3 --> B4[ASCII変換]
B4 --> B5[表示]
B2 --> B6[PeerConnection]
end
A6 -.PUT/GET<br/>(暗号化データ).- S1
B6 -.PUT/GET<br/>(暗号化データ).- S1
A6 <==>|WebRTC P2P接続| B6
classDef hostStyle fill:#4a90e2,stroke:#6bb6ff,stroke-width:2px,color:#ffffff
classDef guestStyle fill:#9f7aea,stroke:#b794f6,stroke-width:2px,color:#ffffff
classDef serverStyle fill:#ed8936,stroke:#f6ad55,stroke-width:2px,color:#ffffff
class A1,A2,A3,A4,A5,A6 hostStyle
class B1,B2,B3,B4,B5,B6 guestStyle
class S1 serverStyle
%%{init: {'theme':'dark', 'themeVariables': { 'primaryColor': '#4a90e2', 'primaryTextColor': '#ffffff', 'primaryBorderColor': '#6bb6ff', 'lineColor': '#8cc8ff', 'secondaryColor': '#ed8936', 'tertiaryColor': '#9f7aea', 'background': '#2d3748', 'mainBkg': '#2d3748', 'secondBkg': '#4a5568', 'actorBkg': '#4a90e2', 'actorTextColor': '#ffffff', 'actorLineColor': '#6bb6ff', 'signalColor': '#ffffff', 'signalTextColor': '#ffffff', 'c0': '#4a90e2', 'c1': '#9f7aea', 'c2': '#ed8936'}}}%%
sequenceDiagram
participant H as ホスト
participant P as Public Piping Server
participant G as ゲスト
H->>H: カメラ起動・AA変換開始
H->>P: PUT /aachat/{keyword}<br/>暗号化されたOffer(SDP)+sessionToken
G->>G: カメラ起動・AA変換開始
loop ポーリング(2秒間隔)
G->>P: GET /aachat/{keyword}
P-->>G: Offerデータ+sessionToken取得
end
G->>P: PUT /aachat/{keyword}/{sessionToken}/answer<br/>暗号化されたAnswer(SDP)
loop ポーリング(2秒間隔)
H->>P: GET /aachat/{keyword}/{sessionToken}/answer
P-->>H: Answerデータ取得
end
par ICE候補の交換
H->>P: PUT /aachat/{keyword}/{sessionToken}/ice-host<br/>ホストのICE候補
loop ポーリング
G->>P: GET /aachat/{keyword}/{sessionToken}/ice-host
P-->>G: ホストのICE候補取得
end
and
G->>P: PUT /aachat/{keyword}/{sessionToken}/ice-guest<br/>ゲストのICE候補
loop ポーリング
H->>P: GET /aachat/{keyword}/{sessionToken}/ice-guest
P-->>H: ゲストのICE候補取得
end
end
Note over H,G: P2P接続確立後は Public Piping Server 不要
H->>G: ビデオ/オーディオ直接送信
G->>H: ビデオ/オーディオ直接送信
Note over H,G: 各自でローカル変換
H->>H: 受信映像をAA変換
G->>G: 受信映像をAA変換
Piping Serverは本来一時的なデータ転送を行うものですが、以下の方法でWebRTCシグナリングに転用しています:
/aachat/{keyword}
/aachat/{keyword}/{sessionToken}/*