AVAudioPlayer is no playing anything

853 Views Asked by At

I have a tableViewCell and i want to play a sound typically .m4a inside it. I have Globally declared my AVAudioPlayer instance like this:

var player = AVAudioPlayer()

Then I download my sound, put it in a directory in Documents. But, when i try to play my sound file from the directory i get this error:

Open failed
The operation couldn’t be completed. (OSStatus error 2003334207.)

This is my code I don't you what is wrong. and I tracked down the files in the simulator I could play them with QuickTimePlayer.

func downloadSound(_ message: ChatVoiceMessageStructure) {
    guard let url = service?.networkManager.CDNURL else { return }
    let doanloadURL = URL(string: url.appending(message.name!))
    let docUrl:URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL!
    let desURL = docUrl.appendingPathComponent("tmpsong.m4a")
    var downloadTask:URLSessionDownloadTask
    let request = URLRequest(url: doanloadURL!)
    downloadTask = URLSession.shared.downloadTask(with: request, completionHandler: { [weak self](URLData, response, error) -> Void in
        do{
            let isFileFound:Bool? = FileManager.default.fileExists(atPath: desURL.path)
            if isFileFound == true{
                print(desURL) //delete tmpsong.m4a & copy
            } else {
                try FileManager.default.copyItem(at: URLData!, to: desURL)
            }
            let sPlayer = try AVAudioPlayer(contentsOf: desURL)
            self?.player = sPlayer
            self?.player.prepareToPlay()
            self?.player.play()

        } catch let err {
            print(err.localizedDescription)
        }

    })
    downloadTask.resume()

}
2

There are 2 best solutions below

0
On BEST ANSWER

I finally figured out the problem thanks to MAhipal. The problem was that AVAudioPlayer can't play some sort of audio formats. like when the audio extension is MPEG4 but the audio coding is not AAC. So pay attention to the formats that the AVAudioPlayer supports. you can find these in CoreAudio Class, sub classes of AudioFormatID. This took me weeks to solve hope that it saves the other some time. if you want to play other types you can use AVPlayer

These are the types for future references:

public var kAudioFormatLinearPCM: AudioFormatID { get }
public var kAudioFormatAC3: AudioFormatID { get }
public var kAudioFormat60958AC3: AudioFormatID { get }
public var kAudioFormatAppleIMA4: AudioFormatID { get }
public var kAudioFormatMPEG4AAC: AudioFormatID { get }
public var kAudioFormatMPEG4CELP: AudioFormatID { get }
public var kAudioFormatMPEG4HVXC: AudioFormatID { get }
public var kAudioFormatMPEG4TwinVQ: AudioFormatID { get }
public var kAudioFormatMACE3: AudioFormatID { get }
public var kAudioFormatMACE6: AudioFormatID { get }
public var kAudioFormatULaw: AudioFormatID { get }
public var kAudioFormatALaw: AudioFormatID { get }
public var kAudioFormatQDesign: AudioFormatID { get }
public var kAudioFormatQDesign2: AudioFormatID { get }
public var kAudioFormatQUALCOMM: AudioFormatID { get }
public var kAudioFormatMPEGLayer1: AudioFormatID { get }
public var kAudioFormatMPEGLayer2: AudioFormatID { get }
public var kAudioFormatMPEGLayer3: AudioFormatID { get }
public var kAudioFormatTimeCode: AudioFormatID { get }
public var kAudioFormatMIDIStream: AudioFormatID { get }
public var kAudioFormatParameterValueStream: AudioFormatID { get }
public var kAudioFormatAppleLossless: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_HE: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_LD: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_ELD: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_ELD_SBR: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_ELD_V2: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_HE_V2: AudioFormatID { get }
public var kAudioFormatMPEG4AAC_Spatial: AudioFormatID { get }
public var kAudioFormatAMR: AudioFormatID { get }
public var kAudioFormatAMR_WB: AudioFormatID { get }
public var kAudioFormatAudible: AudioFormatID { get }
public var kAudioFormatiLBC: AudioFormatID { get }
public var kAudioFormatDVIIntelIMA: AudioFormatID { get }
public var kAudioFormatMicrosoftGSM: AudioFormatID { get }
public var kAudioFormatAES3: AudioFormatID { get }
public var kAudioFormatEnhancedAC3: AudioFormatID { get }
public var kAudioFormatFLAC: AudioFormatID { get }
public var kAudioFormatOpus: AudioFormatID { get }
4
On

please run on Real Device & Add DispatchQueue.main.async in URLSession block.

Here i tried your code with bit of change and its working on real device...

var audioPlayer:AVAudioPlayer!
    func downloadSound() {
        let doanloadURL = URL(string: "https://github.com/robovm/apple-ios-samples/raw/master/avTouch/sample.m4a")!
        let docUrl:URL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
        let desURL = docUrl.appendingPathComponent("sample.m4a")
        var downloadTask:URLSessionDownloadTask
        let request = URLRequest(url: doanloadURL)
        downloadTask = URLSession.shared.downloadTask(with: request, completionHandler: { (URLData, response, error) -> Void in
            DispatchQueue.main.async {
                do{
                    let isFileFound:Bool? = FileManager.default.fileExists(atPath: desURL.path)
                    if isFileFound == true{
                        print(desURL) //delete tmpsong.m4a & copy
                    } else {
                        try FileManager.default.copyItem(at: URLData!, to: desURL)
                    }
                     let sPlayer = try AVAudioPlayer(contentsOf: desURL)
                    try AVAudioSession.sharedInstance().setCategory(.playback, mode: .default)
                    try AVAudioSession.sharedInstance().setActive(true)
                    self.audioPlayer = sPlayer
                    self.audioPlayer.prepareToPlay()
                    self.audioPlayer.play()
                  } catch let err {
                    print(err.localizedDescription)
                }
            }
         })
        downloadTask.resume()
     }