導入
WebRTCの通話機能を実装していたとき、音声制約をどう設定するか迷いました。
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
これで動きます。通話もできます。じゃあ echoCancellation とか noiseSuppression は明示しなくていいのか? undefined のままで本当に大丈夫なのか? true と undefined は同じなのか、違うのか?
調べ始めたら、想像以上に奥が深かったです。true を指定しても実際には適用されないケースがある。処理の順番が音質に影響する。ブラウザごとにデフォルト値が違う。
この記事では、echoCancellation、autoGainControl、noiseSuppression の「音声処理3兄弟」について、実装時に判断できるレベルまで整理します。
3つの制約の役割
echoCancellation(エコーキャンセル)
スピーカーから出た音がマイクに回り込む「エコー」を除去します。スピーカー出力音をリファレンスとして、マイク入力から差し引く処理です。ビデオ会議で相手の声が自分に返ってくる現象を防ぎます。
OFFにすると、スピーカー使用時にハウリング(キーンという音)が発生します。Web会議で「自分の声が3秒後に返ってくる」あの恐怖を体験したことがある方なら、ECのありがたみがわかるはずです。
autoGainControl(自動ゲイン制御)
マイク入力の音量を自動で調整します。小さい声は増幅し、大きい声は抑制して、一定の音量レベルに揃えてくれます。
便利な機能ですが、音楽や効果音を扱う場合はダイナミクス(音量の強弱)を潰してしまいます。ピアノのフォルテッシモが勝手にメゾピアノにされる、みたいな話です。
noiseSuppression(ノイズ抑制)
背景のノイズ(エアコン、ファンの音、環境音)を検知して除去します。
人の声の周波数帯以外を抑制する仕組みなので、ONにすると音声以外の音(楽器の音など)も容赦なく削られます。ギターのアルペジオが「なんか薄い」と感じたら、犯人はだいたいNSです。
undefined vs true vs false -- 何が違うのか
ここが一番誤解されやすいポイントです。「trueって書いたから有効でしょ?」......そう思いますよね。実はそんなに単純じゃないんです。
| 設定値 | 意味 | 挙動 |
|---|---|---|
undefined(未指定) |
ブラウザのデフォルトに従う | Chrome/Firefox: 3つとも ON。ただしハードウェアNSはそのまま動作する可能性あり |
true |
有効化を希望 | ベストエフォートで適用。満たせなくてもエラーにならない。ChromeではハードウェアNSを自動OFFにする(後述) |
false |
無効化を希望 | ベストエフォートで適用。満たせなくてもエラーにならない |
{ exact: true } |
有効化を必須 | 満たせない場合は getUserMedia が エラー |
{ exact: false } |
無効化を必須 | 満たせない場合はエラー |
{ ideal: true } |
true と同等 |
ベストエフォート |
注意: undefined と true はどちらもECがONになりますが、ブラウザの内部処理が異なります。 詳細は次のセクションで解説します。
重要なのは、audio: true と audio: { echoCancellation: true } は結果が違うということです。どちらもECがONになる点は同じですが、ブラウザの内部処理が異なります。
Chromeの場合、echoCancellation: true を明示的に指定すると、ハードウェアレベルのノイズサプレッション(マイクドライバ等)を自動でOFFにします。ソフトウェアのエコーキャンセラーが最適な信号を受け取れるようにするためです(Chrome公式ブログ)。
一方、audio: true(undefined)ではECがデフォルトでONになりますが、制約として明示指定されていないため、ハードウェアNSがそのまま動作する可能性があります。結果として、ハードウェアNSとソフトウェアAECの二重処理で音質が劣化するケースがあります。
つまり、「明示的にtrueを書く」ことには意味があるんです。
// undefinedとtrueの違い { audio: true } // デフォルト適用。ハードウェアNSが残る可能性 { audio: { echoCancellation: true } } // 明示指定。ChromeはハードウェアNSを自動OFF { audio: { echoCancellation: { exact: true } } } // EC必須、不可ならエラー
また、「指定した」と「適用された」は別物です。ブラウザはベストエフォートで処理するため、true を指定しても実際にはONにならないケースがあります。後述する getSettings() で事後確認が必要です。
処理パイプラインの順序 -- なぜ順番が重要なのか
WebRTCの内部では、音声処理は以下の順序で直列に実行されます(libwebrtcの実装、時雨堂ドキュメント参照)。

