Skip to content

Commit 12c9f08

Browse files
committed
Revert "RU-T47 PR#209 fixes"
This reverts commit f7b8233.
1 parent f7b8233 commit 12c9f08

14 files changed

Lines changed: 213 additions & 99 deletions

app.config.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ export default ({ config }: ConfigContext): ExpoConfig => ({
8181
'android.permission.FOREGROUND_SERVICE_CONNECTED_DEVICE',
8282
'android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK',
8383
'android.permission.READ_PHONE_STATE',
84+
'android.permission.READ_PHONE_NUMBERS',
8485
'android.permission.MANAGE_OWN_CALLS',
8586
],
8687
},

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -168,7 +168,7 @@
168168
"react-native-restart": "0.0.27",
169169
"react-native-safe-area-context": "5.4.0",
170170
"react-native-screens": "~4.11.1",
171-
171+
"react-native-sound": "^0.13.0",
172172
"react-native-svg": "15.11.2",
173173
"react-native-web": "^0.20.0",
174174
"react-native-webview": "~13.13.1",

src/components/livekit/__tests__/livekit-bottom-sheet.test.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,8 @@ const mockAvailableRooms = [
130130
];
131131

132132
const mockSelectedAudioDevices = {
133-
microphone: { id: 'mic1', name: 'Default Microphone', type: 'microphone' as const, isAvailable: true },
134-
speaker: { id: 'speaker1', name: 'Default Speaker', type: 'speaker' as const, isAvailable: true },
133+
microphone: { id: 'mic1', name: 'Default Microphone', type: 'default' as const, isAvailable: true },
134+
speaker: { id: 'speaker1', name: 'Default Speaker', type: 'default' as const, isAvailable: true },
135135
};
136136

