iOS AudioSessionSetActive()阻塞主线程?

在我的iOS应用程序中,我试图实现“躲闪”:当我的应用程序播放一个简短的“命令式”声音时,任何背景音乐都应该降低音量。 播放完毕后,音量应该恢复到原来的值。

实施后,躲避基本上按预期工作。 但是,当我在audioPlayerDidFinishPlaying中调用AudioSessionSetActive(NO)时:为了结束回避,在此时发生的任何UI更新中都有一个小的停顿。 这涉及到自定义绘图,以及为前。 自动滚动文字等等。

现在,这是一个问题:

这是iOS6中的一个已知问题吗? 我在iPod / iOS5上运行相同的代码,我没有看到这种行为。 或者我错过了代码的东西? 也许你们中的一个已经遇到同样的问题,并find一个可行的解决scheme。

非常感谢您的支持,

戈茨

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { //... NSError *err = nil; [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryAmbient error:&err]; //... } - (void) playSound { // Enable ducking of music playing in the background (code taken from the Breadcrumb iOS Sample) UInt32 value = kAudioSessionCategory_MediaPlayback; AudioSessionSetProperty(kAudioSessionProperty_AudioCategory, sizeof(value), &value); // Required if using kAudioSessionCategory_MediaPlayback value = YES; AudioSessionSetProperty(kAudioSessionProperty_OverrideCategoryMixWithOthers, sizeof(value), &value); UInt32 isOtherAudioPlaying = 0; UInt32 size = sizeof(isOtherAudioPlaying); AudioSessionGetProperty(kAudioSessionProperty_OtherAudioIsPlaying, &size, &isOtherAudioPlaying); if (isOtherAudioPlaying) {  AudioSessionSetProperty(kAudioSessionProperty_OtherMixableAudioShouldDuck, sizeof(value), &value); } AudioSessionSetActive(YES); // Initialization of the AVAudioPlayer NSString *soundFileName = [[NSBundle mainBundle] pathForResource:@"Beep" ofType:@"caf"]; NSURL    *soundFileURL = [[NSURL alloc] initFileURLWithPath:soundFileURL]; self.soundPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:soundFileURL error:nil]; [self.soundPlayer setDelegate:self]; [self.soundPlayer setVolume:[80.0/100.0]; [self.soundPlayer play]; } - (void) audioPlayerDidFinishPlaying:(AVAudioPlayer *)player successfully:(BOOL)flag { // Callback coming from the AVAudioPlayer // This will block the main thread; however, it is necessary to disable ducking again AudioSessionSetActive(NO);    } 

经过一番头脑的搔痒和debugging,我find了这个问题的答案。 正如原来的问题所述,为了在回避后恢复audio电平,您必须closuresaudio会话。

问题是,停用会话导致.5秒的延迟audio播放时,这阻止了UI线程,并导致应用程序无响应(在我的情况下,一个计时器松了0.5秒和口吃)。

为了解决这个问题,我让我的电话去激活一个单独的线程上的计时器。 这解决了UI阻塞问题,并允许audio鸭预期。 下面的代码显示了解决scheme。 请注意,这是C#代码,因为我使用的是Xamarin,但可以很容易地将它转换为Objective-C或Swift以获得相同的结果:

  private void ActivateAudioSession() { var session = AVAudioSession.SharedInstance(); session.SetCategory(AVAudioSessionCategory.Playback, AVAudioSessionCategoryOptions.DuckOthers); session.SetActive(true); } private void DeactivateAudioSession() { new System.Threading.Thread(new System.Threading.ThreadStart(() => { var session = AVAudioSession.SharedInstance(); session.SetActive(false); })).Start(); } 

在连接AVAudioPlayer之前,我打电话给ActivateAudioSession,一旦我的播放器完成播放,我就调用DeactivateAudioSession(这是恢复audio电平所必需的)。 在新的线程上启动停用会使audio电平恢复,但不会阻止用户界面。