Add audio-gated screen recording for iOS using ReplayKit #224
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Implements PoC screen recording that captures only when audio exceeds threshold, auto-cutting silence. Uses ReplayKit broadcast extension to analyze audio RMS in real-time and gate video frame writing.
Implementation
Native Module (
modules/screen-recorder/)startScreenRecording(),getLastRecordingPath(),isRecording()RPSystemBroadcastPickerViewto select broadcast extensionBroadcast Extension (
ios/BroadcastExtension/)RPBroadcastSampleHandlersubclass processes screen + audio samplesAVAssetWriteroutputs H.264/AAC only during active stateUI (
app/(tabs)/profile.tsx)Configuration
SampleHandler.swiftgroup.com.mieweb.pulse.screenrecorder{container}/Recordings/recording-{timestamp}.mp4Manual Setup Required
Xcode project modification needed to add Broadcast Extension target:
BroadcastExtension, Bundle ID:com.mieweb.pulse.BroadcastExtensionSampleHandler.swiftto targetSee
SCREEN_RECORDING_SETUP.mdfor detailed steps.Testing
Physical iOS device required (ReplayKit unsupported on simulator). Expected behavior:
Files
Warning
Firewall rules blocked me from connecting to one or more addresses (expand for details)
I tried to connect to the following addresses, but was blocked by firewall rules:
cdp.expo.dev/usr/local/bin/node /home/REDACTED/work/pulse/pulse/node_modules/@expo/cli/build/src/utils/telemetry/clients/flushFetchDetached.js /tmp/b527bdf95baf515abf32cd10baf42200/expo-telemetry.json(dns block)/usr/local/bin/node /home/REDACTED/work/pulse/pulse/node_modules/@expo/cli/build/src/utils/telemetry/clients/flushFetchDetached.js /tmp/83dfe08907e57ae4782d1951dd98a567/expo-telemetry.json(dns block)/usr/local/bin/node /home/REDACTED/work/pulse/pulse/node_modules/@expo/cli/build/src/utils/telemetry/clients/flushFetchDetached.js /tmp/83a04291571f28cc5617e268bfc618c1/expo-telemetry.json(dns block)If you need me to access, download, or install something from one of these locations, you can either:
Original prompt
This section details on the original issue you should resolve
<issue_title>Add “Audio-Gated Screen Recording” PoC to Pulse (iOS)</issue_title>
<issue_description>### Summary
Implement a proof-of-concept screen recording flow in the React Native app Pulse that records the iOS screen via ReplayKit, but only writes video when audio is above a configurable threshold (i.e., auto-cuts silence / low-activity periods). Expose this as a “Record Screen” button in the Pulse UI (iOS-only for now).
Background / Motivation
Pulse needs a way to capture short, high-signal screen recordings (e.g. demos, explanations, walkthroughs) without manual editing. The goal is to create something like an “auto short”:
ReplayKit Broadcast Upload Extensions can access screen + audio samples but not hardware buttons or camera, so audio level is a viable real-time signal for when to include or skip parts of the recording.
This ticket is PoC-only, focused on getting the basic pipeline working end-to-end.
Scope
In scope:
Out of scope (for this ticket):
High-Level Requirements
Record Screen Button (React Native UI)
ReplayKit Broadcast Integration (iOS Native)
AVAssetWriteroutput.Output File Handling
AVAssetWriter.React Native ↔ iOS Bridge
startSystemScreenRecording()→ prompts user to start ReplayKit broadcast targeting Pulse’s extension.openLastRecording()or similar to open the last exported video (for testing).Configuration & Debuggability
silent → active,active → silent.Technical Notes / Implementation Details
ReplayKit
RPBroadcastSampleHandler) to receive system-wide screen + audio.processSampleBuffer(_:with:)to handle audio/video:.activeor.silent..active, append to asset writer..silent, drop frame.Audio Level Detection
Float.✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.