使用单声道输入和立体声输出设置音频单元 iOS

Posted

技术标签:

【中文标题】使用单声道输入和立体声输出设置音频单元 iOS【英文标题】:Setting up audio unit iOS with mono input and stereo output 【发布时间】:2014-04-14 21:07:54 【问题描述】:

我正在尝试设置一个能够进行单声道输入和立体声输出的音频单元。打算通过左声道输出播放正弦波音调,并通过右声道输出周期性地播放不同的符号波。

我收到错误消息,

'NSInternalInconsistencyException', reason: ' Error initialing unit: -50;

当我尝试在这里初始化我的音频单元时,

// Initialize audio unit
OSErr err = AudioUnitInitialize(self.ioUnit);
NSAssert1(err == noErr, @"Error initializing unit: %hd", err);

我认为这与我设置音频单元的方式有关,

// Audio component description
AudioComponentDescription desc;
desc.componentType          = kAudioUnitType_Output;
desc.componentSubType       = kAudioUnitSubType_RemoteIO;
desc.componentManufacturer  = kAudioUnitManufacturer_Apple;
desc.componentFlags         = 0;
desc.componentFlagsMask     = 0;

// Get component
AudioComponent inputComponent = AudioComponentFindNext(NULL, &desc);

// Get Audio units
AudioComponentInstanceNew(inputComponent, &ioUnit);

// Enable input, which disabled by default. Output enable by default
UInt32 enableInput = 1;
AudioUnitSetProperty(ioUnit,
                     kAudioOutputUnitProperty_EnableIO,
                     kAudioUnitScope_Input,
                     kInputBus,
                     &enableInput,
                     sizeof(enableInput));

AudiostreamBasicDescription monoStreamFormat;
monoStreamFormat.mSampleRate          = 44100.00;
monoStreamFormat.mFormatID            = kAudioFormatLinearPCM;
monoStreamFormat.mFormatFlags         = kAudioFormatFlagsAudioUnitCanonical;
monoStreamFormat.mBytesPerPacket      = 2;
monoStreamFormat.mBytesPerFrame       = 2;
monoStreamFormat.mFramesPerPacket     = 1;
monoStreamFormat.mChannelsPerFrame    = 1;
monoStreamFormat.mBitsPerChannel      = 16;

// Apply format to input of ioUnit
AudioUnitSetProperty(ioUnit,
                     kAudioUnitProperty_StreamFormat,
                     kAudioUnitScope_Input,
                     kInputBus,
                     &monoStreamFormat,
                     sizeof(monoStreamFormat));


AudioStreamBasicDescription stereoStreamFormat;
stereoStreamFormat.mSampleRate          = 44100.00;
stereoStreamFormat.mFormatID            = kAudioFormatLinearPCM;
stereoStreamFormat.mFormatFlags         = kAudioFormatFlagsAudioUnitCanonical;
stereoStreamFormat.mBytesPerPacket      = 4;
stereoStreamFormat.mBytesPerFrame       = 4;
stereoStreamFormat.mFramesPerPacket     = 1;
stereoStreamFormat.mChannelsPerFrame    = 2;
stereoStreamFormat.mBitsPerChannel      = 32;

// Apply format to output of ioUnit
AudioUnitSetProperty(ioUnit,
                     kAudioUnitProperty_StreamFormat,
                     kAudioUnitScope_Output,
                     kOutputBus,
                     &stereoStreamFormat,
                     sizeof(stereoStreamFormat));

// Set input callback
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = inputCallback;
callbackStruct.inputProcRefCon = (__bridge void *)(self);
AudioUnitSetProperty(ioUnit,
                     kAudioUnitProperty_SetRenderCallback,
                     kAudioUnitScope_Global,
                     kInputBus,
                     &callbackStruct,
                     sizeof(callbackStruct));

// Set output callback
callbackStruct.inputProc = outputCallback;
callbackStruct.inputProcRefCon = (__bridge void *)(self);
AudioUnitSetProperty(ioUnit,
                     kAudioUnitProperty_SetRenderCallback,
                     kAudioUnitScope_Global,
                     kOutputBus,
                     &callbackStruct,
                     sizeof(callbackStruct));

但我在返回的错误代码 -50 上找不到任何内容,所以我不确定它不喜欢什么。我在最后期限,所以非常感谢任何帮助。

【问题讨论】:

-50 is paramErr : 用户参数列表错误 感谢您的回复,但我看不出我的代码中可能出现的位置,您@sbooth 吗? $ macerror -50 同意你的看法。 你有想过这个吗? 【参考方案1】:

kAudioFormatFlagsAudioUnitCanonical 是 32 位 8.24 定点格式。这意味着 mBytesPerFrame 对于单声道应该是 4,对于立体声应该是 8,对于立体声和单声道 mBitsPerChannel 应该是 32。将其设置为 16 位可能会产生此错误。

也就是说,我怀疑你想要 8.24。您可能希望 kAudioFormatFlagsCanonical 获得标准的 16 位音频。或者,如果您想要 32 位,请使用 32 位浮点数 (kAudioFormatFlagIsFloat | kAudioFormatFlagsNativeEndian | kAudioFormatFlagIsPacked | kAudioFormatFlagIsNonInterleaved)。在处理过程中更容易处理数学。

此外,您正在设置虚拟输入和输出的格式,而不是客户端输入和输出,我认为这不是您想要的。这里的 API 比较混乱,但是要设置客户端输入格式,请使用 kAudioUnitScope_Input、kOutputBus。这里的逻辑是您正在设置内部 Core Audio input 转换器单元的 output 格式,从代码的角度来看,它是输入音频.令人困惑,我知道。有关详细信息,请参阅音频单元文档。同样,要设置客户端输出格式,请使用 kAudioUnitScope_Output、kInputBus。

【讨论】:

感谢您的回复。我将对 IO 格式进行这些更改,看看它是否能解决我的错误(你说得对,命名对于 IO 格式来说是违反直觉的)。 根据您的回复,我假设在设置 IO 回调时,我还需要将 kOutputBuskInputBus 切换。 对不起,我弄错了。对于 8.24 的立体声,mBytesPerFrame 应为 8。 我不确定。我认同。我只设置了一个回调,我认为这就是你真正需要的。你得到输入样本,处理它们,然后输出它们,所有这些都在同一个回调中。所以它会是 kAudioUnitProperty_SetRenderCallback、kAudioUnitScope_Input、kOutputBus。 请注意,为了启用输入,您确实使用输入范围和输入总线。【参考方案2】:

每个通道 32 位太多位,无法将 2 个通道放入 4 个字节。试试 16。

【讨论】:

尝试了您的建议,但在初始化调用期间我仍然得到相同的error: -50 (AudioUnitInitialize(self.ioUnit))。 @hotpaw2- 还有其他想法吗?

以上是关于使用单声道输入和立体声输出设置音频单元 iOS的主要内容,如果未能解决你的问题,请参考以下文章

如何渲染来自远程 I/O 音频单元的系统输入并以立体声播放这些样本

AVPlayer 播放单声道音频立体声->单声道

在 C 中将立体声 wav 转换为单声道

使用音频工具 sox,我如何确定立体声录音是不是实际上是单声道?

将单声道音频数据传递给 AVAudioEnvironmentNode

谁知道mp3单声道怎么转立体声