AVAudioEngine playing audio on simulator - but not on physical Apple Watch

48 Views Asked by At

Given a class that plays a file named "WoodClaves.aif" repeatedly based on a given BPM value.

import Foundation
import SwiftUI
import AVFoundation

class MetronomTimerModel: ObservableObject {

    var bpm: Double = 120  // Default BPM
    @Published var beatCounterIndex = 0
    
    var metronomeTimer: Timer?
    
    var audioPlayerNode:AVAudioPlayerNode
    var audioFile:AVAudioFile
    var audioEngine:AVAudioEngine

    init() {
        audioFile = try! AVAudioFile(forReading: Bundle.main.url(forResource: "WoodClaves", withExtension: "aif")!)
         
         audioPlayerNode = AVAudioPlayerNode()
         
         audioEngine = AVAudioEngine()
         audioEngine.attach(self.audioPlayerNode)
         
         audioEngine.connect(audioPlayerNode, to: audioEngine.mainMixerNode, format: audioFile.processingFormat)
        
        do {
            try AVAudioSession.sharedInstance().setCategory(.playback)
        } catch let error {
            print(error.localizedDescription)
        }
        
        

         try! audioEngine.start()
    }

    func startMetronome() {
        
        self.bpm = Double(UserDefaults.standard.integer(forKey: "bpm"))

           let interval = 60.0 / bpm

           metronomeTimer = Timer.scheduledTimer(withTimeInterval: interval, repeats: true) { timer in
               if self.beatCounterIndex == 0 {
                   self.playTick(bpm: Int(self.bpm))
               } else {
                   //...
               }
               // Increment the beatCounter and reset it after each 4 measure
               self.beatCounterIndex = (self.beatCounterIndex + 1) % 4
           }

        // Run the timer on the main run loop
                if let metronomeTimer = metronomeTimer {
                    RunLoop.main.add(metronomeTimer, forMode: .common)
                }
       }
    
    // Function to stop the metronome, invalidates timer and resets beat counter
        func stopMetronome() {
            //...
        }
    
    
    func playTick(bpm: Int) {
        do {
            
            let buffer = generateBuffer(forBpm: bpm)

            self.audioPlayerNode.play()

            self.audioPlayerNode.scheduleBuffer(buffer, at: nil, options: .loops, completionHandler: nil)
            
        } catch let error {
            print(error.localizedDescription)
        }
    }
    
    func stopTicking() {
        audioPlayerNode.stop()
    }
    
    func generateBuffer(forBpm bpm: Int) -> AVAudioPCMBuffer {
        audioFile.framePosition = 0
        let periodLength = AVAudioFrameCount(audioFile.processingFormat.sampleRate * 60 / Double(bpm))
        let buffer = AVAudioPCMBuffer(pcmFormat: audioFile.processingFormat, frameCapacity: periodLength)
        try! audioFile.read(into: buffer!)
        buffer?.frameLength = periodLength
        return buffer!
    }

}

This works fine as long as I run it in the simulator. However, when I run it on a physical device, there's no audio output nor any error.

Silent mode is turned off.

Buy the way, the same problems occurs if I utilize AVAudioPlayer.

What's wrong?

0

There are 0 best solutions below