ReplayKit started throwing error in iOS 12

When I start the screen recording in ReplayKit, it throws an error "Error: Recording interrupted by multitasking and content resizing". It started happening in iOS 12.0.1 (I believe it was working fine in iOS 12.0 and definately in iOS 11). Any suggestions? Code is very simple:


RPScreenRecorder.shared().startRecording { (error) in

if let unwrappedError = error {

print("Error: \(unwrappedError.localizedDescription)")

} else {

print("-- started --")

}

}

Replies

Could you file a bug report for this? If you could include a sample project that demonstrates the problem, that would be great.


Please post the bug number here too.

I'm experiencing this same issue - I've filed a bug report (45277846)

https://bugreport.apple.com/web/?problemID=45277846

It included my sysdiagnose and a project to reproduce the issue.


Appreciate any help you can provide. Thanks

Having the same issue. On top of this sometimes the screen from recording in preview is black.

Again, it would be very helpful if you could submit a bug report for this issue (and post the bug number here).

Same issue. Posted a sample project in Bug Reporter.


Bug number(45942896)


Any feedback is appreciated. Have a very frustrated client.

It works again with iOS 12.1 on my side

Not here. Is this on iPad? I am seeing an issue with Preview being blank on iPad.

For anyone else experiencing the issue where you don't get the replaykit preview displaying after stop recording and you're getting the same error listed by OP "Error: Recording interrupted by multitasking and content resizing"


You can get your device working again by resetting your settings on your device


Settings -> General -> Reset -> Reset All Settings


This isn't ideal but it's the only way I've been able to get the device to display the preview video again. This is a known issue according to the response I got on my bug report. My bug got listed as a duplicate.

Please take a look at sample project I uploaded with Bug number(45942896)

My App was rejected in app review due to this error on iPad, iOS 12.1.4
I created another radar 47948315 but cannot reproduce it myself, so no sample project. But I linked to the other radars.
Do we know what the expected case for this error to reasonably pop up would be?

