Sei sulla pagina 1di 74

Lets start with Core Audio

Francesco Sinopoli
Project Manager & Software Developer francescosinopoli@hotmail.com http://it.linkedin.com/in/francescosinopoli

Outline
Parleremo di:

Audio Technologies su iOS Il Suono Audio Queue Services Audio Unit

Media su iOS
Audio Overview

Audio Overview
Quali sono le alternative a Core Audio?

iOS offre il seguente set di tools organizzati in frameworks in base alla features che forniscono:

Media Player framework: iPod library search and


playback

AV Foundation: Obj-C wrapper for audio le playback


and recording

Core Audio: low level audio streaming

Audio Overview
Usiamo Media Player per eseguire song, audio book, podcast dalla users iPod library

//Import the umbrella header file for the Media Player framework #import <MediaPlayer/MediaPlayer.h>

Audio Overview
Usiamo AV Foundation per eseguire e registrare audio utilizzando un semplice interfaccia Objective-C
#import <AVFoundation/AVFoundation.h>

Audio Overview
AVAsset is the core class in the AV Foundation framework

NSURL *url = <#A URL that identifies an audiovisual asset such as a movie file#>; AVURLAsset *anAsset = [[AVURLAsset alloc] initWithURL:url options:nil];

What is Core Audio?


Core Audio il motore che c dietro ogni suono riprodotto su Mac OS X e iOS

What is Core Audio?


Punti di vista

Da un punto di vista audio Core Audio ad alto livello perch astrae sia lhardware che il formato audio Da un punto di vista del developer appare essere a basso livello perch si utilizzano API C-based

Core Audio
Quando non utilizzare Core Audio

Non usarlo per ... eseguire Video Per accedere alla user iPod Library Per eseguire un le audio (AVAudioPlayer) Per registare un suono (AVAudioRecorder)

You should typically use the highest-level abstraction available that allows you to perform the tasks you want

Core Audio
...allora quando?

Quando vogliamo fare qualcosa direttamente con i dati

audio. Cio, quando abbiamo la necessit di processare il suono in tempo reale; vogliamo mixare, misurare (i decibel e.g.), eseguire eetti sullaudio, etc. performance e low latency

Quando come requisiti vengono richieste high

Core Audio
Core Audio un set di framework per lavorare con audio digitale

possibile suddividere questo set di frameworks in due gruppi:

Engines Helpers

Core Audio
Le engine API le utilizziamo per processare lo stream audio

Audio Units: sono un API per la cattura e lesecuzione di dati

audio, sono caratterizzate da una bassa latenza, ci consentono di produrre eetti ed eettuare mixing. Sono utilizzabili pi audio unit, ciascuno con il suo compito, connessi tra di loro come in un grafo. E altro ancora audio, costruite sopra le audio unit. Sono utilizzate mediante un meccanismo di callback che fornisce o riceve audio, buers di audio della dimensione desiderata. Hanno una latenza maggiore delle audio unit ma supportono formati compressi

Audio Queues: anche loro sono un API per registrare ed eseguire

OpenAL: un API per laudio 3D,

implementata sulle audio unit. Sono utilizzate soprattutto per il gaming

Core Audio
Le helper API le utilizziamo per lavorare i dati o veicolarli attraverso gli engine

Audio File: ci consentono di leggere da e scrivere su diversi tipi di


le audio astraendo dal loro contenuto. Ci consentono anche di recuperare metadati come durata, iTunes info, etc. network e di scoprire al volo lencoding di un le dierenti encoding

Audio File Stream: ci consentono di leggere da un stream Audio Converter: ci consentono di convertire buer di audio tra ExtAudioFile: combinano le features di Audio File e Audio Audio Session: giocano un ruolo decisivo nellambito del
comportamento audio della nostra app (sostituite con le AVAudioSession) Converter; sono uninterfaccia unicata per leggere e scrivere le audio compressi e linear PCM

Core Audio
Audio Session: take notes

iOS gestisce il comportamento audio a livello di app, inter-app


e device usando il concetto di Audio Session comportamento della nostra app complesso

Tramite le Audio Session rispondiamo a diverse questioni sul Laudio environment su un device iOS abbastanza Un Audio Session incapsula un set di comportamenti; ogni set
di comportamenti identicato da una chiave detta categoria essere gestito nella nostra app

Congurando questa chiave stabiliamo come laudio deve

Core Audio Learning Curve

Audio digitale 101

Il suono

About the sound


Suono: questioni principali

