SlideShare a Scribd company logo
Media Frameworks and
Swift:
This is Fine
Chris Adamson • @invalidname
Forward Swift, March 2017
Who the what, now?
@invalidname
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
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)")
}
}
<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
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
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)
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
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
var prop = CMIOObjectPropertyAddress(
mSelector: CMIOObjectPropertySelector(
kCMIOHardwarePropertyAllowScreenCaptureDevices),
mScope: CMIOObjectPropertyScope(
kCMIOObjectPropertyScopeGlobal),
mElement: CMIOObjectPropertyElement(
kCMIOObjectPropertyElementMaster))
var prop = CMIOObjectPropertyAddress(
mSelector: CMIOObjectPropertySelector(
kCMIOHardwarePropertyAllowScreenCaptureDevices),
mScope: CMIOObjectPropertyScope(
kCMIOObjectPropertyScopeGlobal),
mElement: CMIOObjectPropertyElement(
kCMIOObjectPropertyElementMaster))
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
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)
}
extension CMIOObjectPropertySelector {
static let allowScreenCaptureDevices = CMIOObjectPropertySelector(
kCMIOHardwarePropertyAllowScreenCaptureDevices)
}
extension CMIOObjectPropertyScope {
static let global = CMIOObjectPropertyScope(kCMIOObjectPropertyScopeGlobal)
}
extension CMIOObjectPropertyElement {
static let master = CMIOObjectPropertyElement(kCMIOObjectPropertyElementMaster)
}
var prop = CMIOObjectPropertyAddress(
mSelector: .allowScreenCaptureDevices,
mScope: .global,
mElement: .master)
var prop = CMIOObjectPropertyAddress(
mSelector: CMIOObjectPropertySelector(
kCMIOHardwarePropertyAllowScreenCaptureDevices),
mScope: CMIOObjectPropertyScope(
kCMIOObjectPropertyScopeGlobal),
mElement: CMIOObjectPropertyElement(
kCMIOObjectPropertyElementMaster))
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Demo
http://github.com/invalidstream/audio-reverser
Reversing Audio
1. Decode the MP3/AAC to LPCM2. Grab a buffer from the end3. Reverse its samples in memory4. Write it to the front of a new file5. Repeat until fully baked
API Needs
• Convert from MP3/AAC to LPCM
• Write sequentially to audio file (.caf, .aif, .wav)
• Random-access read from audio file
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
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
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
// 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;
// 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)
// 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; }
// open AudioFile for output
var forwardAudioFile: AudioFileID?
err = AudioFileCreateWithURL(forwardURL,
kAudioFileCAFType,
&format,
AudioFileFlags.eraseFile,
&forwardAudioFile)
if err != noErr { return err }
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
// open AudioFile for output
var forwardAudioFile: AudioFileID?
err = AudioFileCreateWithURL(forwardURL,
kAudioFileCAFType,
&format,
AudioFileFlags.eraseFile,
&forwardAudioFile)
if err != noErr { return err }
// 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
// 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
// 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
// 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>
// 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
To say nothing of…
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))
}
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Couldn’t you just…
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
}
}
Been there, done that
• The Amazing Audio Engine 💀
• Novocaine (💀?)
• EZAudio 💀
• AudioKit
• Superpowered
• etc…
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
/**
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
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)
}
C APIs on iOS/macOS
• Core Foundation
• Core Audio
• Core Media
• Video Toolbox
• Keychain
• IOKit
• OpenGL
• SQLite
• Accelerate
• XPC
• BSD, Mach
• etc…
Going deeper…
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
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.
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Wait, what?
-(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
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
XPC
(macOS only)
Swift 3Swift 4
https://github.com/apple/swift/blob/master/docs/
ABIStabilityManifesto.md
“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
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
// 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;
};
}
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
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, you’re asking for trouble.
https://github.com/apple/swift/blob/master/docs/
OwnershipManifesto.md
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
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 […]
And yet…
“[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/
So… when?
Waiting…
• ABI stability — will not be in Swift 4
• Ownership — unclear
• Are these traits sufficient?
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Forward Swift 2017: Media Frameworks and Swift: This Is Fine
Strategies
• Use AV Foundation if you can
• Learn to balance C and Swift
• “Render undo Caesar what is Caesar’s…”
• The goal is to have idiomatic Swift, not Swift
that may work but looks like C
Media Frameworks and
Swift:
This is Fine
Chris Adamson • @invalidname
Forward Swift, March 2017

More Related Content

PDF
Stupid Video Tricks (CocoaConf DC, March 2014)
PDF
Media Frameworks Versus Swift (Swift by Northwest, October 2017)
PDF
CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine
PDF
Stupid Video Tricks
PDF
Stupid Video Tricks, CocoaConf Seattle 2014
PDF
Stupid Video Tricks, CocoaConf Las Vegas
PDF
Video Killed the Rolex Star (CocoaConf San Jose, November, 2015)
PDF
Video Killed the Rolex Star (CocoaConf Columbus, July 2015)
Stupid Video Tricks (CocoaConf DC, March 2014)
Media Frameworks Versus Swift (Swift by Northwest, October 2017)
CocoaConf Chicago 2017: Media Frameworks and Swift: This Is Fine
Stupid Video Tricks
Stupid Video Tricks, CocoaConf Seattle 2014
Stupid Video Tricks, CocoaConf Las Vegas
Video Killed the Rolex Star (CocoaConf San Jose, November, 2015)
Video Killed the Rolex Star (CocoaConf Columbus, July 2015)

What's hot (20)

PDF
Introduction to the Roku SDK
PPTX
A slightly deeper dive into Stagefright
KEY
Managing Eclipse Preferences for Teams (EclipseCon 2011)
KEY
Morpheus configuration engine (slides from Saint Perl-2 conference)
PDF
Web Audio API + AngularJS
PDF
Dart on server - Meetup 18/05/2017
PDF
AngularDart - Meetup 15/03/2017
PDF
Happy Go Programming
PDF
QConSP 2015 - Dicas de Performance para Aplicações Web
PDF
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...
PDF
php & performance
PPTX
Creating Perl modules with Dist::Zilla
PDF
How we use and deploy Varnish at Opera
PDF
VUG5: Varnish at Opera Software
PPTX
Streams, sockets and filters oh my!
PDF
PECL Picks - Extensions to make your life better
PDF
Binary Obfuscation from the Top Down: Obfuscation Executables without Writing...
PPTX
HipHop Virtual Machine
PDF
"Elixir of Life" - Dev In Santos
PDF
PHP & Performance
Introduction to the Roku SDK
A slightly deeper dive into Stagefright
Managing Eclipse Preferences for Teams (EclipseCon 2011)
Morpheus configuration engine (slides from Saint Perl-2 conference)
Web Audio API + AngularJS
Dart on server - Meetup 18/05/2017
AngularDart - Meetup 15/03/2017
Happy Go Programming
QConSP 2015 - Dicas de Performance para Aplicações Web
Puppet Camp Phoenix 2015: Managing Files via Puppet: Let Me Count The Ways (B...
php & performance
Creating Perl modules with Dist::Zilla
How we use and deploy Varnish at Opera
VUG5: Varnish at Opera Software
Streams, sockets and filters oh my!
PECL Picks - Extensions to make your life better
Binary Obfuscation from the Top Down: Obfuscation Executables without Writing...
HipHop Virtual Machine
"Elixir of Life" - Dev In Santos
PHP & Performance
Ad

Viewers also liked (20)

DOCX
Análisis entre el neoclasicismo y impresionismo
PDF
Core Image: The Most Fun API You're Not Using, CocoaConf Atlanta, December 2014
PDF
Master Video with AV Foundation
PDF
Composing and Editing Media with AV Foundation
PDF
Firebase: Totally Not Parse All Over Again (Unless It Is) (CocoaConf San Jose...
PDF
Advanced AV Foundation (CocoaConf, Aug '11)
PDF
Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]
PPTX
Webinar: Is Your Storage Ready for Disaster?
PDF
Creating Container View Controllers
PDF
Video streaming on e-lab
PDF
Mastering Media with AV Foundation
PDF
Introduction to AV Foundation
PPTX
Beyond 2017 Trends
PDF
Histone 2b paper
PDF
Tutorial hotspot
PPTX
DREAM 2017 | Faculty as Drivers of College Reform Efforts
PPTX
Excel vba講座
PPTX
GEOMETRIA II U1 t2 a1
PPTX
Efficiency of protein utilisation ppt
PDF
Hacking and Securing iOS Apps : Part 1
Análisis entre el neoclasicismo y impresionismo
Core Image: The Most Fun API You're Not Using, CocoaConf Atlanta, December 2014
Master Video with AV Foundation
Composing and Editing Media with AV Foundation
Firebase: Totally Not Parse All Over Again (Unless It Is) (CocoaConf San Jose...
Advanced AV Foundation (CocoaConf, Aug '11)
Oh Crap, I Forgot (Or Never Learned) C! [CodeMash 2010]
Webinar: Is Your Storage Ready for Disaster?
Creating Container View Controllers
Video streaming on e-lab
Mastering Media with AV Foundation
Introduction to AV Foundation
Beyond 2017 Trends
Histone 2b paper
Tutorial hotspot
DREAM 2017 | Faculty as Drivers of College Reform Efforts
Excel vba講座
GEOMETRIA II U1 t2 a1
Efficiency of protein utilisation ppt
Hacking and Securing iOS Apps : Part 1
Ad

Similar to Forward Swift 2017: Media Frameworks and Swift: This Is Fine (20)

PDF
Voice That Matter 2010 - Core Audio
KEY
Core Audio in iOS 6 (CocoaConf Portland, Oct. '12)
PDF
Core Audio in iOS 6 (CocoaConf Chicago, March 2013)
PDF
Core Audio: Don't Be Afraid to Play it LOUD! [360iDev, San Jose 2010]
PDF
Core Audio in iOS 6 (CocoaConf San Jose, April 2013)
PDF
Building Modern Audio Apps with AVAudioEngine
PDF
Glitch-Free A/V Encoding (CocoaConf Boston, October 2013)
PDF
KKBOX WWDC17 Airplay 2 - Dolphin
PDF
Movi presentation Singapore video tech meetup
PDF
Utilizing AVFoundation at dubsmash
PDF
Introduction to AV Foundation (CocoaConf, Aug '11)
PDF
iOS Media APIs (MobiDevDay Detroit, May 2013)
PDF
Songbird
PDF
Core Audio Cranks It Up
PDF
Get On The Audiobus (CocoaConf Boston, October 2013)
PDF
Get On The Audiobus (CocoaConf Atlanta, November 2013)
PPT
Core audio
PDF
Core MIDI and Friends
PDF
Android media framework overview
PDF
Building A Streaming Apple TV App (CocoaConf DC, Sept 2016)
Voice That Matter 2010 - Core Audio
Core Audio in iOS 6 (CocoaConf Portland, Oct. '12)
Core Audio in iOS 6 (CocoaConf Chicago, March 2013)
Core Audio: Don't Be Afraid to Play it LOUD! [360iDev, San Jose 2010]
Core Audio in iOS 6 (CocoaConf San Jose, April 2013)
Building Modern Audio Apps with AVAudioEngine
Glitch-Free A/V Encoding (CocoaConf Boston, October 2013)
KKBOX WWDC17 Airplay 2 - Dolphin
Movi presentation Singapore video tech meetup
Utilizing AVFoundation at dubsmash
Introduction to AV Foundation (CocoaConf, Aug '11)
iOS Media APIs (MobiDevDay Detroit, May 2013)
Songbird
Core Audio Cranks It Up
Get On The Audiobus (CocoaConf Boston, October 2013)
Get On The Audiobus (CocoaConf Atlanta, November 2013)
Core audio
Core MIDI and Friends
Android media framework overview
Building A Streaming Apple TV App (CocoaConf DC, Sept 2016)

More from Chris Adamson (12)

PDF
Whatever Happened to Visual Novel Anime? (AWA/Youmacon 2018)
PDF
Whatever Happened to Visual Novel Anime? (JAFAX 2018)
PDF
Fall Premieres: Media Frameworks in iOS 11, macOS 10.13, and tvOS 11 (CocoaCo...
PDF
Building A Streaming Apple TV App (CocoaConf San Jose, Nov 2016)
PDF
Firebase: Totally Not Parse All Over Again (Unless It Is)
PDF
Revenge of the 80s: Cut/Copy/Paste, Undo/Redo, and More Big Hits (CocoaConf C...
PDF
Core Image: The Most Fun API You're Not Using (CocoaConf Columbus 2014)
PDF
Core Audio in iOS 6 (CocoaConf DC, March 2013)
PDF
Mobile Movies with HTTP Live Streaming (CocoaConf DC, March 2013)
PDF
Core Audio Intro (Detroit Mobile City 2013)
PDF
Objective-C Is Not Java
PDF
Core Audio in iOS 6 (CocoaConf Raleigh, Dec. '12)
Whatever Happened to Visual Novel Anime? (AWA/Youmacon 2018)
Whatever Happened to Visual Novel Anime? (JAFAX 2018)
Fall Premieres: Media Frameworks in iOS 11, macOS 10.13, and tvOS 11 (CocoaCo...
Building A Streaming Apple TV App (CocoaConf San Jose, Nov 2016)
Firebase: Totally Not Parse All Over Again (Unless It Is)
Revenge of the 80s: Cut/Copy/Paste, Undo/Redo, and More Big Hits (CocoaConf C...
Core Image: The Most Fun API You're Not Using (CocoaConf Columbus 2014)
Core Audio in iOS 6 (CocoaConf DC, March 2013)
Mobile Movies with HTTP Live Streaming (CocoaConf DC, March 2013)
Core Audio Intro (Detroit Mobile City 2013)
Objective-C Is Not Java
Core Audio in iOS 6 (CocoaConf Raleigh, Dec. '12)

Recently uploaded (20)

PDF
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
PPTX
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
PPTX
sap open course for s4hana steps from ECC to s4
PDF
Machine learning based COVID-19 study performance prediction
PDF
Encapsulation theory and applications.pdf
PDF
Spectral efficient network and resource selection model in 5G networks
PDF
Advanced methodologies resolving dimensionality complications for autism neur...
PDF
Chapter 3 Spatial Domain Image Processing.pdf
PDF
Reach Out and Touch Someone: Haptics and Empathic Computing
PDF
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
PDF
Unlocking AI with Model Context Protocol (MCP)
PDF
KodekX | Application Modernization Development
PDF
Diabetes mellitus diagnosis method based random forest with bat algorithm
PPTX
20250228 LYD VKU AI Blended-Learning.pptx
PDF
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
PPTX
Cloud computing and distributed systems.
PDF
Agricultural_Statistics_at_a_Glance_2022_0.pdf
PPTX
MYSQL Presentation for SQL database connectivity
PDF
Network Security Unit 5.pdf for BCA BBA.
PDF
Approach and Philosophy of On baking technology
TokAI - TikTok AI Agent : The First AI Application That Analyzes 10,000+ Vira...
ACSFv1EN-58255 AWS Academy Cloud Security Foundations.pptx
sap open course for s4hana steps from ECC to s4
Machine learning based COVID-19 study performance prediction
Encapsulation theory and applications.pdf
Spectral efficient network and resource selection model in 5G networks
Advanced methodologies resolving dimensionality complications for autism neur...
Chapter 3 Spatial Domain Image Processing.pdf
Reach Out and Touch Someone: Haptics and Empathic Computing
Peak of Data & AI Encore- AI for Metadata and Smarter Workflows
Unlocking AI with Model Context Protocol (MCP)
KodekX | Application Modernization Development
Diabetes mellitus diagnosis method based random forest with bat algorithm
20250228 LYD VKU AI Blended-Learning.pptx
Architecting across the Boundaries of two Complex Domains - Healthcare & Tech...
Cloud computing and distributed systems.
Agricultural_Statistics_at_a_Glance_2022_0.pdf
MYSQL Presentation for SQL database connectivity
Network Security Unit 5.pdf for BCA BBA.
Approach and Philosophy of On baking technology

Forward Swift 2017: Media Frameworks and Swift: This Is Fine

  • 1. Media Frameworks and Swift: This is Fine Chris Adamson • @invalidname Forward Swift, March 2017
  • 2. Who the what, now? @invalidname
  • 16. 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)") } }
  • 17. <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
  • 19. CMIOObjectPropertyAddress prop = { kCMIOHardwarePropertyAllowScreenCaptureDevices, kCMIOObjectPropertyScopeGlobal, kCMIOObjectPropertyElementMaster }; UInt32 allow = 1; CMIOObjectSetPropertyData( kCMIOObjectSystemObject, &prop, 0, NULL, sizeof(allow), &allow );
  • 20. 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)
  • 21. 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
  • 23. var prop = CMIOObjectPropertyAddress( mSelector: CMIOObjectPropertySelector( kCMIOHardwarePropertyAllowScreenCaptureDevices), mScope: CMIOObjectPropertyScope( kCMIOObjectPropertyScopeGlobal), mElement: CMIOObjectPropertyElement( kCMIOObjectPropertyElementMaster)) var prop = CMIOObjectPropertyAddress( mSelector: CMIOObjectPropertySelector( kCMIOHardwarePropertyAllowScreenCaptureDevices), mScope: CMIOObjectPropertyScope( kCMIOObjectPropertyScopeGlobal), mElement: CMIOObjectPropertyElement( kCMIOObjectPropertyElementMaster))
  • 26. 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) }
  • 27. extension CMIOObjectPropertySelector { static let allowScreenCaptureDevices = CMIOObjectPropertySelector( kCMIOHardwarePropertyAllowScreenCaptureDevices) } extension CMIOObjectPropertyScope { static let global = CMIOObjectPropertyScope(kCMIOObjectPropertyScopeGlobal) } extension CMIOObjectPropertyElement { static let master = CMIOObjectPropertyElement(kCMIOObjectPropertyElementMaster) }
  • 28. var prop = CMIOObjectPropertyAddress( mSelector: .allowScreenCaptureDevices, mScope: .global, mElement: .master) var prop = CMIOObjectPropertyAddress( mSelector: CMIOObjectPropertySelector( kCMIOHardwarePropertyAllowScreenCaptureDevices), mScope: CMIOObjectPropertyScope( kCMIOObjectPropertyScopeGlobal), mElement: CMIOObjectPropertyElement( kCMIOObjectPropertyElementMaster))
  • 31. Reversing Audio 1. Decode the MP3/AAC to LPCM2. Grab a buffer from the end3. Reverse its samples in memory4. Write it to the front of a new file5. Repeat until fully baked
  • 32. API Needs • Convert from MP3/AAC to LPCM • Write sequentially to audio file (.caf, .aif, .wav) • Random-access read from audio file
  • 33. 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
  • 34. 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
  • 36. // 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;
  • 37. // 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)
  • 38. // 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; }
  • 39. // open AudioFile for output var forwardAudioFile: AudioFileID? err = AudioFileCreateWithURL(forwardURL, kAudioFileCAFType, &format, AudioFileFlags.eraseFile, &forwardAudioFile) if err != noErr { return err }
  • 41. // open AudioFile for output var forwardAudioFile: AudioFileID? err = AudioFileCreateWithURL(forwardURL, kAudioFileCAFType, &format, AudioFileFlags.eraseFile, &forwardAudioFile) if err != noErr { return err }
  • 42. // 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
  • 43. // 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
  • 44. // 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
  • 45. // 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>
  • 46. // 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
  • 47. To say nothing of…
  • 48. 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)) }
  • 51. 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 } }
  • 52. Been there, done that • The Amazing Audio Engine 💀 • Novocaine (💀?) • EZAudio 💀 • AudioKit • Superpowered • etc…
  • 54. /** 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
  • 55. 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) }
  • 56. C APIs on iOS/macOS • Core Foundation • Core Audio • Core Media • Video Toolbox • Keychain • IOKit • OpenGL • SQLite • Accelerate • XPC • BSD, Mach • etc…
  • 59. 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.
  • 63. -(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
  • 68. “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
  • 72. // 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; }; }
  • 73. 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
  • 74. 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, you’re asking for trouble.
  • 76. 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
  • 77. 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 […]
  • 79. “[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/
  • 81. Waiting… • ABI stability — will not be in Swift 4 • Ownership — unclear • Are these traits sufficient?
  • 84. Strategies • Use AV Foundation if you can • Learn to balance C and Swift • “Render undo Caesar what is Caesar’s…” • The goal is to have idiomatic Swift, not Swift that may work but looks like C
  • 85. Media Frameworks and Swift: This is Fine Chris Adamson • @invalidname Forward Swift, March 2017