import 'well-known-symbols/Symbol.asyncIterator/auto'; import 'well-known-symbols/Symbol.iterator/auto'; import './polyfills/MediaRecorderShim'; import { registerGlobals as webrtcRegisterGlobals } from '@livekit/react-native-webrtc'; import { setupURLPolyfill } from 'react-native-url-polyfill'; import './polyfills/EncoderDecoderTogether.min.js'; import AudioSession, { AndroidAudioTypePresets, type AndroidAudioTypeOptions, type AppleAudioCategory, type AppleAudioCategoryOption, type AppleAudioConfiguration, type AppleAudioMode, type AudioTrackState, getDefaultAppleAudioConfigurationForMode, } from './audio/AudioSession'; import type { AudioConfiguration } from './audio/AudioSession'; import { PixelRatio, Platform } from 'react-native'; import { type LiveKitReactNativeInfo } from 'livekit-client'; import type { LogLevel, SetLogLevelOptions } from './logger'; import RNE2EEManager from './e2ee/RNE2EEManager'; import RNKeyProvider, { type RNKeyProviderOptions } from './e2ee/RNKeyProvider'; import { setupNativeEvents } from './events/EventEmitter'; import { ReadableStream, WritableStream } from 'web-streams-polyfill'; export interface RegisterGlobalsOptions { /** * Automatically configure audio session before accessing microphone. * When enabled, sets the iOS audio category to 'playAndRecord' before getUserMedia. * Has no effect on non-iOS platforms. * * @default true */ autoConfigureAudioSession?: boolean; } /** * Registers the required globals needed for LiveKit to work. * * Must be called before using LiveKit. * * @param options Optional configuration for global registration */ export function registerGlobals(options?: RegisterGlobalsOptions) { const opts = { autoConfigureAudioSession: true, ...options, }; webrtcRegisterGlobals(); if (opts.autoConfigureAudioSession) { iosCategoryEnforce(); } livekitRegisterGlobals(); setupURLPolyfill(); fixWebrtcAdapter(); shimPromiseAllSettled(); shimArrayAt(); shimCryptoUuid(); shimWebstreams(); setupNativeEvents(); } /** * Enforces changing to playAndRecord category prior to obtaining microphone. */ function iosCategoryEnforce() { if (Platform.OS === 'ios') { // @ts-ignore let getUserMediaFunc = global.navigator.mediaDevices.getUserMedia; // @ts-ignore global.navigator.mediaDevices.getUserMedia = async (constraints: any) => { if (constraints.audio) { await AudioSession.setAppleAudioConfiguration({ audioCategory: 'playAndRecord', }); } return await getUserMediaFunc(constraints); }; } } function livekitRegisterGlobals() { let lkGlobal: LiveKitReactNativeInfo = { platform: Platform.OS, devicePixelRatio: PixelRatio.get(), }; // @ts-ignore global.LiveKitReactNativeGlobal = lkGlobal; } function fixWebrtcAdapter() { // @ts-ignore if (window?.navigator !== undefined) { // @ts-ignore const { navigator } = window; if (navigator.userAgent === undefined) { navigator.userAgent = navigator.product ?? 'Unknown'; } } } function shimPromiseAllSettled() { var allSettled = require('promise.allsettled'); allSettled.shim(); } function shimArrayAt() { // Some versions of RN don't have Array.prototype.at, which is used by sdp-transform if (!Array.prototype.at) { var at = require('array.prototype.at'); at.shim(); } } function shimCryptoUuid() { let crypto = global.crypto; if (typeof global.crypto?.randomUUID !== 'function') { let createRandomUUID = () => { return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace( /[xy]/g, function (c) { /* eslint-disable no-bitwise */ const r = (Math.random() * 16) | 0; const v = c === 'x' ? r : (r & 0x3) | 0x8; return v.toString(16); } ) as `${string}-${string}-${string}-${string}-${string}`; }; if (!crypto) { crypto = {} as typeof global.crypto; global.crypto = crypto; } crypto.randomUUID = createRandomUUID; } } function shimWebstreams() { // @ts-expect-error: global.WritableStream isn't typed here. if (typeof global.WritableStream === 'undefined') { // @ts-expect-error global.WritableStream = WritableStream; } // @ts-expect-error: global.ReadableStream isn't typed here. if (typeof global.ReadableStream === 'undefined') { // @ts-expect-error global.ReadableStream = ReadableStream; } } export * from './hooks'; export * from './components/BarVisualizer'; export * from './components/LiveKitRoom'; export * from './components/VideoTrack'; export * from './components/VideoView'; // deprecated export * from './useParticipant'; // deprecated export * from './useRoom'; // deprecated export * from './logger'; export * from './audio/AudioManager'; export * from './audio/MediaRecorder'; export { AudioSession, RNE2EEManager, RNKeyProvider, AndroidAudioTypePresets, getDefaultAppleAudioConfigurationForMode, }; export type { AudioConfiguration, AndroidAudioTypeOptions, AppleAudioCategory, AppleAudioCategoryOption, AppleAudioConfiguration, AppleAudioMode, AudioTrackState, LogLevel, SetLogLevelOptions, RNKeyProviderOptions, };