尝试确定核心音频与 iPhone 后台执行的问题
我商店里有一个音频应用程序。它可以在 iOS 4.0 之前的 iPhone 操作系统版本上正常运行。我正在开发一个新版本,首先使该应用程序符合新的 iOS 多任务处理功能。 (我的 iPhone 上安装的是 iOS 4.0,并且已升级到最新的 xCode 和 SDK。)
结果令人惊叹。
o 当我在 iPhone 上安装应用程序并在调试器中运行时,或者在 iPhone 断电后启动应用程序时,应用程序运行得很好 - 在我按下按钮时播放音频,或者从保存的“状态”重新启动音频上次运行该应用程序时。
o 如果我尝试按“主页”按钮,然后从后台重新启动应用程序,音频(a 和 1-n 音频流的混合)会发出只有我能识别的结巴声。
o 如果在音频清晰的情况下呼叫 iPhone,我可以接听或拒绝呼叫。在这两种情况下,应用程序都会干净地返回,并按其应有的方式播放。
请注意,我并没有尝试在后台模式下播放任何内容。我只是想关闭所有东西并在需要时将它们恢复。
技术:所有音频逻辑都使用RemoteIO。 (我计划有一天进行一些相当复杂的信号处理。)
请原谅伪代码叙述 - 一些真正的代码非常广泛。
MainViewController:
o viewDidLoad - 没什么特别的
o didBecomeActive 将自己设置为音频会话委托; 将 AudioSessionCategory 设置为 MediaPlayback; 设置音频会话活动; 创建一个播放器(见下文); 重新启动之前播放的所有声音;
o 将辞职活跃 保存正在播放的状态; 停止所有声音; 停止玩家; 将音频会话设置为非活动状态;
o didEnterBackground - 无(方法已注册,但无内容。)
o willEnterForeground - 无(方法已注册,但无内容。)
Player 概述 - 我的类: Player 是一个单例。我确保单例实例被销毁,并在 didBecomeActive 中创建一个新实例。实例化单例实际上启动了 AudioUnit。
构造函数 设置远程IO; 开始 音频输出单元开始; 停止 音频输出单元停止; 玩家回调 平常的东西;
<块引用>>
以下是我的 MainViewController 中的一些方法:
(void)willResignActive:(NSNotification *)note {
[ self saveState ];
[ [ NaturePlayer getInstance ] stopAllSounds ];
[ [ NaturePlayer getInstance ] stop ];
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: NO error: &activationError];
[NaturePlayer destroy];
}
- (void)didBecomeActive:(NSNotification *)note {
[ self setupAudioSession ];
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
[ self restartSounds ];
[ self setViewState ];
}
- (void)didEnterBackground:(NSNotification *)note {
int xxx = 1;
}
- (void)willEnterForeground:(NSNotification *)note {
int xxx = 1;
}
- (void) applicationWillTerminate: (NSNotification*) notification {
int xxx = 1;
}
这是 NaturePlayer 中的一个方法:
/**
* Stop the playback process.
*/
void NaturePlayerDelegate::stop() {
if (isPlaying_) {
AudioOutputUnitStop(outputUnit_);
isPlaying_ = FALSE ;
}
}
我检查过:正在调用 stop(),然后调用 AudioOutputUnitStop(); 还检查了:AudioOutputUnitStop 上的文档表示它会阻塞,直到所有活动完成为止。
I have an audio app in the store. It works fine with versions of the iPhone OS before iOS 4.0. I am working on a new version, starting by bringing the app into compliance with the new iOS multitasking capabilities. (I have iOS 4.0 on my iPhone, and have upgraded to the latest xCode and SDK.)
The result has been a show-stopper.
o When I install the app on the iPhone and run in the debugger, or start the app after the iPhone was powered down, the app acts just fine - playing audio as I push buttons, or restarting audio from "state" that was saved the previous time the app was run.
o If I try to push the Home button and then restart the app from the background, the audio - a and mix of 1-n audio streams - comes out with a stuttering sound that only I could recognize.
o If - while the audio is cleanly - I call the iPhone, I can either answer or decline the call. In both cases the app comes back cleanly, playing as it should.
Note that I am not trying to play anything while in background mode. I simply want to shut things off and bring them back when asked.
Technology: All of the audio logic uses RemoteIO. (I have plans for someday doing some fairly sophisticated signal processing.)
Please excuse the pseudo code narrative - some of the real code is pretty extensive.
MainViewController:
o viewDidLoad - nothing special
o didBecomeActive
set self as audio session delegate;
set the AudioSessionCategory to MediaPlayback;
set the AudioSessionActive;
create a Player (see below);
restart any sounds that were previously playing;
o willResignActive
save the state of what was playing;
stopAllSounds;
stop the player;
set the audio session inactive;
o didEnterBackground - nothing (method is registered, but no content.)
o willEnterForeground - nothing (method is registered, but no content.)
Overview of Player - my class:
The Player is a singleton. I make sure that the singleton instance is destroyed, and a new one created, in didBecomeActive. Instantiating the singleton actually starts the AudioUnit.
constructor
setupRemoteIO;
start
AudioOutputUnitStart;
stop
AudioOutputUnitStop;
player callback
the usual stuff;
>
Here are some methods from my MainViewController:
(void)willResignActive:(NSNotification *)note {
[ self saveState ];
[ [ NaturePlayer getInstance ] stopAllSounds ];
[ [ NaturePlayer getInstance ] stop ];
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: NO error: &activationError];
[NaturePlayer destroy];
}
- (void)didBecomeActive:(NSNotification *)note {
[ self setupAudioSession ];
NSError *activationError = nil;
[[AVAudioSession sharedInstance] setActive: YES error: &activationError];
[ self restartSounds ];
[ self setViewState ];
}
- (void)didEnterBackground:(NSNotification *)note {
int xxx = 1;
}
- (void)willEnterForeground:(NSNotification *)note {
int xxx = 1;
}
- (void) applicationWillTerminate: (NSNotification*) notification {
int xxx = 1;
}
Here is a method from the NaturePlayer:
/**
* Stop the playback process.
*/
void NaturePlayerDelegate::stop() {
if (isPlaying_) {
AudioOutputUnitStop(outputUnit_);
isPlaying_ = FALSE ;
}
}
I checked: stop() is being called, and in turn calls AudioOutputUnitStop();
Also checked: The doc on AudioOutputUnitStop says it blocks until all activity has completed.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果没有更多关于音频代码的细节,很难说。但我建议您可能需要检查 Player 对象拆卸代码,以确保在释放内容之前音频单元和音频会话完全停止(缓冲区回调线程耗尽)。
Hard to say without more details on the audio code. But I suggest you might want to examine your Player object teardown code to make sure the audio unit and the audio session are completely stopped (buffer callback thread drained) before releasing stuff.
您是否在代码中初始化和取消初始化 AudioUnit?我最近发现一个问题,即创建和销毁 AudioUnit,然后离开并返回到您的应用程序会导致卡顿。
我能够通过从不取消初始化 AudioUnits 来在我的应用程序中修复此问题。
有关我的问题和 AudioUnit 代码的更多信息。
Are you initializing and un-initializing AudioUnits within your code? I have recently found an issue that AudioUnits being created and destroyed then leaving and returning to your App will cause stuttering.
I was able to fix this in my application by never uninitializing the AudioUnits.
More info on my problem and my AudioUnit code.
我在我的一个项目中遇到了同样的问题。我发现,如果我在挂起应用程序之前通过单击按钮调用 AudioOutputUnitStop(),然后在应用程序恢复时调用 AudioOutputUnitStart(),则没有问题。但是,如果我从 viewDidUnload 处理程序自动调用 AudioOutputUnitStop() 或作为对 UIApplicationWillResignActiveNotification 的响应,我就会听到上面描述的口吃、类似反馈的声音。
我还注意到,如果我手动停止音频单元,然后暂停应用程序,则会调用中断侦听器。但是,如果我在音频单元仍在运行时暂停应用程序,则不会调用中断侦听器。中断监听器应该停止音频单元,所以这对我没有多大好处。
经过几个小时的跟踪后,我找到了一种无需音频单元即可完成任务的方法,并将它们从我的应用程序中取出。所以恐怕我没有完整的答案。但希望这些线索能对某人有所帮助。将来我可能需要再次执行此操作,因此我会回来查看其他人是否已经解决了这个问题。
I had the same problem in a project of mine. I found that if I called AudioOutputUnitStop() from a button click before suspending the app, then called AudioOutputUnitStart() when the app resumed, I had no problems. But if I called AudioOutputUnitStop() automatically from the viewDidUnload handler or as a response to the UIApplicationWillResignActiveNotification, I had the stuttering, feedback-like sound described above.
I also noticed that if I stopped the audio unit manually, then suspended the app, the interruption listener was called. But if I suspended the app while the audio unit was still running, the interruption listener was not called. The interruption listener is supposed to stop the audio unit, so that's not doing me much good.
After several hours of tracing this, I found a way to finish my task without audio units, and took them out of my app. So I'm afraid I don't have a complete answer. But hopefully these clues will help someone. I may need to do this again in the future, so I'll check back here to see if someone else has figured it out.