Nagrywanie do AAC z RemoteIO: dane są zapisywane, ale nie można odtworzyć pliku

Próbowałem nagrywać z jednostki RemoteIO bezpośrednio do AAC w renderCallback w iOS 5 na iPadzie 2. Widziałem sprzeczne informacje mówiące, że nie jest to możliwe i że jest to możliwe (w komentarzachtutaj). Powodem, dla którego chcę to zrobić, jest to, że nagrywanie na PCM wymaga tak dużo miejsca na dysku, aby nagrać dowolną długość - nawet jeśli zostanie później przekonwertowane na AAC.

Jestem jednak gotów się poddać. Przechwyciłem przez Google, SO, książkę Core Audio i listę mailingową i fora Apple Core-Audio i osiągnąłem punkt, w którym nie dostaję żadnych błędów - i nagrywamcoś na dysk, ale wynikowy plik jest niemożliwy do odtworzenia. Dotyczy to zarówno symulatora, jak i urządzenia.

Więc ... jeśli ktoś ma z tym doświadczenie, byłbym wdzięczny za szturchnięcie we właściwym kierunku. Konfiguracja polega na tym, że RemoteIO odtwarza sygnał wyjściowy z AUSamplerów i działa prawidłowo.

Oto co robię w poniższym kodzie

OkreślićAudioStreamBasicDescription formaty dla urządzenia remoteIO dokAudioFormatLinearPCM

Utwórz i określ format docelowy dlaExtAudioFileRef Określ format klienta, pobierając go z jednostki RemoteIO

Określ renderCallback dla jednostki RemoteID

W renderCallback zapisz dane wkAudioUnitRenderAction_PostRender faza

Jak już powiedziałem, nie otrzymuję żadnych błędów, a wynikowe rozmiary plików audio pokazują, że coś jest pisane, ale plik jest nie do odtworzenia. Być może mam zepsute formaty?

W każdym razie jest to moja wiadomość w butelce i / lub flaga „Be Here Dragons” dla każdego, kto walczy z ciemnymi wodami Core-Audio.

// Nieszczęśliwy komunikat, który otrzymuję podczas próby odtworzenia pliku:

// część konfiguracji remoteIO

<code>    // Enable IO for recording

UInt32 flag = 1;
result = AudioUnitSetProperty(ioUnit, 
                              kAudioOutputUnitProperty_EnableIO, 
                              kAudioUnitScope_Input, 
                              kInputBus, // == 1
                              &flag, 
                              sizeof(flag));
if (noErr != result) {[self printErrorMessage: @"Enable IO for recording" withStatus: result]; return;}

// Describe format - - - - - - - - - -
size_t bytesPerSample = sizeof (AudioUnitSampleType);
AudioStreamBasicDescription audioFormat;
memset(&audioFormat, 0, sizeof(audioFormat));
audioFormat.mSampleRate   = 44100.00;
audioFormat.mFormatID     = kAudioFormatLinearPCM;
audioFormat.mFormatFlags    = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
audioFormat.mFramesPerPacket = 1;
audioFormat.mChannelsPerFrame = 1;
audioFormat.mBitsPerChannel   = 16;
audioFormat.mBytesPerPacket   = 2;
audioFormat.mBytesPerFrame    = 2;

result = AudioUnitSetProperty(ioUnit, 
                              kAudioUnitProperty_StreamFormat, 
                              kAudioUnitScope_Output, 
                              kInputBus, // == 1
                              &audioFormat, 
                              sizeof(audioFormat));


result = AudioUnitSetProperty(ioUnit, 
                              kAudioUnitProperty_StreamFormat, 
                              kAudioUnitScope_Input, 
                              kOutputBus, // == 0
                              &audioFormat, 
                              sizeof(audioFormat));
</code>

// Funkcja, która ustawia plik i renderowanie wywołania zwrotnego

<code> - (void)startRecordingAAC
{

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 = 2;
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));


result = AudioUnitGetProperty(ioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, 0, & clientFormat, &size);
 if(result) printf("AudioUnitGetProperty %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, renderCallback, (__bridge void*)self);
if (result) {[self printErrorMessage: @"AudioUnitAddRenderNotify" withStatus: result];}
}
</code>

// I wreszcie renderowanie zwrotne

<code>static OSStatus renderCallback (void *                       inRefCon,
                            AudioUnitRenderActionFlags * ioActionFlags,
                            const AudioTimeStamp *       inTimeStamp,
                            UInt32                       inBusNumber,
                            UInt32                       inNumberFrames,
                            AudioBufferList *            ioData) 
{

OSStatus result;
if (*ioActionFlags == kAudioUnitRenderAction_PostRender){
    MusicPlayerController* THIS = (__bridge MusicPlayerController *)inRefCon;

       result =  ExtAudioFileWriteAsync(THIS->extAudioFileRef, inNumberFrames, ioData);
       if(result) printf("ExtAudioFileWriteAsync %ld \n", result); 

}
return noErr; 
}
</code>

questionAnswers(3)

yourAnswerToTheQuestion