Segnale analogico continuo vs natura digitale del


computer

Campionamento del segnale: come i campioni sono


rappresentati e organizzati in forma digitale

Problemi quando trattiamo audio digitale: buer (e


relativa latenza), formati (vari tipi di formato audio digitale), etc.

About the sound

About the sound

About the sound

About the sound

Nyquist-Shannon pernonalterareilcontenutoinfrequenzadiunsegnalelafrequenza dicampionamentodeveesseremaggioredeldoppiodella frequenzamassimacontenutanelsegnale

About the sound


Il problema fondamentale della fedelt digitale consiste nel fare la migliore approssimazione considerati i limiti hardware

Core Audio glossary


Sample: rappresenta lampiezza dellonda Sample rate: il numero di sample catturati per ogni
secondo di audio. Si misura in sample per secondo sample. Si pu parlare di risoluzione del sample. Si misura in bit per sample secondo di audio. Si misura in bit per secondo, corrisponde al prodotto tra bit depth e sample rate

Bit depth: il numero di bit di informazione per ogni Bit rate: il numero di bit richiesti per descrivere un Frame: un bundle che combina un sample per canale.
Un frame rappresenta tutti i canali audio in un dato momento di tempo. Per il suono mono: un frame ha un sample; per il suono stereo: un frame ha due sample

Audio Queue Services


Core Audio Engines

Audio Queue
Sono la tecnologia raccomandata per aggiungere semplici feature di registrazione e playback alla nostra app

AudioToolbox framework Higest level playback and recording API (pure C interface)
in Core Audio

Audio Queue
Le Audio Queue service hanno un semplice modello per catturare o eseguire un audio. Semplice perch ci consente di non preoccuparci della complessit dei dati audio o dellhardware sottostante
Agli estremi abbiamo un trasduttore (microfono o speaker)

A recorder audio queue

A playback audio queue I buffer sono riempiti con i dati che provengono dallhardware e che poi vengono passati alla funzione di callback

Lo stream continuo di dati rappresentato da una coda (di buffer)

Example

Catturiamo e registriamo laudio Catturiamo laudio e applichiamo un eetto

Example

DEMO

Audio Queue - Recorder


Audio Queue non un API per registrare ed eseguire un suono ma a un livello pi basso

Congurare il formato audio che vogliamo utilizzare, AudioStreamBasicDescription Creare un audio queue, AudioQueueNewInput() Fornire una funzione di callback che processer laudio in entrata Avviare laudio queue, AudioQueueStart() Terminare laudio queue, AudioQueueStop()

Audio Queue - Recorder


Quando inizia a registrare laudio queue riempie un buffer con i primi dati acquisiti

Laudio queue invia questi buffer alla funzione di callback nello stesso ordine in cui sono stati acquisiti

La funzione di callback dopo avere utilizzato il buffer lo rimette a disposizione dellaudio queue per il suo riuso

Example: Capture + Effect


Formato Crea Inizializza e avvia Controlla

CAStreamBasicDescription recordFormat; recordFormat.mFormatID = kAudioFormatLinearPCM; recordFormat.mChannelsPerFrame = 2; recordFormat.mFormatFlags = kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked; recordFormat.mBitsPerChannel = 16; recordFormat.mBytesPerPacket = (recordFormat.mBitsPerChannel / 8) * recordFormat.mChannelsPerFrame; recordFormat.mBytesPerFrame = (recordFormat.mBitsPerChannel / 8) * recordFormat.mChannelsPerFrame; recordFormat.mFramesPerPacket = 1; recordFormat.mSampleRate = 8000;

Example: Capture + Effect


Formato Crea Inizializza e avvia Controlla

AudioQueueRef queue = {0}; AudioQueueNewInput(&_mRecordFormat, audioQueueBufferHandler, (__bridge void*) self /* userData */, NULL /* run loop */, NULL /* run loop mode */, 0 /* flags */, &queue);

Example: Capture + Effect


Formato Crea Inizializza e avvia Controlla

#define kNumbRecordBuffers ! 3 #define kBufferDurationSecond .5 // enough bytes for half a second bufferByteSize = 32000;! for (i = 0; i < kNumbRecordBuffers; ++i) { AudioQueueAllocateBuffer(_audioQueue, bufferByteSize, &_mBuffers[i]); AudioQueueEnqueueBuffer(_audioQueue, _mBuffers[i], 0, NULL); }

AudioQueueStart(_audioQueue, NULL)

Example: Capture + Effect


