From 883d4b0a0b87662ee8671ca375c49a56232b1b6c Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 23 Jan 2024 14:05:05 -0500 Subject: [PATCH] CMAKE_BUILD_TYPE=Release build (#1897) * Release build * Enable build type setting on all dependencies and update README * Remove SPRINTF usage throughout... * Fix disable data channel unit test build failure and reduce SDP character array lengths wherever relevant following spec * Set count to 7 since the structure member sizes are set to count + 1 * remove debug * Add snprintf checks * Set file size to 10 kb and increase log rotation to avoid high memalloc --- .github/workflows/ci.yml | 26 ++ CMake/Dependencies/libmbedtls-CMakeLists.txt | 2 +- CMake/Dependencies/libusrsctp-CMakeLists.txt | 3 +- .../Dependencies/libwebsockets-CMakeLists.txt | 1 + CMakeLists.txt | 14 +- README.md | 1 + samples/Common.c | 356 +++++++++--------- samples/Samples.h | 2 +- src/source/Ice/TurnConnection.c | 4 +- src/source/PeerConnection/PeerConnection.c | 4 - .../PeerConnection/SessionDescription.c | 205 +++++++--- src/source/Sdp/Sdp.h | 64 ++-- tst/DataChannelApiTest.cpp | 3 + tst/DataChannelFunctionalityTest.cpp | 3 + tst/IngestionFunctionalityTests.cpp | 4 +- 15 files changed, 424 insertions(+), 268 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 830a8289cb..1da9a704dd 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -473,6 +473,32 @@ jobs: - name: Sample check run: | ./scripts/check-sample.sh + sample-check-no-data-channel: + if: github.repository == 'awslabs/amazon-kinesis-video-streams-webrtc-sdk-c' + runs-on: ubuntu-latest + 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 }} + role-duration-seconds: 10800 + - name: Build repository + run: | + sudo sh -c 'echo 0 > /proc/sys/net/ipv6/conf/all/disable_ipv6' + mkdir build && cd build + cmake .. -DENABLE_DATA_CHANNEL=OFF + make + - name: Sample check without data channel + run: | + ./scripts/check-sample.sh ubuntu-os-build: runs-on: ubuntu-20.04 env: diff --git a/CMake/Dependencies/libmbedtls-CMakeLists.txt b/CMake/Dependencies/libmbedtls-CMakeLists.txt index aad9516994..2aa6f7ba72 100644 --- a/CMake/Dependencies/libmbedtls-CMakeLists.txt +++ b/CMake/Dependencies/libmbedtls-CMakeLists.txt @@ -26,7 +26,7 @@ ExternalProject_Add( CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${OPEN_SRC_INSTALL_PREFIX} -DUSE_SHARED_MBEDTLS_LIBRARY=${BUILD_SHARED} - -DCMAKE_BUILD_TYPE=Release + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_MACOSX_RPATH=${CMAKE_MACOSX_RPATH} -DENABLE_TESTING=OFF -DENABLE_PROGRAMS=OFF diff --git a/CMake/Dependencies/libusrsctp-CMakeLists.txt b/CMake/Dependencies/libusrsctp-CMakeLists.txt index 7ccc63f5bf..ab99cf4c15 100644 --- a/CMake/Dependencies/libusrsctp-CMakeLists.txt +++ b/CMake/Dependencies/libusrsctp-CMakeLists.txt @@ -8,7 +8,8 @@ ExternalProject_Add(project_libusrsctp GIT_REPOSITORY https://github.com/sctplab/usrsctp.git GIT_TAG 1ade45cbadfd19298d2c47dc538962d4425ad2dd PREFIX ${CMAKE_CURRENT_BINARY_DIR}/build - CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${OPEN_SRC_INSTALL_PREFIX} + CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${OPEN_SRC_INSTALL_PREFIX} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} -fPIC" -Dsctp_werror=0 BUILD_ALWAYS TRUE diff --git a/CMake/Dependencies/libwebsockets-CMakeLists.txt b/CMake/Dependencies/libwebsockets-CMakeLists.txt index 6ce4f28fec..8e0f068ca1 100644 --- a/CMake/Dependencies/libwebsockets-CMakeLists.txt +++ b/CMake/Dependencies/libwebsockets-CMakeLists.txt @@ -37,6 +37,7 @@ ExternalProject_Add(project_libwebsockets CMAKE_ARGS -DCMAKE_INSTALL_PREFIX=${OPEN_SRC_INSTALL_PREFIX} -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DLWS_WITH_HTTP2=1 -DLWS_HAVE_HMAC_CTX_new=1 -DLWS_HAVE_SSL_EXTRA_CHAIN_CERTS=1 diff --git a/CMakeLists.txt b/CMakeLists.txt index 2e6e39dc09..08913d2a3d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -39,6 +39,10 @@ if(WIN32) set(EXT_PTHREAD_LIBRARIES "" CACHE FILEPATH "Path to PThread libraries") endif() +if(NOT CMAKE_BUILD_TYPE) + message(STATUS "Setting CMAKE_BUILD_TYPE to Release by default") + set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Choose the type of build." FORCE) +endif() execute_process( COMMAND git rev-parse HEAD @@ -148,12 +152,14 @@ if(BUILD_DEPENDENCIES) if (USE_OPENSSL) set(BUILD_ARGS -DBUILD_STATIC_LIBS=${BUILD_STATIC_LIBS} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DBUILD_OPENSSL_PLATFORM=${BUILD_OPENSSL_PLATFORM} -DOPENSSL_EXTRA=${OPENSSL_EXTRA}) build_dependency(openssl ${BUILD_ARGS}) set(OPENSSL_ROOT_DIR ${OPEN_SRC_INSTALL_PREFIX}) elseif(USE_MBEDTLS) set(BUILD_ARGS -DBUILD_STATIC_LIBS=${BUILD_STATIC_LIBS} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} "-DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} -std=c99") build_dependency(mbedtls ${BUILD_ARGS}) endif() @@ -166,8 +172,9 @@ if(BUILD_DEPENDENCIES) set(OPENSSL_LIBRARIES ${OPENSSL_SSL_LIBRARY} ${OPENSSL_CRYPTO_LIBRARY}) string(REPLACE ";" "|" OPENSSL_LIBRARIES_ALT_SEP "${OPENSSL_LIBRARIES}") set(BUILD_ARGS -DBUILD_STATIC_LIBS=${BUILD_STATIC_LIBS} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DUSE_OPENSSL=${USE_OPENSSL} - -DUSE_MBEDTLS=${USE_MBEDTLS} + -DUSE_MBEDTLS=${USE_MBEDTLS} -DLWS_EXT_PTHREAD_INCLUDE_DIR=${EXT_PTHREAD_INCLUDE_DIR} -DLWS_EXT_PTHREAD_LIBRARIES=${EXT_PTHREAD_LIBRARIES} -DLWS_OPENSSL_INCLUDE_DIRS=${OPENSSL_INCLUDE_DIRS} @@ -175,6 +182,7 @@ if(BUILD_DEPENDENCIES) -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}) else() set(BUILD_ARGS -DBUILD_STATIC_LIBS=${BUILD_STATIC_LIBS} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DOPENSSL_DIR=${OPEN_SRC_INSTALL_PREFIX} -DUSE_OPENSSL=${USE_OPENSSL} -DUSE_MBEDTLS=${USE_MBEDTLS} @@ -187,16 +195,18 @@ if(BUILD_DEPENDENCIES) set(BUILD_ARGS -DBUILD_STATIC_LIBS=${BUILD_STATIC_LIBS} + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DOPENSSL_DIR=${OPEN_SRC_INSTALL_PREFIX} -DBUILD_LIBSRTP_HOST_PLATFORM=${BUILD_LIBSRTP_HOST_PLATFORM} -DBUILD_LIBSRTP_DESTINATION_PLATFORM=${BUILD_LIBSRTP_DESTINATION_PLATFORM} -DUSE_OPENSSL=${USE_OPENSSL} -DUSE_MBEDTLS=${USE_MBEDTLS} -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}) - + build_dependency(srtp ${BUILD_ARGS}) set(BUILD_ARGS + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS}) build_dependency(usrsctp ${BUILD_ARGS}) diff --git a/README.md b/README.md index 95ddd46458..ab2a6b711b 100644 --- a/README.md +++ b/README.md @@ -149,6 +149,7 @@ You can pass the following options to `cmake ..`. * `-DMEMORY_SANITIZER` -- Build with MemorySanitizer * `-DTHREAD_SANITIZER` -- Build with ThreadSanitizer * `-DUNDEFINED_BEHAVIOR_SANITIZER` -- Build with UndefinedBehaviorSanitizer +* `-DCMAKE_BUILD_TYPE` -- Build Release/Debug libraries. By default, the SDK generates Release build. The standard options are listed [here](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#default-and-custom-configurations) * `-DLINK_PROFILER` -- Link with gperftools (available profiler options are listed [here](https://github.com/gperftools/gperftools)) To clean up the `open-source` and `build` folders from previous build, use `cmake --build . --target clean` from the `build` folder diff --git a/samples/Common.c b/samples/Common.c index 91f3208169..2deb9d6175 100644 --- a/samples/Common.c +++ b/samples/Common.c @@ -32,182 +32,6 @@ STATUS signalingCallFailed(STATUS status) STATUS_SIGNALING_DESCRIBE_MEDIA_CALL_FAILED == status); } -VOID onDataChannelMessage(UINT64 customData, PRtcDataChannel pDataChannel, BOOL isBinary, PBYTE pMessage, UINT32 pMessageLen) -{ - STATUS retStatus = STATUS_SUCCESS; - UINT32 i, strLen, tokenCount; - CHAR pMessageSend[MAX_DATA_CHANNEL_METRICS_MESSAGE_SIZE], errorMessage[200]; - PCHAR json; - PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; - PSampleConfiguration pSampleConfiguration; - DataChannelMessage dataChannelMessage; - jsmn_parser parser; - jsmntok_t tokens[MAX_JSON_TOKEN_COUNT]; - - CHK(pMessage != NULL && pDataChannel != NULL, STATUS_NULL_ARG); - - if (pSampleStreamingSession == NULL) { - STRCPY(errorMessage, "Could not generate stats since the streaming session is NULL"); - retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) errorMessage, STRLEN(errorMessage)); - DLOGE("%s", errorMessage); - goto CleanUp; - } - - pSampleConfiguration = pSampleStreamingSession->pSampleConfiguration; - if (pSampleConfiguration == NULL) { - STRCPY(errorMessage, "Could not generate stats since the sample configuration is NULL"); - retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) errorMessage, STRLEN(errorMessage)); - DLOGE("%s", errorMessage); - goto CleanUp; - } - - if (pSampleConfiguration->enableSendingMetricsToViewerViaDc) { - jsmn_init(&parser); - json = (PCHAR) pMessage; - tokenCount = jsmn_parse(&parser, json, STRLEN(json), tokens, SIZEOF(tokens) / SIZEOF(jsmntok_t)); - - MEMSET(dataChannelMessage.content, '\0', SIZEOF(dataChannelMessage.content)); - MEMSET(dataChannelMessage.firstMessageFromViewerTs, '\0', SIZEOF(dataChannelMessage.firstMessageFromViewerTs)); - MEMSET(dataChannelMessage.firstMessageFromMasterTs, '\0', SIZEOF(dataChannelMessage.firstMessageFromMasterTs)); - MEMSET(dataChannelMessage.secondMessageFromViewerTs, '\0', SIZEOF(dataChannelMessage.secondMessageFromViewerTs)); - MEMSET(dataChannelMessage.secondMessageFromMasterTs, '\0', SIZEOF(dataChannelMessage.secondMessageFromMasterTs)); - MEMSET(dataChannelMessage.lastMessageFromViewerTs, '\0', SIZEOF(dataChannelMessage.lastMessageFromViewerTs)); - - if (tokenCount > 1) { - if (tokens[0].type != JSMN_OBJECT) { - STRCPY(errorMessage, "Invalid JSON received, please send a valid json as the SDK is operating in datachannel-benchmarking mode"); - retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) errorMessage, STRLEN(errorMessage)); - DLOGE("%s", errorMessage); - retStatus = STATUS_INVALID_API_CALL_RETURN_JSON; - goto CleanUp; - } - DLOGI("DataChannel json message: %.*s\n", pMessageLen, pMessage); - - for (i = 1; i < tokenCount; i++) { - if (compareJsonString(json, &tokens[i], JSMN_STRING, (PCHAR) "content")) { - strLen = (UINT32) (tokens[i + 1].end - tokens[i + 1].start); - if (strLen != 0) { - STRNCPY(dataChannelMessage.content, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start); - } - } else if (compareJsonString(json, &tokens[i], JSMN_STRING, (PCHAR) "firstMessageFromViewerTs")) { - strLen = (UINT32) (tokens[i + 1].end - tokens[i + 1].start); - // parse and retain this message from the viewer to send it back again - if (strLen != 0) { - // since the length is not zero, we have already attached this timestamp to structure in the last iteration - STRNCPY(dataChannelMessage.firstMessageFromViewerTs, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start); - } - } else if (compareJsonString(json, &tokens[i], JSMN_STRING, (PCHAR) "firstMessageFromMasterTs")) { - strLen = (UINT32) (tokens[i + 1].end - tokens[i + 1].start); - if (strLen != 0) { - // since the length is not zero, we have already attached this timestamp to structure in the last iteration - STRNCPY(dataChannelMessage.firstMessageFromMasterTs, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start); - } else { - // if this timestamp was not assigned during the previous message session, add it now - SNPRINTF(dataChannelMessage.firstMessageFromMasterTs, 20, "%llu", GETTIME() / 10000); - break; - } - } else if (compareJsonString(json, &tokens[i], JSMN_STRING, (PCHAR) "secondMessageFromViewerTs")) { - strLen = (UINT32) (tokens[i + 1].end - tokens[i + 1].start); - // parse and retain this message from the viewer to send it back again - if (strLen != 0) { - STRNCPY(dataChannelMessage.secondMessageFromViewerTs, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start); - } - } else if (compareJsonString(json, &tokens[i], JSMN_STRING, (PCHAR) "secondMessageFromMasterTs")) { - strLen = (UINT32) (tokens[i + 1].end - tokens[i + 1].start); - if (strLen != 0) { - // since the length is not zero, we have already attached this timestamp to structure in the last iteration - STRNCPY(dataChannelMessage.secondMessageFromMasterTs, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start); - } else { - // if this timestamp was not assigned during the previous message session, add it now - SNPRINTF(dataChannelMessage.secondMessageFromMasterTs, 20, "%llu", GETTIME() / 10000); - break; - } - } else if (compareJsonString(json, &tokens[i], JSMN_STRING, (PCHAR) "lastMessageFromViewerTs")) { - strLen = (UINT32) (tokens[i + 1].end - tokens[i + 1].start); - if (strLen != 0) { - STRNCPY(dataChannelMessage.lastMessageFromViewerTs, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start); - } - } - } - - if (STRLEN(dataChannelMessage.lastMessageFromViewerTs) == 0) { - // continue sending the data_channel_metrics_message with new timestamps until we receive the lastMessageFromViewerTs from the viewer - SNPRINTF(pMessageSend, MAX_DATA_CHANNEL_METRICS_MESSAGE_SIZE, DATA_CHANNEL_MESSAGE_TEMPLATE, MASTER_DATA_CHANNEL_MESSAGE, - dataChannelMessage.firstMessageFromViewerTs, dataChannelMessage.firstMessageFromMasterTs, - dataChannelMessage.secondMessageFromViewerTs, dataChannelMessage.secondMessageFromMasterTs, - dataChannelMessage.lastMessageFromViewerTs); - DLOGI("Master's response: %s", pMessageSend); - - retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) pMessageSend, STRLEN(pMessageSend)); - } else { - // now that we've received the last message, send across the signaling, peerConnection, ice metrics - SNPRINTF(pSampleStreamingSession->pSignalingClientMetricsMessage, MAX_SIGNALING_CLIENT_METRICS_MESSAGE_SIZE, - SIGNALING_CLIENT_METRICS_JSON_TEMPLATE, pSampleConfiguration->signalingClientMetrics.signalingStartTime, - pSampleConfiguration->signalingClientMetrics.signalingEndTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.offerReceivedTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.answerTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.describeChannelStartTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.describeChannelEndTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.getSignalingChannelEndpointStartTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.getSignalingChannelEndpointEndTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.getIceServerConfigStartTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.getIceServerConfigEndTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.getTokenStartTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.getTokenEndTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.createChannelStartTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.createChannelEndTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.connectStartTime, - pSampleConfiguration->signalingClientMetrics.signalingClientStats.connectEndTime); - DLOGI("Sending signaling metrics to the viewer: %s", pSampleStreamingSession->pSignalingClientMetricsMessage); - - CHK_STATUS(peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->peerConnectionMetrics)); - SNPRINTF(pSampleStreamingSession->pPeerConnectionMetricsMessage, MAX_PEER_CONNECTION_METRICS_MESSAGE_SIZE, - PEER_CONNECTION_METRICS_JSON_TEMPLATE, - pSampleStreamingSession->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime, - pSampleStreamingSession->peerConnectionMetrics.peerConnectionStats.peerConnectionConnectedTime); - DLOGI("Sending peer-connection metrics to the viewer: %s", pSampleStreamingSession->pPeerConnectionMetricsMessage); - - CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->iceMetrics)); - SNPRINTF(pSampleStreamingSession->pIceAgentMetricsMessage, MAX_ICE_AGENT_METRICS_MESSAGE_SIZE, ICE_AGENT_METRICS_JSON_TEMPLATE, - pSampleStreamingSession->iceMetrics.kvsIceAgentStats.candidateGatheringStartTime, - pSampleStreamingSession->iceMetrics.kvsIceAgentStats.candidateGatheringEndTime); - DLOGI("Sending ice-agent metrics to the viewer: %s", pSampleStreamingSession->pIceAgentMetricsMessage); - - retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) pSampleStreamingSession->pSignalingClientMetricsMessage, - STRLEN(pSampleStreamingSession->pSignalingClientMetricsMessage)); - retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) pSampleStreamingSession->pPeerConnectionMetricsMessage, - STRLEN(pSampleStreamingSession->pPeerConnectionMetricsMessage)); - retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) pSampleStreamingSession->pIceAgentMetricsMessage, - STRLEN(pSampleStreamingSession->pIceAgentMetricsMessage)); - } - } else { - DLOGI("DataChannel string message: %.*s\n", pMessageLen, pMessage); - STRCPY(errorMessage, "Send a json message for benchmarking as the C SDK is operating in benchmarking mode"); - retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) errorMessage, STRLEN(errorMessage)); - } - } else { - if (isBinary) { - DLOGI("DataChannel Binary Message"); - } else { - DLOGI("DataChannel String Message: %.*s\n", pMessageLen, pMessage); - } - // Send a response to the message sent by the viewer - retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) MASTER_DATA_CHANNEL_MESSAGE, STRLEN(MASTER_DATA_CHANNEL_MESSAGE)); - } - if (retStatus != STATUS_SUCCESS) { - DLOGI("[KVS Master] dataChannelSend(): operation returned status code: 0x%08x \n", retStatus); - } - -CleanUp: - CHK_LOG_ERR(retStatus); -} - -VOID onDataChannel(UINT64 customData, PRtcDataChannel pRtcDataChannel) -{ - DLOGI("New DataChannel has been opened %s \n", pRtcDataChannel->name); - dataChannelOnMessage(pRtcDataChannel, customData, onDataChannelMessage); -} - VOID onConnectionStateChange(UINT64 customData, RTC_PEER_CONNECTION_STATE newState) { STATUS retStatus = STATUS_SUCCESS; @@ -713,10 +537,12 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P CHK_STATUS(peerConnectionOnIceCandidate(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, onIceCandidateHandler)); CHK_STATUS( peerConnectionOnConnectionStateChange(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, onConnectionStateChange)); +#ifdef ENABLE_DATA_CHANNEL if (pSampleConfiguration->onDataChannel != NULL) { CHK_STATUS(peerConnectionOnDataChannel(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, pSampleConfiguration->onDataChannel)); } +#endif // Declare that we support H264,Profile=42E01F,level-asymmetry-allowed=1,packetization-mode=1 and Opus CHK_STATUS(addSupportedCodec(pSampleStreamingSession->pPeerConnection, RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE)); @@ -1843,3 +1669,181 @@ STATUS removeExpiredMessageQueues(PStackQueue pPendingQueue) return retStatus; } + +#ifdef ENABLE_DATA_CHANNEL +VOID onDataChannelMessage(UINT64 customData, PRtcDataChannel pDataChannel, BOOL isBinary, PBYTE pMessage, UINT32 pMessageLen) +{ + STATUS retStatus = STATUS_SUCCESS; + UINT32 i, strLen, tokenCount; + CHAR pMessageSend[MAX_DATA_CHANNEL_METRICS_MESSAGE_SIZE], errorMessage[200]; + PCHAR json; + PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; + PSampleConfiguration pSampleConfiguration; + DataChannelMessage dataChannelMessage; + jsmn_parser parser; + jsmntok_t tokens[MAX_JSON_TOKEN_COUNT]; + + CHK(pMessage != NULL && pDataChannel != NULL, STATUS_NULL_ARG); + + if (pSampleStreamingSession == NULL) { + STRCPY(errorMessage, "Could not generate stats since the streaming session is NULL"); + retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) errorMessage, STRLEN(errorMessage)); + DLOGE("%s", errorMessage); + goto CleanUp; + } + + pSampleConfiguration = pSampleStreamingSession->pSampleConfiguration; + if (pSampleConfiguration == NULL) { + STRCPY(errorMessage, "Could not generate stats since the sample configuration is NULL"); + retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) errorMessage, STRLEN(errorMessage)); + DLOGE("%s", errorMessage); + goto CleanUp; + } + + if (pSampleConfiguration->enableSendingMetricsToViewerViaDc) { + jsmn_init(&parser); + json = (PCHAR) pMessage; + tokenCount = jsmn_parse(&parser, json, STRLEN(json), tokens, SIZEOF(tokens) / SIZEOF(jsmntok_t)); + + MEMSET(dataChannelMessage.content, '\0', SIZEOF(dataChannelMessage.content)); + MEMSET(dataChannelMessage.firstMessageFromViewerTs, '\0', SIZEOF(dataChannelMessage.firstMessageFromViewerTs)); + MEMSET(dataChannelMessage.firstMessageFromMasterTs, '\0', SIZEOF(dataChannelMessage.firstMessageFromMasterTs)); + MEMSET(dataChannelMessage.secondMessageFromViewerTs, '\0', SIZEOF(dataChannelMessage.secondMessageFromViewerTs)); + MEMSET(dataChannelMessage.secondMessageFromMasterTs, '\0', SIZEOF(dataChannelMessage.secondMessageFromMasterTs)); + MEMSET(dataChannelMessage.lastMessageFromViewerTs, '\0', SIZEOF(dataChannelMessage.lastMessageFromViewerTs)); + + if (tokenCount > 1) { + if (tokens[0].type != JSMN_OBJECT) { + STRCPY(errorMessage, "Invalid JSON received, please send a valid json as the SDK is operating in datachannel-benchmarking mode"); + retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) errorMessage, STRLEN(errorMessage)); + DLOGE("%s", errorMessage); + retStatus = STATUS_INVALID_API_CALL_RETURN_JSON; + goto CleanUp; + } + DLOGI("DataChannel json message: %.*s\n", pMessageLen, pMessage); + + for (i = 1; i < tokenCount; i++) { + if (compareJsonString(json, &tokens[i], JSMN_STRING, (PCHAR) "content")) { + strLen = (UINT32) (tokens[i + 1].end - tokens[i + 1].start); + if (strLen != 0) { + STRNCPY(dataChannelMessage.content, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start); + } + } else if (compareJsonString(json, &tokens[i], JSMN_STRING, (PCHAR) "firstMessageFromViewerTs")) { + strLen = (UINT32) (tokens[i + 1].end - tokens[i + 1].start); + // parse and retain this message from the viewer to send it back again + if (strLen != 0) { + // since the length is not zero, we have already attached this timestamp to structure in the last iteration + STRNCPY(dataChannelMessage.firstMessageFromViewerTs, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start); + } + } else if (compareJsonString(json, &tokens[i], JSMN_STRING, (PCHAR) "firstMessageFromMasterTs")) { + strLen = (UINT32) (tokens[i + 1].end - tokens[i + 1].start); + if (strLen != 0) { + // since the length is not zero, we have already attached this timestamp to structure in the last iteration + STRNCPY(dataChannelMessage.firstMessageFromMasterTs, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start); + } else { + // if this timestamp was not assigned during the previous message session, add it now + SNPRINTF(dataChannelMessage.firstMessageFromMasterTs, 20, "%llu", GETTIME() / 10000); + break; + } + } else if (compareJsonString(json, &tokens[i], JSMN_STRING, (PCHAR) "secondMessageFromViewerTs")) { + strLen = (UINT32) (tokens[i + 1].end - tokens[i + 1].start); + // parse and retain this message from the viewer to send it back again + if (strLen != 0) { + STRNCPY(dataChannelMessage.secondMessageFromViewerTs, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start); + } + } else if (compareJsonString(json, &tokens[i], JSMN_STRING, (PCHAR) "secondMessageFromMasterTs")) { + strLen = (UINT32) (tokens[i + 1].end - tokens[i + 1].start); + if (strLen != 0) { + // since the length is not zero, we have already attached this timestamp to structure in the last iteration + STRNCPY(dataChannelMessage.secondMessageFromMasterTs, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start); + } else { + // if this timestamp was not assigned during the previous message session, add it now + SNPRINTF(dataChannelMessage.secondMessageFromMasterTs, 20, "%llu", GETTIME() / 10000); + break; + } + } else if (compareJsonString(json, &tokens[i], JSMN_STRING, (PCHAR) "lastMessageFromViewerTs")) { + strLen = (UINT32) (tokens[i + 1].end - tokens[i + 1].start); + if (strLen != 0) { + STRNCPY(dataChannelMessage.lastMessageFromViewerTs, json + tokens[i + 1].start, tokens[i + 1].end - tokens[i + 1].start); + } + } + } + + if (STRLEN(dataChannelMessage.lastMessageFromViewerTs) == 0) { + // continue sending the data_channel_metrics_message with new timestamps until we receive the lastMessageFromViewerTs from the viewer + SNPRINTF(pMessageSend, MAX_DATA_CHANNEL_METRICS_MESSAGE_SIZE, DATA_CHANNEL_MESSAGE_TEMPLATE, MASTER_DATA_CHANNEL_MESSAGE, + dataChannelMessage.firstMessageFromViewerTs, dataChannelMessage.firstMessageFromMasterTs, + dataChannelMessage.secondMessageFromViewerTs, dataChannelMessage.secondMessageFromMasterTs, + dataChannelMessage.lastMessageFromViewerTs); + DLOGI("Master's response: %s", pMessageSend); + + retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) pMessageSend, STRLEN(pMessageSend)); + } else { + // now that we've received the last message, send across the signaling, peerConnection, ice metrics + SNPRINTF(pSampleStreamingSession->pSignalingClientMetricsMessage, MAX_SIGNALING_CLIENT_METRICS_MESSAGE_SIZE, + SIGNALING_CLIENT_METRICS_JSON_TEMPLATE, pSampleConfiguration->signalingClientMetrics.signalingStartTime, + pSampleConfiguration->signalingClientMetrics.signalingEndTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.offerReceivedTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.answerTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.describeChannelStartTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.describeChannelEndTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.getSignalingChannelEndpointStartTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.getSignalingChannelEndpointEndTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.getIceServerConfigStartTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.getIceServerConfigEndTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.getTokenStartTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.getTokenEndTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.createChannelStartTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.createChannelEndTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.connectStartTime, + pSampleConfiguration->signalingClientMetrics.signalingClientStats.connectEndTime); + DLOGI("Sending signaling metrics to the viewer: %s", pSampleStreamingSession->pSignalingClientMetricsMessage); + + CHK_STATUS(peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->peerConnectionMetrics)); + SNPRINTF(pSampleStreamingSession->pPeerConnectionMetricsMessage, MAX_PEER_CONNECTION_METRICS_MESSAGE_SIZE, + PEER_CONNECTION_METRICS_JSON_TEMPLATE, + pSampleStreamingSession->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime, + pSampleStreamingSession->peerConnectionMetrics.peerConnectionStats.peerConnectionConnectedTime); + DLOGI("Sending peer-connection metrics to the viewer: %s", pSampleStreamingSession->pPeerConnectionMetricsMessage); + + CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->iceMetrics)); + SNPRINTF(pSampleStreamingSession->pIceAgentMetricsMessage, MAX_ICE_AGENT_METRICS_MESSAGE_SIZE, ICE_AGENT_METRICS_JSON_TEMPLATE, + pSampleStreamingSession->iceMetrics.kvsIceAgentStats.candidateGatheringStartTime, + pSampleStreamingSession->iceMetrics.kvsIceAgentStats.candidateGatheringEndTime); + DLOGI("Sending ice-agent metrics to the viewer: %s", pSampleStreamingSession->pIceAgentMetricsMessage); + + retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) pSampleStreamingSession->pSignalingClientMetricsMessage, + STRLEN(pSampleStreamingSession->pSignalingClientMetricsMessage)); + retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) pSampleStreamingSession->pPeerConnectionMetricsMessage, + STRLEN(pSampleStreamingSession->pPeerConnectionMetricsMessage)); + retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) pSampleStreamingSession->pIceAgentMetricsMessage, + STRLEN(pSampleStreamingSession->pIceAgentMetricsMessage)); + } + } else { + DLOGI("DataChannel string message: %.*s\n", pMessageLen, pMessage); + STRCPY(errorMessage, "Send a json message for benchmarking as the C SDK is operating in benchmarking mode"); + retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) errorMessage, STRLEN(errorMessage)); + } + } else { + if (isBinary) { + DLOGI("DataChannel Binary Message"); + } else { + DLOGI("DataChannel String Message: %.*s\n", pMessageLen, pMessage); + } + // Send a response to the message sent by the viewer + retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) MASTER_DATA_CHANNEL_MESSAGE, STRLEN(MASTER_DATA_CHANNEL_MESSAGE)); + } + if (retStatus != STATUS_SUCCESS) { + DLOGI("[KVS Master] dataChannelSend(): operation returned status code: 0x%08x \n", retStatus); + } + +CleanUp: + CHK_LOG_ERR(retStatus); +} + +VOID onDataChannel(UINT64 customData, PRtcDataChannel pRtcDataChannel) +{ + DLOGI("New DataChannel has been opened %s \n", pRtcDataChannel->name); + dataChannelOnMessage(pRtcDataChannel, customData, onDataChannelMessage); +} +#endif diff --git a/samples/Samples.h b/samples/Samples.h index bc182ad769..83644c0689 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -34,7 +34,7 @@ extern "C" { #define CA_CERT_PEM_FILE_EXTENSION ".pem" -#define FILE_LOGGING_BUFFER_SIZE (10000 * 1024) +#define FILE_LOGGING_BUFFER_SIZE (10 * 1024) #define MAX_NUMBER_OF_LOG_FILES 5 #define SAMPLE_HASH_TABLE_BUCKET_COUNT 50 diff --git a/src/source/Ice/TurnConnection.c b/src/source/Ice/TurnConnection.c index 752ee49f2c..7761b757a9 100644 --- a/src/source/Ice/TurnConnection.c +++ b/src/source/Ice/TurnConnection.c @@ -1134,12 +1134,14 @@ STATUS turnConnectionGetLongTermKey(PCHAR username, PCHAR realm, PCHAR password, { STATUS retStatus = STATUS_SUCCESS; CHAR stringBuffer[STUN_MAX_USERNAME_LEN + MAX_ICE_CONFIG_CREDENTIAL_LEN + STUN_MAX_REALM_LEN + 2]; // 2 for two ":" between each value + INT32 amountWritten = 0; CHK(username != NULL && realm != NULL && password != NULL && pBuffer != NULL, STATUS_NULL_ARG); CHK(username[0] != '\0' && realm[0] != '\0' && password[0] != '\0' && bufferLen >= KVS_MD5_DIGEST_LENGTH, STATUS_INVALID_ARG); CHK((STRLEN(username) + STRLEN(realm) + STRLEN(password)) <= ARRAY_SIZE(stringBuffer) - 2, STATUS_INVALID_ARG); - SPRINTF(stringBuffer, "%s:%s:%s", username, realm, password); + amountWritten = SNPRINTF(stringBuffer, SIZEOF(stringBuffer), "%s:%s:%s", username, realm, password); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "SNPRINTF error: Failed to generate the long term key with username, realm and password"); // TODO: Return back the error check KVS_MD5_DIGEST((PBYTE) stringBuffer, STRLEN(stringBuffer), pBuffer); diff --git a/src/source/PeerConnection/PeerConnection.c b/src/source/PeerConnection/PeerConnection.c index dd3f160aca..859f973bff 100644 --- a/src/source/PeerConnection/PeerConnection.c +++ b/src/source/PeerConnection/PeerConnection.c @@ -1403,13 +1403,10 @@ STATUS createOffer(PRtcPeerConnection pPeerConnection, PRtcSessionDescriptionIni #endif CHK_STATUS(setPayloadTypesForOffer(pKvsPeerConnection->pCodecTable)); - CHK_STATUS(populateSessionDescription(pKvsPeerConnection, &(pKvsPeerConnection->remoteSessionDescription), pSessionDescription)); CHK_STATUS(serializeSessionDescription(pSessionDescription, NULL, &serializeLen)); CHK(serializeLen <= MAX_SESSION_DESCRIPTION_INIT_SDP_LEN, STATUS_NOT_ENOUGH_MEMORY); - CHK_STATUS(serializeSessionDescription(pSessionDescription, pSessionDescriptionInit->sdp, &serializeLen)); - // If embedded SDK acts as the viewer if (NULL != GETENV(DEBUG_LOG_SDP)) { DLOGD("LOCAL_SDP:%s", pSessionDescriptionInit->sdp); @@ -1436,7 +1433,6 @@ STATUS createAnswer(PRtcPeerConnection pPeerConnection, PRtcSessionDescriptionIn pKvsPeerConnection->isOffer = FALSE; CHK_STATUS(peerConnectionGetCurrentLocalDescription(pPeerConnection, pSessionDescriptionInit)); - // If embedded SDK acts as the master if (NULL != GETENV(DEBUG_LOG_SDP)) { DLOGD("LOCAL_SDP:%s", pSessionDescriptionInit->sdp); diff --git a/src/source/PeerConnection/SessionDescription.c b/src/source/PeerConnection/SessionDescription.c index 8d3257ac1a..4b0ab961c7 100644 --- a/src/source/PeerConnection/SessionDescription.c +++ b/src/source/PeerConnection/SessionDescription.c @@ -311,16 +311,21 @@ PCHAR fmtpForPayloadType(UINT64 payloadType, PSessionDescription pSessionDescrip UINT32 currentMedia, currentAttribute; PSdpMediaDescription pMediaDescription = NULL; CHAR payloadStr[MAX_SDP_ATTRIBUTE_VALUE_LENGTH]; + INT32 amountWritten = 0; MEMSET(payloadStr, 0x00, MAX_SDP_ATTRIBUTE_VALUE_LENGTH); - SPRINTF(payloadStr, "%" PRId64, payloadType); + amountWritten = SNPRINTF(payloadStr, SIZEOF(payloadStr), "%" PRId64, payloadType); - for (currentMedia = 0; currentMedia < pSessionDescription->mediaCount; currentMedia++) { - pMediaDescription = &(pSessionDescription->mediaDescriptions[currentMedia]); - for (currentAttribute = 0; currentAttribute < pMediaDescription->mediaAttributesCount; currentAttribute++) { - if (STRCMP(pMediaDescription->sdpAttributes[currentAttribute].attributeName, "fmtp") == 0 && - STRNCMP(pMediaDescription->sdpAttributes[currentAttribute].attributeValue, payloadStr, STRLEN(payloadStr)) == 0) { - return pMediaDescription->sdpAttributes[currentAttribute].attributeValue + STRLEN(payloadStr) + 1; + if (amountWritten < 0) { + DLOGE("Internal error: Full payload type for fmtp could not be written"); + } else { + for (currentMedia = 0; currentMedia < pSessionDescription->mediaCount; currentMedia++) { + pMediaDescription = &(pSessionDescription->mediaDescriptions[currentMedia]); + for (currentAttribute = 0; currentAttribute < pMediaDescription->mediaAttributesCount; currentAttribute++) { + if (STRCMP(pMediaDescription->sdpAttributes[currentAttribute].attributeName, "fmtp") == 0 && + STRNCMP(pMediaDescription->sdpAttributes[currentAttribute].attributeValue, payloadStr, STRLEN(payloadStr)) == 0) { + return pMediaDescription->sdpAttributes[currentAttribute].attributeValue + STRLEN(payloadStr) + 1; + } } } } @@ -400,6 +405,7 @@ STATUS populateSingleMediaSection(PKvsPeerConnection pKvsPeerConnection, PKvsRtp PSdpMediaDescription pSdpMediaDescriptionRemote; PCHAR currentFmtp = NULL, rtpMapValue = NULL; CHAR remoteSdpAttributeValue[MAX_SDP_ATTRIBUTE_VALUE_LENGTH]; + INT32 amountWritten = 0; MEMSET(remoteSdpAttributeValue, 0, MAX_SDP_ATTRIBUTE_VALUE_LENGTH); @@ -423,12 +429,18 @@ STATUS populateSingleMediaSection(PKvsPeerConnection pKvsPeerConnection, PKvsRtp containRtx = (retStatus == STATUS_SUCCESS); retStatus = STATUS_SUCCESS; if (containRtx) { - SPRINTF(pSdpMediaDescription->mediaName, "video 9 UDP/TLS/RTP/SAVPF %" PRId64 " %" PRId64, payloadType, rtxPayloadType); + amountWritten = SNPRINTF(pSdpMediaDescription->mediaName, SIZEOF(pSdpMediaDescription->mediaName), + "video 9 UDP/TLS/RTP/SAVPF %" PRId64 " %" PRId64, payloadType, rtxPayloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full video (with rtx) media name attribute could not be written"); } else { - SPRINTF(pSdpMediaDescription->mediaName, "video 9 UDP/TLS/RTP/SAVPF %" PRId64, payloadType); + amountWritten = + SNPRINTF(pSdpMediaDescription->mediaName, SIZEOF(pSdpMediaDescription->mediaName), "video 9 UDP/TLS/RTP/SAVPF %" PRId64, payloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full video media name attribute could not be written"); } } else if (pRtcMediaStreamTrack->kind == MEDIA_STREAM_TRACK_KIND_AUDIO) { - SPRINTF(pSdpMediaDescription->mediaName, "audio 9 UDP/TLS/RTP/SAVPF %" PRId64, payloadType); + amountWritten = + SNPRINTF(pSdpMediaDescription->mediaName, SIZEOF(pSdpMediaDescription->mediaName), "audio 9 UDP/TLS/RTP/SAVPF %" PRId64, payloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full audio media name attribute could not be written"); } CHK_STATUS(iceAgentPopulateSdpMediaDescriptionCandidates(pKvsPeerConnection->pIceAgent, pSdpMediaDescription, MAX_SDP_ATTRIBUTE_VALUE_LENGTH, @@ -436,60 +448,82 @@ STATUS populateSingleMediaSection(PKvsPeerConnection pKvsPeerConnection, PKvsRtp if (containRtx) { STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "msid"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%s %sRTX", pRtcMediaStreamTrack->streamId, - pRtcMediaStreamTrack->trackId); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%s %sRTX", + pRtcMediaStreamTrack->streamId, pRtcMediaStreamTrack->trackId); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full msid value (with rtx) could not be written"); attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "ssrc-group"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "FID %u %u", pKvsRtpTransceiver->sender.ssrc, - pKvsRtpTransceiver->sender.rtxSsrc); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "FID %u %u", + pKvsRtpTransceiver->sender.ssrc, pKvsRtpTransceiver->sender.rtxSsrc); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full ssrc-grp value (with rtx) could not be written"); attributeCount++; } else { STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "msid"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%s %s", pRtcMediaStreamTrack->streamId, - pRtcMediaStreamTrack->trackId); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%s %s", pRtcMediaStreamTrack->streamId, + pRtcMediaStreamTrack->trackId); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full msid value could not be written"); attributeCount++; } STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "ssrc"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%u cname:%s", pKvsRtpTransceiver->sender.ssrc, - pKvsPeerConnection->localCNAME); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%u cname:%s", + pKvsRtpTransceiver->sender.ssrc, pKvsPeerConnection->localCNAME); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full ssrc cname could not be written"); attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "ssrc"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%u msid:%s %s", pKvsRtpTransceiver->sender.ssrc, - pRtcMediaStreamTrack->streamId, pRtcMediaStreamTrack->trackId); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%u msid:%s %s", + pKvsRtpTransceiver->sender.ssrc, pRtcMediaStreamTrack->streamId, pRtcMediaStreamTrack->trackId); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full ssrc msid could not be written"); attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "ssrc"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%u mslabel:%s", pKvsRtpTransceiver->sender.ssrc, - pRtcMediaStreamTrack->streamId); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%u mslabel:%s", + pKvsRtpTransceiver->sender.ssrc, pRtcMediaStreamTrack->streamId); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full ssrc mslabel could not be written"); attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "ssrc"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%u label:%s", pKvsRtpTransceiver->sender.ssrc, - pRtcMediaStreamTrack->trackId); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%u label:%s", + pKvsRtpTransceiver->sender.ssrc, pRtcMediaStreamTrack->trackId); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full ssrc label could not be written"); attributeCount++; if (containRtx) { STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "ssrc"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%u cname:%s", pKvsRtpTransceiver->sender.rtxSsrc, - pKvsPeerConnection->localCNAME); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%u cname:%s", + pKvsRtpTransceiver->sender.rtxSsrc, pKvsPeerConnection->localCNAME); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full ssrc cname (with rtx) could not be written"); attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "ssrc"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%u msid:%s %sRTX", pKvsRtpTransceiver->sender.rtxSsrc, - pRtcMediaStreamTrack->streamId, pRtcMediaStreamTrack->trackId); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%u msid:%s %sRTX", + pKvsRtpTransceiver->sender.rtxSsrc, pRtcMediaStreamTrack->streamId, pRtcMediaStreamTrack->trackId); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full ssrc msid (with rtx) could not be written"); attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "ssrc"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%u mslabel:%sRTX", pKvsRtpTransceiver->sender.rtxSsrc, - pRtcMediaStreamTrack->streamId); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%u mslabel:%sRTX", + pKvsRtpTransceiver->sender.rtxSsrc, pRtcMediaStreamTrack->streamId); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full ssrc mslabel (with rtx) could not be written"); attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "ssrc"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%u label:%sRTX", pKvsRtpTransceiver->sender.rtxSsrc, - pRtcMediaStreamTrack->trackId); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%u label:%sRTX", + pKvsRtpTransceiver->sender.rtxSsrc, pRtcMediaStreamTrack->trackId); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full ssrc label (with rtx) could not be written"); attributeCount++; } @@ -533,9 +567,13 @@ STATUS populateSingleMediaSection(PKvsPeerConnection pKvsPeerConnection, PKvsRtp // If we don't have it, we loop over, create and add them if (STRLEN(remoteSdpAttributeValue) > 0) { CHK(STRLEN(remoteSdpAttributeValue) < MAX_SDP_ATTRIBUTE_VALUE_LENGTH, STATUS_BUFFER_TOO_SMALL); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%s", remoteSdpAttributeValue); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%s", remoteSdpAttributeValue); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Mid exists, but remote SDP value could not be written"); } else { - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%d", mediaSectionId); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%d", mediaSectionId); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full media section Id could not be written"); } attributeCount++; @@ -594,28 +632,43 @@ STATUS populateSingleMediaSection(PKvsPeerConnection pKvsPeerConnection, PKvsRtp currentFmtp = DEFAULT_H264_FMTP; } STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "rtpmap"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " H264/90000", payloadType); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " H264/90000", payloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full H264 payload type could not be written"); attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "rtcp-fb"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " nack", payloadType); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " nack pli", payloadType); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " nack", payloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full H264 rtcp-fb nack value could not be written"); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " nack pli", payloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full H264 rtcp-fb nack-pli value could not be written"); attributeCount++; // TODO: If level asymmetry is allowed, consider sending back DEFAULT_H264_FMTP instead of the received fmtp value. if (currentFmtp != NULL) { STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "fmtp"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " %s", payloadType, currentFmtp); + amountWritten = + SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " %s", payloadType, currentFmtp); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full H264 fmtp value could not be written"); attributeCount++; } if (containRtx) { STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "rtpmap"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " " RTX_VALUE, rtxPayloadType); + amountWritten = + SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " " RTX_VALUE, rtxPayloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full H264 rtpmap (with rtx) could not be written"); attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "fmtp"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " apt=%" PRId64 "", rtxPayloadType, payloadType); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " apt=%" PRId64 "", + rtxPayloadType, payloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full H264 fmtp apt value (with rtx) could not be written"); attributeCount++; } } else if (pRtcMediaStreamTrack->codec == RTC_CODEC_OPUS) { @@ -624,61 +677,90 @@ STATUS populateSingleMediaSection(PKvsPeerConnection pKvsPeerConnection, PKvsRtp } STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "rtpmap"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " opus/48000/2", payloadType); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " opus/48000/2", payloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full Opus rtpmap could not be written"); attributeCount++; if (currentFmtp != NULL) { STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "fmtp"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " %s", payloadType, currentFmtp); + amountWritten = + SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " %s", payloadType, currentFmtp); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full Opus fmtp could not be written"); attributeCount++; } } else if (pRtcMediaStreamTrack->codec == RTC_CODEC_VP8) { STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "rtpmap"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " " VP8_VALUE, payloadType); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " " VP8_VALUE, payloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full VP8 rtpmap could not be written"); attributeCount++; if (containRtx) { CHK_STATUS(hashTableGet(pKvsPeerConnection->pRtxTable, RTC_RTX_CODEC_VP8, &rtxPayloadType)); STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "rtpmap"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " " RTX_VALUE, rtxPayloadType); + amountWritten = + SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " " RTX_VALUE, rtxPayloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full VP8 rtpmap payload type (with rtx) could not be written"); attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "fmtp"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " apt=%" PRId64 "", rtxPayloadType, payloadType); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " apt=%" PRId64 "", + rtxPayloadType, payloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full VP8 rtpmap fmtp apt value (with rtx) could not be written"); attributeCount++; } } else if (pRtcMediaStreamTrack->codec == RTC_CODEC_MULAW) { STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "rtpmap"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " " MULAW_VALUE, payloadType); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " " MULAW_VALUE, payloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full MULAW rtpmap could not be written"); attributeCount++; } else if (pRtcMediaStreamTrack->codec == RTC_CODEC_ALAW) { STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "rtpmap"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " " ALAW_VALUE, payloadType); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " " ALAW_VALUE, payloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full ALAW rtpmap could not be written"); attributeCount++; } else if (pRtcMediaStreamTrack->codec == RTC_CODEC_UNKNOWN) { CHK_STATUS(hashTableGet(pUnknownCodecRtpmapTable, unknownCodecHashTableKey, (PUINT64) &rtpMapValue)); STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "rtpmap"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " %s", payloadType, rtpMapValue); + amountWritten = + SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " %s", payloadType, rtpMapValue); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full Unknown rtpmap could not be written"); attributeCount++; } STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "ssrc"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%u cname:%s", pKvsRtpTransceiver->sender.ssrc, - pKvsPeerConnection->localCNAME); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%u cname:%s", + pKvsRtpTransceiver->sender.ssrc, pKvsPeerConnection->localCNAME); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full transceiver ssrc cname could not be written"); attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "ssrc"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%u msid:%s %s", pKvsRtpTransceiver->sender.ssrc, - pRtcMediaStreamTrack->streamId, pRtcMediaStreamTrack->trackId); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%u msid:%s %s", + pKvsRtpTransceiver->sender.ssrc, pRtcMediaStreamTrack->streamId, pRtcMediaStreamTrack->trackId); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full transceiver ssrc msid could not be written"); attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "rtcp-fb"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " goog-remb", payloadType); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " goog-remb", payloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full rtcp-fb goog-remb could not be written"); attributeCount++; if (pKvsPeerConnection->twccExtId != 0) { STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "rtcp-fb"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%" PRId64 " " TWCC_SDP_ATTR, payloadType); + amountWritten = + SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%" PRId64 " " TWCC_SDP_ATTR, payloadType); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full rtcp-fb twcc could not be written"); attributeCount++; } @@ -696,8 +778,11 @@ STATUS populateSessionDescriptionDataChannel(PKvsPeerConnection pKvsPeerConnecti ENTERS(); STATUS retStatus = STATUS_SUCCESS; UINT32 attributeCount = 0; + INT32 amountWritten = 0; - SPRINTF(pSdpMediaDescription->mediaName, "application 9 UDP/DTLS/SCTP webrtc-datachannel"); + amountWritten = + SNPRINTF(pSdpMediaDescription->mediaName, SIZEOF(pSdpMediaDescription->mediaName), "application 9 UDP/DTLS/SCTP webrtc-datachannel"); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full data channel media name could not be written"); CHK_STATUS(iceAgentPopulateSdpMediaDescriptionCandidates(pKvsPeerConnection->pIceAgent, pSdpMediaDescription, MAX_SDP_ATTRIBUTE_VALUE_LENGTH, &attributeCount)); @@ -730,11 +815,15 @@ STATUS populateSessionDescriptionDataChannel(PKvsPeerConnection pKvsPeerConnecti attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "mid"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "%d", mediaSectionId); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "%d", mediaSectionId); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full data channel mid media section could not be written"); attributeCount++; STRCPY(pSdpMediaDescription->sdpAttributes[attributeCount].attributeName, "sctp-port"); - SPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, "5000"); + amountWritten = SNPRINTF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue, + SIZEOF(pSdpMediaDescription->sdpAttributes[attributeCount].attributeValue), "5000"); + CHK_ERR(amountWritten > 0, STATUS_INTERNAL_ERROR, "Full data channel sctp-port could not be written"); attributeCount++; pSdpMediaDescription->mediaAttributesCount = attributeCount; @@ -896,9 +985,7 @@ STATUS populateSessionDescription(PKvsPeerConnection pKvsPeerConnection, PSessio INT32 charsCopied; CHK(pKvsPeerConnection != NULL && pLocalSessionDescription != NULL && pRemoteSessionDescription != NULL, STATUS_NULL_ARG); - CHK_STATUS(populateSessionDescriptionMedia(pKvsPeerConnection, pRemoteSessionDescription, pLocalSessionDescription)); - MEMSET(bundleValue, 0, MAX_SDP_ATTRIBUTE_VALUE_LENGTH); MEMSET(wmsValue, 0, MAX_SDP_ATTRIBUTE_VALUE_LENGTH); MEMSET(remoteSdpAttributeValue, 0, MAX_SDP_ATTRIBUTE_VALUE_LENGTH); diff --git a/src/source/Sdp/Sdp.h b/src/source/Sdp/Sdp.h index c156e80357..6077a4e100 100644 --- a/src/source/Sdp/Sdp.h +++ b/src/source/Sdp/Sdp.h @@ -46,17 +46,47 @@ extern "C" { #define MAX_SDP_OFFSET_LENGTH 255 #define MAX_SDP_ENCRYPTION_KEY_METHOD_LENGTH 255 #define MAX_SDP_ENCRYPTION_KEY_LENGTH 255 -#define MAX_SDP_NETWORK_TYPE_LENGTH 255 -#define MAX_SDP_ADDRESS_TYPE_LENGTH 255 -#define MAX_SDP_CONNECTION_ADDRESS_LENGTH 255 -#define MAX_SDP_SESSION_USERNAME_LENGTH 255 -#define MAX_SDP_ATTRIBUTE_NAME_LENGTH 255 -#define MAX_SDP_ATTRIBUTE_VALUE_LENGTH 255 -#define MAX_SDP_MEDIA_NAME_LENGTH 255 -#define MAX_SDP_MEDIA_TITLE_LENGTH 255 -#define MAX_SDP_BANDWIDTH_LENGTH 255 + +/* https://datatracker.ietf.org/doc/html/rfc4566#section-5.7 -- the SDK hardcodes this to be IN as per spec. + * Also, this SDK is to be used in the Internet realm. Allowing for some extra buffer + */ +#define MAX_SDP_NETWORK_TYPE_LENGTH 7 + +/* https://datatracker.ietf.org/doc/html/rfc4566#section-5.7 -- Given the SDK is to operate in IP based sessions, + * the possible values are IP4/IP6 as registered with IANA. Allowing for some extra buffer + */ +#define MAX_SDP_ADDRESS_TYPE_LENGTH 7 + +/* https://datatracker.ietf.org/doc/html/rfc4566#section-5.7 -- Given the SDK is to operate in IP based sessions, + * an IPv4 address can be a maximum of characters where TTL is + * between 0 and 255. IPv6 can be a maximum of . Setting to 63 for additional padding + */ +#define MAX_SDP_CONNECTION_ADDRESS_LENGTH 63 + +// https://datatracker.ietf.org/doc/html/rfc4566#section-5.2 -- the SDK sets it to "-" and the SDK does not parse incoming username either +#define MAX_SDP_SESSION_USERNAME_LENGTH 32 + +// https://datatracker.ietf.org/doc/html/rfc4566#section-6 -- name length restricted based on current supported attribute set +#define MAX_SDP_ATTRIBUTE_NAME_LENGTH 32 + +// One of the attributes is streamId + trackId which sums up to 512 maximum characters +#define MAX_SDP_ATTRIBUTE_VALUE_LENGTH 512 + +#define MAX_SDP_MEDIA_NAME_LENGTH 255 + +/* https://tools.ietf.org/html/rfc4566#section-5.4. Given these are free-form textual strings, that is, the length could be anything. + * Although our SDK parses this information, the SDK does not use it. Leaving this attribute in if SDK uses it in + * the future, but keeping it at smaller size to ensure structure memory efficiency + */ +#define MAX_SDP_MEDIA_TITLE_LENGTH 127 + +/* https://tools.ietf.org/html/rfc4566#section-5.4. Given these are free-form textual strings, that is, the length could be anything. + * Although our SDK parses this information, the SDK does not use it. Leaving this attribute in if SDK uses it in + * the future, but keeping it at smaller size to ensure structure memory efficiency + */ +#define MAX_SDP_SESSION_INFORMATION_LENGTH 127 + #define MAX_SDP_SESSION_NAME_LENGTH 255 -#define MAX_SDP_SESSION_INFORMATION_LENGTH 255 #define MAX_SDP_SESSION_URI_LENGTH 255 #define MAX_SDP_SESSION_EMAIL_ADDRESS_LENGTH 255 #define MAX_SDP_SESSION_PHONE_NUMBER_LENGTH 255 @@ -64,7 +94,6 @@ extern "C" { #define MAX_SDP_TOKEN_LENGTH 128 #define MAX_SDP_FMTP_VALUES 64 -#define MAX_SDP_SESSION_BANDWIDTH_COUNT 2 #define MAX_SDP_SESSION_TIME_DESCRIPTION_COUNT 2 #define MAX_SDP_SESSION_TIMEZONE_COUNT 2 /** @@ -98,11 +127,6 @@ typedef struct { SdpConnectionInformation sdpConnectionInformation; } SdpOrigin, *PSdpOrigin; -typedef struct { - CHAR sdpBandwidthType[MAX_SDP_BANDWIDTH_LENGTH + 1]; - UINT64 sdpBandwidthValue; // bps -} SdpBandwidth, *PSdpBandwidth; - /* * https://tools.ietf.org/html/rfc4566#section-5.9 * https://tools.ietf.org/html/rfc4566#section-5.10 @@ -142,13 +166,13 @@ typedef struct { CHAR mediaName[MAX_SDP_MEDIA_NAME_LENGTH + 1]; // i= - // https://tools.ietf.org/html/rfc4566#section-5.4 + // https://tools.ietf.org/html/rfc4566#section-5.4. Given these are free-form strings, the length could be anything. + // Although our SDK parses this information, the SDK does not use it. Leaving this attribute in if SDK uses it in + // the future CHAR mediaTitle[MAX_SDP_MEDIA_TITLE_LENGTH + 1]; SdpConnectionInformation sdpConnectionInformation; - SdpBandwidth sdpBandwidth[MAX_SDP_MEDIA_BANDWIDTH_COUNT]; - SdpEncryptionKey sdpEncryptionKey; SdpAttributes sdpAttributes[MAX_SDP_ATTRIBUTES_COUNT]; @@ -186,8 +210,6 @@ typedef struct { SdpConnectionInformation sdpConnectionInformation; - SdpBandwidth sdpBandwidth[MAX_SDP_SESSION_BANDWIDTH_COUNT]; - SdpTimeDescription sdpTimeDescription[MAX_SDP_SESSION_TIME_DESCRIPTION_COUNT]; SdpTimeZone sdpTimeZone[MAX_SDP_SESSION_TIMEZONE_COUNT]; diff --git a/tst/DataChannelApiTest.cpp b/tst/DataChannelApiTest.cpp index 05f0836275..0c0f9bc1c6 100644 --- a/tst/DataChannelApiTest.cpp +++ b/tst/DataChannelApiTest.cpp @@ -1,5 +1,6 @@ #include "WebRTCClientTestFixture.h" +#ifdef ENABLE_DATA_CHANNEL namespace com { namespace amazonaws { namespace kinesis { @@ -37,3 +38,5 @@ TEST_F(DataChannelApiTest, createDataChannel_Disconnected) } // namespace kinesis } // namespace amazonaws } // namespace com + +#endif diff --git a/tst/DataChannelFunctionalityTest.cpp b/tst/DataChannelFunctionalityTest.cpp index abf373d5f5..a2a355cd36 100644 --- a/tst/DataChannelFunctionalityTest.cpp +++ b/tst/DataChannelFunctionalityTest.cpp @@ -1,5 +1,6 @@ #include "WebRTCClientTestFixture.h" +#ifdef ENABLE_DATA_CHANNEL namespace com { namespace amazonaws { namespace kinesis { @@ -595,3 +596,5 @@ TEST_F(DataChannelFunctionalityTest, createDataChannel_DataChannelMetricsTest) } // namespace kinesis } // namespace amazonaws } // namespace com + +#endif diff --git a/tst/IngestionFunctionalityTests.cpp b/tst/IngestionFunctionalityTests.cpp index 6f54690ac8..4216189fe8 100644 --- a/tst/IngestionFunctionalityTests.cpp +++ b/tst/IngestionFunctionalityTests.cpp @@ -856,7 +856,7 @@ TEST_F(IngestionFunctionalityTest, fileCachingTestWithDescribeMedia) FREMOVE(DEFAULT_CACHE_FILE_PATH); for (i = 0; i < totalChannelCount; ++i) { - SPRINTF(signalingChannelName, "%s%u", TEST_SIGNALING_CHANNEL_NAME, i); + SNPRINTF(signalingChannelName, SIZEOF(signalingChannelName), "%s%u", TEST_SIGNALING_CHANNEL_NAME, i); channelInfo.pChannelName = signalingChannelName; EXPECT_EQ(STATUS_SUCCESS, createSignalingSync(&clientInfoInternal, &channelInfo, &signalingClientCallbacks, (PAwsCredentialProvider) mTestCredentialProvider, @@ -872,7 +872,7 @@ TEST_F(IngestionFunctionalityTest, fileCachingTestWithDescribeMedia) getEndpointCountNoCache = getEndpointCount; for (i = 0; i < totalChannelCount; ++i) { - SPRINTF(signalingChannelName, "%s%u", TEST_SIGNALING_CHANNEL_NAME, i); + SNPRINTF(signalingChannelName, SIZEOF(signalingChannelName), "%s%u", TEST_SIGNALING_CHANNEL_NAME, i); channelInfo.pChannelName = signalingChannelName; channelInfo.pChannelArn = NULL; EXPECT_EQ(STATUS_SUCCESS,