屏幕保护程序结束后音频继续播放

Audio keeps playing after screensaver ends

我正在制作带有(可选)音频的屏幕保护程序。但是每当我通过滑动鼠标停用它时,音频都会继续播放几秒钟。但是,在系统首选项中单击预览时不会发生这种情况。我的理论是,当在预览中移动鼠标时,屏幕保护进程会立即被终止,但当它不是 运行 预览时则不会。有没有一种方法可以让我感应到鼠标 activity 并通过 运行 函数自行停止音频? 我在下面提供了一些代码: https://gist.github.com/MaxTechnics/3d4280fabc4da53b6df1022864d1bf23 如果需要,将提供更多。提前致谢!

更新:我认为这是问题的主要部分,因为音频永远不会及时停止

// MARK: - Lifecycle
extension VideoView {
    
    override func startAnimation() {
        super.startAnimation()
        manager.player.play()
    }
    
    override func stopAnimation() {
        super.stopAnimation()
        manager.player.pause()
    }
}

经过一些调整后,虽然我们无法拦截键盘(也不应该可靠地检测到退出),但实际上可以在屏幕保护程序中收听一些分布式通知,告诉我们用户何时登录,并使用它来调用我们的代码以停止 animations/sound,因为在我们被有效杀死和用户返回桌面之间存在相当大的延迟。

我确实在此处的此答案中找到了一些事件:Monitoring Screensaver Events in OSX 虽然它有点过时,但这些事件仍然会被触发,并且可以在屏幕保护程序中拦截,尽管有沙盒。我确实发现了一些新的,尽管它们可能对其他用途很有趣。

无论如何,这对我有用:

class AerialView: ScreenSaverView {
    ...
    func setNotifications {
        DistributedNotificationCenter.default.addObserver(self, selector: #selector(AerialView.willStop(_:)), name: Notification.Name("com.apple.screensaver.willstop"), object: nil)
    }

    @objc func willStop(_ aNotification: Notification) {
        NSLog("############ willStop")
        // Put your stop audio/animation code here
    }
}

(您必须自己调用 setNotifications 或将该代码放在其他地方)。

实际上,有多个事件在屏幕保护程序退出时一个接一个地触发:

  • com.apple.screensaver.willstop
  • com.apple.screensaver.didstop
  • com.apple.screenIsUnlocked
  • com.apple.screenLockUIIsShown

这是这些事件的一些记录

2021-04-27 14:52:00.564 : ############ screenLockUIIsShown
2021-04-27 14:52:01.873 : ############ screenIsUnlocked
2021-04-27 14:52:01.873 : ############ willStop
2021-04-27 14:52:01.879 : ############ didStop

第一个事件是我按下一个键,大约1.5秒后手表解锁解锁屏幕,你可以看到3个事件被连续触发。

在那种情况下,屏幕保护程序的实际终止只发生在 14:52:07。

为了完整起见,一些新事件用于检测登录 UI 何时启动和关闭(可能对其他一些事情有用)。这是在 11.4 中,我不知道这些事件是否在以前版本的 macOS 中触发。按射击顺序:

  • com.apple.shieldWindowRaised
  • com.apple.screenIsLocked
  • com.apple.screenLockUIIsShown
  • com.apple.screenLockUIIsHidden
  • com.apple.shieldWindowLowered
  • com.apple.screenIsUnlocked