AVAudioPlayer 和 AudioServices 如果两次播放之间 >1 s 都会延迟声音
AVAudioPlayer and AudioServices both delay sound if >1 s between plays
我希望在用户点击视图时播放声音的延迟可以忽略不计。我在 AVAudioPlayer
和 AudioServices 上都试过这个,但我在两者上都遇到了同样的问题:如果两次点击之间的间隔超过一秒,则会有轻微的延迟。换句话说,会发生以下情况:
- 快速连续点击多次,只有第一次点击有延迟,
- 暂停大约一秒或更长时间,
- 再次点击多次(或仅点击一次),并且只有第一次点击会延迟。
我们谈论的延迟很短,可能是 100 毫秒左右,但足以让播放不像其他播放那样 feel/sound 是瞬时的。这是代码的 AVAudioPlayer
版本:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player:AVAudioPlayer!
override func viewDidLoad() {
super.viewDidLoad()
let soundUrl = Bundle.main.url(forResource: "short_sound", withExtension: "wav")!
player = try! AVAudioPlayer(contentsOf: soundUrl)
player.volume = 0 // "Prime the pump"
player.play()
let r = TouchDownGestureRecognizer(target: self, action: #selector(tapped(_:)))
self.view.addGestureRecognizer(r)
}
func tapped(_ gesture: TouchDownGestureRecognizer){
player.volume = 1
player.play()
}
}
这是 AudioServices 版本。在这种情况下,other posts 建议在 "prime the pump" 初始化期间可以播放无声声音,但这只会解决第一个声音。此问题会影响 1 秒以上延迟后出现的所有声音。
import UIKit
import AudioToolbox
class ViewController: UIViewController {
var soundID:SystemSoundID = 0
override func viewDidLoad() {
super.viewDidLoad()
let soundUrl = Bundle.main.url(forResource: "short_sound", withExtension: "wav")!
AudioServicesCreateSystemSoundID(soundUrl as CFURL, &soundID)
let r = TouchDownGestureRecognizer(target: self, action: #selector(tapped(_:)))
self.view.addGestureRecognizer(r)
}
func tapped(_ gesture: TouchDownGestureRecognizer){
AudioServicesPlaySystemSound(soundID)
}
}
在这两种情况下,都会使用此 "touch down" 识别器 (by @le-sang):
import Foundation
import UIKit.UIGestureRecognizerSubclass
class TouchDownGestureRecognizer: UIGestureRecognizer {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
if self.state == .possible {
self.state = .recognized
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
self.state = .failed
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
self.state = .failed
}
}
我也尝试过将 UILongPressGestureRecognizer
与 minimumPressDuration=0
一起使用,同样的事情发生了。另外,如果我用 UIControl
替换 UIView
并设置 target/action,也是一样的。任何见解将不胜感激,感谢阅读。
这是我找到的修复方法。我对这个解决方案不是很满意(仍然不确定为什么会发生这种情况),但它确实对两个玩家都有效。
这个想法很简单:如果你让任何一个玩家独处一秒钟左右,它就会开始小睡,然后在你需要它的时候花点时间醒来。因此,解决方案是定期 "nudge" 播放器,这样它就不会开始打盹。
对于 AVAudioPlayer
案例:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player:AVAudioPlayer!
var ghostPlayer:AVAudioPlayer!
var timer:Timer!
override func viewDidLoad() {
super.viewDidLoad()
let soundUrl = Bundle.main.url(forResource: "short_sound", withExtension: "wav")!
player = try! AVAudioPlayer(contentsOf: soundUrl)
ghostPlayer = try! AVAudioPlayer(contentsOf: soundUrl)
ghostPlayer.volume = 0
ghostPlayer.play()
timer = Timer.scheduledTimer(timeInterval: 0.5,
target: self,
selector: #selector(nudgeAudio),
userInfo: nil,
repeats: true)
let r = TouchDownGestureRecognizer(target: self, action: #selector(tapped(_:)))
self.view.addGestureRecognizer(r)
}
func tapped(_ gesture: TouchDownGestureRecognizer){
player.play()
}
func nudgeAudio() {
ghostPlayer.play()
}
}
对于音频服务:
import UIKit
import AudioToolbox
class ViewController: UIViewController {
var soundID:SystemSoundID = 0
var ghostID:SystemSoundID = 1
var timer:Timer!
override func viewDidLoad() {
super.viewDidLoad()
let soundUrl = Bundle.main.url(forResource: "short_sound", withExtension: "wav")!
AudioServicesCreateSystemSoundID(soundUrl as CFURL, &soundID)
let ghostUrl = Bundle.main.url(forResource: "silence", withExtension: "wav")!
AudioServicesCreateSystemSoundID(ghostUrl as CFURL, &ghostID)
timer = Timer.scheduledTimer(timeInterval: 0.5,
target: self,
selector: #selector(nudgeAudio),
userInfo: nil,
repeats: true)
let r = TouchDownGestureRecognizer(target: self, action: #selector(tapped(_:)))
self.view.addGestureRecognizer(r)
}
func tapped(_ gesture: TouchDownGestureRecognizer){
AudioServicesPlaySystemSound(soundID)
}
func nudgeAudio() {
AudioServicesPlaySystemSound(ghostID)
}
}
我希望在用户点击视图时播放声音的延迟可以忽略不计。我在 AVAudioPlayer
和 AudioServices 上都试过这个,但我在两者上都遇到了同样的问题:如果两次点击之间的间隔超过一秒,则会有轻微的延迟。换句话说,会发生以下情况:
- 快速连续点击多次,只有第一次点击有延迟,
- 暂停大约一秒或更长时间,
- 再次点击多次(或仅点击一次),并且只有第一次点击会延迟。
我们谈论的延迟很短,可能是 100 毫秒左右,但足以让播放不像其他播放那样 feel/sound 是瞬时的。这是代码的 AVAudioPlayer
版本:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player:AVAudioPlayer!
override func viewDidLoad() {
super.viewDidLoad()
let soundUrl = Bundle.main.url(forResource: "short_sound", withExtension: "wav")!
player = try! AVAudioPlayer(contentsOf: soundUrl)
player.volume = 0 // "Prime the pump"
player.play()
let r = TouchDownGestureRecognizer(target: self, action: #selector(tapped(_:)))
self.view.addGestureRecognizer(r)
}
func tapped(_ gesture: TouchDownGestureRecognizer){
player.volume = 1
player.play()
}
}
这是 AudioServices 版本。在这种情况下,other posts 建议在 "prime the pump" 初始化期间可以播放无声声音,但这只会解决第一个声音。此问题会影响 1 秒以上延迟后出现的所有声音。
import UIKit
import AudioToolbox
class ViewController: UIViewController {
var soundID:SystemSoundID = 0
override func viewDidLoad() {
super.viewDidLoad()
let soundUrl = Bundle.main.url(forResource: "short_sound", withExtension: "wav")!
AudioServicesCreateSystemSoundID(soundUrl as CFURL, &soundID)
let r = TouchDownGestureRecognizer(target: self, action: #selector(tapped(_:)))
self.view.addGestureRecognizer(r)
}
func tapped(_ gesture: TouchDownGestureRecognizer){
AudioServicesPlaySystemSound(soundID)
}
}
在这两种情况下,都会使用此 "touch down" 识别器 (by @le-sang):
import Foundation
import UIKit.UIGestureRecognizerSubclass
class TouchDownGestureRecognizer: UIGestureRecognizer {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent) {
if self.state == .possible {
self.state = .recognized
}
}
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent) {
self.state = .failed
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent) {
self.state = .failed
}
}
我也尝试过将 UILongPressGestureRecognizer
与 minimumPressDuration=0
一起使用,同样的事情发生了。另外,如果我用 UIControl
替换 UIView
并设置 target/action,也是一样的。任何见解将不胜感激,感谢阅读。
这是我找到的修复方法。我对这个解决方案不是很满意(仍然不确定为什么会发生这种情况),但它确实对两个玩家都有效。
这个想法很简单:如果你让任何一个玩家独处一秒钟左右,它就会开始小睡,然后在你需要它的时候花点时间醒来。因此,解决方案是定期 "nudge" 播放器,这样它就不会开始打盹。
对于 AVAudioPlayer
案例:
import UIKit
import AVFoundation
class ViewController: UIViewController {
var player:AVAudioPlayer!
var ghostPlayer:AVAudioPlayer!
var timer:Timer!
override func viewDidLoad() {
super.viewDidLoad()
let soundUrl = Bundle.main.url(forResource: "short_sound", withExtension: "wav")!
player = try! AVAudioPlayer(contentsOf: soundUrl)
ghostPlayer = try! AVAudioPlayer(contentsOf: soundUrl)
ghostPlayer.volume = 0
ghostPlayer.play()
timer = Timer.scheduledTimer(timeInterval: 0.5,
target: self,
selector: #selector(nudgeAudio),
userInfo: nil,
repeats: true)
let r = TouchDownGestureRecognizer(target: self, action: #selector(tapped(_:)))
self.view.addGestureRecognizer(r)
}
func tapped(_ gesture: TouchDownGestureRecognizer){
player.play()
}
func nudgeAudio() {
ghostPlayer.play()
}
}
对于音频服务:
import UIKit
import AudioToolbox
class ViewController: UIViewController {
var soundID:SystemSoundID = 0
var ghostID:SystemSoundID = 1
var timer:Timer!
override func viewDidLoad() {
super.viewDidLoad()
let soundUrl = Bundle.main.url(forResource: "short_sound", withExtension: "wav")!
AudioServicesCreateSystemSoundID(soundUrl as CFURL, &soundID)
let ghostUrl = Bundle.main.url(forResource: "silence", withExtension: "wav")!
AudioServicesCreateSystemSoundID(ghostUrl as CFURL, &ghostID)
timer = Timer.scheduledTimer(timeInterval: 0.5,
target: self,
selector: #selector(nudgeAudio),
userInfo: nil,
repeats: true)
let r = TouchDownGestureRecognizer(target: self, action: #selector(tapped(_:)))
self.view.addGestureRecognizer(r)
}
func tapped(_ gesture: TouchDownGestureRecognizer){
AudioServicesPlaySystemSound(soundID)
}
func nudgeAudio() {
AudioServicesPlaySystemSound(ghostID)
}
}