sh-khashimov / SwiftFortuneWheel

The ultimate spinning wheel view that supports dynamic content and rich customization.
MIT License
351 stars 82 forks source link

External audio stops right after fortune wheel initialization #24

Closed M-I-N closed 2 years ago

M-I-N commented 2 years ago

Navigating to a view controller that hosts a SwiftFortuneWheel stops any external audio that might have been being played within Music application.


https://github.com/sh-khashimov/SwiftFortuneWheel/blob/883669528b6249cf9f5c9edf91e9b581876f6e40/Sources/SwiftFortuneWheel/Utils/Audio/AudioPlayerManager.swift#L36

Commenting the init() of AudioPlayerManager seems to fix this problem. But this might have other consequences somewhere else.

Note: I also need the collision sound effect to be enabled.

sh-khashimov commented 2 years ago

I don't have a Macbook/iPad with me right now to check this out. Could you please try this on your viewDidLoad:

https://stackoverflow.com/questions/67350148/how-can-i-play-a-sound-in-swift-without-stopping-the-playing-music

M-I-N commented 2 years ago

try this on your viewDidLoad:

I already tried that but no luck.


It seems to me that AVAudioEngine works differently than the usual AVAudioPlayer.

sh-khashimov commented 2 years ago

They both use AVAudioSession.

Try to add it to AppDelegate to didFinishLaunchingWithOptions.

Try other options like here:

https://stackoverflow.com/questions/32198013/avaudioengine-stops-devices-background-audio

sh-khashimov commented 2 years ago

If it does not help, the only problem I see is that, after collisions and sounds stop, the wheel should notify others.

try AVAudioSession.sharedInstance().setActive(false, options: .notifyOthersOnDeactivation)

The reason for this is that other apps playing music in the background will know when to turn their audio back on when you deactivate yours. Otherwise, your background music won't turn back on.

If you cannot find the workaround, I will look into it in the coming days.

M-I-N commented 2 years ago

Well, the problem is not with resuming background music from Music app. The problem I wanted to focus is:

Whenever a view controller with SwiftFortuneWheel is opened, all the sounds from other sources stop even before the spinning of the wheel

If other sound would stop when the wheel spinning animation started, that wouldn't be a problem. It's the intended behaviour after all. The issue is, I just navigate to the wheel view controller and sound from other source stops immediately.


Then there is a crash 💥 as per following sequence:

  1. Navigate to a view controller with fortune wheel
  2. Play music from iPhone music player (preferably resuming playback from control centre)
  3. Tap the spin button of fortune wheel
  4. Boom 💥
M-I-N commented 2 years ago

I found a good relevant comment here: https://stackoverflow.com/a/55505717/3687801

If you're using AVAudioEngine, defer setting up the engine or connecting anything to the engine's mainMixerNode or outputNode until you actually need to start playing something.

M-I-N commented 2 years ago

@sh-khashimov Can you please check the PR? Would be nice if you can verify and merge.

sh-khashimov commented 2 years ago

Please be patient. I will check your merge as soon as will have time.

sh-khashimov commented 2 years ago

I don't have a Macbook/iPad with me right now to check this out. Could you please try this on your viewDidLoad:

https://stackoverflow.com/questions/67350148/how-can-i-play-a-sound-in-swift-without-stopping-the-playing-music

adding this code:


            do {
                try AVAudioSession.sharedInstance()
                    .setCategory(.playback, options: .duckOthers)
                try AVAudioSession.sharedInstance()
                    .setActive(true)
            } catch {
                print(error)
            }

to AppDelegate didFinishLaunchingWithOptions or to


    @IBOutlet weak var fortuneWheel: SwiftFortuneWheel! {
        didSet {
            do {
                try AVAudioSession.sharedInstance()
                    .setCategory(.playback, options: .duckOthers)
                try AVAudioSession.sharedInstance()
                    .setActive(true)
            } catch {
                print(error)
            }
        }
    }

Fix everything. However, the problem caused that instead of an engine.start() there should be an engine.prepare() method. Thank you for investigating the problem. I appreciate it. 🙏

M-I-N commented 2 years ago

Would you mind closing this issue?