音频单元背景冲突

Posted

技术标签:

【中文标题】音频单元背景冲突【英文标题】:Audio Unit background conflict 【发布时间】:2013-06-09 17:22:09 【问题描述】:

我有一个使用音频单元的音频分析应用程序,当应用程序单独运行时,它可以完美运行。但是,如果后台运行其他音频应用,AudioUnitRender 会返回 -50 错误。

有谁知道解决这个问题的方法,以便 AudioUnitRender 即使在其他音频应用程序正在运行时也能正常工作?

提前致谢。

音频会话启动

AVAudiosession *session = [AVAudioSession sharedInstance];
[session setPreferredHardwareSampleRate:sampleRate error:&err];
[session setCategory:AVAudioSessionCategoryRecord error:&err];
[session setActive:YES error:&err];
[session setMode:setMode:AVAudioSessionModeMeasurement error:&err];
[session setDelegate:listener];
UInt32 audioRouteOverride = kAudioSessionOverrideAudioRoute_None;
AudioSessionSetProperty (kAudioSessionProperty_OverrideAudioRoute,sizeof (audioRouteOverride),&audioRouteOverride);

I/O 单元说明:

    OSStatus err;
AudioComponentDescription ioUnitDescription;
ioUnitDescription.componentType = kAudioUnitType_Output;
ioUnitDescription.componentSubType = kAudioUnitSubType_RemoteIO;
ioUnitDescription.componentManufacturer = kAudioUnitManufacturer_Apple;
ioUnitDescrition.componentFlags = 0;
ioUnitDescription.componentFlagsMask = 0;

// Declare and instantiate an audio processing graph
NewAUGraph(&processingGraph);

// Add an audio unit node to the graph, then instantiate the audio unit.
/* 
 An AUNode is an opaque type that represents an audio unit in the context
 of an audio processing graph. You receive a reference to the new audio unit
 instance, in the ioUnit parameter, on output of the AUGraphNodeInfo 
 function call.
 */
AUNode ioNode;
AUGraphAddNode(processingGraph, &ioUnitDescription, &ioNode);

AUGraphOpen(processingGraph); // indirectly performs audio unit instantiation

// Obtain a reference to the newly-instantiated I/O unit. Each Audio Unit
// requires its own configuration.
AUGraphNodeInfo(processingGraph, ioNode, NULL, &ioUnit);

// Initialize below.
AURenderCallbackStruct callbackStruct = 0;
UInt32 enableInput;
UInt32 enableOutput;

// Enable input and disable output.
enableInput = 1; enableOutput = 0;
callbackStruct.inputProc = RenderFFTCallback;
callbackStruct.inputProcRefCon = (__bridge void*)self;

err = AudioUnitSetProperty(ioUnit, kAudioOutputUnitProperty_EnableIO, 
                           kAudioUnitScope_Input, 
                           kInputBus, &enableInput, sizeof(enableInput));

err = AudioUnitSetProperty(ioUnit, kAudioOutputUnitProperty_EnableIO, 
                           kAudioUnitScope_Output, 
                           kOutputBus, &enableOutput, sizeof(enableOutput));

err = AudioUnitSetProperty(ioUnit, kAudioOutputUnitProperty_SetInputCallback, 
                           kAudioUnitScope_Input, 
                           kOutputBus, &callbackStruct, sizeof(callbackStruct));


// Set the stream format.
size_t bytesPerSample = [self ASBDForSoundMode];

err = AudioUnitSetProperty(ioUnit, kAudioUnitProperty_StreamFormat, 
                           kAudioUnitScope_Output, 
                           kInputBus, &streamFormat, sizeof(streamFormat));

err = AudioUnitSetProperty(ioUnit, kAudioUnitProperty_StreamFormat, 
                           kAudioUnitScope_Input, 
                           kOutputBus, &streamFormat, sizeof(streamFormat));



// Disable system buffer allocation. We'll do it ourselves.
UInt32 flag = 1;
err = AudioUnitSetProperty(ioUnit, kAudioUnitProperty_ShouldAllocateBuffer,
                           kAudioUnitScope_Output, 
                           kInputBus, &flag, sizeof(flag));

渲染回调:

RIOInterface* THIS = (__bridge_transfer RIOInterface *)inRefCon;
COMPLEX_SPLIT A = THIS->A;
void *dataBuffer = THIS->dataBuffer;
float *outputBuffer = THIS->outputBuffer;
FFTSetup fftSetup = THIS->fftSetup;
float *hammingWeights = THIS->hammingWeights;

uint32_t log2n = THIS->log2n;
uint32_t n = THIS->n;
uint32_t nOver2 = THIS->nOver2;
uint32_t stride = 1;
int bufferCapacity = THIS->bufferCapacity;
SInt16 index = THIS->index;

AudioUnit rioUnit = THIS->ioUnit;
OSStatus renderErr;
UInt32 bus1 = 1;


renderErr = AudioUnitRender(rioUnit, ioActionFlags, 
                            inTimeStamp, bus1, inNumberFrames, THIS->bufferList); 

if (renderErr < 0) 
    return renderErr;

【问题讨论】:

【参考方案1】:

我发现当另一个 AVAudioSession 在另一个应用程序中处于活动状态时会发生此问题,在这种情况下,第一个启动的 AVAudioSession 的设置优先于我的设置。我试图将采样频率设置为 22050,但如果其他音频会话将其设置为 44100,则它仍保持在 44100。

我通过使我的代码“适应”其他设置来解决问题,例如就缓冲区大小而言,因此它仍然可以有效地(如果不是最佳地)使用与我偏好不同的音频设置。

【讨论】:

以上是关于音频单元背景冲突的主要内容,如果未能解决你的问题,请参考以下文章

音频单元无法在 Logic 中运行; .exp _Entry 在链接器中未定义

如何保存和恢复作为音频单元主机的音频单元状态

音频单元主机需要做啥才能使用非 Apple 音频单元?

如何使用音频单元 osx 从设备音频输入中获取音频

Core Audio(音频单元)音频会话和 MPVolumeView

当我需要自定义音频效果时,我是不是需要处理音频单元,或者我可以依赖音频队列服务?