我有一个DSP软件,可以在共享环回模式下使用WASAPI api捕获音频播放。
hr = _pAudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_LOOPBACK, 0, 0, _pFormat, 0);
这部分工作正常,但现在我希望能够检测到实际播放的频道数量。换句话说,我怎样才能检测到音频播放是否是立体声,5.1,7.1?
问题是:
*由于环回必须使用共享模式,因此可以播放多个源
*此分析必须实时完成。不能等到播放完毕
*检测任何播放源和暂时静音的频道
我认为最好的解决方案是如果我可以检索所有播放源/子混音的列表,并查询它们各自的频道数。这样我就不必分析音频数据流了。
答案 0 :(得分:0)
环回记录以端点上定义的混合格式进行,因此无论原始音频格式是什么,您都可以使用混合格式获取数据,从可能的多个播放源混合并转换为此类共享格式。
WASAPI环回包含正在播放的所有音频的混合...
GetMixFormat
方法检索音频引擎用于共享模式流内部处理的流格式......应用程序使用GetMixFormat或IsFormatSupported为共享模式或独占模式流查找适当的格式后,应用程序可以调用Initialize方法初始化具有该格式的流。尝试初始化共享模式流的应用程序,其格式与从GetMixFormat方法获得的混合格式不同,但具有相同数量的通道和与混合格式相同的采样率,可能会成功。在调用Initialize之前,应用程序可以调用IsFormatSupported来验证Initialize是否接受格式。
即使WASAPI在音频格式方面提供了一些灵活性,在回送捕获时,通道配置和采样率也是由共享格式定义的。
当你得到混音时,你无法真正识别“非活跃”频道:这些信息在混合到共享格式时会丢失。
此外,可以通过控制面板以交互方式配置实际的共享格式:
答案 1 :(得分:0)
好的,我现在可以解决我的问题。据我所知,您无法检测共享混音中的子混音,因此唯一的选择是分析音频流/捕获缓冲区。
首先在我的主捕获循环期间,我为所有正在播放的频道设置当前时间戳。
const time_t now = Date::getCurrentTimeMillis();
//Iterate all capture frames
for (i = 0; i < numFramesAvailable; ++i) {
for (j = 0; j < _nChannelsIn; ++j) {
//Identify which channels are playing.
if (pCaptureBuffer[j] != 0) {
_pUsedChannels[j] = now;
}
}
}
然后每秒我都会调用此函数来评估一个频道是否播放了最后一秒。根据正在播放的频道,我可以进行条件路由。
void checkUsedChannels() {
const time_t now = Date::getCurrentTimeMillis();
//Compare now against last used timestamp and determine active channels
for (size_t i = 0; i < _nChannelsIn; ++i) {
if (now - _pUsedChannels[i] > 1000) {
_pUsedChannels[i] = 0;
}
}
//Update conditional routing
for (const Input *pInut : _inputs) {
pInut->evalConditions();
}
}
非常简单的解决方案,但似乎有效。