My app has same problem, "Error: Recording interrupted by multitasking and content resizing" with iOS 12.1.4, causing app to fail review (For reference it's a Unity app using ARKit)


I thought I had it mitigated - I moved the initial ReplayKit dialog popup to title screen before ARKit is initialized and I got no reproduction in 30 iPad reboots - but I submitted and was rejected again 🙂 I think app reviewers may be getting this error more frequently than I am...


(Submitted to Bug Reporter just now - https://bugreport.apple.com/web/?problemID=48336197 )

I haven't any issue on my iPad mini. I got this error on iPhones (7, SE, 6+) only on my side :-(

After looking at system logs more, like others my theory is that permissions popup is interfering with ReplayKit ^^;


Here's what the logs look like for me when recording fails - permission alert activates, then ReplayKit starts, then permission alert deactivates:

default 19:19:03.481967 +0900 SpringBoard Activation - Presenting <SBUserNotificationAlert: 0x108babf30; title: “/*..*/; source: replayd; pid: 243> with presenter: <SBUnlockedAlertItemPresenter: 0x28120d580>

default 19:19:06.544478 +0900 deleted com.apple.replayd-cache-delete : 64

default 19:19:06.548708 +0900 atc <private>|including purgeable user data from CacheDelete: /*..*/

default 19:19:07.101506 +0900 replayd user acknowledged recording, but microphone recording is disabled

default 19:19:07.101569 +0900 replayd starting...

default 19:19:07.101671 +0900 replayd broadcast disabled

default 19:19:07.101733 +0900 replayd RPRecordingSession: disableBroadcast

default 19:19:07.101879 +0900 replayd RPRecordingManager:interruptRecordingSessions

default 19:19:07.102619 +0900 replayd RPRecordingSession: startSession

default 19:19:07.102833 +0900 replayd RPConnectionManager: startRecordingWindowLayerContextIDs completed

default 19:19:07.103314 +0900 SpringBoard Deactivated alertItem: <SBUserNotificationAlert: 0x108babf30; title: “/*..*/; source: replayd; pid: 243>


Here's logs for the identical logic when recording succeeds - permission alert activates, then permission alert deactivates, then ReplayKit starts:

default 19:34:45.666900 +0900 SpringBoard Activation - Presenting <SBUserNotificationAlert: 0x10b302af0; title: “/*..*/; source: replayd; pid: 234> with presenter: <SBUnlockedAlertItemPresenter: 0x283441a60>

default 19:34:46.836707 +0900 SpringBoard Deactivated alertItem: <SBUserNotificationAlert: 0x10b302af0; title: “/*..*/; source: replayd; pid: 234>

default 19:34:46.836772 +0900 replayd user acknowledged recording, but microphone recording is disabled

default 19:34:46.836811 +0900 replayd starting...

default 19:34:46.836884 +0900 replayd broadcast disabled

default 19:34:46.836923 +0900 replayd RPRecordingSession: disableBroadcast

default 19:34:46.836979 +0900 replayd RPRecordingManager:interruptRecordingSessions

default 19:34:46.837591 +0900 replayd RPRecordingSession: startSession

default 19:34:46.838125 +0900 SpringBoard [FBServiceFacilityServer] Client replayd:234 connected to service com.apple.frontboardservices.display-layout-monitor

default 19:34:46.838269 +0900 replayd RPConnectionManager: startRecordingWindowLayerContextIDs completed

For me, recording is happening in iOS 12.1.4. And that is limited to app screen.

When I close the app (click home button only), then the recording get paused. I am trying to record device screen and save the recorded content to photolibrary. Below are the logs and code snippet.


default 19:28:47.504383 +0530 replayd RPRecordingManager: HandleInputBuffer: Successfully enqueued the audio buffer
default 19:28:47.504553 +0530 replayd replayd sending audio payload to broadcast extension...
default 19:28:47.504694 +0530 replayd replayd sending audio payload to broadcast extension...
default 19:28:47.508415 +0530 replayd RPRecordingManager:broadcastSessionDidUpdateDuration:
default 19:28:47.509871 +0530 ScreenBroadCast RPBroadcastSampleHandler: broadcast extension recieved audio payload from replayd
default 19:28:47.510044 +0530 replayd replayd sending audio payload to broadcast extension...
default 19:28:47.532084 +0530 replayd RPRecordingManager:broadcastSessionDidUpdateDuration:
default 19:28:47.534650 +0530 ScreenBroadCast RPBroadcastSampleHandler: broadcast extension recieved audio payload from replayd
default 19:28:47.534875 +0530 replayd replayd sending audio payload to broadcast extension...
default 19:28:47.557325 +0530 replayd RPRecordingManager:broadcastSessionDidUpdateDuration:
default 19:28:47.560960 +0530 ScreenBroadCast RPBroadcastSampleHandler: broadcast extension recieved audio payload from replayd
default 19:28:47.561334 +0530 replayd replayd sending audio payload to broadcast extension...
default 19:28:47.581341 +0530 replayd RPRecordingManager:broadcastSessionDidUpdateDuration:
default 19:28:47.584910 +0530 ScreenBroadCast RPBroadcastSampleHandler: broadcast extension recieved audio payload from replayd
default 19:28:47.585499 +0530 replayd replayd sending audio payload to broadcast extension...
default 19:28:47.777372 +0530 replayd RPConnectionManager: pauseRecording
default 19:28:47.777405 +0530 replayd RPRecordingManager:pauseRecording
default 19:28:47.777436 +0530 replayd RPRecordingSession: pauseSession
default 19:28:47.777497 +0530 replayd RPRecordingSession: stopAllCapture
default 19:28:47.777533 +0530 replayd RPRecordingManager:broadcastSessionDidUpdateDuration:
default 19:28:47.779245 +0530 mediaserverd 392: AQME device AQDefaultDevice: client stopping: <remoteioclient@0x15020b800(@0x15020b858); input;="" sid:0x1a084,="" replayd(142),="" 'prim'="">; running count now 0
default 19:28:47.779383 +0530 mediaserverd 4439: { "action":"set_play_state", "session":{"ID":"0x1a084","PID":142,"name":"replayd"}, "details":"entry" }
default 19:28:47.779590 +0530 mediaserverd -CMSessionMgr- cmsSetIsPlaying: CMSession: 'sid:0x1a084, replayd(142), 'prim'' with [PlayAndRecord_WithBluetooth/Default] [Mixable] [System Audio] stopping playing. Ringer switch state: ON.
default 19:28:47.779650 +0530 mediaserverd CAReportingClient.mm:328:-[CAReportingClient sendMessage:category:type:reporters:]: message {
    Volume = "0.5";
    VolumeCategory = "Audio/Video";
    VolumeOperationProcess = replayd;
    VolumeOperationTime = 27654;
    VolumePlayingState = 0;
}: (
    1703959
)
default 19:28:47.779735 +0530 mediaserverd -CMSessionMgr- cmsSetIsPlaying: CMSession: Starting deactivate timer for client 'sid:0x1a084, replayd(142), 'prim''
default 19:28:47.780002 +0530 mediaserverd -CMSUtilities- CMSUtility_SetIsRecording: CMSession: Client sid:0x1a084, replayd(142), 'prim' has stopped recording
default 19:28:47.780390 +0530 mediaserverd 4588: { "action":"set_play_state", "session":{"ID":"0x1a084","PID":142,"name":"replayd"}, "details":{"IOs":[0,0,0,0,0],"IsRecording":false,"active":true,"modes":"Input","player":"0x15020b800","state":"Stopped","type":"Remote IO"} }
default 19:28:47.786236 +0530 mediaserverd -CMSessionMgr- cmsSetIsActive: CMSession: 'sid:0x1a084, replayd(142), 'prim'' with category/mode PlayAndRecord_WithBluetooth/Default going inactive 0 0
default 19:28:47.844179 +0530 replayd RPCaptureManager: stopDeviceCaptureSessionWithFinishHandler
default 19:28:47.844250 +0530 replayd [FBSDisplaySource 2-2] KVO: did change connectionSeed
default 19:28:47.844314 +0530 replayd [FBSDisplaySource 2-2] KVO: did change uniqueId
default 19:28:47.844417 +0530 replayd [FBSDisplaySource 2-2] KVO: did change availableModes
default 19:28:47.844514 +0530 replayd [FBSDisplaySource 2-2] KVO: did change currentMode
default 19:28:47.844602 +0530 replayd [FBSDisplaySource 2-2] KVO: did change preferredMode
default 19:28:47.844724 +0530 replayd [FBSDisplaySource 2-2] KVO: did change bounds
default 19:28:47.844807 +0530 replayd [FBSDisplaySource 2-2] KVO: did change frame
default 19:28:47.844874 +0530 replayd RPRecordingManager:broadcastSessionDidUpdateDuration:
default 19:28:47.844970 +0530 replayd [FBSDisplaySource 2-2] KVO: did change cloningSupported
default 19:28:47.845251 +0530 replayd RPRecordingManager:broadcastSessionDidUpdateDuration:
default 19:28:47.845447 +0530 replayd RPRecordingManager:broadcastSessionDidUpdateDuration:
default 19:28:47.845566 +0530 replayd RPRecordingManager:broadcastSessionDidUpdateDuration:
default 19:28:47.860670 +0530 replayd [FBSDisplaySource 2-2] KVO: did change tag
default 19:28:48.224228 +0530 mediaserverd -CMSessionMgr- cmsSetIsActive: CMSession: Stopping deactivate timer for client 'sid:0x1a084, replayd(142), 'prim''
default 19:28:48.224289 +0530 mediaserverd CAReportingClient.mm:328:-[CAReportingClient sendMessage:category:type:reporters:]: message {
    Volume = "0.4375";
    VolumeOperationProcess = replayd;
    VolumeOperationTime = 27655;
    VolumePlayingState = 0;
}: (
    1703959
)
default 19:28:48.224347 +0530 mediaserverd -CMSUtilities- CMSUtility_SendSessionStateAndVolumeReportToAudioToolBox: CMSession: Stopping reporter for session : sid:0x1a084, replayd(142), 'prim', reporter id = 1703959
default 19:28:48.484271 +0530 replayd RPRecordingManager: Audio Queue has been disposed
default 19:28:48.484314 +0530 replayd Stop mirroring
default 19:28:48.484354 +0530 replayd RPConnectionManager: pauseRecording completed
default 19:28:48.484393 +0530 replayd RPConnectionManager: clientDidResignActive
default 19:28:48.484432 +0530 replayd RPRecordingManager:clientDidResignActiveWithBundleID:
default 19:28:48.484471 +0530 replayd RPConnectionManager: clientDidResignActive completed
default 19:28:48.484516 +0530 replayd [FBSDisplaySource 2-2] KVO: did change tag
default 19:28:48.535173 +0530 mediaserverd 3434: { "action":"property_change", "session":{"ID":"0x1a084","PID":142,"name":"replayd"}, "details":{"key":"ActiveAudioRouteDidChange"} }
error 19:28:48.549960 +0530 replayd AVAudioSessionPortImpl.mm:56:ValidateRequiredFields: Unknown selected data source for Port Receiver (type: Receiver)
default 19:28:48.549995 +0530 replayd AVAudioSession.mm:250:HandleRouteChange: Posting AVAudioSessionRouteChangeNotification. Reason: 3
error 19:28:48.550030 +0530 replayd AVAudioSessionPortImpl.mm:56:ValidateRequiredFields: Unknown selected data source for Port Speaker (type: Speaker)
error 19:29:28.571764 +0530 kernel Sandbox: replayd(142) deny(1) mach-lookup com.apple.backboard.hid.services



Here is main target level broadcasting snippet:



func startBroadcast(viewController:UIViewController){
        self.containerVC = viewController
        delegate = self.containerVC as? ScreenRecorderDelegate

        guard recorder.isAvailable else {
            print("Recording is not available at this time.")
            return
        }
        recorder.isCameraEnabled = true
        recorder.isMicrophoneEnabled = true

        // Broadcast Pairing
        let bundleID = "com.tech.screenCastDemo.BroadcastExtensionUI"

        RPBroadcastActivityViewController.load(withPreferredExtension: bundleID, handler: { (broadcastViewController, error) in

            guard broadcastViewController != nil else {
                return
            }
            self.broadcastActivityViewController = broadcastViewController
            self.broadcastActivityViewController!.delegate = self
            self.broadcastActivityViewController!.modalPresentationStyle = .popover
            self.broadcastActivityViewController!.modalTransitionStyle = .flipHorizontal

            print("error:\(String(describing: error))")
            print(self.broadcastActivityViewController as Any)
            print(self.broadcastActivityViewController?.extensionContext as Any)
            print(self.broadcastActivityViewController?.delegate as Any)
            print(self.containerVC as Any)

           
            DispatchQueue.main.async {
                self.containerVC!.present(self.broadcastActivityViewController!, animated: true, completion: {
                    print("done")
                })
            }
        })
    }

    func stopBroadcast(){
        broadcaster?.finishBroadcast { error in
            if error == nil {
                print("Broadcast ended")
                self.broadcastEnded()
            }
        }
    }

    func broadcastActivityViewController(_ broadcastActivityViewController: RPBroadcastActivityViewController, didFinishWith broadcastController: RPBroadcastController?, error: Error?) {

        print(broadcastActivityViewController)
        print(broadcastController)
        print(error)
        guard error == nil else {
            print("Broadcast Activity Controller is not available.")
            return
        }
        print("broadcasting")

        DispatchQueue.main.async {
            broadcastActivityViewController.dismiss(animated: true) {

            }
            self.broadcaster = broadcastController
            self.broadcaster!.delegate = self
            self.broadcaster!.startBroadcast { (error) in
                guard error == nil else {
                    print("error while start broadcasting - \(String(describing: error))")
                    return
                }
                self.isBroadCasting = true
                if error == nil {
                    print("Broadcast started successfully!")
                    self.broadcastStarted()
                }
            }
        }
    }


And here is my ScreenBroadCasterUI class


//
//  BroadcastSetupViewController.swift
//  ScreenBroadCastSetupUI
//
//  Created by Ankit Thakur on 25/03/19.
//

import ReplayKit

class BroadcastSetupViewController: UIViewController {

    override func viewDidLoad() {
        print("recording started")
        userDidFinishSetup()
    }
    // Call this method when the user has finished interacting with the view controller and a broadcast stream can start
    func userDidFinishSetup() {
        // URL of the resource where broadcast can be viewed that will be returned to the application
        print("recording userDidFinishSetup")
        let broadcastURL = URL(string:"http://apple.com/broadcast/streamID") 
       
        // Dictionary with setup information that will be provided to broadcast extension when broadcast is started
        let setupInfo: [String : NSCoding & NSObjectProtocol] = ["broadcastName": "example" as NSCoding & NSObjectProtocol]
       
        // Tell ReplayKit that the extension is finished setting up and can begin broadcasting
        self.extensionContext?.completeRequest(withBroadcast: broadcastURL!, setupInfo: setupInfo)
    }
   
    func userDidCancelSetup() {
        print("recording userDidCancelSetup")
        let error = NSError(domain: "YouAppDomain", code: -1, userInfo: nil)
        // Tell ReplayKit that the extension was cancelled by the user
        self.extensionContext?.cancelRequest(withError: error)
    }
}



Here is SampleHelper:



import ReplayKit

class SampleHandler: RPBroadcastSampleHandler {

    override func broadcastStarted(withSetupInfo setupInfo: [String : NSObject]?) {
        // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
        print("recording broadcastStarted")
    }
   
    override func broadcastPaused() {
        // User has requested to pause the broadcast. Samples will stop being delivered.
        print(#function)
    }
   
    override func broadcastResumed() {
        // User has requested to resume the broadcast. Samples delivery will resume.
        print(#function)
    }
   
    override func broadcastFinished() {
        // User has requested to finish the broadcast.
        print(#function)
    }
   
    override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
        print(#function)
        switch sampleBufferType {
            case RPSampleBufferType.video:
                // Handle video sample buffer
                break
            case RPSampleBufferType.audioApp:
                // Handle audio sample buffer for app audio
                break
            case RPSampleBufferType.audioMic:
                // Handle audio sample buffer for mic audio
                break
        }
    }
}



Here are the console logs in XCode



2019-03-28 19:04:01.097602+0530 ScreenSharing[822:112046] [MC] System group container for systemgroup.com.apple.configurationprofiles path is /private/var/containers/Shared/SystemGroup/systemgroup.com.apple.configurationprofiles
2019-03-28 19:04:01.097965+0530 ScreenSharing[822:112046] [MC] Reading from public effective user settings.
2019-03-28 19:04:01.113621+0530 ScreenSharing[822:112046] [framework] CUIThemeStore: No theme registered with id=0
error:nil
Optional()
nil
Optional()
Optional()
done

Optional()
nil
broadcasting
2019-03-28 19:04:02.894801+0530 ScreenSharing[822:112080] [Assert] Cannot be called with asCopy = NO on non-main thread.
2019-03-28 19:04:02.894865+0530 ScreenSharing[822:112080] [Assert] Cannot be called with asCopy = NO on non-main thread.
Broadcast started successfully!
broadcast started
self.broadcaster?.isBroadcasting: Optional(true)
self.broadcaster?.isBroadcasting: Optional()
error in connection_block_invoke_2: Connection interrupted