137137
describe('LiveKitBottomSheet', () => {

src/components/settings/audio-device-selection.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,9 +70,9 @@ export const AudioDeviceSelection: React.FC<AudioDeviceSelectionProps> = ({ show
7070
);
7171
};
7272

73-
const availableMicrophones = availableAudioDevices.filter((device) => device.isAvailable && (device.type === 'microphone' || device.type === 'bluetooth' || device.type === 'wired'));
73+
const availableMicrophones = availableAudioDevices.filter((device) => device.isAvailable && (device.type === 'default' || device.type === 'microphone' || device.type === 'bluetooth' || device.type === 'wired'));
7474

75-
const availableSpeakers = availableAudioDevices.filter((device) => device.isAvailable && (device.type === 'speaker' || device.type === 'bluetooth' || device.type === 'wired'));
75+
const availableSpeakers = availableAudioDevices.filter((device) => device.isAvailable && (device.type === 'default' || device.type === 'speaker' || device.type === 'bluetooth' || device.type === 'wired'));
7676

7777
return (
7878
<ScrollView className="flex-1">

src/components/settings/bluetooth-device-selection-bottom-sheet.tsx

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
import { BluetoothIcon, RefreshCwIcon, WifiIcon } from 'lucide-react-native';
22
import React, { useCallback, useEffect, useState } from 'react';
33
import { useTranslation } from 'react-i18next';
4-
import { Alert, useWindowDimensions } from 'react-native';
54
import { showMessage } from 'react-native-flash-message';
5+
import { Alert, useWindowDimensions } from 'react-native';
66

77
import { Box } from '@/components/ui/box';
88
import { Button, ButtonIcon, ButtonText } from '@/components/ui/button';
@@ -108,6 +108,7 @@ export function BluetoothDeviceSelectionBottomSheet({ isOpen, onClose }: Bluetoo
108108
// Checking previous logs, service seems to play "connectedDevice".
109109

110110
onClose();
111+
111112
} catch (error) {
112113
logger.warn({
113114
message: 'Failed to connect to device',
@@ -118,7 +119,7 @@ export function BluetoothDeviceSelectionBottomSheet({ isOpen, onClose }: Bluetoo
118119
const errorMessage = error instanceof Error ? error.message : String(error);
119120
showMessage({
120121
message: t('bluetooth.connection_error_title') || 'Connection Failed',
121-
description: errorMessage === 'Device disconnected' ? t('bluetooth.device_disconnected') : errorMessage || t('bluetooth.connection_error_message') || 'Could not connect to device',
122+
description: errorMessage === 'Device disconnected' ? t('bluetooth.device_disconnected') : (errorMessage || t('bluetooth.connection_error_message') || 'Could not connect to device'),
122123
type: 'danger',
123124
duration: 4000,
124125
});

src/components/ui/actionsheet/index.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,11 @@ const ActionsheetVirtualizedList = React.forwardRef<React.ElementRef<typeof UIAc
392392
const ActionsheetFlatList = React.forwardRef<React.ElementRef<typeof UIActionsheet.FlatList>, IActionsheetFlatListProps>(({ className, style, ...props }, ref) => {
393393
return (
394394
<View className={actionsheetFlatListStyle({ class: className })} style={style}>
395-
<UIActionsheet.FlatList ref={ref} estimatedItemSize={94} {...props} />
395+
<UIActionsheet.FlatList
396+
ref={ref}
397+
estimatedItemSize={94}
398+
{...props}
399+
/>
396400
</View>
397401
);
398402
});

src/components/ui/select/select-actionsheet.tsx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -392,7 +392,11 @@ const ActionsheetVirtualizedList = React.forwardRef<React.ComponentRef<typeof UI
392392
const ActionsheetFlatList = React.forwardRef<React.ComponentRef<typeof UIActionsheet.FlatList>, IActionsheetFlatListProps>(function ActionsheetFlatList({ className, style, ...props }, ref) {
393393
return (
394394
<View className={actionsheetFlatListStyle({ class: className })} style={style}>
395-
<UIActionsheet.FlatList ref={ref} estimatedItemSize={94} {...props} />
395+
<UIActionsheet.FlatList
396+
ref={ref}
397+
estimatedItemSize={94}
398+
{...props}
399+
/>
396400
</View>
397401
);
398402
});

src/services/audio.service.ts

Lines changed: 143 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,23 @@
11
import { Asset } from 'expo-asset';
2-
import { Audio, InterruptionModeIOS } from 'expo-av';
2+
import { Audio, type AVPlaybackSource, InterruptionModeIOS } from 'expo-av';
3+
import { Platform } from 'react-native';
4+
import Sound from 'react-native-sound';
35

46
import { logger } from '@/lib/logging';
57

8+
// Enable playback in silence mode
9+
Sound.setCategory('Ambient', true);
10+
611
class AudioService {
712
private static instance: AudioService;
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-
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;
1621
private isInitialized = false;
1722

1823
private constructor() {
@@ -37,12 +42,15 @@ class AudioService {
3742

3843
try {
3944
// 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.
4047
await Audio.setAudioModeAsync({
4148
allowsRecordingIOS: true,
4249
staysActiveInBackground: true,
4350
playsInSilentModeIOS: true,
4451
shouldDuckAndroid: true,
45-
playThroughEarpieceAndroid: false,
52+
// For speaker, we want false (speaker). For others, simple routing.
53+
playThroughEarpieceAndroid: false,
4654
interruptionModeIOS: InterruptionModeIOS.DoNotMix,
4755
});
4856

@@ -88,25 +96,60 @@ class AudioService {
8896

8997
private async loadAudioFiles(): Promise<void> {
9098
try {
91-
// Load start transmitting sound
92-
const { sound: startSound } = await Audio.Sound.createAsync(require('@assets/audio/ui/space_notification1.mp3'));
93-
this.startTransmittingSound = startSound;
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+
});
94109

95-
// Load stop transmitting sound
96-
const { sound: stopSound } = await Audio.Sound.createAsync(require('@assets/audio/ui/space_notification2.mp3'));
97-
this.stopTransmittingSound = stopSound;
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;
98114

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;
115+
this.stopTransmittingSound = new Sound(stopUri, '', (error) => {
116+
if (error) {
117+
logger.error({ message: 'Failed to load stop transmitting sound', context: { error } });
118+
}
119+
});
102120

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;
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;
106125

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;
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+
});
110153

111154
logger.debug({
112155
message: 'Audio files loaded successfully',
@@ -119,10 +162,21 @@ class AudioService {
119162
}
120163
}
121164

165+
// Remove old playSound helper as we are using Sound directly now
166+
// private async playSound...
167+
168+
// Updated to use react-native-sound
122169
async playStartTransmittingSound(): Promise<void> {
123170
try {
124171
if (this.startTransmittingSound) {
125-
await this.startTransmittingSound.replayAsync();
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+
});
126180
}
127181
} catch (error) {
128182
logger.error({
@@ -132,11 +186,19 @@ class AudioService {
132186
}
133187
}
134188

189+
// Updated to use react-native-sound
135190
async playStopTransmittingSound(): Promise<void> {
136191
try {
137-
if (this.stopTransmittingSound) {
138-
await this.stopTransmittingSound.replayAsync();
139-
}
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+
}
140202
} catch (error) {
141203
logger.error({
142204
message: 'Failed to play stop transmitting sound',
@@ -148,8 +210,14 @@ class AudioService {
148210
async playConnectedDeviceSound(): Promise<void> {
149211
try {
150212
if (this.connectedDeviceSound) {
151-
await this.connectedDeviceSound.replayAsync();
152-
logger.debug({ message: 'Sound played successfully', context: { soundName: 'connectedDevice' } });
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+
});
153221
}
154222
} catch (error) {
155223
logger.error({
@@ -161,9 +229,14 @@ class AudioService {
161229

162230
async playConnectToAudioRoomSound(): Promise<void> {
163231
try {
164-
if (this.connectToAudioRoomSound) {
165-
await this.connectToAudioRoomSound.replayAsync();
166-
}
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+
}
167240
} catch (error) {
168241
logger.error({
169242
message: 'Failed to play connected to audio room sound',
@@ -174,9 +247,14 @@ class AudioService {
174247

175248
async playDisconnectedFromAudioRoomSound(): Promise<void> {
176249
try {
177-
if (this.disconnectedFromAudioRoomSound) {
178-
await this.disconnectedFromAudioRoomSound.replayAsync();
179-
}
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+
}
180258
} catch (error) {
181259
logger.error({
182260
message: 'Failed to play disconnected from audio room sound',
@@ -187,21 +265,35 @@ class AudioService {
187265

188266
async cleanup(): Promise<void> {
189267
try {
190-
const sounds = [this.startTransmittingSound, this.stopTransmittingSound, this.connectedDeviceSound, this.connectToAudioRoomSound, this.disconnectedFromAudioRoomSound];
268+
// Unload start transmitting sound
269+
if (this.startTransmittingSound) {
270+
this.startTransmittingSound.release();
271+
this.startTransmittingSound = null;
272+
}
191273

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;
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+
}
205297

206298
this.isInitialized = false;
207299

0 commit comments

Comments
 (0)