admin管理员组文章数量:1313347
We have a flow in our app where we allow someone to be speaking (microphone) to a bot and the bot is talking back via audio.
It works fine when there is only one device, but if the user wants to use airpods we are having problems. On iOS (Safari, and Chrome) when using wired/Bluetooth headphones that include a microphone here is what we experience:
- Before recording: Audio playback works correctly through headphones.
- After recording + permissions being granted the audio output switches to the device speakers, even though the headphones are still connected.
I created a very simple page to reproduce the issue. I did find a bug that says it's been fixed but its clearly no .cgi?id=196539
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Microphone Recorder</title>
</head>
<body>
<h1>Microphone Recorder</h1>
<button id="startBtn">Start Recording</button>
<button id="stopBtn" disabled>Stop Recording</button>
<audio id="audioPlayback" controls src="/[email protected]/media/Justice_Genesis_16bit_trim_mono_y6iHYTjEyKU.wav" playsinline></audio>
<script>
let mediaRecorder;
let audioChunks = [];
document.getElementById('startBtn').addEventListener('click', async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(stream);
audioChunks = [];
mediaRecorder.ondataavailable = event => {
if (event.data.size > 0) {
audioChunks.push(event.data);
}
};
mediaRecorder.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
const audioUrl = URL.createObjectURL(audioBlob);
document.getElementById('audioPlayback').src = audioUrl;
};
mediaRecorder.start();
document.getElementById('startBtn').disabled = true;
document.getElementById('stopBtn').disabled = false;
} catch (error) {
console.error('Error accessing microphone:', error);
}
});
document.getElementById('stopBtn').addEventListener('click', () => {
mediaRecorder.stop();
document.getElementById('startBtn').disabled = false;
document.getElementById('stopBtn').disabled = true;
});
</script>
</body>
</html>
Again the steps to reproduce:
- Connect headhpones
- Start playing audio
- Click start recording
Notice: sound changes from headphones to speakers. This works fine when using Chrome on my laptop.
We have a flow in our app where we allow someone to be speaking (microphone) to a bot and the bot is talking back via audio.
It works fine when there is only one device, but if the user wants to use airpods we are having problems. On iOS (Safari, and Chrome) when using wired/Bluetooth headphones that include a microphone here is what we experience:
- Before recording: Audio playback works correctly through headphones.
- After recording + permissions being granted the audio output switches to the device speakers, even though the headphones are still connected.
I created a very simple page to reproduce the issue. I did find a bug that says it's been fixed but its clearly no https://bugs.webkit./show_bug.cgi?id=196539
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Microphone Recorder</title>
</head>
<body>
<h1>Microphone Recorder</h1>
<button id="startBtn">Start Recording</button>
<button id="stopBtn" disabled>Stop Recording</button>
<audio id="audioPlayback" controls src="https://cdn.jsdelivr/npm/[email protected]/media/Justice_Genesis_16bit_trim_mono_y6iHYTjEyKU.wav" playsinline></audio>
<script>
let mediaRecorder;
let audioChunks = [];
document.getElementById('startBtn').addEventListener('click', async () => {
try {
const stream = await navigator.mediaDevices.getUserMedia({ audio: true });
mediaRecorder = new MediaRecorder(stream);
audioChunks = [];
mediaRecorder.ondataavailable = event => {
if (event.data.size > 0) {
audioChunks.push(event.data);
}
};
mediaRecorder.onstop = () => {
const audioBlob = new Blob(audioChunks, { type: 'audio/wav' });
const audioUrl = URL.createObjectURL(audioBlob);
document.getElementById('audioPlayback').src = audioUrl;
};
mediaRecorder.start();
document.getElementById('startBtn').disabled = true;
document.getElementById('stopBtn').disabled = false;
} catch (error) {
console.error('Error accessing microphone:', error);
}
});
document.getElementById('stopBtn').addEventListener('click', () => {
mediaRecorder.stop();
document.getElementById('startBtn').disabled = false;
document.getElementById('stopBtn').disabled = true;
});
</script>
</body>
</html>
Again the steps to reproduce:
- Connect headhpones
- Start playing audio
- Click start recording
Notice: sound changes from headphones to speakers. This works fine when using Chrome on my laptop.
Share Improve this question asked Jan 30 at 20:19 NixNix 58.6k31 gold badges153 silver badges204 bronze badges 1- 1 Hey, I have the exact same issue, no workaround yet. I found these two webkit bugs that you may want to keep an eye on. --- Just reported Nov 2024, seems to match 100%: bugs.webkit./show_bug.cgi?id=282939 --- More on the WebRTC side, worked on for years, with recent user reports from just a few days ago: bugs.webkit./show_bug.cgi?id=211192#c24 – Andrew Commented Feb 4 at 0:03
1 Answer
Reset to default 2I have found a workaround! It uses the newish AudioSession API to kick iOS into rerouting properly.
In addition to the behavior in the original question, I'd like to also add that if you use a wired headset+mic, sometimes the iphone mic will still be used even though output is routed through the headphones! Very confusing.
I found a workaround for all scenarios though:
- set
navigator.audioSession.type = 'auto'
(just to reset to defaults) - call
getUserMedia({audio: true})
, this will return the iphone mic and likely reroute audio output to the handset speakers - set
navigator.audioSession.type = 'play-and-record'
This seems to "kick" iOS into rerouting audio. Now the external device's mic and speakers (headphones) will be used!
NOTE: if you attempt to set play-and-record
before calling getUserMedia
, it seems like you have a 50/50 chance of still getting the iPhone mic and not the headphones mic.
Sometimes, an additional problem will manifest after you have closed the mic stream/tracks: the audioSession will remain in play-and-record
, resulting in degraded audio output quality. The solution is to always (after releasing the mic):
- set
navigator.audioSession.type = 'playback'
- set
navigator.audioSession.type = 'auto'
(immediately, no need for a delay)
This will again "kick" iOS into rerouting / resetting audio. You'll be back in hi fidelity!
I hope this helps!
I have posted similar instructions on the newish open bug report that seems to accurately describe the issue: https://bugs.webkit./show_bug.cgi?id=282939
本文标签:
版权声明:本文标题:javascript - iOS Safari switches audio output to speakers when starting microphone recording with getUserMedia() - Stack Overflo 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1741937768a2405959.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论