| Summary: | Web audio rendering becomes garbled with switching from speakers to headphones (and vice-versa) | ||
|---|---|---|---|
| Product: | WebKit | Reporter: | Ludo <lmillot> |
| Component: | Web Audio | Assignee: | Chris Dumez <cdumez> |
| Status: | RESOLVED FIXED | ||
| Severity: | Normal | CC: | cdumez, eric.carlson, jer.noble, seth.wang, webkit-bug-importer, youennf |
| Priority: | P2 | Keywords: | InRadar |
| Version: | Safari 15 | ||
| Hardware: | Mac (Apple Silicon) | ||
| OS: | macOS 12 | ||
|
Description
Ludo
2022-06-02 05:54:04 PDT
I have just tried the demo site but it didn't even output anything on the speakers for me. It did work on Chrome though. OK, I am able to reproduce now. A few findings: 1. This has nothing to do with AudioWorklet and it is reproducible with just an OscillatorNode in the audio graph 2. It is likely due to some state that remains in the GPUProcess. The reason I say this is that if you start with speakers and then plug in your headphones, the sound will become bad. If you reload the tab, the sound will remain bad. If you open the demo in a new tab, the sound is still bad as well. However, if you restart Safari, the sound becomes OK (with headphones). Then if you unplug the headphones, the sound becomes bad with the speakers. One thing I noticed is that RemoteAudioDestination::render() normally gets called with numberOfFrames=128. However, when I plug in the headphones, RemoteAudioDestination::render() then gets called consistently with numberOfFrames=480. (In reply to Chris Dumez from comment #4) > One thing I noticed is that RemoteAudioDestination::render() normally gets > called with numberOfFrames=128. However, when I plug in the headphones, > RemoteAudioDestination::render() then gets called consistently with > numberOfFrames=480. And when I restart the browser with the headphone plugged in, numberOfFrames becomes 128 again. As far as I know, our code assumes a rendering quantum of 128 for WebAudio so it is probably not too surprising that rendering goes bad when the rendering quantum becomes 480. As far as I know MediaSessionManagerCocoa::updateSessionState() is supposed to set the preferred buffer size of 128 when Web Audio is in use. However, clearly this gets ignored when switching audio output. (In reply to Chris Dumez from comment #5) > (In reply to Chris Dumez from comment #4) > > One thing I noticed is that RemoteAudioDestination::render() normally gets > > called with numberOfFrames=128. However, when I plug in the headphones, > > RemoteAudioDestination::render() then gets called consistently with > > numberOfFrames=480. > > And when I restart the browser with the headphone plugged in, numberOfFrames > becomes 128 again. As far as I know, our code assumes a rendering quantum of > 128 for WebAudio so it is probably not too surprising that rendering goes > bad when the rendering quantum becomes 480. > > As far as I know MediaSessionManagerCocoa::updateSessionState() is supposed > to set the preferred buffer size of 128 when Web Audio is in use. However, > clearly this gets ignored when switching audio output. Ok, so interestingly, MediaSessionManagerCocoa::updateSessionState() does get called when I plug in my headphones and does call `AudioSession::sharedSession().setPreferredBufferSize(128)`. However, `AudioSessionMac::setPreferredBufferSize()` early returns because `m_bufferSize == bufferSize`. If I comment out the early return when `m_bufferSize == bufferSize`, then the audio stays good when plugging in the headphones. (In reply to Chris Dumez from comment #6) > (In reply to Chris Dumez from comment #5) > > (In reply to Chris Dumez from comment #4) > > > One thing I noticed is that RemoteAudioDestination::render() normally gets > > > called with numberOfFrames=128. However, when I plug in the headphones, > > > RemoteAudioDestination::render() then gets called consistently with > > > numberOfFrames=480. > > > > And when I restart the browser with the headphone plugged in, numberOfFrames > > becomes 128 again. As far as I know, our code assumes a rendering quantum of > > 128 for WebAudio so it is probably not too surprising that rendering goes > > bad when the rendering quantum becomes 480. > > > > As far as I know MediaSessionManagerCocoa::updateSessionState() is supposed > > to set the preferred buffer size of 128 when Web Audio is in use. However, > > clearly this gets ignored when switching audio output. > > Ok, so interestingly, MediaSessionManagerCocoa::updateSessionState() does > get called when I plug in my headphones and does call > `AudioSession::sharedSession().setPreferredBufferSize(128)`. However, > `AudioSessionMac::setPreferredBufferSize()` early returns because > `m_bufferSize == bufferSize`. > > If I comment out the early return when `m_bufferSize == bufferSize`, then > the audio stays good when plugging in the headphones. Normally, you'd expect AudioSessionMac::handleBufferSizeChange() to get called here and update m_bufferSize since the buffer size did change. However, we set the listener in AudioSessionMac::addBufferSizeObserverIfNeeded(), we pass in the defaultDevice(). However, the default device is changing when we connect the headphones. As a result, our observer becomes useless. Pull request: https://github.com/WebKit/WebKit/pull/6501 Committed 256712@main (91ac45e95dc3): <https://commits.webkit.org/256712@main> Reviewed commits have been landed. Closing PR #6501 and removing active labels. *** Bug 248592 has been marked as a duplicate of this bug. *** |