Skip to content

Commit

Permalink
Completely remove Promises dependency (migrate to async/await) (liv…
Browse files Browse the repository at this point in the history
…ekit#271)

* engine rewrite

* impl

* reconnect attempts

* remove Promises from Engine

* progress

* remove Promises

* remove Promises package

* macOS screen sharing

* resend frame timer

* objC

* fix iOS

* clean up
  • Loading branch information
hiroshihorie committed Nov 3, 2023
1 parent 75dc6cf commit 4b2df99
Show file tree
Hide file tree
Showing 50 changed files with 1,195 additions and 2,559 deletions.
4 changes: 2 additions & 2 deletions Package.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ let package = Package(
dependencies: [
.package(name: "WebRTC", url: "https://github.com/livekit/webrtc-xcframework-static.git", .exact("114.5735.09")),
.package(name: "SwiftProtobuf", url: "https://github.com/apple/swift-protobuf.git", .upToNextMajor(from: "1.21.0")),
.package(name: "Promises", url: "https://github.com/google/promises.git", .upToNextMajor(from: "2.2.0")),
.package(url: "https://github.com/apple/swift-log.git", .upToNextMajor(from: "1.5.2"))
],
targets: [
Expand All @@ -28,7 +27,8 @@ let package = Package(
name: "LiveKit",
dependencies: [
.target(name: "CHeaders"),
"WebRTC", "SwiftProtobuf", "Promises",
"WebRTC",
"SwiftProtobuf",
.product(name: "Logging", package: "swift-log"),
],
path: "Sources"
Expand Down
100 changes: 41 additions & 59 deletions Sources/LiveKit/Broadcast/BroadcastScreenCapturer.swift
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
//

import Foundation
import Promises

#if canImport(UIKit)
import UIKit
Expand All @@ -17,83 +16,66 @@ import UIKit
#if os(iOS)

class BroadcastScreenCapturer: BufferCapturer {

static let kRTCScreensharingSocketFD = "rtc_SSFD"
static let kAppGroupIdentifierKey = "RTCAppGroupIdentifier"
static let kRTCScreenSharingExtension = "RTCScreenSharingExtension"

var frameReader: SocketConnectionFrameReader?

override func startCapture() -> Promise<Bool> {

super.startCapture().then(on: queue) {didStart -> Promise<Bool> in

guard didStart, self.frameReader == nil else {
// already started
return Promise(false)
}

guard let identifier = self.lookUpAppGroupIdentifier(),
let filePath = self.filePathForIdentifier(identifier)
else {
return Promise { false }
}

return Promise { fufill, _ in
let bounds = UIScreen.main.bounds
let width = bounds.size.width
let height = bounds.size.height
let screenDimension = Dimensions(width: Int32(width), height: Int32(height))

// pre fill dimensions, so that we don't have to wait for the broadcast to start to get actual dimensions.
// should be able to safely predict using actual screen dimensions.
let targetDimensions = screenDimension
.aspectFit(size: self.options.dimensions.max)
.toEncodeSafeDimensions()

defer { self.dimensions = targetDimensions }
let frameReader = SocketConnectionFrameReader()
guard let socketConnection = BroadcastServerSocketConnection(filePath: filePath, streamDelegate: frameReader)
else {
fufill(false)
return
}
frameReader.didCapture = { pixelBuffer, rotation in
self.capture(pixelBuffer, rotation: rotation.toLKType())

}
frameReader.startCapture(with: socketConnection)
self.frameReader = frameReader
fufill(true)
}
override func startCapture() async throws -> Bool {

let didStart = try await super.startCapture()

guard didStart else { return false }

guard let identifier = lookUpAppGroupIdentifier(),
let filePath = filePathForIdentifier(identifier) else { return false }

let bounds = await UIScreen.main.bounds
let width = bounds.size.width
let height = bounds.size.height
let screenDimension = Dimensions(width: Int32(width), height: Int32(height))

// pre fill dimensions, so that we don't have to wait for the broadcast to start to get actual dimensions.
// should be able to safely predict using actual screen dimensions.
let targetDimensions = screenDimension
.aspectFit(size: self.options.dimensions.max)
.toEncodeSafeDimensions()

defer { self.dimensions = targetDimensions }
let frameReader = SocketConnectionFrameReader()
guard let socketConnection = BroadcastServerSocketConnection(filePath: filePath, streamDelegate: frameReader)
else { return false }
frameReader.didCapture = { pixelBuffer, rotation in
self.capture(pixelBuffer, rotation: rotation.toLKType())

}
frameReader.startCapture(with: socketConnection)
self.frameReader = frameReader

return true
}

override func stopCapture() -> Promise<Bool> {
override func stopCapture() async throws -> Bool {

super.stopCapture().then(on: queue) { didStop -> Promise<Bool> in
let didStop = try await super.stopCapture()

guard didStop, self.frameReader != nil else {
// already stopped
return Promise(false)
}
// Already stopped
guard didStop else { return false }

return Promise { fulfill, _ in
self.frameReader?.stopCapture()
self.frameReader = nil
fulfill(true)
}
}
self.frameReader?.stopCapture()
self.frameReader = nil
return true
}

private func lookUpAppGroupIdentifier() -> String? {
return Bundle.main.infoDictionary?[BroadcastScreenCapturer.kAppGroupIdentifierKey] as? String
Bundle.main.infoDictionary?[BroadcastScreenCapturer.kAppGroupIdentifierKey] as? String
}

private func filePathForIdentifier(_ identifier: String) -> String? {
guard let sharedContainer = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: identifier)
else {
return nil
}
else { return nil }

let filePath = sharedContainer.appendingPathComponent(BroadcastScreenCapturer.kRTCScreensharingSocketFD).path
return filePath
Expand Down
1 change: 0 additions & 1 deletion Sources/LiveKit/Broadcast/Uploader/LKSampleHandler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@

#if os(iOS)

import Promises
import OSLog
import Logging

Expand Down
32 changes: 17 additions & 15 deletions Sources/LiveKit/Core/Engine+SignalClientDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@
*/

import Foundation
import Promises

@_implementationOnly import WebRTC

Expand All @@ -32,34 +31,37 @@ extension Engine: SignalClientDelegate {
// engine is currently connected state
case .connected = _state.connectionState {
log("[reconnect] starting, reason: socket network error. connectionState: \(_state.connectionState)")
startReconnect()
Task {
try await startReconnect()
}
}
}

func signalClient(_ signalClient: SignalClient, didReceive iceCandidate: LKRTCIceCandidate, target: Livekit_SignalTarget) {

guard let transport = target == .subscriber ? subscriber : publisher else {
log("failed to add ice candidate, transport is nil for target: \(target)", .error)
log("Failed to add ice candidate, transport is nil for target: \(target)", .error)
return
}

promise(from: transport.add(iceCandidate:), param1: iceCandidate).catch(on: queue) { error in
self.log("failed to add ice candidate for transport: \(transport), error: \(error)", .error)
Task {
do {
try await transport.add(iceCandidate: iceCandidate)
} catch let error {
log("Failed to add ice candidate for transport: \(transport), error: \(error)", .error)
}
}
}

func signalClient(_ signalClient: SignalClient, didReceiveAnswer answer: LKRTCSessionDescription) {

guard let publisher = self.publisher else {
log("publisher is nil", .error)
return
}

promise(from: publisher.set(remoteDescription:), param1: answer).catch(on: queue) { error in
self.log("failed to set remote description, error: \(error)", .error)
Task {
do {
let publisher = try await requirePublisher()
try await publisher.set(remoteDescription: answer)
} catch let error {
log("Failed to set remote description, error: \(error)", .error)
}
}

return
}

func signalClient(_ signalClient: SignalClient, didReceiveOffer offer: LKRTCSessionDescription) {
Expand Down
4 changes: 3 additions & 1 deletion Sources/LiveKit/Core/Engine+TransportDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,9 @@ extension Engine: TransportDelegate {
// Attempt re-connect if primary or publisher transport failed
if (transport.isPrimary || (_state.hasPublished && transport.target == .publisher)) && [.disconnected, .failed].contains(pcState) {
log("[reconnect] starting, reason: transport disconnected or failed")
startReconnect()
Task {
try await startReconnect()
}
}
}
}
Expand Down
Loading

0 comments on commit 4b2df99

Please sign in to comment.