AudioUnitInitialize 在初始化 AudioComponentInstance 时抛出错误

Posted

技术标签:

【中文标题】AudioUnitInitialize 在初始化 AudioComponentInstance 时抛出错误【英文标题】:AudioUnitInitialize throws error while initializing AudioComponentInstance 【发布时间】:2012-05-15 11:24:02 【问题描述】:

我正在使用下面的代码来初始化我的音频组件。

-(void) startListeningWithCoreAudio

     NSError *error = nil;

     [[AVAudiosession sharedInstance] setCategory: AVAudioSessionCategoryPlayAndRecord error:&error];
     if (error) 
          NSLog(@"error setting up audio session: %@", [error localizedDescription]);

     [[AVAudioSession sharedInstance] setDelegate:self];

     OSStatus status = AudioSessionSetActive(YES);
     checkStatus(status);

          // Find the apple mic
    AudioComponentDescription desc;
    desc.componentType = kAudioUnitType_Output;
    desc.componentSubType = kAudioUnitSubType_VoiceProcessingIO;
    desc.componentFlags = 0;
    desc.componentFlagsMask = 0;
    desc.componentManufacturer = kAudioUnitManufacturer_Apple;

    AudioComponent inputComponent = AudioComponentFindNext( NULL, &desc );
    status = AudioComponentInstanceNew( inputComponent, &kAudioUnit );
    checkStatus( status );

          // enable mic output as our input
    UInt32 flag = 1;
    status = AudioUnitSetProperty( kAudioUnit, kAudioOutputUnitProperty_EnableIO, kAudioUnitScope_Input, kInputBus, &flag, sizeof(flag) );
    checkStatus(status);


          // Define mic output audio format
    AudioStreamBasicDescription audioFormat;
    audioFormat.mSampleRate         = 16000.0;
    audioFormat.mFormatID           = kAudioFormatLinearPCM;
    audioFormat.mFormatFlags        = kAudioFormatFlagIsSignedInteger | kAudioFormatFlagIsPacked;
    audioFormat.mFramesPerPacket    = 1;
    audioFormat.mChannelsPerFrame   = 1;
    audioFormat.mBitsPerChannel     = 16;
    audioFormat.mBytesPerPacket     = 2;
    audioFormat.mBytesPerFrame      = 2;

    status = AudioUnitSetProperty( kAudioUnit, kAudioUnitProperty_StreamFormat, kAudioUnitScope_Output, kInputBus, &audioFormat, sizeof(audioFormat) );
    checkStatus(status);

          // Define our callback methods
    AURenderCallbackStruct callbackStruct;
    callbackStruct.inputProc = recordingCallback;
    callbackStruct.inputProcRefCon = self;
    status = AudioUnitSetProperty( kAudioUnit, kAudioOutputUnitProperty_SetInputCallback, kAudioUnitScope_Global, kInputBus, &callbackStruct, sizeof(callbackStruct) );
    checkStatus(status);

          // By pass voice processing
     UInt32 audiobypassProcessing = [[NSUserDefaults standardUserDefaults] boolForKey:VOICE_BY_PASS_PROCESSING];
     status = AudioUnitSetProperty(kAudioUnit, kAUVoiceIOProperty_BypassVoiceProcessing, 
                                   kAudioUnitScope_Global, kInputBus, &audiobypassProcessing, sizeof(audiobypassProcessing));
     checkStatus(status);

          // Automatic Gain Control
     UInt32 audioAGC = [[NSUserDefaults standardUserDefaults]boolForKey:VOICE_AGC];
     status = AudioUnitSetProperty(kAudioUnit, kAUVoiceIOProperty_VoiceProcessingEnableAGC, 
                                   kAudioUnitScope_Global, kInputBus, &audioAGC, sizeof(audioAGC));
     checkStatus(status);

          //Non Audio Voice Ducking
     UInt32 audioDucking = [[NSUserDefaults standardUserDefaults]boolForKey:VOICE_DUCKING];
     status = AudioUnitSetProperty(kAudioUnit, kAUVoiceIOProperty_DuckNonVoiceAudio, 
                                   kAudioUnitScope_Global, kInputBus, &audioDucking, sizeof(audioDucking));
     checkStatus(status);

          //Audio Quality
     UInt32 quality = [[NSUserDefaults standardUserDefaults]integerForKey:VOICE_QUALITY];
     status = AudioUnitSetProperty(kAudioUnit, kAUVoiceIOProperty_VoiceProcessingQuality, 
                                   kAudioUnitScope_Global, kInputBus, &quality, sizeof(quality));
     checkStatus(status);

     status = AudioUnitInitialize(kAudioUnit);
     checkStatus(status);

    status = AudioOutputUnitStart( kAudioUnit );
    checkStatus(status);

    UInt32 audioRoute = (UInt32)kAudioSessionOverrideAudioRoute_Speaker;
    status = AudioSessionSetProperty(kAudioSessionProperty_OverrideAudioRoute, sizeof (audioRoute), &audioRoute);
    checkStatus(status);     



