2011-12-23 5 views
11

questo è il mio codice: io uso questo codice per registrare l'audio dell'uscita iPhone utilizzando l'unità audio quindi salvando l'output in output.caf ma il file output.caf è vuoto qualsiasi organismo ha idea di cosa devo fare? il file audio di output è vuotoQualcuno può aiutarmi a registrare l'audio dell'uscita iPhone tramite l'unità audio

questo è INIZIALIZZA l'unità audio

-(void) initializaeOutputUnit 
{ 
    OSStatus status; 

    // Describe audio component 
    AudioComponentDescription desc; 
    desc.componentType = kAudioUnitType_Output; 
    desc.componentSubType = kAudioUnitSubType_RemoteIO; 
    desc.componentFlags = 0; 
    desc.componentFlagsMask = 0; 
    desc.componentManufacturer = kAudioUnitManufacturer_Apple; 

    // Get component 
    AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc); 

    // Get audio units 
    status = AudioComponentInstanceNew(inputComponent, &audioUnit); 

    // Enable IO for recording 
    UInt32 flag = 1; 
    status = AudioUnitSetProperty(audioUnit, 
            kAudioOutputUnitProperty_EnableIO, 
            kAudioUnitScope_Input, 
            kInputBus, 
            &flag, 
            sizeof(flag)); 

    // Enable IO for playback 
    status = AudioUnitSetProperty(audioUnit, 
            kAudioOutputUnitProperty_EnableIO, 
            kAudioUnitScope_Output, 
            kOutputBus, 
            &flag, 
            sizeof(flag)); 

    // Describe format 
    AudioStreamBasicDescription audioFormat={0}; 
    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; 

    // Apply format 
    status = AudioUnitSetProperty(audioUnit, 
            kAudioUnitProperty_StreamFormat, 
            kAudioUnitScope_Output, 
            kInputBus, 
            &audioFormat, 
            sizeof(audioFormat)); 
    status = AudioUnitSetProperty(audioUnit, 
            kAudioUnitProperty_StreamFormat, 
            kAudioUnitScope_Input, 
            kOutputBus, 
            &audioFormat, 
            sizeof(audioFormat)); 


    // Set input callback 
    AURenderCallbackStruct callbackStruct; 
    callbackStruct.inputProc = recordingCallback; 
    callbackStruct.inputProcRefCon = self; 
    status = AudioUnitSetProperty(audioUnit, 
            kAudioOutputUnitProperty_SetInputCallback, 
            kAudioUnitScope_Global, 
            kInputBus, 
            &callbackStruct, 
            sizeof(callbackStruct)); 

    // Set output callback 
    callbackStruct.inputProc = playbackCallback; 
    callbackStruct.inputProcRefCon = self; 
    status = AudioUnitSetProperty(audioUnit, 
            kAudioUnitProperty_SetRenderCallback, 
            kAudioUnitScope_Global, 
            kOutputBus, 
            &callbackStruct, 
            sizeof(callbackStruct)); 

    // Disable buffer allocation for the recorder (optional - do this if we want to pass in our own) 
    flag = 0; 
    status = AudioUnitSetProperty(audioUnit, 
            kAudioUnitProperty_ShouldAllocateBuffer, 
            kAudioUnitScope_Output, 
            kInputBus, 
            &flag, 
            sizeof(flag)); 


    AudioUnitInitialize(audioUnit); 
    AudioOutputUnitStart(audioUnit); 


    // 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, &audioFormat, NULL, kAudioFileFlags_EraseFile, &effectState.audioFileRef); 
    CFRelease(destinationURL); 
    NSAssert(setupErr == noErr, @"Couldn't create file for writing"); 

    setupErr = ExtAudioFileSetProperty(effectState.audioFileRef, kExtAudioFileProperty_ClientDataFormat, sizeof(AudioStreamBasicDescription), &audioFormat); 
    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"); 

    } 

la chiamata di registrazione posteriore

static OSStatus recordingCallback  (void *       inRefCon, 
             AudioUnitRenderActionFlags *  ioActionFlags, 
             const AudioTimeStamp *   inTimeStamp, 
             UInt32       inBusNumber, 
             UInt32       inNumberFrames, 
             AudioBufferList *     ioData) { 
    NSLog(@"callback"); 
    if (*ioActionFlags == kAudioUnitRenderAction_PostRender&&inBusNumber==0) 
    { 
     AudioBufferList *bufferList; // <- Fill this up with buffers (you will want to malloc it, as it's a dynamic-length list) 

     EffectState *effectState = (EffectState *)inRefCon; 
     AudioUnit rioUnit =[(MixerHostAudio*)inRefCon getAudioUnit]; 

     OSStatus status; 
     NSLog(@"de5eal el call back "); 
     // BELOW I GET THE ERROR 
     status = AudioUnitRender(rioUnit,  
           ioActionFlags, 
           inTimeStamp, 
           inBusNumber, 
           inNumberFrames, 
           bufferList); 

     if (noErr != status) { NSLog(@"AudioUnitRender error"); return noErr;} 

     // Now, we have the samples we just read sitting in buffers in bufferList 
     ExtAudioFileWriteAsync(effectState->audioFileRef, inNumberFrames, bufferList); 

    } 
    return noErr;  
} 




