gpt4 book ai didi

ios - 如何拥有高优先级线程进行音频处理

转载 作者:行者123 更新时间:2023-11-29 05:35:11 25 4
gpt4 key购买 nike

我有 iOS 应用程序,我正在使用 AVAudioEngine 播放音频。我将音频文件中的帧读取到 AVAudioPCMBuffer 中,然后将缓冲区发布到 AVAudioPlayerNode.scheduleBuffer 中。我在 DispatchQueue 上读取帧。我遇到的问题是,当应用程序有很多其他工作要做时 - 与服务器同步和下载文件,读取 DispatchQueue 上的帧会延迟几秒钟,这会导致声音中断。我已将 DispatchQueueQos 设置为尽可能高的 .userInteractive,并且应用程序中没有具有相同 qos 的其他队列,但有时仍需要几秒钟才能在该队列上执行代码。

有什么办法可以解决这个问题吗?有什么方法可以告诉操作系统这个队列用于音频或类似的东西吗?

注意:如果应用程序运行一些繁重的后台操作,我的 AVPlayer 不会出现此问题。

编辑:一些代码以便更好地理解。问题是有时需要几秒钟的时间才能将任务发布到队列上(从评论 1 到评论 2)。

var audioProcessingQueue = DispatchQueue(label: "audioProcessing", qos: .userInteractive)
var player = AVAudioPlayerNode()
//comment 1
self.audioProcessingQueue.async(flags: .barrier) {
//comment 2
//some buffer processing here...
player.scheduleBuffer(buffer, at: nil)
}

谢谢

最佳答案

有两件事:

1) 您提供的代码安排在哪个队列上?因为听起来该队列可能与您的下载任务共享其服务质量。分派(dispatch)到另一个队列确实需要多个步骤。因此,仅仅因为“comment1”被传递,其他队列之一可能会在您调度时获得线程时间来完成一些工作。这会导致一些延迟,是的,而且似乎是最可能的原因。

2) WWDC 2016 视频 Concurrent Programming with GCD in Swift 3 , 可能有帮助。如果 cpu 的所有核心都忙于其他任务,则将新任务分派(dispatch)到更高优先级队列不会立即自动启动该任务。 GCD 会尽力而为,但也许您在其他队列上的任务非常紧张/做一些中断会导致问题的事情。

因此,如果您有必须立即启动的任务,请确保有一个 CPU 核心/线程处于空闲状态。我会尝试使用 OperationQueue 并设置其 maxConcurrentOperationCount。然后将所有下载操作放入该操作队列中,留下核心/线程准备启动音频。

但是我认为选项 2 在这里无效,因为你说它有时需要几秒钟。

更新:

正如您所说,您提供的代码在一个队列上运行,该队列也用于您的下载任务,这主要是一个错误的架构设计,我很遗憾地说,没有任何人可以想出解决方案查看整个项目以帮助更好地构建它。您必须弄清楚何时以及将哪些任务分派(dispatch)给哪个优先级。

以下是我对您提供的代码的想法:

为什么要使用.barrier标志?此标志可确保队列不会完成其他并发任务,如果您的数据由多个任务操作并且希望避免“竞争条件”,那么该标志非常有用。然而,这也意味着在您调度该 block 之后,它将等待在它之前调度的其他任务,然后阻塞队列来执行您的任务。

正如其他人评论的那样,使用工具分析您的代码可能会显示此行为。

以下是我如何构建您的音频请求:

//A serial (not concurrent) audio queue. Will download one data at a time and play audio
let audioQueue = DispatchQueue(label: "Audio Queue My App", qos: .userInitiated)

//I'm on the main queue here!

audioQueue.async {
//I'm on the audio queue here, thus not blocking the main thread
let result = downloadSomeData()
//Download is done here, and I'm not being blocked by other dispatch queues if their priority is lower.
switch result {
case .success(let data):
//Do something with the data and play audio
case .failure(let error):
//Handle Error
}
}
///Downloads some audio data
func downloadSomeData() -> Swift.Result<Data, Error> {
//Create dispatch group
let dg = DispatchGroup()
dg.enter()
///my audio data
var data: Data?
//Dispatch onto a background queue OR place a block operation onto your OperationQueue
DispatchQueue.global(qos: .background).async {
//Download audio data... Alamofire/ URLSession
data = Data()
dg.leave()
}
dg.wait()

//Data was downloaded! We're back on the queue that called us.
if let nonOptionalData = data {
return .success(nonOptionalData)
} else {
return .failure(NSError(domain: "MyDomain", code: 007, userInfo: [ NSLocalizedDescriptionKey: "No data downloaded, failed?"]))
}
}

关于选项#2:

可以使用ProcessInfo().activeProcessorCount检索事件核心的数量。请注意,理论上,该值可能会在运行应用程序时由于热限制或其他原因而发生变化。通过使用此信息并将 OperationQueuemaxConcurrentOperationCount 设置为等于事件处理器的数量,您可以确保操作/任务不必共享 CPU 时间。 (只要没有其他 DispatchQueue 正在运行。)然而这种方法并不安全。所需要的只是团队成员将来将任务分派(dispatch)到其他地方。

但是,此信息的有用之处在于,您可以通过使用专用的操作队列(例如 2 个最大并发操作)并将所有后台工作放在此 DispatchQueue 上来限制下载任务使用的资源量。您的 CPU 很可能不会充分发挥其潜力并留下一些空间。

关于ios - 如何拥有高优先级线程进行音频处理,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57097561/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com