oficina / meet Public

Clone
git clone https://amadan.net/oficina/meet

Plain git — no account needed to clone.

Download

Download this file

1import CallsBroadcastKit
2import CoreMedia
3import ReplayKit
4
5/// The broadcast upload extension: ReplayKit's frames in, the app's socket
6/// out. It links CallsBroadcastKit and nothing else of Calls, and holds
7/// one frame buffer, because it lives under a memory ceiling of about
8/// fifty megabytes and is killed without a word past it.
9///
10/// It never talks to the meeting. The app is already in the call and owns
11/// every peer connection; this only hands it pictures.
12final class SampleHandler: RPBroadcastSampleHandler {
13 private var sender: BroadcastSender?
14
15 override func broadcastStarted(withSetupInfo setupInfo: [String: NSObject]?) {
16 guard let group = BroadcastPath.appGroup, let path = BroadcastPath.socket(appGroup: group)
17 else {
18 finish("Calls could not share your screen on this build.")
19 return
20 }
21 let sender = BroadcastSender(path: path)
22 // Two seconds: the countdown has just ended, and the app, which is in
23 // the call, is listening already. Longer would only delay the answer
24 // to someone who started a broadcast with no call to share it to.
25 guard sender.connect(timeout: 2) else {
26 finish("Join a call in Calls, then share your screen from there.")
27 return
28 }
29 sender.onClosed = { [weak self] in
30 self?.finish("You stopped sharing your screen in Calls.")
31 }
32 self.sender = sender
33 }
34
35 override func processSampleBuffer(
36 _ sampleBuffer: CMSampleBuffer, with sampleBufferType: RPSampleBufferType
37 ) {
38 guard sampleBufferType == .video, let sender, let pixels = sampleBuffer.imageBuffer else {
39 return
40 }
41 let orientation =
42 (CMGetAttachment(sampleBuffer, key: RPVideoSampleOrientationKey as CFString, attachmentModeOut: nil)
43 as? NSNumber)?.uint16Value ?? 1
44 let time = CMTimeGetSeconds(sampleBuffer.presentationTimeStamp)
45 sender.send(pixels, orientation: orientation, timestampNs: UInt64(max(0, time) * 1_000_000_000))
46 }
47
48 override func broadcastFinished() {
49 sender?.close()
50 sender = nil
51 }
52
53 /// Ends the broadcast with a sentence the system shows the person. The
54 /// only way an extension can say anything at all.
55 private func finish(_ sentence: String) {
56 sender?.close()
57 sender = nil
58 finishBroadcastWithError(
59 NSError(domain: "Calls", code: 1, userInfo: [NSLocalizedDescriptionKey: sentence]))
60 }
61}
62