2012-08-30 8 views
5

Sto scrivendo un'app per iOS che riceve l'input dal microfono, la trasmette attraverso un'unità audio con filtro passa-alto e la riproduce attraverso gli altoparlanti. Sono stato in grado di farlo correttamente utilizzando l'API AUGraph. In esso, ho inserito due nodi: un'unità I/O remota e un'unità audio effetto (kAudioUnitType_Effect, kAudioUnitSubType_HighPassFilter) e collegato l'ambito di uscita dell'elemento input dell'elemento io all'ingresso dell'unità effetto e l'uscita del nodo effetto all'unità io l'ambito di input dell'elemento di output. Ma ora ho bisogno di fare delle analisi basate sui campioni audio processati, quindi ho bisogno di un accesso diretto al buffer. Questo significa (e, per favore, correggimi se ho torto) Non posso più usare AUGraphConnectNodeInput per creare la connessione tra l'uscita del nodo effetto e l'elemento di uscita dell'unità io, e devo allegare una funzione di callback di rendering per l'elemento di uscita dell'unità io, in modo che possa accedere al buffer ogni volta che gli oratori necessitano di nuovi campioni. Ho fatto così, ma ottengo un errore -50 quando chiamo la funzione AudioUnitRender nella richiamata di rendering. Credo di avere un caso di disallineamento tra ASBD tra le due unità audio, dal momento che non sto facendo nulla al riguardo nel richiamo del rendering (e l'AUGRAPH se ne è occupato prima). Ecco il codice:Errore durante la scrittura di una funzione di richiamata di I/O remoto

AudioController.h:

@interface AudioController : NSObject 
{ 
    AUGraph mGraph; 
    AudioUnit mEffects; 
    AudioUnit ioUnit; 
} 

@property (readonly, nonatomic) AudioUnit mEffects; 
@property (readonly, nonatomic) AudioUnit ioUnit; 

-(void)initializeAUGraph; 
-(void)startAUGraph; 
-(void)stopAUGraph; 

@end 

AudioController.mm:

@implementation AudioController 

… 

static OSStatus renderInput(void *inRefCon, AudioUnitRenderActionFlags *ioActionFlags, const AudioTimeStamp *inTimeStamp, UInt32 inBusNumber, UInt32 inNumberFrames, AudioBufferList *ioData) 
{ 
    AudioController *THIS = (__bridge AudioController*)inRefCon; 

    AudioBuffer buffer; 

    AudioStreamBasicDescription fxOutputASBD; 
    UInt32 fxOutputASBDSize = sizeof(fxOutputASBD); 
    AudioUnitGetProperty([THIS mEffects], kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &fxOutputASBD, &fxOutputASBDSize); 

    buffer.mDataByteSize = inNumberFrames * fxOutputASBD.mBytesPerFrame; 
    buffer.mNumberChannels = fxOutputASBD.mChannelsPerFrame; 
    buffer.mData = malloc(buffer.mDataByteSize); 

    AudioBufferList bufferList; 
    bufferList.mNumberBuffers = 1; 
    bufferList.mBuffers[0] = buffer; 

    //TODO prender ARM y solucionar problema de memoria 

    OSStatus result = AudioUnitRender([THIS mEffects], ioActionFlags, inTimeStamp, inBusNumber, inNumberFrames, &bufferList); 
    [THIS hasError:result:__FILE__:__LINE__]; 

    memcpy(ioData, buffer.mData, buffer.mDataByteSize); 

    return noErr; 
} 


- (void)initializeAUGraph 
{ 
    OSStatus result = noErr; 

    // create a new AUGraph 
    result = NewAUGraph(&mGraph); 

    AUNode outputNode; 
    AUNode effectsNode; 

    AudioComponentDescription effects_desc; 
    effects_desc.componentType = kAudioUnitType_Effect; 
    effects_desc.componentSubType = kAudioUnitSubType_LowPassFilter; 
    effects_desc.componentFlags = 0; 
    effects_desc.componentFlagsMask = 0; 
    effects_desc.componentManufacturer = kAudioUnitManufacturer_Apple; 

    AudioComponentDescription output_desc; 
    output_desc.componentType = kAudioUnitType_Output; 
    output_desc.componentSubType = kAudioUnitSubType_RemoteIO; 
    output_desc.componentFlags = 0; 
    output_desc.componentFlagsMask = 0; 
    output_desc.componentManufacturer = kAudioUnitManufacturer_Apple; 

    // Add nodes to the graph to hold the AudioUnits 
    result = AUGraphAddNode(mGraph, &output_desc, &outputNode); 
    [self hasError:result:__FILE__:__LINE__]; 
    result = AUGraphAddNode(mGraph, &effects_desc, &effectsNode); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Connect the effect node's output to the output node's input 
    // This is no longer the case, as I need to access the buffer 
    // result = AUGraphConnectNodeInput(mGraph, effectsNode, 0, outputNode, 0); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Connect the output node's input scope's output to the effectsNode input 
    result = AUGraphConnectNodeInput(mGraph, outputNode, 1, effectsNode, 0); 
    [self hasError:result:__FILE__:__LINE__]; 

    // open the graph AudioUnits 
    result = AUGraphOpen(mGraph); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Get a link to the effect AU 
    result = AUGraphNodeInfo(mGraph, effectsNode, NULL, &mEffects); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Same for io unit 
    result = AUGraphNodeInfo(mGraph, outputNode, NULL, &ioUnit); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Enable input on io unit 
    UInt32 flag = 1; 
    result = AudioUnitSetProperty(ioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, 1, &flag, sizeof(flag)); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Setup render callback struct 
    AURenderCallbackStruct renderCallbackStruct; 
    renderCallbackStruct.inputProc = &renderInput; 
    renderCallbackStruct.inputProcRefCon = (__bridge void*)self; 

    // Set a callback for the specified node's specified input 
    result = AUGraphSetNodeInputCallback(mGraph, outputNode, 0, &renderCallbackStruct); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Get fx unit's input current stream format... 
    AudioStreamBasicDescription fxInputASBD; 
    UInt32 sizeOfASBD = sizeof(AudioStreamBasicDescription); 

    result = AudioUnitGetProperty(mEffects, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input, 0, &fxInputASBD, &sizeOfASBD); 
    [self hasError:result:__FILE__:__LINE__]; 

    // ...and set it on the io unit's input scope's output 
    result = AudioUnitSetProperty(ioUnit, 
            kAudioUnitProperty_StreamFormat, 
            kAudioUnitScope_Output, 
            1, 
            &fxInputASBD, 
            sizeof(fxInputASBD)); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Set fx unit's output sample rate, just in case 
    Float64 sampleRate = 44100.0; 

    result = AudioUnitSetProperty(mEffects, 
            kAudioUnitProperty_SampleRate, 
            kAudioUnitScope_Output, 
            0, 
            &sampleRate, 
            sizeof(sampleRate)); 
    [self hasError:result:__FILE__:__LINE__]; 

    // Once everything is set up call initialize to validate connections 
    result = AUGraphInitialize(mGraph); 
    [self hasError:result:__FILE__:__LINE__]; 
} 

@end 

Come ho detto prima, sto ottenendo un errore di -50 sulla chiamata AudioUnitRender, e Sto trovando poca o nessuna documentazione a riguardo.

Qualsiasi aiuto sarà molto apprezzato.

Grazie a Tim Bolstad (http://timbolstad.com/2010/03/14/core-audio-getting-started/) per fornire un eccellente tutorial punto di partenza.

risposta

0

Esistono esempi più semplici di utilizzo di RemoteIO per la semplice riproduzione di buffer di audio. Forse inizia con uno di quelli prima piuttosto che con un grafico.

0

Verificare che si stiano effettivamente effettuando tutte le connessioni necessarie. Sembra che tu stia inizializzando la maggior parte di tutto il necessario, ma se vuoi semplicemente passare l'audio non hai bisogno della funzione di richiamata del rendering.

Ora, se si vuole fare il filtro, potrebbe essere necessario uno, ma anche così, assicurarsi che si stiano effettivamente collegando i componenti insieme correttamente.

Ecco un frammento da un app sto lavorando:

AUGraphConnectNodeInput(graph, outputNode, kInputBus, mixerNode, kInputBus); 
AUGraphConnectNodeInput(graph, mixerNode, kOutputBus, outputNode, kOutputBus); 

Questo collega l'ingresso dall'unità RemoteIO ad un'unità multicanale Mixer, quindi collega l'uscita del mixer all'uscita del RemoteIO al altoparlante.

0

Mi sembra che tu stia passando nell'unità audio errata a AudioUnitRender. Penso che sia necessario passare in ioUnit anziché mEffects. In ogni caso, ricontrolla tutti i parametri che stai passando a AudioUnitRender. Quando vedo -50 restituito è perché ho sbagliato uno di loro.

Problemi correlati