根据Microsoft的说法,从Windows 10开始,使用共享模式WASAPI的应用程序可以请求小于10毫秒的缓冲区大小(请参阅https://msdn.microsoft.com/en-us/library/windows/hardware/mt298187%28v=vs. 85%29.aspx).
根据这篇文章,实现如此低的延迟需要一些驱动程序更新,我做了.使用独占模式渲染和捕获流,我测量了大约13ms的总往返延迟(使用硬件环回电缆).这告诉我,至少有一个端点成功实现了<10ms的延迟.(这个假设是正确的吗?)
文章提到应用程序可以使用新IAudioClient3界面查询Windows音频引擎使用的最小缓冲区大小IAudioClient3::GetSharedModeEnginePeriod().但是,此功能总是在我的系统上返回10ms,并且任何尝试使用任一IAudioClient::Initialize()或IAudioClient3::InitializeSharedAudioStream()低于10ms的周期初始化音频流总是会导致AUDCLNT_E_INVALID_DEVICE_PERIOD.
为了确保,我还禁用了音频驱动程序中的任何效果处理.我错过了什么?甚至可以从共享模式获得低延迟?请参阅下面的示例代码.
#include <windows.h>
#include <atlbase.h>
#include <mmdeviceapi.h>
#include <audioclient.h>
#include <iostream>
#define VERIFY(hr) do { \
auto temp = (hr); \
if(FAILED(temp)) { \
std::cout << "Error: " << #hr << ": " << temp << "\n"; \
goto error; \
} \
} while(0)
int main(int argc, char** argv) {
HRESULT hr;
CComPtr<IMMDevice> device;
AudioClientProperties props;
CComPtr<IAudioClient> client;
CComPtr<IAudioClient2> client2;
CComPtr<IAudioClient3> client3; …Run Code Online (Sandbox Code Playgroud) 是否有可能获得Windows 7上各个程序的峰值仪表读数,如果是,如何获得?
使用WASAPI,可以通过环回设备捕获整个系统音频,但这并不区分不同程序的输出.这个问题涉及为单个指定应用程序捕获音频,但在处理捕获所有单独播放音频的程序时,答案似乎过高.这必须是可能的,因为SndVol可以做到这一点,如下图所示.问题是它是如何完成的?它是通过未暴露的API调用完成的,还是实际上可以通过WASAPI实现这样的东西?

谢谢.
我正在编写自己的API来执行SndVol系统实用程序的一些功能.我希望这个API的一部分能够设置给定音频会话的音量级别.
SndVol在"设备"面板上显示一个滑块,用户可以使用该滑块更改音频设备的主音量级别以及每个音频会话的滑块(在"应用程序"面板上),用于更改会话的音量级别:

如果我拖动其中一个音频会话的滑块手柄,则SndVol可以更改音频会话的音量级别.它是如何做到的?
我认为可以使用Windows Vista的Core Audio API,但我遇到的问题是虽然我能够使用一个设备迭代设备的音频会话IAudioSessionEnumerator,但IAudioSessionEnumerator只能让我访问IAudioSessionControl对象,但我需要该IAudioClient对象来获取一个ISimpleAudioVolume对象我可以用来设置音频会话音量级别.是否有可能获得与IAudioClient对象关联的IAudioSessionControl对象?
CSCore(https://github.com/filoe/cscore)似乎是一个非常好的C#音频库,但它缺乏文档和很好的例子.
我一直在玩Bass.Net很长一段时间,CSCore的架构不像Bass库,所以很难找到正确的方法来完成一些常见的任务.
我正在尝试从WasapiCapture设备捕获麦克风输入并将记录的数据输出到WasapiOut设备,但我无法成功.
以下是我在谷歌搜索后可以找到的代码,但它不起作用.
MMDeviceEnumerator deviceEnum = new MMDeviceEnumerator();
MMDeviceCollection devices = deviceEnum.EnumAudioEndpoints(DataFlow.Capture, DeviceState.Active);
using (var capture = new WasapiCapture())
{
capture.Device = deviceEnum.GetDefaultAudioEndpoint(DataFlow.Capture, Role.Multimedia);
capture.Initialize();
using (var source = new SoundInSource(capture))
{
using (var soundOut = new WasapiOut())
{
capture.Start();
soundOut.Device = deviceEnum.GetDefaultAudioEndpoint(DataFlow.Render, Role.Multimedia);
soundOut.Initialize(source);
soundOut.Play();
}
}
}
Run Code Online (Sandbox Code Playgroud)
我要做的是写一个像这样的应用程序:http: //www.pitchtech.ch/PitchBox/
我有自己的DSP功能,我想将其应用于记录数据.
有没有人有将WasapiCapture指向WasapiOut并编写自定义DSP的例子?
编辑:
我在CSCore库创建者Florian Rosmann(filoe)的帮助下找到了解决方案.
这是一个DSP类,它放大了提供的音频数据.
class DSPGain: ISampleSource
{
ISampleSource _source;
public DSPGain(ISampleSource source)
{
if (source == null)
throw new ArgumentNullException("source");
_source …Run Code Online (Sandbox Code Playgroud) 我试图在Unity项目中使用此代码,但似乎Mono/.NET中的COM Interop的实现不同,这导致代码失败或崩溃.在.NET中运行代码工作正常,但使用Mono 2.0(在Unity之外)运行它的方式与Unity中的方式相同,这表明它与Mono一般存在问题,而不是Unity.
如果我按原样编译并运行代码,则会失败,因为从MMDeviceEnumerator转换为IIMMDeviceEnumerator 的类型失败.使用[ComInterop]装饰所有接口时,转换成功,但对GetDefaultAudioEndpoint的调用使Unity/Mono因访问冲突而崩溃.
很难在Mono上找到COM Interop的良好文档 - 尤其是关于这样一个旧版本的文档.是否可以让它运行?
我正在尝试修复一个围绕portmixer的Audacity错误.输出/输入级别可以使用mac版本的portmixer进行设置,但不能始终在Windows中进行设置.我正在调试portmixer的窗口代码,试图让它在那里工作.
使用IAudioEndpointVolume :: SetMasterVolumeLevelScalar设置主音量适用于板载声音,但使用专业外部USB或火线接口(如RME Fireface 400),输出音量不会改变,尽管它反映在该设备的Window声音控制面板中,还有系统调音台.
此外,在我们的程序之外,更改系统混音器的主滑块(在任务栏中)没有任何效果 - 声卡输出相同(完整)级别,而不管系统所处的级别如何.更改输出级别的唯一方法是使用硬件开发人员为卡提供的自定义应用程序.
IAudioEndpointVolume :: QueryHardwareSupport函数返回ENDPOINT_HARDWARE_SUPPORT_VOLUME,因此它应该能够执行此操作.
许多设备上的输入和输出都存在此行为.
这可能是Window的错误吗?
可以通过模拟(缩放)输出来解决这个问题,但这不是首选,因为它在功能上并不相同 - 更好的是让音频接口进行缩放(特别是如果它涉及前置放大器的输入).
我遇到了来自 NAudio 库的 BufferedWaveProvider 的问题。我正在录制 2 个音频设备(一个麦克风和一个扬声器),将它们合并为 1 个流并将其发送到编码器(用于视频)。
为此,我执行以下操作:
WasapiCapture.WasapiLookbackCapture. (我也使用 aSilenceProvider所以我记录的内容没有空白)。MediaFoundationResampler来调整其格式,使其与扬声器中的音频相同。BufferedWaveProvider.MixingSampleProvider我ISampleProvider从每个录制线程传递的地方。所以我通过MediaFoundationResampler麦克风和BufferedWaveProvider扬声器。MixingSampleProvider,它应该BufferedWaveProvider在填充时异步清空(s)。请参阅下面的流程图,它说明了我上面的描述。
during进行 Discord、Skype 或 Teams 音频对话时,我都会立即(在 5 秒内)崩溃,BufferedWaveProvider.AppSamples因为缓冲区已满。在调试模式下查看它,我可以看到:
从我在 NAudio 的作者博客、文档和 StackOverflow 上阅读的内容来看,我认为我正在做最佳实践(但我可能是错的),即从一个线程写入缓冲区,并从另一个线程并行读取它. 当然有一种风险,它比我阅读它的速度更快,这基本上就是现在正在发生的事情。但我不明白为什么。
我需要一些帮助来理解我在这里遗漏了什么,请。以下几点让我感到困惑:
为什么这个问题只发生在 …
我正在使用NAudio 库,并使用其 WasapiLoopbackCapture 以非常简单的方式记录“您听到的内容”:
var outputFolder = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "NAudio");
Directory.CreateDirectory(outputFolder);
var outputFilePath = Path.Combine(outputFolder, "recorded.pcm");
var loopback = new WasapiLoopbackCapture();
var fileWriter = new WaveFileWriter(outputFilePath, loopback.WaveFormat);
loopback.RecordingStopped += (s, a) => { fileWriter.Dispose(); };
loopback.DataAvailable += (object? sender, WaveInEventArgs args) =>
{
fileWriter.Write(args.Buffer, 0, args.BytesRecorded);
};
Run Code Online (Sandbox Code Playgroud)
然后我在 YouTube 上播放视频并将扬声器静音。
在大多数设备上,这种方法效果很好,并且无论扬声器是否静音,生成的文件都会包含设备上正在播放的音频。
但在某些设备中,当扬声器静音时,接收到的音频因此文件内容只是静音。
我不确定发生了什么或如何解决它,我尝试更新驱动程序并尝试创建我自己的 WasapiLoopbackCapture 版本来更改音频设备等,但目前没有任何效果。
任何人都知道这里发生了什么以及我如何在所有设备上实现这一目标?
以下是发生不良行为的设备示例:
ACER Aspire 3 A315-23-R8T0
Windows 10 Pro 22H2 Build 19045.3208
Realtek(R) Audio
Driver Provider: Microsoft
Driver Version: 10.0.19041.1
Run Code Online (Sandbox Code Playgroud)
作为参考,我也在 NAudio 上发布了该问题 …
我正在构建一个应用程序来使用 WASAPI 从设备捕获音频,其中使用的所有 API 都支持 Windows Vista 及更高版本的设备。
最初,我使用WASAPI Capture 作为共享计时器驱动模式从设备捕获音频,其中将有一个线程每 0 毫秒从设备捕获音频。它在 Windows Vista 及以上设备中工作的地方。
由于上述方法在 CPU 消耗方面效率不高,并且并非每项都经过优化,因此我尝试使用WASAPI Capture 作为共享事件驱动模式从设备捕获音频,其中仅当数据被系统触发事件时才会捕获音频。可用的。此方法确实完全降低了 CPU 消耗,但在 Windows VISTA 到 Windows Server 2016 设备中不起作用。
Initialization of audio client interface
音频接口使用共享模式初始化,并且给出的流标志用于 AUDCLNT_STREAMFLAGS_EVENTCALLBACK,因为我使用的是事件驱动模式。GetExtensibleMixFormat 方法提供使用 Windows 的 GetMixFormat() 获取的默认混合格式。
int enginelatency = 20;
HRESULT hr = _AudioClient->Initialize(AUDCLNT_SHAREMODE_SHARED, AUDCLNT_STREAMFLAGS_EVENTCALLBACK | AUDCLNT_STREAMFLAGS_LOOPBACK , enginelatency * 10000, 0, (WAVEFORMATEX*)mix_format_wasapicap_ptr->GetExtensibleMixFormat(), NULL);
Run Code Online (Sandbox Code Playgroud)
Initializing the event
其中 _AudioSamplesReadyEvent 是提供给 SetEventHandle 方法的句柄。当音频缓冲区准备好由客户端处理时,系统将触发此事件。
hr = _AudioClient->SetEventHandle(_AudioSamplesReadyEvent);
Run Code Online (Sandbox Code Playgroud)
尽管 Windows VISTA 及以上设备支持所有使用的 API,但无法弄清楚为什么在 …
wasapi ×10
audio ×7
c# ×4
c++ ×4
windows ×4
naudio ×2
audacity ×1
com ×1
com-interop ×1
core-audio ×1
cscore ×1
event-driven ×1
mono ×1
shared ×1
winapi ×1