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

Default stack size change and Rolling buffer config rework #2011

Open
wants to merge 30 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
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
38 changes: 20 additions & 18 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -54,11 +54,11 @@ add_definitions(-DVERSION_STRING=\"${PROJECT_VERSION}\")
add_definitions(-DDETECTED_GIT_HASH)

if(NOT KVS_STACK_SIZE OR KVS_STACK_SIZE STREQUAL "")
message(STATUS "Setting default stack size to 64*1024")
set(KVS_DEFAULT_STACK_SIZE 65536)
add_definitions(-DKVS_DEFAULT_STACK_SIZE=65536)
message(STATUS "Setting default stack size to platform specific stack size")
set(KVS_DEFAULT_STACK_SIZE 0)
add_definitions(-DKVS_DEFAULT_STACK_SIZE=0)
else()
message(STATUS "Setting default stack size to provided value")
message(STATUS "Setting default stack size to provided value of ${KVS_STACK_SIZE}")
disa6302 marked this conversation as resolved.
Show resolved Hide resolved
set(KVS_DEFAULT_STACK_SIZE ${KVS_STACK_SIZE})
add_definitions(-DKVS_DEFAULT_STACK_SIZE=${KVS_STACK_SIZE})
endif()
Expand Down Expand Up @@ -214,16 +214,6 @@ if(BUILD_DEPENDENCIES)

build_dependency(srtp ${BUILD_ARGS})

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}/configs")
set(BUILD_ARGS
-DBUILD_STATIC_LIBS=${BUILD_STATIC_LIBS}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS})

build_dependency(kvssdp ${BUILD_ARGS})
build_dependency(kvsstun ${BUILD_ARGS})
build_dependency(kvsrtp ${BUILD_ARGS})

set(BUILD_ARGS
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS})
Expand Down Expand Up @@ -260,6 +250,16 @@ set(BUILD_ARGS
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS})
build_dependency(kvsCommonLws ${BUILD_ARGS})

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}/configs")
set(BUILD_ARGS
-DBUILD_STATIC_LIBS=${BUILD_STATIC_LIBS}
-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}
-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS})

# Custom dependencies that need to be built
build_dependency(kvssdp ${BUILD_ARGS})
build_dependency(kvsstun ${BUILD_ARGS})
build_dependency(kvsrtp ${BUILD_ARGS})
############# find dependent libraries ############

find_package(Threads)
Expand Down Expand Up @@ -388,6 +388,7 @@ endif()

file(GLOB WEBRTC_SIGNALING_CLIENT_SOURCE_FILES "src/source/Signaling/*.c")

message(STATUS "OPEN_SRC_INSTALL_PREFIX: ${OPEN_SRC_INSTALL_PREFIX}")
include_directories(${OPEN_SRC_INCLUDE_DIRS})
include_directories(${OPEN_SRC_INSTALL_PREFIX}/include)
include_directories(${KINESIS_VIDEO_WEBRTC_CLIENT_SRC}/src/include)
Expand All @@ -401,17 +402,18 @@ endif()
if(ENABLE_KVS_THREADPOOL)
file(GLOB THREADPOOL_SOURCE_FILES "src/source/Threadpool/*.c")
add_library(kvsWebRtcThreadpool ${LINKAGE} ${THREADPOOL_SOURCE_FILES})
target_link_libraries(kvsWebRtcThreadpool PRIVATE kvspicUtils)
target_link_libraries(kvsWebRtcThreadpool PUBLIC kvspicUtils)
set(EXTRA_DEPS ${EXTRA_DEPS} kvsWebRtcThreadpool)
endif()

