Web録音で音が入らない問題と解決法
はじめに
プログラミング初心者の私が、Railsで音声録音機能を作っていたときに遭遇した問題です。録音ボタンを押すと成功したように見えるのに、再生すると何も聞こえないという状況で数時間悩みました。
何が起きたか
- 録音ボタンを押すと正常に動作している様子
- ファイルも作られる
- でも再生すると無音
- ファイル自体は壊れていない(専用ツールで確認すると音声形式は正しい)
環境
- macOS の MacBook Pro
- Google Chrome ブラウザ
- Ruby on Rails 8
- Bluetooth イヤホン(Shokz OpenMove)を接続中
何をやって原因を見つけたか
1. 音声レベルを確認してみる
まず、本当に音が録音されているかを確認するコードを書きました:
// 音声レベルをリアルタイムで表示する
function checkAudioLevel(stream) {
const audioContext = new AudioContext();
const source = audioContext.createMediaStreamSource(stream);
const analyser = audioContext.createAnalyser();
source.connect(analyser);
const dataArray = new Uint8Array(analyser.frequencyBinCount);
setInterval(() => {
analyser.getByteTimeDomainData(dataArray);
console.log('音声の数値:', dataArray[0]);
// 128 = 無音、それ以外なら音が入っている
}, 500);
}
結果:ずっと「128」が表示される → 完全に無音状態
2. どのマイクが使われているか調べる
// 使えるマイクの一覧を表示
navigator.mediaDevices.enumerateDevices().then(devices => {
devices.forEach(device => {
if (device.kind === 'audioinput') {
console.log('マイク:', device.label);
}
});
});
結果:
- OpenMove by Shokz(Bluetooth)
- MacBook Pro のマイク(内蔵)
- 既定 - OpenMove by Shokz(Bluetooth)
3. 原因が判明
Bluetooth イヤホンのマイクが自動で選ばれていたが、実際には動作していなかった
Chrome は Bluetooth デバイスが接続されていると、そちらのマイクを優先的に使おうとします。でも、そのマイクが正常に動作しない場合があり、その結果として「録音は成功するけど音は入らない」という状況になっていました。
解決方法
方法1: システム設定で解決(簡単)
macOS の設定
- システム設定を開く
- サウンド → 入力
- 「MacBook Pro のマイク」を選択
Chrome の設定
-
chrome://settings/content/microphone
にアクセス - デフォルトマイクを内蔵マイクに変更
方法2: プログラムで解決(確実)
アプリ内でマイクを選択できる機能を作ります:
// マイク選択の画面を作る
function createMicSelector() {
const container = document.createElement('div');
container.innerHTML = `
<label>使用するマイク:</label>
<select id="micSelect">
<option value="">自動選択</option>
</select>
<button id="testBtn">テスト</button>
`;
// 録音ボタンの上に追加
document.getElementById('recordBtn').parentNode.insertBefore(container, document.getElementById('recordBtn'));
}
// 使えるマイクの一覧を取得
async function loadMicrophones() {
const devices = await navigator.mediaDevices.enumerateDevices();
const microphones = devices.filter(device => device.kind === 'audioinput');
const select = document.getElementById('micSelect');
microphones.forEach(mic => {
const option = document.createElement('option');
option.value = mic.deviceId;
option.textContent = mic.label || 'マイク';
select.appendChild(option);
});
}
// 選んだマイクをテストする
async function testMicrophone() {
const selectedMicId = document.getElementById('micSelect').value;
const stream = await navigator.mediaDevices.getUserMedia({
audio: {
deviceId: selectedMicId ? { exact: selectedMicId } : undefined
}
});
// 3秒間音声レベルをチェック
const audioContext = new AudioContext();
const analyser = audioContext.createAnalyser();
audioContext.createMediaStreamSource(stream).connect(analyser);
const dataArray = new Uint8Array(analyser.frequencyBinCount);
let isWorking = false;
const checkSound = () => {
analyser.getByteTimeDomainData(dataArray);
// 128以外の値があれば音が入っている
if (dataArray.some(value => value !== 128)) {
isWorking = true;
}
};
const interval = setInterval(checkSound, 100);
setTimeout(() => {
clearInterval(interval);
stream.getTracks().forEach(track => track.stop());
audioContext.close();
alert(isWorking ? 'マイクは正常です' : 'このマイクでは音が検出されません');
}, 3000);
}
// 録音時に選択したマイクを使う
async function startRecording() {
const selectedMicId = document.getElementById('micSelect').value;
const stream = await navigator.mediaDevices.getUserMedia({
audio: {
deviceId: selectedMicId ? { exact: selectedMicId } : undefined
}
});
mediaRecorder = new MediaRecorder(stream);
// 録音処理を続ける...
}
学んだこと
-
Bluetooth デバイスは要注意
接続されていても、マイクが正常に動作するとは限らない -
事前テストが重要
録音する前に、マイクが実際に音を拾っているか確認する -
ユーザーに選択肢を与える
複数のマイクがある環境では、どれを使うか選べるようにする -
段階的に問題を切り分ける
- システムレベル(macOS の設定)
- ブラウザレベル(Chrome の設定)
- アプリレベル(プログラムの実装)
まとめ
Web で録音機能を作るときは、Bluetooth デバイスのマイクが原因で無音になる場合があります。
解決策:
- システム設定で内蔵マイクを選択
- アプリでマイク選択機能を実装
- 録音前の動作テスト機能を追加
全く動かなくて、本当に詰まりました。
まさか、ヘッドホンが原因だったとは思いませんでした。