Estoy intentando grabar el sonido producido por la salida de una unidad mezcladora.Cómo grabar el sonido producido por la salida de la unidad mezcladora (iOS Core Audio y Audio Graph)
Por el momento, mi código se basa en la demostración apple MixerHost iOS app: Un nodo mezclador está conectado a un nodo remoto IO en el graphe de audio.
y trato de establecer una devolución de llamada entrada en la nodo IO remoto de entrada en la salida del mezclador.
Hago algo mal pero no puedo encontrar el error.
Aquí está el código a continuación. Esto se hace justo después de la unidad de instalación multicanal Mezclador:
UInt32 flag = 1;
// Enable IO for playback
result = AudioUnitSetProperty(iOUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Output,
0, // Output bus
&flag,
sizeof(flag));
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty EnableIO" withStatus: result]; return;}
/* can't do that because *** AudioUnitSetProperty EnableIO error: -1073752493 00000000
result = AudioUnitSetProperty(iOUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input,
0, // Output bus
&flag,
sizeof(flag));
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty EnableIO" withStatus: result]; return;}
*/
continuación, crear un formato de flujo:
// I/O stream format
iOStreamFormat.mSampleRate = 44100.0;
iOStreamFormat.mFormatID = kAudioFormatLinearPCM;
iOStreamFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
iOStreamFormat.mFramesPerPacket = 1;
iOStreamFormat.mChannelsPerFrame = 1;
iOStreamFormat.mBitsPerChannel = 16;
iOStreamFormat.mBytesPerPacket = 2;
iOStreamFormat.mBytesPerFrame = 2;
[self printASBD: iOStreamFormat];
Entonces afectan el formato y especificar la frecuencia de muestreo:
result = AudioUnitSetProperty(iOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
1, // Input bus
&iOStreamFormat,
sizeof(iOStreamFormat));
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty StreamFormat" withStatus: result]; return;}
result = AudioUnitSetProperty(iOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
0, // Output bus
&iOStreamFormat,
sizeof(iOStreamFormat));
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty StreamFormat" withStatus: result]; return;}
// SampleRate I/O
result = AudioUnitSetProperty (iOUnit, kAudioUnitProperty_SampleRate, kAudioUnitScope_Input,
0, // Output
&graphSampleRate,
sizeof (graphSampleRate));
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty (set I/O unit input stream format)" withStatus: result]; return;}
entonces, intenta establecer la devolución de llamada de renderizado.
Solución 1 >>> mi devolución de llamada de grabación nunca se llama
effectState.rioUnit = iOUnit;
AURenderCallbackStruct renderCallbackStruct;
renderCallbackStruct.inputProc = &recordingCallback;
renderCallbackStruct.inputProcRefCon = &effectState;
result = AudioUnitSetProperty (iOUnit, kAudioUnitProperty_SetRenderCallback, kAudioUnitScope_Input,
0, // Output bus
&renderCallbackStruct,
sizeof (renderCallbackStruct));
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty SetRenderCallback" withStatus: result]; return;}
Solución 2 >>> mis aplicación se bloquea en el lanzamiento de esta
AURenderCallbackStruct renderCallbackStruct;
renderCallbackStruct.inputProc = &recordingCallback;
renderCallbackStruct.inputProcRefCon = &effectState;
result = AUGraphSetNodeInputCallback (processingGraph, iONode,
0, // Output bus
&renderCallbackStruct);
if (noErr != result) {[self printErrorMessage: @"AUGraphSetNodeInputCallback (I/O unit input callback bus 0)" withStatus: result]; return;}
Si alguien tiene una idea ...
EDIT Solución 3 (gracias a arlo anwser) >> Ahora hay un problema de formato
AudioStreamBasicDescription dstFormat = {0};
dstFormat.mSampleRate=44100.0;
dstFormat.mFormatID=kAudioFormatLinearPCM;
dstFormat.mFormatFlags=kAudioFormatFlagsNativeEndian|kAudioFormatFlagIsSignedInteger|kAudioFormatFlagIsPacked;
dstFormat.mBytesPerPacket=4;
dstFormat.mBytesPerFrame=4;
dstFormat.mFramesPerPacket=1;
dstFormat.mChannelsPerFrame=2;
dstFormat.mBitsPerChannel=16;
dstFormat.mReserved=0;
result = AudioUnitSetProperty(iOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output,
1,
&stereoStreamFormat,
sizeof(stereoStreamFormat));
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty" withStatus: result]; return;}
result = AudioUnitSetProperty(iOUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Input,
0,
&stereoStreamFormat,
sizeof(stereoStreamFormat));
if (noErr != result) {[self printErrorMessage: @"AudioUnitSetProperty" withStatus: result]; return;}
AudioUnitAddRenderNotify(
iOUnit,
&recordingCallback,
&effectState
);
y la configuración del archivo:
if (noErr != result) {[self printErrorMessage: @"AUGraphInitialize" withStatus: result]; return;}
// On initialise le fichier audio
NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
NSString *documentsDirectory = [paths objectAtIndex:0];
NSString *destinationFilePath = [[[NSString alloc] initWithFormat: @"%@/output.caf", documentsDirectory] autorelease];
NSLog(@">>> %@", destinationFilePath);
CFURLRef destinationURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault, (CFStringRef)destinationFilePath, kCFURLPOSIXPathStyle, false);
OSStatus setupErr = ExtAudioFileCreateWithURL(destinationURL, kAudioFileWAVEType, &dstFormat, NULL, kAudioFileFlags_EraseFile, &effectState.audioFileRef);
CFRelease(destinationURL);
NSAssert(setupErr == noErr, @"Couldn't create file for writing");
setupErr = ExtAudioFileSetProperty(effectState.audioFileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &stereoStreamFormat);
NSAssert(setupErr == noErr, @"Couldn't create file for format");
setupErr = ExtAudioFileWriteAsync(effectState.audioFileRef, 0, NULL);
NSAssert(setupErr == noErr, @"Couldn't initialize write buffers for audio file");
Y la devolución de llamada de grabación:
static OSStatus recordingCallback (void * inRefCon,
AudioUnitRenderActionFlags * ioActionFlags,
const AudioTimeStamp * inTimeStamp,
UInt32 inBusNumber,
UInt32 inNumberFrames,
AudioBufferList * ioData) {
if (*ioActionFlags == kAudioUnitRenderAction_PostRender && inBusNumber == 0)
{
EffectState *effectState = (EffectState *)inRefCon;
ExtAudioFileWriteAsync(effectState->audioFileRef, inNumberFrames, ioData);
}
return noErr;
}
hay algo que falta en el archivo de salida output.caf :). Estoy totalmente perdido en formatos para aplicar.
que estoy tratando de hacer lo mismo bt incapaz de implementar código ur sobre MixerHost Ejemplo puede u PLZ me ayuda .. – Aadil
Hola lefakir y arlomedia, ¿sería posible que alguno de ustedes pudiera publicar la clase EffectState? Estoy tratando de reproducir el código de trabajo usando MixerHost y lo anterior. Mejor, Gregor –
Hola Gregor, deberías mirar aquí http://stackoverflow.com/questions/7032468/record-sounds-played-by-my-iphone-app-with-audiounits. La estructura EffectState se declara en esta pregunta. – lefakir