2012-05-07 4 views
7

Sto codificando un'app di registrazione musicale utilizzando Audio Units e sto riscontrando alcuni problemi che impediscono al mio file M4A di riprodurre qualcosa di diverso da un ronzio non così impressionante . Ho usato questi SO sourcesasreferences, e ho provato tutto per risolvere i problemi.Scrittura e codifica dell'uscita I/O remota su file - Core Audio

Ho un AUGraph con 2 nodi: un mixer multicanale e un I/O remoto. Ho due callback di input sul mio mixer: uno che tira input dal microfono e uno che tira da un file audio. L'uscita del mixer è collegata all'elemento di ingresso dell'ambito di uscita sull'unità I/O. Ciò consente l'I/O simultaneo.

Per catturare l'output ho aggiunto una funzione di callback e due metodi:

Il callback

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; 
} 

Metodo di registrazione:

- (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];}  
} 

Metodo di risparmio:

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

} 

Questo è quello che vedo nella mia console:

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

Mi sembra che il mio codice è molto simile a quello delle persone che hanno ottenuto questo lavoro, ma chiaramente ho fatto un errore cruciale. Sono sicuro che ci devono essere altri che lottano con questo.

Qualcuno ha qualche idea?

Grazie.

+0

Sembra che il metodo '-saveFile' venga chiamato prima che 'recordAndSaveCallback' sia finito. Stai fermando l'AUGRAPH prima di chiamare saveFile? – sbooth

+0

come esperimento per escludere eventuali problemi con il grafico potrebbe essere una buona idea provare e registrare utilizzando un formato più semplice come wav. ASBD può essere difficile da ottenere, ma se si può determinare che l'ASBD è il problema (la mia opinione), almeno si può semplicemente concentrarsi sulla sperimentazione con il formato del file. – dubbeat

+0

esegue macerror -50 dalla riga di comando fornisce questo: Errore Mac OS -50 (paramErr): errore nell'elenco dei parametri utente – morgancodes

risposta

1

So che il problema è stato fatto molto tempo fa e probabilmente scoperto l'errore, ormai, sto solo rispondendo per altro che potrebbe avere lo stesso problema.

Potrei sbagliarmi, ma credo che il problema viene dal fatto che si sta facendo una dichiarazione di variabile in-scope per il buffer.

mi sento di raccomandare di cambiare

SInt16 samples[inNumberFrames]; 

in

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

Dal momento che la recordAndSaveCallback è destinato a riempire la lista dei buffer, se si fa una dichiarazione in-campo di applicazione, dati verranno distrutti come appena finito lo scopo.

Problemi correlati