Why does CADisplayLink of an external UIScreen drift in time?

I am using Apple's original Lightning Digital AV-adapter (Lightning-to-HDMI dongle) to connect my iPhone to an external display via a HDMI cable.

I need to synchronize rendering with the external display's refresh rate, so I create a new CADisplayLink tied to the external display's UIScreen: UIScreen.screens[externalDisplayIdx].displayLink(withTarget:, selector:).

The callback is being called regularly, but with increasing delay relative to the CADisplayLink.timestamp, so the next time the callback is called, I have less and less time to draw the next frame (see the snippet below).

Assuming 60 FPS, the value of secondsTillDeadline starts at an arbitrary value in the range of approx -0.0001 to 0.0166667, and then it slowly decreases towards zero (and for a brief period it goes into small negative numbers). Once it reaches zero, it flips back to 0.0166667 and continues to decrease again. This cycle repeats indefinitely.

Changing the external display's resolution (UIScreen's mode) or the CADisplayLink's preferredFrameRateRange to a lower FPS does not seem to have any effect on the temporal drifting (even the rate of change seem to be the same).

When I create a new CADisplayLink for the iPhone's main screen, the value of secondsTillDeadline is stable, it does not drift and it is very close to 0.0166667, as expected.

Is this drift caused by the external monitor or by Apple's Lightning-to-HDMI dongle ...or is the problem somewhere else?

Can the drifting be stopped?

func onDisplayLinkUpdate(displayLink: CADisplayLink) {
    // Gradually decreases from 0.01667 to -0.0001, then flips back to 0.01667 and continues to decrease
    let secondsTillDeadline = displayLink.targetTimestamp - CACurrentMediaTime()
}
Answered by DTS Engineer in 851642022

Our engineering teams need to investigate this issue, as resolution may involve changes to Apple's software. Please file a bug report, include a small Xcode project and some directions that can be used to reproduce the problem, and post the Feedback number here once you do. If you post the Feedback number here I'll check the status next time I do a sweep of forums posts where I've suggested bug reports.

Bug Reporting: How and Why? has tips on creating your bug report.

Our engineering teams need to investigate this issue, as resolution may involve changes to Apple's software. Please file a bug report, include a small Xcode project and some directions that can be used to reproduce the problem, and post the Feedback number here once you do. If you post the Feedback number here I'll check the status next time I do a sweep of forums posts where I've suggested bug reports.

Bug Reporting: How and Why? has tips on creating your bug report.

Thanks for your help. The bug report ID: FB19273833

There are two very important updates in the bug report, which I found later, after posting on the Developer Forums:

  • My original post was incorrect: drifting happens when using 60 or 30 FPS as the preferred framerate of the CADisplayLink. When I changed the framerate to 15 FPS, there was no drifting.
  • The drifting happens only when not using the SceneDelegate-based lifecycle. When I created a new SceneDelegate-based app, the CADisplayLink's callback was called without drifting even at 30 and 60 FPS.

Nevertheless, this potential bug led me to question the reliability of the dongle. The dongle seems to use the AirPlay protocol under the hood, so it likely receives a H.264 video stream from the iDevice which it then decodes and sends to the external monitor via HDMI.

Because the dongle is an active component, I'd like to ask if I can rely on iOS and the dongle to stream the video at a constant framerate without drifting over time. That is, when the external screen runs at 60 FPS, does iOS and the dongle guarantee that the average frame duration will always be approx. 0.016667 seconds and not continuously increasing or decreasing?

I don't mind frame drops as I belive a frame drop should be detectable based on the timestamp values in the CADisplayLink's callback. I just want to ask if the framerate is guaranteed to always be the same (driftless) and if the dongle runs at the native framerate of the external monitor.

So if the external monitor would run at 59.94 FPS instead of exactly 60 FPS, would the dongle really detect this and stream the video frames at the native framerate of the monitor even though it is not a multiple of the iDevice's native framerate?

You can rely on iOS to try to maintain the frame rate you have configured for CADisplayLink under normal conditions that you have tested and confirmed on actual devices. Conditions such as memory availability, power availability, device temperature, and other processing your app is doing may result in lower frame rates.

For best results, our recommendation is to test and tune your software for performance under expected conditions on actual devices (not the simulator) that you expect your customers will be using.

Why does CADisplayLink of an external UIScreen drift in time?
 
 
Q