Formato Crea Inizializza e avvia Controlla
// AudioQueue callback function, called when an input buffers has been filled. void audioQueueBufferHandler(void *inUserData, AudioQueueRef inAQ, AudioQueueBufferRef inBuffer, const AudioTimeStamp *inStartTime, UInt32 inNumPackets, const AudioStreamPacketDescription *inPacketDesc){ ! PMMAQCapture *capture = (__bridge PMMAQCapture *)inUserData; ! try { ! ! if (inNumPackets > 0) { ! ! ! // TO DO Something AudioQueueEnqueueBuffer(capture.audioQueue, inBuffer, 0, NULL); ! ! } ! ! } catch (CAXException e) { ! ! char buf[256]; ! ! fprintf(stderr, "Error: %s (%s)\n", e.mOperation, e.FormatError(buf)); ! } }

Example: Capture + Effect


Set up size of the buffers How big the buffers should be?

Format, ASBD (bit rate, bit depth,...) (Buffer) duration in seconds Audio Queue, kAudioConverterPropertyMaximumOutputPacketSize
(compressed data) 8000 x
samples /seconds

1
channels

2
bytes /channel

1
seconds

= 16000 bytes

Example: Capture + Effect


Write to a le
Declaration @property (nonatomic, assign) AudioFileID recordFile; @property (nonatomic, assign) SInt64 recordPacket; ... Set Up NSString *recordFile = [NSTemporaryDirectory() stringByAppendingPathComponent:(NSString*)CFSTR("capture.caf")]; CFURLRef url = CFURLCreateWithString(kCFAllocatorDefault, (CFStringRef)recordFile, NULL); AudioFileCreateWithURL(url, kAudioFileCAFType, &recordFormat, kAudioFileFlags_EraseFile, &_recordFile); ... AudioFileWritePackets(capture.recordFile, Callback FALSE, inBuffer->mAudioDataByteSize, inPacketDesc, capture.recordPacket, &inNumPackets, inBuffer->mAudioData); capture.recordPacket += inNumPackets;

Example: Capture + Effect


Property-driven nature of the Audio Queue

kAudioQueueProperty_EnableLevelMetering kAudioQueueProperty_CurrentLevelMeter(DB)

Example: Capture + Effect


Level metering
Declaration @property (nonatomic, assign) AudioQueueLevelMeterState! *chan_lvls; ...

Set Up UInt32 val = 1; XThrowIfError(AudioQueueSetProperty(_audioQueue, kAudioQueueProperty_EnableLevelMetering, &val, sizeof(UInt32)), "couldn't enable metering"); ... Callback | Timer UInt32 data_sz = sizeof(AudioQueueLevelMeterState) * 1; //[_channelNumbers count]; OSErr status = AudioQueueGetProperty(self.audioQueue, kAudioQueueProperty_CurrentLevelMeterDB, self.chan_lvls, &data_sz); float value = (float)(self.chan_lvls[0].mAveragePower); [self.delegate recorderEngine:self levelMeterChanged:value]; ...

Audio Queue
Playback

Core Audio Engines

Audio Unit

Audio Unit
Nelle puntate precedenti

iOS offre pi tecnologie per gestire laudio digitale: Media Player, AVFoundation, Core Audio. Ciascuna di queste tecnologie deve essere utilizzata in presenza di speciche necessit Core Audio contiene tre engine per processare uno stream di dati audio (Audio Unit, Audio Queue e OpenAL). Audio Unit lengine principale, Audio Queue e OpenAL sono costruiti su di esso

Audio Unit
One engine to rule them all, one engine to nd them, one engine to bring them all and in the darkness bind them

Audio Unit
All audio technologies in iOS are build on top of audio units

Audio Unit
Benvenuti nella funzionalit di pi basso livello di Core Audio

Non possibile, per un dev iOS, andare pi vicini allhardware possibile lavorare con i dati audio raw come non possibile fare a pi alti livelli di astrazione possibile sintetizzare laudio, eseguire effetti su stream audio, catturare il suono dal microfono, combinare tutte queste cose tra di loro e farne altre ancora (ogni audio unit offre delle funzionalit particolari)

Audio Unit
Quando le utilizziamo

Eccellente reattivit Ricongurazione dinamica

Audio Unit
AUGraph

Audio Unit consente di lavorare con un meccanismo di plug-in; ogni singolo Audio Unit pu inserirsi in una catena di processamento audio (grafo) Ci viene in aiuto un helper API: AUGraph

