I'm currently reading Chris Adamson's "Learning Core Audio" and try to follow along in Swift 3 (instead of Objective-C ).
The first code example makes use of AudioTool
to gather information about an audio-file. My Swift 3 version looks like this:
import Foundation
import AudioToolbox
func main() {
let arguments = CommandLine.arguments
guard arguments.count > 1 else {
print("Usage: CAMetaData /full/path/to/audiofile")
return
}
// Get filepath out of cmd-arguments
let audiofilePath = NSString(string: arguments[1]).expandingTildeInPath
// Load audio file into appropriate data structure
let audioURL = NSURL(fileURLWithPath: audiofilePath)
var audiofile: AudioFileID? = nil
var possibleError = noErr
possibleError = AudioFileOpenURL(audioURL, AudioFilePermissions.readPermission, 0, &audiofile)
assert(possibleError == noErr)
// Get size of metadata dictionary
var outDataSize: UInt32 = 0
possibleError = AudioFileGetPropertyInfo(audiofile!, kAudioFilePropertyInfoDictionary, &outDataSize, nil)
assert(possibleError == noErr)
// Get metadata
var outDataPointer: UnsafePointer<CFDictionary>? = nil
possibleError = AudioFileGetProperty(audiofile!, kAudioFilePropertyInfoDictionary, &outDataSize, &outDataPointer)
assert(possibleError == noErr)
// How to use this outDataPointer?
let outData = outDataPointer!.pointee as NSDictionary
dump(outData)
// No CFRelease necessary - Swift takes care of that
// Close connection to audiofile
possibleError = AudioFileClose(audiofile!)
assert(possibleError == noErr)
}
main()
Everything seems to work great (all assertions/ AudioToolbox
-API call pass). Now I'm asking myself how I'm able to display the data stored inside the outDataPointer
.
This is how I understand the situation: outDataPointer
holds an optional with associated type UnsafePointer<CFDictionary>
. I'm able to verify that outDataPointer
is not nil
, therefore accessing the associated value won't crash my program. outDataPointer!.pointee
should give me the CFDictionary
pointed to by the associated value behind outDataPointer
. CFDictionary
is castable to NSDictionary
.
Sadly dumping the underlaying data prints
- __NSAtom #0
to the console. Quite not what I expected (information about the audiofile). How can I get this data out of my outDataPointer
variable?
Swift's CFDictionary
isn't itself a data structure; it's a pointer to a data structure, and it is equivalent to Objective-C's CFDictionaryRef
. In other words, it behaves like a Swift class
, not a struct
.
The value written into outDataPointer
is not a pointer to a CFDictionary
; it is a CFDictionary
. You're dereferencing it one too many times, causing the data stored in the dictionary to be treated as a pointer to a dictionary. On my system, the resulting memory address was 0x001dffffc892e2f1
, which Objective-C treats as a tagged pointer , resulting in the NSAtom
message.
To fix the problem, declare outDataPointer
as a CFDictionary?
instead of an UnsafePointer<CFDictionary>?
:
// Get metadata
var outDataPointer: CFDictionary? = nil
possibleError = AudioFileGetProperty(audiofile!, kAudioFilePropertyInfoDictionary, &outDataSize, &outDataPointer)
assert(possibleError == noErr)
let outData = outDataPointer! as NSDictionary
dump(outData)
Output:
▿ 1 key/value pair #0
▿ (2 elements)
- .0: approximate duration in seconds #1
- super: __NSCFString
- super: NSMutableString
- super: NSString
- super: NSObject
- .1: 187.387 #2
- super: NSString
- super: NSObject
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.