When running the simple code below in Safari with AirPods, we only get a single dataavailable
event that has any data:
dataavailable 1536
dataavailable 0
dataavailable 0
dataavailable 0
dataavailable 0
... and so on
The rest of the events have 0 length, so there is no data coming from the AirPods. It works fine without AirPods (e.g. Built in MacBook M2 microphone as well as using iPhone as an external Mic). Everything works fine on MacOS in Chrome using AirPods. Also the <audio>
tag correctly plays back the audio, e.g. I can hear myself (with AirPods on Safari) so I know the audio streaming is working. It's probably something I'm doing wrong with the initialization or usage of the MediaRecorder
.
Alternatively is there any other way to fetch raw data from a getUserMedia
stream than using a MediaRecorder
?
// Based On https://github.com/webrtc/samples/tree/gh-pages/src/content/getusermedia/audio
document.querySelector("#micTest").addEventListener('click', async function(){
if ( window.stream ) {
this.innerText = "Test Microphone";
} else {
this.innerText = "Stop Test";
}
if (!navigator.mediaDevices) throw new Error('unsupported mediaDevices');
if (window.stream) {
window.stream.getAudioTracks().forEach(track => track.stop());
window.stream = null;
return;
}
await navigator.mediaDevices.getUserMedia({ audio: true, video: false });
const devices = await navigator.mediaDevices.enumerateDevices()
const devStr = devices.map((d) => `${d.deviceId}:${d.label}`).join('\n');
const deviceId = window.prompt(`choose device: ${devStr}`);
if (!deviceId) return;
const constraints = window.constraints = {
audio: { deviceId },
video: false
}
const stream = await navigator.mediaDevices.getUserMedia(constraints)
window.stream = stream;
const audio = document.createElement('audio');
audio.controls = true;
audio.autoplay = true;
audio.srcObject = stream;
const mediaRecorder = new MediaRecorder(stream);
mediaRecorder.addEventListener('dataavailable', async (e) => {
console.log('dataavailable', e.data.size)
})
mediaRecorder.addEventListener('pause', () => console.log('pause'))
mediaRecorder.addEventListener('error', (err) => console.log('error', err))
mediaRecorder.addEventListener('stop', (err) => console.log('stop'))
mediaRecorder.start(5000);
stream.oninactive = function() {
console.log('Stream ended');
};
});
<main class="has-background-dark">
<div class="is-family-sans-serif has-text-white has-text-centered">
<h1 class="is-size-1 has-text-centered is-uppercase has-text-weight-bold">Sound check!</h1>
<p class="">See if your microphone and headphones are setup properly</p>
<p> For the Microphone test, a prompt will appear asking for permission to access your select output device </p>
<p>If you are not using headphones, it'll have a loop feedback</p>
<p></p>
<button class="button is-primary is-fullwidth is-large" id="micTest" type="button">Test Microphone</button>
</div>
</main>