2012-05-07 8 views
7

Estoy codificando una aplicación de grabación de música usando unidades de audio y tengo algunos problemas para que mi archivo M4A resultante reproduzca algo que no sea un zumbido no tan increíble . He utilizado estos SO sourcesasreferences, y he intentado todo para solucionar los problemas.Escribir y codificar salida I/0 remota a archivo - Core Audio

Tengo un AUGraph con 2 nodos: un mezclador multicanal y una E/S remota. Tengo dos devoluciones de entrada en mi mezclador: una que extrae la entrada del micrófono y otra que saca de un archivo de audio. La salida del mezclador está conectada al elemento de entrada del alcance de salida en la unidad de E/S. Esto permite E/S simultáneas.

Para capturar la salida he añadido una devolución de llamada y dos métodos:

La devolución de llamada

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

    OSStatus status; 
    status = AudioUnitRender(THIS.ioUnit,  
          ioActionFlags, 
          inTimeStamp, 
          0, 
          inNumberFrames, 
          &bufferList); 

    SInt16 samples[inNumberFrames]; // A large enough size to not have to worry about buffer overrun 
    memset (&samples, 0, sizeof (samples)); 

    bufferList.mNumberBuffers = 1; 
    bufferList.mBuffers[0].mData = samples; 
    bufferList.mBuffers[0].mNumberChannels = 1; 
    bufferList.mBuffers[0].mDataByteSize = inNumberFrames*sizeof(SInt16); 

    OSStatus result; 
    if (*ioActionFlags == kAudioUnitRenderAction_PostRender) { 
     result = ExtAudioFileWriteAsync(THIS.extAudioFileRef, inNumberFrames, &bufferList); 
     if(result) printf("ExtAudioFileWriteAsync %ld \n", result);} 
    return noErr; 
} 

Método de grabación:

- (void)recordFile 
{  
    OSStatus result; 

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); 
    NSString *documentsDirectory = [paths objectAtIndex:0]; 
    NSString *recordFile = [documentsDirectory stringByAppendingPathComponent: @"audio.m4a"]; 

    CFURLRef destinationURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, 
                  (__bridge CFStringRef)recordFile, 
                  kCFURLPOSIXPathStyle, 
                  false);  

    AudioStreamBasicDescription destinationFormat; 
    memset(&destinationFormat, 0, sizeof(destinationFormat)); 
    destinationFormat.mChannelsPerFrame = 1; 
    destinationFormat.mFormatID = kAudioFormatMPEG4AAC; 
    UInt32 size = sizeof(destinationFormat); 
    result = AudioFormatGetProperty(kAudioFormatProperty_FormatInfo, 0, NULL, &size, &destinationFormat);   
    if(result) printf("AudioFormatGetProperty %ld \n", result);  


    result = ExtAudioFileCreateWithURL(destinationURL, 
             kAudioFileM4AType, 
             &destinationFormat, 
             NULL, 
             kAudioFileFlags_EraseFile, 
             &extAudioFileRef); 
    if(result) printf("ExtAudioFileCreateWithURL %ld \n", result); 


    AudioStreamBasicDescription clientFormat; 
    memset(&clientFormat, 0, sizeof(clientFormat)); 


    UInt32 clientsize = sizeof(clientFormat); 
    result = AudioUnitGetProperty(ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, &clientFormat, &clientsize); 
    if(result) printf("AudioUnitGetProperty %ld \n", result); 

    UInt32 codec = kAppleHardwareAudioCodecManufacturer; 

    result = ExtAudioFileSetProperty(extAudioFileRef, 
            kExtAudioFileProperty_CodecManufacturer, 
            sizeof(codec), 
            &codec); 

    if(result) printf("ExtAudioFileSetProperty %ld \n", result); 


    result = ExtAudioFileSetProperty(extAudioFileRef,kExtAudioFileProperty_ClientDataFormat,sizeof(clientFormat), &clientFormat); 
    if(result) printf("ExtAudioFileSetProperty %ld \n", result); 


    result = ExtAudioFileWriteAsync(extAudioFileRef, 0, NULL); 
    if (result) {[self printErrorMessage: @"ExtAudioFileWriteAsync error" withStatus: result];} 

    result = AudioUnitAddRenderNotify(ioUnit, recordAndSaveCallback, (__bridge void*)self); 
    if (result) {[self printErrorMessage: @"AudioUnitAddRenderNotify" withStatus: result];}  
} 

Método Ahorro:

- (void) saveFile { 
    OSStatus status = ExtAudioFileDispose(extAudioFileRef); 
    NSLog(@"OSStatus(ExtAudioFileDispose): %ld\n", status); 

} 

Esto es lo que veo en mi consola:

Stopping audio processing graph 
OSStatus(ExtAudioFileDispose): 0 
ExtAudioFileWriteAsync -50 
ExtAudioFileWriteAsync -50 
ExtAudioFileWriteAsync -50 

Me parece que mi código es muy similar a la de las personas que han conseguido que esto funcione, pero está claro que he cometió un error crucial Estoy seguro de que debe haber otros luchando con esto.

¿Alguien tiene alguna idea?

Gracias.

+0

Parece que se llama al método '-saveFile' antes de que finalice' recordAndSaveCallback'. ¿Estás deteniendo el AUGraph antes de llamar a saveFile? – sbooth

+0

como un experimento para descartar cualquier problema con su gráfico, podría ser una buena idea tratar de registrar usando un formato más simple como wav. ASBD puede ser difícil de entender, pero si puedes determinar que el ASBD es el problema (mi opinión), al menos puedes concentrarte en experimentar con el formato de archivo. – dubbeat

+0

ejecutando macerror -50 desde la línea de comandos da esto: Mac OS error -50 (paramErr): error en la lista de parámetros de usuario – morgancodes

Respuesta

1

Sé que la pregunta se ha hecho hace mucho tiempo y probablemente ya descubras el error, solo estoy respondiendo por otra que pueda tener el mismo problema.

Podría estar equivocado, pero creo que el problema proviene del hecho de que está haciendo una declaración de variable en el ámbito para el búfer.

Yo recomendaría que cambie

SInt16 samples[inNumberFrames]; 

en

SInt16* samples = malloc(inNumberFrames * sizeof(SInt16)); 

Desde el recordAndSaveCallback está destinado a llenar la lista de buffers, si lo hace una declaración dentro del alcance, datas más serán destruidas como pronto como el alcance se termina.

Cuestiones relacionadas