Skip to content

Commit

Permalink
Merge pull request #1624 from shogo4405/feature/fix-DisplayLinkChoreo…
Browse files Browse the repository at this point in the history
…grapher

fixed an issue with the handling of CADisplayLink's duration.
  • Loading branch information
shogo4405 authored Nov 16, 2024
2 parents b03a9da + f5b4987 commit 2f275c8
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 22 deletions.
12 changes: 11 additions & 1 deletion HaishinKit/Sources/HKStream/MediaLink.swift
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import Foundation

final actor MediaLink {
static let capacity = 90
static let startedAt: TimeInterval = 0.0

var dequeue: AsyncStream<CMSampleBuffer> {
AsyncStream<CMSampleBuffer> { continutation in
Expand All @@ -16,6 +17,7 @@ final actor MediaLink {
oldValue?.finish()
}
}
private var startedAt: TimeInterval = MediaLink.startedAt
private var presentationTimeStampOrigin: CMTime = .invalid
private lazy var displayLink = DisplayLinkChoreographer()
private weak var audioPlayer: AudioPlayerNode?
Expand Down Expand Up @@ -45,6 +47,13 @@ final actor MediaLink {
func setAudioPlayer(_ audioPlayer: AudioPlayerNode?) {
self.audioPlayer = audioPlayer
}

private func getCurrentTime(_ currentTime: TimeInterval) async -> TimeInterval {
if startedAt == 0 {
startedAt = currentTime
}
return await audioPlayer?.currentTime ?? (currentTime - startedAt)
}
}

extension MediaLink: AsyncRunner {
Expand All @@ -56,11 +65,12 @@ extension MediaLink: AsyncRunner {
isRunning = true
displayLink.startRunning()
Task {
startedAt = MediaLink.startedAt
for await currentTime in displayLink.updateFrames where isRunning {
guard let storage else {
continue
}
let currentTime = await audioPlayer?.currentTime ?? currentTime
let currentTime = await getCurrentTime(currentTime)
var frameCount = 0
while !storage.isEmpty {
guard let first = storage.head else {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
import Foundation

#if os(macOS)

import CoreVideo
import Foundation

// swiftlint:disable attributes
// CADisplayLink is deprecated, I've given up on making it conform to Sendable.
Expand All @@ -12,7 +10,7 @@ final class DisplayLink: NSObject, @unchecked Sendable {

var isPaused = false {
didSet {
guard let displayLink = displayLink, oldValue != isPaused else {
guard let displayLink, oldValue != isPaused else {
return
}
if isPaused {
Expand Down Expand Up @@ -64,14 +62,14 @@ final class DisplayLink: NSObject, @unchecked Sendable {
}

func add(to runloop: RunLoop, forMode mode: RunLoop.Mode) {
guard let displayLink = displayLink, !isPaused else {
guard let displayLink, !isPaused else {
return
}
CVDisplayLinkStart(displayLink)
}

func invalidate() {
guard let displayLink = displayLink, isPaused else {
guard let displayLink, isPaused else {
return
}
CVDisplayLinkStop(displayLink)
Expand All @@ -96,19 +94,7 @@ import QuartzCore
typealias DisplayLink = CADisplayLink
#endif

protocol ChoreographerDelegate: AnyObject {
func choreographer(_ choreographer: some Choreographer, didFrame duration: Double)
}

protocol Choreographer: Runner {
var isPaused: Bool { get set }
var delegate: (any ChoreographerDelegate)? { get set }

func clear()
}

final class DisplayLinkChoreographer: NSObject {
private static let currentTime = 0.0
private static let preferredFramesPerSecond = 0

var updateFrames: AsyncStream<TimeInterval> {
Expand All @@ -127,18 +113,20 @@ final class DisplayLinkChoreographer: NSObject {
private(set) var isRunning = false
private var displayLink: DisplayLink? {
didSet {
guard displayLink != oldValue else {
return
}
displayLink?.preferredFramesPerSecond = preferredFramesPerSecond
displayLink?.isPaused = false
displayLink?.add(to: .main, forMode: .common)
oldValue?.invalidate()
}
}
private var currentTime: TimeInterval = DisplayLinkChoreographer.currentTime
private var continutation: AsyncStream<TimeInterval>.Continuation?

@objc
private func update(displayLink: DisplayLink) {
continutation?.yield(currentTime)
currentTime += displayLink.duration
continutation?.yield(displayLink.timestamp)
}
}

Expand All @@ -156,7 +144,6 @@ extension DisplayLinkChoreographer: Runner {
return
}
displayLink = nil
currentTime = DisplayLinkChoreographer.currentTime
isRunning = false
}
}

0 comments on commit 2f275c8

Please sign in to comment.