Q: Low latency isochronous out on OSX and Windows 10 I'm trying to output isochronous data (generated programmatically) over High Speed USB 2 with very low latency. Ideally around 1-2 ms. On Windows I'm using WinUsb, and on OSX I'm using IOKit.
There are two approaches I have thought of. I'm wondering which is best.
1-frame transfers
WinUsb is quite restrictive in what it allows, and requires each isochronous transfer to be a whole number of frames (1 frame = 1 ms). Therefore to minimise latency use transfers of one frame each in a loop something like this:
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);
}

This works fairly well and gives a latency of 2 ms. On OSX I can do a similar thing, though it is quite a bit more complicated. This is the gist of the code - the full code is too long to post here:
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.
}

Again this kind of works and gives a latency of around 3.5 ms. But it's not super-reliable.
Race the kernel
OSX's low latency isochronous functions allow you to submit long transfers (e.g. 64 frames), and then regularly (max once per millisecond) update the frame list which says where the kernel has got to in reading the write buffer.
I think the idea is that you somehow wake up every N milliseconds (or microseconds), read the frame list, work out where you need to write to and do that. I haven't written code for this yet but I'm not entirely sure how to proceed, and there are no examples I can find.
It doesn't seem to provide a callback when the frame list is updated so I suppose you have to use your own timer - CFRunLoopTimerCreate() and read the frame list from that callback?
Also I'm wondering if WinUsb allows a similar thing, because it also forces you to register a buffer so it can be simultaneously accessed by the kernel and user-space. I can't find any examples that explicitly say you can write to the buffer while the kernel is reading it though. Are you meant to use WinUsb_GetCurrentFrameNumber in a regular callback to work out where the kernel has got to in a transfer?
That would require getting a regular callback on Windows, which seems a bit tricky. The only way I've seen is to use multimedia timers which have a minimum period of 1 millisecond (unless you use the undocumented (NtSetTimerResolution?).
So my question is: Can I improve the "1-frame transfers" approach, or should I switch to a 1 kHz callback that tries to race the kernel. Example code very appreciated!

A: (Too long for a comment, so…)
I can only address the OS X side of things. This part of the question:

I think the idea is that you somehow wake up every N milliseconds (or
  microseconds), read the frame list, work out where you need to write
  to and do that. I haven't written code for this yet but I'm not
  entirely sure how to proceed, and there are no examples I can find.
It doesn't seem to provide a callback when the frame list is updated
  so I suppose you have to use your own timer - CFRunLoopTimerCreate()
  and read the frame list from that callback?

Has me scratching my head over what you're trying to do. Where is your data coming from, where latency is critical but the data source does not already notify you when data is ready?
The idea is that your data is being streamed from some source, and as soon as any data becomes available, presumably when some completion for that data source gets called, you write all available data into the user/kernel shared data buffer at the appropriate location.
So maybe you could explain in a little more detail what you're trying to do and I might be able to help.
