14 Replies
      Latest reply on Mar 28, 2019 7:12 AM by Ankitthakur
      oxigenator Level 1 Level 1 (0 points)

        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 --")

                        }

                    }

        • Re: ReplayKit started throwing error in iOS 12
          Polyphonic Apple Staff Apple Staff (70 points)

          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.

          • Re: ReplayKit started throwing error in iOS 12
            designmax Level 1 Level 1 (0 points)

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

            • Re: ReplayKit started throwing error in iOS 12
              wavewash Level 1 Level 1 (0 points)

              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.

              • Re: ReplayKit started throwing error in iOS 12
                hannesoid Level 1 Level 1 (0 points)

                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?

                • Re: ReplayKit started throwing error in iOS 12
                  Johnabre Level 1 Level 1 (0 points)

                  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 )

                    • Re: ReplayKit started throwing error in iOS 12
                      RustamKhisamov Level 1 Level 1 (0 points)

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

                      • Re: ReplayKit started throwing error in iOS 12
                        Johnabre Level 1 Level 1 (0 points)

                        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

                      • Re: ReplayKit started throwing error in iOS 12
                        Ankitthakur Level 1 Level 1 (0 points)

                        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