我一直在尝试在IOS中找到适合我项目需求的线程实现。到目前为止,我找不到可接受的解决方案。
我的问题:
我需要同时从磁盘上读取多达16个mp3文件的音频。
我尝试过:
首先我尝试使用 NSTimer 女巫重复。计时器不够快,当我播放超过4个文件时,音频会丢失。
其次我尝试使用优先级为1的 NSThread 。音频播放正常但UI完全没有响应。
最后,当我需要来自文件的更多音频时,我尝试在回调中使用 GCD 调度块。音频会再次丢失,但UI会响应。
在上面的所有三个示例中,我还尝试通过创建4个线程并让每个线程处理4个音频文件来分担工作负载,但这会导致音频的同步问题非常糟糕。
我是否可以尝试或执行以上其他线程选项总结IOS提供的内容?
您是否认为同时从磁盘读取16个文件对IOS系统来说太过紧张?
IOS可以处理的线程数是否有限制?
为了避免让我的问题听起来像是一个讨论,我将总结如下。
什么IOS线程技术最适合非常频繁的调用,快速完成执行,可以轻松同步,不会影响UI响应。
任何解决类似音频编程问题的轶事建议也值得赞赏。
编辑1
这是一些精简代码,我根据用户的建议建模。所有我都在坚定地建议什么样的设置最适合我。自从我上一篇文章以来,我尝试了NSThread,它确实让我留下了音频丢失。此外,我尝试使用NSConditions,以便我的线程在其非填充缓冲区时浪费处理能力,但使用这些锁对于音频回调来说似乎是个坏主意。
OSStatus channelMixerCallback(void *inRefCon,
AudioUnitRenderActionFlags *ioActionFlags,
const AudioTimeStamp *inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList *ioData) {
AudioInfo = myaudio[inBusNumber];
if(myaudio.needsbufferfill==YES)
{
[refToSelf performSelector:@selector(GetAudioForItem:) onThread:engineDescribtion.producerthread withObject:myaudio waitUntilDone:false];
}
}
-(void) startthread
{
engineDescribtion.producerthread =[[NSThread alloc]initWithTarget:self selector:@selector(dosinglerunloop) object:nil];
[engineDescribtion.producerthread start];
}
-(void)dosinglerunloop
{
BOOL isstarted=YES;
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc]init];
do {
[[NSRunLoop currentRunLoop]addPort:[NSMachPort port] forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop]runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]];
} while (isstarted);
[pool release];
}
- (void)GetAudioForItem:(AudioInfo *)info
{
// use data in Audio Info to seek to
//corrent place in file
//and extract audio to buffers
}
答案 0 :(得分:1)
问题0:
您的音频渲染回调永远不应该锁定。示例:创建单个堆分配将锁定。
你的线程都将争夺硬件。为了保持UI响应,您不应该有许多最高优先级线程(音频播放应该是唯一的)。考虑您的设计中可用的核心数,磁盘数等。
如果您在正确修复后仍然遇到问题:将短文件加载到内存中可以将部分磁盘需求卸载到内存中。
您应该进行分析以确定实际问题:它可能是CPU 或 I / O.您可能只是错过了渲染截止日期,并将音频丢失等同于“读取速度不够快”。如果您使用大量CPU,那么磁盘I / O可能不是问题。对16个mp3文件进行解码和执行采样率转换可能需要相对较高的CPU(作为您需要查找的事物的一个示例)。
pthreads将最快,但需要一些工作才能正确实施。这在当时并不重要,因为似乎还有一些高级问题,并且有多个API可以正常处理任务。
你的程序应该足够聪明,以便检测读取缓冲区何时无法足够快地填充。
你正在填充缓冲区,对吗?
据推测,您正在使用运行循环?
答案 1 :(得分:0)
嗯,只有一个磁盘......所以任何需要16个同时读取的解决方案都可能是个问题。 (取决于您是否受I / O限制或CPU绑定。)
NSTimer不会为您提供一致的结果。
我没有看到NSThread会杀死UI响应的任何原因,也许你有一个错误。
答案 2 :(得分:0)
我正在使用这个系统受磁盘限制,因为在现代机器上,16个MP3通道在CPU方面没有问题 - 你的盒子会发出多少嘎嘎声?我可能只想使用一个线程来填充空缓冲区,其缓冲区大小可以容纳(averageDiskLatency *(bytes / msec)* 16 * bodgeFactor)字节的音频流,(bodgeFactor意味着舍入到8K边界并添加几个8K)。每当线程/回调/任何空的缓冲区开始在另一个缓冲区上启动时,它们应该将空缓冲区排队到磁盘读取线程(线程安全的生产者 - 消费者队列),以使其再次填满。可能每个缓冲区都应包含一个'fileControl'实例,其中包含fileSpec,文件句柄,EOF的状态变量等,错误字符串空间以及读取线程工作所需的任何其他内容以及缓冲区空间本身。
这种设计允许磁盘读取漂亮的大块,而不会在读取过程中被中途抢占,并且可以避免过于频繁地移动金属块。
RGDS, 马丁
PS - 如果你还没有,那么获得SSD - 可以为多声道音频/视频延迟创造奇迹。