I am attempting to convert a MPMediaItem instance into a caf formatted audio file. I have been following the work of Chris Adamson and his post on From iPod Library to PCM Samples in Far Fewer Steps Than Were Previously Necessary
As I was digging around looking how to do this in swift I came across Abel Domingues github FileConverter.swift for doing just this in Swift.
I then set about converting to Swift 3 as an extension to protocol.
All went well until I try to run it it. It crashes on the assetWriterInput
object creation and seems to be related to the outputSettings
variable.
var outputSettings = [
AVFormatIDKey: kAudioFormatLinearPCM,
AVSampleRateKey: 44100,
AVNumberOfChannelsKey: 2,
AVChannelLayoutKey: NSData(bytes:&channelLayout, length:MemoryLayout<AudioChannelLayout>.size),
AVLinearPCMBitDepthKey: 16,
AVLinearPCMIsNonInterleaved: false,
AVLinearPCMIsFloatKey: false,
AVLinearPCMIsBigEndianKey: false
] as [String : Any]
// create an asset writer input
let assetWriterInput = AVAssetWriterInput(mediaType:AVMediaTypeAudio, outputSettings:outputSettings as NSDictionary as! [String : Any])
The error message I receive is the following:
-[_SwiftValue unsignedIntValue]: unrecognized selector sent to instance 0x1704407b0
2016-10-13 18:34:52.032784 Testie[3098:1535938] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_SwiftValue unsignedIntValue]: unrecognized selector sent to instance 0x1704407b0'
I have searched for examples of this, but must posts are in Objective-C and/or related to setting up the dictionary for video.
This is the documentation from the AVAssetWriterInput source related to audio:
For AVMediaTypeAudio the following keys are not currently supported in the outputSettings dictionary: AVEncoderAudioQualityKey and AVSampleRateConverterAudioQualityKey. When using this initializer, an audio settings dictionary must be fully specified, meaning that it must contain AVFormatIDKey, AVSampleRateKey, and AVNumberOfChannelsKey. If no other channel layout information is available, a value of 1 for AVNumberOfChannelsKey will result in mono output and a value of 2 will result in stereo output. If AVNumberOfChannelsKey specifies a channel count greater than 2, the dictionary must also specify a value for AVChannelLayoutKey. For kAudioFormatLinearPCM, all relevant AVLinearPCM*Key keys must be included, and for kAudioFormatAppleLossless, AVEncoderBitDepthHintKey keys must be included. See -initWithMediaType:outputSettings:sourceFormatHint: for a way to avoid having to specify a value for each of those keys.
So what in the dictionary is causing the error?
In Swift 3, kAudioFormatLinearPCM
is imported as UInt32
(aka AudioFormatID
), and Swift 3.0.0 cannot convert it to an appropriate type (NSNumber
in this case) when put in [String: Any]
.
Try this:
var outputSettings = [
AVFormatIDKey: UInt(kAudioFormatLinearPCM),
AVSampleRateKey: 44100,
AVNumberOfChannelsKey: 2,
AVChannelLayoutKey: NSData(bytes:&channelLayout, length:MemoryLayout<AudioChannelLayout>.size),
AVLinearPCMBitDepthKey: 16,
AVLinearPCMIsNonInterleaved: false,
AVLinearPCMIsFloatKey: false,
AVLinearPCMIsBigEndianKey: false
] as [String : Any]
Or wait till Xcode 8.1/Swift 3.0.1, which should fix your case.