我正在尝试以非常低的延迟在高速USB 2上输出等时数据(以编程方式生成)。理想情况下大约1-2毫秒。在Windows上我使用WinUsb,在OSX上我使用的是IOKit。
我想到了两种方法。我想知道哪个是最好的。
WinUsb在其允许的范围内是相当严格的,并且要求每个等时传输是整数帧(1帧= 1毫秒)。因此,为了最大限度地减少延迟,请使用循环中的每个帧进行传输,如下所示:
for (;;)
{
// Submit a 1-frame transfer ASAP.
WinUsb_WriteIsochPipeAsap(..., &overlapped[i]);
// Wait for the transfer from 2 frames ago to complete, for timing purposes. This
// keeps the loop in sync with the USB frames.
WinUsb_GetOverlappedResult(..., &overlapped[i-2], block=true);
}
这种方法效果很好,延迟时间为2毫秒。在OSX上我可以做类似的事情,虽然它有点复杂。这是代码的要点 - 完整的代码太长了,无法在此处发布:
uint64_t frame = ...->GetBusFrameNumber(...) + 1;
for (;;)
{
// Submit at the next available frame.
for (a few attempts)
{
kr = ...->LowLatencyWriteIsochPipeAsync(...
frame, // Start on this frame.
&transfer[i]); // Callback
if (kr == kIOReturnIsoTooOld)
frame++; // Try the next frame.
else if (kr == kIOReturnSuccess)
break;
else
abort();
}
// Above, I pass a callback with a reference to a condition_variable. When
// the transfer completes the condition_variable is triggered and wakes this up:
transfer[i-5].waitForResult();
// I have to wait for 5 frames ago on OSX, otherwise it skips frames.
}
这种工作再次发挥作用,延迟时间约为3.5毫秒。但它并不是非常可靠。
OSX的低延迟等时功能允许您提交长传输(例如64帧),然后定期(每毫秒最多一次)更新帧列表,该列表说明内核在读取写缓冲区时所处的位置。
我认为这个想法是你以某种方式唤醒每N毫秒(或微秒),读取帧列表,找出你需要写入的地方并做到这一点。我还没有为此编写代码,但我不完全确定如何继续,而且我找不到任何例子。
当帧列表更新时似乎没有提供回调,所以我想你必须使用自己的计时器 - CFRunLoopTimerCreate()
并从该回调中读取帧列表?
此外,我想知道WinUsb是否允许类似的事情,因为它还会强制您注册缓冲区,以便内核和用户空间可以同时访问它。我找不到任何明确说明你可以在内核读取时写入缓冲区的例子。您是否打算在常规回调中使用WinUsb_GetCurrentFrameNumber
来计算内核在传输中的位置?
这需要在Windows上进行常规回调,这看起来有点棘手。我见过的唯一方法是使用最短周期为1毫秒的multimedia timers(除非您使用未记录的NtSetTimerResolution
?)。
所以我的问题是:我可以改进“1帧传输”方法,还是应该切换到尝试竞争内核的1 kHz回调。示例代码非常感谢!
答案 0 :(得分:1)
(评论太长了,所以......)
我只能解决OS X方面的问题。这部分问题:
我认为这个想法是你以某种方式每N毫秒唤醒(或者 微秒),读取帧列表,找出你需要写的地方 并且这样做。我还没有为此编写代码,但我不是 完全确定如何进行,没有我能找到的例子。
在更新帧列表时似乎没有提供回调 所以我想你必须使用自己的计时器 - CFRunLoopTimerCreate() 并从该回调中读取帧列表?
让我对你正在尝试做的事情摸不着头脑。您的数据来自哪里,延迟是至关重要的,但数据准备好后数据源还没有通知您?
我们的想法是,您的数据正在从某些来源流式传输,并且只要有任何数据可用,可能是在调用该数据源的某些完成时,您将所有可用数据写入用户/内核共享数据缓冲区中适当的位置。
所以也许你可以更详细地解释一下你想做什么,我也许可以提供帮助。