-(void) stopListeningWithCoreAudio
 
    OSStatus     status = AudioUnitUninitialize( kAudioUnit );
     checkStatus(status);

     status = AudioOutputUnitStop( kAudioUnit );
    checkStatus( status );

//     if(kAudioUnit)
//     
//          status = AudioComponentInstanceDispose(kAudioUnit);
//          checkStatus(status);
//          kAudioUnit = nil;
//     

    status = AudioSessionSetActive(NO);
     checkStatus(status);

     NSError *error = nil;
    [[AVAudioSession sharedInstance] setCategory: AVAudioSessionCategorySoloAmbient error:&error];
    if (error)
          NSLog(@"error setting up audio session: %@", [error localizedDescription]);

它第一次运行良好。我的意思是startListeningWithCoreAudio 被按钮按下事件调用。它可以很好地录制/处理音频。在其他事件中,我打电话给stopListeningWithCoreAudio 来停止录制/处理音频。

当我再次尝试调用函数startListeningWithCoreAudio 时,问题就来了。它为两个函数抛出错误。 AudioUnitInitializeAudioOutputUnitStartstartListeningWithCoreAudio 调用。

谁能帮我看看有什么问题?

【问题讨论】:

【参考方案1】:

我找到了解决方案。 如果我们背靠背调用下面的函数,就会产生问题。

extern OSStatus AudioUnitUninitialize(AudioUnit inUnit)                     
extern OSStatus AudioComponentInstanceDispose(AudioComponentInstance inInstance)

所以,我通过以下方式在主线程上调用了 dispose 方法。

[self performSelectorOnMainThread:@selector(disposeCoreAudio) withObject:nil waitUntilDone:NO];

-(void) disposeCoreAudio

     OSStatus status = AudioComponentInstanceDispose(kAudioUnit);
     kAudioUnit = nil;

它解决了这个问题。因此,正确的顺序是停止录制,取消初始化录制器,然后在主线程上释放录制器。

【讨论】:

【参考方案2】:

一个可能的问题是您的代码试图在停止之前取消初始化正在运行的音频单元。

【讨论】:

感谢您的回答。为此+1。实际原因是音频会话。我在应用程序处于活动状态时设置会话,并在应用程序进入后台时删除会话。之后没有音频单元的初始化。

以上是关于AudioUnitInitialize 在初始化 AudioComponentInstance 时抛出错误的主要内容,如果未能解决你的问题,请参考以下文章

CoreAudio:AudioUnit 既不能停止也不能未初始化

挂钩 C 函数

在初始化列表中初始化一个常量大小的数组

为啥在没有初始化任何内容时使用初始化列表?

以下短语在 C++ 中是啥意思:零初始化、默认初始化和值初始化?

初始化变量:在所有成员初始化之前由闭包捕获的“自我”