11import { Asset } from 'expo-asset' ;
2- import { Audio , type AVPlaybackSource , InterruptionModeIOS } from 'expo-av' ;
3- import { Platform } from 'react-native' ;
4- import Sound from 'react-native-sound' ;
2+ import { Audio , InterruptionModeIOS } from 'expo-av' ;
53
64import { logger } from '@/lib/logging' ;
75
8- // Enable playback in silence mode
9- Sound . setCategory ( 'Ambient' , true ) ;
10-
116class AudioService {
127 private static instance : AudioService ;
13- // Use specific type for react-native-sound instances
14- private startTransmittingSound : Sound | null = null ;
15- private stopTransmittingSound : Sound | null = null ;
16-
17- // Keep others as expo-av for now
18- private connectedDeviceSound : Sound | null = null ;
19- private connectToAudioRoomSound : Sound | null = null ;
20- private disconnectedFromAudioRoomSound : Sound | null = null ;
8+
9+ // Use expo-av Sound objects
10+ private startTransmittingSound : Audio . Sound | null = null ;
11+ private stopTransmittingSound : Audio . Sound | null = null ;
12+ private connectedDeviceSound : Audio . Sound | null = null ;
13+ private connectToAudioRoomSound : Audio . Sound | null = null ;
14+ private disconnectedFromAudioRoomSound : Audio . Sound | null = null ;
15+
2116 private isInitialized = false ;
2217
2318 private constructor ( ) {
@@ -42,15 +37,12 @@ class AudioService {
4237
4338 try {
4439 // Configure audio mode for production builds
45- // Note: react-native-sound handles its own session category (Ambient),
46- // ensuring expo-av doesn't conflict is still good practice if used elsewhere.
4740 await Audio . setAudioModeAsync ( {
4841 allowsRecordingIOS : true ,
4942 staysActiveInBackground : true ,
5043 playsInSilentModeIOS : true ,
5144 shouldDuckAndroid : true ,
52- // For speaker, we want false (speaker). For others, simple routing.
53- playThroughEarpieceAndroid : false ,
45+ playThroughEarpieceAndroid : false ,
5446 interruptionModeIOS : InterruptionModeIOS . DoNotMix ,
5547 } ) ;
5648
@@ -96,60 +88,25 @@ class AudioService {
9688
9789 private async loadAudioFiles ( ) : Promise < void > {
9890 try {
99- // Load start transmitting sound (react-native-sound)
100- const startTransmittingSoundAsset = Asset . fromModule ( require ( '@assets/audio/ui/space_notification1.mp3' ) ) ;
101- await startTransmittingSoundAsset . downloadAsync ( ) ;
102- const startUri = startTransmittingSoundAsset . localUri || startTransmittingSoundAsset . uri ;
103-
104- this . startTransmittingSound = new Sound ( startUri , '' , ( error ) => {
105- if ( error ) {
106- logger . error ( { message : 'Failed to load start transmitting sound' , context : { error } } ) ;
107- }
108- } ) ;
91+ // Load start transmitting sound
92+ const { sound : startSound } = await Audio . Sound . createAsync ( require ( '@assets/audio/ui/space_notification1.mp3' ) ) ;
93+ this . startTransmittingSound = startSound ;
10994
110- // Load stop transmitting sound (react-native-sound)
111- const stopTransmittingSoundAsset = Asset . fromModule ( require ( '@assets/audio/ui/space_notification2.mp3' ) ) ;
112- await stopTransmittingSoundAsset . downloadAsync ( ) ;
113- const stopUri = stopTransmittingSoundAsset . localUri || stopTransmittingSoundAsset . uri ;
95+ // Load stop transmitting sound
96+ const { sound : stopSound } = await Audio . Sound . createAsync ( require ( '@assets/audio/ui/space_notification2.mp3' ) ) ;
97+ this . stopTransmittingSound = stopSound ;
11498
115- this . stopTransmittingSound = new Sound ( stopUri , '' , ( error ) => {
116- if ( error ) {
117- logger . error ( { message : 'Failed to load stop transmitting sound' , context : { error } } ) ;
118- }
119- } ) ;
99+ // Load connected device sound
100+ const { sound : connectedSound } = await Audio . Sound . createAsync ( require ( '@assets/audio/ui/positive_interface_beep.mp3' ) ) ;
101+ this . connectedDeviceSound = connectedSound ;
120102
121- // Load connected device sound (react-native-sound)
122- const connectedDeviceSoundAsset = Asset . fromModule ( require ( '@assets/audio/ui/positive_interface_beep.mp3' ) ) ;
123- await connectedDeviceSoundAsset . downloadAsync ( ) ;
124- const connectedUri = connectedDeviceSoundAsset . localUri || connectedDeviceSoundAsset . uri ;
103+ // Load connect to audio room sound
104+ const { sound : connectRoomSound } = await Audio . Sound . createAsync ( require ( '@assets/audio/ui/software_interface_start.mp3' ) ) ;
105+ this . connectToAudioRoomSound = connectRoomSound ;
125106
126- this . connectedDeviceSound = new Sound ( connectedUri , '' , ( error ) => {
127- if ( error ) {
128- logger . error ( { message : 'Failed to load connected device sound' , context : { error } } ) ;
129- }
130- } ) ;
131-
132- // Load connect to audio room sound (react-native-sound)
133- const connectToAudioRoomSoundAsset = Asset . fromModule ( require ( '@assets/audio/ui/software_interface_start.mp3' ) ) ;
134- await connectToAudioRoomSoundAsset . downloadAsync ( ) ;
135- const connectRoomUri = connectToAudioRoomSoundAsset . localUri || connectToAudioRoomSoundAsset . uri ;
136-
137- this . connectToAudioRoomSound = new Sound ( connectRoomUri , '' , ( error ) => {
138- if ( error ) {
139- logger . error ( { message : 'Failed to load connect to audio room sound' , context : { error } } ) ;
140- }
141- } ) ;
142-
143- // Load disconnect from audio room sound (react-native-sound)
144- const disconnectedFromAudioRoomSoundAsset = Asset . fromModule ( require ( '@assets/audio/ui/software_interface_back.mp3' ) ) ;
145- await disconnectedFromAudioRoomSoundAsset . downloadAsync ( ) ;
146- const disconnectRoomUri = disconnectedFromAudioRoomSoundAsset . localUri || disconnectedFromAudioRoomSoundAsset . uri ;
147-
148- this . disconnectedFromAudioRoomSound = new Sound ( disconnectRoomUri , '' , ( error ) => {
149- if ( error ) {
150- logger . error ( { message : 'Failed to load disconnect from audio room sound' , context : { error } } ) ;
151- }
152- } ) ;
107+ // Load disconnect from audio room sound
108+ const { sound : disconnectRoomSound } = await Audio . Sound . createAsync ( require ( '@assets/audio/ui/software_interface_back.mp3' ) ) ;
109+ this . disconnectedFromAudioRoomSound = disconnectRoomSound ;
153110
154111 logger . debug ( {
155112 message : 'Audio files loaded successfully' ,
@@ -162,21 +119,10 @@ class AudioService {
162119 }
163120 }
164121
165- // Remove old playSound helper as we are using Sound directly now
166- // private async playSound...
167-
168- // Updated to use react-native-sound
169122 async playStartTransmittingSound ( ) : Promise < void > {
170123 try {
171124 if ( this . startTransmittingSound ) {
172- // Stop if playing
173- this . startTransmittingSound . stop ( ) ;
174- // Play
175- this . startTransmittingSound . play ( ( success ) => {
176- if ( ! success ) {
177- logger . warn ( { message : 'Failed to play start transmitting sound (playback error)' } ) ;
178- }
179- } ) ;
125+ await this . startTransmittingSound . replayAsync ( ) ;
180126 }
181127 } catch ( error ) {
182128 logger . error ( {
@@ -186,19 +132,11 @@ class AudioService {
186132 }
187133 }
188134
189- // Updated to use react-native-sound
190135 async playStopTransmittingSound ( ) : Promise < void > {
191136 try {
192- if ( this . stopTransmittingSound ) {
193- // Stop if playing
194- this . stopTransmittingSound . stop ( ) ;
195- // Play
196- this . stopTransmittingSound . play ( ( success ) => {
197- if ( ! success ) {
198- logger . warn ( { message : 'Failed to play stop transmitting sound (playback error)' } ) ;
199- }
200- } ) ;
201- }
137+ if ( this . stopTransmittingSound ) {
138+ await this . stopTransmittingSound . replayAsync ( ) ;
139+ }
202140 } catch ( error ) {
203141 logger . error ( {
204142 message : 'Failed to play stop transmitting sound' ,
@@ -210,14 +148,8 @@ class AudioService {
210148 async playConnectedDeviceSound ( ) : Promise < void > {
211149 try {
212150 if ( this . connectedDeviceSound ) {
213- this . connectedDeviceSound . stop ( ) ;
214- this . connectedDeviceSound . play ( ( success ) => {
215- if ( success ) {
216- logger . debug ( { message : 'Sound played successfully' , context : { soundName : 'connectedDevice' } } ) ;
217- } else {
218- logger . warn ( { message : 'Failed to play connected device sound (playback error)' } ) ;
219- }
220- } ) ;
151+ await this . connectedDeviceSound . replayAsync ( ) ;
152+ logger . debug ( { message : 'Sound played successfully' , context : { soundName : 'connectedDevice' } } ) ;
221153 }
222154 } catch ( error ) {
223155 logger . error ( {
@@ -229,14 +161,9 @@ class AudioService {
229161
230162 async playConnectToAudioRoomSound ( ) : Promise < void > {
231163 try {
232- if ( this . connectToAudioRoomSound ) {
233- this . connectToAudioRoomSound . stop ( ) ;
234- this . connectToAudioRoomSound . play ( ( success ) => {
235- if ( ! success ) {
236- logger . warn ( { message : 'Failed to play connect to audio room sound' } ) ;
237- }
238- } ) ;
239- }
164+ if ( this . connectToAudioRoomSound ) {
165+ await this . connectToAudioRoomSound . replayAsync ( ) ;
166+ }
240167 } catch ( error ) {
241168 logger . error ( {
242169 message : 'Failed to play connected to audio room sound' ,
@@ -247,14 +174,9 @@ class AudioService {
247174
248175 async playDisconnectedFromAudioRoomSound ( ) : Promise < void > {
249176 try {
250- if ( this . disconnectedFromAudioRoomSound ) {
251- this . disconnectedFromAudioRoomSound . stop ( ) ;
252- this . disconnectedFromAudioRoomSound . play ( ( success ) => {
253- if ( ! success ) {
254- logger . warn ( { message : 'Failed to play disconnected from audio room sound' } ) ;
255- }
256- } ) ;
257- }
177+ if ( this . disconnectedFromAudioRoomSound ) {
178+ await this . disconnectedFromAudioRoomSound . replayAsync ( ) ;
179+ }
258180 } catch ( error ) {
259181 logger . error ( {
260182 message : 'Failed to play disconnected from audio room sound' ,
@@ -265,35 +187,21 @@ class AudioService {
265187
266188 async cleanup ( ) : Promise < void > {
267189 try {
268- // Unload start transmitting sound
269- if ( this . startTransmittingSound ) {
270- this . startTransmittingSound . release ( ) ;
271- this . startTransmittingSound = null ;
272- }
190+ const sounds = [ this . startTransmittingSound , this . stopTransmittingSound , this . connectedDeviceSound , this . connectToAudioRoomSound , this . disconnectedFromAudioRoomSound ] ;
273191
274- // Unload stop transmitting sound
275- if ( this . stopTransmittingSound ) {
276- this . stopTransmittingSound . release ( ) ;
277- this . stopTransmittingSound = null ;
278- }
279-
280- // Unload connected device sound
281- if ( this . connectedDeviceSound ) {
282- this . connectedDeviceSound . release ( ) ;
283- this . connectedDeviceSound = null ;
284- }
285-
286- // Unload connect to audio room sound
287- if ( this . connectToAudioRoomSound ) {
288- this . connectToAudioRoomSound . release ( ) ;
289- this . connectToAudioRoomSound = null ;
290- }
291-
292- // Unload disconnect from audio room sound
293- if ( this . disconnectedFromAudioRoomSound ) {
294- this . disconnectedFromAudioRoomSound . release ( ) ;
295- this . disconnectedFromAudioRoomSound = null ;
296- }
192+ await Promise . all (
193+ sounds . map ( async ( sound ) => {
194+ if ( sound ) {
195+ await sound . unloadAsync ( ) ;
196+ }
197+ } )
198+ ) ;
199+
200+ this . startTransmittingSound = null ;
201+ this . stopTransmittingSound = null ;
202+ this . connectedDeviceSound = null ;
203+ this . connectToAudioRoomSound = null ;
204+ this . disconnectedFromAudioRoomSound = null ;
297205
298206 this . isInitialized = false ;
299207
0 commit comments