直列パイプラインなので、前段の処理が後段に影響します。料理で言えば、下ごしらえ(NS)を省略して味付け(AEC)しても美味しくならないのと同じです。
- NSをOFFにすると → AECに渡される信号にノイズが混在 → AECの精度が低下する可能性があります
- AECをOFFにすると → AGCがエコーを含んだ信号を増幅 → ハウリングが悪化します
- AGCは最後に適用されるため、EC/NSの結果を増幅します
つまり「NSだけOFFにすれば音質が良くなる」という単純な話ではなく、パイプライン全体への影響を考慮する必要があります。
ハマりポイント3選
1. EC:false + AGC:true → ハウリング → 会話不能
エコーキャンセルをOFFにしてAGCだけONにすると、スピーカーからのエコーをAGCが「音声入力」と判断して増幅します。増幅されたエコーがさらにスピーカーから出て......というフィードバックループでハウリングが始まります。
AGCはハウリングを検知すると入力ゲインを自動で下げますが、結果として通常の会話音声も聞こえないレベルまで音量が低下します。「相手の声が消えた!」という問い合わせの裏に、このコンボが隠れていることがあります。
対策: ECをOFFにするなら、AGCもOFFにしましょう。セットで考える必要があります。
2. ハードウェアNS × ソフトウェアAEC の干渉
一部のマイクはドライバレベルでノイズサプレッションを実行しています。このハードウェアNSが、WebRTCのソフトウェアAECより先に音声を加工してしまうため、AECが期待する「クリーンな信号」が得られず精度が低下します。
Chromeはこの問題に対応済みで、echoCancellation が有効な場合、ハードウェアNSを自動でOFFにしてくれます(Chrome公式ブログ)。
ただし、Chrome以外のブラウザではこの対策がない可能性があります。「Chromeでは問題ないのにFirefox/Safariでエコーが酷い」という報告の原因がここにあるケースがあります。
3. EC:true + channelCount:2 → 正常に動作しない
Chromeのエコーキャンセラーはモノラル前提の実装です。そもそもChromeは channelCount: 2 を指定してもステレオ録音をサポートしておらず(2026年現在)、エコーキャンセルと併用すると正常に動作しない制限があります。
これはバグというよりChromeの実装上の制限です。Firefoxではステレオ録音に対応しています。
対策: ステレオが必要な場合は echoCancellation: false を明示してください。
// ステレオ録音する場合 const stream = await navigator.mediaDevices.getUserMedia({ audio: { channelCount: 2, echoCancellation: false, // 必須 noiseSuppression: false, autoGainControl: false, } });
ユースケース別おすすめ設定
通話(スピーカー使用)
{ audio: { echoCancellation: true, noiseSuppression: true, autoGainControl: true, } }
デフォルトと同じですが、明示的に書くことで意図が伝わります。スピーカー使用時はEC必須です。
通話(ヘッドセット使用)
{ audio: { echoCancellation: false, noiseSuppression: true, autoGainControl: true, } }
ヘッドセットならエコーの回り込みが少ないため、ECをOFFにすると音質が向上します。NSとAGCは通話品質のために残しておきましょう。
録音・ポッドキャスト
{ audio: { echoCancellation: false, noiseSuppression: false, autoGainControl: false, channelCount: 2, sampleRate: 48000, } }
音声処理を全てOFFにして、生の入力を取得します。後処理で音質を調整する前提です。channelCount: 2 はFirefoxでのみ有効で、Chromeではモノラルのまま無視されます(前述の制限)。
音楽セッション・配信
{ audio: { echoCancellation: false, noiseSuppression: false, autoGainControl: false, latency: 0.01, } }
音楽ではダイナミクス(音量の強弱)が重要なのでAGCは厳禁です。NSも楽器の音を削るためOFFにします。低レイテンシの明示指定も忘れずに。
getSettings()で実際の設定を確認する
制約を指定した ≠ 実際に適用された。これがWebRTC音声制約の最大の罠です。「言ったよね?」「聞いてません」みたいなコミュニケーション事故が、ブラウザとの間でも起きます。
getSettings() で、ブラウザが実際に適用した設定を事後確認する習慣をつけましょう。
const stream = await navigator.mediaDevices.getUserMedia({ audio: { echoCancellation: false, noiseSuppression: false, autoGainControl: false, } }); const track = stream.getAudioTracks()[0]; const settings = track.getSettings(); console.log('EC:', settings.echoCancellation); // 本当にfalseですか? console.log('NS:', settings.noiseSuppression); // 本当にfalseですか? console.log('AGC:', settings.autoGainControl); // 本当にfalseですか?
特にモバイルブラウザでは、false を指定しても無視されるケースがあります。getSettings() の結果が true なら、制約が効いていません。
ブラウザ差異まとめ
| 制約 | Chrome | Firefox | Safari |
|---|---|---|---|
| echoCancellation | ON by default, 制御可 | ON by default, 制御可 | ON by default, 制御可 |
| noiseSuppression | ON by default, 制約が効かない場合あり | ON by default, 制御可 | 非対応 |
| autoGainControl | ON by default, 制約が効かない場合あり | OFF by default, 制御可 | 非対応 |
Firefoxは autoGainControl のデフォルトが OFF である点に注意です。Chrome前提で開発して「完璧!」と思ったら、Firefoxユーザーから「声が小さいんですけど」という問い合わせが来ます。WebRTCあるあるです。
補足: goog系プレフィックス
Chrome固有の非標準制約として goog プレフィックスが存在します。
{ audio: { // 標準制約 echoCancellation: true, noiseSuppression: true, autoGainControl: true, // Chrome固有(非標準) googHighpassFilter: true, // 低周波ノイズ除去(エアコン音等) googTypingNoiseDetection: true, // タイピング音検知・除去 googExperimentalNoiseSuppression: true, } }
非標準なので将来削除される可能性がありますが、googHighpassFilter はエアコンやファンの低周波ノイズに効果的です。「なんか『ブーン』って鳴ってるんだけど」にはまずこれを試す価値があります。Chrome限定で問題ない環境向けです。
まとめ
audio: trueで動きますが、それは「デフォルトで良い」という意味ではありません- undefined / true / false はベストエフォートです。
{ exact: true/false }が必須指定です - 処理パイプラインは直列(HPF → NS → AEC → AGC)。前段が後段に影響します
- EC:false + AGC:true は危険です。EC:true + channelCount:2 はChromeで正常に動作しません
getSettings()で事後確認する習慣をつけましょう- ユースケースに応じて設定を変えてください。「全部true」が正解ではありません
「動いてるから大丈夫」は、借金を「返済日はまだ先だから大丈夫」と言っているのと同じです。問題が起きる前に理解しておくと、起きたときの対応力が段違いになります。





