diff --git a/.changeset/fix-media-recorder-restart.md b/.changeset/fix-media-recorder-restart.md deleted file mode 100644 index a51c7d73..00000000 --- a/.changeset/fix-media-recorder-restart.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@livekit/react-native': patch ---- - -Fix `MediaRecorder` duplicating audio data after it is stopped and started again diff --git a/CHANGELOG.md b/CHANGELOG.md index ab54c948..f4185c85 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,11 @@ # @livekit/react-native +## 3.1.1 + +### Patch Changes + +- Fix `MediaRecorder` duplicating audio data after it is stopped and started again - [#478](https://github.com/livekit/client-sdk-react-native/pull/478) ([@RaphaelFakhri](https://github.com/RaphaelFakhri)) + ## 3.1.0 ### Minor Changes diff --git a/docs/assets/highlight.css b/docs/assets/highlight.css index dc27c6d4..aec8e247 100644 --- a/docs/assets/highlight.css +++ b/docs/assets/highlight.css @@ -1,20 +1,20 @@ :root { - --light-hl-0: #795E26; - --dark-hl-0: #DCDCAA; - --light-hl-1: #000000; - --dark-hl-1: #D4D4D4; - --light-hl-2: #A31515; - --dark-hl-2: #CE9178; - --light-hl-3: #0000FF; - --dark-hl-3: #569CD6; - --light-hl-4: #267F99; - --dark-hl-4: #4EC9B0; - --light-hl-5: #008000; - --dark-hl-5: #6A9955; - --light-hl-6: #001080; - --dark-hl-6: #9CDCFE; - --light-hl-7: #AF00DB; - --dark-hl-7: #C586C0; + --light-hl-0: #008000; + --dark-hl-0: #6A9955; + --light-hl-1: #AF00DB; + --dark-hl-1: #C586C0; + --light-hl-2: #000000; + --dark-hl-2: #D4D4D4; + --light-hl-3: #795E26; + --dark-hl-3: #DCDCAA; + --light-hl-4: #001080; + --dark-hl-4: #9CDCFE; + --light-hl-5: #A31515; + --dark-hl-5: #CE9178; + --light-hl-6: #0000FF; + --dark-hl-6: #569CD6; + --light-hl-7: #267F99; + --dark-hl-7: #4EC9B0; --light-hl-8: #0070C1; --dark-hl-8: #4FC1FF; --light-hl-9: #800000; diff --git a/docs/classes/AudioSession.html b/docs/classes/AudioSession.html index 47f8655e..85a42cc4 100644 --- a/docs/classes/AudioSession.html +++ b/docs/classes/AudioSession.html @@ -1,4 +1,4 @@ -
StaticconfigureStaticgetGets the available audio outputs for use with selectAudioOutput.
+StaticgetGets the available audio outputs for use with selectAudioOutput.
startAudioSession must be called prior to using this method.
For Android, will return if available:
react-native-avroutepicker for a native platform
control.
the available audio output types
-StaticselectSelect the provided audio output if available.
+StaticselectSelect the provided audio output if available.
startAudioSession must be called prior to using this method.
A deviceId retrieved from getAudioOutputs
-StaticsetDirectly change the AVAudioSession category/mode.
+StaticsetDirectly change the AVAudioSession category/mode.
The configuration to use. Null values will be omitted and the existing values will be unchanged.
-StaticsetSet default audio track volume when new tracks are subscribed. +
StaticsetSet default audio track volume when new tracks are subscribed. Does not affect any existing tracks.
A number between 0.0 and 1.0, where 0.0 represents 0% volume and 1.0 represents full volume.
-StaticshowiOS only, requires iOS 11+.
+StaticshowiOS only, requires iOS 11+.
Displays an AVRoutePickerView for the user to choose their audio output.
-StaticstartStarts an AudioSession.
-StaticstopStops the existing AudioSession.
-StaticstartStarts an AudioSession.
+StaticstopStops the existing AudioSession.
+ExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalExperimentalOptionalparticipantIdentity: stringOptionalkeyIndex: numberExperimentalOptionalkeyIndex: numberExperimentalAccepts a passphrase that's used to create the crypto keys for a participant's stream.
-OptionalkeyIndex: numberExperimentalAccepts a passphrase that's used to create the crypto keys.
-OptionalkeyIndex: numberExperimentalExperimentalExperimentalExperimentalOptionalparticipantIdentity: stringOptionalkeyIndex: numberExperimentalOptionalkeyIndex: numberExperimentalAccepts a passphrase that's used to create the crypto keys for a participant's stream.
+OptionalkeyIndex: numberExperimentalAccepts a passphrase that's used to create the crypto keys.
+OptionalkeyIndex: numberExperimentalVisualizes audio signals from a TrackReference as bars. +
Visualizes audio signals from a TrackReference as bars.
If the state prop is set, it automatically transitions between VoiceAssistant states.
The LiveKitRoom component provides the room context to all its child components.
+
The LiveKitRoom component provides the room context to all its child components.
It is generally the starting point of your LiveKit app and the root of the LiveKit component tree.
It provides the room state as a React context to all child components, so you don't have to pass it yourself.
<LiveKitRoom
token='<livekit-token>'
serverUrl='<url-to-livekit-server>'
connect={true}
>
...
</LiveKitRoom>
+Use the default behavior of setupIOSAudioManagement instead.
Use the default behavior of setupIOSAudioManagement instead.
Kept in sync with getDefaultAppleAudioConfigurationForAudioState in
./AudioManager.ts. If you change the defaults in one place, update the
other so the legacy path and the new path produce the same configuration.
AudioTrackState carries no voice-processing state, so this matches the
voice-processing-enabled results of that function only.
Registers the required globals needed for LiveKit to work.
+Registers the required globals needed for LiveKit to work.
Must be called before using LiveKit.
Optionaloptions: RegisterGlobalsOptionsOptional configuration for global registration
-Set the log level for both the @livekit/react-native package and the @livekit-client package.
+
Set the log level for both the @livekit/react-native package and the @livekit-client package.
To set the @livekit-client log independently, use the liveKitClientLogLevel prop on the options object.
Sets up automatic iOS audio session management based on audio engine state.
+Sets up automatic iOS audio session management based on audio engine state.
Call this once at app startup (e.g. in index.js). registerGlobals()
invokes it for you by default unless autoConfigureAudioSession: false
is passed.
OptionalpreferSpeakerOutput: booleanWhether to prefer speaker output. Defaults to true.
A cleanup function that removes the installed handlers or native configuration. A cleanup function from a superseded setup is a no-op.
-Sets up automatic iOS audio session management with a static native policy.
+Sets up automatic iOS audio session management with a static native policy.
Unused when a full policy is provided; kept for call-site consistency with the default overload.
Static recording/playout configuration applied natively.
setupIOSAudioManagement for the default native path and usage notes.
-The onConfigureNativeAudio callback is unsafe. It runs inside
the audio engine's lifecycle callbacks while native code waits for the
result (bounded at a few seconds). The callback must return quickly and
must not call APIs that enter the WebRTC engine or a peer connection
(for example addTransceiver, getUserMedia, or device enumeration):
those can block on the same engine operation the callback is holding up.
Prefer the default native path, or pass an IOSAudioSessionPolicy.
Default sort for participants, it'll order participants by:
+Default sort for participants, it'll order participants by:
OptionallocalParticipant: LocalParticipantOptionallocalParticipant: LocalParticipantOptionalonConfigureNativeAudio: (Use setupIOSAudioManagement instead. +
OptionalonConfigureNativeAudio: (Use setupIOSAudioManagement instead.
The room parameter is ignored — audio session is now managed
via audio engine events, not room track counts.
The onConfigureNativeAudio callback is also deprecated and unsafe: it
@@ -10,4 +10,4 @@
publication counts. Edge cases can differ. For example, a
published-but-muted local audio track that previously yielded
localOnly may now appear as remoteOnly or none.
A hook for tracking the volume of an audio track across multiple frequency bands.
+A hook for tracking the volume of an audio track across multiple frequency bands.
OptionaltrackOrTrackReference: LocalAudioTrack | RemoteAudioTrack | TrackReferenceOrPlaceholderOptionaloptions: MultiBandTrackVolumeOptionsA number array containing the volume for each frequency band.
-Optionaloptions: RoomOptionsOptionaloptions: RoomOptionsA hook for tracking the volume of an audio track.
+A hook for tracking the volume of an audio track.
OptionaltrackOrTrackReference: LocalAudioTrack | RemoteAudioTrack | TrackReferenceOrPlaceholderA number between 0-1 representing the volume.
-+If you're building Voice AI, LiveKit Agents is the SDK for code-first realtime voice agents. STT, LLM, TTS, turn detection, expressive speech, keyterm accuracy, tool usage, and telephony all come bundled in the framework. It's available in both Python and Node.js.
+# agent.py
from livekit import agents
from livekit.agents import Agent, AgentServer, AgentSession, STTContextOptions, TurnHandlingOptions, inference
server = AgentServer()
@server.rtc_session(agent_name="my-agent")
async def my_agent(ctx: agents.JobContext):
session = AgentSession(
stt=inference.STT(model="deepgram/nova-3", language="multi"),
llm=inference.LLM(model="google/gemma-4-31b-it"),
tts=inference.TTS(model="inworld/inworld-tts-2", voice="Ashley"),
turn_handling=TurnHandlingOptions(turn_detection=inference.TurnDetector()),
stt_context_options=STTContextOptions(keyterms=["LiveKit", "Acme Corp"]),
expressive=True,
)
await session.start(room=ctx.room, agent=Agent(instructions="You are a helpful voice AI assistant."))
await session.generate_reply(instructions="Greet the user and offer your assistance.")
if __name__ == "__main__":
agents.cli.run_app(server)
+
+
+Models come from LiveKit Inference with no per-provider API keys, and LiveKit Cloud handles deployment and observability. Visit the docs for more info at docs.livekit.io/agents.
+Using a coding agent? Install the LiveKit skill with npx skills add livekit/agent-skills and add the docs MCP at https://docs.livekit.io/mcp/ (see coding agent support).
npm install @livekit/react-native @livekit/react-native-webrtc livekit-client
+npm install @livekit/react-native @livekit/react-native-webrtc livekit-client
Yarn
-yarn add @livekit/react-native @livekit/react-native-webrtc livekit-client
+yarn add @livekit/react-native @livekit/react-native-webrtc livekit-client
This library depends on @livekit/react-native-webrtc, which has additional installation instructions found here:
@@ -30,7 +40,7 @@ YarniOS Podfile
This package depends on the LiveKitWebRTC pod, which is published to the
livekit/podspecs spec repo and the CocoaPods trunk. The CocoaPods trunk stops accepting new pods on December 2, 2026, so later LiveKitWebRTC versions will only be available from livekit/podspecs. Add both sources to the top of your ios/Podfile:
-source 'https://github.com/livekit/podspecs.git'
source 'https://cdn.cocoapods.org/'
+source 'https://github.com/livekit/podspecs.git'
source 'https://cdn.cocoapods.org/'
Keep the cdn.cocoapods.org line: once a Podfile lists any source, CocoaPods stops using
@@ -43,14 +53,14 @@
AndroidMainApplication.java file:
-import com.livekit.reactnative.LiveKitReactNative;
import com.livekit.reactnative.audio.AudioType;
public class MainApplication extends Application implements ReactApplication {
@Override
public void onCreate() {
// Place this above any other RN related initialization
// When AudioType is omitted, it'll default to CommunicationAudioType.
// Use MediaAudioType if user is only consuming audio, and not publishing.
LiveKitReactNative.setup(this, new AudioType.CommunicationAudioType());
//...
}
}
+import com.livekit.reactnative.LiveKitReactNative;
import com.livekit.reactnative.audio.AudioType;
public class MainApplication extends Application implements ReactApplication {
@Override
public void onCreate() {
// Place this above any other RN related initialization
// When AudioType is omitted, it'll default to CommunicationAudioType.
// Use MediaAudioType if user is only consuming audio, and not publishing.
LiveKitReactNative.setup(this, new AudioType.CommunicationAudioType());
//...
}
}
Kotlin
In your MainApplication.kt file:
-import com.livekit.reactnative.LiveKitReactNative
import com.livekit.reactnative.audio.AudioType
class MainApplication : Application, ReactApplication() {
override fun onCreate() {
// Place this above any other RN related initialization
// When AudioType is omitted, it'll default to CommunicationAudioType.
// Use MediaAudioType if user is only consuming audio, and not publishing.
LiveKitReactNative.setup(this, AudioType.CommunicationAudioType())
//...
}
}
+import com.livekit.reactnative.LiveKitReactNative
import com.livekit.reactnative.audio.AudioType
class MainApplication : Application, ReactApplication() {
override fun onCreate() {
// Place this above any other RN related initialization
// When AudioType is omitted, it'll default to CommunicationAudioType.
// Use MediaAudioType if user is only consuming audio, and not publishing.
LiveKitReactNative.setup(this, AudioType.CommunicationAudioType())
//...
}
}
@@ -58,14 +68,14 @@ iOS
Objective-C
In your AppDelegate.m file:
-#import "LivekitReactNative.h"
#import "WebRTCModuleOptions.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Place this above any other RN related initialization
[LivekitReactNative setup];
// Uncomment the following lines if you want to use the camera in the background
// Requires voip background mode and iOS 18+.
// WebRTCModuleOptions *options = [WebRTCModuleOptions sharedInstance];
// options.enableMultitaskingCameraAccess = YES;
//...
}
+#import "LivekitReactNative.h"
#import "WebRTCModuleOptions.h"
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Place this above any other RN related initialization
[LivekitReactNative setup];
// Uncomment the following lines if you want to use the camera in the background
// Requires voip background mode and iOS 18+.
// WebRTCModuleOptions *options = [WebRTCModuleOptions sharedInstance];
// options.enableMultitaskingCameraAccess = YES;
//...
}
Swift
In your AppDelegate.swift file:
-import livekit_react_native
import livekit_react_native_webrtc
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
// Place this above any other RN related initialization
LivekitReactNative.setup()
// Uncomment the following lines if you want to use the camera in the background
// Requires voip background mode and iOS 18+.
// let options = WebRTCModuleOptions.sharedInstance()
// options.enableMultitaskingCameraAccess = true
// ...
}
}
+import livekit_react_native
import livekit_react_native_webrtc
@main
class AppDelegate: UIResponder, UIApplicationDelegate {
func application(
_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]? = nil
) -> Bool {
// Place this above any other RN related initialization
LivekitReactNative.setup()
// Uncomment the following lines if you want to use the camera in the background
// Requires voip background mode and iOS 18+.
// let options = WebRTCModuleOptions.sharedInstance()
// options.enableMultitaskingCameraAccess = true
// ...
}
}
@@ -76,12 +86,12 @@ Example appUsage
In your index.js file, setup the LiveKit SDK by calling registerGlobals().
This sets up the required WebRTC libraries for use in Javascript, and is needed for LiveKit to work.
-import { registerGlobals } from '@livekit/react-native';
// ...
registerGlobals();
+import { registerGlobals } from '@livekit/react-native';
// ...
registerGlobals();
In your app, wrap your component in a LiveKitRoom component, which manages a
Room object and allows you to use our hooks to create your own real-time video/audio app.
-import * as React from 'react';
import {
StyleSheet,
View,
FlatList,
ListRenderItem,
} from 'react-native';
import { useEffect } from 'react';
import {
AudioSession,
LiveKitRoom,
useTracks,
TrackReferenceOrPlaceholder,
VideoTrack,
isTrackReference,
registerGlobals,
} from '@livekit/react-native';
import { Track } from 'livekit-client';
const wsURL = "wss://example.com"
const token = "your-token-here"
export default function App() {
// Start the audio session first.
useEffect(() => {
let start = async () => {
await AudioSession.startAudioSession();
};
start();
return () => {
AudioSession.stopAudioSession();
};
}, []);
return (
<LiveKitRoom
serverUrl={wsURL}
token={token}
connect={true}
options={{
// Use screen pixel density to handle screens with differing densities.
adaptiveStream: { pixelDensity: 'screen' },
}}
audio={true}
video={true}
>
<RoomView />
</LiveKitRoom>
);
};
const RoomView = () => {
// Get all camera tracks.
// The useTracks hook grabs the tracks from LiveKitRoom component
// providing the context for the Room object.
const tracks = useTracks([Track.Source.Camera]);
const renderTrack: ListRenderItem<TrackReferenceOrPlaceholder> = ({item}) => {
// Render using the VideoTrack component.
if(isTrackReference(item)) {
return (<VideoTrack trackRef={item} style={styles.participantView} />)
} else {
return (<View style={styles.participantView} />)
}
};
return (
<View style={styles.container}>
<FlatList
data={tracks}
renderItem={renderTrack}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'stretch',
justifyContent: 'center',
},
participantView: {
height: 300,
},
});
+import * as React from 'react';
import {
StyleSheet,
View,
FlatList,
ListRenderItem,
} from 'react-native';
import { useEffect } from 'react';
import {
AudioSession,
LiveKitRoom,
useTracks,
TrackReferenceOrPlaceholder,
VideoTrack,
isTrackReference,
registerGlobals,
} from '@livekit/react-native';
import { Track } from 'livekit-client';
const wsURL = "wss://example.com"
const token = "your-token-here"
export default function App() {
// Start the audio session first.
useEffect(() => {
let start = async () => {
await AudioSession.startAudioSession();
};
start();
return () => {
AudioSession.stopAudioSession();
};
}, []);
return (
<LiveKitRoom
serverUrl={wsURL}
token={token}
connect={true}
options={{
// Use screen pixel density to handle screens with differing densities.
adaptiveStream: { pixelDensity: 'screen' },
}}
audio={true}
video={true}
>
<RoomView />
</LiveKitRoom>
);
};
const RoomView = () => {
// Get all camera tracks.
// The useTracks hook grabs the tracks from LiveKitRoom component
// providing the context for the Room object.
const tracks = useTracks([Track.Source.Camera]);
const renderTrack: ListRenderItem<TrackReferenceOrPlaceholder> = ({item}) => {
// Render using the VideoTrack component.
if(isTrackReference(item)) {
return (<VideoTrack trackRef={item} style={styles.participantView} />)
} else {
return (<View style={styles.participantView} />)
}
};
return (
<View style={styles.container}>
<FlatList
data={tracks}
renderItem={renderTrack}
/>
</View>
);
};
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'stretch',
justifyContent: 'center',
},
participantView: {
height: 300,
},
});
API documentation is located here.
@@ -99,28 +109,28 @@ Media playbackuseEffect(() => {
let connect = async () => {
// configure audio session prior to starting it.
await AudioSession.configureAudio({
android: {
// currently supports .media and .communication presets
audioTypeOptions: AndroidAudioTypePresets.media,
},
});
await AudioSession.startAudioSession();
await room.connect(url, token, {});
};
connect();
return () => {
room.disconnect();
AudioSession.stopAudioSession();
};
}, [url, token, room]);
+useEffect(() => {
let connect = async () => {
// configure audio session prior to starting it.
await AudioSession.configureAudio({
android: {
// currently supports .media and .communication presets
audioTypeOptions: AndroidAudioTypePresets.media,
},
});
await AudioSession.startAudioSession();
await room.connect(url, token, {});
};
connect();
return () => {
room.disconnect();
AudioSession.stopAudioSession();
};
}, [url, token, room]);
Customizing audio session
Instead of using our presets, you can further customize the audio session to suit your specific needs.
-await AudioSession.configureAudio({
android: {
preferredOutputList: ['earpiece'],
// See [AudioManager](https://developer.android.com/reference/android/media/AudioManager)
// for details on audio and focus modes.
audioTypeOptions: {
manageAudioFocus: true,
audioMode: 'normal',
audioFocusMode: 'gain',
audioStreamType: 'music',
audioAttributesUsageType: 'media',
audioAttributesContentType: 'unknown',
},
},
});
await AudioSession.startAudioSession();
+await AudioSession.configureAudio({
android: {
preferredOutputList: ['earpiece'],
// See [AudioManager](https://developer.android.com/reference/android/media/AudioManager)
// for details on audio and focus modes.
audioTypeOptions: {
manageAudioFocus: true,
audioMode: 'normal',
audioFocusMode: 'gain',
audioStreamType: 'music',
audioAttributesUsageType: 'media',
audioAttributesContentType: 'unknown',
},
},
});
await AudioSession.startAudioSession();
iOS
For iOS, registerGlobals() automatically configures and activates the audio
session based on WebRTC audio engine lifecycle events. This is enabled by
default and is usually enough for voice and video apps:
-registerGlobals();
+registerGlobals();
If your app manages AVAudioSession directly, disable the automatic setup:
-registerGlobals({ autoConfigureAudioSession: false });
+registerGlobals({ autoConfigureAudioSession: false });
For custom categories/modes, disable the default setup and pass a static
policy to setupIOSAudioManagement once during app startup:
-import { registerGlobals, setupIOSAudioManagement } from '@livekit/react-native';
registerGlobals({ autoConfigureAudioSession: false });
const cleanup = setupIOSAudioManagement(true, {
recording: {
audioCategory: 'playAndRecord',
audioCategoryOptions: ['allowBluetooth', 'mixWithOthers'],
audioMode: 'videoChat',
},
playout: {
audioCategory: 'playback',
audioCategoryOptions: ['mixWithOthers'],
audioMode: 'spokenAudio',
},
});
+import { registerGlobals, setupIOSAudioManagement } from '@livekit/react-native';
registerGlobals({ autoConfigureAudioSession: false });
const cleanup = setupIOSAudioManagement(true, {
recording: {
audioCategory: 'playAndRecord',
audioCategoryOptions: ['allowBluetooth', 'mixWithOthers'],
audioMode: 'videoChat',
},
playout: {
audioCategory: 'playback',
audioCategoryOptions: ['mixWithOthers'],
audioMode: 'spokenAudio',
},
});
The older useIOSAudioManagement(room, ...) hook is still exported for
@@ -132,7 +142,7 @@
AndroidAndroid screenshare requires a foreground service with type mediaProjection to be present.
From version 2.4.0 onwards, the foreground service is handled internally,
but you must declare the permission yourself in your app's AndroidManifest.xml file.
-<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
+<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PROJECTION" />
iOS
@@ -145,7 +155,7 @@ iOSconst screenCaptureRef = React.useRef(null);
const screenCapturePickerView = Platform.OS === 'ios' && (
<ScreenCapturePickerView ref={screenCaptureRef} />
);
const startBroadcast = async () => {
if (Platform.OS === 'ios') {
const reactTag = findNodeHandle(screenCaptureRef.current);
await NativeModules.ScreenCapturePickerViewManager.show(reactTag);
room.localParticipant.setScreenShareEnabled(true);
} else {
room.localParticipant.setScreenShareEnabled(true);
}
};
return (
<View style={styles.container}>
/*...*/ // Make sure the ScreenCapturePickerView exists in the view tree.
{screenCapturePickerView}
</View>
);
+const screenCaptureRef = React.useRef(null);
const screenCapturePickerView = Platform.OS === 'ios' && (
<ScreenCapturePickerView ref={screenCaptureRef} />
);
const startBroadcast = async () => {
if (Platform.OS === 'ios') {
const reactTag = findNodeHandle(screenCaptureRef.current);
await NativeModules.ScreenCapturePickerViewManager.show(reactTag);
room.localParticipant.setScreenShareEnabled(true);
} else {
room.localParticipant.setScreenShareEnabled(true);
}
};
return (
<View style={styles.container}>
/*...*/ // Make sure the ScreenCapturePickerView exists in the view tree.
{screenCapturePickerView}
</View>
);
Note
@@ -155,11 +165,11 @@ AndroidTo support staying connected to LiveKit in the background, you will need a foreground service on Android.
The example app uses @supersami/rn-foreground-service for this.
Add the following permissions to your AndroidManifest.xml file:
-<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
+<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_CAMERA" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MICROPHONE" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK" />
Declare the the service and ensure it's labelled a mediaProjection service like so:
-<service android:name="com.supersami.foregroundservice.ForegroundService" android:foregroundServiceType="camera|microphone|mediaPlayback" />
<service android:name="com.supersami.foregroundservice.ForegroundServiceTask" />
+<service android:name="com.supersami.foregroundservice.ForegroundService" android:foregroundServiceType="camera|microphone|mediaPlayback" />
<service android:name="com.supersami.foregroundservice.ForegroundServiceTask" />
The camera and microphone permissions/foreground service types can be omitted if you are not using those.
@@ -190,7 +200,7 @@ This usually happens after upgrading @livekit/react-native-webrtc. The error may also say the
matching specs "required a higher minimum deployment target", which is misleading.
Make sure both Podfile sources are in your ios/Podfile, then run:
-cd ios && pod update LiveKitWebRTC
+cd ios && pod update LiveKitWebRTC
You may also see a Found multiple specifications for LiveKitWebRTC warning. It is harmless:
@@ -213,4 +223,4 @@
LicenseDeveloper Community · Slack · X · YouTube
-
BetaBetaOptional BetabarNumber of bars that show up in the visualizer
-Optional BetaoptionsOptional BetastateIf set, the visualizer will transition between different voice assistant states
-Optional BetastyleCustom React Native styles for the container.
-Optional BetatrackOptional BetaoptionsOptional BetastateIf set, the visualizer will transition between different voice assistant states
+Optional BetastyleCustom React Native styles for the container.
+Optional BetatrackOptionalconnectIf set to true a connection to LiveKit room is initiated.
OptionalconnectDefine options how to connect to the LiveKit server.
+OptionalconnectDefine options how to connect to the LiveKit server.
Optional ExperimentalfeatureOptionalonOptionalonOptionalonOptionalonOptionalonOptionaloptionsOptions for when creating a new room. +
Optional ExperimentalfeatureOptionalonOptionalonOptionalonOptionalonOptionalonOptionaloptionsOptions for when creating a new room. When you pass your own room instance to this component, these options have no effect. Instead, set the options directly in the room instance.
OptionalroomOptional room instance. +
OptionalroomOptional room instance.
By passing your own room instance you overwrite the options parameter,
make sure to set the options directly on the room instance itself.
OptionalscreenPublish screen share immediately after connecting to your LiveKit room.
+OptionalscreenPublish screen share immediately after connecting to your LiveKit room.
URL to the LiveKit server. +
URL to the LiveKit server.
For example: wss://<domain>.livekit.cloud
To simplify the implementation, undefined is also accepted as an intermediate value, but only with a valid string url can the connection be established.
OptionalsimulateA user specific access token for a client to authenticate to the room. +
OptionalsimulateA user specific access token for a client to authenticate to the room.
This token is necessary to establish a connection to the room.
To simplify the implementation, undefined is also accepted as an intermediate value, but only with a valid string token can the connection be established.
OptionalvideoPublish video immediately after connecting to your LiveKit room.
+OptionalvideoPublish video immediately after connecting to your LiveKit room.
AlphaInterface for configuring options for the useMultibandTrackVolume hook.
-AlphaInterface for configuring options for the useMultibandTrackVolume hook.
+Optional Alphabandsthe number of bands to split the audio into
-Optional Alphamaxcut off frequency on the higher end
-Optional Alphamincut off frequency on the lower end
-Optional Alphaupdateupdate should run every x ms
-Optional Alphamaxcut off frequency on the higher end
+Optional Alphamincut off frequency on the lower end
+Optional Alphaupdateupdate should run every x ms
+OptionalcameraOptionalmetadataOptionalmicrophoneOptionalscreenOptionalcameraOptionalmetadataOptionalmicrophoneOptionalscreenOptionalaudioCorresponds to Android's AndroidAttributes content type.
Defaults to 'speech'.
See also https://developer.android.com/reference/android/media/AudioAttributes
-OptionalaudioCorresponds to Android's AudioAttributes usage type.
+OptionalaudioCorresponds to Android's AudioAttributes usage type.
Defaults to 'voiceCommunication'.
See also https://developer.android.com/reference/android/media/AudioAttributes
-OptionalaudioCorresponds to the duration hint when requesting audio focus.
+OptionalaudioCorresponds to the duration hint when requesting audio focus.
Defaults to 'gain'.
See also https://developer.android.com/reference/android/media/AudioManager#AUDIOFOCUS_GAIN
-OptionalaudioOptionalaudioCorresponds to https://developer.android.com/reference/android/media/AudioManager#setMode(int)
Defaults to 'inCommunication'.
-OptionalaudioCorresponds to the stream type when requesting audio focus. Used on pre-O devices.
+OptionalaudioCorresponds to the stream type when requesting audio focus. Used on pre-O devices.
Defaults to 'voiceCall'
See also https://developer.android.com/reference/android/media/AudioManager#STREAM_VOICE_CALL
-OptionalforceOn certain Android devices, audio routing does not function properly and +
OptionalforceOn certain Android devices, audio routing does not function properly and
bluetooth microphones will not work unless audio mode is set to
inCommunication or inCall. Audio routing is turned off those cases.
If this set to true, will attempt to do audio routing regardless of audio mode.
Defaults to false.
-OptionalmanageWhether LiveKit should handle managing the audio focus or not.
+OptionalmanageWhether LiveKit should handle managing the audio focus or not.
Defaults to true.
-Configuration for the underlying AudioSession.
+Configuration for the underlying AudioSession.
Android specific options:
By default, this is set to "speaker"
OptionalandroidOptionaliosOptionalandroidOptionaliosWhether Apple Voice Processing I/O is running for this engine state. The
voiceChat/videoChat modes engage iOS's call-tuned speaker gain, which
only VPIO compensates for, so a configuration derived for recording should
account for this.
Retained only for the legacy useIOSAudioManagement hook and
+
Retained only for the legacy useIOSAudioManagement hook and
getDefaultAppleAudioConfigurationForMode. New code should use
setupIOSAudioManagement (optionally with an IOSAudioSessionPolicy).
That API is driven by playout/recording engine state, which has no direct
AudioTrackState equivalent.
Static recording/playout policy for setupIOSAudioManagement.
-Static recording/playout policy for setupIOSAudioManagement.
+OptionaldeactivateWhether to deactivate the audio session when both playout and recording are disabled. Defaults to true.
-OptionalrecordingRecording configuration to apply while Apple Voice Processing I/O is off, +
OptionalrecordingRecording configuration to apply while Apple Voice Processing I/O is off,
for example after AudioDeviceModule.setVoiceProcessingEnabled(false).
A policy whose recording config uses voiceChat/videoChat should
set a default-mode variant here, otherwise remote audio plays back
noticeably quieter without VPIO to compensate for the call-tuned gain.
Defaults to recording, so a policy that does not set this behaves
exactly as before.
Unsafe. Prefer IOSAudioSessionPolicy or the default +
Unsafe. Prefer IOSAudioSessionPolicy or the default native path. See setupIOSAudioManagement.
-Options for construction an RNKeyProvider
-Options for construction an RNKeyProvider
+Props for the VideoTrack component.
-Props for the VideoTrack component.
+iosPIP.startAutomatically can be used to automatically
enter PIP when backgrounding the app.
iosPIP.preferredSize is used to provide a suggested aspect ratio.
import { startIOSPIP, stopIOSPIP } from '@livekit/react-native-webrtc';
// Obtain a ref to the view
const videoRef = useRef<Component>(null);
const videoView = (
<VideoTrack
ref={videoRef}
iosPIP={{
enabled: true,
startAutomatically: true,
preferredSize: {
width: 9,
height: 16,
},
}}
...
/>
);
// Start/stop manually
startIOSPIP(videoRef);
stopIOSPIP(videoRef);
+import { startIOSPIP, stopIOSPIP } from '@livekit/react-native-webrtc';
// Obtain a ref to the view
const videoRef = useRef<Component>(null);
const videoView = (
<VideoTrack
ref={videoRef}
iosPIP={{
enabled: true,
startAutomatically: true,
preferredSize: {
width: 9,
height: 16,
},
}}
...
/>
);
// Start/stop manually
startIOSPIP(videoRef);
stopIOSPIP(videoRef);
-OptionalmirrorIndicates whether the video should be mirrored during rendering. +
OptionalmirrorIndicates whether the video should be mirrored during rendering. This is commonly used for front-facing cameras.
-OptionalobjectSpecifies how the video content should be resized to fit its container. +
OptionalobjectSpecifies how the video content should be resized to fit its container. 'cover' (default): The video will fill the entire container, potentially cropping the video. 'contain': The entire video will be visible within the container, potentially leaving empty space.
-OptionalstyleCustom React Native styles for the video container.
-The track reference to display. This should be a TrackReference object +
OptionalstyleCustom React Native styles for the video container.
+The track reference to display. This should be a TrackReference object or undefined if no track is available.
-OptionalzSpecifies the depth-stacking order of this video view in the stacking space of all video views. +
OptionalzSpecifies the depth-stacking order of this video view in the stacking space of all video views. A larger zOrder value generally causes the view to cover those with lower values.
The support for zOrder is platform-dependent and/or implementation-specific. Thus, specifying a value for zOrder is to be @@ -38,4 +38,4 @@ application usually needs a maximum of two zOrder values: 0 for the remote video(s) which appear in the background, and 1 for the local video(s) which appear above the remote video(s).
-ConstA pre-configured AndroidAudioConfiguration for voice communication.
+ConstA pre-configured AndroidAudioConfiguration for voice communication.
A pre-configured AndroidAudioConfiguration for media playback.
-ConstVideoTrack component for displaying video tracks in a React Native application. +
ConstVideoTrack component for displaying video tracks in a React Native application. It supports both local and remote video tracks from LiveKit, and handles adaptive streaming for remote tracks.
ConstConst
Applies the provided audio configuration to the underlying AudioSession.
Must be called prior to connecting to a Room for the configuration to apply correctly.
See also
-setupIOSAudioManagementfor automatic configuration of iOS audio options.