mirror of
https://github.com/yattee/yattee.git
synced 2026-07-20 14:22:02 +00:00
Add tvOS A/V sync diagnostics on its own settings page
Surface audio-delay (±10/±100 ms) and video-sync-mode controls behind an "A/V Sync" navigation row in Advanced settings rather than inline, keeping the Advanced page uncluttered. Audio delay applies live to the running MPV instance; sync mode takes effect on next playback.
This commit is contained in:
@@ -439,8 +439,13 @@ final class MPVClient: @unchecked Sendable {
|
||||
|
||||
// Use display-vdrop: drops/repeats frames to match display timing
|
||||
// This is lighter weight than display-resample (no interpolation overhead)
|
||||
// and handles both hardware and software decode gracefully
|
||||
// and handles both hardware and software decode gracefully.
|
||||
// On tvOS, the user may override this via the debug Video Sync Mode setting.
|
||||
#if os(tvOS)
|
||||
setOptionSync("video-sync", SettingsManager.tvVideoSyncModeSync().rawValue)
|
||||
#else
|
||||
setOptionSync("video-sync", "display-vdrop")
|
||||
#endif
|
||||
|
||||
// Allow frame dropping when decoder can't keep up (essential for software decode)
|
||||
// decoder+vo: drop at decoder level first, then at video output if still behind
|
||||
@@ -480,10 +485,30 @@ final class MPVClient: @unchecked Sendable {
|
||||
// Apply subtitle appearance settings
|
||||
applySubtitleSettings()
|
||||
|
||||
// Apply user-configured fixed audio delay on tvOS (in seconds; setting is ms)
|
||||
#if os(tvOS)
|
||||
let delaySeconds = SettingsManager.tvAudioDelayMsSync() / 1000.0
|
||||
setOptionSync("audio-delay", String(delaySeconds))
|
||||
#endif
|
||||
|
||||
// Apply user's custom MPV options (these can override defaults)
|
||||
applyCustomOptions()
|
||||
}
|
||||
|
||||
/// Update the `audio-delay` property on a running MPV instance. Safe to call
|
||||
/// while playback is active. Value is in milliseconds; converted to seconds
|
||||
/// before being sent to MPV.
|
||||
func updateAudioDelay(milliseconds: Double) {
|
||||
mpvQueue.async { [weak self] in
|
||||
guard let self, let mpv = self.mpv, !self.isDestroyed else { return }
|
||||
let seconds = milliseconds / 1000.0
|
||||
let str = String(seconds)
|
||||
str.withCString { ptr in
|
||||
_ = mpv_set_property_string(mpv, "audio-delay", ptr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Apply subtitle appearance settings from user preferences.
|
||||
private func applySubtitleSettings() {
|
||||
let subtitleSettings = SettingsManager.subtitleSettingsSync()
|
||||
@@ -981,6 +1006,14 @@ final class MPVClient: @unchecked Sendable {
|
||||
var videoSpeedCorrection: Double?
|
||||
var audioSpeedCorrection: Double?
|
||||
var framedrop: String?
|
||||
var audioDelay: Double?
|
||||
var currentVo: String?
|
||||
var currentAo: String?
|
||||
var audioDevice: String?
|
||||
var displayWidth: Int?
|
||||
var displayHeight: Int?
|
||||
var displayNames: String?
|
||||
var decoderFrameDropCount: Int?
|
||||
}
|
||||
|
||||
/// Fetch all debug properties in a single sync block to avoid multiple lock acquisitions.
|
||||
@@ -1052,6 +1085,14 @@ final class MPVClient: @unchecked Sendable {
|
||||
props.videoSpeedCorrection = getDouble("video-speed-correction")
|
||||
props.audioSpeedCorrection = getDouble("audio-speed-correction")
|
||||
props.framedrop = getString("framedrop")
|
||||
props.audioDelay = getDouble("audio-delay")
|
||||
props.currentVo = getString("current-vo")
|
||||
props.currentAo = getString("current-ao")
|
||||
props.audioDevice = getString("audio-device")
|
||||
props.displayWidth = getInt("display-width")
|
||||
props.displayHeight = getInt("display-height")
|
||||
props.displayNames = getString("display-names")
|
||||
props.decoderFrameDropCount = getInt("decoder-frame-drop-count")
|
||||
#endif
|
||||
|
||||
return props
|
||||
@@ -1281,8 +1322,16 @@ final class MPVClient: @unchecked Sendable {
|
||||
props.videoSpeedCorrection = getDouble("video-speed-correction")
|
||||
props.audioSpeedCorrection = getDouble("audio-speed-correction")
|
||||
props.framedrop = getString("framedrop")
|
||||
props.audioDelay = getDouble("audio-delay")
|
||||
props.currentVo = getString("current-vo")
|
||||
props.currentAo = getString("current-ao")
|
||||
props.audioDevice = getString("audio-device")
|
||||
props.displayWidth = getInt("display-width")
|
||||
props.displayHeight = getInt("display-height")
|
||||
props.displayNames = getString("display-names")
|
||||
props.decoderFrameDropCount = getInt("decoder-frame-drop-count")
|
||||
#endif
|
||||
|
||||
|
||||
continuation.resume(returning: props)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -902,6 +902,12 @@ final class MPVBackend: PlayerBackend {
|
||||
mpvClient?.updateSubtitleSettings()
|
||||
}
|
||||
|
||||
/// Push the current tvOS audio-delay setting into the running MPV instance.
|
||||
/// Caller passes milliseconds; MPVClient converts to seconds.
|
||||
func updateAudioDelay(milliseconds: Double) {
|
||||
mpvClient?.updateAudioDelay(milliseconds: milliseconds)
|
||||
}
|
||||
|
||||
/// Get the actual video track dimensions from MPV.
|
||||
/// Returns (width, height) or nil if not available.
|
||||
func getVideoSize() -> (width: Int, height: Int)? {
|
||||
@@ -963,6 +969,14 @@ final class MPVBackend: PlayerBackend {
|
||||
stats.audioSpeedCorrection = props.audioSpeedCorrection
|
||||
stats.framedrop = props.framedrop
|
||||
stats.displayLinkFps = renderView?.displayLinkTargetFPS
|
||||
stats.audioDelay = props.audioDelay
|
||||
stats.currentVo = props.currentVo
|
||||
stats.currentAo = props.currentAo
|
||||
stats.audioDevice = props.audioDevice
|
||||
stats.displayWidth = props.displayWidth
|
||||
stats.displayHeight = props.displayHeight
|
||||
stats.displayNames = props.displayNames
|
||||
stats.decoderFrameDropCount = props.decoderFrameDropCount
|
||||
#endif
|
||||
|
||||
return stats
|
||||
|
||||
Reference in New Issue
Block a user