第4回:Bluetoothイヤホンで翻訳音声を聞けるか

前回の記事では、「Intent-First Translation」プロジェクトで構築したリアルタイム翻訳基盤をもとに、3つの今後の構想をお伝えしました。その1番目、「音声読み上げ(TTS)によるハンズフリー翻訳」を実際に実装し、Bluetoothイヤホンで検証した記録です。

本プロジェクトは、Intent-First Translationの翻訳基盤(Deepgram音声認識 + LLMストリーミング翻訳)をそのまま活用し、その上に音声出力レイヤーを追加する形で進めました。

結論を先にお伝えすると、半分は成功し、半分はブラウザの技術的制約に阻まれました。しかし、そのプロセスで得られた知見は、今後のネイティブアプリ開発への確かな道筋になりました。


目指したこと

AppleはAirPods Pro(39,800円)にライブ翻訳機能を搭載し、iOS 26とApple Intelligenceを組み合わせた対面翻訳を実現しています。Timekettle M3(16,980円〜)やVasco E1といった翻訳専用イヤホンも登場しています。

これらは専用ハードウェアや特定のエコシステムと組み合わせることで、完成度の高い体験を提供しています。

一方で、公開されているAPIやオープンな技術を活用すれば、個人の開発でもこの領域にどこまで近づけるのか。その可能性と限界を検証したいと考えました。

具体的には、手持ちのスマートフォンとBluetoothイヤホンだけで、翻訳音声を耳で聞ける体験がどこまで実現できるかを試みました。

相手が英語で話す
  → スマホが音声を拾う
  → リアルタイムで翻訳
  → 翻訳を日本語音声で読み上げ
  → Bluetoothイヤホンから翻訳が聞こえる

Web Speech API でTTSを実装する

翻訳テキストの音声読み上げには、ブラウザ内蔵のWeb Speech APIを選びました。

const utterance = new SpeechSynthesisUtterance(translationText);
utterance.lang = 'ja-JP';
utterance.rate = 1.3;
window.speechSynthesis.speak(utterance);

API課金が不要で、ネットワーク遅延もありません。プロトタイプとして最速の選択肢です。

実装自体は数行で済みましたが、ここから想定外の問題が次々と現れました。


問題1:同じコードなのに、PCとiPhoneで全く違う

Web Speech APIは「ブラウザ標準」ですが、実際のTTSエンジンはOSごとに異なります。

設定PC (Windows Chrome)iPhone Chrome
rate=1.1通常速度通常速度
rate=1.8やや速いかなり速い
rate=3.0ちょうどいい速すぎて聞き取れない

同じ rate=3.0 でも、iPhoneでは人間が聞き取れないほどの速さになりました。

原因は、iPhone上のすべてのブラウザ(Chrome、Safari、Firefox)がAppleのWebKitエンジンを使用しており、TTS処理もApple独自のエンジンで行われるためです。「ブラウザ標準API」であっても、プラットフォームによる差異を吸収しきれないことを実感しました。

対策として、UserAgentでモバイルを判定し、rateを分岐させました。

const isMobile = /iPhone|iPad|Android/i.test(navigator.userAgent);
const ttsRate = isMobile ? 1.3 : 3.0;

問題2:iPhoneでは音が出ない

PCで問題なく動作したTTSが、iPhoneでは完全に無音でした。

原因は、モバイルブラウザの自動再生制限です。speechSynthesis.speak() は、ユーザーのタップ操作から直接呼ばれた場合のみ動作します。WebSocketのコールバック内からの呼び出しは「ユーザー操作」とは見なされず、ブロックされます。

対策として、TTS ONボタンをタップした瞬間に、無音の発話でロックを解除する手法を採りました。

// ユーザーのタップイベント内で実行
const unlock = new SpeechSynthesisUtterance('');
unlock.volume = 0;
window.speechSynthesis.speak(unlock);  // これでロック解除

この1回のタップ以降は、プログラムからの speak() 呼び出しが有効になります。


問題3:翻訳が表示されているのに、読み上げられないことがある

画面には翻訳が表示されているのに、音声が再生されないケースが散発しました。

原因を調査したところ、TTSの発火条件にありました。当初、音声認識の確定結果(is_final=true)のときだけTTSを発火していましたが、実験モードでは進行中の結果(is_final=false)でも翻訳が画面に表示されることがあります。進行中の翻訳が表示された後、確定結果が来る前に次の発話で上書きされると、TTSが発火しないまま消えていたのです。

対策として、is_final フラグに関係なく、翻訳テキストがあれば発火する方式に変更しました。 同じテキストの重複読み上げは、直前に読み上げたテキストとの比較で防止しています。


