He intentado grabar desde una unidad RemoteIO directamente a AAC en un renderCallback en iOS 5 en un iPad 2. He visto información conflictiva diciendo que no es posible & que es posible (en los comentarios here). Mi razón para querer hacerlo es porque la grabación en PCM requiere tanto espacio en disco para una grabación de cualquier longitud, incluso si luego se convierte en AAC.Grabación en AAC desde RemoteIO: se están escribiendo datos pero no se pueden reproducir archivos
Estoy a punto de darme por vencido. Recorrí Google, SO, el libro Core Audio y la lista de correo de Apple Core-Audio & foros y llegué al punto en el que no recibo ningún error, y estoy grabando algo en el disco, pero el archivo resultante no se puede reproducir . Este es el caso tanto con el simulador como con el dispositivo.
Entonces ... si alguien tiene experiencia con esto, realmente agradecería un empujón en la dirección correcta. La configuración es que RemoteIO reproduce la salida de AUSamplers & que está funcionando bien.
Aquí es lo que estoy haciendo en el código de abajo
Especificar las
AudioStreamBasicDescription
formatos para la unidad remoteIO akAudioFormatLinearPCM
Crear y especificar el formato de destino para el
ExtAudioFileRef
Especificar el cliente formato obteniéndolo de la unidad RemoteIOEspecifique la renderCallback f o la unidad RemoteID
En el renderCallback, escribir datos en el
kAudioUnitRenderAction_PostRender
fase
Como ya he dicho, no estoy recibiendo ningún error, y los tamaños de los archivos de audio resultantes muestran algo que se está escribiendo, pero el archivo no se puede reproducir. Quizás tengo mis formatos estropeados?
De todos modos, este es mi mensaje en una botella y/o bandera de "Be Here Dragons" para cualquier persona que desafíe las aguas oscuras de Core-Audio.
// El msg infeliz consigo al intentar reproducir el archivo:
// parte de la instalación remoteIO
// 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));
// Función que configura el archivo & rendercallback
- (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];}
}
// Y finalmente, el rendercallback
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;
}
Muchas gracias hombre! ¡Acabo de grabar directamente en AAC (m4a) trabajando! –
La única parte en la que me quedé atascado fue establecer kExtAudioFileProperty_ClientDataFormat. Tenía que ver con el entrelazado (El sonido era audible pero con muchas grietas). Mi audioFormat (formato de los búferes de entrada) está intercalado y necesitaba establecer el kExtAudioFileProperty_ClientDataFormat exactamente en AudioFormat. –
@skinnyTOD Esto funcionó.Muchas gracias, pero, cada dos o tres veces que llamo a la función startRecordingAAC, obtengo un error EXC_BAD_ACCESS (código = 1, dirección = 0x2f8) y la aplicación se cierra. ¿Alguna idea de cómo puedo resolver este problema? Gracias por adelantado. –