85 lines
4.4 KiB
Swift
85 lines
4.4 KiB
Swift
import AppKit
|
|
import MediaPlayer
|
|
|
|
@main
|
|
@MainActor
|
|
struct SystemPlaybackChecks {
|
|
static func require(_ condition: @autoclosure () -> Bool, _ message: String) {
|
|
if !condition() { fatalError("FAIL: " + message) }
|
|
}
|
|
|
|
static func until(_ message: String, _ condition: () -> Bool) {
|
|
let deadline = ContinuousClock.now.advanced(by: .seconds(10))
|
|
while !condition(), ContinuousClock.now < deadline {
|
|
RunLoop.main.run(until: Date(timeIntervalSinceNow: 0.01))
|
|
}
|
|
require(condition(), message)
|
|
}
|
|
|
|
static func main() {
|
|
_ = NSApplication.shared
|
|
NSApp.setActivationPolicy(.prohibited)
|
|
let suite = "terebi.system-playback-check.\(UUID().uuidString)"
|
|
let defaults = UserDefaults(suiteName: suite)!
|
|
defer { defaults.removePersistentDomain(forName: suite) }
|
|
let model = PlayerModel(defaults: defaults)
|
|
defer { model.shutdown() }
|
|
model.setVolume(0)
|
|
let directory = URL(fileURLWithPath: CommandLine.arguments[1], isDirectory: true)
|
|
let center = MPNowPlayingInfoCenter.default()
|
|
let commands = MPRemoteCommandCenter.shared()
|
|
|
|
model.open(directory.appendingPathComponent("av.mp4"))
|
|
until("open starts authoritative playback") { model.canTogglePlayback && model.state.status == PLAYER_PLAYING }
|
|
require(center.playbackState == .playing, "playing publishes macOS playback ownership")
|
|
require(model.setPlayback(playing: false), "explicit pause accepted")
|
|
until("pause acknowledged") { model.state.status == PLAYER_PAUSED }
|
|
let pausedPosition = model.state.position
|
|
require(model.setPlayback(playing: false), "repeated pause accepted")
|
|
until("idempotent pause does not restart playback") {
|
|
model.state.status == PLAYER_PAUSED && center.playbackState == .paused
|
|
}
|
|
require(model.state.position == pausedPosition, "repeated pause preserves position")
|
|
require(center.nowPlayingInfo?[MPNowPlayingInfoPropertyPlaybackRate] as? Double == 0,
|
|
"paused system timeline does not extrapolate")
|
|
|
|
let seekableState = model.state
|
|
var nonseekableState = seekableState
|
|
nonseekableState.can_seek = false
|
|
model.applyState(nonseekableState)
|
|
require(commands.playCommand.isEnabled && !commands.nextTrackCommand.isEnabled &&
|
|
!commands.skipBackwardCommand.isEnabled && !model.seekRelative(1),
|
|
"nonseekable input retains playback but rejects system seeking")
|
|
model.applyState(seekableState)
|
|
require(commands.nextTrackCommand.isEnabled,
|
|
"seekability changes re-enable commands even when playback metadata is unchanged")
|
|
|
|
require(model.seekRelative(1), "relative seek accepted")
|
|
until("paused seek acknowledged") {
|
|
model.state.status == PLAYER_PAUSED && !model.state.seek_pending &&
|
|
abs(model.state.position - pausedPosition - 1) < 0.05
|
|
}
|
|
require(model.seekRelative(-100), "backward boundary seek accepted")
|
|
until("backward seek clamps at start") { !model.state.seek_pending && model.state.position == 0 }
|
|
require(!model.seekRelative(.nan), "nonfinite external seek rejected")
|
|
require(model.setPlayback(playing: true), "explicit play accepted")
|
|
until("play resumes advancing timeline") { model.state.status == PLAYER_PLAYING && model.state.position > 0.1 }
|
|
require(model.setPlayback(playing: true), "repeated play accepted")
|
|
until("repeated play keeps playing") { model.state.status == PLAYER_PLAYING && model.state.position > 0.2 }
|
|
|
|
model.closeFile()
|
|
require(center.nowPlayingInfo == nil && center.playbackState == .stopped,
|
|
"accepted close releases system playback immediately")
|
|
require(!commands.togglePlayPauseCommand.isEnabled && !commands.nextTrackCommand.isEnabled,
|
|
"closed source cannot receive system playback or seek commands")
|
|
model.open(directory.appendingPathComponent("hdr.mkv"))
|
|
until("decode error acknowledged") { model.state.status == PLAYER_ERROR && !model.isBusy }
|
|
require(center.nowPlayingInfo == nil && !commands.playCommand.isEnabled,
|
|
"failed source does not claim playback keys")
|
|
model.shutdown()
|
|
require(center.nowPlayingInfo == nil && !commands.pauseCommand.isEnabled,
|
|
"shutdown releases system playback")
|
|
print("System playback checks passed")
|
|
}
|
|
}
|