---
title: "音声通話"
description: "ゲーム向け（声で話すアプリにも使えます）。音声通話はリアルタイムの部屋の中で使います。`voice`を付けて部屋を作ると、その部屋のプレイヤー同士で声をやり取りできます。"
url: "/ja/docs/guides/voice/"
lang: ja
index: "/ja/llms.txt"
---
# 音声通話

**ゲーム向け**（声で話すアプリにも使えます）。音声通話は[リアルタイムの部屋](/ja/docs/guides/realtime/index.md)の中で使います。`voice`を付けて部屋を作ると、その部屋のプレイヤー同士で声をやり取りできます。パーティー、チーム、対戦、大人数の集まりなどに使えます。1回の通話は100人までです。8人まではプレイヤー同士をつなぎ（P2P）、9人以上はKUMODeckの中継サーバー（SFU）を通します。どちらになるかは部屋の人数で自動で決まり、使い方は同じです。ONにするまではOFFで、リアルタイムの部屋もONにする必要があります。

```sh
kumodeck features on realtimeChannels voice
kumodeck config push --env development
```

**KUMODeckは通話を録音しません。** 声は聴く人へ届けるだけで、つなぐための合図のメッセージも中継したら捨てます。KUMODeckが持つのは、今だれが通話にいるかと、入った時刻だけです。

## 通話を始める

```js
const party = await kumo.realtime.create({ voice: true, maxMembers: 4, join: 'invited' });
await party.invite(playerId);                 // 入れる人（party.name をその人に渡す）

// join() はボタンから呼ぶ: ブラウザがマイクの許可を聞き、音はタップやクリックの後でないと鳴らせないため
await party.voice.join();                    // { mic: false } = 聴くだけ
party.voice.mute();                          // 自分のマイク
party.voice.unmute();
party.voice.on('speaking', ({ playerId, speaking }) => { … });   // 話している人を光らせる
await party.voice.leave();                   // 通話から出る（部屋には残る）
```

大人数の通話も同じ書き方です。

```js
const hall = await kumo.realtime.create({ voice: true, maxMembers: 60 });   // 9人以上 = 中継サーバー
hall.voice.mode;                             // 'sfu'
```

通話があるのは`voice`を付けて作った部屋だけです。ほかの部屋では`ch.voice`は`null`です。ほかのプレイヤーはいつもどおり部屋に入り（`kumo.realtime.join(party.name)`）、そのあと`ch.voice.join()`を呼びます。接続が切れたときは、SDKが部屋と通話に自動で入り直します。

## 人数と方式

| 部屋の作り方 | 方式（`ch.voice.mode`） | |
|---|---|---|
| `voice: true`、`maxMembers`が8以下（既定は8） | `'p2p'` | プレイヤー同士をつなぐ。声は中継を通るので、相手のIPアドレスは見えない |
| `voice: true`、`maxMembers`が9〜100 | `'sfu'` | 自動で中継サーバーを通す |
| `voice: { mode: 'sfu' }` | `'sfu'` | 少人数でも中継サーバーを通す（`maxMembers`の既定は50）。ミュートを確実にしたい部屋向け（下を参照） |
| `maxMembers`が100より多い | — | `voice_too_large` |

方式は部屋を作るときに決まり、通話の途中では変わりません。

**中継サーバー（`'sfu'`）の部屋の決まり**

- **聴こえるのは、自分以外で最近話した上位8人です。** 大勢が同時に話しても聞き取れるのは数人までなので、聴く量（料金）が人数の2乗で増えないようにしています。`ch.voice.peers`は今聴いている人（8人まで）で、`speaking`もその人たちについて届きます。通話にいる全員は`ch.voice.members`で分かります。
- **ミュートはサーバーが強制します。** 持ち主や自分のサーバーがミュートした人、話せる人の名簿に無い人の声は、中継サーバーが誰にも配りません。改造したクライアントでも聴けません。
- 相手のIPアドレスは見えません（声は中継サーバーから届きます）。

## 状態・イベント・エラー

| 状態 | |
|---|---|
| `ch.voice.mode` | `'p2p'`か`'sfu'`（読むだけ） |
| `ch.voice.joined` | 自分が通話に入っている |
| `ch.voice.muted` | 自分のマイクをミュートしている |
| `ch.voice.canSpeak` | 自分の声がほかの人に聞こえる（持ち主や自分のサーバーにミュートされた・話せる人の名簿に無いときは`false`） |
| `ch.voice.members` | 通話にいる人: `[{ id, canSpeak }]` |
| `ch.voice.peers` | 声が届く相手: `{ playerId, state, canSpeak, speaking, relayed }`（`'sfu'`では今聴いている上位8人） |

| イベント | 中身 |
|---|---|
| `peer` | つながりが変わった: `{ playerId, state, canSpeak, speaking, relayed }` |
| `speaking` | `{ playerId, speaking }` |
| `members` | 通話にいる人の一覧（変わるたびに全体） |
| `playerJoined` / `playerLeft` | `{ id, canSpeak }` / `{ playerId }`（自分以外） |
| `self` | `{ canSpeak }` — 自分がミュートされた・解除された |
| `closed` | `{ reason }` — 下の表 |

| `closed`の`reason` | どんなとき | 部屋には |
|---|---|---|
| `left` | 自分で通話から出た | 残る |
| `kicked` / `banned` | 部屋から外された | 外れる |
| `time_limit` | 1回の通話が4時間を過ぎた | 残る（入り直せる） |
| `suspended` | KUMODeckの運営がこの部屋かゲームの音声通話を止めた（悪用への対応など）。解除されるまで通話に入れない。文字のやり取りは続けられる | 残る |
| `unavailable` | 今は通話を続けられない（前払いの残高がなくなった など） | 残る |
| `connection_lost` | 回線が切れて入り直せなかった | — |

