在做语音识别项目时候发现一个问题,识别率奇低无比……所以就把原始音频数据录下来,发现音频丢数据。

实验机器:iPhone6s iOS12

问题代码如下:

OSStatus AudioUnitInput::RecordCallback(
    void *inRefCon,
    AudioUnitRenderActionFlags *ioActionFlags,
    const AudioTimeStamp *inTimeStamp,
    UInt32 inBusNumber,
    UInt32 inNumberFrames,
    AudioBufferList *ioData)
{
  int count = 0;
  OSStatus status = noErr;

  if (inNumberFrames > 0) {
    AudioUnitInput *ars = (AudioUnitInput *)inRefCon;
    status = AudioUnitRender(ars->mRecordUnit,
                             ioActionFlags,
                             inTimeStamp,
                             inBusNumber,
                             inNumberFrames,
                             ars->recordBufList);
  } else {
    NSLog(@"inNumberFrames is %d", inNumberFrames);
  }
  return noErr;
}
…………
…………
…………
bufferByteSize = ComputeRecordBufferSize(&mRecordFormat,
                                             kBufferDurationSeconds);
    NSLog(@"Compute recorder %f seconds data buffer size is %d.",
        kBufferDurationSeconds,
        bufferByteSize);
    recordBufList = (AudioBufferList *)malloc(sizeof(AudioBufferList));
    recordBufList->mNumberBuffers = 1;
    recordBufList->mBuffers[0].mNumberChannels = 1;
    recordBufList->mBuffers[0].mDataByteSize = bufferByteSize * 2;
    recordBufList->mBuffers[0].mData = malloc(bufferByteSize * 2);​

以上代码可以看出,AudioBufferList我是在初始化的时候进行了malloc,然后在recordCallback中进行数据获取。理论上这样是没问题的,很多教程这么写。mData的malloc大小是通过计算的,bufferByteSize是20ms 16k 16bit的大小,即640。但是我发现recordCallback中frame数为341,即682字节,所以我就malloc了640的两倍。这里还有一个很好玩的点,就是如果我把playout开起来进行echo,在playCallback进行数据保存,这样获取的数据就非常正常。

以下给出两种解决方法:

1. 把malloc放在recordCallback中进行,记得用完后要free!

OSStatus AudioUnitInput::RecordCallback(
    void *inRefCon,
    AudioUnitRenderActionFlags *ioActionFlags,
    const AudioTimeStamp *inTimeStamp,
    UInt32 inBusNumber,
    UInt32 inNumberFrames,
    AudioBufferList *ioData)
{
  int count = 0;
  OSStatus status = noErr;
  UInt16 numSamples = inNumberFrames*1;

  if (inNumberFrames > 0) {
    AudioUnitInput *ars = (AudioUnitInput *)inRefCon;
    ars->recordBufList = (AudioBufferList *)malloc(sizeof(AudioBufferList));
    ars->recordBufList->mNumberBuffers = 1;
    ars->recordBufList->mBuffers[0].mNumberChannels = 1;
    ars->recordBufList->mBuffers[0].mDataByteSize = numSamples * sizeof(UInt16);
    ars->recordBufList->mBuffers[0].mData = malloc(numSamples * sizeof(UInt16));
    status = AudioUnitRender(ars->mRecordUnit,
                             ioActionFlags,
                             inTimeStamp,
                             inBusNumber,
                             inNumberFrames,
                             ars->recordBufList);
  } else {
    NSLog(@"inNumberFrames is %d", inNumberFrames);
  }
  return noErr;
}

 

2.还有一种是不用malloc了,也是在recordCallback中分配一个AudioBufferList

OSStatus AudioUnitInput::RecordCallback(
    void *inRefCon,
    AudioUnitRenderActionFlags *ioActionFlags,
    const AudioTimeStamp *inTimeStamp,
    UInt32 inBusNumber,
    UInt32 inNumberFrames,
    AudioBufferList *ioData)
{
  int count = 0;
  OSStatus status = noErr;
  AudioBufferList bufferList;
  UInt16 numSamples = inNumberFrames*1;
  UInt16 samples[numSamples];
  memset(&samples, 0, sizeof(samples));
  bufferList.mNumberBuffers = 1;
  bufferList.mBuffers[0].mData = samples;
  bufferList.mBuffers[0].mNumberChannels = 1;
  bufferList.mBuffers[0].mDataByteSize = numSamples * sizeof(UInt16);

  if (inNumberFrames > 0) {
    AudioUnitInput *ars = (AudioUnitInput *)inRefCon;
    status = AudioUnitRender(ars->mRecordUnit,
                             ioActionFlags,
                             inTimeStamp,
                             inBusNumber,
                             inNumberFrames,
                             &bufferList);
  } else {
    NSLog(@"inNumberFrames is %d", inNumberFrames);
  }
  return noErr;
}

具体为什么还不是很清楚,难道是堆栈的问题?

 

参考文章:https://blog.csdn.net/wuxinyanzi/article/details/49782969

感谢

 

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