Audio Unit
Audio Units life cycle

Instantiate Congure: qui congureremo lAudio Unit come richiesto dal tipo utilizzato al ne di raggiungere lo scopo della nostra app; Initialize: qui prepareremo lAudio Unit a gestire laudio che transiter da esso Start Control: consideriamo che, ad un alto livello siamo abituati a passare un URL ad un player o ad un recorder; ad un Audio Unit level lavoriamo con funzioni di callback che sono chiamate centinaia di volte al secondo Clean

Audio Unit
Creare un Audio Unit

Laudio unit creato tramite tre codici:

Type Subtype Manufacturer

questa tripletta identica univocamente un audio unit

Audio Unit
Creare un Audio Unit

Nel caso di pi audio unit necessario creare le connessioni tra di loro prima di avviare il processo audio

Audio Unit
Audio Unit un oggetto software che esegue un certo tipo di lavoro su uno stream audio.
Generator unit: creano uno stream di audio da qualche sorgente, come
le, network o memoria

Music unit: sono simili ai generator ma producono uno stream di audio


sintetizzato da un MIDI data stream in uno o pi stream

Mixer unit (Multichannel mixer, 3D mixer): combinano multipli Effect unit (iPodEQ, Delay, ...): eseguono qualche tipo di
processamento del segnale audio su uno stream

Converter unit (Format Converter): esegue trasformazioni che non


sono rivolte allutente nale ma piuttosto a conversioni tra diversi variet di PCM (ad esempio, cambia il sample rate o il bit depth)

Output unit (Remote I/O, Voice Processing I/O, Generic

Output): fanno anche da input. Sono delle interfacce con laudio input e output hardware, ci consentono di catturare laudio dal microfono o eseguirlo attraverso le casse

Audio Unit
Scope: un contesto allinterno di audio unit Element: chiamato anche bus, un contesto allinterno di un audio unit scope

Audio Unit
Come avviene il usso del segnale audio? I/O Unit: unastrazione sullaudio hardware (From hardware To hardware). Ogni elemento ha un input scope e un output scope
Output element = Element 0

Input element = Element 1

Audio Unit
Come avviene il usso del segnale audio? Riceviamo audio dalloutput scope dellelement di input e inviamo audio allinput scope dellelemento di output

Audio Unit

Audio Unit

Example
Catturiamo laudio e applichiamo un eetto

Creiamo un audio unit per la cattura dellaudio dal microfono e mostriamo come applicare effetti anche senza utilizzare un effect unit di sistema fornito da iOS Come facciamo ad eseguire effetti manualmente? Collezioniamo i sample nelloutput scope del bus 1 di un I/O unit e, dopo averli processati, forniamo questi sample, per essere eseguiti, allinput scope del bus 0 dello stesso I/O unit

Example

DEMO

Example: Capture + Effect

Direct connection su bus 0/input scope e bus 1/output scope. AUGraph con un solo nodo Render callback function sul bus 0/input scope allinterno della quale effettuare il pull sul bus 1/output scope

Example: Capture + Effect


Crea Congura Inizializza e avvia Controlla

AudioUnit rioUnit; ... AudioComponentDescription audioComponentDesc; audioComponentDesc.componentType = kAudioUnitType_Output; audioComponentDesc.componentSubType = kAudioUnitSubType_RemoteIO; audioComponentDesc.componentManufacturer = kAudioUnitManufacturer_Apple; audioComponentDesc.componentFlags = 0; audioComponentDesc.componentFlagsMask = 0; AudioComponent rioComponent = AudioComponentFindNext(NULL, &audioComponentDesc); AudioComponentInstanceNew(rioComponent, &rioUnit);

Example: Capture + Effect


Crea Congura Inizializza e avvia Controlla
UInt32 onFlag = 1; AudioUnitElement bus1 = 1; AudioUnitSetProperty(rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, bus1, &onFlag, sizeof(onFlag)); AudioUnitElement bus0 = 0; AudioUnitSetProperty(rioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output, bus0, &onFlag, sizeof(onFlag));

Example: Capture + Effect


Crea Congura Inizializza e avvia Controlla

AudioStreamBasicDescription customASBD; memset(&customASBD, 0, sizeof(customASBD)); customASBD.mSampleRate = hardwareSampleRate; customASBD.mFormatID = kAudioFormatLinearPCM; customASBD.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked; //kAudioFormatFlagsCanonical; //which means that you'll be working with signed integer samples customASBD.mBytesPerPacket = 2; //4; customASBD.mFramesPerPacket = 1; customASBD.mBytesPerFrame = 2; //4; customASBD.mChannelsPerFrame = 1; //mono 2 for stereo! customASBD.mBitsPerChannel = 16;

