Remote I/O 音频单元是不是设置缓冲区中的通道数?
Posted
技术标签:
【中文标题】Remote I/O 音频单元是不是设置缓冲区中的通道数?【英文标题】:Does the Remote I/O audio unit set the number of channels in the buffer?Remote I/O 音频单元是否设置缓冲区中的通道数? 【发布时间】:2013-11-13 18:37:36 【问题描述】:我正在使用kxmovie(它是一个基于 ffmpeg 的视频播放器)作为应用程序的基础,并且我试图弄清楚 RemoteI/O 单元在唯一连接到设备时如何在 ios 上工作是耳机,我们正在播放超过 2 个声道的曲目(比如环绕 6 声道)。似乎它与输出通道设置一起使用,缓冲区只有 2 个通道。这是因为 Core Audio 的拉式结构吗?如果是这样,轨道中的其他频道会发生什么?它们是被下混还是被忽略了?
连接到 remoteio 单元的渲染回调代码在这里:
- (BOOL) renderFrames: (UInt32) numFrames
ioData: (AudioBufferList *) ioData
NSLog(@"Number of channels in buffer: %lu",ioData->mNumberBuffers);
for (int iBuffer=0; iBuffer < ioData->mNumberBuffers; ++iBuffer)
memset(ioData->mBuffers[iBuffer].mData, 0, ioData->mBuffers[iBuffer].mDataByteSize);
if (_playing && _outputBlock )
// Collect data to render from the callbacks
_outputBlock(_outData, numFrames, _numOutputChannels);
// Put the rendered data into the output buffer
if (_numBytesPerSample == 4) // then we've already got floats
float zero = 0.0;
for (int iBuffer=0; iBuffer < ioData->mNumberBuffers; ++iBuffer)
int thisNumChannels = ioData->mBuffers[iBuffer].mNumberChannels;
for (int iChannel = 0; iChannel < thisNumChannels; ++iChannel)
vDSP_vsadd(_outData+iChannel, _numOutputChannels, &zero, (float *)ioData->mBuffers[iBuffer].mData, thisNumChannels, numFrames);
else if (_numBytesPerSample == 2) // then we need to convert SInt16 -> Float (and also scale)
float scale = (float)INT16_MAX;
vDSP_vsmul(_outData, 1, &scale, _outData, 1, numFrames*_numOutputChannels);
for (int iBuffer=0; iBuffer < ioData->mNumberBuffers; ++iBuffer)
int thisNumChannels = ioData->mBuffers[iBuffer].mNumberChannels;
for (int iChannel = 0; iChannel < thisNumChannels; ++iChannel)
vDSP_vfix16(_outData+iChannel, _numOutputChannels, (SInt16 *)ioData->mBuffers[iBuffer].mData+iChannel, thisNumChannels, numFrames);
return noErr;
谢谢!
编辑:这是 ASBD (_ouputFormat) 的代码。它直接从远程获取它的值。也可以查看整个方法文件here。
if (checkError(AudioUnitGetProperty(_audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&_outputFormat,
&size),
"Couldn't get the hardware output stream format"))
return NO;
_outputFormat.mSampleRate = _samplingRate;
if (checkError(AudioUnitSetProperty(_audioUnit,
kAudioUnitProperty_StreamFormat,
kAudioUnitScope_Input,
0,
&_outputFormat,
size),
"Couldn't set the hardware output stream format"))
// just warning
_numBytesPerSample = _outputFormat.mBitsPerChannel / 8;
_numOutputChannels = _outputFormat.mChannelsPerFrame;
NSLog(@"Current output bytes per sample: %ld", _numBytesPerSample);
NSLog(@"Current output num channels: %ld", _numOutputChannels);
// Slap a render callback on the unit
AURenderCallbackStruct callbackStruct;
callbackStruct.inputProc = renderCallback;
callbackStruct.inputProcRefCon = (__bridge void *)(self);
if (checkError(AudioUnitSetProperty(_audioUnit,
kAudioUnitProperty_SetRenderCallback,
kAudioUnitScope_Input,
0,
&callbackStruct,
sizeof(callbackStruct)),
"Couldn't set the render callback on the audio unit"))
return NO;
【问题讨论】:
显示您的 AudioStreamBasicDescription 设置。 如果内存服务,您提供负责提供 AudiobufferList 和它指向的非交错缓冲区。如果你愿意,你可以填写它们。 RemoteIO 单元可能只看前两个。 @user523234,我在原帖中添加了 ADBD 部分,还添加了指向完整方法文件的链接。 @marko 我会尝试在环绕文件中的环绕声道中添加白噪声,看看是否发生了这种情况。我确实尝试记录正在缓冲的频道数量,但它只显示了两个。 【参考方案1】:我终于找到了将声道重新混合为立体声的代码。它使用 RIO 的 ASBD 在 KxAudioManager 中设置一个属性。然后,在 KxMovieDecoder.m 中,它使用相同的变量设置 ffmpeg 选项。代码如下:
id<KxAudioManager> audioManager = [KxAudioManager audioManager];
swrContext = swr_alloc_set_opts(NULL,
av_get_default_channel_layout(audioManager.numOutputChannels),
AV_SAMPLE_FMT_S16,
audioManager.samplingRate,
av_get_default_channel_layout(codecCtx->channels),
codecCtx->sample_fmt,
codecCtx->sample_rate,
0,
NULL);
现在开始阅读 ffmpeg 如何进行解码。欢乐时光。
【讨论】:
以上是关于Remote I/O 音频单元是不是设置缓冲区中的通道数?的主要内容,如果未能解决你的问题,请参考以下文章
如何渲染来自远程 I/O 音频单元的系统输入并以立体声播放这些样本