Conversation
|
lukasIO
left a comment
There was a problem hiding this comment.
Thanks for the PR!
I believe the speaker selection API comes with some more caveats (explicit user permission must be granted for output selection if no microphone is acquired yet).
I haven't tested this, but probably needs its own selection path via MediaDevices.selectAudioOutput ?
| return ( | ||
| (browser?.name === 'Safari' && compareVersions(browser.version, '26') >= 0) || | ||
| (browser?.os === 'iOS' && !!browser?.osVersion && compareVersions(browser.osVersion, '26') >= 0) || | ||
| (browser?.os === 'macOS' && !!browser?.osVersion && compareVersions(browser.osVersion, '26') >= 0) |
There was a problem hiding this comment.
this check is not connected to checking against Safari, I believe?
13aa615 to
d2eab63
Compare
…election API since iOS26 and iPadOS26.
f779352 to
2b09b51
Compare
|
@fkwp If it's helpful, a few months back I spent a bit of time attempting to further adapt your changes to get ios speaker selection to work. I wasn't able to get it all the way there (and the effort has since been deprioritized), but maybe some of this code could be useful in your effort here: https://github.com/livekit/client-sdk-js/tree/ios-speaker-selection |
@1egoman nice Ill definitely will look into this. I used https://github.com/livekit-examples/meet as reference app and meanwhile the following stack is working on my end (given you also publish audio): |
418a8b1 to
9110173
Compare
|
Per comment left in #1836, some more notes from when I attempted to dig into this on my own, in case they would be helpful to anybody else attempting to introduce speaker selection support: I was able to get the api working on my test iphone 11, but was NOT able to get the api to work when I integrated it within Importantly, if I add a button into the demo app which on tap reaches into the DOM, gets the active audio element playing remote participant audio, and manually calls setSinkId on it, this works and works every single time without fail. So the APIs definitely exist on my test iphone. A few things that might be part of the problem with integrating into livekit-client:
|
Support iOS 26 Speaker Selection API
Apple added
HTMLMediaElement.setSinkId()in iOS/iPadOS 26 and Safari 26. However, calling it directly on<audio>elements backed by WebRTC remote tracks is silently ignored. It seems iOS renders that audio through the WebRTC engine's internal pipeline (→ AVAudioSession), bypassing the AVPlayer pipeline thatsetSinkIdcontrols.This PR adds a shared WebAudio relay element per AudioContext: all remote tracks mix into one
MediaStreamAudioDestinationNode, played via a single<audio>element on whichsetSinkIdis called once during the user gesture inswitchActiveDevice. iOS grants the permission once for the lifetime of that element, so participants joining later route correctly without their own user gesture.RTCPeerConnection remote track A ─┐
RTCPeerConnection remote track B ─┼─→ shared MediaStreamDestinationNode ─→ shared ← setSinkId() here
RTCPeerConnection remote track C ─┘
(each via AudioContext + GainNode)
Changes
isSafariSpeakerSelectionSupported()— detects iOS/Safari 26+supportsSetSinkId()— returnstruefor iOS 26+ (skips feature-detection that misfires before DOM attachment)getOrCreateSharedRelay()/disposeSharedRelay()— lazy AudioContext-scoped relay setupRemoteAudioTrack.connectWebAudioroutes the gain node to the shared destination whenAudioContext.setSinkIdis unavailableRoom.switchActiveDevicecallssetSinkIdon the shared relay for the iOS 26 path; per-participantsetAudioOutputpath retained for Chrome (echo cancellation) and otherbrowsers
selectDefaultDevices/handleDeviceChangeno longer block audiooutput auto-switching on iOS 26supportsSetSinkIdexported alongsideisSafariSpeakerSelectionSupportedfixes #1568
My testing stack is https://github.com/livekit-examples/meet as reference app and meanwhile the following stack is working on my end: