iOS AudioSessionSetActive()阻塞主线程? [英] iOS AudioSessionSetActive() blocking main thread?

查看:1581
本文介绍了iOS AudioSessionSetActive()阻塞主线程?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

in my iOS app, I'm trying to implement "ducking": while my app plays a short "command-like" sound, any background music should be lowered in volume. Having finished playing the sound, the music volume should go back to its original value.

实施后,闪避基本上按预期工作。但是,当我在audioPlayerDidFinishPlaying中调用AudioSessionSetActive(NO)时:为了结束闪避,此时发生的任何UI更新都会暂停一小段时间。这包括自定义绘图,以及前者。自动滚动文本等等。

As implemented, ducking basically works as expected. However, when I call AudioSessionSetActive(NO) in audioPlayerDidFinishPlaying: in order to end ducking, there is a small pause in any UI updates that occur at this point of time. This involves custom drawing, as well as for ex. automatic scrolling of text and so on.

现在,问题是:

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

Is this a known problem in iOS6? I'm running the same code on an iPod / iOS5, where I do not see this behavior. Or am I missing something from the code? Maybe one of you already came across the same problem and found a workable solution.

非常感谢您的支持,

Goetz

- (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);     
}


推荐答案

经过一番搔痒,调试,我找到了这个问题的答案。正如原始问题所述,为了在闪避后恢复音频电平,您必须停用音频会话。

After some head scratching, and debugging, I found the answer to this question. As the original question states, in order to bring the audio level back up after ducking, you must deactivate the audio session.

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

The problem is that deactivating the session causes .5 second delay when audio is playing, which blocks the UI thread and causes the application to go unresponsive (in my case, a timer looses .5 seconds and stutters).

为解决此问题,我打电话在另一个线程上停用计时器。这解决了UI阻塞问题,并允许音频按预期显示。下面的代码显示了解决方案。注意,这是C#代码,因为我正在使用Xamarin,但它可以很容易地转换为Objective-C或Swift以获得相同的结果:

To resolve the issue, I make my call to deactivate the timer on a separate thread. This resolves the UI blocking issue and allows the audio to duck as expected. The code below shows the solution. Note, this is C# code because I'm using Xamarin, but it could easily be translated to Objective-C or Swift for the same result:

        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(这是恢复音频电平所必需的)。在新线程上启动取消激活会使音频级别恢复,但不会阻止UI。

I call ActivateAudioSession before I wire up my AVAudioPlayer and once my player is done playing, I call DeactivateAudioSession (which is necessary to bring the audio level back up). Starting the deactivation on a new thread ducks the audio level back up, but does not block the UI.

这篇关于iOS AudioSessionSetActive()阻塞主线程?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