使用 AVAudioEngine 恢复播放时应用程序挂起

问题描述 投票:0回答:1

我在下面附上了一个完全可用的 SwiftUI 应用程序。例如,当我在后台播放 Apple Music 并转到应用程序并按下播放按钮时,我注意到每次都有大约 700 到 800 毫秒的挂起时间。没有收到 Apple 对此的答复。

我希望该应用程序能够接管其他应用程序的音乐。我不希望该应用程序的音频与其他应用程序混合。

struct ContentView: View {
    @EnvironmentObject var contentViewModel: ContentViewModel
    
    var body: some View {
        Button {
            AudioManager.shared.play()
        } label: {
            Image(systemName: contentViewModel.isPlaying ? "pause.fill" : "play.fill")
                .font(.title)
                .foregroundStyle(.white)
        }
    }
}

class ContentViewModel: ObservableObject {
    @Published var isPlaying = false
}

class AudioManager {
    static let shared = AudioManager()
    private let audioEngine = AVAudioEngine()
    private let playerNode = AVAudioPlayerNode()
    
    let contentViewModel = ContentViewModel()
    
    init() {
        startAudioSession()
        setupAudioEngine()
        setupNotifications()
    }
    
    func startAudioSession() {
        let session = AVAudioSession.sharedInstance()
        
        do {
            try session.setCategory(.playback)
            try session.setActive(true)
        } catch {
            print("Failed to start Audio Session: \(error.localizedDescription)")
        }
    }
    
    func setupAudioEngine() {
        ///Pass in a music file to the url here
        let url = Bundle.main.url(forResource: "Your song goes here", withExtension: "mp3")!
        
        do {
            let audioFile = try AVAudioFile(forReading: url)
            
            audioEngine.attach(playerNode)
            audioEngine.connect(playerNode, to: audioEngine.mainMixerNode, format: audioFile.processingFormat)
            
            playerNode.scheduleFile(audioFile, at: nil, completionCallbackType: .dataPlayedBack) {_ in
                print("Song finished playing")
            }
        } catch let error {
            print(error.localizedDescription)
        }
    }
    
    func play() {
        if playerNode.isPlaying {
            playerNode.pause()
            audioEngine.pause()
            contentViewModel.isPlaying = false
        } else {
            do {
                try audioEngine.start()
                playerNode.play()
                contentViewModel.isPlaying = true
            } catch {
                print(error.localizedDescription)
            }
        }
    }
    
    //Handling interruptions
    func setupNotifications() {
        let nc = NotificationCenter.default
        nc.addObserver(self,
                       selector: #selector(handleInterruption),
                       name: AVAudioSession.interruptionNotification,
                       object: AVAudioSession.sharedInstance())
    }


    @objc func handleInterruption(notification: Notification) {
        guard let userInfo = notification.userInfo,
                let typeValue = userInfo[AVAudioSessionInterruptionTypeKey] as? UInt,
                let type = AVAudioSession.InterruptionType(rawValue: typeValue) else {
                    return
            }


            // Switch over the interruption type.
            switch type {


            case .began:
                // An interruption began. Update the UI as necessary.
                print("Interruption Began")
                play()
            case .ended:
               // An interruption ended. Resume playback, if appropriate.
                guard let optionsValue = userInfo[AVAudioSessionInterruptionOptionKey] as? UInt else { return }
                let options = AVAudioSession.InterruptionOptions(rawValue: optionsValue)
                if options.contains(.shouldResume) {
                    // An interruption ended. Resume playback.
                    play()
                } else {
                    // An interruption ended. Don't resume playback.
                }
            default: ()
            }
    }
}
swift swiftui avkit
1个回答
0
投票

我没有得到您的确切要求,但是,以下可以提高您的代码的性能。 AudioManager 的共享对象仅在您按下播放按钮时初始化。尝试在onAppear中初始化它并调用audioEngine.prepare().

extension AudioManager {
    
    func prepareAudioEngine() {
        audioEngine.prepare()
    }
}

onAppear

中调用该函数
.onAppear(perform: {
     AudioManager.shared.prepareAudioEngine()
 })
© www.soinside.com 2019 - 2024. All rights reserved.