Add audio output switcher for voice calls (Android speaker fix)
- Add Audio button during active calls to switch output - Fallback to Speaker/Earpiece options when LiveKit API unavailable - Speaker now works correctly on Android 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
8dd8590c1c
commit
5b5cdf1098
@ -45,6 +45,7 @@ import {
|
|||||||
import { ConnectionState, Track } from 'livekit-client';
|
import { ConnectionState, Track } from 'livekit-client';
|
||||||
import { getToken, type BeneficiaryData } from '@/services/livekitService';
|
import { getToken, type BeneficiaryData } from '@/services/livekitService';
|
||||||
import { useAuth } from '@/contexts/AuthContext';
|
import { useAuth } from '@/contexts/AuthContext';
|
||||||
|
import { getAvailableAudioOutputs, selectAudioOutput, setAudioOutput } from '@/utils/audioSession';
|
||||||
|
|
||||||
// Register LiveKit globals (must be called before using LiveKit)
|
// Register LiveKit globals (must be called before using LiveKit)
|
||||||
registerGlobals();
|
registerGlobals();
|
||||||
@ -612,6 +613,40 @@ export default function ChatScreen() {
|
|||||||
endVoiceCallContext();
|
endVoiceCallContext();
|
||||||
}, [endVoiceCallContext, callState.callDuration]);
|
}, [endVoiceCallContext, callState.callDuration]);
|
||||||
|
|
||||||
|
// Audio output picker
|
||||||
|
const showAudioPicker = useCallback(async () => {
|
||||||
|
const devices = await getAvailableAudioOutputs();
|
||||||
|
|
||||||
|
// If devices found from LiveKit API, use them
|
||||||
|
if (devices.length > 0) {
|
||||||
|
const buttons: any[] = devices.map(device => ({
|
||||||
|
text: device.name,
|
||||||
|
onPress: () => selectAudioOutput(device.id),
|
||||||
|
}));
|
||||||
|
buttons.push({ text: 'Cancel', style: 'cancel' });
|
||||||
|
Alert.alert('Audio Output', 'Select audio device:', buttons);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback for Android (and iOS if no devices found)
|
||||||
|
// Show simple Speaker/Earpiece toggle using setAudioOutput()
|
||||||
|
Alert.alert(
|
||||||
|
'Audio Output',
|
||||||
|
'Select audio output:',
|
||||||
|
[
|
||||||
|
{
|
||||||
|
text: '🔊 Speaker',
|
||||||
|
onPress: () => setAudioOutput(true),
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: '📱 Earpiece',
|
||||||
|
onPress: () => setAudioOutput(false),
|
||||||
|
},
|
||||||
|
{ text: 'Cancel', style: 'cancel' },
|
||||||
|
]
|
||||||
|
);
|
||||||
|
}, []);
|
||||||
|
|
||||||
// Handle voice transcript entries - add to chat in real-time
|
// Handle voice transcript entries - add to chat in real-time
|
||||||
const handleVoiceTranscript = useCallback((role: 'user' | 'assistant', text: string) => {
|
const handleVoiceTranscript = useCallback((role: 'user' | 'assistant', text: string) => {
|
||||||
if (!text.trim()) return;
|
if (!text.trim()) return;
|
||||||
@ -1025,6 +1060,15 @@ export default function ChatScreen() {
|
|||||||
</Text>
|
</Text>
|
||||||
</View>
|
</View>
|
||||||
)}
|
)}
|
||||||
|
{/* Audio output button - only during active call */}
|
||||||
|
{isCallActive && (
|
||||||
|
<TouchableOpacity
|
||||||
|
style={styles.audioButton}
|
||||||
|
onPress={showAudioPicker}
|
||||||
|
>
|
||||||
|
<Ionicons name="volume-high" size={20} color={AppColors.primary} />
|
||||||
|
</TouchableOpacity>
|
||||||
|
)}
|
||||||
|
|
||||||
<TextInput
|
<TextInput
|
||||||
style={styles.input}
|
style={styles.input}
|
||||||
@ -1238,6 +1282,17 @@ const styles = StyleSheet.create({
|
|||||||
backgroundColor: AppColors.error,
|
backgroundColor: AppColors.error,
|
||||||
borderColor: AppColors.error,
|
borderColor: AppColors.error,
|
||||||
},
|
},
|
||||||
|
audioButton: {
|
||||||
|
width: 44,
|
||||||
|
height: 44,
|
||||||
|
borderRadius: 22,
|
||||||
|
backgroundColor: AppColors.surface,
|
||||||
|
justifyContent: 'center',
|
||||||
|
alignItems: 'center',
|
||||||
|
marginRight: Spacing.sm,
|
||||||
|
borderWidth: 1,
|
||||||
|
borderColor: AppColors.primary,
|
||||||
|
},
|
||||||
callActiveIndicator: {
|
callActiveIndicator: {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '100%',
|
height: '100%',
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user