@@ -30,6 +30,7 @@ import com.twilio.audioswitch.AudioSwitch
3030import com.twilio.audioswitch.LegacyAudioSwitch
3131import io.livekit.android.room.Room
3232import io.livekit.android.util.LKLog
33+ import java.util.Collections
3334import javax.inject.Inject
3435import javax.inject.Singleton
3536
@@ -54,15 +55,47 @@ constructor(private val context: Context) : AudioHandler {
5455 *
5556 * @see AudioDeviceChangeListener
5657 */
58+ @Deprecated(" Use registerAudioDeviceChangeListener." )
5759 var audioDeviceChangeListener: AudioDeviceChangeListener ? = null
5860
61+ private val audioDeviceChangeListeners = Collections .synchronizedSet(mutableSetOf<AudioDeviceChangeListener >())
62+
63+ private val audioDeviceChangeDispatcher by lazy(LazyThreadSafetyMode .NONE ) {
64+ object : AudioDeviceChangeListener {
65+ override fun invoke (audioDevices : List <AudioDevice >, selectedAudioDevice : AudioDevice ? ) {
66+ @Suppress(" DEPRECATION" )
67+ audioDeviceChangeListener?.invoke(audioDevices, selectedAudioDevice)
68+ synchronized(audioDeviceChangeListeners) {
69+ for (listener in audioDeviceChangeListeners) {
70+ listener.invoke(audioDevices, selectedAudioDevice)
71+ }
72+ }
73+ }
74+ }
75+ }
76+
5977 /* *
6078 * Listen to changes in audio focus.
6179 *
6280 * @see AudioManager.OnAudioFocusChangeListener
6381 */
82+ @Deprecated(" Use registerOnAudioFocusChangeListener." )
6483 var onAudioFocusChangeListener: AudioManager .OnAudioFocusChangeListener ? = null
6584
85+ private val onAudioFocusChangeListeners = Collections .synchronizedSet(mutableSetOf<AudioManager .OnAudioFocusChangeListener >())
86+
87+ private val onAudioFocusChangeDispatcher by lazy(LazyThreadSafetyMode .NONE ) {
88+ AudioManager .OnAudioFocusChangeListener { focusChange ->
89+ @Suppress(" DEPRECATION" )
90+ onAudioFocusChangeListener?.onAudioFocusChange(focusChange)
91+ synchronized(onAudioFocusChangeListeners) {
92+ for (listener in onAudioFocusChangeListeners) {
93+ listener.onAudioFocusChange(focusChange)
94+ }
95+ }
96+ }
97+ }
98+
6699 /* *
67100 * The preferred priority of audio devices to use. The first available audio device will be used.
68101 *
@@ -170,14 +203,14 @@ constructor(private val context: Context) : AudioHandler {
170203 AudioSwitch (
171204 context = context,
172205 loggingEnabled = loggingEnabled,
173- audioFocusChangeListener = onAudioFocusChangeListener ? : defaultOnAudioFocusChangeListener ,
206+ audioFocusChangeListener = onAudioFocusChangeDispatcher ,
174207 preferredDeviceList = preferredDeviceList ? : defaultPreferredDeviceList,
175208 )
176209 } else {
177210 LegacyAudioSwitch (
178211 context = context,
179212 loggingEnabled = loggingEnabled,
180- audioFocusChangeListener = onAudioFocusChangeListener ? : defaultOnAudioFocusChangeListener ,
213+ audioFocusChangeListener = onAudioFocusChangeDispatcher ,
181214 preferredDeviceList = preferredDeviceList ? : defaultPreferredDeviceList,
182215 )
183216 }
@@ -190,7 +223,7 @@ constructor(private val context: Context) : AudioHandler {
190223 switch.forceHandleAudioRouting = forceHandleAudioRouting
191224
192225 audioSwitch = switch
193- switch.start(audioDeviceChangeListener ? : defaultAudioDeviceChangeListener )
226+ switch.start(audioDeviceChangeDispatcher )
194227 switch.activate()
195228 }
196229 }
@@ -235,16 +268,43 @@ constructor(private val context: Context) : AudioHandler {
235268 }
236269 }
237270
271+ /* *
272+ * Listen to changes in the available and active audio devices.
273+ * @see unregisterAudioDeviceChangeListener
274+ */
275+ fun registerAudioDeviceChangeListener (listener : AudioDeviceChangeListener ) {
276+ audioDeviceChangeListeners.add(listener)
277+ }
278+
279+ /* *
280+ * Remove a previously registered audio device change listener.
281+ * @see registerAudioDeviceChangeListener
282+ */
283+ fun unregisterAudioDeviceChangeListener (listener : AudioDeviceChangeListener ) {
284+ audioDeviceChangeListeners.remove(listener)
285+ }
286+
287+ /* *
288+ * Listen to changes in audio focus.
289+ *
290+ * @see AudioManager.OnAudioFocusChangeListener
291+ * @see unregisterOnAudioFocusChangeListener
292+ */
293+ fun registerOnAudioFocusChangeListener (listener : AudioManager .OnAudioFocusChangeListener ) {
294+ onAudioFocusChangeListeners.add(listener)
295+ }
296+
297+ /* *
298+ * Remove a previously registered focus change listener.
299+ *
300+ * @see AudioManager.OnAudioFocusChangeListener
301+ * @see registerOnAudioFocusChangeListener
302+ */
303+ fun unregisterOnAudioFocusChangeListener (listener : AudioManager .OnAudioFocusChangeListener ) {
304+ onAudioFocusChangeListeners.remove(listener)
305+ }
306+
238307 companion object {
239- private val defaultOnAudioFocusChangeListener by lazy(LazyThreadSafetyMode .NONE ) {
240- AudioManager .OnAudioFocusChangeListener { }
241- }
242- private val defaultAudioDeviceChangeListener by lazy(LazyThreadSafetyMode .NONE ) {
243- object : AudioDeviceChangeListener {
244- override fun invoke (audioDevices : List <AudioDevice >, selectedAudioDevice : AudioDevice ? ) {
245- }
246- }
247- }
248308 private val defaultPreferredDeviceList by lazy(LazyThreadSafetyMode .NONE ) {
249309 listOf (
250310 AudioDevice .BluetoothHeadset ::class .java,
0 commit comments