target_link_libraries(
kvsWebrtcClient
PUBLIC
kvssdp
kvsstun
kvsrtp
PRIVATE kvspicUtils
kvspicState
kvssdp
kvsstun
kvsrtp
${CMAKE_THREAD_LIBS_INIT}
${OPENSSL_SSL_LIBRARY}
${OPENSSL_CRYPTO_LIBRARY}
Expand Down
106 changes: 62 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -374,6 +374,68 @@ If using the WebRTC SDK Test Page, set the following values using the same AWS c

Then choose Start Viewer to start live video streaming of the sample H264/Opus frames.

## Memory optimization switches

Starting with v1.11.0, the SDK provides some knobs to optimize memory usage to tailor to platform needs and resources

### Controlling RTP rolling buffer capacity

The SDK maintains an RTP rolling buffer to hold the RTP packets. This is useful to respond to NACKs and even in case of JitterBuffer. The rolling buffer size is controlled by 3 parameters:
1. MTU: This is set to a default of 1200 bytes
2. Buffer duration: This is the amount of time of media that you would like the rolling buffer to accommodate before it is overwritten due to buffer overflow. By default, the SDK sets this to 3 seconds
3. Highest expected bitrate: This is the expected bitrate of the media in question. The typical bitrates could vary based on resolution and codec. By default, the SDK sets this to 5 mibps for video and 1 mibps for audio

The rolling buffer capacity is calculated as follows:
```
Capacity = Buffer duration * highest expected bitrate (in bips) / 8 / MTU

With buffer duration = 1 second, Highest expected bitrate = 5 mibps and MTU 1200 bytes, capacity = 546 RTP packets
```

The rolling buffer size can be configured per transceiver using the `createRollingBufferConfig` API. Make sure to use the API after the addTransceiver call to ensure the `RtcMediaStreamTrack` and `KvsRtpTransceiver` objects are created. By default, the rolling buffer duration is set to 3 sec and bitrate is set to 5mibps for video an 1mibps for audio.

The rolling buffer config parameters are as follows:
```
rollingBufferDurationSec = <duration in seconds>, must be more than 100ms and less than 10 seconds (translates to 0.1 seconds)
rollingBufferBitratebps = <bitrate in bits/sec>, must be more than 100kibits/sec and less than 240 mibps
```

For example, if we want to set duration to 200ms and bitrate to 150kibps,
```c
PRtcRtpTransceiver pVideoRtcRtpTransceiver;
RtcMediaStreamTrack videoTrack;
videoTrack.kind = MEDIA_STREAM_TRACK_KIND_VIDEO;
videoTrack.codec = RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE;
CHK_STATUS(createRollingBufferConfig(pVideoRtcRtpTransceiver, &videoTrack, 0.2, 150 * 1024));
```
By setting these up, applications can have better control over the amount of memory that the application consumes. However, note, if the allocation is too small and the network bad leading to multiple nacks, it can lead to choppy media / dropped frames. Hence, care must be taken while deciding on the values to ensure the parameters satisfy necessary performance requirements.
For more information, check the sample to see how these values are set up.

### Thread stack sizes
The default thread stack size for the KVS WebRTC SDK is platform specific. The SDK provides 2 avenues to modify the stack sizes:
1. `THREAD_CREATE_WITH_PARAMS`: Use this API to control the thread stack size for individual threads. Starting v1.11.0, the samples set these up for the sample media threads.
2. `-DKVS_STACK_SIZE`: Default stack size for threads created using THREAD_CREATE(). The parameter is set to 0 by default, which means the SDK will use platform specific defaults. To set a particular value, build the SDK with this option and provide the size in bytes. For example, to set stack size for threads to 64KiB,
```
cmake .. -DKVS_STACK_SIZE=65536`
```

The samples provided with this SDK have been tested with a lowest stack size of 64KiB.

If your SOC/platform has a high default stack size, it is recommended to tweak these values to ensure reducing your application's memory footprint.

### Disable 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 **disables** generating these stats by default. In order to be enable the SDK to calculate these stats, the application needs to set the following field:
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
The SDK **disables** generating these stats by default. In order to be enable the SDK to calculate these stats, the application needs to set the following field:
The SDK **disables** generating these stats by default. In order to enable the SDK to calculate these stats, the application needs to set the following field:

`configuration.kvsRtcConfiguration.enableIceStats = TRUE`. Note that this increases the memory usage by about 200KB per peer connection.

## Setup IoT
* To use IoT certificate to authenticate with KVS signaling, please refer to [Controlling Access to Kinesis Video Streams Resources Using AWS IoT](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/how-iot.html) for provisioning details.
* A sample IAM policy for the IoT role looks like below, policy can be modified based on your permission requirement.
Expand Down Expand Up @@ -539,9 +601,6 @@ The threadpool is enabled by default, and starts with 1 threads that it can incr

To disable threadpool, run `cmake .. -DENABLE_KVS_THREADPOOL=OFF`

### Thread stack sizes
The default thread stack size for the KVS WebRTC SDK is 64 kb. Notable stack sizes that may need to be changed for your specific application will be the ConnectionListener Receiver thread and the media sender threads. Please modify the stack sizes for these media dependent threads to be suitable for the media your application is processing.

### Set up TWCC
TWCC is a mechanism in WebRTC designed to enhance the performance and reliability of real-time communication over the Internet. TWCC addresses the challenges of network congestion by providing detailed feedback on the transport of packets across the network, enabling adaptive bitrate control and optimization of
media streams in real-time. This feedback mechanism is crucial for maintaining high-quality audio and video communication, as it allows senders to adjust their transmission strategies based on comprehensive information about packet losses, delays, and jitter experienced across the entire transport path.
Expand Down Expand Up @@ -586,47 +645,6 @@ 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 disables generating these stats by default. In order to be enable the SDK to calculate these stats, the application needs to set the following field:
`configuration.kvsRtcConfiguration.enableIceStats = TRUE`.

### Controlling RTP rolling buffer capacity

The SDK maintains an RTP rolling buffer to hold the RTP packets. This is useful to respond to NACKs and even in case of JitterBuffer. The rolling buffer size is controlled by 3 parameters:
1. MTU: This is set to a default of 1200 bytes
2. Buffer duration: This is the amount of time of media that you would like the rolling buffer to accommodate before it is overwritten due to buffer overflow. By default, the SDK sets this to 1 second
3. Highest expected bitrate: This is the expected bitrate of the media in question. The typical bitrates could vary based on resolution and codec. By default, the SDK sets this to 5 mibps for video and 1 mibps for audio

The rolling buffer capacity is calculated as follows:
```
Capacity = Buffer duration * highest expected bitrate (in bps) / 8 / MTU

With buffer duration = 1 second, Highest expected bitrate = 5 mibps and MTU 1200 bytes, capacity = 546 RTP packets
```

The rolling buffer size can be configured per transceiver through the following fields:
```
RtcRtpTransceiverInit.rollingBufferDurationSec = <duration in seconds, must be more than 100ms (translates to 0.1 seconds)
RtcRtpTransceiverInit.rollingBufferBitratebps = <bitrate in bits/sec, must be more than 100kibits/sec
```

For example, if we want to set duration to 200ms and birtate to 150kibps,
```
RtcRtpTransceiverInit.rollingBufferDurationSec = 0.2;
RtcRtpTransceiverInit.rollingBufferBitratebps = 150 * 1024;
```
By setting these up, applications can have better control over the amount of memory that the application consumes. However, note, if the allocation is too small and the network bad leading to multiple nacks, it can lead to choppy media / dropped frames. Hence, care must be taken while deciding on the values to ensure the parameters satisfy necessary performance requirements.
For more information, check the sample to see how these values are set up.

## Documentation
All Public APIs are documented in our [Include.h](https://github.com/awslabs/amazon-kinesis-video-streams-webrtc-sdk-c/blob/master/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
28 changes: 21 additions & 7 deletions samples/Common.c
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,8 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P

MEMSET(&videoTrack, 0x00, SIZEOF(RtcMediaStreamTrack));
MEMSET(&audioTrack, 0x00, SIZEOF(RtcMediaStreamTrack));
MEMSET(&audioRtpTransceiverInit, 0x00, SIZEOF(RtcRtpTransceiverInit));
MEMSET(&videoRtpTransceiverInit, 0x00, SIZEOF(RtcRtpTransceiverInit));
disa6302 marked this conversation as resolved.
Show resolved Hide resolved

CHK(pSampleConfiguration != NULL && ppSampleStreamingSession != NULL, STATUS_NULL_ARG);
CHK((isMaster && peerId != NULL) || !isMaster, STATUS_INVALID_ARG);
Expand Down Expand Up @@ -578,30 +580,42 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P
videoTrack.kind = MEDIA_STREAM_TRACK_KIND_VIDEO;
videoTrack.codec = pSampleConfiguration->videoCodec;
videoRtpTransceiverInit.direction = RTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV;
videoRtpTransceiverInit.rollingBufferDurationSec = 3;
// Considering 4 Mbps for 720p (which is what our samples use). This is for H.264.
// The value could be different for other codecs.
videoRtpTransceiverInit.rollingBufferBitratebps = 4 * 1024 * 1024;
STRCPY(videoTrack.streamId, "myKvsVideoStream");
STRCPY(videoTrack.trackId, "myVideoTrack");
CHK_STATUS(addTransceiver(pSampleStreamingSession->pPeerConnection, &videoTrack, &videoRtpTransceiverInit,
&pSampleStreamingSession->pVideoRtcRtpTransceiver));

if (videoTrack.codec == RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE) {
CHK_STATUS(createRollingBufferConfig(pSampleStreamingSession->pVideoRtcRtpTransceiver, &videoTrack, H264_ROLLING_BUFFER_DURATION_SECONDS,
H264_ROLLING_BUFFER_BITRATE_BITS_PER_SECOND));
} else if (videoTrack.codec == RTC_CODEC_H265) {
CHK_STATUS(createRollingBufferConfig(pSampleStreamingSession->pVideoRtcRtpTransceiver, &videoTrack, H265_ROLLING_BUFFER_DURATION_SECONDS,
H265_ROLLING_BUFFER_BITRATE_BITS_PER_SECOND));
} else if (videoTrack.codec == RTC_CODEC_VP8) {
CHK_STATUS(createRollingBufferConfig(pSampleStreamingSession->pVideoRtcRtpTransceiver, &videoTrack, VP8_ROLLING_BUFFER_DURATION_SECONDS,
VP8_ROLLING_BUFFER_BITRATE_BITS_PER_SECOND));
}

CHK_STATUS(transceiverOnBandwidthEstimation(pSampleStreamingSession->pVideoRtcRtpTransceiver, (UINT64) pSampleStreamingSession,
sampleBandwidthEstimationHandler));

// Add a SendRecv Transceiver of type audio
audioTrack.kind = MEDIA_STREAM_TRACK_KIND_AUDIO;
audioTrack.codec = pSampleConfiguration->audioCodec;
audioRtpTransceiverInit.direction = RTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV;
audioRtpTransceiverInit.rollingBufferDurationSec = 3;
// For opus, the bitrate could be between 6 Kbps to 510 Kbps
audioRtpTransceiverInit.rollingBufferBitratebps = 510 * 1024;
STRCPY(audioTrack.streamId, "myKvsVideoStream");
STRCPY(audioTrack.trackId, "myAudioTrack");
CHK_STATUS(addTransceiver(pSampleStreamingSession->pPeerConnection, &audioTrack, &audioRtpTransceiverInit,
&pSampleStreamingSession->pAudioRtcRtpTransceiver));

if (audioTrack.codec == RTC_CODEC_OPUS) {
CHK_STATUS(createRollingBufferConfig(pSampleStreamingSession->pAudioRtcRtpTransceiver, &audioTrack, OPUS_ROLLING_BUFFER_DURATION_SECONDS,
OPUS_ROLLING_BUFFER_BITRATE_BITS_PER_SECOND));
} else if (audioTrack.codec == RTC_CODEC_ALAW || audioTrack.codec == RTC_CODEC_MULAW) {
CHK_STATUS(createRollingBufferConfig(pSampleStreamingSession->pAudioRtcRtpTransceiver, &audioTrack, G711_ROLLING_BUFFER_DURATION_SECONDS,
G711_ROLLING_BUFFER_BITRATE_BITS_PER_SECOND));
}

CHK_STATUS(transceiverOnBandwidthEstimation(pSampleStreamingSession->pAudioRtcRtpTransceiver, (UINT64) pSampleStreamingSession,
sampleBandwidthEstimationHandler));
// twcc bandwidth estimation
Expand Down
12 changes: 12 additions & 0 deletions samples/Samples.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,18 @@ extern "C" {
#define MASTER_DATA_CHANNEL_MESSAGE "This message is from the KVS Master"
#define VIEWER_DATA_CHANNEL_MESSAGE "This message is from the KVS Viewer"

#define H264_ROLLING_BUFFER_DURATION_SECONDS (DOUBLE) 3
#define H264_ROLLING_BUFFER_BITRATE_BITS_PER_SECOND (DOUBLE) 4 * 1024 * 1024 // Based on 1080p resolution
#define H265_ROLLING_BUFFER_DURATION_SECONDS (DOUBLE) 3
#define H265_ROLLING_BUFFER_BITRATE_BITS_PER_SECOND (DOUBLE) 4 * 1024 * 1024 // Based on 1080p resolution
#define VP8_ROLLING_BUFFER_DURATION_SECONDS (DOUBLE) 3
#define VP8_ROLLING_BUFFER_BITRATE_BITS_PER_SECOND (DOUBLE) 6 * 1024 * 1024 // Based on 1080p resolution
#define OPUS_ROLLING_BUFFER_DURATION_SECONDS (DOUBLE) 3
#define OPUS_ROLLING_BUFFER_BITRATE_BITS_PER_SECOND \
(DOUBLE) 510 * 1024 // Opus supports bitrates from 6 kbps to 510 kbps for typical stereo audio sources
#define G711_ROLLING_BUFFER_DURATION_SECONDS (DOUBLE) 3
#define G711_ROLLING_BUFFER_BITRATE_BITS_PER_SECOND (DOUBLE) 64 * 1024 // G.711 codecs use a sampling rate of 8 kHz and 8 bits per sample

#define DATA_CHANNEL_MESSAGE_TEMPLATE \
"{\"content\":\"%s\",\"firstMessageFromViewerTs\":\"%s\",\"firstMessageFromMasterTs\":\"%s\",\"secondMessageFromViewerTs\":\"%s\"," \
"\"secondMessageFromMasterTs\":\"%s\",\"lastMessageFromViewerTs\":\"%s\" }"
Expand Down
Loading