iOS AudioSessionSetActive() blocking main thread?

后端 未结 2 844
走了就别回头了
走了就别回头了 2020-12-31 11:49

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 pla

相关标签:
2条回答
  • 2020-12-31 12:13

    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.

    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).

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

    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.

    0 讨论(0)
  • 2020-12-31 12:26

    A Swift 5 solution to this:

    // Create a background serial queue to call AVAudioPlayer.setActive() on
    queue = DispatchQueue(label: "backgroundAudio", qos: .userInitiated, attributes: [], autoreleaseFrequency: .inherit, target: nil)
    
    // ... sometime later, activate or deactivate the audio instance
    queue.async {
        do {
            try AVAudioSession.sharedInstance().setActive(false, options: [/* my options */])
        } catch {
            print("AVAudioSession.sharedInstance().setActive(false) failed: \(error)")
        }
    }
    
    
    0 讨论(0)
提交回复
热议问题