feat(livekit): improve native audio/video handling and stability
Implement robust WebRTC polyfills and native audio session management for LiveKit on mobile platforms. This includes configuring iOS audio sessions to prevent issues during calls and implementing a delayed video activation strategy to avoid main thread deadlocks on iOS. - Add WebRTC and environment polyfills in `src/polyfills.ts` - Implement iOS-specific `AudioSession` configuration in `LiveKitService` - Add support for toggling speaker output on iOS - Update `callStore` to handle video enablement after connection settles - Fix `useUnreadCountQuery` to correctly handle async fetching
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
import '../../polyfills';
|
||||
import { Platform } from 'react-native';
|
||||
import { Room, RoomEvent, Track, ConnectionState, LocalParticipant, RemoteParticipant, RemoteTrackPublication, TrackPublication, Participant as LKParticipant } from 'livekit-client';
|
||||
|
||||
export interface LiveKitServiceConfig {
|
||||
@@ -44,11 +45,26 @@ class LiveKitServiceImpl {
|
||||
return this.room?.remoteParticipants ?? new Map();
|
||||
}
|
||||
|
||||
async connect(url: string, token: string): Promise<void> {
|
||||
async connect(url: string, token: string, isVideoCall: boolean = false): Promise<void> {
|
||||
if (this.room) {
|
||||
await this.disconnect();
|
||||
}
|
||||
|
||||
// Configure native audio session before connecting (iOS only)
|
||||
if (Platform.OS === 'ios') {
|
||||
try {
|
||||
const { AudioSession } = require('@livekit/react-native');
|
||||
await AudioSession.configureAudio({
|
||||
ios: {
|
||||
defaultOutput: isVideoCall ? 'speaker' : 'default',
|
||||
},
|
||||
});
|
||||
await AudioSession.startAudioSession();
|
||||
} catch (err) {
|
||||
console.warn('[LiveKit] Audio session configuration failed:', err);
|
||||
}
|
||||
}
|
||||
|
||||
this.room = new Room({
|
||||
adaptiveStream: true,
|
||||
dynacast: true,
|
||||
@@ -87,6 +103,14 @@ class LiveKitServiceImpl {
|
||||
await this.room.disconnect();
|
||||
this.room = null;
|
||||
this._connectionStatus = 'disconnected';
|
||||
|
||||
if (Platform.OS === 'ios') {
|
||||
try {
|
||||
const { AudioSession } = require('@livekit/react-native');
|
||||
await AudioSession.stopAudioSession();
|
||||
} catch {}
|
||||
}
|
||||
|
||||
this.emit('connectionStatusChanged', 'disconnected');
|
||||
this.emit('disconnected', undefined);
|
||||
}
|
||||
@@ -98,7 +122,20 @@ class LiveKitServiceImpl {
|
||||
|
||||
async setVideoEnabled(enabled: boolean): Promise<void> {
|
||||
if (!this.room?.localParticipant) return;
|
||||
await this.room.localParticipant.setCameraEnabled(enabled);
|
||||
console.log('[LiveKit] setVideoEnabled called:', enabled);
|
||||
try {
|
||||
await this.room.localParticipant.setCameraEnabled(enabled);
|
||||
console.log('[LiveKit] setVideoEnabled succeeded:', enabled);
|
||||
} catch (err) {
|
||||
console.error('[LiveKit] setVideoEnabled failed:', err);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
async setSpeakerOn(speakerOn: boolean): Promise<void> {
|
||||
if (Platform.OS === 'web' || Platform.OS === 'android') return;
|
||||
const AudioSession = require('@livekit/react-native').AudioSession;
|
||||
await AudioSession.selectAudioOutput(speakerOn ? 'force_speaker' : 'default');
|
||||
}
|
||||
|
||||
isMuted(): boolean {
|
||||
|
||||
Reference in New Issue
Block a user