1+ import { Platform } from 'react-native' ;
12import AudioSession , {
23 type AppleAudioConfiguration ,
34} from './AudioSession' ;
@@ -10,65 +11,97 @@ export type AudioEngineConfigurationState = {
1011 preferSpeakerOutput : boolean ;
1112} ;
1213
14+ type CleanupFn = ( ) => void ;
15+
1316/**
14- * Handles setting the appropriate AVAudioSession options automatically
15- * depending on the audio track states of the Room.
17+ * Sets up automatic iOS audio session management based on audio engine state.
18+ *
19+ * Call this once at app startup (e.g. in index.js). For usage inside React
20+ * components, use {@link useIOSAudioManagement} instead.
1621 *
17- * @param preferSpeakerOutput
18- * @param onConfigureNativeAudio A custom method for determining options used.
22+ * @param preferSpeakerOutput - Whether to prefer speaker output. Defaults to true.
23+ * @param onConfigureNativeAudio - Optional custom callback for determining audio configuration.
24+ * @returns A cleanup function that removes the event handlers.
1925 */
20- export function useIOSAudioManagement (
26+ export function setupIOSAudioManagement (
2127 preferSpeakerOutput = true ,
22- onConfigureNativeAudio ?: ( configurationState : AudioEngineConfigurationState ) => AppleAudioConfiguration
23- ) {
28+ onConfigureNativeAudio ?: (
29+ configurationState : AudioEngineConfigurationState
30+ ) => AppleAudioConfiguration
31+ ) : CleanupFn {
32+ if ( Platform . OS !== 'ios' ) {
33+ return ( ) => { } ;
34+ }
35+
2436 let audioEngineState : AudioEngineConfigurationState = {
2537 isPlayoutEnabled : false ,
2638 isRecordingEnabled : false ,
27- preferSpeakerOutput : preferSpeakerOutput ,
39+ preferSpeakerOutput,
2840 } ;
2941
30- const tryConfigure = async ( newState : AudioEngineConfigurationState , oldState : AudioEngineConfigurationState ) => {
31- if ( ( ! newState . isPlayoutEnabled && ! newState . isRecordingEnabled ) && ( oldState . isPlayoutEnabled || oldState . isRecordingEnabled ) ) {
32- log . info ( "AudioSession deactivating..." )
33- await AudioSession . stopAudioSession ( )
42+ const tryConfigure = async (
43+ newState : AudioEngineConfigurationState ,
44+ oldState : AudioEngineConfigurationState
45+ ) => {
46+ if (
47+ ! newState . isPlayoutEnabled &&
48+ ! newState . isRecordingEnabled &&
49+ ( oldState . isPlayoutEnabled || oldState . isRecordingEnabled )
50+ ) {
51+ log . info ( 'AudioSession deactivating...' ) ;
52+ await AudioSession . stopAudioSession ( ) ;
3453 } else if ( newState . isRecordingEnabled || newState . isPlayoutEnabled ) {
35- const config = onConfigureNativeAudio ? onConfigureNativeAudio ( newState ) : getDefaultAppleAudioConfigurationForAudioState ( newState ) ;
36- log . info ( "AudioSession configuring category:" , config . audioCategory )
37- await AudioSession . setAppleAudioConfiguration ( config )
54+ const config = onConfigureNativeAudio
55+ ? onConfigureNativeAudio ( newState )
56+ : getDefaultAppleAudioConfigurationForAudioState ( newState ) ;
57+ log . info ( 'AudioSession configuring category:' , config . audioCategory ) ;
58+ await AudioSession . setAppleAudioConfiguration ( config ) ;
3859 if ( ! oldState . isPlayoutEnabled && ! oldState . isRecordingEnabled ) {
39- log . info ( " AudioSession activating..." )
40- await AudioSession . startAudioSession ( )
60+ log . info ( ' AudioSession activating...' ) ;
61+ await AudioSession . startAudioSession ( ) ;
4162 }
4263 }
4364 } ;
4465
45- const handleEngineStateUpdate = async ( { isPlayoutEnabled, isRecordingEnabled } : { isPlayoutEnabled : boolean , isRecordingEnabled : boolean } ) => {
66+ const handleEngineStateUpdate = async ( {
67+ isPlayoutEnabled,
68+ isRecordingEnabled,
69+ } : {
70+ isPlayoutEnabled : boolean ;
71+ isRecordingEnabled : boolean ;
72+ } ) => {
4673 const oldState = audioEngineState ;
47- const newState = {
74+ const newState : AudioEngineConfigurationState = {
4875 isPlayoutEnabled,
4976 isRecordingEnabled,
5077 preferSpeakerOutput : audioEngineState . preferSpeakerOutput ,
5178 } ;
5279
53- // If this throws, the audio engine will not continue it's operation
80+ // If this throws, the audio engine will not continue its operation
5481 await tryConfigure ( newState , oldState ) ;
5582 // Update the audio state only if configure succeeds
5683 audioEngineState = newState ;
5784 } ;
5885
59- // Attach audio engine events
6086 audioDeviceModuleEvents . setWillEnableEngineHandler ( handleEngineStateUpdate ) ;
6187 audioDeviceModuleEvents . setDidDisableEngineHandler ( handleEngineStateUpdate ) ;
88+
89+ return ( ) => {
90+ audioDeviceModuleEvents . setWillEnableEngineHandler ( null ) ;
91+ audioDeviceModuleEvents . setDidDisableEngineHandler ( null ) ;
92+ } ;
6293}
6394
6495function getDefaultAppleAudioConfigurationForAudioState (
65- configurationState : AudioEngineConfigurationState ,
96+ configurationState : AudioEngineConfigurationState
6697) : AppleAudioConfiguration {
6798 if ( configurationState . isRecordingEnabled ) {
6899 return {
69100 audioCategory : 'playAndRecord' ,
70101 audioCategoryOptions : [ 'allowBluetooth' , 'mixWithOthers' ] ,
71- audioMode : configurationState . preferSpeakerOutput ? 'videoChat' : 'voiceChat' ,
102+ audioMode : configurationState . preferSpeakerOutput
103+ ? 'videoChat'
104+ : 'voiceChat' ,
72105 } ;
73106 } else if ( configurationState . isPlayoutEnabled ) {
74107 return {
0 commit comments