cocoaconf chicago 2017: media frameworks and swift: this is fine
TRANSCRIPT
![Page 1: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/1.jpg)
Media Frameworks and Swift:
This is FineChris Adamson • @invalidname CocoaConf Chicago, April 2017
Slides available at slideshare.net/invalidname Code available at github.com/invalidstream
![Page 2: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/2.jpg)
Who the what, now?
@invalidname
![Page 3: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/3.jpg)
![Page 4: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/4.jpg)
![Page 5: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/5.jpg)
![Page 6: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/6.jpg)
![Page 7: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/7.jpg)
![Page 8: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/8.jpg)
![Page 9: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/9.jpg)
![Page 10: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/10.jpg)
![Page 11: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/11.jpg)
![Page 12: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/12.jpg)
![Page 13: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/13.jpg)
![Page 14: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/14.jpg)
![Page 15: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/15.jpg)
![Page 16: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/16.jpg)
import Cocoa import AVFoundation import CoreMediaIO
if let devices = AVCaptureDevice.devices(), let avDevices = devices.filter( {$0 is AVCaptureDevice}) as? [AVCaptureDevice] { for device in avDevices { print("\(device.description)") } }
![Page 17: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/17.jpg)
<AVCaptureHALDevice: 0x100b16ab0 [Loopback Simulator][com.rogueamoeba.Loopback:E8577B20-0806-4472-A5E6-426CABCD6C8E]> <AVCaptureHALDevice: 0x100c1a7c0 [Loopback Line-In][com.rogueamoeba.Loopback:A00F38FD-C2B6-43FD-98B7-23BAA6FACB03]> <AVCaptureHALDevice: 0x100c16910 [iMic USB audio system][AppleUSBAudioEngine:Griffin Technology, Inc:iMic USB audio system:220000:2,1]> <AVCaptureHALDevice: 0x100d13900 [Loopback Keynote][com.rogueamoeba.Loopback:1936D2A3-6D0B-428E-899E-0ABE46628EA4]> <AVCaptureHALDevice: 0x100a26850 [Soundflower (64ch)][SoundflowerEngine:1]> <AVCaptureHALDevice: 0x100a26310 [HD Pro Webcam C920][AppleUSBAudioEngine:Unknown Manufacturer:HD Pro Webcam C920:1218B05F:3]> <AVCaptureHALDevice: 0x100d13660 [Soundflower (2ch)][SoundflowerEngine:0]> <AVCaptureDALDevice: 0x100a348f0 [iGlasses][iGlasses]> <AVCaptureDALDevice: 0x100a28d00 [HD Pro Webcam C920][0x244000046d082d]> Program ended with exit code: 0
![Page 18: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/18.jpg)
![Page 19: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/19.jpg)
CMIOObjectPropertyAddress prop = { kCMIOHardwarePropertyAllowScreenCaptureDevices, kCMIOObjectPropertyScopeGlobal, kCMIOObjectPropertyElementMaster }; UInt32 allow = 1; CMIOObjectSetPropertyData( kCMIOObjectSystemObject, &prop, 0, NULL, sizeof(allow), &allow );
![Page 20: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/20.jpg)
var prop = CMIOObjectPropertyAddress( mSelector: CMIOObjectPropertySelector(
kCMIOHardwarePropertyAllowScreenCaptureDevices), mScope: CMIOObjectPropertyScope(kCMIOObjectPropertyScopeGlobal), mElement: CMIOObjectPropertyElement(
kCMIOObjectPropertyElementMaster)) var allow : UInt32 = 1 CMIOObjectSetPropertyData(CMIOObjectID(kCMIOObjectSystemObject), &prop, 0, nil, UInt32(MemoryLayout<UInt32>.size), &allow)
![Page 21: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/21.jpg)
CMIOObjectPropertyAddress prop = { kCMIOHardwarePropertyAllowScreenCaptureDevices, kCMIOObjectPropertyScopeGlobal, kCMIOObjectPropertyElementMaster }; UInt32 allow = 1; CMIOObjectSetPropertyData( kCMIOObjectSystemObject, &prop, 0, NULL, sizeof(allow), &allow );
var prop = CMIOObjectPropertyAddress( mSelector: CMIOObjectPropertySelector(
kCMIOHardwarePropertyAllowScreenCaptureDevices), mScope: CMIOObjectPropertyScope(kCMIOObjectPropertyScopeGlobal), mElement: CMIOObjectPropertyElement(
kCMIOObjectPropertyElementMaster)) var allow : UInt32 = 1 CMIOObjectSetPropertyData(CMIOObjectID(kCMIOObjectSystemObject), &prop, 0, nil, UInt32(MemoryLayout<UInt32>.size), &allow)
![Page 22: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/22.jpg)
CMIOObjectPropertyAddress prop = { kCMIOHardwarePropertyAllowScreenCaptureDevices, kCMIOObjectPropertyScopeGlobal, kCMIOObjectPropertyElementMaster }; UInt32 allow = 1; CMIOObjectSetPropertyData( kCMIOObjectSystemObject, &prop, 0, NULL, sizeof(allow), &allow );
var prop = CMIOObjectPropertyAddress( mSelector: CMIOObjectPropertySelector(
kCMIOHardwarePropertyAllowScreenCaptureDevices), mScope: CMIOObjectPropertyScope(kCMIOObjectPropertyScopeGlobal), mElement: CMIOObjectPropertyElement(
kCMIOObjectPropertyElementMaster)) var allow : UInt32 = 1 CMIOObjectSetPropertyData(CMIOObjectID(kCMIOObjectSystemObject), &prop, 0, nil, UInt32(MemoryLayout<UInt32>.size), &allow)
This is
fine
![Page 23: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/23.jpg)
CMIOObjectPropertyAddress prop = { kCMIOHardwarePropertyAllowScreenCaptureDevices, kCMIOObjectPropertyScopeGlobal, kCMIOObjectPropertyElementMaster }; UInt32 allow = 1; CMIOObjectSetPropertyData( kCMIOObjectSystemObject, &prop, 0, NULL, sizeof(allow), &allow );
var prop = CMIOObjectPropertyAddress( mSelector: CMIOObjectPropertySelector(
kCMIOHardwarePropertyAllowScreenCaptureDevices), mScope: CMIOObjectPropertyScope(kCMIOObjectPropertyScopeGlobal), mElement: CMIOObjectPropertyElement(
kCMIOObjectPropertyElementMaster)) var allow : UInt32 = 1 CMIOObjectSetPropertyData(CMIOObjectID(kCMIOObjectSystemObject), &prop, 0, nil, UInt32(MemoryLayout<UInt32>.size), &allow)
This is
fine
![Page 24: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/24.jpg)
![Page 25: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/25.jpg)
var prop = CMIOObjectPropertyAddress( mSelector: CMIOObjectPropertySelector(
kCMIOHardwarePropertyAllowScreenCaptureDevices), mScope: CMIOObjectPropertyScope(
kCMIOObjectPropertyScopeGlobal), mElement: CMIOObjectPropertyElement(
kCMIOObjectPropertyElementMaster))
![Page 26: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/26.jpg)
var prop = CMIOObjectPropertyAddress( mSelector: CMIOObjectPropertySelector(
kCMIOHardwarePropertyAllowScreenCaptureDevices), mScope: CMIOObjectPropertyScope(
kCMIOObjectPropertyScopeGlobal), mElement: CMIOObjectPropertyElement(
kCMIOObjectPropertyElementMaster))
![Page 27: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/27.jpg)
![Page 28: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/28.jpg)
![Page 29: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/29.jpg)
public typealias CMIOObjectPropertySelector = UInt32
public typealias CMIOObjectPropertyScope = UInt32
public typealias CMIOObjectPropertyElement = UInt32
public struct CMIOObjectPropertyAddress { public var mSelector: CMIOObjectPropertySelector
public var mScope: CMIOObjectPropertyScope
public var mElement: CMIOObjectPropertyElement
public init()
public init(mSelector: CMIOObjectPropertySelector, mScope: CMIOObjectPropertyScope, mElement: CMIOObjectPropertyElement)
}
![Page 30: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/30.jpg)
extension CMIOObjectPropertySelector { static let allowScreenCaptureDevices = CMIOObjectPropertySelector( kCMIOHardwarePropertyAllowScreenCaptureDevices) }
extension CMIOObjectPropertyScope { static let global = CMIOObjectPropertyScope(kCMIOObjectPropertyScopeGlobal) }
extension CMIOObjectPropertyElement { static let master = CMIOObjectPropertyElement(kCMIOObjectPropertyElementMaster) }
![Page 31: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/31.jpg)
var prop = CMIOObjectPropertyAddress( mSelector: CMIOObjectPropertySelector(
kCMIOHardwarePropertyAllowScreenCaptureDevices), mScope: CMIOObjectPropertyScope(
kCMIOObjectPropertyScopeGlobal), mElement: CMIOObjectPropertyElement(
kCMIOObjectPropertyElementMaster))
![Page 32: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/32.jpg)
var prop = CMIOObjectPropertyAddress( mSelector: .allowScreenCaptureDevices, mScope: .global, mElement: .master)
![Page 33: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/33.jpg)
![Page 34: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/34.jpg)
Demo
http://github.com/invalidstream/audio-reverser
![Page 35: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/35.jpg)
Reversing Audio
1. Decode the MP3/AAC to LPCM
![Page 36: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/36.jpg)
Reversing Audio
2. Grab a buffer from the end
![Page 37: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/37.jpg)
Reversing Audio
3. Reverse its samples in memory
![Page 38: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/38.jpg)
Reversing Audio
4. Write it to the front of a new file
![Page 39: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/39.jpg)
Reversing Audio
5. Repeat until fully baked
![Page 40: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/40.jpg)
API Needs
• Convert from MP3/AAC to LPCM
• Write sequentially to audio file (.caf, .aif, .wav)
• Random-access read from audio file
![Page 41: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/41.jpg)
Plan A (Swift)
• AV Foundation
• AVAssetReader/Writer can do format conversion while reading/writing audio files
• Can’t (easily) read from arbitrary packet offsets; meant to process everything forward
![Page 42: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/42.jpg)
Plan B (C, Swift?)
• Audio Toolbox (part of Core Audio)
• ExtAudioFile can do format conversions while reading/writing audio files
• AudioFile can read from arbitrary packet offset
![Page 43: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/43.jpg)
![Page 44: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/44.jpg)
// declare LPCM format we are converting to AudioStreamBasicDescription format = {0}; format.mSampleRate = 44100.0; format.mFormatID = kAudioFormatLinearPCM; format.mFormatFlags = kAudioFormatFlagIsPacked | kAudioFormatFlagIsSignedInteger; format.mBitsPerChannel = 16; format.mChannelsPerFrame = 2; format.mBytesPerFrame = 4; format.mFramesPerPacket = 1; format.mBytesPerPacket = 4;
![Page 45: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/45.jpg)
// declare LPCM format we are converting to var format = AudioStreamBasicDescription( mSampleRate: 44100.0, mFormatID: kAudioFormatLinearPCM, mFormatFlags: kAudioFormatFlagIsPacked + kAudioFormatFlagIsSignedInteger, mBytesPerPacket: 4, mFramesPerPacket: 1, mBytesPerFrame: 4, mChannelsPerFrame: 2, mBitsPerChannel: 16, mReserved: 0)
![Page 46: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/46.jpg)
// open AudioFile for output AudioFileID forwardAudioFile; err = AudioFileCreateWithURL(forwardURL, kAudioFileCAFType, &format, kAudioFileFlags_EraseFile, &forwardAudioFile); IF_ERR_RETURN
#define IF_ERR_RETURN if (err != noErr) { return err; }
![Page 47: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/47.jpg)
// open AudioFile for output var forwardAudioFile: AudioFileID? err = AudioFileCreateWithURL(forwardURL, kAudioFileCAFType, &format, AudioFileFlags.eraseFile, &forwardAudioFile) if err != noErr { return err }
![Page 48: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/48.jpg)
![Page 49: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/49.jpg)
// open AudioFile for output var forwardAudioFile: AudioFileID? err = AudioFileCreateWithURL(forwardURL, kAudioFileCAFType, &format, AudioFileFlags.eraseFile, &forwardAudioFile) if err != noErr { return err }
![Page 50: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/50.jpg)
// open AudioFile for output var forwardAudioFile: AudioFileID? err = AudioFileCreateWithURL(forwardURL, kAudioFileCAFType, &format, AudioFileFlags.eraseFile, &forwardAudioFile) if err != noErr { return err }
1. Uses a free function, rather than a method on AudioFile
![Page 51: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/51.jpg)
// open AudioFile for output var forwardAudioFile: AudioFileID? err = AudioFileCreateWithURL(forwardURL, kAudioFileCAFType, &format, AudioFileFlags.eraseFile, &forwardAudioFile) if err != noErr { return err }
2. Errors are communicated via the return value, rather than throws
![Page 52: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/52.jpg)
// open AudioFile for output var forwardAudioFile: AudioFileID? err = AudioFileCreateWithURL(forwardURL, kAudioFileCAFType, &format, AudioFileFlags.eraseFile, &forwardAudioFile) if err != noErr { return err }
3. Some parameters are UInt32 constants, some are enums
![Page 53: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/53.jpg)
// open AudioFile for output var forwardAudioFile: AudioFileID? err = AudioFileCreateWithURL(forwardURL, kAudioFileCAFType, &format, AudioFileFlags.eraseFile, &forwardAudioFile) if err != noErr { return err }
4. Audio format is passed as an UnsafePointer<AudioStreamBasicDescription>
![Page 54: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/54.jpg)
// open AudioFile for output var forwardAudioFile: AudioFileID? err = AudioFileCreateWithURL(forwardURL, kAudioFileCAFType, &format, AudioFileFlags.eraseFile, &forwardAudioFile) if err != noErr { return err }
5. Created object is returned via an in-out parameter
![Page 55: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/55.jpg)
To say nothing of…
![Page 56: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/56.jpg)
Pointer arithmetic!
// swap packets inside transfer buffer for i in 0..<packetsToTransfer/2 { let swapSrc = transferBuffer.advanced(by: Int(i) * Int(format.mBytesPerPacket)) let swapDst = transferBuffer.advanced(by: transferBufferSize - (Int(i+1) * Int(format.mBytesPerPacket))) memcpy(swapBuffer, swapSrc, Int(format.mBytesPerPacket)) memcpy(swapSrc, swapDst, Int(format.mBytesPerPacket)) memcpy(swapDst, swapBuffer, Int(format.mBytesPerPacket)) }
![Page 57: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/57.jpg)
Pointer arithmetic!
// swap packets inside transfer buffer for i in 0..<packetsToTransfer/2 { let swapSrc = transferBuffer.advanced(by: Int(i) * Int(format.mBytesPerPacket)) let swapDst = transferBuffer.advanced(by: transferBufferSize - (Int(i+1) * Int(format.mBytesPerPacket))) memcpy(swapBuffer, swapSrc, Int(format.mBytesPerPacket)) memcpy(swapSrc, swapDst, Int(format.mBytesPerPacket)) memcpy(swapDst, swapBuffer, Int(format.mBytesPerPacket)) }
![Page 58: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/58.jpg)
![Page 59: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/59.jpg)
Couldn’t you just…
![Page 60: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/60.jpg)
extension AudioFileID { init? (url: URL, fileType: UInt32, format: AudioStreamBasicDescription, flags: AudioFileFlags) { var fileId : AudioFileID? var format = format let err = AudioFileCreateWithURL(url as CFURL, fileType, &format, flags, &fileId) guard err != noErr, let createdFile = fileId else { return nil } self = createdFile } }
![Page 61: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/61.jpg)
Been there, done that• The Amazing Audio Engine !
• Novocaine (!?)
• EZAudio !
• AudioKit
• Superpowered
• etc…
![Page 62: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/62.jpg)
![Page 63: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/63.jpg)
/** Convert a source audio file (using any Core Audio-supported codec) and create LPCM .caf files for its forward and backward versions. - parameter sourceURL: A file URL containing the source audio to be read from - parameter forwardURL: A file URL with the destination to write the decompressed (LPCM) forward file - parameter backwardURL: A file URL with the destination to write the backward file */ OSStatus convertAndReverse(CFURLRef sourceURL, CFURLRef forwardURL, CFURLRef backwardURL);
AudioReversingC.h
// // Use this file to import your target's public headers that you would like to expose to Swift. //
#import <CoreFoundation/CoreFoundation.h> #import <AudioToolbox/AudioToolbox.h>
OSStatus convertAndReverse(CFURLRef sourceURL, CFURLRef forwardURL, CFURLRef backwardURL);
AudioReverser-Bridging-Header.h
![Page 64: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/64.jpg)
if USE_SWIFT_CONVERTER { err = convertAndReverseSwift(sourceURL: source as CFURL, forwardURL: self.forwardURL as! CFURL, backwardURL: self.backwardURL as! CFURL) } else { err = convertAndReverse(source as! CFURL, self.forwardURL as! CFURL, self.backwardURL as! CFURL) }
![Page 65: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/65.jpg)
C APIs on iOS/macOS• Core Foundation
• Core Audio
• Core Media
• Video Toolbox
• Keychain
• IOKit
• OpenGL
• SQLite
• Accelerate
• OpenCV
• BSD, Mach
• etc…
![Page 66: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/66.jpg)
Going deeper…
![Page 67: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/67.jpg)
![Page 68: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/68.jpg)
Audio Units
• Discrete software objects for working with audio
• Generators, I/O, Filters/Effects, Mixers, Converters
• Typically combined in a “graph” model
• Used by Garage Band, Logic, etc.
![Page 69: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/69.jpg)
Demo
R(t) = C(t) x M(t)
https://github.com/invalidstream/ring-modulator-v3audiounit
![Page 70: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/70.jpg)
Ring Modulator
• Multiplication of two signals
• One is usually a sine wave
• Originally implemented as a ring-shaped circuit
![Page 71: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/71.jpg)
0 0.8 1.6 2.4 3.2 4 4.8 5.6 6.4 7.2
-2.4
-1.6
-0.8
0.8
1.6
2.4
R(t) = C(t) x M(t)
![Page 72: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/72.jpg)
0 0.8 1.6 2.4 3.2 4 4.8 5.6 6.4 7.2
-2.4
-1.6
-0.8
0.8
1.6
2.4
R(t) = C(t) x M(t)
![Page 73: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/73.jpg)
0 0.8 1.6 2.4 3.2 4 4.8 5.6 6.4 7.2
-2.4
-1.6
-0.8
0.8
1.6
2.4
R(t) = C(t) x M(t)
![Page 74: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/74.jpg)
0 0.8 1.6 2.4 3.2 4 4.8 5.6 6.4 7.2
-2.4
-1.6
-0.8
0.8
1.6
2.4
R(t) = C(t) x M(t)
![Page 75: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/75.jpg)
Modulate! Modulate!
• Ring modulator best known as the “Dalek” voice effect on Doctor Who (circa 1963)
• Also used in early electronic music
![Page 76: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/76.jpg)
![Page 77: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/77.jpg)
![Page 78: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/78.jpg)
![Page 79: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/79.jpg)
![Page 80: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/80.jpg)
Wait, what?
![Page 81: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/81.jpg)
-(instancetype)initWithComponentDescription:(AudioComponentDescription)componentDescription options:(AudioComponentInstantiationOptions)options error:(NSError **)outError { self = [super initWithComponentDescription:componentDescription options:options error:outError]; if (self == nil) { return nil; } // ... return self; }
MyAudioUnit.m
![Page 82: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/82.jpg)
![Page 83: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/83.jpg)
XPC
![Page 84: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/84.jpg)
(macOS only)
![Page 85: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/85.jpg)
![Page 86: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/86.jpg)
Swift 3
![Page 87: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/87.jpg)
Swift 3
![Page 88: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/88.jpg)
Swift 4
![Page 89: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/89.jpg)
Swift 4
![Page 90: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/90.jpg)
![Page 91: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/91.jpg)
https://github.com/apple/swift/blob/master/docs/ABIStabilityManifesto.md
![Page 92: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/92.jpg)
“Given the importance of getting the core ABI and the related fundamentals correct, we are going to defer the declaration of ABI stability out of Swift 4 while still focusing the majority of effort to get to the point where the ABI can be declared stable.”
—Ted Kremenek, Feb. 16, 2017 “Swift 4, stage 2 starts now”
https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170213/032116.html
![Page 93: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/93.jpg)
![Page 94: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/94.jpg)
![Page 95: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/95.jpg)
![Page 96: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/96.jpg)
// Block which subclassers must provide to implement rendering.
- (AUInternalRenderBlock)internalRenderBlock { // Capture in locals to avoid Obj-C member lookups. // If "self" is captured in render, we're doing it wrong. See sample code. return ^AUAudioUnitStatus(AudioUnitRenderActionFlags *actionFlags, const AudioTimeStamp *timestamp, AVAudioFrameCount frameCount, NSInteger outputBusNumber, AudioBufferList *outputData, const AURenderEvent *realtimeEventListHead, AURenderPullInputBlock pullInputBlock) {
// Do event handling and signal processing here. return noErr; }; }
![Page 97: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/97.jpg)
Don’t do this
• An audio unit’s render block is called on a realtime thread
• Therefore it cannot perform any action that could block:
• I/O (file or network)
• Waiting on a mutex or semaphore
![Page 98: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/98.jpg)
Also, don’t do this
• Call objc_msg_send()
• Capture any Objective-C or Swift object
• Allocate memory
Basically, if you touch anything in the block other than a pre-allocated C struct or primitive, you’re asking for trouble.
![Page 99: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/99.jpg)
// Block which subclassers must provide to implement rendering. - (AUInternalRenderBlock)internalRenderBlock { // Capture in locals to avoid Obj-C member lookups. // If "self" is captured in render, we're doing it wrong. See sample code. AUValue *frequencyCapture = &frequency; AudioStreamBasicDescription *asbdCapture = &asbd; __block UInt64 *totalFramesCapture = &totalFrames; AudioBufferList *renderABLCapture = &renderABL; return ^AUAudioUnitStatus(AudioUnitRenderActionFlags *actionFlags, const AudioTimeStamp *timestamp, AVAudioFrameCount frameCount, NSInteger outputBusNumber, AudioBufferList *outputData, const AURenderEvent *realtimeEventListHead, AURenderPullInputBlock pullInputBlock) {
// Do event handling and signal processing here.
// BLOCK IMPLEMENTATION ON NEXT SLIDE
return noErr; };
![Page 100: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/100.jpg)
// Block which subclassers must provide to implement rendering. - (AUInternalRenderBlock)internalRenderBlock { // Capture in locals to avoid Obj-C member lookups. // If "self" is captured in render, we're doing it wrong. See sample code. AUValue *frequencyCapture = &frequency; AudioStreamBasicDescription *asbdCapture = &asbd; __block UInt64 *totalFramesCapture = &totalFrames; AudioBufferList *renderABLCapture = &renderABL; return ^AUAudioUnitStatus(AudioUnitRenderActionFlags *actionFlags, const AudioTimeStamp *timestamp, AVAudioFrameCount frameCount, NSInteger outputBusNumber, AudioBufferList *outputData, const AURenderEvent *realtimeEventListHead, AURenderPullInputBlock pullInputBlock) {
// Do event handling and signal processing here.
// BLOCK IMPLEMENTATION ON NEXT SLIDE
return noErr; };
![Page 101: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/101.jpg)
// Block which subclassers must provide to implement rendering. - (AUInternalRenderBlock)internalRenderBlock { // Capture in locals to avoid Obj-C member lookups. // If "self" is captured in render, we're doing it wrong. See sample code. AUValue *frequencyCapture = &frequency; AudioStreamBasicDescription *asbdCapture = &asbd; __block UInt64 *totalFramesCapture = &totalFrames; AudioBufferList *renderABLCapture = &renderABL; return ^AUAudioUnitStatus(AudioUnitRenderActionFlags *actionFlags, const AudioTimeStamp *timestamp, AVAudioFrameCount frameCount, NSInteger outputBusNumber, AudioBufferList *outputData, const AURenderEvent *realtimeEventListHead, AURenderPullInputBlock pullInputBlock) {
// Do event handling and signal processing here.
// BLOCK IMPLEMENTATION ON NEXT SLIDE
return noErr; };
❌
![Page 102: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/102.jpg)
// pull in samples to filter pullInputBlock(actionFlags, timestamp, frameCount, 0, renderABLCapture);
// copy samples from ABL, apply filter, write to outputData size_t sampleSize = sizeof(Float32); for (int frame = 0; frame < frameCount; frame++) { *totalFramesCapture += 1; for (int renderBuf = 0; renderBuf < renderABLCapture->mNumberBuffers; renderBuf++) { Float32 *sample = renderABLCapture->mBuffers[renderBuf].mData + (frame * asbdCapture->mBytesPerFrame); // apply modulation Float32 time = totalFrames / asbdCapture->mSampleRate; *sample = *sample * fabs(sinf(M_PI * 2 * time * *frequencyCapture)); memcpy(outputData->mBuffers[renderBuf].mData + (frame * asbdCapture->mBytesPerFrame), sample, sampleSize); } }
return noErr;
![Page 103: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/103.jpg)
Obj-C Instance Variables!
❌AUValue *frequencyCapture = &frequency; AudioStreamBasicDescription *asbdCapture = &asbd; __block UInt64 *totalFramesCapture = &totalFrames; AudioBufferList *renderABLCapture = &renderABL;
![Page 104: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/104.jpg)
https://github.com/apple/swift/blob/master/docs/OwnershipManifesto.md
![Page 105: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/105.jpg)
Certain kinds of low-level programming require stricter performance guarantees. Often these guarantees are less about absolute performance than predictable performance. For example, keeping up with an audio stream is not a taxing job for a modern processor, even with significant per-sample overheads, but any sort of unexpected hiccup is immediately noticeable by users.
—“Swift Ownership Manifesto”,February 2017
![Page 106: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/106.jpg)
We believe that these problems can be addressed with an opt-in set of features that we collectively call ownership. […]
Swift already has an ownership system, but it's “under the covers”: it's an implementation detail that programmers have little ability to influence. What we are proposing here is easy to summarize:
• We should add a core rule to the ownership system, called the Law of Exclusivity […]
• We should add features to give programmers more control over the ownership system […]
• We should add features to allow programmers to express types with unique ownership […]
![Page 107: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/107.jpg)
And yet…
![Page 108: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/108.jpg)
“[Swift] is the first industrial-quality systems programming language that is as expressive and enjoyable as a scripting language.”
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/
![Page 109: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/109.jpg)
So… when?
![Page 110: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/110.jpg)
Waiting…
• ABI stability — will not be in Swift 4
• Ownership — unclear
• Are these traits sufficient?
![Page 111: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/111.jpg)
![Page 112: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/112.jpg)
![Page 113: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/113.jpg)
![Page 114: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/114.jpg)
Strategies
• Use AV Foundation if you can
• Learn to balance C and Swift
• “Render undo C-sar what is C-sar’s…”
• The goal is to have idiomatic Swift, not Swift that may work but looks like C
![Page 115: CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine](https://reader036.vdocument.in/reader036/viewer/2022062306/5a6488967f8b9a7c568b49c3/html5/thumbnails/115.jpg)
Media Frameworks and Swift:
This is FineChris Adamson • @invalidname CocoaConf Chicago, April 2017
Slides available at slideshare.net/invalidname Code available at github.com/invalidstream