SampleHandler.swift 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. //
  2. // SampleHandler.swift
  3. // Broadcast Extension
  4. //
  5. // Created by Alex-Dan Bumbu on 04.06.2021.
  6. //
  7. // From https://github.com/jitsi/jitsi-meet-sdk-samples (Apache 2.0 license)
  8. // SPDX-FileCopyrightText: 2021 Alex-Dan Bumbu
  9. // SPDX-License-Identifier: Apache-2.0
  10. import ReplayKit
  11. class SampleHandler: RPBroadcastSampleHandler {
  12. private var clientConnection: SocketConnection?
  13. private var uploader: SampleUploader?
  14. private var frameCount: Int = 0
  15. var socketFilePath: String {
  16. let sharedContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: groupIdentifier)
  17. return sharedContainer?.appendingPathComponent("rtc_SSFD").path ?? ""
  18. }
  19. override init() {
  20. super.init()
  21. if let connection = SocketConnection(filePath: socketFilePath) {
  22. clientConnection = connection
  23. setupConnection()
  24. uploader = SampleUploader(connection: connection)
  25. }
  26. }
  27. override func broadcastStarted(withSetupInfo setupInfo: [String: NSObject]?) {
  28. // User has requested to start the broadcast. Setup info from the UI extension can be supplied but optional.
  29. frameCount = 0
  30. DarwinNotificationCenter.shared.postNotification(DarwinNotificationCenter.broadcastStartedNotification)
  31. openConnection()
  32. }
  33. override func broadcastPaused() {
  34. // User has requested to pause the broadcast. Samples will stop being delivered.
  35. }
  36. override func broadcastResumed() {
  37. // User has requested to resume the broadcast. Samples delivery will resume.
  38. }
  39. override func broadcastFinished() {
  40. // User has requested to finish the broadcast.
  41. DarwinNotificationCenter.shared.postNotification(DarwinNotificationCenter.broadcastStoppedNotification)
  42. clientConnection?.close()
  43. }
  44. override func processSampleBuffer(_ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType) {
  45. switch sampleBufferType {
  46. case RPSampleBufferType.video:
  47. // very simple mechanism for adjusting frame rate by using every third frame
  48. frameCount += 1
  49. if frameCount % 2 == 0 {
  50. uploader?.send(sample: sampleBuffer)
  51. }
  52. default:
  53. break
  54. }
  55. }
  56. }
  57. private extension SampleHandler {
  58. func setupConnection() {
  59. clientConnection?.didClose = { [weak self] error in
  60. print("client connection did close \(String(describing: error))")
  61. if let error = error {
  62. self?.finishBroadcastWithError(error)
  63. } else {
  64. // the displayed failure message is more user friendly when using NSError instead of Error
  65. let JMScreenSharingStopped = 10001
  66. let localizedError = NSLocalizedString("Screensharing stopped", comment: "")
  67. let customError = NSError(domain: RPRecordingErrorDomain, code: JMScreenSharingStopped, userInfo: [NSLocalizedDescriptionKey: localizedError])
  68. self?.finishBroadcastWithError(customError)
  69. }
  70. }
  71. }
  72. func openConnection() {
  73. let queue = DispatchQueue(label: "broadcast.connectTimer")
  74. let timer = DispatchSource.makeTimerSource(queue: queue)
  75. timer.schedule(deadline: .now(), repeating: .milliseconds(100), leeway: .milliseconds(500))
  76. timer.setEventHandler { [weak self] in
  77. guard self?.clientConnection?.open() == true else {
  78. return
  79. }
  80. timer.cancel()
  81. }
  82. timer.resume()
  83. }
  84. }