Livqeno Docs

React Native SDK

The same API as Livqeno Web — the Room class is the same class.

import { Raven, RavenVideoView } from '@ravenkash/react-native';
 
const raven = new Raven({ token, endpoint });
const room = await raven.join('room_123');
 
await room.enableCamera();
await room.enableMicrophone();

If that looks like the web SDK, that's the point — and it isn't a resemblance. The Room you get back is the same class @ravenkash/rtc returns in a browser. Everything you know about rooms, participants, tracks, and events on web is true here, and a fix to that logic lands on both platforms at once.

Install

npm install @ravenkash/react-native @ravenkash/rtc @ravenkash/effects @ravenkash/chat \
            react-native-webrtc react-native-incall-manager
 
cd ios && pod install   # iOS only

react-native-webrtc is a required native module, not a separate SDK to integrate with — React Native's autolinking needs it installed directly in your app so the native WebRTC implementation builds for iOS and Android. You never import or call it; everything you write is @ravenkash/react-native's API.

react-native-incall-manager is optional and only used for call-audio routing (earpiece/speaker, proximity, the in-call audio session). Without it, audio.* throws NOT_SUPPORTED and everything else works; audio.setAdapter() lets you supply your own native module instead.

Permissions — the SDK can't add these for you.

ios/YourApp/Info.plist:

<key>NSCameraUsageDescription</key>
<string>Camera access is used for video calls.</string>
<key>NSMicrophoneUsageDescription</key>
<string>Microphone access is used for calls.</string>

android/app/src/main/AndroidManifest.xml:

<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.RECORD_AUDIO" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />

Missing an iOS usage string doesn't produce an error — it crashes the app the instant it asks, surfacing as an App Store review failure rather than a bug report.

Initializing

RTC and chat are independent, and so are their credentials:

new Raven({ token, endpoint });                       // a call, with or without chat
new Raven({ token, endpoint, chatToken, chatApiUrl }); // both
new Raven({ chatToken, chatApiUrl });                  // messaging only — no RTC connection is ever created

raven.hasRtc tells you which you got — what a shared component needs to decide whether to render call controls. Calling join() on a messaging-only instance throws immediately with an error that says so, checked before any permission prompt or audio session starts.

Joining

const room = await raven.join('room_123');
await raven.leave();      // leaves the room, keeps chat connected
await raven.dispose();    // tears down everything, including chat

join() requests camera and microphone permission by default — on mobile, discovering you can't publish mid-call is worse than being asked up front. A refusal doesn't block joining; a user who declined the camera can still watch and listen.

Rendering video

<RavenVideoView participant={remote} room={room} style={{ flex: 1 }} />
<RavenVideoView participant={room.localParticipant} room={room} style={pip} zOrder={1} />

Pass room and the view follows track changes — published, unpublished, muted, resubscribed — by itself.

Chat

Present as raven.chat when you passed a chatToken:

const raven = new Raven({ chatToken: session.token, chatApiUrl: session.apiUrl });
await raven.chat!.connect('room_123');
await raven.chat!.send('Hello everyone!');

Everything else is @ravenkash/chat's API unchanged — messages.list(), startTyping(), markAsRead(), presence, threads. It's the same client, so Chat applies verbatim.

Reconnection

Handled for you — bounded exponential backoff, re-joins rooms, gives up rather than looping forever. Install @react-native-community/netinfo (optional) for connectivity-aware reconnects (a Wi-Fi → cellular handover triggers a fast reconnect instead of waiting out an ICE timeout).

Lifecycle

The SDK watches AppState and reports transitions, but deliberately does not disconnect on background — dropping the socket on a brief app-switch would turn "checked a notification" into "left the meeting." Video capture does stop when backgrounded (the OS suspends the camera) and resumes on return. Whether a backgrounded user should stay in the room is your call:

new Raven({
  onAppStateChange: (state) => {
    if (state === 'background') void raven.leave();
  },
});

Live Streaming

RavenLiveStream is a thin wrapper around Raven — not a parallel implementation. A stream's host and viewers are ordinary participants of one room, and its chat is ordinary @ravenkash/chat, so every mobile concern Livqeno.join() already handles (permissions, audio session, app lifecycle, network recovery) applies unchanged:

import { joinLiveStream, useLiveStream, useCamera } from '@ravenkash/react-native';
 
const stream = await joinLiveStream(credentials);
// or, inside a component:
const { room, joining, error } = useLiveStream(stream);
const camera = useCamera(room);
 
if (stream.isHost) {
  await camera.enable();
}
 
await stream.react('❤️');
await stream.leave();

credentials is exactly what addHost()/createViewerToken() (server SDK) returns. joinLiveStream() defaults requestPermissions to whether the role can publish at all — a VIEWER is never prompted for camera/microphone access, since their token can't use it either way.

stream.room/stream.chat are the same Room/RavenChatHandle this page already documents — useParticipants(stream.room), useCamera(stream.room), and stream.chat!.messages.list(...) all work unchanged. No new types were introduced for participants or messages.

Requires no new dependency — this package already composes Raven, and Live Streaming credentials are a plain object (streamId, role, rtc, chat?, chatRootMessageId?) this package types locally.

Production notes

  • Background audio (iOS): add the audio background mode to Info.plist, or calls end when the app is backgrounded.
  • Simulators can't capture video — the iOS Simulator and most Android emulators have no camera. Test video on real hardware.
  • Cleartext: use wss:///https://. Android blocks cleartext by default; don't work around it.

Troubleshooting

  • "RTCPeerConnection is not defined" — the WebRTC globals weren't registered. Constructing a Raven does this automatically; if you touch WebRTC before that, call bootstrapRavenNative() in index.js.
  • Black video, no error — almost always permissions; call permissions.request() (or require()) and look for blockedcheck() never reports it, since it only inspects status without prompting.
  • Works on Wi-Fi, fails on cellular — carrier NAT needs TURN. Forward iceServers from your token response.

Full API reference (permissions module, audio routing, error types): @ravenkash/react-native's exported types.