mirror of
https://github.com/moonlight-stream/moonlight-common-c.git
synced 2026-04-12 10:46:06 +00:00
Improve support for high-resolution stats
* This patch adds a new microsecond-resolution function call, LiGetMicroseconds(), to complement the existing LiGetMillis(). Many variables used by stats have been updated to work at this higher resolution and now provide better results when displaying e.g. sub-millisecond frametime stats. To try and avoid confusion, variables that now contain microseconds have been renamed with a suffix of 'Us', and those ending in 'Ms' contain milliseconds. I originally experimented with nanoseconds but it felt like overkill for our needs. Public API in Limelight.h: uint64_t LiGetMicroseconds(void); uint64_t LiGetMillis(void); const RTP_AUDIO_STATS* LiGetRTPAudioStats(void); // provides access to RTP data for the overlay stats const RTP_VIDEO_STATS* LiGetRTPVideoStats(void); Note: Users of this library may need to make changes. If using LiGetMillis() to track the duration of something that is shown to the user, consider switching to LiGetMicroseconds(). Remember to divide by 1000 at time of display to show in milliseconds.
This commit is contained in:
committed by
Cameron Gutman
parent
5f2280183c
commit
82ee2d6590
@@ -204,15 +204,19 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
|
||||
|
||||
if (packet->packetType == RTP_PAYLOAD_TYPE_AUDIO) {
|
||||
if (length < sizeof(RTP_PACKET)) {
|
||||
queue->stats.packetCountInvalid++;
|
||||
Limelog("RTP audio data packet too small: %u\n", length);
|
||||
LC_ASSERT_VT(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
queue->stats.packetCountAudio++;
|
||||
|
||||
// Remember if we've received out-of-sequence packets lately. We can use
|
||||
// this knowledge to more quickly give up on FEC blocks.
|
||||
if (!queue->synchronizing && isBefore16(packet->sequenceNumber, queue->oldestRtpBaseSequenceNumber)) {
|
||||
queue->lastOosSequenceNumber = packet->sequenceNumber;
|
||||
queue->stats.packetCountOOS++;
|
||||
if (!queue->receivedOosData) {
|
||||
Limelog("Leaving fast audio recovery mode after OOS audio data (%u < %u)\n",
|
||||
packet->sequenceNumber, queue->oldestRtpBaseSequenceNumber);
|
||||
@@ -238,11 +242,14 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
|
||||
PAUDIO_FEC_HEADER fecHeader = (PAUDIO_FEC_HEADER)(packet + 1);
|
||||
|
||||
if (length < sizeof(RTP_PACKET) + sizeof(AUDIO_FEC_HEADER)) {
|
||||
queue->stats.packetCountFecInvalid++;
|
||||
Limelog("RTP audio FEC packet too small: %u\n", length);
|
||||
LC_ASSERT_VT(false);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
queue->stats.packetCountFec++;
|
||||
|
||||
// This is an FEC packet, so we can just copy (and byteswap) the FEC header
|
||||
fecBlockPayloadType = fecHeader->payloadType;
|
||||
fecBlockBaseSeqNum = BE16(fecHeader->baseSequenceNumber);
|
||||
@@ -252,6 +259,7 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
|
||||
// Ensure the FEC shard index is valid to prevent OOB access
|
||||
// later during recovery.
|
||||
if (fecHeader->fecShardIndex >= RTPA_FEC_SHARDS) {
|
||||
queue->stats.packetCountFecInvalid++;
|
||||
Limelog("Too many audio FEC shards: %u\n", fecHeader->fecShardIndex);
|
||||
LC_ASSERT_VT(false);
|
||||
return NULL;
|
||||
@@ -261,6 +269,7 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
|
||||
// The FEC blocks must start on a RTPA_DATA_SHARDS boundary for our queuing logic to work. This isn't
|
||||
// the case for older versions of GeForce Experience (at least 3.13). Disable the FEC logic if this
|
||||
// invariant is validated.
|
||||
queue->stats.packetCountFecInvalid++;
|
||||
Limelog("Invalid FEC block base sequence number (got %u, expected %u)\n",
|
||||
fecBlockBaseSeqNum, (fecBlockBaseSeqNum / RTPA_DATA_SHARDS) * RTPA_DATA_SHARDS);
|
||||
Limelog("Audio FEC has been disabled due to an incompatibility with your host's old software!\n");
|
||||
@@ -304,6 +313,7 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
|
||||
if (existingBlock->blockSize != blockSize) {
|
||||
// This can happen with older versions of GeForce Experience (3.13) and Sunshine that don't use a
|
||||
// constant size for audio packets.
|
||||
queue->stats.packetCountFecInvalid++;
|
||||
Limelog("Audio block size mismatch (got %u, expected %u)\n", blockSize, existingBlock->blockSize);
|
||||
Limelog("Audio FEC has been disabled due to an incompatibility with your host's old software!\n");
|
||||
LC_ASSERT_VT(existingBlock->blockSize == blockSize);
|
||||
@@ -331,7 +341,7 @@ static PRTPA_FEC_BLOCK getFecBlockForRtpPacket(PRTP_AUDIO_QUEUE queue, PRTP_PACK
|
||||
|
||||
memset(block, 0, sizeof(*block));
|
||||
|
||||
block->queueTimeMs = PltGetMillis();
|
||||
block->queueTimeUs = PltGetMicroseconds();
|
||||
block->blockSize = blockSize;
|
||||
memset(block->marks, 1, sizeof(block->marks));
|
||||
|
||||
@@ -454,13 +464,15 @@ static bool completeFecBlock(PRTP_AUDIO_QUEUE queue, PRTPA_FEC_BLOCK block) {
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef FEC_VERBOSE
|
||||
|
||||
if (block->dataShardsReceived != RTPA_DATA_SHARDS) {
|
||||
queue->stats.packetCountFecRecovered += RTPA_DATA_SHARDS - block->dataShardsReceived;
|
||||
#ifdef FEC_VERBOSE
|
||||
Limelog("Recovered %d audio data shards from block %d\n",
|
||||
RTPA_DATA_SHARDS - block->dataShardsReceived,
|
||||
block->fecHeader.baseSequenceNumber);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef FEC_VALIDATION_MODE
|
||||
// Check the RTP header values
|
||||
@@ -531,9 +543,10 @@ static void handleMissingPackets(PRTP_AUDIO_QUEUE queue) {
|
||||
// At this point, we know we've got a second FEC block queued up waiting on the first one to complete.
|
||||
// If we've never seen OOS data from this host, we'll assume the first one is lost and skip forward.
|
||||
// If we have seen OOS data, we'll wait for a little while longer to see if OOS packets arrive before giving up.
|
||||
if (!queue->receivedOosData || PltGetMillis() - queue->blockHead->queueTimeMs > (uint32_t)(AudioPacketDuration * RTPA_DATA_SHARDS) + RTPQ_OOS_WAIT_TIME_MS) {
|
||||
if (!queue->receivedOosData || PltGetMicroseconds() - queue->blockHead->queueTimeUs > (uint64_t)(AudioPacketDuration * RTPA_DATA_SHARDS) + (RTPQ_OOS_WAIT_TIME_MS * 1000)) {
|
||||
LC_ASSERT(!isBefore16(queue->nextRtpSequenceNumber, queue->blockHead->fecHeader.baseSequenceNumber));
|
||||
|
||||
queue->stats.packetCountFecFailed++;
|
||||
Limelog("Unable to recover audio data block %u to %u (%u+%u=%u received < %u needed)\n",
|
||||
queue->blockHead->fecHeader.baseSequenceNumber,
|
||||
queue->blockHead->fecHeader.baseSequenceNumber + RTPA_DATA_SHARDS - 1,
|
||||
|
||||
Reference in New Issue
Block a user