RPBroadcastSampleHandler stops immediately after countdown — AVAssetWriter crash on first frame

1 day ago 1
ARTICLE AD BOX

I need help with ReplayKit screen recording using a Broadcast Upload Extension in my React Native Expo (bare) iOS project.

Current situation:

My broadcast extension appears correctly in Control Center under Screen Recording.

When I select it:

The 3-2-1 countdown starts

Recording begins

But it stops instantly

So the broadcast is not actually running properly.

Because of this:

When I return to the app and call stopRecording()

The App Group UserDefaults key (lastRecordingPath) is empty

No video path is returned

It looks like:

broadcastStarted is triggered

But the extension stops immediately

So broadcastFinished might be called right away

Or the extension is crashing on the first frame

Based on debugging, I suspect the crash happens when processSampleBuffer receives the first video frame and calls setupWriter(), which initializes AVAssetWriter with:

AVAssetWriter(outputURL: url, fileType: .mp4)

Project structure:

Main App
Broadcast Upload Extension (SampleHandler.swift)
App Group configured and shared
Extension embedded correctly (Embed & Sign)
Automatic signing enabled
Testing on physical device (iPhone 11, iOS 18.2)

Bundle IDs:
Main App: com.athelia.app
Broadcast Extension: com.athelia.app.AtheliaBroadcast

The extension is visible in Control Center, so configuration seems correct.

Main issue:
Recording starts but stops immediately. Video path is never saved to App Group

Crash log shows (from Analytics Data on device):
Exception: EXC_CRASH (SIGABRT) -[AVAssetWriterInput markAsFinished] closure #1 in SampleHandler.broadcastFinished() consecutiveCrashCount: 3

Logs from main app: zero [EXT] logs ever appear, confirming extension crashes before broadcastStarted prints anything:
Triggering broadcast picker button
Broadcast detection poll 1: isActive=false ... 🔍 Broadcast detection poll 20: isActive=false ⚠️ Broadcast detection timeout

SampleHandler.swift:

override func broadcastStarted(withSetupInfo setupInfo: [String: NSObject]?) { let container = FileManager.default.containerURL( forSecurityApplicationGroupIdentifier: "group.com.athelia.app" ) let baseURL = container ?? FileManager.default .urls(for: .documentDirectory, in: .userDomainMask)[0] let url = baseURL.appendingPathComponent("broadcast_\(Int(Date().timeIntervalSince1970)).mp4") outputURL = url UserDefaults(suiteName: "group.com.athelia.app")?.set(true, forKey: "broadcastIsActive") } override func broadcastFinished() { guard sessionStarted, let writer = assetWriter, writer.status == .writing else { saveResultAndExit(path: nil) return } videoInput?.markAsFinished() // guarded — should never crash audioInput?.markAsFinished() writer.finishWriting { ... } }

Question: Why does the broadcast extension stop immediately after the countdown? What causes broadcastFinished to be called instantly after broadcastStarted with no frames received?

Read Entire Article