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

Memory Optimization - ICE Agent Stats (#1947) #2074

Open
wants to merge 16 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 10 commits
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
30 changes: 30 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,36 @@ jobs:
run: |
cd build
timeout --signal=SIGABRT 60m ./tst/webrtc_client_test
ubuntu-os-build-stats-calc-control:
runs-on: ubuntu-20.04
env:
AWS_KVS_LOG_LEVEL: 2
permissions:
id-token: write
contents: read
steps:
- name: Clone repository
uses: actions/checkout@v4
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
aws-region: ${{ secrets.AWS_REGION }}
- name: Install dependencies
run: |
sudo apt clean && sudo apt update
sudo apt-get -y install libcurl4-openssl-dev
- name: Build repository
run: |
# TODO: Remove the following line. This is only a workaround for enabling IPv6, https://github.com/travis-ci/travis-ci/issues/8891.
sudo sh -c 'echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6'
mkdir build && cd build
cmake .. -DBUILD_TEST=TRUE -DENABLE_STATS_CALCULATION_CONTROL=TRUE
make
- name: Run tests
run: |
cd build
timeout --signal=SIGABRT 60m ./tst/webrtc_client_test
windows-msvc-openssl:
runs-on: windows-2022
env:
Expand Down
5 changes: 5 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ option(ENABLE_DATA_CHANNEL "Enable support for data channel" ON)
option(ENABLE_KVS_THREADPOOL "Enable support for KVS thread pool in signaling" OFF)
option(INSTRUMENTED_ALLOCATORS "Enable memory instrumentation" OFF)
option(ENABLE_AWS_SDK_IN_TESTS "Enable support for compiling AWS SDKs for tests" ON)
option(ENABLE_STATS_CALCULATION_CONTROL "Enable support for runtime control of ice agent stat calculations." OFF)

# Developer Flags
option(BUILD_TEST "Build the testing tree." OFF)
Expand Down Expand Up @@ -115,6 +116,10 @@ if (ENABLE_KVS_THREADPOOL)
add_definitions(-DENABLE_KVS_THREADPOOL)
endif()

if (ENABLE_STATS_CALCULATION_CONTROL)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be helpful to include a note explaining that this modification is for memory optimization, along with an estimate of the memory savings if this feature were disabled?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have "Disabling these stats may lead to reductions in memory use." in the ReadMe. Will leave this comment open so we can consider adding a memory saving estimation for all of these, perhaps after more testing is done?

add_definitions(-DENABLE_STATS_CALCULATION_CONTROL)
endif()

if(USE_OPENSSL)
add_definitions(-DKVS_USE_OPENSSL)
elseif(USE_MBEDTLS)
Expand Down
15 changes: 15 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ You can pass the following options to `cmake ..`.
* `-DLINK_PROFILER` -- Link with gperftools (available profiler options are listed [here](https://github.com/gperftools/gperftools))
* `-DPKG_CONFIG_EXECUTABLE` -- Set pkg config path. This might be required to find gstreamer's pkg config specifically on Windows.
* `-DENABLE_KVS_THREADPOOL` -- Enable the KVS threadpool which is off by default.
* `-DENABLE_STATS_CALCULATION_CONTROL` -- Enable the runtime control of ICE agent stats calculations.

To clean up the `open-source` and `build` folders from previous build, use `cmake --build . --target clean` from the `build` folder

Expand Down Expand Up @@ -589,6 +590,20 @@ Let us look into when each of these could be changed:
3. `iceConnectionCheckTimeout`: It is useful to increase this timeout in unstable/slow network where the packet exchange takes time and hence the binding request/response. Essentially, increasing it will allow atleast one candidate pair to be tried for nomination by the other peer.
4. `iceConnectionCheckPollingInterval`: This value is set to a default of 50 ms per [spec](https://datatracker.ietf.org/doc/html/rfc8445#section-14.2). Changing this would change the frequency of connectivity checks and essentially, the ICE state machine transitions. Decreasing the value could help in faster connection establishment in a reliable high performant network setting with good system resources. Increasing the value could help in reducing the network load, however, the connection establishment could slow down. Unless there is a strong reasoning, it is **NOT** recommended to deviate from spec/default.

### Enable ICE agent stats

The SDK calculates 4 different stats:
1. ICE server stats - stats for ICE servers the SDK is using
2. [Local candidate stats](https://www.w3.org/TR/webrtc-stats/#dom-rtcstatstype-local-candidate) - stats for the selected local candidate
3. [Remote candidate stats](https://www.w3.org/TR/webrtc-stats/#dom-rtcstatstype-remote-candidate) - stats for the selected remote candidate
4. [Candidate pair stats](https://www.w3.org/TR/webrtc-stats/#dom-rtcstatstype-candidate-pair) - stats for the selected candidate pair

For more information on these stats, refer to [AWS Docs](https://docs.aws.amazon.com/kinesisvideostreams-webrtc-dg/latest/devguide/kvswebrtc-reference.html)

The SDK enables generating these stats by default. To control whether the SDK calculates these stats, the ENABLE_STATS_CALCULATION_CONTROL CMake option must be set, enabling the use of the following field:
`configuration.kvsRtcConfiguration.enableIceStats = FALSE`.
Disabling these stats may lead to reductions in memory use.

## Documentation
All Public APIs are documented in our [Include.h](https://github.com/awslabs/amazon-kinesis-video-streams-webrtc-sdk-c/blob/main/src/include/com/amazonaws/kinesis/video/webrtcclient/Include.h), we also generate a [Doxygen](https://awslabs.github.io/amazon-kinesis-video-streams-webrtc-sdk-c/) each commit for easier navigation.

Expand Down
43 changes: 25 additions & 18 deletions samples/Common.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ VOID onConnectionStateChange(UINT64 customData, RTC_PEER_CONNECTION_STATE newSta
CHK_STATUS(peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->peerConnectionMetrics));
CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->iceMetrics));

if (STATUS_FAILED(retStatus = logSelectedIceCandidatesInformation(pSampleStreamingSession))) {
DLOGW("Failed to get information about selected Ice candidates: 0x%08x", retStatus);
if (pSampleConfiguration->enableIceStats) {
CHK_LOG_ERR(logSelectedIceCandidatesInformation(pSampleStreamingSession));
}
break;
case RTC_PEER_CONNECTION_STATE_FAILED:
Expand Down Expand Up @@ -114,21 +114,21 @@ STATUS logSelectedIceCandidatesInformation(PSampleStreamingSession pSampleStream
CHK(pSampleStreamingSession != NULL, STATUS_NULL_ARG);
rtcMetrics.requestedTypeOfStats = RTC_STATS_TYPE_LOCAL_CANDIDATE;
CHK_STATUS(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, NULL, &rtcMetrics));
DLOGD("Local Candidate IP Address: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.address);
DLOGD("Local Candidate type: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.candidateType);
DLOGD("Local Candidate port: %d", rtcMetrics.rtcStatsObject.localIceCandidateStats.port);
DLOGD("Local Candidate priority: %d", rtcMetrics.rtcStatsObject.localIceCandidateStats.priority);
DLOGD("Local Candidate transport protocol: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.protocol);
DLOGD("Local Candidate relay protocol: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.relayProtocol);
DLOGD("Local Candidate Ice server source: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.url);
DLOGI("Local Candidate IP Address: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.address);
DLOGI("Local Candidate type: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.candidateType);
DLOGI("Local Candidate port: %d", rtcMetrics.rtcStatsObject.localIceCandidateStats.port);
DLOGI("Local Candidate priority: %d", rtcMetrics.rtcStatsObject.localIceCandidateStats.priority);
DLOGI("Local Candidate transport protocol: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.protocol);
DLOGI("Local Candidate relay protocol: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.relayProtocol);
DLOGI("Local Candidate Ice server source: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.url);

rtcMetrics.requestedTypeOfStats = RTC_STATS_TYPE_REMOTE_CANDIDATE;
CHK_STATUS(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, NULL, &rtcMetrics));
DLOGD("Remote Candidate IP Address: %s", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.address);
DLOGD("Remote Candidate type: %s", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.candidateType);
DLOGD("Remote Candidate port: %d", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.port);
DLOGD("Remote Candidate priority: %d", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.priority);
DLOGD("Remote Candidate transport protocol: %s", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.protocol);
DLOGI("Remote Candidate IP Address: %s", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.address);
DLOGI("Remote Candidate type: %s", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.candidateType);
DLOGI("Remote Candidate port: %d", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.port);
DLOGI("Remote Candidate priority: %d", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.priority);
DLOGI("Remote Candidate transport protocol: %s", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.protocol);
CleanUp:
LEAVES();
return retStatus;
Expand Down Expand Up @@ -365,6 +365,10 @@ STATUS initializePeerConnection(PSampleConfiguration pSampleConfiguration, PRtcP
// Set the ICE mode explicitly
configuration.iceTransportPolicy = ICE_TRANSPORT_POLICY_ALL;

#ifdef ENABLE_STATS_CALCULATION_CONTROL
configuration.kvsRtcConfiguration.enableIceStats = pSampleConfiguration->enableIceStats;
#endif

// Set the STUN server
PCHAR pKinesisVideoStunUrlPostFix = KINESIS_VIDEO_STUN_URL_POSTFIX;
// If region is in CN, add CN region uri postfix
Expand Down Expand Up @@ -501,6 +505,10 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P
pSampleStreamingSession->twccMetadata.updateLock = MUTEX_CREATE(TRUE);
}

// Flag to enable/disable SDK calculations of selected ice server, local, remote and candidate pair stats.
// Note: enableIceStats only has an effect if compiler flag ENABLE_STATS_CALCULATION_CONTROL is defined.
pSampleConfiguration->enableIceStats = FALSE;

CHK_STATUS(initializePeerConnection(pSampleConfiguration, &pSampleStreamingSession->pPeerConnection));
CHK_STATUS(peerConnectionOnIceCandidate(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, onIceCandidateHandler));
CHK_STATUS(
Expand Down Expand Up @@ -1208,9 +1216,8 @@ STATUS freeSampleConfiguration(PSampleConfiguration* ppSampleConfiguration)
}

for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) {
retStatus = gatherIceServerStats(pSampleConfiguration->sampleStreamingSessionList[i]);
if (STATUS_FAILED(retStatus)) {
DLOGW("Failed to ICE Server Stats for streaming session %d: %08x", i, retStatus);
if (pSampleConfiguration->enableIceStats) {
CHK_LOG_ERR(gatherIceServerStats(pSampleConfiguration->sampleStreamingSessionList[i]));
}
freeSampleStreamingSession(&pSampleConfiguration->sampleStreamingSessionList[i]);
}
Expand Down Expand Up @@ -1542,7 +1549,7 @@ STATUS signalingMessageReceived(UINT64 customData, PReceivedSignalingMessage pRe
MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock);
locked = FALSE;

if (startStats &&
if (pSampleConfiguration->enableIceStats && startStats &&
STATUS_FAILED(retStatus = timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, SAMPLE_STATS_DURATION, SAMPLE_STATS_DURATION,
getIceCandidatePairStatsCallback, (UINT64) pSampleConfiguration,
&pSampleConfiguration->iceCandidatePairStatsTimerId))) {
Expand Down
1 change: 1 addition & 0 deletions samples/Samples.h
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ typedef struct {
PCHAR rtspUri;
UINT32 logLevel;
BOOL enableTwcc;
BOOL enableIceStats;
} SampleConfiguration, *PSampleConfiguration;

typedef struct {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -460,11 +460,6 @@ extern "C" {
*/
#define MAX_SIGNALING_ENDPOINT_URI_LEN 512

/**
* Maximum allowed ICE URI length
*/
#define MAX_ICE_CONFIG_URI_LEN 256

/**
* Maximum allowed correlation ID length
*/
Expand Down Expand Up @@ -1204,6 +1199,10 @@ typedef struct {
BOOL disableSenderSideBandwidthEstimation; //!< Disable TWCC feedback based sender bandwidth estimation, enabled by default.
//!< You want to set this to TRUE if you are on a very stable connection and want to save 1.2MB of
//!< memory
#ifdef ENABLE_STATS_CALCULATION_CONTROL
BOOL enableIceStats; //!< Control whether ICE agent stats are to be calculated. ENABLE_STATS_CALCULATION_CONTROL compiler flag must be defined
stefankiesz marked this conversation as resolved.
Show resolved Hide resolved
//!< to use this member, else stats are enabled by default.
#endif
} KvsRtcConfiguration, *PKvsRtcConfiguration;

/**
Expand Down
43 changes: 26 additions & 17 deletions src/include/com/amazonaws/kinesis/video/webrtcclient/Stats.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,11 @@ extern "C" {
*/
#define MAX_CANDIDATE_ID_LENGTH 9U

/**
* Maximum allowed ICE URI length
*/
#define MAX_ICE_CONFIG_URI_LEN 256

/**
* Maximum allowed relay protocol length
*/
Expand Down Expand Up @@ -63,6 +68,11 @@ extern "C" {
* Maximum allowed generic length used in DOMString
*/
#define MAX_STATS_STRING_LENGTH 255U

/**
* Maximum length of candidate type (host, srflx, relay, prflx, unknown)
*/
#define MAX_CANDIDATE_TYPE_LENGTH 10U
/*!@} */

/**
Expand Down Expand Up @@ -233,14 +243,14 @@ typedef struct {
* Reference: https://www.w3.org/TR/webrtc-stats/#ice-server-dict*
*/
typedef struct {
DOMString url; //!< STUN/TURN server URL
DOMString protocol; //!< Valid values: UDP, TCP
UINT32 iceServerIndex; //!< Ice server index to get stats from. Not available in spec! Needs to be
//!< populated by the application to get specific server stats
INT32 port; //!< Port number used by client
UINT64 totalRequestsSent; //!< Total amount of requests that have been sent to the server
UINT64 totalResponsesReceived; //!< Total number of responses received from the server
UINT64 totalRoundTripTime; //!< Sum of RTTs of all the requests for which response has been received
CHAR url[MAX_ICE_CONFIG_URI_LEN + 1]; //!< STUN/TURN server URL
CHAR protocol[MAX_PROTOCOL_LENGTH + 1]; //!< Valid values: UDP, TCP
UINT32 iceServerIndex; //!< Ice server index to get stats from. Not available in spec! Needs to be
//!< populated by the application to get specific server stats
INT32 port; //!< Port number used by client
UINT64 totalRequestsSent; //!< Total amount of requests that have been sent to the server
UINT64 totalResponsesReceived; //!< Total number of responses received from the server
UINT64 totalRoundTripTime; //!< Sum of RTTs of all the requests for which response has been received
} RtcIceServerStats, *PRtcIceServerStats;

/**
Expand All @@ -267,15 +277,14 @@ typedef struct {
*/

typedef struct {
DOMString url; //!< For local candidates this is the URL of the ICE server from which the candidate was obtained
DOMString transportId; //!< Not used currently. ID of object that was inspected for RTCTransportStats
CHAR address[IP_ADDR_STR_LENGTH + 1]; //!< IPv4 or IPv6 address of the candidate
DOMString protocol; //!< Valid values: UDP, TCP
DOMString relayProtocol; //!< Protocol used by endpoint to communicate with TURN server. (Only for local candidate)
//!< Valid values: UDP, TCP, TLS
INT32 priority; //!< Computed using the formula in https://tools.ietf.org/html/rfc5245#section-15.1
INT32 port; //!< Port number of the candidate
DOMString candidateType; //!< Type of local/remote ICE candidate
DOMString url; //!< For local candidates this is the URL of the ICE server from which the candidate was obtained
stefankiesz marked this conversation as resolved.
Show resolved Hide resolved
CHAR address[IP_ADDR_STR_LENGTH + 1]; //!< IPv4 or IPv6 address of the candidate
CHAR protocol[MAX_PROTOCOL_LENGTH + 1]; //!< Valid values: UDP, TCP
CHAR relayProtocol[MAX_PROTOCOL_LENGTH + 1]; //!< Protocol used by endpoint to communicate with TURN server. (Only for local candidate)
//!< Valid values: UDP, TCP, TLS
INT32 priority; //!< Computed using the formula in https://tools.ietf.org/html/rfc5245#section-15.1
INT32 port; //!< Port number of the candidate
CHAR candidateType[MAX_CANDIDATE_TYPE_LENGTH + 1]; //!< Type of local/remote ICE candidate
} RtcIceCandidateStats, *PRtcIceCandidateStats;

/**
Expand Down
Loading
Loading