| エラー | どんなとき |
|---|---|
| `webrtc_unavailable` | ブラウザにWebRTCが無い |
| `mic_denied` | プレイヤーがマイクを許可しなかった（`{ mic: false }`で聴くだけにはできる） |
| `voice_disabled` | この部屋は`voice`を付けて作られていない |
| `voice_too_large` | `maxMembers`が100より多い（P2Pを指定した部屋では8より多い） |
| `voice_suspended` | KUMODeckの運営がこの部屋かゲームの音声通話を止めている |
| `voice_unavailable` | 今は中継サーバーの通話を使えない。少し待って入り直す |
| `voice_not_joined` | `join()`の前に通話の操作をした |
| `feature_disabled` | `features.voice`がOFF |
| `player_required` | プレイヤーIDの無いプレイヤー（下を参照） |
| `rate_limited` | 通話への入り直しが多すぎる（1時間あたりの回数の上限） |

## 自分のサーバーから（秘密鍵）

自分のサーバーからも通話のある部屋を用意できます。`PUT /v1/realtime/channels/@name`に`{ "voice": true }`を送ります（いつもの`join`、`send`、`maxMembers`、`allow`、`speakers`も一緒に使えます）。人数による方式の決まりは上と同じで、`{ "voice": { "mode": "sfu" } }`で少人数でも中継サーバーにできます。`{ "voice": { "mode": "p2p" } }`は8人までの部屋にだけ使えます（9人以上は`voice_too_large`）。すでにあるP2Pの部屋を9人以上に広げるときは、`maxMembers`と一緒に`{ "voice": { "mode": "sfu" } }`を送ってください（`maxMembers`だけでは方式は変わらず、`voice_too_large`になります）。`GET`で`voice`（`mode`を含む）と通話にいる人が分かります。通話に人がいる間は、音声の設定を変えられません（`409 voice_in_use`）。

P2Pの部屋では、既定で声はすべて中継を通るので、プレイヤーに相手のIPアドレスは見えません。これを外せるのは自分のサーバーだけで、部屋ごとに`{ "voice": { "relayOnly": false } }`とします（直接つながった組は中継の費用がかかりません）。13歳未満のプレイヤーは常に中継を通ります。中継サーバーの部屋ではこの設定は効きません。

## ミュート・キック・BAN

部屋の決まりがそのまま通話に効きます。持ち主（または自分のサーバー）の`mute`、`send: 'invited'`の部屋の話せる人の名簿、`kick`、`ban`です。

- **キックとBANは通信そのものを止めます。** そのプレイヤーは部屋と通話から外れ、中継を使う資格もすぐに取り消されます。ゲームからBANしたプレイヤーは、どの部屋にも入れません。キックした人は、部屋が入れる相手ならまた入れます。入らせたくないときはBANしてください。
- **ミュートの効き方は方式で違います。** 中継サーバー（`'sfu'`）では、サーバーがその人の声を配るのをやめます。P2P（`'p2p'`）では、KUMODeckが全員に「この人は話せない」と伝え、聴く人それぞれのSDKがその声の再生を止めます。声そのものはほかの人に届いているので、改造したクライアントなら再生できてしまいます。確実にミュートしたい部屋（知らない人どうしの通話など）は`voice: { mode: 'sfu' }`で作るか、キックしてください。
- **表示名は誰かの証明になりません。** 誰でもほかの人と同じ名前や「運営」のような名前を付けられます。持ち主や運営の印は、表示名ではなくプレイヤーID（`ownerId`）で出してください。
- **発言の中身の見張りは、クリエイターの責任です。** 誰が話せるかを決め、困ったときにすぐ動けるようにしておいてください（ミュート・キック・BAN）。悪用があったときは、KUMODeckの運営が部屋やゲームの音声通話だけを止めることもあります（`suspended`）。

## 上限

| | |
|---|---|
| 1回の通話の人数 | 100人。P2Pは8人まで（`voice: true`の`maxMembers`の既定は8、`{ mode: 'sfu' }`は50） |
| 聴こえる人 | P2Pは通話の全員。中継サーバーは自分以外で最近話した上位8人 |
| 1回の通話の時間 | 4時間。過ぎると`closed`（`time_limit`）。部屋には残り、通話に入り直せる |
| 入れる人 | プレイヤーIDのある人（既定。SDKがゲストとして自動でログインさせる）。`open`の部屋では使えない |
| 部屋 | `voice`を付けて作った`@`の部屋だけ（プレイヤーか自分のサーバーが作る）。`@`の無い部屋では使えない |

前払いの残高がなくなると、ほかのプレイヤー向けの機能と同じく、新しい通話は始められず、通話中の人も通話から外れます（`closed`の`unavailable`）。

## 料金

KUMODeckの利用料（原価どおり）として、前払いの残高から差し引きます。費用がかかるのは、聴く人それぞれへ届けた声の量です。黙っている人はほとんど送りません（無音の間はSDKが送らない）。P2Pで直接つながった組は費用がかかりません。

P2P（8人まで）:

| 1時間あたり | 1度に1人が話す | 全員がずっと話す |
|---|---|---|
| 2人 | 約0.13セント | 約0.26セント |
| 4人 | 約0.4セント | 約1.5セント |
| 8人 | 約0.9セント | 約7.2セント |

中継サーバー（9人以上）。1人が聴くのは8人までなので、費用は人数にほぼ比例します:

| 1時間あたり | 同時に話すのは平均2人 | 全員がずっと話す |
|---|---|---|
| 16人 | 約4セント | 約16セント |
| 50人 | 約13セント | 約51セント |
| 100人 | 約26セント | 約1ドル |
