-
-
Notifications
You must be signed in to change notification settings - Fork 1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix(rtp): improve timestamp accuracy #3513
base: master
Are you sure you want to change the base?
fix(rtp): improve timestamp accuracy #3513
Conversation
7230cb5
to
2710caa
Compare
Oops, I changed the title in the commit, but forgot to do the PR. I guess it's still too long anyway:
|
2710caa
to
15f6927
Compare
a6aa913
to
5c2a8e2
Compare
5c2a8e2
to
f8580af
Compare
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #3513 +/- ##
=========================================
- Coverage 8.44% 6.18% -2.27%
=========================================
Files 90 66 -24
Lines 16069 11989 -4080
Branches 7633 5584 -2049
=========================================
- Hits 1357 741 -616
+ Misses 14214 11072 -3142
+ Partials 498 176 -322
Flags with carried forward coverage won't be shown. Click here to find out more.
|
I believe that's accurate. The clients that I know of that try to pace audio do it via monitoring the amount of pending audio (either in moonlight-common-c's queue, in the OS audio stack, or both).
AFAIK, Nvidia did their own thing and didn't implement any known RTP FEC standard, so it's asserting what GFE and current Sunshine do. IIUC, what is happening in your case is that you hit the (common) case where a data packet is received first and we synthesize an FEC header using this code:
Since you've adjusted the logic to no longer guarantee that there is
Did you have some idea of how you would "fix it"? AFAICT, it seems basically intrinsic to this model where timestamps are real measured things and not just a glorified counter.
I know Nvidia didn't use it. Given how tiny of a fraction that audio data is of the total traffic, it probably made sense to use the existing Reed-Solomon FEC scheme they were already using for video. They didn't even bother with a variable FEC scheme for audio, unlike video FEC which can change based on client feedback. |
src/stream.cpp
Outdated
// Audio timestamps are in milliseconds and should be AudioPacketDuration (5ms or 10ms) apart | ||
auto timestamp = static_cast<std::uint32_t>( | ||
std::chrono::duration_cast<std::chrono::microseconds>( | ||
std::chrono::steady_clock::now() - session->audio.timestamp_epoch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's possible to get capture time from the OS too like we do with video frames. IAudioCaptureClient::GetBuffer()
takes an optional pu64QPCPosition
parameter that gives you the timestamp of capture.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh nice, that seems useful and we might as well use it, even though the difference between this and the timestamp I put in the patch is probably so small to be meaningless. I took a crack at adding this in, but got as far as adding a packet_timestamp
into auto packets = mail::man->queue<audio::packet_t>(mail::audio_packets);
and then got stumped by those brutal C++ tuple macros and fun compiler errors. Anyway it's here if one of you guys can spot the right way to get that timestamp through the queue.
088a19a
to
0767e00
Compare
* Video: instead of using now() when the RTP packet is created, use the earlier packet->frame_timestamp that we're already collecting for host latency stats. This timestamp should be more accurate to when we captured the frame. I am not sure if all backends support this timestamp, so there is a fallback to the current method. * Audio: fix bug where the RTP timestamps stop advancing when no audio is being sent. Audio now uses the same timer-based source for this field, but remains as milliseconds. * Both use steady_clock and microseconds / 1000 to maintain precision. Video still uses 90khz time base per the spec, and audio is effectively at packet duration resolution of 5ms/10ms.
… queue to support passing capture_timestamp.
0767e00
to
f55cf64
Compare
Quality Gate failedFailed conditions See analysis details on SonarQube Cloud Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE |
This ended up getting a bit insane due to the layering of the queues and the need to refactor every layer to deal with passing additional metadata. I don't really know how I feel about any of this now, it was supposed to be a simple patch... I'm not sure I have it in me to deal with the SonarQube nonsense it will complain about. Some things I noticed:
|
Sonar is only a tool, not an absolute deal breaker or blocker if there are failures. |
Background
I am experimenting with the iOS AVSampleBufferAudioRenderer and AVSampleBufferRenderSynchronizer APIs, which include the ability to use RTP timestamps as a way to pace playback, provide a/v sync that won't drift, use variable-speed playback to cover for short glitches (such as Game Mode's drop in Bluetooth latency), proper spatial audio support for free, and more. It should also be nicely compatible with the AVSampleBufferDisplayLayer API currently used by the iOS video code. The biggest challenge with these APIs is their higher latency, but I'm hopeful it can get to a reasonable level. Worst case, it could be a good option when you are willing to trade a little latency for solid playback.
Description
Known issue: I had to comment out one assert in Moonlight, because this patch changes one of the FEC timestamps. The FEC RFC says "The timestamp SHALL be set to a time corresponding to the repair packet's transmission time. Note that the timestamp value has no use in the actual FEC protection process and is usually useful for jitter calculations.", so I don't think this assert is correct anyway. Even though this shouldn't affect Moonlight release builds which don't use asserts or the extra FEC verification code, this probably needs to be resolved before this can be accepted, either by only sending correct timestamp packets to newer Moonlight versions, or fixing it in the FEC code. (Not to get too sidetracked but was the Opus FEC support ever tried? I sometimes wonder if the 40% FEC overhead on audio is too high for benefit.)
RtpAudioQueue.c:300
LC_ASSERT_VT(existingBlock->fecHeader.baseTimestamp == fecBlockBaseTs);
Type of Change
.github/...
)Checklist