Skip to content
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

Sample TWCC implementation #1957

Merged
merged 11 commits into from
May 1, 2024
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 31 additions & 26 deletions samples/Common.c
Original file line number Diff line number Diff line change
Expand Up @@ -553,7 +553,7 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P

ATOMIC_STORE_BOOL(&pSampleStreamingSession->terminateFlag, FALSE);
ATOMIC_STORE_BOOL(&pSampleStreamingSession->candidateGatheringDone, FALSE);
pSampleStreamingSession->newVideoBitrate = 0;
MEMSET(&pSampleStreamingSession->twccMetadata, 0x00, SIZEOF(TwccMetadata));
disa6302 marked this conversation as resolved.
Show resolved Hide resolved
pSampleStreamingSession->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime = GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND;
// Flag to enable SDK to calculate selected ice server, local, remote and candidate pair stats.
pSampleConfiguration->enableIceStats = FALSE;
Expand Down Expand Up @@ -705,35 +705,40 @@ VOID sampleBandwidthEstimationHandler(UINT64 customData, DOUBLE maximumBitrate)
DLOGV("received bitrate suggestion: %f", maximumBitrate);
}

VOID sampleSenderBandwidthEstimationHandler(UINT64 customData, UINT32 txBytes, UINT32 rxBytes, UINT32 txPacketsCnt, UINT32 rxPacketsCnt,
UINT64 duration)
{
void sampleSenderBandwidthEstimationHandler(UINT64 customData, UINT32 txBytes, UINT32 rxBytes, UINT32 txPacketsCnt, UINT32 rxPacketsCnt, UINT64 duration) {
UNUSED_PARAM(duration);
UNUSED_PARAM(rxBytes);
UNUSED_PARAM(txBytes);
UINT32 lostPacketsCnt = txPacketsCnt - rxPacketsCnt;
UINT32 percentLost = lostPacketsCnt * 100 / txPacketsCnt;
PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData;
UINT64 bitrate;
DLOGI("Percent lost: %d", percentLost);
if (percentLost <= 5) {
// increase encoder bitrate by 5 percent
bitrate = pSampleStreamingSession->currentVideoBitrate * 1.05f;
} else if (percentLost > 5) {
if(pSampleStreamingSession->currentVideoBitrate >= 1 * 1024) {
// decrease encoder bitrate by packet loss percent
bitrate = pSampleStreamingSession->currentVideoBitrate * (1.0f - percentLost/100.0f);
}
else {
DLOGW("Bitrate already too low...maintaining..expect frame packet drops and choppy playback");
bitrate = pSampleStreamingSession->currentVideoBitrate;
}
UINT8 percentLost = (txPacketsCnt > 0) ? (lostPacketsCnt * 100 / txPacketsCnt) : 0;
disa6302 marked this conversation as resolved.
Show resolved Hide resolved

SampleStreamingSession* pSampleStreamingSession = (SampleStreamingSession*) customData;

// Calculate smoothed packet loss
DOUBLE currentPacketLoss = (DOUBLE) percentLost;
disa6302 marked this conversation as resolved.
Show resolved Hide resolved
EMA_ACCUMULATOR_GET_NEXT(pSampleStreamingSession->twccMetadata.averagePacketLoss, currentPacketLoss);

UINT64 currentTimeMs = GETTIME();
UINT64 timeDiff = currentTimeMs - pSampleStreamingSession->twccMetadata.lastAdjustmentTimeMs;
if (timeDiff < ADJUSTMENT_INTERVAL_MS) {
// Too soon for another adjustment
DLOGI("Too soon");
return;
}
if(bitrate > 2048000) {
bitrate = pSampleStreamingSession->currentVideoBitrate;

UINT64 bitrate = pSampleStreamingSession->twccMetadata.currentVideoBitrate;
if (pSampleStreamingSession->twccMetadata.averagePacketLoss <= 5) {
disa6302 marked this conversation as resolved.
Show resolved Hide resolved
disa6302 marked this conversation as resolved.
Show resolved Hide resolved
// increase encoder bitrate by 5 percent with a cap at MAX_BITRATE
disa6302 marked this conversation as resolved.
Show resolved Hide resolved
bitrate = (UINT64) MIN(bitrate * 1.05f, MAX_BITRATE);
} else {
// decrease encoder bitrate by average packet loss percent, with a cap at MIN_BITRATE
bitrate = (UINT64) MAX(bitrate * (1.0f - pSampleStreamingSession->twccMetadata.averagePacketLoss / 100.0f), MIN_BITRATE);
}
pSampleStreamingSession->newVideoBitrate = bitrate;
DLOGI("received sender bitrate estimation: suggested bitrate %u kbps sent: %u bytes %u packets received: %u bytes %u packets in %lu msec, ", bitrate,

// Update the session with the new bitrate and adjustment time
pSampleStreamingSession->twccMetadata.newVideoBitrate = bitrate;
pSampleStreamingSession->twccMetadata.lastAdjustmentTimeMs = currentTimeMs;

DLOGI("Adjustment made: average packet loss = %.2f%%, timediff: %llu ms", pSampleStreamingSession->twccMetadata.averagePacketLoss, ADJUSTMENT_INTERVAL_MS, timeDiff);
DLOGI("received sender bitrate estimation: suggested bitrate %u sent: %u bytes %u packets received: %u bytes %u packets in %lu msec", bitrate,
txBytes, txPacketsCnt, rxBytes, rxPacketsCnt, duration / 10000ULL);
}

Expand Down
19 changes: 15 additions & 4 deletions samples/Samples.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,11 @@ extern "C" {
#define MAX_SIGNALING_CLIENT_METRICS_MESSAGE_SIZE 736 // strlen(SIGNALING_CLIENT_METRICS_JSON_TEMPLATE) + 20 * 10
#define MAX_ICE_AGENT_METRICS_MESSAGE_SIZE 113 // strlen(ICE_AGENT_METRICS_JSON_TEMPLATE) + 20 * 2


#define ADJUSTMENT_INTERVAL_MS 5 * HUNDREDS_OF_NANOS_IN_A_SECOND
disa6302 marked this conversation as resolved.
Show resolved Hide resolved
#define MIN_BITRATE 512
#define MAX_BITRATE 2048000

typedef enum {
SAMPLE_STREAMING_VIDEO_ONLY,
SAMPLE_STREAMING_AUDIO_VIDEO,
Expand Down Expand Up @@ -179,6 +184,15 @@ typedef struct {

typedef VOID (*StreamSessionShutdownCallback)(UINT64, PSampleStreamingSession);

typedef struct {
UINT64 lastAdjustmentTimeMs;
UINT64 currentVideoBitrate;
disa6302 marked this conversation as resolved.
Show resolved Hide resolved
UINT64 newVideoBitrate;
UINT64 currentAudioBitrate;
UINT64 newAudioBitrate;
float averagePacketLoss;
} TwccMetadata, *PTwccMetadata;

struct __SampleStreamingSession {
volatile ATOMIC_BOOL terminateFlag;
volatile ATOMIC_BOOL candidateGatheringDone;
Expand Down Expand Up @@ -208,10 +222,7 @@ struct __SampleStreamingSession {
CHAR pPeerConnectionMetricsMessage[MAX_PEER_CONNECTION_METRICS_MESSAGE_SIZE];
CHAR pSignalingClientMetricsMessage[MAX_SIGNALING_CLIENT_METRICS_MESSAGE_SIZE];
CHAR pIceAgentMetricsMessage[MAX_ICE_AGENT_METRICS_MESSAGE_SIZE];
UINT64 currentVideoBitrate;
UINT64 newVideoBitrate;
UINT64 newAudioBitrate;
UINT64 currentAudioBitrate;
TwccMetadata twccMetadata;
};

// TODO this should all be in a higher webrtccontext layer above PeerConnection
Expand Down
8 changes: 4 additions & 4 deletions samples/kvsWebRTCClientMasterGstSample.c
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ GstFlowReturn on_new_sample(GstElement* sink, gpointer data, UINT64 trackid)
if(encoder != NULL) {
guint bitrate;
g_object_get(G_OBJECT(encoder), "bitrate", &bitrate, NULL);
pSampleStreamingSession->currentVideoBitrate = (UINT64) bitrate;
if(pSampleStreamingSession->newVideoBitrate != 0) {
bitrate = (guint) (pSampleStreamingSession->newVideoBitrate);
pSampleStreamingSession->newVideoBitrate = 0;
pSampleStreamingSession->twccMetadata.currentVideoBitrate = (UINT64) bitrate;
if(pSampleStreamingSession->twccMetadata.newVideoBitrate != 0) {
bitrate = (guint) (pSampleStreamingSession->twccMetadata.newVideoBitrate);
pSampleStreamingSession->twccMetadata.newVideoBitrate = 0;
g_object_set(G_OBJECT(encoder), "bitrate", bitrate, NULL);
}

Expand Down