104 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
			
		
		
	
	
			104 lines
		
	
	
		
			3.4 KiB
		
	
	
	
		
			Swift
		
	
	
	
	
	
//
 | 
						|
//  SampleHandler.swift
 | 
						|
//  Broadcast Extension
 | 
						|
//
 | 
						|
//  Created by Alex-Dan Bumbu on 04.06.2021.
 | 
						|
//
 | 
						|
 | 
						|
import ReplayKit
 | 
						|
import OSLog
 | 
						|
 | 
						|
let broadcastLogger = OSLog(subsystem: "dev.solsynth.solian", category: "Broadcast")
 | 
						|
private enum Constants {
 | 
						|
    // the App Group ID value that the app and the broadcast extension targets are setup with. It differs for each app.
 | 
						|
    static let appGroupIdentifier = "group.solsynth.solian"
 | 
						|
}
 | 
						|
 | 
						|
class SampleHandler: RPBroadcastSampleHandler {
 | 
						|
 | 
						|
    private var clientConnection: SocketConnection?
 | 
						|
    private var uploader: SampleUploader?
 | 
						|
 | 
						|
    private var frameCount: Int = 0
 | 
						|
 | 
						|
    var socketFilePath: String {
 | 
						|
      let sharedContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: Constants.appGroupIdentifier)
 | 
						|
        return sharedContainer?.appendingPathComponent("rtc_SSFD").path ?? ""
 | 
						|
    }
 | 
						|
 | 
						|
    override init() {
 | 
						|
      super.init()
 | 
						|
        if let connection = SocketConnection(filePath: socketFilePath) {
 | 
						|
          clientConnection = connection
 | 
						|
          setupConnection()
 | 
						|
 | 
						|
          uploader = SampleUploader(connection: connection)
 | 
						|
        }
 | 
						|
        os_log(.debug, log: broadcastLogger, "%{public}s", socketFilePath)
 | 
						|
    }
 | 
						|
 | 
						|
    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.
 | 
						|
        frameCount = 0
 | 
						|
 | 
						|
        DarwinNotificationCenter.shared.postNotification(.broadcastStarted)
 | 
						|
        openConnection()
 | 
						|
    }
 | 
						|
 | 
						|
    override func broadcastPaused() {
 | 
						|
        // User has requested to pause the broadcast. Samples will stop being delivered.
 | 
						|
    }
 | 
						|
 | 
						|
    override func broadcastResumed() {
 | 
						|
        // User has requested to resume the broadcast. Samples delivery will resume.
 | 
						|
    }
 | 
						|
 | 
						|
    override func broadcastFinished() {
 | 
						|
        // User has requested to finish the broadcast.
 | 
						|
        DarwinNotificationCenter.shared.postNotification(.broadcastStopped)
 | 
						|
        clientConnection?.close()
 | 
						|
    }
 | 
						|
 | 
						|
    override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
 | 
						|
        switch sampleBufferType {
 | 
						|
        case RPSampleBufferType.video:
 | 
						|
            uploader?.send(sample: sampleBuffer)
 | 
						|
        default:
 | 
						|
            break
 | 
						|
        }
 | 
						|
    }
 | 
						|
}
 | 
						|
 | 
						|
private extension SampleHandler {
 | 
						|
 | 
						|
    func setupConnection() {
 | 
						|
        clientConnection?.didClose = { [weak self] error in
 | 
						|
            os_log(.debug, log: broadcastLogger, "client connection did close \(String(describing: error))")
 | 
						|
 | 
						|
            if let error = error {
 | 
						|
                self?.finishBroadcastWithError(error)
 | 
						|
            } else {
 | 
						|
                // the displayed failure message is more user friendly when using NSError instead of Error
 | 
						|
                let JMScreenSharingStopped = 10001
 | 
						|
                let customError = NSError(domain: RPRecordingErrorDomain, code: JMScreenSharingStopped, userInfo: [NSLocalizedDescriptionKey: "Screen sharing stopped"])
 | 
						|
                self?.finishBroadcastWithError(customError)
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    func openConnection() {
 | 
						|
        let queue = DispatchQueue(label: "broadcast.connectTimer")
 | 
						|
        let timer = DispatchSource.makeTimerSource(queue: queue)
 | 
						|
        timer.schedule(deadline: .now(), repeating: .milliseconds(100), leeway: .milliseconds(500))
 | 
						|
        timer.setEventHandler { [weak self] in
 | 
						|
            guard self?.clientConnection?.open() == true else {
 | 
						|
                return
 | 
						|
            }
 | 
						|
 | 
						|
            timer.cancel()
 | 
						|
        }
 | 
						|
 | 
						|
        timer.resume()
 | 
						|
    }
 | 
						|
}
 |