2012-07-18 123 views
1

我一直在这个昨天挣扎,真的很感激帮助。音频单元录制噪音

我有一个多通道混音器音频单元,分配给每个通道的回调函数在调用时填充所需的音频缓冲区。我试图通过将数据写入文件来在相同的回调中进行记录。

此刻音频记录为噪音,如果我不打电话给AudioUnitRender,如果我确实打电话给我,我会得到两个错误。错误10877和错误50.

回调的记录代码看起来像这样

if (recordingOn) 
{ 
    AudioBufferList *bufferList = (AudioBufferList *)malloc(sizeof(AudioBuffer)); 

    SInt16 samples[inNumberFrames]; 
    memset (&samples, 0, sizeof (samples)); 

    bufferList->mNumberBuffers = 1; 
    bufferList->mBuffers[0].mData = samples; 
    bufferList->mBuffers[0].mNumberChannels = 2; 
    bufferList->mBuffers[0].mDataByteSize = inNumberFrames*sizeof(SInt16); 

    OSStatus status; 
    status = AudioUnitRender(audioObject.mixerUnit,  
          ioActionFlags, 
          inTimeStamp, 
          inBusNumber, 
          inNumberFrames, 
          bufferList); 

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

    ExtAudioFileWriteAsync(audioObject.recordingFile, inNumberFrames, bufferList); 
} 

是不是正确的在每个通道的回调将数据写入或者我应该把它连接到远程I/O单元?

我使用LPCM和ASBD的记录文件(CAF)是

recordingFormat.mFormatID = kAudioFormatLinearPCM; 
recordingFormat.mFormatFlags = kAudioFormatFlagIsSignedInteger | 
kAudioFormatFlagIsBigEndian | kAudioFormatFlagIsPacked; 
recordingFormat.mSampleRate = 44100; 
recordingFormat.mChannelsPerFrame = 2; 
recordingFormat.mFramesPerPacket = 1; 
recordingFormat.mBytesPerPacket = recordingFormat.mChannelsPerFrame * sizeof (SInt16); 
recordingFormat.mBytesPerFrame = recordingFormat.mChannelsPerFrame * sizeof (SInt16); 
recordingFormat.mBitsPerChannel = 16; 

我真的不知道我在做什么错。

在写入文件之前,立体声如何影响记录数据的处理方式?

回答

2

有几个问题。如果您试图记录最终的“混音”,则可以使用AudioUnitAddRenderNotify(iounit,callback,file)在I/O单元上添加回调。回调然后简单地采用ioData并将其传递给ExtAudioFileWriteAsync(...)。所以,你也不需要创建任何缓冲区。附注:在渲染线程中分配内存不好。你应该避免渲染回调中的所有系统调用。不能保证这些调用将在音频线程的非常严格的最后期限内执行。因此,为什么有一个ExtAudioFileWriteAsync,它会考虑到这一点,并在另一个线程中写入磁盘。

+0

我真的很感激帮助。这些音频问题的意见越来越少。好吧,我会补充一点,看看它是如何发展的。所以在这个添加的录音回调中,我可以将&ioData传递给writeAsync调用?关于回调中的分配,是的,它真的很糟糕,我的头目前一团糟,需要一步一步分解。我也在回调中做这个[[NSNotificationCenter defaultCenter] postNotificationName:MixerAudioObjectSampleFinishedPlayingNotification object:nil];以便通过kMultiChannelMixerParam_Enable将完成的通道设置为无声。这是不好的权利? – jarryd 2012-07-18 12:39:06

+0

是的,那很糟糕。常用的方法是在主线程中进行轮询并收听/观看数据。并且该数据应该是一个c结构或C++对象。是的,ioData在缓冲区列表中具有渲染的音频。 – 2012-07-19 23:15:53

0

我找到了一个演示代码,也许有用4 U;

DEMO网址:https://github.com/JNYJdev/AudioUnit

OR

博客:http://atastypixel.com/blog/using-remoteio-audio-unit/

static OSStatus recordingCallback(void *inRefCon, 
          AudioUnitRenderActionFlags *ioActionFlags, 
          const AudioTimeStamp *inTimeStamp, 
          UInt32 inBusNumber, 
          UInt32 inNumberFrames, 
          AudioBufferList *ioData) { 
// Because of the way our audio format (setup below) is chosen: 
// we only need 1 buffer, since it is mono 
// Samples are 16 bits = 2 bytes. 
// 1 frame includes only 1 sample 

AudioBuffer buffer; 

buffer.mNumberChannels = 1; 
buffer.mDataByteSize = inNumberFrames * 2; 
buffer.mData = malloc(inNumberFrames * 2); 

// Put buffer in a AudioBufferList 
AudioBufferList bufferList; 
bufferList.mNumberBuffers = 1; 
bufferList.mBuffers[0] = buffer; 

// Then: 
// Obtain recorded samples 

OSStatus status; 

status = AudioUnitRender([iosAudio audioUnit], 
        ioActionFlags, 
        inTimeStamp, 
        inBusNumber, 
        inNumberFrames, 
        &bufferList); 
checkStatus(status); 

// Now, we have the samples we just read sitting in buffers in bufferList 
// Process the new data 
[iosAudio processAudio:&bufferList]; 

// release the malloc'ed data in the buffer we created earlier 
free(bufferList.mBuffers[0].mData); 

return noErr; 
}