2012-08-30 6 views
5

Estoy escribiendo una aplicación iOS que toma la entrada desde el micrófono, la ejecuta a través de una unidad de audio de filtro de paso alto y la reproduce a través de los altavoces. Pude hacer esto con éxito utilizando la API de AUGraph. En él, puse dos nodos: una unidad de E/S remotas y una unidad de audio de efectos (kAudioUnitType_Effect, kAudioUnitSubType_HighPassFilter) y conecté el alcance de salida del elemento de entrada de la unidad io a la entrada de la unidad de efectos y la salida del nodo de efectos a la unidad alcance de entrada del elemento de salida. Pero ahora tengo la necesidad de hacer un análisis basado en las muestras de audio procesadas, por lo que necesito acceso directo al buffer. Esto significa (y corríjame si estoy equivocado) ya no puedo usar AUGraphConnectNodeInput para establecer la conexión entre la salida del nodo de efectos y el elemento de salida de la unidad io, y tengo que adjuntar una función de devolución de llamada para el elemento de salida de la unidad io, para que pueda acceder al búfer cada vez que los altavoces necesitan nuevas muestras. Lo he hecho, pero obtengo un error -50 cuando llamo a la función AudioUnitRender en la devolución de llamada de renderizado. Creo que tengo un caso de desajuste de ASBD entre las dos unidades de audio, ya que no estoy haciendo nada al respecto en la devolución de llamada de render (y el AUGraph se encargó de eso antes). Aquí está el código:Problema al escribir una función de devolución de llamada de renderizado de E/S remotas

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 

Como he dicho antes, estoy recibiendo un error de -50 en la llamada AudioUnitRender, y Estoy encontrando poca o ninguna documentación sobre eso.

Cualquier ayuda será muy apreciada.

Gracias a Tim Bolstad (http://timbolstad.com/2010/03/14/core-audio-getting-started/) por proporcionar un excelente tutorial de punto de partida.

Respuesta

0

Hay ejemplos de trabajo más simples de usar RemoteIO para solo reproducir memorias de audio. Tal vez comience con uno de esos primeros en lugar de un gráfico.

0

Asegúrate de que estás realizando todas las conexiones necesarias. Parece que está inicializando la mayoría de todo lo necesario, pero si simplemente desea pasar el audio, no necesita la función de devolución de llamada.

Ahora, si desea hacer el filtro, puede necesitar uno, pero aún así, asegúrese de que realmente está conectando los componentes juntos correctamente.

He aquí un fragmento de una aplicación que estoy trabajando:

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

Esto conecta la entrada de la unidad RemoteIO a una unidad multicanal mezclador, a continuación, conecta la salida del mezclador a la salida del RemoteIO a la altavoz.

0

Me parece que está pasando la unidad de audio incorrecta al AudioUnitRender. Creo que debe pasar ioUnit en lugar de mEffects. En cualquier caso, verifique dos veces todos los parámetros que está pasando al AudioUnitRender. Cuando veo que -50 regresó es porque fallé con uno de ellos.

Cuestiones relacionadas