Example: Capture + Effect


Crea Congura Inizializza e avvia Controlla
//Set ASBD for output (bus 0) on the RIO's input scope AudioUnitSetProperty(rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, bus0, &customASBD, sizeof(customASBD)); //Set ASBD for mic input (bus 1) on the Rio's output scope AudioUnitSetProperty(rioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, bus1, &customASBD, sizeof(customASBD));

Example: Capture + Effect


Congure: set stream formats

Example: Capture + Effect


Crea Congura Inizializza e avvia Controlla

// Set render proc to supply samples from input unit AURenderCallbackStruct callbackStruct; callbackStruct.inputProc = InputRenderCallback; callbackStruct.inputProcRefCon = (__bridge void*)self; AudioUnitSetProperty(rioUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Global, bus0, &callbackStruct, sizeof(callbackStruct));

Example: Capture + Effect


Crea Congura Inizializza e avvia Controlla

//initialize and start Rio unit AudioUnitInitialize(_effectState.rioUnit); AudioOutputUnitStart(_effectState.rioUnit); //now, RemoteIO Unit starts making callback to a //function called inputRenderCallback

Example: Capture + Effect


Crea Congura Inizializza e avvia Controlla
static OSStatus InputRenderCallback (void AudioUnitRenderActionFlags const AudioTimeStamp UInt32 UInt32 AudioBufferList EffectClass *effectClass = (EffectClass*) inRefCon; // Just copy samples UInt32 bus1 = 1; AudioUnitRender(effectClass->rioUnit, ioActionFlags, inTimeStamp, bus1, inNumberFrames, ioData); roboticVoice(effectClass, ioData, inNumberFrames); return noErr; } *inRefCon, *ioActionFlags, *inTimeStamp, inBusNumber, inNumberFrames, *ioData){

Ehy, you can nd other DSP stuff on that site: http://musicdsp.org/

Example: Capture + Effect


Crea Congura Inizializza e avvia Controlla

Finito?

Audio App
Cose da fare per un app sounds

Congure Your Audio Session Categorize your application Respond to interruptions Handle routing changes

Audio App
Set Up the session

AVAudioSession *appSession = [AVAudioSession sharedInstance]; //we want to avoid sample rate conversion (CPU intensive); 44.100 Hertz [appSession setPreferredSampleRate:44100.0 error:nil]; [appSession setCategory:AVAudioSessionCategoryPlayAndRecord error:nil]; [appSession setActive:YES error:nil]; //set up AudioQueue, AVAudioPlayer or Audio Unit, etc.

Audio App
Handle interruptions
[[NSNotificationCenter defaultCenter] addObserver: selector: name: object: self @selector(handleInterruption:) AVAudioSessionInterruptionNotification [AVAudioSession sharedInstance] ];

- (void) handleInterruption:(NSNotification*)notification { NSDictionary *interruptionDict = notification.userInfo; NSUInteger interruptionType = (NSUInteger)[interruptionDict valueForKey:AVAudioSessionInterruptionTypeKey]; if (interruptionType == AVAudioSessionInterruptionTypeBegan) ... else if (interruptionType == AVAudioSessionInterruptionTypeEnded){ ... } }

Audio App
Handle route changes
//Posted on the main thread when the systems audio route changes. [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(handleRouteChanging:) name: AVAudioSessionRouteChangeNotification object: [AVAudioSession sharedInstance]]; - (void)handleRouteChanging:(NSNotification*)notification{ UInt8 reasonValue = [[notification.userInfo valueForKey: AVAudioSessionRouteChangeReasonKey] intValue]; switch (reasonValue) { case AVAudioSessionRouteChangeReasonNoSuitableRouteForCategory: break; case AVAudioSessionRouteChangeReasonWakeFromSleep: break; case AVAudioSessionRouteChangeReasonOverride: break; case AVAudioSessionRouteChangeReasonCategoryChange: break; case AVAudioSessionRouteChangeReasonOldDeviceUnavailable: break; case AVAudioSessionRouteChangeReasonNewDeviceAvailable: break; case AVAudioSessionRouteChangeReasonUnknown: default: break; } }

Resources
Apple documentation Learning Core Audio - (Adamson-Avila) Coreaudio-api mailing list

The End

Thank you