4

I'm developing a game that includes an audio multitrack player running in the background. When dealing with pausing all tracks and then resuming when the pause button is pressed, I've found no significant difficulty:

class AudioMultiTrack {

var tracks     : [AudioTrack]
var mixer      : AVAudioMixerNode
var pauseTime  : AVAudioTime?

var engine     = AVAudioEngine()
var volumes    = [Float]()

init(audioTracks: [AudioTrack]){
    tracks = audioTracks
    mixer = engine.mainMixerNode
}

func initialize() {
    for track in tracks {
        track.setUpTrack()
        engine.attach(track.audioPlayer)
        engine.connect(track.audioPlayer, to: mixer, format: track.format)
        track.scheduleFile()
    }

    do {
        try engine.start()
    } catch {
        fatalError("error starting engine")
    }
}

func play() {
    for track in tracks {
        track.audioPlayer.play(at: startTime())
    }
}

func pause() {
    pauseTime = tracks[0].audioPlayer.lastRenderTime

    for track in tracks {
        track.audioPlayer.pause()
    }

}

func unPause() {

    for track in tracks {
        track.scheduleFile()
        track.audioPlayer.play(at: pauseTime)
    }
}

func stop() {
    pauseTime = tracks[0].audioPlayer.lastRenderTime
    engine.stop()

    for track in tracks {
        engine.detach(track.audioPlayer)
    }

    engine.reset()
}

func startTime() ->AVAudioTime {
    let sampleRate = tracks[0].format.sampleRate
    let sampleTime = AVAudioFramePosition(sampleRate)

    return AVAudioTime(sampleTime: sampleTime, atRate: sampleRate)
}

When pause is pressed in the GameViewController:

func pausePressed() {
   audio.pause()
}

func continuePressed() {
   audio.unPause()
}

However, when dealing with interruptions or route changes in this manner:

    func handleInterruption(notification: NSNotification) {
    guard let info = notification.userInfo else { return }

    switch info[AVAudioSessionInterruptionTypeKey] as! Int {
    case 0:
        audio.unPause()
    case 1:
        audio.pause()
    default:
        break;
    }
}

The program crashes and I receive:

*** Terminating app due to uncaught exception 'com.apple.coreaudio.avfaudio', reason: 'required condition is false: _engine->IsRunning()'

So it looks like the audio engine is stopping, and I don't want to re-initalize the audio player for a number of reasons including setup time and continuity of game play...

I am correct in my assessment of the problem? If so, how can I keep the audio engine running through an interruption or route change?

derekFairholm
  • 285
  • 1
  • 14

1 Answers1

0

I don't think it is possible because you create a audio player per sound, it needs to be prepared, setup the hardware etc. When the sound has completed that setup will be removed and needs to be done again. I.e. it is probably not possible to keep the audio engine "running".

StackUnderflow
  • 2,403
  • 2
  • 21
  • 28