0

我已经在这几天了。我对框架的音频单元层不是很熟悉。有人可以给我指出一些完整的例子,说明我如何让用户记录,而不是用 x 个间隔即时写入文件。例如,用户按记录,每 10 秒,我想写入一个文件,第 11 秒,它会写入下一个文件,在第 21 秒,它是相同的。所以当我录制 25 秒的音频时,它会产生 3 个不同的文件。

我已经用 AVCapture 试过这个,但它会在中间产生点击和弹出。我已经阅读了它,这是由于读写操作之间的毫秒数。我已经尝试过音频队列服务,但知道我正在开发的应用程序,我需要完全控制音频层;所以我决定使用音频单元。

4

1 回答 1

0

我想我越来越近了……还是很迷茫。我最终使用了 The Amazing Audio Engine (TAAE)。我现在正在查看 AEAudioReceiver,我的回调代码如下所示。我认为逻辑上是正确的,但我认为它实施正确。

手头的任务:以 AAC 格式记录约 5 秒的片段。

尝试:使用 AEAudioReciever 回调并将 AudioBufferList 存储在循环缓冲区中。跟踪在录音机类中接收到的音频秒数;一旦超过 5 秒标记(它可能会超过一点,但不会超过 6 秒)。调用 Obj-c 方法使用 AEAudioFileWriter 写入文件

结果:没用,录音听起来很慢,而且经常有很多噪音;我可以听到一些录音;所以我知道那里有一些数据,但就像我丢失了很多数据一样。我什至不确定如何调试它(我会继续尝试,但现在很迷茫)。

另一个项目是转换为 AAC,我是先以 PCM 格式写入文件而不是转换为 AAC,还是可以仅将音频段转换为 AAC?

提前感谢您的帮助!

----- 循环缓冲区初始化 -----

//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 回调 ------

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;
}
}

---- 写入文件(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];
}

----- 音频控制器 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;
于 2015-01-15T06:38:23.423 回答