From 88131bc1fc149b9df07626b7bddb2a0741a12b3e Mon Sep 17 00:00:00 2001 From: Stefan Kieszkowski <85728496+stefankiesz@users.noreply.github.com> Date: Fri, 22 Nov 2024 10:53:02 -0800 Subject: [PATCH] Memory Optimization - Rolling Buffer (#2077) * Rb size config (#1921) * Reduce default size * Rolling buffer configurability * Add configurability * Allow setting parameter through trx instead of config * Add UT, fix the members to DOUBLE * Remove unnecessary fields * Rolling buffer readme update * Use enums for min values * Add usage example in samples * Fix unit test * Memset init in UTs * Modify the bitrates in the samples based on codec used in our samples * Modify unit tests, add video/audio specific defaults * Add missing null check * Readme update * Address nits * Clang fix * Logs for RB * set explicit type cast * add max values * Refactor RB logic, readme update, sample cleanup * nits * Fix unit tests * return * update description in header * fix unused var * minor changes * typo fix * review comments * sdp, stun, rtp * comments * cancelled builds * log status * sctp * Revert unrelated sample changes * Revert unrelated CMake changes * Revert unrelated test changes * Revert unrelated ReadMe changes * Fix DEFAULT_MTU_SIZE variable name * Cleanup merge changes * Fixup and comment on Rtp.c * Fixup Rtp.h * Fixup ReadMe * Clang format * Revert all sample changes * Address comments * Add back accidentally deleted line * Address comment * Update README.md --------- Co-authored-by: Divya Sampath Kumar --- CMakeLists.txt | 1 + README.md | 37 +++++++ .../kinesis/video/webrtcclient/Include.h | 15 ++- src/source/Crypto/Dtls_mbedtls.c | 4 +- src/source/Crypto/Tls_mbedtls.c | 4 +- src/source/PeerConnection/PeerConnection.c | 23 +++- src/source/PeerConnection/Rtp.c | 78 +++++++++++++ src/source/PeerConnection/Rtp.h | 22 +++- .../PeerConnection/SessionDescription.c | 20 +++- tst/DtlsFunctionalityTest.cpp | 16 +-- tst/RtcpFunctionalityTest.cpp | 2 +- tst/RtpFunctionalityTest.cpp | 20 ++-- tst/RtpRollingBufferFunctionalityTest.cpp | 104 ++++++++++++++++++ tst/SdpApiTest.cpp | 13 ++- 14 files changed, 325 insertions(+), 34 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index bc3508db3d..c4b1c22c5e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -391,6 +391,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) diff --git a/README.md b/README.md index 0c1b4ef690..ad917e112b 100644 --- a/README.md +++ b/README.md @@ -370,6 +370,43 @@ 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 `configureTransceiverRollingBuffer` 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 and 1mibps for audio. + +The rolling buffer config parameters are as follows: +``` +rollingBufferDurationSec = , must be more than 100ms and less than 10 seconds +rollingBufferBitratebps = , 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(configureTransceiverRollingBuffer(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. + ## 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. diff --git a/src/include/com/amazonaws/kinesis/video/webrtcclient/Include.h b/src/include/com/amazonaws/kinesis/video/webrtcclient/Include.h index 535e34509f..cac592962d 100644 --- a/src/include/com/amazonaws/kinesis/video/webrtcclient/Include.h +++ b/src/include/com/amazonaws/kinesis/video/webrtcclient/Include.h @@ -1167,7 +1167,7 @@ typedef struct { UINT16 maximumTransmissionUnit; //!< Controls the size of the largest packet the WebRTC SDK will send //!< Some networks may drop packets if they exceed a certain size, and is useful in those conditions. //!< A smaller MTU will incur higher bandwidth usage however since more packets will be generated with - //!< smaller payloads. If unset DEFAULT_MTU_SIZE will be used + //!< smaller payloads. If unset DEFAULT_MTU_SIZE_BYTES will be used UINT32 iceLocalCandidateGatheringTimeout; //!< Maximum time ice will wait for gathering STUN and RELAY candidates. Once //!< it's reached, ice will proceed with whatever candidate it current has. Use default value if 0. @@ -1609,6 +1609,19 @@ typedef struct { * @{ */ +/** + * @brief Set up rolling buffer configuration - max duration of media to store (sec) and expected max bitrate (bips) of the encoded media + * + * + * @param[in] PRtcRtpTransceiver IN/Initialized and configured RtcRtpTransceiver + * @param[in] PRtcMediaStreamTrack IN/Initialized media stream track information + * @param[in] DOUBLE IN/Rolling buffer duration in seconds + * @param[in] DOUBLE IN/Rolling buffer bitrate in bits/second + * + * @return STATUS code of the execution. STATUS_SUCCESS on success + */ +STATUS configureTransceiverRollingBuffer(PRtcRtpTransceiver, PRtcMediaStreamTrack, DOUBLE, DOUBLE); + /** * @brief Initialize a RtcPeerConnection with the provided Configuration * diff --git a/src/source/Crypto/Dtls_mbedtls.c b/src/source/Crypto/Dtls_mbedtls.c index 29dca1a8c6..ac59402f67 100644 --- a/src/source/Crypto/Dtls_mbedtls.c +++ b/src/source/Crypto/Dtls_mbedtls.c @@ -31,7 +31,7 @@ STATUS createDtlsSession(PDtlsSessionCallbacks pDtlsSessionCallbacks, TIMER_QUEU mbedtls_ctr_drbg_set_prediction_resistance(&pDtlsSession->ctrDrbg, MBEDTLS_CTR_DRBG_PR_ON); CHK(mbedtls_ctr_drbg_seed(&pDtlsSession->ctrDrbg, mbedtls_entropy_func, &pDtlsSession->entropy, NULL, 0) == 0, STATUS_CREATE_SSL_FAILED); - CHK_STATUS(createIOBuffer(DEFAULT_MTU_SIZE, &pDtlsSession->pReadBuffer)); + CHK_STATUS(createIOBuffer(DEFAULT_MTU_SIZE_BYTES, &pDtlsSession->pReadBuffer)); pDtlsSession->timerQueueHandle = timerQueueHandle; pDtlsSession->timerId = MAX_UINT32; pDtlsSession->sslLock = MUTEX_CREATE(TRUE); @@ -290,7 +290,7 @@ STATUS dtlsSessionStart(PDtlsSession pDtlsSession, BOOL isServer) mbedtls_ssl_conf_export_keys_ext_cb(&pDtlsSession->sslCtxConfig, dtlsSessionKeyDerivationCallback, pDtlsSession); CHK(mbedtls_ssl_setup(&pDtlsSession->sslCtx, &pDtlsSession->sslCtxConfig) == 0, STATUS_SSL_CTX_CREATION_FAILED); - mbedtls_ssl_set_mtu(&pDtlsSession->sslCtx, DEFAULT_MTU_SIZE); + mbedtls_ssl_set_mtu(&pDtlsSession->sslCtx, DEFAULT_MTU_SIZE_BYTES); mbedtls_ssl_set_bio(&pDtlsSession->sslCtx, pDtlsSession, dtlsSessionSendCallback, dtlsSessionReceiveCallback, NULL); mbedtls_ssl_set_timer_cb(&pDtlsSession->sslCtx, &pDtlsSession->transmissionTimer, dtlsSessionSetTimerCallback, dtlsSessionGetTimerCallback); diff --git a/src/source/Crypto/Tls_mbedtls.c b/src/source/Crypto/Tls_mbedtls.c index 3b17c1ea7f..ea4c1ea40a 100644 --- a/src/source/Crypto/Tls_mbedtls.c +++ b/src/source/Crypto/Tls_mbedtls.c @@ -15,7 +15,7 @@ STATUS createTlsSession(PTlsSessionCallbacks pCallbacks, PTlsSession* ppTlsSessi pTlsSession = (PTlsSession) MEMCALLOC(1, SIZEOF(TlsSession)); CHK(pTlsSession != NULL, STATUS_NOT_ENOUGH_MEMORY); - CHK_STATUS(createIOBuffer(DEFAULT_MTU_SIZE, &pTlsSession->pReadBuffer)); + CHK_STATUS(createIOBuffer(DEFAULT_MTU_SIZE_BYTES, &pTlsSession->pReadBuffer)); pTlsSession->callbacks = *pCallbacks; pTlsSession->state = TLS_SESSION_STATE_NEW; @@ -117,7 +117,7 @@ STATUS tlsSessionStart(PTlsSession pTlsSession, BOOL isServer) mbedtls_ssl_conf_authmode(&pTlsSession->sslCtxConfig, MBEDTLS_SSL_VERIFY_REQUIRED); mbedtls_ssl_conf_rng(&pTlsSession->sslCtxConfig, mbedtls_ctr_drbg_random, &pTlsSession->ctrDrbg); CHK(mbedtls_ssl_setup(&pTlsSession->sslCtx, &pTlsSession->sslCtxConfig) == 0, STATUS_SSL_CTX_CREATION_FAILED); - mbedtls_ssl_set_mtu(&pTlsSession->sslCtx, DEFAULT_MTU_SIZE); + mbedtls_ssl_set_mtu(&pTlsSession->sslCtx, DEFAULT_MTU_SIZE_BYTES); mbedtls_ssl_set_bio(&pTlsSession->sslCtx, pTlsSession, tlsSessionSendCallback, tlsSessionReceiveCallback, NULL); /* init and send handshake */ diff --git a/src/source/PeerConnection/PeerConnection.c b/src/source/PeerConnection/PeerConnection.c index ce5dd86bc7..d25101cb38 100644 --- a/src/source/PeerConnection/PeerConnection.c +++ b/src/source/PeerConnection/PeerConnection.c @@ -961,6 +961,7 @@ STATUS createPeerConnection(PRtcConfiguration pConfiguration, PRtcPeerConnection CHK_STATUS(timerQueueCreate(&pKvsPeerConnection->timerQueueHandle)); pKvsPeerConnection->peerConnection.version = PEER_CONNECTION_CURRENT_VERSION; + CHK_STATUS(generateJSONSafeString(pKvsPeerConnection->localIceUfrag, LOCAL_ICE_UFRAG_LEN)); CHK_STATUS(generateJSONSafeString(pKvsPeerConnection->localIcePwd, LOCAL_ICE_PWD_LEN)); CHK_STATUS(generateJSONSafeString(pKvsPeerConnection->localCNAME, LOCAL_CNAME_LEN)); @@ -983,7 +984,7 @@ STATUS createPeerConnection(PRtcConfiguration pConfiguration, PRtcPeerConnection pKvsPeerConnection->peerConnectionObjLock = MUTEX_CREATE(FALSE); pKvsPeerConnection->connectionState = RTC_PEER_CONNECTION_STATE_NONE; pKvsPeerConnection->MTU = pConfiguration->kvsRtcConfiguration.maximumTransmissionUnit == 0 - ? DEFAULT_MTU_SIZE + ? DEFAULT_MTU_SIZE_BYTES : pConfiguration->kvsRtcConfiguration.maximumTransmissionUnit; ATOMIC_STORE_BOOL(&pKvsPeerConnection->sctpIsEnabled, FALSE); @@ -1539,6 +1540,19 @@ STATUS setLocalDescription(PRtcPeerConnection pPeerConnection, PRtcSessionDescri return retStatus; } +STATUS configureTransceiverRollingBuffer(PRtcRtpTransceiver pRtcRtpTransceiver, PRtcMediaStreamTrack pRtcMediaStreamTrack, + DOUBLE rollingBufferDurationSec, DOUBLE rollingBufferBitratebps) +{ + STATUS retStatus = STATUS_SUCCESS; + PKvsRtpTransceiver pKvsRtpTransceiver = (PKvsRtpTransceiver) pRtcRtpTransceiver; + CHK_WARN(pKvsRtpTransceiver != NULL || pRtcMediaStreamTrack != NULL, STATUS_NULL_ARG, + "Transceiver is not created. This needs to be invoked after addTransceiver is invoked"); + + CHK_STATUS(setUpRollingBufferConfigInternal(pKvsRtpTransceiver, pRtcMediaStreamTrack, rollingBufferDurationSec, rollingBufferBitratebps)); +CleanUp: + return retStatus; +} + STATUS addTransceiver(PRtcPeerConnection pPeerConnection, PRtcMediaStreamTrack pRtcMediaStreamTrack, PRtcRtpTransceiverInit pRtcRtpTransceiverInit, PRtcRtpTransceiver* ppRtcRtpTransceiver) { @@ -1553,12 +1567,13 @@ STATUS addTransceiver(PRtcPeerConnection pPeerConnection, PRtcMediaStreamTrack p UINT32 ssrc = (UINT32) RAND(), rtxSsrc = (UINT32) RAND(); RTC_RTP_TRANSCEIVER_DIRECTION direction = RTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV; RtcMediaStreamTrack videoTrack; + + CHK(pKvsPeerConnection != NULL, STATUS_NULL_ARG); + if (pRtcRtpTransceiverInit != NULL) { direction = pRtcRtpTransceiverInit->direction; } - CHK(pKvsPeerConnection != NULL, STATUS_NULL_ARG); - if (direction == RTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY && pRtcMediaStreamTrack == NULL) { MEMSET(&videoTrack, 0x00, SIZEOF(RtcMediaStreamTrack)); videoTrack.kind = MEDIA_STREAM_TRACK_KIND_VIDEO; @@ -1566,6 +1581,8 @@ STATUS addTransceiver(PRtcPeerConnection pPeerConnection, PRtcMediaStreamTrack p STRCPY(videoTrack.streamId, "myKvsVideoStream"); STRCPY(videoTrack.trackId, "myVideoTrack"); pRtcMediaStreamTrack = &videoTrack; + // rollingBufferDurationSec will be DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS + // rollingBufferBitratebps will be DEFAULT_EXPECTED_VIDEO_BIT_RATE } switch (pRtcMediaStreamTrack->codec) { diff --git a/src/source/PeerConnection/Rtp.c b/src/source/PeerConnection/Rtp.c index 434a5564bf..a098140fc6 100644 --- a/src/source/PeerConnection/Rtp.c +++ b/src/source/PeerConnection/Rtp.c @@ -49,12 +49,87 @@ STATUS createKvsRtpTransceiver(RTC_RTP_TRANSCEIVER_DIRECTION direction, PKvsPeer return retStatus; } +STATUS setUpRollingBufferConfigInternal(PKvsRtpTransceiver pKvsRtpTransceiver, PRtcMediaStreamTrack pRtcMediaStreamTrack, + DOUBLE rollingBufferDurationSec, DOUBLE rollingBufferBitratebps) +{ + STATUS retStatus = STATUS_SUCCESS; + CHK_ERR(pKvsRtpTransceiver != NULL || pRtcMediaStreamTrack != NULL, STATUS_NULL_ARG, + "Media track and transceiver not set. Make sure to set up transceiver with addTransceiver()"); + + // Do not attempt to alloc for a new RollingBufferConfig if one is still not freed. + if (pKvsRtpTransceiver->pRollingBufferConfig == NULL) { + pKvsRtpTransceiver->pRollingBufferConfig = (PRollingBufferConfig) MEMCALLOC(1, SIZEOF(RollingBufferConfig)); + CHK(pKvsRtpTransceiver->pRollingBufferConfig != NULL, STATUS_NOT_ENOUGH_MEMORY); + } + + // Validate configured buffer duration is within acceptable range, else set to default duration. + if (rollingBufferDurationSec >= MIN_ROLLING_BUFFER_DURATION_IN_SECONDS && rollingBufferDurationSec <= MAX_ROLLING_BUFFER_DURATION_IN_SECONDS) { + DLOGI("Rolling buffer duration set to %lf seconds.", rollingBufferDurationSec); + pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec = rollingBufferDurationSec; + } else if (rollingBufferDurationSec != 0) { + DLOGW("Rolling buffer duration does not fit range (%lf sec - %lf sec). Setting to default %lf sec", MIN_ROLLING_BUFFER_DURATION_IN_SECONDS, + MAX_ROLLING_BUFFER_DURATION_IN_SECONDS, DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS); + pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec = DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS; + } else if (rollingBufferDurationSec == 0) { + DLOGI("Setting to default buffer duration of %lf sec", DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS); + pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec = DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS; + } + + // Validate configured expected bitrate is within acceptable range, else set to default bitrate. + if (rollingBufferBitratebps >= MIN_EXPECTED_BIT_RATE && rollingBufferBitratebps <= MAX_EXPECTED_BIT_RATE) { + if (pRtcMediaStreamTrack->kind == MEDIA_STREAM_TRACK_KIND_VIDEO) { + DLOGI("Rolling buffer expected bitrate set to %lf bps for video.", rollingBufferBitratebps); + } else if (pRtcMediaStreamTrack->kind == MEDIA_STREAM_TRACK_KIND_AUDIO) { + DLOGI("Rolling buffer expected bitrate set to %lf bps for audio.", rollingBufferBitratebps); + } else { + DLOGI("Rolling buffer expected bitrate set to %lf bps for unkown codec.", rollingBufferBitratebps); + } + pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps = rollingBufferBitratebps; + } else if (rollingBufferBitratebps != 0) { + if (pRtcMediaStreamTrack->kind == MEDIA_STREAM_TRACK_KIND_VIDEO) { + DLOGW("Rolling buffer bitrate does not fit range (%lf bps - %lf bps) for video. Setting to default %lf bps.", MIN_EXPECTED_BIT_RATE, + MAX_EXPECTED_BIT_RATE, DEFAULT_EXPECTED_VIDEO_BIT_RATE); + pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps = DEFAULT_EXPECTED_VIDEO_BIT_RATE; + } else if (pRtcMediaStreamTrack->kind == MEDIA_STREAM_TRACK_KIND_AUDIO) { + DLOGW("Rolling buffer bitrate does not fit range (%lf bps - %lf bps) for audio. Setting to default %lf bps.", MIN_EXPECTED_BIT_RATE, + MAX_EXPECTED_BIT_RATE, DEFAULT_EXPECTED_AUDIO_BIT_RATE); + pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps = DEFAULT_EXPECTED_AUDIO_BIT_RATE; + } else { + DLOGW("Rolling buffer bitrate does not fit range (%lf bps - %lf bps) for unknown codec. Setting to default %lf bps.", + MIN_EXPECTED_BIT_RATE, MAX_EXPECTED_BIT_RATE, DEFAULT_EXPECTED_VIDEO_BIT_RATE); + pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps = DEFAULT_EXPECTED_VIDEO_BIT_RATE; + } + } else if (rollingBufferBitratebps == 0) { + if (pRtcMediaStreamTrack->kind == MEDIA_STREAM_TRACK_KIND_VIDEO) { + DLOGI("Setting to default rolling buffer bitrate of %lf bps for video.", DEFAULT_EXPECTED_VIDEO_BIT_RATE); + pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps = DEFAULT_EXPECTED_VIDEO_BIT_RATE; + } else if (pRtcMediaStreamTrack->kind == MEDIA_STREAM_TRACK_KIND_AUDIO) { + DLOGI("Setting to default rolling buffer bitrate of %lf bps for audio.", DEFAULT_EXPECTED_AUDIO_BIT_RATE); + pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps = DEFAULT_EXPECTED_AUDIO_BIT_RATE; + } else { + DLOGI("Setting to default rolling buffer bitrate of %lf bps for unknown codec.", DEFAULT_EXPECTED_VIDEO_BIT_RATE); + pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps = DEFAULT_EXPECTED_VIDEO_BIT_RATE; + } + } + +CleanUp: + CHK_LOG_ERR(retStatus); + + return retStatus; +} + STATUS freeTransceiver(PRtcRtpTransceiver* pRtcRtpTransceiver) { UNUSED_PARAM(pRtcRtpTransceiver); return STATUS_NOT_IMPLEMENTED; } +STATUS freeRollingBufferConfig(PRollingBufferConfig pRollingBufferConfig) +{ + SAFE_MEMFREE(pRollingBufferConfig); + return STATUS_SUCCESS; +} + STATUS freeKvsRtpTransceiver(PKvsRtpTransceiver* ppKvsRtpTransceiver) { STATUS retStatus = STATUS_SUCCESS; @@ -76,6 +151,9 @@ STATUS freeKvsRtpTransceiver(PKvsRtpTransceiver* ppKvsRtpTransceiver) if (pKvsRtpTransceiver->sender.retransmitter != NULL) { freeRetransmitter(&pKvsRtpTransceiver->sender.retransmitter); } + + freeRollingBufferConfig(pKvsRtpTransceiver->pRollingBufferConfig); + MUTEX_FREE(pKvsRtpTransceiver->statsLock); SAFE_MEMFREE(pKvsRtpTransceiver->peerFrameBuffer); diff --git a/src/source/PeerConnection/Rtp.h b/src/source/PeerConnection/Rtp.h index d9104d73eb..f45c0be8aa 100644 --- a/src/source/PeerConnection/Rtp.h +++ b/src/source/PeerConnection/Rtp.h @@ -9,13 +9,18 @@ extern "C" { // Default MTU comes from libwebrtc // https://groups.google.com/forum/#!topic/discuss-webrtc/gH5ysR3SoZI -#define DEFAULT_MTU_SIZE 1200 -#define DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS 3 -#define HIGHEST_EXPECTED_BIT_RATE (10 * 1024 * 1024) +#define DEFAULT_MTU_SIZE_BYTES 1200 +#define DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS (DOUBLE) 3 +#define DEFAULT_EXPECTED_VIDEO_BIT_RATE (DOUBLE)(10 * 1024 * 1024) +#define DEFAULT_EXPECTED_AUDIO_BIT_RATE (DOUBLE)(10 * 1024 * 1024) #define DEFAULT_SEQ_NUM_BUFFER_SIZE 1000 #define DEFAULT_VALID_INDEX_BUFFER_SIZE 1000 #define DEFAULT_PEER_FRAME_BUFFER_SIZE (5 * 1024) #define SRTP_AUTH_TAG_OVERHEAD 10 +#define MIN_ROLLING_BUFFER_DURATION_IN_SECONDS (DOUBLE) 0.1 +#define MIN_EXPECTED_BIT_RATE (DOUBLE)(102.4 * 1024) // Considering 1Kib = 1024 bits +#define MAX_ROLLING_BUFFER_DURATION_IN_SECONDS (DOUBLE) 10 +#define MAX_EXPECTED_BIT_RATE (DOUBLE)(240 * 1024 * 1024) // Considering 1Kib = 1024 bits // https://www.w3.org/TR/webrtc-stats/#dom-rtcoutboundrtpstreamstats-huge // Huge frames, by definition, are frames that have an encoded size at least 2.5 times the average size of the frames. @@ -43,6 +48,12 @@ typedef struct { } RtcRtpSender, *PRtcRtpSender; +typedef struct { + DOUBLE rollingBufferDurationSec; //!< Maximum duration of media that needs to be buffered (in seconds). The lowest allowed is 0.1 seconds (100ms) + DOUBLE rollingBufferBitratebps; //!< Maximum expected bitrate of media (In bits/second). It is used to determine the buffer capacity. The lowest + //!< allowed is 100 Kbps +} RollingBufferConfig, *PRollingBufferConfig; + typedef struct { RtcRtpTransceiver transceiver; RtcRtpSender sender; @@ -52,6 +63,8 @@ typedef struct { UINT32 jitterBufferSsrc; PJitterBuffer pJitterBuffer; + PRollingBufferConfig pRollingBufferConfig; + UINT64 onFrameCustomData; RtcOnFrame onFrame; @@ -84,6 +97,9 @@ STATUS writeRtpPacket(PKvsPeerConnection pKvsPeerConnection, PRtpPacket pRtpPack STATUS hasTransceiverWithSsrc(PKvsPeerConnection pKvsPeerConnection, UINT32 ssrc); STATUS findTransceiverBySsrc(PKvsPeerConnection pKvsPeerConnection, PKvsRtpTransceiver* ppTransceiver, UINT32 ssrc); +STATUS setUpRollingBufferConfigInternal(PKvsRtpTransceiver, PRtcMediaStreamTrack, DOUBLE, DOUBLE); +STATUS freeRollingBufferConfig(PRollingBufferConfig); + #ifdef __cplusplus } #endif diff --git a/src/source/PeerConnection/SessionDescription.c b/src/source/PeerConnection/SessionDescription.c index 2ca79fbf83..1684fdeadb 100644 --- a/src/source/PeerConnection/SessionDescription.c +++ b/src/source/PeerConnection/SessionDescription.c @@ -315,9 +315,23 @@ STATUS setTransceiverPayloadTypes(PHashTable codecTable, PHashTable rtxTable, PD } } - CHK_STATUS(createRtpRollingBuffer(DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS * HIGHEST_EXPECTED_BIT_RATE / 8 / DEFAULT_MTU_SIZE, - &pKvsRtpTransceiver->sender.packetBuffer)); - CHK_STATUS(createRetransmitter(DEFAULT_SEQ_NUM_BUFFER_SIZE, DEFAULT_VALID_INDEX_BUFFER_SIZE, &pKvsRtpTransceiver->sender.retransmitter)); + if (pKvsRtpTransceiver != NULL) { + if (pKvsRtpTransceiver->pRollingBufferConfig == NULL) { + // Passing in 0,0. The default values will be set up since application has not set up rolling buffer config with the + // configureTransceiverRollingBuffer() call + DLOGI("Rolling buffer config not set up for tranceiver. Setting defaults."); + CHK_STATUS(setUpRollingBufferConfigInternal(pKvsRtpTransceiver, &pKvsRtpTransceiver->sender.track, 0, 0)); + } + + DLOGI("Rolling buffer params: %lf sec, %lf bps", pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec, + pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps); + UINT64 rollingBufferCapacity = (UINT64) (pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec * + pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps / 8 / DEFAULT_MTU_SIZE_BYTES); + + DLOGI("The rolling buffer is configured to store %" PRIu64 " packets", rollingBufferCapacity); + CHK_STATUS(createRtpRollingBuffer(rollingBufferCapacity, &pKvsRtpTransceiver->sender.packetBuffer)); + CHK_STATUS(createRetransmitter(DEFAULT_SEQ_NUM_BUFFER_SIZE, DEFAULT_VALID_INDEX_BUFFER_SIZE, &pKvsRtpTransceiver->sender.retransmitter)); + } } CleanUp: diff --git a/tst/DtlsFunctionalityTest.cpp b/tst/DtlsFunctionalityTest.cpp index 32faca8ab7..f0e647abd3 100644 --- a/tst/DtlsFunctionalityTest.cpp +++ b/tst/DtlsFunctionalityTest.cpp @@ -131,8 +131,8 @@ TEST_F(DtlsFunctionalityTest, putApplicationDataWithVariedSizes) PBYTE pData = NULL; INT32 dataSizes[] = { 4, // very small packet - DEFAULT_MTU_SIZE - 200, // small packet but should be still under mtu - DEFAULT_MTU_SIZE + 200, // big packet and bigger than even a jumbo frame + DEFAULT_MTU_SIZE_BYTES - 200, // small packet but should be still under mtu + DEFAULT_MTU_SIZE_BYTES + 200, // big packet and bigger than even a jumbo frame }; EXPECT_EQ(STATUS_SUCCESS, timerQueueCreate(&timerQueueHandle)); @@ -161,8 +161,8 @@ TEST_F(DtlsFunctionalityTest, processPacketWithVariedSizes) PBYTE pData = NULL; INT32 dataSizes[] = { 4, // very small packet - DEFAULT_MTU_SIZE - 200, // small packet but should be still under mtu - DEFAULT_MTU_SIZE + 200, // big packet and bigger than even a jumbo frame + DEFAULT_MTU_SIZE_BYTES - 200, // small packet but should be still under mtu + DEFAULT_MTU_SIZE_BYTES + 200, // big packet and bigger than even a jumbo frame }; INT32 readDataSize; @@ -193,8 +193,8 @@ TEST_F(DtlsFunctionalityTest, putApplicationDataWithVariedSizesInThread) PBYTE pData = NULL; INT32 dataSizes[] = { 4, // very small packet - DEFAULT_MTU_SIZE - 200, // small packet but should be still under mtu - DEFAULT_MTU_SIZE + 200, // big packet and bigger than even a jumbo frame + DEFAULT_MTU_SIZE_BYTES - 200, // small packet but should be still under mtu + DEFAULT_MTU_SIZE_BYTES + 200, // big packet and bigger than even a jumbo frame }; EXPECT_EQ(STATUS_SUCCESS, timerQueueCreate(&timerQueueHandle)); @@ -223,8 +223,8 @@ TEST_F(DtlsFunctionalityTest, processPacketWithVariedSizesInThread) PBYTE pData = NULL; INT32 dataSizes[] = { 4, // very small packet - DEFAULT_MTU_SIZE - 200, // small packet but should be still under mtu - DEFAULT_MTU_SIZE + 200, // big packet and bigger than even a jumbo frame + DEFAULT_MTU_SIZE_BYTES - 200, // small packet but should be still under mtu + DEFAULT_MTU_SIZE_BYTES + 200, // big packet and bigger than even a jumbo frame }; INT32 readDataSize; diff --git a/tst/RtcpFunctionalityTest.cpp b/tst/RtcpFunctionalityTest.cpp index 7a3cd74da6..3e87cc4437 100644 --- a/tst/RtcpFunctionalityTest.cpp +++ b/tst/RtcpFunctionalityTest.cpp @@ -153,7 +153,7 @@ TEST_F(RtcpFunctionalityTest, onRtcpPacketCompoundNack) BYTE validRtcpPacket[] = {0x81, 0xcd, 0x00, 0x03, 0x2c, 0xd1, 0xa0, 0xde, 0x00, 0x00, 0xab, 0xe0, 0x00, 0x00, 0x00, 0x00}; initTransceiver(44000); ASSERT_EQ(STATUS_SUCCESS, - createRtpRollingBuffer(DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS * HIGHEST_EXPECTED_BIT_RATE / 8 / DEFAULT_MTU_SIZE, + createRtpRollingBuffer(DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS * DEFAULT_EXPECTED_VIDEO_BIT_RATE / 8 / DEFAULT_MTU_SIZE_BYTES, &pKvsRtpTransceiver->sender.packetBuffer)); ASSERT_EQ(STATUS_SUCCESS, createRetransmitter(DEFAULT_SEQ_NUM_BUFFER_SIZE, DEFAULT_VALID_INDEX_BUFFER_SIZE, &pKvsRtpTransceiver->sender.retransmitter)); diff --git a/tst/RtpFunctionalityTest.cpp b/tst/RtpFunctionalityTest.cpp index f9272c11c3..6fc9c950b2 100644 --- a/tst/RtpFunctionalityTest.cpp +++ b/tst/RtpFunctionalityTest.cpp @@ -113,7 +113,7 @@ TEST_F(RtpFunctionalityTest, marshallUnmarshallH264Data) // First call for payload size and sub payload length size EXPECT_EQ(STATUS_SUCCESS, - createPayloadForH264(DEFAULT_MTU_SIZE, (PBYTE) payload, payloadLen, NULL, &payloadArray.payloadLength, NULL, + createPayloadForH264(DEFAULT_MTU_SIZE_BYTES, (PBYTE) payload, payloadLen, NULL, &payloadArray.payloadLength, NULL, &payloadArray.payloadSubLenSize)); if (payloadArray.payloadLength > payloadArray.maxPayloadLength) { @@ -133,7 +133,7 @@ TEST_F(RtpFunctionalityTest, marshallUnmarshallH264Data) // Second call with actual buffer to fill in data EXPECT_EQ(STATUS_SUCCESS, - createPayloadForH264(DEFAULT_MTU_SIZE, (PBYTE) payload, payloadLen, payloadArray.payloadBuffer, &payloadArray.payloadLength, + createPayloadForH264(DEFAULT_MTU_SIZE_BYTES, (PBYTE) payload, payloadLen, payloadArray.payloadBuffer, &payloadArray.payloadLength, payloadArray.payloadSubLength, &payloadArray.payloadSubLenSize)); EXPECT_LT(0, payloadArray.payloadSubLenSize); @@ -192,7 +192,7 @@ TEST_F(RtpFunctionalityTest, packingUnpackingVerifySameH264Frame) // First call for payload size and sub payload length size EXPECT_EQ(STATUS_SUCCESS, - createPayloadForH264(DEFAULT_MTU_SIZE, (PBYTE) payload, payloadLen, NULL, &payloadArray.payloadLength, NULL, + createPayloadForH264(DEFAULT_MTU_SIZE_BYTES, (PBYTE) payload, payloadLen, NULL, &payloadArray.payloadLength, NULL, &payloadArray.payloadSubLenSize)); if (payloadArray.payloadLength > payloadArray.maxPayloadLength) { @@ -212,7 +212,7 @@ TEST_F(RtpFunctionalityTest, packingUnpackingVerifySameH264Frame) // Second call with actual buffer to fill in data EXPECT_EQ(STATUS_SUCCESS, - createPayloadForH264(DEFAULT_MTU_SIZE, (PBYTE) payload, payloadLen, payloadArray.payloadBuffer, &payloadArray.payloadLength, + createPayloadForH264(DEFAULT_MTU_SIZE_BYTES, (PBYTE) payload, payloadLen, payloadArray.payloadBuffer, &payloadArray.payloadLength, payloadArray.payloadSubLength, &payloadArray.payloadSubLenSize)); EXPECT_LT(0, payloadArray.payloadSubLenSize); @@ -289,7 +289,7 @@ TEST_F(RtpFunctionalityTest, packingUnpackingVerifySameH265Frame) // First call for payload size and sub payload length size EXPECT_EQ(STATUS_SUCCESS, - createPayloadForH265(DEFAULT_MTU_SIZE, (PBYTE) payload, payloadLen, NULL, &payloadArray.payloadLength, NULL, + createPayloadForH265(DEFAULT_MTU_SIZE_BYTES, (PBYTE) payload, payloadLen, NULL, &payloadArray.payloadLength, NULL, &payloadArray.payloadSubLenSize)); if (payloadArray.payloadLength > payloadArray.maxPayloadLength) { @@ -309,7 +309,7 @@ TEST_F(RtpFunctionalityTest, packingUnpackingVerifySameH265Frame) // Second call with actual buffer to fill in data EXPECT_EQ(STATUS_SUCCESS, - createPayloadForH265(DEFAULT_MTU_SIZE, (PBYTE) payload, payloadLen, payloadArray.payloadBuffer, &payloadArray.payloadLength, + createPayloadForH265(DEFAULT_MTU_SIZE_BYTES, (PBYTE) payload, payloadLen, payloadArray.payloadBuffer, &payloadArray.payloadLength, payloadArray.payloadSubLength, &payloadArray.payloadSubLenSize)); EXPECT_LT(0, payloadArray.payloadSubLenSize); @@ -375,7 +375,7 @@ TEST_F(RtpFunctionalityTest, packingUnpackingVerifySameOpusFrame) // First call for payload size and sub payload length size EXPECT_EQ(STATUS_SUCCESS, - createPayloadForOpus(DEFAULT_MTU_SIZE, (PBYTE) &payload, payloadLen, NULL, &payloadArray.payloadLength, NULL, + createPayloadForOpus(DEFAULT_MTU_SIZE_BYTES, (PBYTE) &payload, payloadLen, NULL, &payloadArray.payloadLength, NULL, &payloadArray.payloadSubLenSize)); if (payloadArray.payloadLength > payloadArray.maxPayloadLength) { @@ -395,7 +395,7 @@ TEST_F(RtpFunctionalityTest, packingUnpackingVerifySameOpusFrame) // Second call with actual buffer to fill in data EXPECT_EQ(STATUS_SUCCESS, - createPayloadForOpus(DEFAULT_MTU_SIZE, (PBYTE) &payload, payloadLen, payloadArray.payloadBuffer, &payloadArray.payloadLength, + createPayloadForOpus(DEFAULT_MTU_SIZE_BYTES, (PBYTE) &payload, payloadLen, payloadArray.payloadBuffer, &payloadArray.payloadLength, payloadArray.payloadSubLength, &payloadArray.payloadSubLenSize)); EXPECT_EQ(1, payloadArray.payloadSubLenSize); @@ -430,7 +430,7 @@ TEST_F(RtpFunctionalityTest, packingUnpackingVerifySameShortG711Frame) // First call for payload size and sub payload length size EXPECT_EQ(STATUS_SUCCESS, - createPayloadForG711(DEFAULT_MTU_SIZE, (PBYTE) &payload, payloadLen, NULL, &payloadArray.payloadLength, NULL, + createPayloadForG711(DEFAULT_MTU_SIZE_BYTES, (PBYTE) &payload, payloadLen, NULL, &payloadArray.payloadLength, NULL, &payloadArray.payloadSubLenSize)); if (payloadArray.payloadLength > payloadArray.maxPayloadLength) { @@ -450,7 +450,7 @@ TEST_F(RtpFunctionalityTest, packingUnpackingVerifySameShortG711Frame) // Second call with actual buffer to fill in data EXPECT_EQ(STATUS_SUCCESS, - createPayloadForG711(DEFAULT_MTU_SIZE, (PBYTE) &payload, payloadLen, payloadArray.payloadBuffer, &payloadArray.payloadLength, + createPayloadForG711(DEFAULT_MTU_SIZE_BYTES, (PBYTE) &payload, payloadLen, payloadArray.payloadBuffer, &payloadArray.payloadLength, payloadArray.payloadSubLength, &payloadArray.payloadSubLenSize)); EXPECT_EQ(1, payloadArray.payloadSubLenSize); diff --git a/tst/RtpRollingBufferFunctionalityTest.cpp b/tst/RtpRollingBufferFunctionalityTest.cpp index b9cabca2ff..19a9f2de97 100644 --- a/tst/RtpRollingBufferFunctionalityTest.cpp +++ b/tst/RtpRollingBufferFunctionalityTest.cpp @@ -155,6 +155,110 @@ TEST_F(RtpRollingBufferFunctionalityTest, getIndexForSeqListReturnCorrectIndexsW EXPECT_EQ(STATUS_SUCCESS, freeRtpPacket(&pRtpPacket)); } +TEST_F(RtpRollingBufferFunctionalityTest, testRollingBufferParams) +{ + RtcConfiguration config{}; + PKvsRtpTransceiver pKvsRtpTransceiver = nullptr; + PRtcPeerConnection pRtcPeerConnection = nullptr; + PRtcRtpTransceiver pRtcRtpTransceiver = nullptr; + RtcMediaStreamTrack videoTrack{}; + + videoTrack.codec = RTC_CODEC_VP8; + videoTrack.kind = MEDIA_STREAM_TRACK_KIND_VIDEO; + + // Testing with 0,0 + EXPECT_EQ(STATUS_SUCCESS, createPeerConnection(&config, &pRtcPeerConnection)); + EXPECT_EQ(STATUS_SUCCESS, ::addTransceiver(pRtcPeerConnection, &videoTrack, nullptr, &pRtcRtpTransceiver)); + pKvsRtpTransceiver = reinterpret_cast(pRtcRtpTransceiver); + EXPECT_TRUE(pKvsRtpTransceiver->pRollingBufferConfig == nullptr); + EXPECT_EQ(configureTransceiverRollingBuffer(pRtcRtpTransceiver, &videoTrack, 0, 0), STATUS_SUCCESS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec, DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps, DEFAULT_EXPECTED_VIDEO_BIT_RATE); + EXPECT_EQ(freePeerConnection(&pRtcPeerConnection), STATUS_SUCCESS); + + // Testing with invalid value for rolling buffer duration and valid rolling buffer bitrate + EXPECT_EQ(STATUS_SUCCESS, createPeerConnection(&config, &pRtcPeerConnection)); + EXPECT_EQ(STATUS_SUCCESS, ::addTransceiver(pRtcPeerConnection, &videoTrack, nullptr, &pRtcRtpTransceiver)); + pKvsRtpTransceiver = reinterpret_cast(pRtcRtpTransceiver); + EXPECT_TRUE(pKvsRtpTransceiver->pRollingBufferConfig == nullptr); + EXPECT_EQ(configureTransceiverRollingBuffer(pRtcRtpTransceiver, &videoTrack, 0.001, 4 * 1024 * 1024), STATUS_SUCCESS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec, DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps, 4 * 1024 * 1024); + EXPECT_EQ(freePeerConnection(&pRtcPeerConnection), STATUS_SUCCESS); + + // Testing with valid value for rolling buffer duration and invalid rolling buffer bitrate + EXPECT_EQ(STATUS_SUCCESS, createPeerConnection(&config, &pRtcPeerConnection)); + EXPECT_EQ(STATUS_SUCCESS, ::addTransceiver(pRtcPeerConnection, &videoTrack, nullptr, &pRtcRtpTransceiver)); + pKvsRtpTransceiver = reinterpret_cast(pRtcRtpTransceiver); + EXPECT_TRUE(pKvsRtpTransceiver->pRollingBufferConfig == nullptr); + EXPECT_EQ(configureTransceiverRollingBuffer(pRtcRtpTransceiver, &videoTrack, 0.2, 102.39 * 1024), STATUS_SUCCESS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec, 0.2); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps, DEFAULT_EXPECTED_VIDEO_BIT_RATE); + EXPECT_EQ(freePeerConnection(&pRtcPeerConnection), STATUS_SUCCESS); + + // Testing with invalid value for rolling buffer duration and invalid rolling buffer bitrate + EXPECT_EQ(STATUS_SUCCESS, createPeerConnection(&config, &pRtcPeerConnection)); + EXPECT_EQ(STATUS_SUCCESS, ::addTransceiver(pRtcPeerConnection, &videoTrack, nullptr, &pRtcRtpTransceiver)); + pKvsRtpTransceiver = reinterpret_cast(pRtcRtpTransceiver); + EXPECT_TRUE(pKvsRtpTransceiver->pRollingBufferConfig == nullptr); + EXPECT_EQ(configureTransceiverRollingBuffer(pRtcRtpTransceiver, &videoTrack, 0.0000001, 102.39 * 1024), STATUS_SUCCESS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec, DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps, DEFAULT_EXPECTED_VIDEO_BIT_RATE); + EXPECT_EQ(freePeerConnection(&pRtcPeerConnection), STATUS_SUCCESS); + + + // Testing with max value for rolling buffer duration and max rolling buffer bitrate + EXPECT_EQ(STATUS_SUCCESS, createPeerConnection(&config, &pRtcPeerConnection)); + EXPECT_EQ(STATUS_SUCCESS, ::addTransceiver(pRtcPeerConnection, &videoTrack, nullptr, &pRtcRtpTransceiver)); + pKvsRtpTransceiver = reinterpret_cast(pRtcRtpTransceiver); + EXPECT_TRUE(pKvsRtpTransceiver->pRollingBufferConfig == nullptr); + EXPECT_EQ(configureTransceiverRollingBuffer(pRtcRtpTransceiver, &videoTrack, MAX_ROLLING_BUFFER_DURATION_IN_SECONDS, MAX_EXPECTED_BIT_RATE), STATUS_SUCCESS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec, MAX_ROLLING_BUFFER_DURATION_IN_SECONDS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps, MAX_EXPECTED_BIT_RATE); + EXPECT_EQ(freePeerConnection(&pRtcPeerConnection), STATUS_SUCCESS); + + // Testing with max value for rolling buffer duration and min rolling buffer bitrate + EXPECT_EQ(STATUS_SUCCESS, createPeerConnection(&config, &pRtcPeerConnection)); + EXPECT_EQ(STATUS_SUCCESS, ::addTransceiver(pRtcPeerConnection, &videoTrack, nullptr, &pRtcRtpTransceiver)); + pKvsRtpTransceiver = reinterpret_cast(pRtcRtpTransceiver); + EXPECT_TRUE(pKvsRtpTransceiver->pRollingBufferConfig == nullptr); + EXPECT_EQ(configureTransceiverRollingBuffer(pRtcRtpTransceiver, &videoTrack, MAX_ROLLING_BUFFER_DURATION_IN_SECONDS, MIN_EXPECTED_BIT_RATE), STATUS_SUCCESS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec, MAX_ROLLING_BUFFER_DURATION_IN_SECONDS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps, MIN_EXPECTED_BIT_RATE); + EXPECT_EQ(freePeerConnection(&pRtcPeerConnection), STATUS_SUCCESS); + + + // Testing with min value for rolling buffer duration and max rolling buffer bitrate + EXPECT_EQ(STATUS_SUCCESS, createPeerConnection(&config, &pRtcPeerConnection)); + EXPECT_EQ(STATUS_SUCCESS, ::addTransceiver(pRtcPeerConnection, &videoTrack, nullptr, &pRtcRtpTransceiver)); + pKvsRtpTransceiver = reinterpret_cast(pRtcRtpTransceiver); + EXPECT_TRUE(pKvsRtpTransceiver->pRollingBufferConfig == nullptr); + EXPECT_EQ(configureTransceiverRollingBuffer(pRtcRtpTransceiver, &videoTrack, MIN_ROLLING_BUFFER_DURATION_IN_SECONDS, MAX_EXPECTED_BIT_RATE), STATUS_SUCCESS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec, MIN_ROLLING_BUFFER_DURATION_IN_SECONDS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps, MAX_EXPECTED_BIT_RATE); + EXPECT_EQ(freePeerConnection(&pRtcPeerConnection), STATUS_SUCCESS); + + // Testing with min value for rolling buffer duration and min rolling buffer bitrate + EXPECT_EQ(STATUS_SUCCESS, createPeerConnection(&config, &pRtcPeerConnection)); + EXPECT_EQ(STATUS_SUCCESS, ::addTransceiver(pRtcPeerConnection, &videoTrack, nullptr, &pRtcRtpTransceiver)); + pKvsRtpTransceiver = reinterpret_cast(pRtcRtpTransceiver); + EXPECT_TRUE(pKvsRtpTransceiver->pRollingBufferConfig == nullptr); + EXPECT_EQ(configureTransceiverRollingBuffer(pRtcRtpTransceiver, &videoTrack, MIN_ROLLING_BUFFER_DURATION_IN_SECONDS, MIN_EXPECTED_BIT_RATE), STATUS_SUCCESS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec, MIN_ROLLING_BUFFER_DURATION_IN_SECONDS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps, MIN_EXPECTED_BIT_RATE); + EXPECT_EQ(freePeerConnection(&pRtcPeerConnection), STATUS_SUCCESS); + + // Testing with valid value for rolling buffer duration and valid rolling buffer bitrate + EXPECT_EQ(STATUS_SUCCESS, createPeerConnection(&config, &pRtcPeerConnection)); + EXPECT_EQ(STATUS_SUCCESS, ::addTransceiver(pRtcPeerConnection, &videoTrack, nullptr, &pRtcRtpTransceiver)); + pKvsRtpTransceiver = reinterpret_cast(pRtcRtpTransceiver); + EXPECT_TRUE(pKvsRtpTransceiver->pRollingBufferConfig == nullptr); + EXPECT_EQ(configureTransceiverRollingBuffer(pRtcRtpTransceiver, &videoTrack, 0.2, 9.2 * 1024 * 1024), STATUS_SUCCESS); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferDurationSec, 0.2); + EXPECT_EQ(pKvsRtpTransceiver->pRollingBufferConfig->rollingBufferBitratebps, 9.2 * 1024 * 1024); + EXPECT_EQ(freePeerConnection(&pRtcPeerConnection), STATUS_SUCCESS); + +} } // namespace webrtcclient } // namespace video } // namespace kinesis diff --git a/tst/SdpApiTest.cpp b/tst/SdpApiTest.cpp index 2ac27c316b..3400044ef8 100644 --- a/tst/SdpApiTest.cpp +++ b/tst/SdpApiTest.cpp @@ -249,6 +249,7 @@ TEST_F(SdpApiTest, setTransceiverPayloadTypes_NoRtxType) PHashTable pRtxTable; PDoubleList pTransceivers; KvsRtpTransceiver transceiver; + MEMSET(&transceiver, 0x00, SIZEOF(KvsRtpTransceiver)); transceiver.sender.track.codec = RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE; transceiver.transceiver.direction = RTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV; transceiver.sender.packetBuffer = NULL; @@ -259,11 +260,15 @@ TEST_F(SdpApiTest, setTransceiverPayloadTypes_NoRtxType) EXPECT_EQ(STATUS_SUCCESS, doubleListCreate(&pTransceivers)); EXPECT_EQ(STATUS_SUCCESS, doubleListInsertItemHead(pTransceivers, (UINT64)(&transceiver))); EXPECT_EQ(STATUS_SUCCESS, setTransceiverPayloadTypes(pCodecTable, pRtxTable, pTransceivers)); + EXPECT_EQ(transceiver.pRollingBufferConfig->rollingBufferDurationSec, DEFAULT_ROLLING_BUFFER_DURATION_IN_SECONDS); + EXPECT_EQ(transceiver.pRollingBufferConfig->rollingBufferBitratebps, DEFAULT_EXPECTED_VIDEO_BIT_RATE); EXPECT_EQ(1, transceiver.sender.payloadType); EXPECT_NE((PRtpRollingBuffer) NULL, transceiver.sender.packetBuffer); EXPECT_NE((PRetransmitter) NULL, transceiver.sender.retransmitter); hashTableFree(pCodecTable); hashTableFree(pRtxTable); + + freeRollingBufferConfig(transceiver.pRollingBufferConfig); freeRtpRollingBuffer(&transceiver.sender.packetBuffer); freeRetransmitter(&transceiver.sender.retransmitter); doubleListFree(pTransceivers); @@ -275,6 +280,7 @@ TEST_F(SdpApiTest, setTransceiverPayloadTypes_HasRtxType) PHashTable pRtxTable; PDoubleList pTransceivers; KvsRtpTransceiver transceiver; + MEMSET(&transceiver, 0x00, SIZEOF(KvsRtpTransceiver)); transceiver.sender.track.codec = RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE; transceiver.transceiver.direction = RTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV; transceiver.sender.packetBuffer = NULL; @@ -292,6 +298,7 @@ TEST_F(SdpApiTest, setTransceiverPayloadTypes_HasRtxType) EXPECT_NE((PRetransmitter) NULL, transceiver.sender.retransmitter); hashTableFree(pCodecTable); hashTableFree(pRtxTable); + freeRollingBufferConfig(transceiver.pRollingBufferConfig); freeRtpRollingBuffer(&transceiver.sender.packetBuffer); freeRetransmitter(&transceiver.sender.retransmitter); doubleListFree(pTransceivers); @@ -303,6 +310,7 @@ TEST_F(SdpApiTest, setTransceiverPayloadTypes_HasRtxType_H265) PHashTable pRtxTable; PDoubleList pTransceivers; KvsRtpTransceiver transceiver; + MEMSET(&transceiver, 0x00, SIZEOF(KvsRtpTransceiver)); transceiver.sender.track.codec = RTC_CODEC_H265; transceiver.transceiver.direction = RTC_RTP_TRANSCEIVER_DIRECTION_SENDRECV; transceiver.sender.packetBuffer = NULL; @@ -320,6 +328,7 @@ TEST_F(SdpApiTest, setTransceiverPayloadTypes_HasRtxType_H265) EXPECT_NE((PRetransmitter) NULL, transceiver.sender.retransmitter); hashTableFree(pCodecTable); hashTableFree(pRtxTable); + freeRollingBufferConfig(transceiver.pRollingBufferConfig); freeRtpRollingBuffer(&transceiver.sender.packetBuffer); freeRetransmitter(&transceiver.sender.retransmitter); doubleListFree(pTransceivers); @@ -498,7 +507,6 @@ TEST_F(SdpApiTest, populateSingleMediaSection_TestTxRecvOnlyStreamNull) // Create peer connection EXPECT_EQ(createPeerConnection(&configuration, &offerPc), STATUS_SUCCESS); - PRtcRtpTransceiver pTransceiver; RtcRtpTransceiverInit rtcRtpTransceiverInit; rtcRtpTransceiverInit.direction = RTC_RTP_TRANSCEIVER_DIRECTION_RECVONLY; @@ -546,6 +554,7 @@ a=rtpmap:102 H264/90000 MEMSET(&rtcConfiguration, 0x00, SIZEOF(RtcConfiguration)); MEMSET(&rtcMediaStreamTrack, 0x00, SIZEOF(RtcMediaStreamTrack)); MEMSET(&rtcSessionDescriptionInit, 0x00, SIZEOF(RtcSessionDescriptionInit)); + MEMSET(&rtcRtpTransceiverInit, 0x00, SIZEOF(RtcRtpTransceiverInit)); EXPECT_EQ(createPeerConnection(&rtcConfiguration, &pRtcPeerConnection), STATUS_SUCCESS); EXPECT_EQ(addSupportedCodec(pRtcPeerConnection, RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE), STATUS_SUCCESS); @@ -1227,6 +1236,7 @@ a=fmtp:125 level-asymmetry-allowed=1;packetization-mode=0;profile-level-id=42e01 MEMSET(&rtcConfiguration, 0x00, SIZEOF(RtcConfiguration)); MEMSET(&rtcMediaStreamTrack, 0x00, SIZEOF(RtcMediaStreamTrack)); MEMSET(&rtcSessionDescriptionInit, 0x00, SIZEOF(RtcSessionDescriptionInit)); + MEMSET(&rtcRtpTransceiverInit, 0x00, SIZEOF(RtcRtpTransceiverInit)); EXPECT_EQ(createPeerConnection(&rtcConfiguration, &pRtcPeerConnection), STATUS_SUCCESS); EXPECT_EQ(addSupportedCodec(pRtcPeerConnection, RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE), STATUS_SUCCESS); @@ -1702,6 +1712,7 @@ TEST_P(SdpApiTest_SdpMatch, populateSingleMediaSection_TestH264Fmtp) MEMSET(&rtcConfiguration, 0x00, SIZEOF(RtcConfiguration)); MEMSET(&track1, 0x00, SIZEOF(RtcMediaStreamTrack)); MEMSET(&rtcSessionDescriptionInit, 0x00, SIZEOF(RtcSessionDescriptionInit)); + MEMSET(&rtcRtpTransceiverInit, 0x00, SIZEOF(RtcRtpTransceiverInit)); EXPECT_EQ(createPeerConnection(&rtcConfiguration, &pRtcPeerConnection), STATUS_SUCCESS); EXPECT_EQ(addSupportedCodec(pRtcPeerConnection, RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE), STATUS_SUCCESS);