Recording audio with Audio Unit with files segmented in X number of seconds each

旧城冷巷雨未停 提交于 2019-12-12 01:55:19

问题


I've been at this for a few days now. I'm not very familiar with the Audio Unit layer of the framework. Could someone point me to some full example on how I can let user record and than write the file on the fly with x number of interval. For example, user press record, every 10 seconds, I want to write to a file, on the 11th second, it'll write to the next file and in the 21th second, it's the same thing. So when I record 25 seconds word of audio, it'll produce 3 different files.

I've tried this with AVCapture but it produce clicks and pops in the middle. I've read up on it, it is due to the milliseconds between the read and write operations. I've tried Audio Queue Services but knowing the app I'm working on, I'll need full control over the audio layer; so I've decided to go with Audio Unit.


回答1:


I think I'm getting closer...still pretty lost. I ended up using The Amazing Audio Engine (TAAE). I'm now looking at AEAudioReceiver, my callback code looks like this. I think logically is right but I don' think it's implemented correctly.

The task at hand: Record ~5-second segments in AAC format.

The attempt: Use the AEAudioReciever callback and store the AudioBufferList in the circular buffer. Track the number of seconds of audio have received in the recorder class; once it pass the 5 seconds mark (it can be a little bit over but not 6 seconds). Call Obj-c method to write the file using the AEAudioFileWriter

The outcome: Didn't work, the recordings sounded very slow and lots of noise constantly; I can hear some of the record audio; so I know some data is there but it's like I'm losing a lot of data. I'm not even sure how to debug this (I'll continue to try but pretty lost at the moment).

Another item is converting to AAC, do I write the file first in PCM format than convert to AAC or is it possible to convert just the audio segment to AAC?

Thanks ahead for helping!

----- Circular buffer init -----

//trying to get 5 seconds audio, how do I know what the length is if I don't know the frame size yet? and is that even the right question to ask?
TPCircularBufferInit(&_buffer, 1024 * 256);  

----- AEAudioReceiver callback ------

static void receiverCallback(__unsafe_unretained MyAudioRecorder *THIS,
                         __unsafe_unretained AEAudioController *audioController,
                         void *source,
                         const AudioTimeStamp *time,
                         UInt32 frames,
                         AudioBufferList *audio) {
//store the audio into the buffer
TPCircularBufferCopyAudioBufferList(&THIS->_buffer, audio, time, kTPCircularBufferCopyAll, NULL);

//increase the time interval to track by THIS    
THIS.numberOfSecondInCurrentRecording += AEConvertFramesToSeconds(THIS.audioController, frames);

//if number of seconds passed an interval of 5 seconds, than write the last 5 seconds of the buffer to a file
if (THIS.numberOfSecondInCurrentRecording > 5 * THIS->_currentSegment + 1) {

    NSLog(@"Segment %d is full, writing file", THIS->_currentSegment);
    [THIS writeBufferToFile];

   //segment tracking variables
    THIS->_numberOfReceiverLoop = 0;
    THIS.lastTimeStamp = nil;
    THIS->_currentSegment += 1;
} else {
    THIS->_numberOfReceiverLoop += 1;
}

// Do something with 'audio'
if (!THIS.lastTimeStamp) {
    THIS.lastTimeStamp = (AudioTimeStamp *)time;
}
}

---- Writing to file (method inside of the MyAudioRecorderClass) ----

- (void)writeBufferToFileHandler {

NSString *documentsFolder = [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)
                             objectAtIndex:0];

NSString *filePath = [documentsFolder stringByAppendingPathComponent:[NSString stringWithFormat:@"Segment_%d.aiff", _currentSegment]];

NSError *error = nil;

//setup audio writer, should the buffer be converted to aac first or save the file than convert; and how the heck do you do that?
AEAudioFileWriter *writeFile = [[AEAudioFileWriter alloc] initWithAudioDescription:_audioController.inputAudioDescription];
[writeFile beginWritingToFileAtPath:filePath fileType:kAudioFileAIFFType error:&error];

if (error) {
    NSLog(@"Error in init. the file: %@", error);
    return;
}

int i = 1;
//loop to write all the AudioBufferLists that is in the Circular Buffer; retrieve the ones based off of the _lastTimeStamp; but I had it in NULL too and worked the same way.
while (1) {

//NSLog(@"Processing buffer file list for segment [%d] and buffer index [%d]", _currentSegment, i);
    i += 1;
    // Discard any buffers with an incompatible format, in the event of a format change

    AudioBufferList *nextBuffer = TPCircularBufferNextBufferList(&_buffer, _lastTimeStamp);
    Float32 *frame = (Float32*) &nextBuffer->mBuffers[0].mData;

    //if buffer runs out, than we are done writing it and exit loop to close the file       
    if ( !nextBuffer ) {
        NSLog(@"Ran out of frames, there were [%d] AudioBufferList", i - 1);
        break;
    }
    //Adding audio using AudioFileWriter, is the length correct?
    OSStatus status = AEAudioFileWriterAddAudio(writeFile, nextBuffer, sizeof(nextBuffer->mBuffers[0].mDataByteSize));
    if (status) {
      NSLog(@"Writing Error? %d", status);
    }

    //consume/clear the buffer
    TPCircularBufferConsumeNextBufferList(&_buffer);
}

//close the file and hope it worked
[writeFile finishWriting];
}

----- Audio Controller AudioStreamBasicDescription ------

//interleaved16BitStereoAudioDescription
AudioStreamBasicDescription audioDescription;
memset(&audioDescription, 0, sizeof(audioDescription));
audioDescription.mFormatID          = kAudioFormatLinearPCM;
audioDescription.mFormatFlags       = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked | kAudioFormatFlagsNativeEndian;
audioDescription.mChannelsPerFrame  = 2;
audioDescription.mBytesPerPacket    = sizeof(SInt16)*audioDescription.mChannelsPerFrame;
audioDescription.mFramesPerPacket   = 1;
audioDescription.mBytesPerFrame     = sizeof(SInt16)*audioDescription.mChannelsPerFrame;
audioDescription.mBitsPerChannel    = 8 * sizeof(SInt16);
audioDescription.mSampleRate        = 44100.0;


来源:https://stackoverflow.com/questions/27893428/recording-audio-with-audio-unit-with-files-segmented-in-x-number-of-seconds-each

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!