Bluetoothイヤホンでの実機テスト

ここまでの修正を経て、iPhoneにBluetoothイヤホンを接続し、実機テストを行いました。

動作したこと

  • 自分が英語を話す → イヤホンで日本語訳が聞こえる

イヤホンのマイクが自分の声を拾い、翻訳され、日本語の音声がイヤホンから再生されました。翻訳テキストの表示と音声出力の遅延差は約1秒以内でした。

動作しなかったこと

  • 相手の英語をイヤホンマイクで拾って翻訳する

Bluetoothイヤホンのマイクは、装着者の声を拾うように設計されています。ノイズキャンセリングが周囲の音を積極的にカットし、通話に最適化されているため、目の前にいる相手の声をまともに拾うことができませんでした。

これはソフトウェアの問題ではなく、マイクの物理的な設計の制約です。AirPods Proや翻訳専用イヤホンがビームフォーミング技術やマルチマイクアレイを搭載しているのは、この制約を専用ハードウェアで解決するためです。


「入力は内蔵マイク、出力はイヤホン」を試みる

相手の声を拾うには、スマホの内蔵マイクを使えばよいはずです。入力デバイスをスマホの内蔵マイクに固定し、出力だけをBluetoothイヤホンに送る構成を試みました。

マイク選択UIを実装し、getUserMedia のdeviceId制約で内蔵マイクを指定しました。

結果は失敗でした。 iOSのブラウザ(WebKit)では、オーディオ入力デバイスの明示的な選択がサポートされておらず、デバイスを指定しても無視されるか、接続が即座に切断されました。


ブラウザの限界と、ネイティブアプリという選択肢

ここで、ブラウザでできることの限界が明確になりました。

機能ブラウザネイティブアプリ
TTS音声出力✅(制限あり)✅(制限なし)
入力/出力デバイスの分離
バックグラウンド動作

iOSのネイティブアプリであれば、AVAudioSession APIを使って入力デバイスと出力デバイスを個別に制御できます。内蔵マイクで相手の声を拾い、Bluetoothイヤホンから翻訳音声を再生する——この構成はネイティブアプリであれば技術的に実現可能です。

相手が英語で話す
  → スマホ内蔵マイク(AVAudioSessionで固定)
  → Deepgram → LLM → 翻訳(約2秒)
  → iOS TTS (AVSpeechSynthesizer)
  → Bluetoothイヤホンで日本語訳を聞く

バックエンド(FastAPI + Deepgram + LLM)はそのまま流用でき、フロントエンドをReact NativeやSwiftに置き換えることで実現できる見通しです。


実測データ:翻訳テキストとTTS音声の遅延比較

最後に、今回の検証で得られた遅延データをまとめます。

指標計測値
発話終了 → 翻訳テキスト表示平均 2,115ms
翻訳テキスト表示 → TTS読み上げ完了(短文)1秒以内
発話終了 → 翻訳音声が聞こえる3秒

参考として、プロの同時通訳者は通常2〜3秒遅れで訳出します。短い発話であれば近いレイテンシを達成しており、個人開発のプロトタイプとしては手応えのある結果でした。


この実験で確認できたこと

  1. 公開APIの組み合わせで、翻訳音声のリアルタイム再生は実現できる(ただしプラットフォーム差異への対処が必要)
  2. 汎用のBluetoothイヤホンでも、翻訳音声の出力には問題がない
  3. ブラウザではオーディオ入出力デバイスの分離制御ができない(iOS WebKitの制約)
  4. ネイティブアプリ化すれば、「内蔵マイクで聞き取り + イヤホンで翻訳音声」は技術的に実現可能

専用製品が提供する体験のすべてを個人開発で再現することはできません。特にハードウェアに依存する部分——ビームフォーミングによる周囲音の集音——は、ソフトウェアだけでは超えられない壁です。

しかし、「スマホの内蔵マイクで音声を拾い、翻訳音声をイヤホンで聞く」という構成であれば、公開されているAPIとオープンな技術の組み合わせで十分に機能するプロトタイプを構築できることがわかりました。

今回の検証で得られた知見——プラットフォームごとのTTS挙動の差異、モバイルブラウザの制約、Bluetoothオーディオルーティングの限界——は、ネイティブアプリとして再設計する際の確かな判断材料になると考えています。


第1回:音声翻訳の本当の課題は精度ではなかった 第2回:JSONフィールド順序で翻訳表示が2倍速に 第3回:自宅GPUでリアルタイム翻訳は動くのか