有一个音频应用程序,通过网络传输文件,一切正常工作,但只有一件事。要在后台自动播放下一个音轨,在调用CFReadStream之后(我可以在日志中看到)初始化AudioQueueStop,但是在应用程序进入前台之前,回调永远不会被调用(编辑:实际调用一次)。流的代码段:
//also tried main runloop just for test, no luck
CFReadStreamScheduleWithRunLoop(stream, CFRunLoopGetCurrent(), kCFRunLoopCommonModes);连线的事情是,应用程序在队列停止后是功能性的,流正在初始化,但是只有在前台模式下初始化流时,回调才会被正确地调用。下面是一段回调代码:
CFReadStreamSetClient(stream,
kCFStreamEventHasBytesAvailable | kCFStreamEventErrorOccurred | kCFStreamEventEndEncountered,
MyReadStreamCallBack,
&context);另一方面,当应用程序处于后台时调用回调,下一个跟踪不是自动触发,而是使用应用程序委托(具有相同的功能)。
我不完全理解这三种情况的区别,请帮帮忙。
编辑。
OSStatus status = AudioFileStreamOpen(self, MyAudioListener ...MyAudioListener回调被调用,而MyReadStreamCallBack只被称为一次。
编辑2
ReadStream回调最经常不被调用一次,一次是我所能看到的最大次数。
另一方面,这让我对正在发生的事情产生了误解,在上一个AudioQueue被停止之后,和下一个轨道是一个本地文件,然后打开另一个AudioQueue打开,它用AudioFileReadPackets读取文件,我不需要从后台唤醒应用程序就可以开始下一个轨道回放,因为在后台播放本身。
发布于 2012-01-23 06:02:58
给定批准的后台模式,音频队列将继续在后台运行。但是一旦停止,一个音频队列似乎不会在后台开始运行。其中一个回调可能只是使缓冲区处于最佳状态,这样队列就可以在被带到前台后立即启动。
我找到的唯一解决方案是,在后台时不要停止先前的音频队列,而是以某种方式将新的音频数据提供给运行中的旧音频队列,而不会在中间出现任何回调。
发布于 2012-01-25 01:31:43
当前的解决方案是添加一个后台作业,直到有一个数据来启动一个新队列(启动队列w/o数据会产生-50错误,我相信会挂起一个hw解码器)。
比方说,在彩带播放函数中,有类似于以下内容的openNetworkStream函数:
// ...whatever we need to be happy
// start the background job
UIDevice* device = [UIDevice currentDevice];
BOOL isBackgroundSupported = NO;
if ([device respondsToSelector:@selector(isMultitaskingSupported)])
isBackgroundSupported = device.multitaskingSupported;
if(isBackgroundSupported && waitForQueueToStartBackgroundTask == UIBackgroundTaskInvalid) {
waitForQueueToStartbackgroundTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{
[[UIApplication sharedApplication] endBackgroundTask:waitForQueueToStartBackgroundTask];
waitForQueueToStartBackgroundTask = UIBackgroundTaskInvalid;
}];
}
// Open the stream
if (!CFReadStreamOpen(stream)) {您应该有一个AudioQueueStart调用,对我来说,它是StreamEnqueueBuffer函数,用于处理下载的数据片段,因为缓冲区已经准备好播放或文件的末尾已经到达(AudioQueueEnqueueBuffer),这个函数也是AudioQueue的初始启动程序,因为我们需要填充缓冲区来启动它。我的解决方案是在启动队列时在这里结束初始化的已启动的后台作业:
OSStatus StreamEnqueueBuffer(AudioNetworkStreamer* aStreamer)
// wahtever you need to be happy with a filled buffer
if (!aStreamer->didStart) { // start the queue if it has not been started already
aStreamer->isBuffering = NO;
[aStreamer startQueue];
UIDevice* device = [UIDevice currentDevice];
BOOL isBackgroundSupported = NO;
if ([device respondsToSelector:@selector(isMultitaskingSupported)])
isBackgroundSupported = device.multitaskingSupported;
if(isBackgroundSupported && aStreamer->waitForQueueToStartBackgroundTask == UIBackgroundTaskInvalid) {
[[UIApplication sharedApplication] endBackgroundTask:aStreamer->waitForQueueToStartBackgroundTask];
aStreamer->waitForQueueToStartBackgroundTask = UIBackgroundTaskInvalid;
}
}
// nandle mutexes, flags ...https://stackoverflow.com/questions/8966623
复制相似问题