From d4f51568eb0ff7a38cca797e7d8d6dc0ca37a114 Mon Sep 17 00:00:00 2001 From: Jacob Gelman <3182119+ladvoc@users.noreply.github.com> Date: Sat, 18 Jan 2025 13:18:33 -0800 Subject: [PATCH] Use Combine to avoid extra dependency --- Package.swift | 2 - Package@swift-5.9.swift | 2 - .../Broadcast/BroadcastExtensionState.swift | 36 ++++-------- .../Participant/LocalParticipant.swift | 56 ++++++++++++------- 4 files changed, 47 insertions(+), 49 deletions(-) diff --git a/Package.swift b/Package.swift index 944d6599e..bf7183a9a 100644 --- a/Package.swift +++ b/Package.swift @@ -17,7 +17,6 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/apple/swift-async-algorithms", from: "1.0.0"), // LK-Prefixed Dynamic WebRTC XCFramework .package(url: "https://github.com/livekit/webrtc-xcframework.git", exact: "125.6422.11"), .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.26.0"), @@ -37,7 +36,6 @@ let package = Package( dependencies: [ .product(name: "LiveKitWebRTC", package: "webrtc-xcframework"), .product(name: "SwiftProtobuf", package: "swift-protobuf"), - .product(name: "AsyncAlgorithms", package: "swift-async-algorithms"), .product(name: "Logging", package: "swift-log"), "LKObjCHelpers", ], diff --git a/Package@swift-5.9.swift b/Package@swift-5.9.swift index 9e7ee2c30..37e1c664d 100644 --- a/Package@swift-5.9.swift +++ b/Package@swift-5.9.swift @@ -19,7 +19,6 @@ let package = Package( ), ], dependencies: [ - .package(url: "https://github.com/apple/swift-async-algorithms", from: "1.0.0"), // LK-Prefixed Dynamic WebRTC XCFramework .package(url: "https://github.com/livekit/webrtc-xcframework.git", exact: "125.6422.11"), .package(url: "https://github.com/apple/swift-protobuf.git", from: "1.26.0"), @@ -39,7 +38,6 @@ let package = Package( dependencies: [ .product(name: "LiveKitWebRTC", package: "webrtc-xcframework"), .product(name: "SwiftProtobuf", package: "swift-protobuf"), - .product(name: "AsyncAlgorithms", package: "swift-async-algorithms"), .product(name: "Logging", package: "swift-log"), "LKObjCHelpers", ], diff --git a/Sources/LiveKit/Broadcast/BroadcastExtensionState.swift b/Sources/LiveKit/Broadcast/BroadcastExtensionState.swift index a31fe0a6f..a7a7afc6e 100644 --- a/Sources/LiveKit/Broadcast/BroadcastExtensionState.swift +++ b/Sources/LiveKit/Broadcast/BroadcastExtensionState.swift @@ -16,45 +16,31 @@ #if os(iOS) -import AsyncAlgorithms +import Combine import Foundation #if canImport(ReplayKit) import ReplayKit #endif -actor BroadcastExtensionState { - /// Whether or not the broadcast extension is currently broadcasting. - private(set) var isBroadcasting = false +class BroadcastExtensionState { + /// A publisher that emits a Boolean value indicating whether or not the extension is currently broadcasting. + static var isBroadcasting: some Publisher { + Publishers.Merge( + DarwinNotificationCenter.shared.publisher(for: .broadcastStarted).map { _ in true }, + DarwinNotificationCenter.shared.publisher(for: .broadcastStopped).map { _ in false } + ) + .eraseToAnyPublisher() + } /// Displays the system broadcast picker, allowing the user to start the broadcast. /// - Note: This is merely a request and does not guarantee the user will choose to start the broadcast. - nonisolated func requestActivation() async { + static func requestActivation() async { await RPSystemBroadcastPickerView.show( for: BroadcastScreenCapturer.screenSharingExtension, showsMicrophoneButton: false ) } - - private var listenTask: Task? - - /// Creates a new instance and begins listening. - init(_ changeHandler: ((Bool) async -> Void)? = nil) async { - listenTask = Task { - let stateStream = merge( - DarwinNotificationCenter.shared.notifications(named: .broadcastStarted).map { true }, - DarwinNotificationCenter.shared.notifications(named: .broadcastStopped).map { false } - ) - for await isBroadcasting in stateStream { - self.isBroadcasting = isBroadcasting - await changeHandler?(isBroadcasting) - } - } - } - - deinit { - listenTask?.cancel() - } } #endif diff --git a/Sources/LiveKit/Participant/LocalParticipant.swift b/Sources/LiveKit/Participant/LocalParticipant.swift index 60e6fe460..7b0c516dd 100644 --- a/Sources/LiveKit/Participant/LocalParticipant.swift +++ b/Sources/LiveKit/Participant/LocalParticipant.swift @@ -15,6 +15,7 @@ */ import Foundation +import Combine #if swift(>=5.9) internal import LiveKitWebRTC @@ -237,27 +238,42 @@ public class LocalParticipant: Participant { /// returning `true` or `false` based on the user's response . /// public var broadcastStarted: (() async -> Bool)? - - private var extensionState: BroadcastExtensionState! + + private var isBroadcasting = false { + didSet { broadcastStateChanged() } + } + private var cancellable = Set() override init(room: Room, sid: Participant.Sid? = nil, identity: Participant.Identity? = nil) { super.init(room: room, sid: sid, identity: identity) - Task { - extensionState = await BroadcastExtensionState { [weak self] isBroadcasting in - guard isBroadcasting else { return } - - logger.debug("Broadcast extension initiated screen share") - let shouldPublish = await self?.broadcastStarted?() ?? true - - guard shouldPublish else { - logger.debug("Will not publish screen share track") - return - } - do { - try await self?.setScreenShare(enabled: true) - } catch { - logger.error("Failed to enable screen share: \(error)") - } + + BroadcastExtensionState + .isBroadcasting + .sink { [weak self] in + guard let self else { return } + self.isBroadcasting = $0 + } + .store(in: &cancellable) + } + + private func broadcastStateChanged() { + guard isBroadcasting else { + logger.debug("Broadcast stopped") + return + } + logger.debug("Broadcast started") + + Task { [weak self] in + guard let self else { return } + let shouldPublish = await self.broadcastStarted?() ?? true + guard shouldPublish else { + logger.debug("Will not publish screen share track") + return + } + do { + try await self.setScreenShare(enabled: true) + } catch { + logger.error("Failed to enable screen share: \(error)") } } } @@ -372,8 +388,8 @@ public extension LocalParticipant { let localTrack: LocalVideoTrack let options = (captureOptions as? ScreenShareCaptureOptions) ?? room._state.roomOptions.defaultScreenShareCaptureOptions if options.useBroadcastExtension { - guard await self.extensionState.isBroadcasting else { - await self.extensionState.requestActivation() + guard self.isBroadcasting else { + await BroadcastExtensionState.requestActivation() return nil } // Wait until broadcasting to publish track