ebg11
ebg11

Reputation: 1046

Casting in swift

So my swift skills arent great... I want to try and retrieve an audio track description for a video and have come up with this method. If anything fails the method should return null

   func getAudioTrackDescription(path: String) -> AudioStreamBasicDescription? {
        let asset = getAssetFromPath(path: path)
        guard let track = asset.tracks(withMediaType: AVMediaType.audio).first else {      
            return nil
        }
        
        
        guard let audioDesc = track.formatDescriptions.first else {
            return nil
        }
        
        // let casted = audioDesc as! CMAudioFormatDescription

        // THE SDF IS JUST AN EXAMPLE THAT CAUSES IT TO FAIL 
        // I ACTUALLY WANT TO USE THE COMMENTED LINE ABOVE
        if let casted = ("Sdf" as! CMAudioFormatDescription) {
            let basic = CMAudioFormatDescriptionGetStreamBasicDescription(casted)
            guard let pointee = basic?.pointee else {
                return nil
            }
            return pointee
        } else {
            return nil
        }
    }

I am really struggling to understand how the casting works in swift... The track.formatDescriptions list holds type Any which means it could crash if the type is not what i expect it to be (CMAudioFormatDescription)

For example I have changed the if audioDesc to be the string "Sdf" and the code crashes.

I want to be able to check if audioDesc can be casted to CMAudioFormatDescription and if cant i want to return nil.

I tried using as? and this always gives me this error

Conditional downcast to CoreFoundation type 'CMAudioFormatDescription' (aka 'CMFormatDescription') will always succeed

Can someone help?

---------------------- EDIT

is below a safe approach?

    func getVideoAudioChannelCount(path: String) -> Int {
        guard let audioFile = getAudioInformation(path: path) else {
               return DEFAULT_AUDIO_CHANNEL
        }
        return Int(audioFile.channelCount)
    }
    
    
    func getAudioInformation(path: String) -> AVAudioFormat? {
        var returnVar: AVAudioFormat?;
        do {
            returnVar = try AVAudioFile(forReading: URL(fileURLWithPath: path)).fileFormat
        } catch _ {
            returnVar = nil
        }
        return returnVar
    }

Upvotes: 1

Views: 241

Answers (1)

Sweeper
Sweeper

Reputation: 271625

According to the documentation, the array will always contain CMFormatDescription (aka CMAudioFormatDescription), so you can safely cast with as!.

The array contains CMFormatDescriptions (see CMFormatDescription), each of which indicates the format of media samples referenced by the track.

You get the error that conditional casts always succeed because CMAudioFormatDescription is a Core Foundation type (it conforms to _CFObject). For more info, see here.

Edit:

is below a safe approach?

Yes, if by "safe" you mean it won't crash. You can simplify the code if you use try?:

func getAudioInformation(path: String) -> AVAudioFormat? {
    try? AVAudioFile(forReading: URL(fileURLWithPath: path)).fileFormat
}

Upvotes: 2

Related Questions