diff --git a/ci/ios/Podfile.lock b/ci/ios/Podfile.lock index 3b8b5d1c..8bdfa446 100644 --- a/ci/ios/Podfile.lock +++ b/ci/ios/Podfile.lock @@ -8,7 +8,7 @@ PODS: - hermes-engine (0.82.0): - hermes-engine/Pre-built (= 0.82.0) - hermes-engine/Pre-built (0.82.0) - - livekit-react-native (2.9.8): + - livekit-react-native (2.10.0): - boost - DoubleConversion - fast_float @@ -37,7 +37,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - livekit-react-native-webrtc (144.0.0): + - livekit-react-native-webrtc (144.1.0-beta.0): - React-Core - WebRTC-SDK (= 144.7559.01) - RCT-Folly (2024.11.18.00): @@ -2692,8 +2692,8 @@ SPEC CHECKSUMS: fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 hermes-engine: 8642d8f14a548ab718ec112e9bebdfdd154138b5 - livekit-react-native: 16923c9c9cdf21c68cbac52f9a5222c9f05c2f06 - livekit-react-native-webrtc: a9a45c67543105a40192b144809513e5ab266d0a + livekit-react-native: 0d36ebbf20e663c7d1abb7079e1cf1237f3bcb02 + livekit-react-native-webrtc: 2023c6774526d44024e77f98e37d233f8df1a326 RCT-Folly: 846fda9475e61ec7bcbf8a3fe81edfcaeb090669 RCTDeprecation: f17e2ebc07876ca9ab8eb6e4b0a4e4647497ae3a RCTRequired: e2c574c1b45231f7efb0834936bd609d75072b63 diff --git a/ci/package.json b/ci/package.json index 362acd2d..25bff5d3 100644 --- a/ci/package.json +++ b/ci/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@livekit/react-native": "*", - "@livekit/react-native-webrtc": "^144.0.0", + "@livekit/react-native-webrtc": "^144.1.0-beta.0", "@react-native/new-app-screen": "0.82.1", "livekit-client": "^2.15.8", "react": "19.1.1", diff --git a/ci/yarn.lock b/ci/yarn.lock index 0db52754..1d773ae2 100644 --- a/ci/yarn.lock +++ b/ci/yarn.lock @@ -1953,15 +1953,15 @@ __metadata: languageName: node linkType: hard -"@livekit/react-native-webrtc@npm:^144.0.0": - version: 144.0.0 - resolution: "@livekit/react-native-webrtc@npm:144.0.0" +"@livekit/react-native-webrtc@npm:^144.1.0-beta.0": + version: 144.1.0-beta.0 + resolution: "@livekit/react-native-webrtc@npm:144.1.0-beta.0" dependencies: base64-js: "npm:1.5.1" debug: "npm:4.3.4" peerDependencies: react-native: ">=0.60.0" - checksum: 10/d97454e8bcb5ab0ae98e8a9d134f8486276b12bdf993052b5b01ac3e8da375e63bb66c84061201bd4499266afbe383a9a065c85c19b0734d659bc21fcf156508 + checksum: 10/d03b01c97bd6bad3e27908abbc2889e0c7e47af953e1f1d7824d8bc8babf4a2b91f59d719c9f5603329aa9fc1f8fcdac9f2f431b5e32ab88095168317f797b41 languageName: node linkType: hard @@ -3587,7 +3587,7 @@ __metadata: "@babel/preset-env": "npm:^7.25.3" "@babel/runtime": "npm:^7.25.0" "@livekit/react-native": "npm:*" - "@livekit/react-native-webrtc": "npm:^144.0.0" + "@livekit/react-native-webrtc": "npm:^144.1.0-beta.0" "@react-native-community/cli": "npm:20.0.0" "@react-native-community/cli-platform-android": "npm:20.0.0" "@react-native-community/cli-platform-ios": "npm:20.0.0" diff --git a/example/index.js b/example/index.js index 231dc300..619c8ea2 100644 --- a/example/index.js +++ b/example/index.js @@ -1,7 +1,11 @@ import { AppRegistry } from 'react-native'; import App from './src/App'; import { name as appName } from './app.json'; -import { registerGlobals, setLogLevel } from '@livekit/react-native'; +import { + registerGlobals, + setLogLevel, + setupIOSAudioManagement, +} from '@livekit/react-native'; import { LogLevel } from 'livekit-client'; import { setupErrorLogHandler } from './src/utils/ErrorLogHandler'; import { setupCallService } from './src/callservice/CallService'; @@ -16,3 +20,5 @@ setupCallService(); // Required React-Native setup for app registerGlobals(); AppRegistry.registerComponent(appName, () => App); + +setupIOSAudioManagement(); diff --git a/example/ios/Podfile.lock b/example/ios/Podfile.lock index 8b3e6389..5b88ef49 100644 --- a/example/ios/Podfile.lock +++ b/example/ios/Podfile.lock @@ -8,7 +8,7 @@ PODS: - hermes-engine (0.82.0): - hermes-engine/Pre-built (= 0.82.0) - hermes-engine/Pre-built (0.82.0) - - livekit-react-native (2.9.8): + - livekit-react-native (2.10.0): - boost - DoubleConversion - fast_float @@ -37,7 +37,7 @@ PODS: - ReactCommon/turbomodule/core - SocketRocket - Yoga - - livekit-react-native-webrtc (144.0.0): + - livekit-react-native-webrtc (144.1.0-beta.0): - React-Core - WebRTC-SDK (= 144.7559.01) - RCT-Folly (2024.11.18.00): @@ -2790,8 +2790,8 @@ SPEC CHECKSUMS: fmt: a40bb5bd0294ea969aaaba240a927bd33d878cdd glog: 5683914934d5b6e4240e497e0f4a3b42d1854183 hermes-engine: 8642d8f14a548ab718ec112e9bebdfdd154138b5 - livekit-react-native: 16923c9c9cdf21c68cbac52f9a5222c9f05c2f06 - livekit-react-native-webrtc: a9a45c67543105a40192b144809513e5ab266d0a + livekit-react-native: 0d36ebbf20e663c7d1abb7079e1cf1237f3bcb02 + livekit-react-native-webrtc: 2023c6774526d44024e77f98e37d233f8df1a326 RCT-Folly: 59ec0ac1f2f39672a0c6e6cecdd39383b764646f RCTDeprecation: f17e2ebc07876ca9ab8eb6e4b0a4e4647497ae3a RCTRequired: e2c574c1b45231f7efb0834936bd609d75072b63 diff --git a/example/package.json b/example/package.json index 8efc933d..ff500672 100644 --- a/example/package.json +++ b/example/package.json @@ -10,7 +10,7 @@ "postinstall": "patch-package" }, "dependencies": { - "@livekit/react-native-webrtc": "^144.0.0", + "@livekit/react-native-webrtc": "^144.1.0-beta.0", "@react-native-async-storage/async-storage": "^1.17.10", "@react-navigation/native": "^7.1.18", "@react-navigation/native-stack": "^7.3.27", diff --git a/example/src/RoomPage.tsx b/example/src/RoomPage.tsx index b114f5b3..b96e57a5 100644 --- a/example/src/RoomPage.tsx +++ b/example/src/RoomPage.tsx @@ -25,7 +25,6 @@ import { useTracks, type TrackReferenceOrPlaceholder, AndroidAudioTypePresets, - useIOSAudioManagement, useRNE2EEManager, } from '@livekit/react-native'; import { Platform } from 'react-native'; @@ -106,8 +105,6 @@ const RoomView = ({ navigation, e2ee }: RoomViewProps) => { return () => {}; }, [room, e2ee]); - useIOSAudioManagement(room, true); - // Setup room listeners useEffect(() => { room.registerTextStreamHandler('lk.chat', async (reader, participant) => { diff --git a/ios/LiveKitReactNativeModule.swift b/ios/LiveKitReactNativeModule.swift index b3c3ef47..feb6d415 100644 --- a/ios/LiveKitReactNativeModule.swift +++ b/ios/LiveKitReactNativeModule.swift @@ -29,7 +29,7 @@ public class LivekitReactNativeModule: RCTEventEmitter { super.init() let config = RTCAudioSessionConfiguration() config.category = AVAudioSession.Category.playAndRecord.rawValue - config.categoryOptions = [.allowAirPlay, .allowBluetooth, .allowBluetoothA2DP, .defaultToSpeaker] + config.categoryOptions = [.allowAirPlay, .allowBluetoothHFP, .allowBluetoothA2DP, .defaultToSpeaker] config.mode = AVAudioSession.Mode.videoChat.rawValue RTCAudioSessionConfiguration.setWebRTC(config) diff --git a/package.json b/package.json index d38b5ef2..44d4478e 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "@eslint/eslintrc": "^3.3.1", "@eslint/js": "^9.35.0", "@livekit/changesets-changelog-github": "^0.0.4", - "@livekit/react-native-webrtc": "^144.0.0", + "@livekit/react-native-webrtc": "^144.1.0-beta.0", "@react-native/babel-preset": "0.83.0", "@react-native/eslint-config": "0.83.0", "@release-it/conventional-changelog": "10.0.1", @@ -94,7 +94,7 @@ "typescript": "^5.9.2" }, "peerDependencies": { - "@livekit/react-native-webrtc": "^144.0.0", + "@livekit/react-native-webrtc": "^144.1.0-beta.0", "livekit-client": "^2.15.8", "react": "*", "react-native": "*" diff --git a/src/audio/AudioManager.ts b/src/audio/AudioManager.ts index f227bd7c..68894ded 100644 --- a/src/audio/AudioManager.ts +++ b/src/audio/AudioManager.ts @@ -1,141 +1,132 @@ -import { useState, useEffect, useMemo } from 'react'; import { Platform } from 'react-native'; -import { - RoomEvent, - Room, - type LocalTrackPublication, - type RemoteTrackPublication, -} from 'livekit-client'; -import AudioSession, { - getDefaultAppleAudioConfigurationForMode, - type AppleAudioConfiguration, - type AudioTrackState, -} from './AudioSession'; +import AudioSession, { type AppleAudioConfiguration } from './AudioSession'; import { log } from '..'; +import { audioDeviceModuleEvents } from '@livekit/react-native-webrtc'; + +export type AudioEngineConfigurationState = { + isPlayoutEnabled: boolean; + isRecordingEnabled: boolean; + preferSpeakerOutput: boolean; +}; + +const kAudioEngineErrorFailedToConfigureAudioSession = -4100; + +type CleanupFn = () => void; /** - * Handles setting the appropriate AVAudioSession options automatically - * depending on the audio track states of the Room. + * Sets up automatic iOS audio session management based on audio engine state. + * + * Call this once at app startup (e.g. in index.js). For usage inside React + * components, use {@link useIOSAudioManagement} instead. * - * @param room - * @param preferSpeakerOutput - * @param onConfigureNativeAudio A custom method for determining options used. + * @param preferSpeakerOutput - Whether to prefer speaker output. Defaults to true. + * @param onConfigureNativeAudio - Optional custom callback for determining audio configuration. + * @returns A cleanup function that removes the event handlers. */ -export function useIOSAudioManagement( - room: Room, - preferSpeakerOutput: boolean = true, +export function setupIOSAudioManagement( + preferSpeakerOutput = true, onConfigureNativeAudio?: ( - trackState: AudioTrackState, - preferSpeakerOutput: boolean + configurationState: AudioEngineConfigurationState ) => AppleAudioConfiguration -) { - const [localTrackCount, setLocalTrackCount] = useState(0); - const [remoteTrackCount, setRemoteTrackCount] = useState(0); - const trackState = useMemo( - () => computeAudioTrackState(localTrackCount, remoteTrackCount), - [localTrackCount, remoteTrackCount] - ); - - useEffect(() => { - let recalculateTrackCounts = () => { - setLocalTrackCount(getLocalAudioTrackCount(room)); - setRemoteTrackCount(getRemoteAudioTrackCount(room)); - }; - - recalculateTrackCounts(); +): CleanupFn { + if (Platform.OS !== 'ios') { + return () => {}; + } - room.on(RoomEvent.Connected, recalculateTrackCounts); + let audioEngineState: AudioEngineConfigurationState = { + isPlayoutEnabled: false, + isRecordingEnabled: false, + preferSpeakerOutput, + }; - return () => { - room.off(RoomEvent.Connected, recalculateTrackCounts); - }; - }, [room]); - useEffect(() => { - if (Platform.OS !== 'ios') { - return () => {}; + const tryConfigure = async ( + newState: AudioEngineConfigurationState, + oldState: AudioEngineConfigurationState + ) => { + if ( + !newState.isPlayoutEnabled && + !newState.isRecordingEnabled && + (oldState.isPlayoutEnabled || oldState.isRecordingEnabled) + ) { + log.info('AudioSession deactivating...'); + await AudioSession.stopAudioSession(); + } else if (newState.isRecordingEnabled || newState.isPlayoutEnabled) { + const config = onConfigureNativeAudio + ? onConfigureNativeAudio(newState) + : getDefaultAppleAudioConfigurationForAudioState(newState); + log.info('AudioSession configuring category:', config.audioCategory); + await AudioSession.setAppleAudioConfiguration(config); + if (!oldState.isPlayoutEnabled && !oldState.isRecordingEnabled) { + log.info('AudioSession activating...'); + await AudioSession.startAudioSession(); + } } + }; - let onLocalPublished = (publication: LocalTrackPublication) => { - if (publication.kind === 'audio') { - setLocalTrackCount(localTrackCount + 1); - } - }; - let onLocalUnpublished = (publication: LocalTrackPublication) => { - if (publication.kind === 'audio') { - if (localTrackCount - 1 < 0) { - log.warn( - 'mismatched local audio track count! attempted to reduce track count below zero.' - ); - } - setLocalTrackCount(Math.max(localTrackCount - 1, 0)); - } + const handleEngineStateUpdate = async ({ + isPlayoutEnabled, + isRecordingEnabled, + }: { + isPlayoutEnabled: boolean; + isRecordingEnabled: boolean; + }) => { + const oldState = audioEngineState; + const newState: AudioEngineConfigurationState = { + isPlayoutEnabled, + isRecordingEnabled, + preferSpeakerOutput: audioEngineState.preferSpeakerOutput, }; - let onRemotePublished = (publication: RemoteTrackPublication) => { - if (publication.kind === 'audio') { - setRemoteTrackCount(remoteTrackCount + 1); - } - }; - let onRemoteUnpublished = (publication: RemoteTrackPublication) => { - if (publication.kind === 'audio') { - if (remoteTrackCount - 1 < 0) { - log.warn( - 'mismatched remote audio track count! attempted to reduce track count below zero.' - ); - } - setRemoteTrackCount(Math.max(remoteTrackCount - 1, 0)); - } - }; - - room - .on(RoomEvent.LocalTrackPublished, onLocalPublished) - .on(RoomEvent.LocalTrackUnpublished, onLocalUnpublished) - .on(RoomEvent.TrackPublished, onRemotePublished) - .on(RoomEvent.TrackUnpublished, onRemoteUnpublished); - return () => { - room - .off(RoomEvent.LocalTrackPublished, onLocalPublished) - .off(RoomEvent.LocalTrackUnpublished, onLocalUnpublished) - .off(RoomEvent.TrackPublished, onRemotePublished) - .off(RoomEvent.TrackUnpublished, onRemoteUnpublished); - }; - }, [room, localTrackCount, remoteTrackCount]); + // If tryConfigure throws, the error propagates to the native audio engine + // observer which converts it to a non-zero error code, causing the engine + // to stop/rollback (matching the Swift SDK's error propagation pattern). + try { + await tryConfigure(newState, oldState); + } catch (error) { + log.error( + 'AudioSession configuration failed, stopping audio engine:', + error + ); + // Throw the error code so the native AudioDeviceModuleObserver returns it + // to the WebRTC engine, which will stop/rollback the operation. - useEffect(() => { - if (Platform.OS !== 'ios') { - return; + throw kAudioEngineErrorFailedToConfigureAudioSession; } + // Update the audio state only if configure succeeds + audioEngineState = newState; + }; - let configFunc = - onConfigureNativeAudio ?? getDefaultAppleAudioConfigurationForMode; - let audioConfig = configFunc(trackState, preferSpeakerOutput); - AudioSession.setAppleAudioConfiguration(audioConfig); - }, [trackState, onConfigureNativeAudio, preferSpeakerOutput]); -} + audioDeviceModuleEvents.setWillEnableEngineHandler(handleEngineStateUpdate); + audioDeviceModuleEvents.setDidDisableEngineHandler(handleEngineStateUpdate); -function computeAudioTrackState( - localTracks: number, - remoteTracks: number -): AudioTrackState { - if (localTracks > 0 && remoteTracks > 0) { - return 'localAndRemote'; - } else if (localTracks > 0 && remoteTracks === 0) { - return 'localOnly'; - } else if (localTracks === 0 && remoteTracks > 0) { - return 'remoteOnly'; - } else { - return 'none'; - } + return () => { + audioDeviceModuleEvents.setWillEnableEngineHandler(null); + audioDeviceModuleEvents.setDidDisableEngineHandler(null); + }; } -function getLocalAudioTrackCount(room: Room): number { - return room.localParticipant.audioTrackPublications.size; -} +function getDefaultAppleAudioConfigurationForAudioState( + configurationState: AudioEngineConfigurationState +): AppleAudioConfiguration { + if (configurationState.isRecordingEnabled) { + return { + audioCategory: 'playAndRecord', + audioCategoryOptions: ['allowBluetooth', 'mixWithOthers'], + audioMode: configurationState.preferSpeakerOutput + ? 'videoChat' + : 'voiceChat', + }; + } else if (configurationState.isPlayoutEnabled) { + return { + audioCategory: 'playback', + audioCategoryOptions: ['mixWithOthers'], + audioMode: 'spokenAudio', + }; + } -function getRemoteAudioTrackCount(room: Room): number { - var audioTracks = 0; - room.remoteParticipants.forEach((participant) => { - audioTracks += participant.audioTrackPublications.size; - }); - return audioTracks; + return { + audioCategory: 'soloAmbient', + audioCategoryOptions: [], + audioMode: 'default', + }; } diff --git a/src/audio/AudioManagerLegacy.ts b/src/audio/AudioManagerLegacy.ts new file mode 100644 index 00000000..701d66e2 --- /dev/null +++ b/src/audio/AudioManagerLegacy.ts @@ -0,0 +1,89 @@ +/** + * Backward-compatible wrappers for the legacy AudioManager API. + * + * These exports preserve the old `useIOSAudioManagement(room, ...)` signature + * and the removed `getDefaultAppleAudioConfigurationForMode` function so that + * existing consumers continue to compile without changes. + * + * New code should use `setupIOSAudioManagement` from `./AudioManager` instead. + */ +import { useEffect } from 'react'; +import type { Room } from 'livekit-client'; +import type { AppleAudioConfiguration, AudioTrackState } from './AudioSession'; +import { + setupIOSAudioManagement, + type AudioEngineConfigurationState, +} from './AudioManager'; + +/** + * @deprecated Use {@link setupIOSAudioManagement} instead. + * The `room` parameter is ignored — audio session is now managed + * via audio engine events, not room track counts. + */ +export function useIOSAudioManagement( + _room: Room, + preferSpeakerOutput: boolean = true, + onConfigureNativeAudio?: ( + trackState: AudioTrackState, + preferSpeakerOutput: boolean + ) => AppleAudioConfiguration +) { + useEffect(() => { + let wrappedOnConfig: + | ((state: AudioEngineConfigurationState) => AppleAudioConfiguration) + | undefined; + + if (onConfigureNativeAudio) { + const legacyCb = onConfigureNativeAudio; + wrappedOnConfig = (state: AudioEngineConfigurationState) => + legacyCb(engineStateToTrackState(state), state.preferSpeakerOutput); + } + + const cleanup = setupIOSAudioManagement( + preferSpeakerOutput, + wrappedOnConfig + ); + return cleanup; + }, [preferSpeakerOutput, onConfigureNativeAudio]); +} + +/** + * @deprecated Use the default behavior of `setupIOSAudioManagement` instead. + */ +export function getDefaultAppleAudioConfigurationForMode( + mode: AudioTrackState, + preferSpeakerOutput: boolean = true +): AppleAudioConfiguration { + if (mode === 'remoteOnly') { + return { + audioCategory: 'playback', + audioCategoryOptions: ['mixWithOthers'], + audioMode: 'spokenAudio', + }; + } else if (mode === 'localAndRemote' || mode === 'localOnly') { + return { + audioCategory: 'playAndRecord', + audioCategoryOptions: ['allowBluetooth', 'mixWithOthers'], + audioMode: preferSpeakerOutput ? 'videoChat' : 'voiceChat', + }; + } + + return { + audioCategory: 'soloAmbient', + audioCategoryOptions: [], + audioMode: 'default', + }; +} + +function engineStateToTrackState( + state: AudioEngineConfigurationState +): AudioTrackState { + if (state.isRecordingEnabled && state.isPlayoutEnabled) { + return 'localAndRemote'; + } else if (state.isRecordingEnabled) { + return 'localOnly'; + } else if (state.isPlayoutEnabled) { + return 'remoteOnly'; + } + return 'none'; +} diff --git a/src/audio/AudioSession.ts b/src/audio/AudioSession.ts index ed3b9a9c..ce910b6c 100644 --- a/src/audio/AudioSession.ts +++ b/src/audio/AudioSession.ts @@ -197,37 +197,15 @@ export type AppleAudioConfiguration = { audioMode?: AppleAudioMode; }; +/** + * @deprecated Use `AudioEngineConfigurationState` from `AudioManager` instead. + */ export type AudioTrackState = | 'none' | 'remoteOnly' | 'localOnly' | 'localAndRemote'; -export function getDefaultAppleAudioConfigurationForMode( - mode: AudioTrackState, - preferSpeakerOutput: boolean = true -): AppleAudioConfiguration { - if (mode === 'remoteOnly') { - return { - audioCategory: 'playback', - audioCategoryOptions: ['mixWithOthers'], - audioMode: 'spokenAudio', - }; - } else if (mode === 'localAndRemote' || mode === 'localOnly') { - return { - audioCategory: 'playAndRecord', - audioCategoryOptions: ['allowBluetooth', 'mixWithOthers'], - audioMode: preferSpeakerOutput ? 'videoChat' : 'voiceChat', - }; - } - - return { - audioCategory: 'soloAmbient', - audioCategoryOptions: [], - audioMode: 'default', - }; -} - export default class AudioSession { /** * Applies the provided audio configuration to the underlying AudioSession. diff --git a/src/components/VideoTrack.tsx b/src/components/VideoTrack.tsx index cd26f1c9..df360b78 100644 --- a/src/components/VideoTrack.tsx +++ b/src/components/VideoTrack.tsx @@ -22,7 +22,9 @@ import { useEffect, useMemo, useState, + type ForwardRefExoticComponent, type ReactNode, + type RefAttributes, } from 'react'; import { RemoteVideoTrack } from 'livekit-client'; import ViewPortDetector from './ViewPortDetector'; @@ -132,7 +134,9 @@ type RTCViewInstance = InstanceType; * @returns A React component that renders the given video track. * @public */ -export const VideoTrack = forwardRef( +export const VideoTrack: ForwardRefExoticComponent< + VideoTrackProps & RefAttributes +> = forwardRef( ( { style = {}, @@ -224,7 +228,6 @@ export const VideoTrack = forwardRef( objectFit={objectFit} zOrder={zOrder} mirror={mirror} - // TODO: fix this up in react-native-webrtc side. // @ts-expect-error iosPIP={iosPIP} ref={ref} diff --git a/src/index.tsx b/src/index.tsx index fc9e660c..fe809622 100644 --- a/src/index.tsx +++ b/src/index.tsx @@ -1,7 +1,13 @@ 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 { + registerGlobals as webrtcRegisterGlobals, + AudioDeviceModule, + AudioEngineMuteMode, + AudioEngineAvailability, + audioDeviceModuleEvents, +} from '@livekit/react-native-webrtc'; import { setupURLPolyfill } from 'react-native-url-polyfill'; import './polyfills/EncoderDecoderTogether.min.js'; import AudioSession, { @@ -12,7 +18,6 @@ import AudioSession, { type AppleAudioConfiguration, type AppleAudioMode, type AudioTrackState, - getDefaultAppleAudioConfigurationForMode, } from './audio/AudioSession'; import type { AudioConfiguration } from './audio/AudioSession'; import { PixelRatio, Platform } from 'react-native'; @@ -161,14 +166,18 @@ export * from './useParticipant'; // deprecated export * from './useRoom'; // deprecated export * from './logger'; export * from './audio/AudioManager'; +export * from './audio/AudioManagerLegacy'; export * from './audio/MediaRecorder'; export { AudioSession, + AudioDeviceModule, + AudioEngineMuteMode, + AudioEngineAvailability, + audioDeviceModuleEvents, RNE2EEManager, RNKeyProvider, AndroidAudioTypePresets, - getDefaultAppleAudioConfigurationForMode, }; export type { AudioConfiguration, diff --git a/yarn.lock b/yarn.lock index 875b798f..376a1b59 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3578,15 +3578,15 @@ __metadata: languageName: node linkType: hard -"@livekit/react-native-webrtc@npm:^144.0.0": - version: 144.0.0 - resolution: "@livekit/react-native-webrtc@npm:144.0.0" +"@livekit/react-native-webrtc@npm:^144.1.0-beta.0": + version: 144.1.0-beta.0 + resolution: "@livekit/react-native-webrtc@npm:144.1.0-beta.0" dependencies: base64-js: "npm:1.5.1" debug: "npm:4.3.4" peerDependencies: react-native: ">=0.60.0" - checksum: 10/d97454e8bcb5ab0ae98e8a9d134f8486276b12bdf993052b5b01ac3e8da375e63bb66c84061201bd4499266afbe383a9a065c85c19b0734d659bc21fcf156508 + checksum: 10/d03b01c97bd6bad3e27908abbc2889e0c7e47af953e1f1d7824d8bc8babf4a2b91f59d719c9f5603329aa9fc1f8fcdac9f2f431b5e32ab88095168317f797b41 languageName: node linkType: hard @@ -3602,7 +3602,7 @@ __metadata: "@livekit/changesets-changelog-github": "npm:^0.0.4" "@livekit/components-react": "npm:^2.9.17" "@livekit/mutex": "npm:^1.1.1" - "@livekit/react-native-webrtc": "npm:^144.0.0" + "@livekit/react-native-webrtc": "npm:^144.1.0-beta.0" "@react-native/babel-preset": "npm:0.83.0" "@react-native/eslint-config": "npm:0.83.0" "@release-it/conventional-changelog": "npm:10.0.1" @@ -3632,7 +3632,7 @@ __metadata: web-streams-polyfill: "npm:^4.1.0" well-known-symbols: "npm:^4.1.0" peerDependencies: - "@livekit/react-native-webrtc": ^144.0.0 + "@livekit/react-native-webrtc": ^144.1.0-beta.0 livekit-client: ^2.15.8 react: "*" react-native: "*" @@ -10344,7 +10344,7 @@ __metadata: "@babel/core": "npm:^7.25.2" "@babel/preset-env": "npm:^7.25.3" "@babel/runtime": "npm:^7.25.0" - "@livekit/react-native-webrtc": "npm:^144.0.0" + "@livekit/react-native-webrtc": "npm:^144.1.0-beta.0" "@react-native-async-storage/async-storage": "npm:^1.17.10" "@react-native-community/cli": "npm:20.0.0" "@react-native-community/cli-platform-android": "npm:20.0.0"