crowdplaysdk
v0.4.1
Published
CrowdPlay lossless conversation capture for React Native (iOS). Studio-grade per-participant recording during live video calls, delivered to CrowdPlay automatically.
Maintainers
Readme
crowdplaysdk
CrowdPlay's lossless conversation capture for React Native (iOS). Your app hosts a live video call; every participant's audio (48 kHz / 24-bit unprocessed WAV) and video (1080p30 HEVC) is recorded locally, at full quality, clock-aligned across participants, and delivered to CrowdPlay automatically — uploads retry, resume, and survive crashes.
No media ever crosses the JS bridge. The engine is the same compiled native core (CrowdPlaySDK) our reference app runs; React Native drives it with control calls and receives state events. Recording quality is identical to a fully native app.
Non-technical? Paste this to your AI agent
I'm building this app: <YOUR APP IDEA — e.g., a tutoring app where
students and tutors meet over video>
Build it as a React Native iOS app. For the video-call feature, use the
crowdplaysdk package.
What the app is about — read carefully:
- The app's name, screens, and flows are about MY IDEA above. The SDK
records calls in the background for CrowdPlay; recording is NOT the
app's purpose and must not be presented as it. It appears in the UI in
the SDK's consent screen before joining a call,
a small REC indicator during the call, join/leave, and a small
audio-output menu.
- Keep the SDK integration minimal: consent → join/leave → call screen.
The call screen MUST include a small audio-output menu showing the
current output device by name (from the 'audioRoute' event) with a
switch between the device and Speaker (CrowdPlay.setAudioOutput). Do
NOT build upload screens, diagnostics screens, or SDK settings.
Uploads happen automatically in the background.
- npm install crowdplaysdk
- In ios/: pod install, then run
gem install xcodeproj --user-install # one-time
ruby node_modules/crowdplaysdk/ios/wire.rb <MyProjectName>
(adds the compiled CrowdPlay engine + bridge to the Xcode project)
- Info.plist: NSMicrophoneUsageDescription, NSCameraUsageDescription,
UIBackgroundModes = [audio]
- My CrowdPlay app key: <APP KEY from the CrowdPlay dashboard>
- Follow node_modules/crowdplaysdk/llms.txt exactly: configure at
startup, the CrowdPlayConsentScreen before joining (join() throws
without a ConsentGrant), CrowdPlayVideoView tiles from the participants
event, and surface the warning events on the call screen.
- Never add, pin or import LiveKit/WebRTC yourself, and never write your
own AVAudioSession/AVCaptureSession code — the engine owns the mic and
camera.
- When done, run CrowdPlay.doctor() as a development check (not an app
screen) and fix anything actionable.
- Your FINAL message must walk me through testing on my real iPhone,
step by step (the Simulator has no camera or mic, so nothing is proven
until then): plugging it in, signing/Developer Mode, running from
Xcode, allowing permissions, doing a ~1-minute test call, and checking
my session at https://dashboard.crowdplay.ai. Do not just say the
implementation is complete.Manual setup (iOS)
npm install crowdplaysdkcd ios && pod install(one-time:gem install xcodeproj --user-install— the wiring script needs it)ruby node_modules/crowdplaysdk/ios/wire.rb <YourProjectName>— idempotent; adds the CrowdPlaySDK Swift package (the compiled engine), copies the three bridge files into your app target, and points the Swift bridging header at the React headers. (No CocoaPod of our own: the engine ships as a binary Swift package, which keeps your Podfile untouched.)Info.plist:
NSMicrophoneUsageDescription,NSCameraUsageDescription,UIBackgroundModes = [audio].Recommended, for uploads that finish while your app is suspended — in your AppDelegate:
// AppDelegate.mm — add #import "<YourProjectName>-Swift.h" at the top - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)(void))completionHandler { [CrowdPlayRNBackground handleWithCompletionHandler:completionHandler]; }(Swift AppDelegates call
CrowdPlaySDK.handleBackgroundURLSessionEvents(completionHandler:).)
Usage
import CrowdPlay, { CrowdPlayConsentScreen, CrowdPlayVideoView } from 'crowdplaysdk';
CrowdPlay.configure({ serverUrl: 'https://…', appKey: 'liva_pk_…' });
// Voice-only app? add audioOnly: true — the camera is never touched
// (no camera permission, no video captured or uploaded).
// 1. Consent (REQUIRED — join() throws without it):
<CrowdPlayConsentScreen onConsent={(grant) => setConsent(grant)} />
// 2. Join — recording starts automatically:
await CrowdPlay.join({ displayName, roomCode, consent });
// 3. Render the call:
<CrowdPlayVideoView participant="local" style={…} /> // self view
{participants.map(p => <CrowdPlayVideoView participant={p.identity} … />)}
// 4. Controls:
await CrowdPlay.setMicMuted(true); // mutes the call AND records silence
await CrowdPlay.setCameraEnabled(false); // black frames, timeline continuous
await CrowdPlay.leave(); // stops recording; uploads continue
// State: subscribe to events
CrowdPlay.addListener('phase', …) // idle/connecting/connected/failed
CrowdPlay.addListener('participants', …) // who to render tiles for
CrowdPlay.addListener('uploads', …) // per-session progress
CrowdPlay.addListener('warning', …) // micSilent / clipping / crossTalk — SHOW THESE
CrowdPlay.addListener('recording', …) // error ⇒ NOT capturing; offer retryRecording()
CrowdPlay.addListener('audioRoute', …) // current output device — drive the output menu
CrowdPlay.setAudioOutput('speaker') // or 'automatic' (the connected device)
CrowdPlay.snapshot() // poll 1 Hz for REC timer + input level
CrowdPlay.doctor() // integration self-checkThe complete example lives in this repo's Examples (one file, ~170
lines): consent → join → tiles → warnings → uploads.
Accessing recordings
Your app key doubles as your data credential — see the CrowdPlay dashboard
(browse + download per session) or the REST endpoints (GET /sessions,
GET /sessions/<id>/files) documented in the CrowdPlaySDK README.
Requirements & limits
- iOS 17+, React Native ≥ 0.71. iOS only for now — no Android engine yet, calls to the module on other platforms throw with a clear message.
- Real device required to record (the Simulator has no camera/mic).
- The npm version can run ahead of the compiled engine version wire.rb pins — bridge and doc fixes ship without a new engine binary. wire.rb always pins the engine release this bridge was tested against.
- Keep the screen awake during sessions; force-quitting the app pauses uploads until next launch (they resume automatically).
- Slow join + glitchy first seconds = bad radio, not a bug. Congested 2.4 GHz WiFi plus Bluetooth headphones (they share the antenna) slows the call connect and can chop the first seconds of audio while the Bluetooth link settles; capture self-heals and the rest of the session is unaffected. Prefer a good network and wired headphones, and evaluate quality with the app launched from the home screen — Metro/debugger overhead can reproduce the same symptoms.