// then stop Recording 
- (void) stopRecord 
{ 

    AudioOutputUnitStop(audioUnit); 
    AudioUnitUninitialize(audioUnit); 
} 
+3

Non è sufficiente solo dire "questo è il mio codice" e poi inviare l'intera applicazione. Questo non conta come una domanda. –

+0

chiarire e spiegare l'intero scenario. – Sarah

+0

C'è un errore in arrivo da 'ExtAudioFileWriteAsync'? – mattjgalloway

risposta

14

In initializaeOutputUnit si è creato solo il file audio:

OSStatus setupErr = ExtAudioFileCreateWithURL(destinationURL, kAudioFileWAVEType, &audioFormat, NULL, kAudioFileFlags_EraseFile, &effectState.audioFileRef); 

passando (fotogrammi) e NULL (audiobuffer) è solo per i buffer interni INIT:

setupErr = ExtAudioFileWriteAsync(effectState.audioFileRef, 0, NULL); 

Ecco cosa non funziona nella registrazione llback:

1) ioActionFlags sono sempre 0 e inBusNumber sono sempre 1, perché questo è come si imposta il callback (kInputBus = 1):

if (*ioActionFlags == kAudioUnitRenderAction_PostRender&&inBusNumber==0) 

quindi basta rimuovere l'istruzione if.

2) Da AudioUnitRender si riceverà -50 errore, che è definito in CoreAudioTypes.h come un errore kAudio_ParamError. Questo accade da bufferList non è definito e NULL!

OSStatus status; 
status = AudioUnitRender(THIS->mAudioUnit,  
          ioActionFlags, 
          inTimeStamp, 
          kInputBus, 
          inNumberFrames, 
          &bufferList); 

if (noErr != status) { 
     printf("AudioUnitRender error: %ld", status); 
     return noErr; 
} 

Hai solo bisogno di definire un AudioBuffer valida e passarlo al AudioUnitRender, questo è il mio RenderCallback di lavoro:

static OSStatus recordingCallback  (void *      inRefCon, 
              AudioUnitRenderActionFlags *  ioActionFlags, 
              const AudioTimeStamp *   inTimeStamp, 
              UInt32       inBusNumber, 
              UInt32       inNumberFrames, 
              AudioBufferList *     ioData) { 
     double timeInSeconds = inTimeStamp->mSampleTime/kSampleRate; 
     printf("\n%fs inBusNumber: %lu inNumberFrames: %lu ", timeInSeconds, inBusNumber, inNumberFrames); 
     //printAudioUnitRenderActionFlags(ioActionFlags); 

     AudioBufferList 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); 

     ViewController* THIS = THIS = (__bridge ViewController *)inRefCon; 

     OSStatus status; 
     status = AudioUnitRender(THIS->mAudioUnit,  
           ioActionFlags, 
           inTimeStamp, 
           kInputBus, 
           inNumberFrames, 
           &bufferList); 

     if (noErr != status) { 

      printf("AudioUnitRender error: %ld", status); 
      return noErr; 
     } 

     // Now, we have the samples we just read sitting in buffers in bufferList 
     ExtAudioFileWriteAsync(THIS->mAudioFileRef, inNumberFrames, &bufferList); 

     return noErr;  
} 

In stopRecord si dovrebbe chiudere la file audio con ExtAudioFileDispose:

- (void)stopRecording:(NSTimer*)theTimer { 
     printf("\nstopRecording\n"); 
     AudioOutputUnitStop(mAudioUnit); 
     AudioUnitUninitialize(mAudioUnit); 

     OSStatus status = ExtAudioFileDispose(mAudioFileRef); 
     printf("OSStatus(ExtAudioFileDispose): %ld\n", status); 
} 

Il codice sorgente completo: http://pastebin.com/92Fyjaye

+0

Grazie mille !! +1 per la pubblicazione del codice sorgente. – Ravi

3

L'Unità audio RemoteIO non registra l'uscita audio, solo l'ingresso dal microfono . L'uscita non è collegata all'ingresso del microfono.

Se si utilizza RemoteIO per la riproduzione dell'audio, è possibile copiare la copia degli stessi buffer che si alimentano con il callback dell'output per la riproduzione audio in un writer di file. Ma è solo per i contenuti audio grezzi riprodotti tramite RemoteIO.

+0

scrivo il mio codice usando quei collegamenti con unità audio [Blog] (http://atastypixel.com/blog/using-remoteio-audio-unit/) [Domanda] (http://stackoverflow.com/questions/7118429/how-to-record-sound-produced-by-mixer-unit-output-ios-core-audio-audio-graph) che perché io uso I/o remoto per registrare l'uscita audio – khaled

+0

RemoteIO non registra l'uscita audio. Leggi invece la documentazione audio ufficiale di Apple. – hotpaw2

+0

quindi hai qualche documentazione che mi aiuti a registrare l'uscita audio dell'iPhone ??? – khaled