2

At the moment I have two functions which are almost identical, but only one of them works and I can't figure out why.

The playSound() function works and uses the class's audioPlayer: AVAudioPlayer object to play one audio file at a time.

To make it so I could play multiple sounds simultaneously, I made a new function called playMySound() which creates its own instance of AVAudioPlayer instead of using the class's audioPlayer: AVAudioPlayer object.

The weird thing is, the sound plays fine when I call playSound(), but it doesn't play when I call playMySound().

Here's the code that works:

  var audioPlayer: AVAudioPlayer!
  override func viewDidLoad() {
      super.viewDidLoad()
      audioPlayer = AVAudioPlayer()

    }

  func playSound(audioFileName: String) {
    if let sound = NSDataAsset(name: audioFileName) {
      do {
        try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try! AVAudioSession.sharedInstance().setActive(true)

        try audioPlayer = AVAudioPlayer(data: sound.data)
        audioPlayer.delegate = self
        audioPlayer.play()

      } catch {
        print("Error playing sound: \(audioFileName)")
      }
    }

  }

And the code that doesn't work:

  func playMySound(audioFileName: String) {
    if let sound = NSDataAsset(name: audioFileName) {
      do {
        try! AVAudioSession.sharedInstance().setCategory(AVAudioSessionCategoryPlayback)
        try! AVAudioSession.sharedInstance().setActive(true)

        var myAudioPlayer: AVAudioPlayer = AVAudioPlayer()

        myAudioPlayer = try AVAudioPlayer(data: sound.data)
        myAudioPlayer.delegate = self

        // Calling prepareToPlay() doesn't seem to fix it
        // myAudioPlayer.prepareToPlay()

        print("Trying to play my audio player")
        myAudioPlayer.play()

      } catch {
        print("Error playing sound: \(audioFileName)")
      }
    }
  }

"Trying to play my audio player" gets outputted to the console, so it's definitely running through the function, but for some reason calling myAudioPlayer.play() doesn't seem to work.

Can anyone help? Thanks in advance!

rmaddy
  • 314,917
  • 42
  • 532
  • 579
DMeechan
  • 5,690
  • 1
  • 13
  • 15
  • You need to keep strong reference to the `AVAudioPlayer` while it its playing. `play()` method just triggers playing and returns immediately. So, your `playMySound` finishes as soon as the `AVAudioPlayer` start playing and releases the strong reference held in the local variable `myAudioPlayer`. By the way, `audioPlayer = AVAudioPlayer()` in your first code snippet and `var myAudioPlayer: AVAudioPlayer = AVAudioPlayer()` is not needed. (Append `let ` to the line next to `var myAudioPlayer...` instead.) Generally, you should not instantiate unused instances. – OOPer Aug 13 '17 at 16:15
  • Thanks for the tips @OOPer! If I make the reference to `AVAudioPlayer` strong, won't that create a build up of memory if new sounds keep getting created and old instances aren't removed? – DMeechan Aug 13 '17 at 16:22
  • If you care about memory, remove unnecessary `AVAudioPlayer()` first. It consumes memory for unused instance. The instance is soon deallocated, but allocation and deallocation needs cost. And keeping while playing is required for `AVAudioPlayer` to play sound. `AVAudioPlayer` loads sound data when you call `play()` first time, and that sound data needs to be kept while playing. You can release it when playing finished if you care about memory. – OOPer Aug 13 '17 at 16:29
  • Similar to [this thread](https://stackoverflow.com/q/38771258/6541007). (The line `audioPlayer = AVAudioPlayer()` in the accepted answer is not needed.) – OOPer Aug 13 '17 at 17:36

0 Answers0