Search code examples
swiftxcodefirebaseswiftuiavaudioplayer

Playing audio file from Firebase not working


I'm (unsuccessfully) trying to play an audio file stored in Firebase using AVAudioPlayer.

I'm getting the following error message: Error creating audio player: The operation couldn’t be completed. (OSStatus error 2003334207.)

Here's the code for my Audio Player View Model:

class AudioPlayerViewModel: ObservableObject {
    
    private var audioPlayer: AVAudioPlayer?
    
    func playAudioFromUrl(from storagePath: String) {
        let storage = Storage.storage()
        let storageRef = storage.reference()
        let audioRef = storageRef.child(storagePath)
        
        audioRef.downloadURL { url, error in
            print(audioRef)
            guard let audioURL = url, error == nil else {
                print("Error fetching audio URL: \(error?.localizedDescription ?? "")")
                return
            }
            
            print("Audio URL: \(audioURL)")
            print("Audio URL String: \(audioURL.absoluteString)")
            
            do {
                self.audioPlayer = try AVAudioPlayer(contentsOf: audioURL)
                self.audioPlayer?.prepareToPlay()
                self.audioPlayer?.play()
            } catch {
                print("Error creating audio player: \(error.localizedDescription)")
                if let nsError = error as NSError? {
                    print("Error code: \(nsError.code)")
                }
            }
        }
    }
    
    func stopAudio() {
        audioPlayer?.stop()
    }
}

And the code for my view:

struct PlaybackControlsView: View {
    
    var audioPath: String
    
    @ObservedObject private var audioPlayerVM = AudioPlayerViewModel()
    
    var body: some View {
        
        VStack {
            // Add UI elements here, e.g., play and stop buttons
            Button("Play Audio") {
                audioPlayerVM.playAudioFromUrl(from: "Stories/\(audioPath).mp3")
            }
            .padding()
            
            Button("Stop Audio") {
                audioPlayerVM.stopAudio()
            }
            .padding()
        }
    }
}

#Preview {
    PlaybackControlsView(audioPath: "example")
}

Not sure where I'm going wrong here. Any help would be greatly appreciated.


Solution

  • You could try this approach using AVPlayer with a url, instead of the AVAudioPlayer that seems to only play audio data from a file or buffer.

    class AudioPlayerViewModel2: ObservableObject {
        
        private var audioPlayer: AVPlayer?  // <-- here
        
        func playAudioFromUrl(from storagePath: String) {
            let storage = Storage.storage()
            let storageRef = storage.reference()
            let audioRef = storageRef.child(storagePath)
    
            audioRef.downloadURL { url, error in
                print(audioRef)
                guard let audioURL = url, error == nil else {
                    print("Error fetching audio URL: \(error?.localizedDescription ?? "")")
                    return
                }
    
                print("Audio URL: \(audioURL)")
                print("Audio URL String: \(audioURL.absoluteString)")
    
                // --- here
                let playerItem = AVPlayerItem(url: audioURL)
                self.audioPlayer = AVPlayer(playerItem: playerItem)
                self.audioPlayer?.volume = 10
                self.audioPlayer?.play()
            }
        }
        
        func stopAudio() {
            audioPlayer?.pause()
        }
    }