我正在尝试通过高速USB 2输出同步数据(以编程方式生成),延迟非常低。理想情况下约为1-2毫秒。在Windows上我用的是WinUsb,在OSX上我用的是IOKit。
我想到了两种方法。我在想哪一个最好。
1帧传输
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毫秒(或微秒)唤醒一次,读取帧列表,计算出你需要写入的位置并这样做。我还没有为此编写代码,但我不完全确定如何继续,也没有我能找到的示例。
当帧列表更新时,它似乎不提供回调,所以我想你必须使用自己的timer - CFRunLoopTimerCreate()并从该回调中读取帧列表?
另外,我想知道WinUsb是否允许类似的事情,因为它还强制您注册一个缓冲区,以便内核和用户空间可以同时访问它。但是,我找不到任何明确说明可以在内核读取缓冲区时写入缓冲区的示例。您是否打算在常规回调中使用WinUsb_GetCurrentFrameNumber来计算内核在传输中的位置?
这将需要在Windows上获得一个常规的回调,这似乎有点棘手。我见过的唯一方法是使用multimedia timers,它的最小周期为1毫秒(除非您使用未记录的(NtSetTimerResolution?)。
所以我的问题是:我是否可以改进“1帧传输”的方法,或者我应该切换到1 kHz回调,试图与内核竞争。示例代码非常感谢!
发布于 2017-06-03 21:04:15
(评论太长了,所以…)
我只能解决OS方面的问题。问题的这一部分:
我认为
的想法是,你以某种方式每N毫秒(或微秒)唤醒一次,读取帧列表,找出需要写入的位置并执行此操作。我还没有为此编写代码,但我不完全确定如何继续,也没有我能找到的示例。
当帧列表更新时,它似乎没有提供回调,所以我想您必须使用自己的timer - CFRunLoopTimerCreate()并从该回调中读取帧列表?
让我为你想做的事抓狂。您的数据来自哪里,延迟很关键,但数据源还没有在数据准备就绪时通知您?
这样做的想法是,您的数据是从某个源流式传输的,一旦有任何数据可用,您就可以将所有可用的数据写入用户/内核共享数据缓冲区中的适当位置。
因此,也许你可以更详细地解释一下你想要做的事情,我也许能帮上忙。
https://stackoverflow.com/questions/44304453
复制相似问题