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