From 3294ebbe761d146132aae02ac0105dacf3b587cb Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 30 Apr 2024 17:42:34 -0700 Subject: [PATCH 01/64] Start --- samples/Samples.h | 14 +++++++++++++ samples/kvsMetricsMonitoring.c | 38 ++++++++++++++++++++++++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 samples/kvsMetricsMonitoring.c diff --git a/samples/Samples.h b/samples/Samples.h index e409a9b5dd..4726269f95 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -109,6 +109,20 @@ typedef enum { RTSP_SOURCE, } SampleSourceType; +typedef enum { + ICE_CANDIDATE_PAIR_METRICS = 1 << 0, + ICE_SERVER_METRICS = 1 << 1, + DATA_CHANNEL_METRICS = 1 << 2, + INBOUND_RTP_METRICS = 1 << 4, + ICE_LOCAL_CANDIDATE_METRICS = 1 << 5, + OUTBOUND_RTP_METRICS = 1 << 6, + ICE_REMOTE_CANDIDATE_METRICS = 1 << 7, + REMOTE_INBOUND_RTP_METRICS = 1 << 8, + REMOTE_OUTBOUND_RTP_METRICS = 1 << 9, + TRANSPORT_METRICS = 1 << 10, + ALL_METRICS = 1 << 11 +} MetricsType; + typedef struct __SampleStreamingSession SampleStreamingSession; typedef struct __SampleStreamingSession* PSampleStreamingSession; diff --git a/samples/kvsMetricsMonitoring.c b/samples/kvsMetricsMonitoring.c new file mode 100644 index 0000000000..4fbfe96b3a --- /dev/null +++ b/samples/kvsMetricsMonitoring.c @@ -0,0 +1,38 @@ +#include "Samples.h" + +STATUS initMetricsModule(UINT64 metrics) { + if(metrics & ICE_CANDIDATE_PAIR_METRICS) { + + } + if(metrics & ICE_SERVER_METRICS) { + + } + if(metrics & DATA_CHANNEL_METRICS) { + + } + if(metrics & INBOUND_RTP_METRICS) { + + } + if(metrics & ICE_LOCAL_CANDIDATE_METRICS) { + + } + if(metrics & OUTBOUND_RTP_METRICS) { + + } + if(metrics & ICE_REMOTE_CANDIDATE_METRICS) { + + } + if(metrics & REMOTE_INBOUND_RTP_METRICS) { + + } + if(metrics & REMOTE_OUTBOUND_RTP_METRICS) { + + } + if(metrics & TRANSPORT_METRICS) { + + } + if(metrics & ALL_METRICS) { + + } + return STATUS_SUCCESS; +} \ No newline at end of file From b760fb420e68771f8b6d907d0bae852e8333afa5 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 2 May 2024 16:05:49 -0700 Subject: [PATCH 02/64] Trial --- CMake/Dependencies/libawscpp-CMakeLists.txt | 4 +- CMakeLists.txt | 17 +- aws-sdk-integ/CloudwatchMetrics.c | 0 samples/CMakeLists.txt | 5 +- samples/c_wrapper.cpp | 11 ++ samples/c_wrapper.h | 14 ++ samples/kvsWebRTCClientMasterCloudwatch.c | 195 ++++++++++++++++++++ 7 files changed, 242 insertions(+), 4 deletions(-) create mode 100644 aws-sdk-integ/CloudwatchMetrics.c create mode 100644 samples/c_wrapper.cpp create mode 100644 samples/c_wrapper.h create mode 100644 samples/kvsWebRTCClientMasterCloudwatch.c diff --git a/CMake/Dependencies/libawscpp-CMakeLists.txt b/CMake/Dependencies/libawscpp-CMakeLists.txt index 60f6bee6f8..5c457b406f 100644 --- a/CMake/Dependencies/libawscpp-CMakeLists.txt +++ b/CMake/Dependencies/libawscpp-CMakeLists.txt @@ -7,8 +7,10 @@ ExternalProject_Add(libawscpp-download GIT_TAG 1.11.217 LIST_SEPARATOR "|" CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF - -DBUILD_ONLY=kinesisvideo|kinesis-video-webrtc-storage + -DENABLE_TESTING=OFF + -DBUILD_ONLY=${BUILD_ONLY} -DCMAKE_INSTALL_PREFIX=${OPEN_SRC_INSTALL_PREFIX} + -DTARGET_ARCH=APPLE BUILD_ALWAYS TRUE TEST_COMMAND "" ) diff --git a/CMakeLists.txt b/CMakeLists.txt index 92e432bc0a..6b0bd570de 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,6 +21,7 @@ option(ENABLE_DATA_CHANNEL "Enable support for data channel" ON) option(ENABLE_KVS_THREADPOOL "Enable support for KVS thread pool in signaling" ON) option(INSTRUMENTED_ALLOCATORS "Enable memory instrumentation" OFF) option(ENABLE_AWS_SDK_IN_TESTS "Enable support for compiling AWS SDKs for tests" ON) +option(AWS_SDK_INTEG "Enable integration samples with cloudwatch" ON) # Developer Flags option(BUILD_TEST "Build the testing tree." OFF) @@ -233,9 +234,12 @@ if(BUILD_DEPENDENCIES) if(BUILD_TEST) build_dependency(gtest) - + set(BUILD_ARGS + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} + -DBUILD_ONLY=kinesisvideo|kinesis-video-webrtc-storage) if(ENABLE_AWS_SDK_IN_TESTS) - build_dependency(awscpp) + build_dependency(awscpp ${BUILD_ARGS}) endif() endif() @@ -247,6 +251,15 @@ if(BUILD_DEPENDENCIES) if (LINK_PROFILER) build_dependency(gperftools) endif() + + if(AWS_SDK_INTEG) + message(STATUS "Building...") + set(BUILD_ARGS + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} + -DBUILD_ONLY=monitoring|logs) + build_dependency(awscpp ${BUILD_ARGS}) + endif() message(STATUS "Finished building dependencies.") endif() diff --git a/aws-sdk-integ/CloudwatchMetrics.c b/aws-sdk-integ/CloudwatchMetrics.c new file mode 100644 index 0000000000..e69de29bb2 diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index ea9067bf18..b1532ab2ca 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -1,6 +1,9 @@ cmake_minimum_required(VERSION 3.6.3) -project(KinesisVideoWebRTCClientSamples LANGUAGES C) +project(KinesisVideoWebRTCClientSamples) + +set(CMAKE_CXX_STANDARD 11) # Adjust the version according to your needs + #set(OPEN_SRC_INSTALL_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/open-source" CACHE PATH "Libraries will be downloaded and build in this directory.") diff --git a/samples/c_wrapper.cpp b/samples/c_wrapper.cpp new file mode 100644 index 0000000000..68756468fd --- /dev/null +++ b/samples/c_wrapper.cpp @@ -0,0 +1,11 @@ +#include +#include "c_wrapper.h" + +extern "C" { +AwsSdkHandle aws_sdk_init() { + Aws::SDKOptions options; + Aws::InitAPI(options); + // Return some handle or pointer to indicate success + return NULL; +} +} diff --git a/samples/c_wrapper.h b/samples/c_wrapper.h new file mode 100644 index 0000000000..a655bac11c --- /dev/null +++ b/samples/c_wrapper.h @@ -0,0 +1,14 @@ +#ifdef __cplusplus +extern "C" { +#endif + +// Declare C-compatible interface +typedef void* AwsSdkHandle; + +AwsSdkHandle aws_sdk_init(); +void aws_sdk_cleanup(AwsSdkHandle handle); +void aws_sdk_some_operation(AwsSdkHandle handle); + +#ifdef __cplusplus +} +#endif diff --git a/samples/kvsWebRTCClientMasterCloudwatch.c b/samples/kvsWebRTCClientMasterCloudwatch.c new file mode 100644 index 0000000000..7fcfa0625f --- /dev/null +++ b/samples/kvsWebRTCClientMasterCloudwatch.c @@ -0,0 +1,195 @@ +#include "Samples.h" +#include "c_wrapper.h" +//#include +//#include +//#include +//#include +//#include +//#include +//#include +//#include + +extern PSampleConfiguration gSampleConfiguration; + +INT32 main(INT32 argc, CHAR* argv[]) +{ + STATUS retStatus = STATUS_SUCCESS; + + aws_sdk_init(); + +CleanUp: + + retStatus = RESET_INSTRUMENTED_ALLOCATORS(); + DLOGI("All SDK allocations freed? %s..0x%08x", retStatus == STATUS_SUCCESS ? "Yes" : "No", retStatus); + // https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html + // We can only return with 0 - 127. Some platforms treat exit code >= 128 + // to be a success code, which might give an unintended behaviour. + // Some platforms also treat 1 or 0 differently, so it's better to use + // EXIT_FAILURE and EXIT_SUCCESS macros for portability. + return STATUS_FAILED(retStatus) ? EXIT_FAILURE : EXIT_SUCCESS; +} + +STATUS readFrameFromDisk(PBYTE pFrame, PUINT32 pSize, PCHAR frameFilePath) +{ + STATUS retStatus = STATUS_SUCCESS; + UINT64 size = 0; + CHK_ERR(pSize != NULL, STATUS_NULL_ARG, "[KVS Master] Invalid file size"); + size = *pSize; + // Get the size and read into frame + CHK_STATUS(readFile(frameFilePath, TRUE, pFrame, &size)); + CleanUp: + + if (pSize != NULL) { + *pSize = (UINT32) size; + } + + return retStatus; +} + +PVOID sendVideoPackets(PVOID args) +{ + STATUS retStatus = STATUS_SUCCESS; + PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) args; + RtcEncoderStats encoderStats; + Frame frame; + UINT32 fileIndex = 0, frameSize; + CHAR filePath[MAX_PATH_LEN + 1]; + STATUS status; + UINT32 i; + UINT64 startTime, lastFrameTime, elapsed; + MEMSET(&encoderStats, 0x00, SIZEOF(RtcEncoderStats)); + CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); + + frame.presentationTs = 0; + startTime = GETTIME(); + lastFrameTime = startTime; + + while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { + fileIndex = fileIndex % NUMBER_OF_H264_FRAME_FILES + 1; + SNPRINTF(filePath, MAX_PATH_LEN, "./h264SampleFrames/frame-%04d.h264", fileIndex); + + CHK_STATUS(readFrameFromDisk(NULL, &frameSize, filePath)); + + // Re-alloc if needed + if (frameSize > pSampleConfiguration->videoBufferSize) { + pSampleConfiguration->pVideoFrameBuffer = (PBYTE) MEMREALLOC(pSampleConfiguration->pVideoFrameBuffer, frameSize); + CHK_ERR(pSampleConfiguration->pVideoFrameBuffer != NULL, STATUS_NOT_ENOUGH_MEMORY, "[KVS Master] Failed to allocate video frame buffer"); + pSampleConfiguration->videoBufferSize = frameSize; + } + + frame.frameData = pSampleConfiguration->pVideoFrameBuffer; + frame.size = frameSize; + + CHK_STATUS(readFrameFromDisk(frame.frameData, &frameSize, filePath)); + + // based on bitrate of samples/h264SampleFrames/frame-* + encoderStats.width = 640; + encoderStats.height = 480; + encoderStats.targetBitrate = 262000; + frame.presentationTs += SAMPLE_VIDEO_FRAME_DURATION; + MUTEX_LOCK(pSampleConfiguration->streamingSessionListReadLock); + for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { + status = writeFrame(pSampleConfiguration->sampleStreamingSessionList[i]->pVideoRtcRtpTransceiver, &frame); + if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { + PROFILE_WITH_START_TIME(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, "Time to first frame"); + pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame = FALSE; + } + encoderStats.encodeTimeMsec = 4; // update encode time to an arbitrary number to demonstrate stats update + updateEncoderStats(pSampleConfiguration->sampleStreamingSessionList[i]->pVideoRtcRtpTransceiver, &encoderStats); + if (status != STATUS_SRTP_NOT_READY_YET) { + if (status != STATUS_SUCCESS) { + DLOGV("writeFrame() failed with 0x%08x", status); + } + } else { + // Reset file index to ensure first frame sent upon SRTP ready is a key frame. + fileIndex = 0; + } + } + MUTEX_UNLOCK(pSampleConfiguration->streamingSessionListReadLock); + + // Adjust sleep in the case the sleep itself and writeFrame take longer than expected. Since sleep makes sure that the thread + // will be paused at least until the given amount, we can assume that there's no too early frame scenario. + // Also, it's very unlikely to have a delay greater than SAMPLE_VIDEO_FRAME_DURATION, so the logic assumes that this is always + // true for simplicity. + elapsed = lastFrameTime - startTime; + THREAD_SLEEP(SAMPLE_VIDEO_FRAME_DURATION - elapsed % SAMPLE_VIDEO_FRAME_DURATION); + lastFrameTime = GETTIME(); + } + + CleanUp: + DLOGI("[KVS Master] Closing video thread"); + CHK_LOG_ERR(retStatus); + + return (PVOID) (ULONG_PTR) retStatus; +} + +PVOID sendAudioPackets(PVOID args) +{ + STATUS retStatus = STATUS_SUCCESS; + PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) args; + Frame frame; + UINT32 fileIndex = 0, frameSize; + CHAR filePath[MAX_PATH_LEN + 1]; + UINT32 i; + STATUS status; + + CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); + frame.presentationTs = 0; + + while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { + fileIndex = fileIndex % NUMBER_OF_OPUS_FRAME_FILES + 1; + SNPRINTF(filePath, MAX_PATH_LEN, "./opusSampleFrames/sample-%03d.opus", fileIndex); + + CHK_STATUS(readFrameFromDisk(NULL, &frameSize, filePath)); + + // Re-alloc if needed + if (frameSize > pSampleConfiguration->audioBufferSize) { + pSampleConfiguration->pAudioFrameBuffer = (UINT8*) MEMREALLOC(pSampleConfiguration->pAudioFrameBuffer, frameSize); + CHK_ERR(pSampleConfiguration->pAudioFrameBuffer != NULL, STATUS_NOT_ENOUGH_MEMORY, "[KVS Master] Failed to allocate audio frame buffer"); + pSampleConfiguration->audioBufferSize = frameSize; + } + + frame.frameData = pSampleConfiguration->pAudioFrameBuffer; + frame.size = frameSize; + + CHK_STATUS(readFrameFromDisk(frame.frameData, &frameSize, filePath)); + + frame.presentationTs += SAMPLE_AUDIO_FRAME_DURATION; + + MUTEX_LOCK(pSampleConfiguration->streamingSessionListReadLock); + for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { + status = writeFrame(pSampleConfiguration->sampleStreamingSessionList[i]->pAudioRtcRtpTransceiver, &frame); + if (status != STATUS_SRTP_NOT_READY_YET) { + if (status != STATUS_SUCCESS) { + DLOGV("writeFrame() failed with 0x%08x", status); + } else if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { + PROFILE_WITH_START_TIME(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, "Time to first frame"); + pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame = FALSE; + } + } else { + // Reset file index to stay in sync with video frames. + fileIndex = 0; + } + } + MUTEX_UNLOCK(pSampleConfiguration->streamingSessionListReadLock); + THREAD_SLEEP(SAMPLE_AUDIO_FRAME_DURATION); + } + + CleanUp: + DLOGI("[KVS Master] closing audio thread"); + return (PVOID) (ULONG_PTR) retStatus; +} + +PVOID sampleReceiveAudioVideoFrame(PVOID args) +{ + STATUS retStatus = STATUS_SUCCESS; + PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) args; + CHK_ERR(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); + CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pVideoRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleVideoFrameHandler)); + CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pAudioRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleAudioFrameHandler)); + + CleanUp: + + return (PVOID) (ULONG_PTR) retStatus; +} + From df911a400288723a782cb75aee559172f90d8b3d Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 7 May 2024 17:50:57 -0700 Subject: [PATCH 03/64] Initial commit:rtp stats, config file --- CMake/Dependencies/libawscpp-CMakeLists.txt | 3 +- CMakeLists.txt | 8 + aws-cpp-sdk-integ/CMakeLists.txt | 29 ++ .../CloudwatchMetricsMonitoring.cpp | 183 ++++++++++++ .../CloudwatchMetricsMonitoring.h | 27 ++ aws-cpp-sdk-integ/Config.cpp | 274 ++++++++++++++++++ aws-cpp-sdk-integ/Config.h | 66 +++++ aws-cpp-sdk-integ/Include.h | 133 +++++++++ .../kvsWebRTCClientMasterCloudwatch.cpp | 174 ++++++++--- samples/CMakeLists.txt | 20 +- samples/Common.c | 242 ++++------------ .../CloudwatchMetrics.c => samples/Media.c | 0 samples/MetricsHandling.c | 203 +++++++++++++ samples/Samples.h | 46 ++- samples/Utility.c | 30 ++ samples/c_wrapper.cpp | 11 - samples/c_wrapper.h | 14 - samples/config_default.h | 8 + samples/kvsMetricsMonitoring.c | 36 +-- samples/kvsWebRTCClientMaster.c | 26 +- samples/sample_config.h | 11 + 21 files changed, 1228 insertions(+), 316 deletions(-) create mode 100644 aws-cpp-sdk-integ/CMakeLists.txt create mode 100644 aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.cpp create mode 100644 aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.h create mode 100644 aws-cpp-sdk-integ/Config.cpp create mode 100644 aws-cpp-sdk-integ/Config.h create mode 100644 aws-cpp-sdk-integ/Include.h rename samples/kvsWebRTCClientMasterCloudwatch.c => aws-cpp-sdk-integ/kvsWebRTCClientMasterCloudwatch.cpp (56%) rename aws-sdk-integ/CloudwatchMetrics.c => samples/Media.c (100%) create mode 100644 samples/MetricsHandling.c create mode 100644 samples/Utility.c delete mode 100644 samples/c_wrapper.cpp delete mode 100644 samples/c_wrapper.h create mode 100644 samples/config_default.h create mode 100644 samples/sample_config.h diff --git a/CMake/Dependencies/libawscpp-CMakeLists.txt b/CMake/Dependencies/libawscpp-CMakeLists.txt index 5c457b406f..8bfdec6ce2 100644 --- a/CMake/Dependencies/libawscpp-CMakeLists.txt +++ b/CMake/Dependencies/libawscpp-CMakeLists.txt @@ -4,13 +4,14 @@ include(ExternalProject) ExternalProject_Add(libawscpp-download GIT_REPOSITORY https://github.com/aws/aws-sdk-cpp.git - GIT_TAG 1.11.217 + GIT_TAG 1.11.143 LIST_SEPARATOR "|" CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DENABLE_TESTING=OFF -DBUILD_ONLY=${BUILD_ONLY} -DCMAKE_INSTALL_PREFIX=${OPEN_SRC_INSTALL_PREFIX} -DTARGET_ARCH=APPLE + -DCUSTOM_MEMORY_MANAGEMENT=OFF BUILD_ALWAYS TRUE TEST_COMMAND "" ) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b0bd570de..8eb43dc366 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,6 +34,12 @@ option(THREAD_SANITIZER "Build with ThreadSanitizer." OFF) option(UNDEFINED_BEHAVIOR_SANITIZER "Build with UndefinedBehaviorSanitizer." OFF) option(LINK_PROFILER "Link gperftools profiler" OFF) + +set(SAMPLE_CONFIG_HEADER "" CACHE FILEPATH "Config header") + +add_definitions(-DSAMPLE_CONFIG_HEADER="${SAMPLE_CONFIG_HEADER}") +message(STATUS ${SAMPLE_CONFIG_HEADER}) + if(WIN32) set(EXT_PTHREAD_INCLUDE_DIR "" CACHE PATH "Path to the PThread dir") set(EXT_PTHREAD_LIBRARIES "" CACHE FILEPATH "Path to PThread libraries") @@ -487,6 +493,8 @@ if (BUILD_SAMPLE) add_subdirectory(samples) endif() +add_subdirectory(aws-cpp-sdk-integ) + if(BUILD_TEST) # adding ZLIB because aws sdk static link seems to be broken when zlib is needed if(NOT WIN32) diff --git a/aws-cpp-sdk-integ/CMakeLists.txt b/aws-cpp-sdk-integ/CMakeLists.txt new file mode 100644 index 0000000000..1f324921ca --- /dev/null +++ b/aws-cpp-sdk-integ/CMakeLists.txt @@ -0,0 +1,29 @@ +cmake_minimum_required(VERSION 3.6.3) + +project(KinesisVideoWebRTCClientSamplesCloudwatch LANGUAGES C CXX) +set(CMAKE_CXX_STANDARD 11) + +message("OPEN_SRC_INSTALL_PREFIX=${OPEN_SRC_INSTALL_PREFIX}") + +include_directories(${OPEN_SRC_INSTALL_PREFIX}/include) +include_directories(${OPEN_SRC_INCLUDE_DIRS}) +link_directories(${OPEN_SRC_INSTALL_PREFIX}/lib) + +find_package(ZLIB REQUIRED) +find_package(AWSSDK REQUIRED COMPONENTS monitoring logs) + +add_executable( + kvsWebrtcClientMasterCW + ../samples/Common.c + ../samples/kvsMetricsMonitoring.c + ../samples/Utility.c + ../samples/MetricsHandling.c + Config.cpp + CloudwatchMetricsMonitoring.cpp + kvsWebRTCClientMasterCloudwatch.cpp) +target_link_libraries(kvsWebrtcClientMasterCW + kvsWebrtcClient + kvsWebrtcSignalingClient + ${EXTRA_DEPS} + kvsCommonLws kvspicUtils websockets kvssdp kvsstun + ${AWSSDK_LINK_LIBRARIES}) diff --git a/aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.cpp b/aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.cpp new file mode 100644 index 0000000000..48dc133d54 --- /dev/null +++ b/aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.cpp @@ -0,0 +1,183 @@ +#include "Include.h" +#include "Config.h" +#include "CloudwatchMetricsMonitoring.h" + +namespace CppInteg { + CloudwatchMetricsMonitoring::CloudwatchMetricsMonitoring(PConfig pConfig, ClientConfiguration* pClientConfig) : pConfig(pConfig), client(*pClientConfig) + { + pConfig->isStorage ? this->isStorage = true : this->isStorage = false; + } + + STATUS CloudwatchMetricsMonitoring::init(CppInteg::PConfig pConfig) + { + ENTERS(); + STATUS retStatus = STATUS_SUCCESS; + ClientConfiguration clientConfig; + + clientConfig.region = pConfig->region.value; + auto& instance = getInstanceImpl(pConfig, &clientConfig); + + this->isStorage ? this->channelDimension.SetName(INDIVIDUAL_STORAGE_CW_DIMENSION) : this->channelDimension.SetName(INDIVIDUAL_CW_DIMENSION); + this->channelDimension.SetValue(pConfig->channelName.value); + + this->isStorage ? this->labelDimension.SetName(AGGREGATE_STORAGE_CW_DIMENSION) : this->labelDimension.SetName(AGGREGATE_CW_DIMENSION); + this->labelDimension.SetValue(pConfig->label.value); + CleanUp: + + LEAVES(); + return retStatus; + } + + static const CHAR* unitToString(const Aws::CloudWatch::Model::StandardUnit& unit) + { + switch (unit) { + case Aws::CloudWatch::Model::StandardUnit::Count: + return "Count"; + case Aws::CloudWatch::Model::StandardUnit::Count_Second: + return "Count_Second"; + case Aws::CloudWatch::Model::StandardUnit::Milliseconds: + return "Milliseconds"; + case Aws::CloudWatch::Model::StandardUnit::Percent: + return "Percent"; + case Aws::CloudWatch::Model::StandardUnit::None: + return "None"; + case Aws::CloudWatch::Model::StandardUnit::Kilobits_Second: + return "Kilobits_Second"; + default: + return "Unknown unit"; + } + } + + CloudwatchMetricsMonitoring& CloudwatchMetricsMonitoring::getInstance() + { + return getInstanceImpl(); + } + + CloudwatchMetricsMonitoring& CloudwatchMetricsMonitoring::getInstanceImpl(CppInteg::PConfig pConfig, ClientConfiguration* pClientConfig) + { + static CloudwatchMetricsMonitoring instance{pConfig, pClientConfig}; + return instance; + } + + VOID CloudwatchMetricsMonitoring::deinit() + { + auto& instance = getInstance(); + while (this->pendingMetrics.load() > 0) { + THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_MILLISECOND * 500); + } + } + + VOID CloudwatchMetricsMonitoring::push(const MetricDatum& datum) + { + Aws::CloudWatch::Model::PutMetricDataRequest cwRequest; + MetricDatum single = datum; + MetricDatum aggregated = datum; + + single.AddDimensions(this->channelDimension); + single.AddDimensions(this->labelDimension); + + cwRequest.SetNamespace(DEFAULT_CLOUDWATCH_NAMESPACE); + cwRequest.AddMetricData(single); + + + auto asyncHandler = [this](const Aws::CloudWatch::CloudWatchClient* cwClient, const Aws::CloudWatch::Model::PutMetricDataRequest& request, + const Aws::CloudWatch::Model::PutMetricDataOutcome& outcome, + const std::shared_ptr& context) { + UNUSED_PARAM(cwClient); + UNUSED_PARAM(request); + UNUSED_PARAM(context); + + if (!outcome.IsSuccess()) { + DLOGE("Failed to put sample metric data: %s", outcome.GetError().GetMessage().c_str()); + } else { + DLOGS("Successfully put sample metric data"); + } + this->pendingMetrics--; + }; + this->pendingMetrics++; + this->client.PutMetricDataAsync(cwRequest, asyncHandler); + + std::stringstream ss; + + ss << "Emitted the following metric:\n\n"; + ss << " Name : " << datum.GetMetricName() << '\n'; + ss << " Unit : " << unitToString(datum.GetUnit()) << '\n'; + + ss << " Values : "; + auto& values = datum.GetValues(); + // If the datum uses single value, GetValues will be empty and the data will be accessible + // from GetValue + if (values.empty()) { + ss << datum.GetValue(); + } else { + for (auto i = 0; i < values.size(); i++) { + ss << values[i]; + if (i != values.size() - 1) { + ss << ", "; + } + } + } + ss << '\n'; + + ss << " Dimensions : "; + auto& dimensions = datum.GetDimensions(); + if (dimensions.empty()) { + ss << "N/A"; + } else { + ss << '\n'; + for (auto& dimension : dimensions) { + ss << " - " << dimension.GetName() << "\t: " << dimension.GetValue() << '\n'; + } + } + ss << '\n'; + + DLOGI("%s", ss.str().c_str()); + } + + VOID CloudwatchMetricsMonitoring::pushOutboundRtpStats(POutgoingRTPMetricsContext pOutboundRtpStats) + { + DLOGI("HEre"); + MetricDatum bytesDiscardedPercentageDatum, averageFramesRateDatum, nackRateDatum, retransmissionPercentDatum; + + bytesDiscardedPercentageDatum.SetMetricName("PercentageFrameDiscarded"); + bytesDiscardedPercentageDatum.SetValue(pOutboundRtpStats->framesPercentageDiscarded); + bytesDiscardedPercentageDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Percent); + this->push(bytesDiscardedPercentageDatum); + + averageFramesRateDatum.SetMetricName("FramesPerSecond"); + averageFramesRateDatum.SetValue(pOutboundRtpStats->averageFramesSentPerSecond); + averageFramesRateDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count_Second); + this->push(averageFramesRateDatum); + + nackRateDatum.SetMetricName("NackPerSecond"); + nackRateDatum.SetValue(pOutboundRtpStats->nacksPerSecond); + nackRateDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count_Second); + this->push(nackRateDatum); + + retransmissionPercentDatum.SetMetricName("PercentageFramesRetransmitted"); + retransmissionPercentDatum.SetValue(pOutboundRtpStats->retxBytesPercentage); + retransmissionPercentDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Percent); + this->push(retransmissionPercentDatum); + } + + VOID CloudwatchMetricsMonitoring::pushInboundRtpStats(PIncomingRTPMetricsContext pIncomingRtpStats) + { + MetricDatum incomingBitrateDatum, incomingPacketRate, incomingFrameDropRateDatum; + + incomingBitrateDatum.SetMetricName("IncomingBitRate"); + incomingBitrateDatum.SetValue(pIncomingRtpStats->incomingBitRate); + incomingBitrateDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Kilobits_Second); + this->push(incomingBitrateDatum); + + incomingPacketRate.SetMetricName("IncomingPacketsPerSecond"); + incomingPacketRate.SetValue(pIncomingRtpStats->packetReceiveRate); + incomingPacketRate.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count_Second); + this->push(incomingPacketRate); + + incomingFrameDropRateDatum.SetMetricName("IncomingFramesDroppedPerSecond"); + incomingFrameDropRateDatum.SetValue(pIncomingRtpStats->framesDroppedPerSecond); + incomingFrameDropRateDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count_Second); + this->push(incomingFrameDropRateDatum); + } + +} // namespace Canary diff --git a/aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.h b/aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.h new file mode 100644 index 0000000000..2cb1ede301 --- /dev/null +++ b/aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.h @@ -0,0 +1,27 @@ +#pragma once + +#include "Config.h" +#include "../samples/Samples.h" +namespace CppInteg { + + class CloudwatchMetricsMonitoring { + public: + CloudwatchMetricsMonitoring(CppInteg::PConfig, ClientConfiguration*); + STATUS init(CppInteg::PConfig); + VOID deinit(); + static CloudwatchMetricsMonitoring& getInstance(); + VOID pushOutboundRtpStats(POutgoingRTPMetricsContext pOutboundRtpStats); + VOID pushInboundRtpStats(PIncomingRTPMetricsContext pIncomingRtpStats); + + private: + static CloudwatchMetricsMonitoring& getInstanceImpl(CppInteg::PConfig = nullptr, ClientConfiguration* = nullptr); + Dimension channelDimension; + Dimension labelDimension; + PConfig pConfig; + VOID push(const MetricDatum&); + CloudWatchClient client; + std::atomic pendingMetrics; + BOOL isStorage; + }; + +} // namespace Canary diff --git a/aws-cpp-sdk-integ/Config.cpp b/aws-cpp-sdk-integ/Config.cpp new file mode 100644 index 0000000000..4b9cb6e3f4 --- /dev/null +++ b/aws-cpp-sdk-integ/Config.cpp @@ -0,0 +1,274 @@ +#include "Config.h" + +namespace CppInteg { + + STATUS Config::init(INT32 argc, PCHAR argv[]) + { + // TODO: Probably also support command line args to fill the config + STATUS retStatus = STATUS_SUCCESS; + + CHK(argv != NULL, STATUS_NULL_ARG); + CHK_STATUS(initWithEnvVars()); + + // Need to impose a min duration + if (duration.value != 0 && duration.value < CANARY_MIN_DURATION) { + DLOGW("Canary duration should be at least %u seconds. Overriding with minimal duration.", + CANARY_MIN_DURATION / HUNDREDS_OF_NANOS_IN_A_SECOND); + duration.value = CANARY_MIN_DURATION; + } + + // Need to impose a min iteration duration + if (iterationDuration.value < CANARY_MIN_ITERATION_DURATION) { + DLOGW("Canary iterations duration should be at least %u seconds. Overriding with minimal iterations duration.", + CANARY_MIN_ITERATION_DURATION / HUNDREDS_OF_NANOS_IN_A_SECOND); + iterationDuration.value = CANARY_MIN_ITERATION_DURATION; + } + + CleanUp: + + return retStatus; + } + + BOOL strtobool(const CHAR* value) + { + if (STRCMPI(value, "on") == 0 || STRCMPI(value, "true") == 0) { + return TRUE; + } + + return FALSE; + } + + STATUS mustenv(CHAR const* pKey, Config::Value* pResult) + { + STATUS retStatus = STATUS_SUCCESS; + const CHAR* value; + + CHK(pResult != NULL, STATUS_NULL_ARG); + CHK(!pResult->initialized, retStatus); + + CHK_ERR((value = getenv(pKey)) != NULL, STATUS_INVALID_OPERATION, "%s must be set", pKey); + pResult->value = value; + pResult->initialized = TRUE; + + CleanUp: + + return retStatus; + } + + STATUS optenv(CHAR const* pKey, Config::Value* pResult, std::string defaultValue) + { + STATUS retStatus = STATUS_SUCCESS; + const CHAR* value; + + CHK(pResult != NULL, STATUS_NULL_ARG); + CHK(!pResult->initialized, retStatus); + + if (NULL != (value = getenv(pKey))) { + pResult->value = value; + } else { + pResult->value = defaultValue; + } + pResult->initialized = TRUE; + + CleanUp: + + return retStatus; + } + + STATUS mustenvBool(CHAR const* pKey, Config::Value* pResult) + { + STATUS retStatus = STATUS_SUCCESS; + Config::Value raw; + + CHK(pResult != NULL, STATUS_NULL_ARG); + CHK(!pResult->initialized, retStatus); + CHK_STATUS(mustenv(pKey, &raw)); + + pResult->value = strtobool(raw.value.c_str()); + pResult->initialized = TRUE; + + CleanUp: + + return retStatus; + } + + STATUS optenvBool(CHAR const* pKey, Config::Value* pResult, BOOL defVal) + { + STATUS retStatus = STATUS_SUCCESS; + Config::Value raw; + + CHK(pResult != NULL, STATUS_NULL_ARG); + CHK(!pResult->initialized, retStatus); + CHK_STATUS(optenv(pKey, &raw, "")); + if (!raw.value.empty()) { + pResult->value = strtobool(raw.value.c_str()); + } else { + pResult->value = defVal; + } + pResult->initialized = TRUE; + + CleanUp: + + return retStatus; + } + + STATUS mustenvUint64(CHAR const* pKey, Config::Value* pResult) + { + STATUS retStatus = STATUS_SUCCESS; + Config::Value raw; + + CHK(pResult != NULL, STATUS_NULL_ARG); + CHK(!pResult->initialized, retStatus); + CHK_STATUS(mustenv(pKey, &raw)); + + STRTOUI64((PCHAR) raw.value.c_str(), NULL, 10, &pResult->value); + pResult->initialized = TRUE; + + CleanUp: + + return retStatus; + } + + STATUS optenvUint64(CHAR const* pKey, Config::Value* pResult, UINT64 defVal) + { + STATUS retStatus = STATUS_SUCCESS; + Config::Value raw; + + CHK(pResult != NULL, STATUS_NULL_ARG); + CHK(!pResult->initialized, retStatus); + CHK_STATUS(optenv(pKey, &raw, "")); + if (!raw.value.empty()) { + STRTOUI64((PCHAR) raw.value.c_str(), NULL, 10, &pResult->value); + } else { + pResult->value = defVal; + } + pResult->initialized = TRUE; + + CleanUp: + + return retStatus; + } + + STATUS Config::initWithEnvVars() + { + STATUS retStatus = STATUS_SUCCESS; + Config::Value logLevel64; + std::stringstream defaultLogStreamName; + UINT64 fileSize; + + /* This is ignored for master. Master can extract the info from offer. Viewer has to know if peer can trickle or + * not ahead of time. */ + CHK_STATUS(optenvBool(CANARY_TRICKLE_ICE_ENV_VAR, &trickleIce, TRUE)); + CHK_STATUS(optenvBool(CANARY_USE_TURN_ENV_VAR, &useTurn, TRUE)); + CHK_STATUS(optenvBool(CANARY_FORCE_TURN_ENV_VAR, &forceTurn, FALSE)); + CHK_STATUS(optenvBool(CANARY_USE_IOT_CREDENTIALS_ENV_VAR, &useIotCredentialProvider, FALSE)); + CHK_STATUS(optenvBool(CANARY_RUN_IN_PROFILING_MODE_ENV_VAR, &isProfilingMode, FALSE)); + + CHK_STATUS(optenv(CANARY_VIDEO_CODEC_ENV_VAR, &videoCodec, CANARY_VIDEO_CODEC_H264)); + CHK_STATUS(optenv(CACERT_PATH_ENV_VAR, &caCertPath, KVS_CA_CERT_PATH)); + + if(useIotCredentialProvider.value == TRUE) { + CHK_STATUS(mustenv(IOT_CORE_CREDENTIAL_ENDPOINT_ENV_VAR, &iotCoreCredentialEndPointFile)); + CHK_STATUS(readFile((PCHAR)iotCoreCredentialEndPointFile.value.c_str(), TRUE, NULL, &fileSize)); + CHK_ERR(fileSize != 0, STATUS_WEBRTC_EMPTY_IOT_CRED_FILE, "Empty credential file"); + CHK_STATUS(readFile((PCHAR)iotCoreCredentialEndPointFile.value.c_str(), TRUE, iotEndpoint, &fileSize)); + iotEndpoint[fileSize - 1] = '\0'; + CHK_STATUS(mustenv(IOT_CORE_CERT_ENV_VAR, &iotCoreCert)); + CHK_STATUS(mustenv(IOT_CORE_PRIVATE_KEY_ENV_VAR, &iotCorePrivateKey)); + CHK_STATUS(mustenv(IOT_CORE_ROLE_ALIAS_ENV_VAR, &iotCoreRoleAlias)); + CHK_STATUS(mustenv(IOT_CORE_THING_NAME_ENV_VAR, &channelName)); + } + else { + CHK_STATUS(mustenv(ACCESS_KEY_ENV_VAR, &accessKey)); + CHK_STATUS(mustenv(SECRET_KEY_ENV_VAR, &secretKey)); + CHK_STATUS(optenv(CANARY_CHANNEL_NAME_ENV_VAR, &channelName, CANARY_DEFAULT_CHANNEL_NAME)); + } + CHK_STATUS(optenv(SESSION_TOKEN_ENV_VAR, &sessionToken, "")); + CHK_STATUS(optenv(DEFAULT_REGION_ENV_VAR, ®ion, DEFAULT_AWS_REGION)); + + // Set the logger log level + if (!logLevel.initialized) { + CHK_STATUS(optenvUint64(DEBUG_LOG_LEVEL_ENV_VAR, &logLevel64, LOG_LEVEL_WARN)); + logLevel.value = (UINT32) logLevel64.value; + logLevel.initialized = TRUE; + } + + CHK_STATUS(optenv(CANARY_ENDPOINT_ENV_VAR, &endpoint, "")); + CHK_STATUS(optenv(CANARY_LABEL_ENV_VAR, &label, CANARY_DEFAULT_LABEL)); + + CHK_STATUS(optenv(CANARY_CLIENT_ID_ENV_VAR, &clientId, CANARY_DEFAULT_CLIENT_ID)); + CHK_STATUS(optenvBool(CANARY_IS_MASTER_ENV_VAR, &isMaster, TRUE)); + CHK_STATUS(optenvBool(CANARY_RUN_BOTH_PEERS_ENV_VAR, &runBothPeers, FALSE)); + + CHK_STATUS(optenv(CANARY_LOG_GROUP_NAME_ENV_VAR, &this->logGroupName, CANARY_DEFAULT_LOG_GROUP_NAME)); + defaultLogStreamName << channelName.value << '-' << (isMaster.value ? "master" : "viewer") << '-' + << GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + CHK_STATUS(optenv(CANARY_LOG_STREAM_NAME_ENV_VAR, &this->logStreamName, defaultLogStreamName.str())); + + if (!duration.initialized) { + CHK_STATUS(optenvUint64(CANARY_DURATION_IN_SECONDS_ENV_VAR, &duration, 0)); + duration.value *= HUNDREDS_OF_NANOS_IN_A_SECOND; + } + + // Iteration duration is an optional param + if (!iterationDuration.initialized) { + CHK_STATUS(optenvUint64(CANARY_ITERATION_IN_SECONDS_ENV_VAR, &iterationDuration, CANARY_DEFAULT_ITERATION_DURATION_IN_SECONDS)); + iterationDuration.value *= HUNDREDS_OF_NANOS_IN_A_SECOND; + } + + CHK_STATUS(optenvUint64(CANARY_BIT_RATE_ENV_VAR, &bitRate, CANARY_DEFAULT_BITRATE)); + CHK_STATUS(optenvUint64(CANARY_FRAME_RATE_ENV_VAR, &frameRate, CANARY_DEFAULT_FRAMERATE)); + + if (this->isStorage) { + CHK_STATUS(optenv(STORAGE_CANARY_FIRST_FRAME_TS_FILE_ENV_VAR, &storageFristFrameSentTSFileName, STORAGE_CANARY_DEFAULT_FIRST_FRAME_TS_FILE)); + } + + CleanUp: + + return retStatus; + } + + VOID Config::print() + { + DLOGD("Applied configuration:\n\n" + "\tEndpoint : %s\n" + "\tRegion : %s\n" + "\tLabel : %s\n" + "\tChannel Name : %s\n" + "\tClient ID : %s\n" + "\tRole : %s\n" + "\tTrickle ICE : %s\n" + "\tUse TURN : %s\n" + "\tLog Level : %u\n" + "\tLog Group : %s\n" + "\tLog Stream : %s\n" + "\tDuration : %lu seconds\n" + "\tVideo codec : %s\n" + "\tIteration : %lu seconds\n" + "\tRun both peers : %s\n" + "\tCredential type : %s\n" + "\tStorage : %s\n" + "\n", + this->endpoint.value.c_str(), this->region.value.c_str(), this->label.value.c_str(), this->channelName.value.c_str(), + this->clientId.value.c_str(), this->isMaster.value ? "Master" : "Viewer", this->trickleIce.value ? "True" : "False", + this->useTurn.value ? "True" : "False", this->logLevel.value, this->logGroupName.value.c_str(), this->logStreamName.value.c_str(), + this->duration.value / HUNDREDS_OF_NANOS_IN_A_SECOND, this->videoCodec.value.c_str(), this->iterationDuration.value / HUNDREDS_OF_NANOS_IN_A_SECOND, + this->runBothPeers.value ? "True" : "False", this->useIotCredentialProvider.value ? "IoT" : "Static", this->isStorage ? "True" : "False"); + if(this->useIotCredentialProvider.value) { + DLOGD("\tIoT endpoint : %s\n" + "\tIoT cert filename : %s\n" + "\tIoT private key filename : %s\n" + "\tIoT role alias : %s\n", + (PCHAR) this->iotEndpoint, + this->iotCoreCert.value.c_str(), + this->iotCorePrivateKey.value.c_str(), + this->iotCoreRoleAlias.value.c_str()); + } + if(this->isStorage) { + DLOGD("\n\n\tFirstFrameSentTSFileName : %s\n", + this->storageFristFrameSentTSFileName.value.c_str() + ); + } + } + +} // namespace Cloudwatch diff --git a/aws-cpp-sdk-integ/Config.h b/aws-cpp-sdk-integ/Config.h new file mode 100644 index 0000000000..a9fdc01836 --- /dev/null +++ b/aws-cpp-sdk-integ/Config.h @@ -0,0 +1,66 @@ +#pragma once +#include "../samples/Samples.h" +#include "Include.h" +#include + +namespace CppInteg { + + class Config; + typedef Config* PConfig; + + class Config { + public: + STATUS init(INT32 argc, PCHAR argv[]); + template class Value { + public: + T value; + BOOL initialized = FALSE; + }; + + Value endpoint; + Value label; + Value channelName; + Value clientId; + Value videoCodec; + Value isMaster; + Value runBothPeers; + Value trickleIce; + Value useTurn; + Value forceTurn; + Value useIotCredentialProvider; + Value isProfilingMode; + + BOOL isStorage; + + // credentials + Value accessKey; + Value secretKey; + Value sessionToken; + Value region; + Value iotCoreCredentialEndPointFile; + Value iotCoreCert; + Value iotCorePrivateKey; + Value iotCoreRoleAlias; + + // logging + Value logLevel; + Value logGroupName; + Value logStreamName; + + Value duration; + Value iterationDuration; + Value bitRate; + Value frameRate; + + Value caCertPath; + Value storageFristFrameSentTSFileName; + + BYTE iotEndpoint[MAX_CONFIG_JSON_FILE_SIZE]; + + VOID print(); + + private: + STATUS initWithEnvVars(); + }; + +} // namespace Canary diff --git a/aws-cpp-sdk-integ/Include.h b/aws-cpp-sdk-integ/Include.h new file mode 100644 index 0000000000..580b1fe6e4 --- /dev/null +++ b/aws-cpp-sdk-integ/Include.h @@ -0,0 +1,133 @@ +#pragma once + +#define DEFAULT_CLOUDWATCH_NAMESPACE "KinesisVideoSDKWebRTC" +#define DEFAULT_FPS_VALUE 25 +// TODO: This value shouldn't matter. But, since we don't allow NULL value, we have to set to a value +#define DEFAULT_VIEWER_PEER_ID "ConsumerViewer" +#define DEFAULT_FILE_LOGGING_BUFFER_SIZE (200 * 1024) + +#define MAX_CLOUDWATCH_LOG_COUNT 128 +#define MAX_CONCURRENT_CONNECTIONS 10 +#define MAX_TURN_SERVERS 1 +#define MAX_STATUS_CODE_LENGTH 16 +#define MAX_CONFIG_JSON_TOKENS 128 +#define MAX_CONFIG_JSON_VALUE_SIZE 256 +#define MAX_CONFIG_JSON_FILE_SIZE 1024 +#define MAX_CONTROL_PLANE_URI_CHAR_LEN 256 +#define MAX_UINT64_DIGIT_COUNT 20 + +#define NUMBER_OF_H264_FRAME_FILES 1500 +#define NUMBER_OF_OPUS_FRAME_FILES 618 +#define SAMPLE_VIDEO_FRAME_DURATION (HUNDREDS_OF_NANOS_IN_A_SECOND / DEFAULT_FPS_VALUE) +#define SAMPLE_AUDIO_FRAME_DURATION (20 * HUNDREDS_OF_NANOS_IN_A_MILLISECOND) + +#define ASYNC_ICE_CONFIG_INFO_WAIT_TIMEOUT (3 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define ICE_CONFIG_INFO_POLL_PERIOD (20 * HUNDREDS_OF_NANOS_IN_A_MILLISECOND) + +#define CA_CERT_PEM_FILE_EXTENSION ".pem" +#define SIGNALING_CANARY_MASTER_CLIENT_ID "CANARY_MASTER" +#define SIGNALING_CANARY_VIEWER_CLIENT_ID "CANARY_VIEWER" +#define SIGNALING_CANARY_START_DELAY (100 * HUNDREDS_OF_NANOS_IN_A_MILLISECOND) +#define SIGNALING_CANARY_MIN_SESSION_PERIOD (20 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define SIGNALING_CANARY_OFFER "Signaling canary offer" +#define SIGNALING_CANARY_ANSWER "Signaling canary answer" +#define SIGNALING_CANARY_ROUNDTRIP_TIMEOUT (10 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define SIGNALING_CANARY_CHANNEL_NAME (PCHAR) "ScaryTestChannel_" +#define SIGNALING_CANARY_MAX_CONSECUTIVE_ITERATION_FAILURE_COUNT 5 + +#define CANARY_METADATA_SIZE (SIZEOF(UINT64) + SIZEOF(UINT32) + SIZEOF(UINT32)) +#define ANNEX_B_NALU_SIZE 4 + +#define CANARY_DEFAULT_FRAMERATE 30 +#define CANARY_DEFAULT_BITRATE (250 * 1024) + +#define CANARY_DEFAULT_ITERATION_DURATION_IN_SECONDS 30 + +#define CANARY_DEFAULT_VIEWER_INIT_DELAY (5 * HUNDREDS_OF_NANOS_IN_A_SECOND) + +#define CANARY_MIN_DURATION (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define CANARY_MIN_ITERATION_DURATION (15 * HUNDREDS_OF_NANOS_IN_A_SECOND) + +#define CANARY_ENDPOINT_ENV_VAR "CANARY_ENDPOINT" +#define CANARY_LABEL_ENV_VAR "CANARY_LABEL" +#define CANARY_CHANNEL_NAME_ENV_VAR "CANARY_CHANNEL_NAME" +#define CANARY_CLIENT_ID_ENV_VAR "CANARY_CLIENT_ID" +#define CANARY_TRICKLE_ICE_ENV_VAR "CANARY_TRICKLE_ICE" +#define CANARY_IS_MASTER_ENV_VAR "CANARY_IS_MASTER" +#define CANARY_USE_TURN_ENV_VAR "CANARY_USE_TURN" +#define CANARY_LOG_GROUP_NAME_ENV_VAR "CANARY_LOG_GROUP_NAME" +#define CANARY_LOG_STREAM_NAME_ENV_VAR "CANARY_LOG_STREAM_NAME" +#define CANARY_CERT_PATH_ENV_VAR "CANARY_CERT_PATH" +#define CANARY_DURATION_IN_SECONDS_ENV_VAR "CANARY_DURATION_IN_SECONDS" +#define CANARY_VIDEO_CODEC_ENV_VAR "CANARY_VIDEO_CODEC" +#define CANARY_ITERATION_IN_SECONDS_ENV_VAR "CANARY_ITERATION_IN_SECONDS" +#define CANARY_FORCE_TURN_ENV_VAR "CANARY_FORCE_TURN" +#define CANARY_BIT_RATE_ENV_VAR "CANARY_DATARATE_IN_BITS_PER_SECOND" +#define CANARY_FRAME_RATE_ENV_VAR "CANARY_FRAME_RATE" +#define CANARY_RUN_BOTH_PEERS_ENV_VAR "CANARY_RUN_BOTH_PEERS" +#define CANARY_USE_IOT_CREDENTIALS_ENV_VAR "CANARY_USE_IOT_PROVIDER" +#define CANARY_RUN_IN_PROFILING_MODE_ENV_VAR "CANARY_IS_PROFILING_MODE" +#define IOT_CORE_CREDENTIAL_ENDPOINT_ENV_VAR "AWS_IOT_CORE_CREDENTIAL_ENDPOINT" +#define IOT_CORE_CERT_ENV_VAR "AWS_IOT_CORE_CERT" +#define IOT_CORE_PRIVATE_KEY_ENV_VAR "AWS_IOT_CORE_PRIVATE_KEY" +#define IOT_CORE_ROLE_ALIAS_ENV_VAR "AWS_IOT_CORE_ROLE_ALIAS" +#define IOT_CORE_THING_NAME_ENV_VAR "AWS_IOT_CORE_THING_NAME" +#define STORAGE_CANARY_FIRST_FRAME_TS_FILE_ENV_VAR "STORAGE_CANARY_FIRST_FRAME_TS_FILE" + +#define CANARY_DEFAULT_LABEL "ScaryTestLabel" +#define CANARY_DEFAULT_CHANNEL_NAME "ScaryTestStream" +#define CANARY_VIDEO_CODEC_H264 "h264" +#define CANARY_VIDEO_CODEC_H265 "h265" +#define CANARY_DEFAULT_CLIENT_ID "DefaultClientId" +#define CANARY_DEFAULT_LOG_GROUP_NAME "DefaultLogGroupName" +#define CANARY_DEFAULT_LOG_GROUP_NAME "DefaultLogGroupName" +#define FIRST_FRAME_TS_FILE_PATH "../" +#define STORAGE_CANARY_DEFAULT_FIRST_FRAME_TS_FILE "DefaultFirstFrameSentTSFileName.txt" + +#define INDIVIDUAL_STORAGE_CW_DIMENSION "StorageWebRTCSDKCanaryChannelName" +#define INDIVIDUAL_CW_DIMENSION "WebRTCSDKCanaryChannelName" +#define AGGREGATE_STORAGE_CW_DIMENSION "StorageWebRTCSDKCanaryLabel" +#define AGGREGATE_CW_DIMENSION "WebRTCSDKCanaryLabel" + +// Signaling Canary error definitions +#define STATUS_SIGNALING_CANARY_BASE 0x73000000 +#define STATUS_SIGNALING_CANARY_UNEXPECTED_MESSAGE STATUS_SIGNALING_CANARY_BASE + 0x00000001 +#define STATUS_SIGNALING_CANARY_ANSWER_CID_MISMATCH STATUS_SIGNALING_CANARY_BASE + 0x00000002 +#define STATUS_SIGNALING_CANARY_OFFER_CID_MISMATCH STATUS_SIGNALING_CANARY_BASE + 0x00000003 +#define STATUS_SIGNALING_CANARY_ANSWER_PAYLOAD_MISMATCH STATUS_SIGNALING_CANARY_BASE + 0x00000004 +#define STATUS_SIGNALING_CANARY_OFFER_PAYLOAD_MISMATCH STATUS_SIGNALING_CANARY_BASE + 0x00000005 + +#define STATUS_WEBRTC_CANARY_BASE 0x74000000 +#define STATUS_WEBRTC_EMPTY_IOT_CRED_FILE STATUS_WEBRTC_CANARY_BASE + 0x00000001 +#define STATUS_WAITING_ON_FIRST_FRAME STATUS_WEBRTC_CANARY_BASE + 0x00000002 + +#define CANARY_VIDEO_FRAMES_PATH (PCHAR) "./assets/h264SampleFrames/frame-%04d.h264" +#define CANARY_AUDIO_FRAMES_PATH (PCHAR) "./assets/opusSampleFrames/sample-%03d.opus" + +#define METRICS_INVOCATION_PERIOD (60 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define END_TO_END_METRICS_INVOCATION_PERIOD (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define KVS_METRICS_INVOCATION_PERIOD (5 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define CANARY_METADATA_SIZE (SIZEOF(UINT64) + SIZEOF(UINT32) + SIZEOF(UINT32)) + +#define MAX_CALL_RETRY_COUNT 10 + +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +using namespace Aws::Client; +using namespace Aws::CloudWatchLogs; +using namespace Aws::CloudWatchLogs::Model; +using namespace Aws::CloudWatch::Model; +using namespace Aws::CloudWatch; +using namespace std; diff --git a/samples/kvsWebRTCClientMasterCloudwatch.c b/aws-cpp-sdk-integ/kvsWebRTCClientMasterCloudwatch.cpp similarity index 56% rename from samples/kvsWebRTCClientMasterCloudwatch.c rename to aws-cpp-sdk-integ/kvsWebRTCClientMasterCloudwatch.cpp index 7fcfa0625f..7275e9d9fc 100644 --- a/samples/kvsWebRTCClientMasterCloudwatch.c +++ b/aws-cpp-sdk-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -1,48 +1,27 @@ -#include "Samples.h" -#include "c_wrapper.h" -//#include -//#include -//#include -//#include -//#include -//#include -//#include -//#include - -extern PSampleConfiguration gSampleConfiguration; +#include +#include "../samples/Samples.h" +#include "Config.h" +#include "CloudwatchMetricsMonitoring.h" -INT32 main(INT32 argc, CHAR* argv[]) +STATUS publishStatsForCanary(RTC_STATS_TYPE statsType, PSampleStreamingSession pSampleStreamingSession) { STATUS retStatus = STATUS_SUCCESS; - - aws_sdk_init(); - -CleanUp: - - retStatus = RESET_INSTRUMENTED_ALLOCATORS(); - DLOGI("All SDK allocations freed? %s..0x%08x", retStatus == STATUS_SUCCESS ? "Yes" : "No", retStatus); - // https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html - // We can only return with 0 - 127. Some platforms treat exit code >= 128 - // to be a success code, which might give an unintended behaviour. - // Some platforms also treat 1 or 0 differently, so it's better to use - // EXIT_FAILURE and EXIT_SUCCESS macros for portability. - return STATUS_FAILED(retStatus) ? EXIT_FAILURE : EXIT_SUCCESS; -} - -STATUS readFrameFromDisk(PBYTE pFrame, PUINT32 pSize, PCHAR frameFilePath) -{ - STATUS retStatus = STATUS_SUCCESS; - UINT64 size = 0; - CHK_ERR(pSize != NULL, STATUS_NULL_ARG, "[KVS Master] Invalid file size"); - size = *pSize; - // Get the size and read into frame - CHK_STATUS(readFile(frameFilePath, TRUE, pFrame, &size)); - CleanUp: - - if (pSize != NULL) { - *pSize = (UINT32) size; + pSampleStreamingSession->canaryMetrics.requestedTypeOfStats = statsType; + switch (statsType) { + case RTC_STATS_TYPE_OUTBOUND_RTP: + CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->canaryMetrics)); + populateOutgoingRtpMetricsContext(pSampleStreamingSession); + CppInteg::CloudwatchMetricsMonitoring::getInstance().pushOutboundRtpStats(&pSampleStreamingSession->canaryOutgoingRTPMetricsContext); + break; + case RTC_STATS_TYPE_INBOUND_RTP: + CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->canaryMetrics)); + populateIncomingRtpMetricsContext(pSampleStreamingSession); + CppInteg::CloudwatchMetricsMonitoring::getInstance().pushInboundRtpStats(&pSampleStreamingSession->canaryIncomingRTPMetricsContext); + break; + default: + CHK(FALSE, STATUS_NOT_IMPLEMENTED); } - + CleanUp: return retStatus; } @@ -90,6 +69,8 @@ PVOID sendVideoPackets(PVOID args) MUTEX_LOCK(pSampleConfiguration->streamingSessionListReadLock); for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { status = writeFrame(pSampleConfiguration->sampleStreamingSessionList[i]->pVideoRtcRtpTransceiver, &frame); + pSampleConfiguration->sampleStreamingSessionList[i]->canaryOutgoingRTPMetricsContext.videoFramesGenerated++; + pSampleConfiguration->sampleStreamingSessionList[i]->canaryOutgoingRTPMetricsContext.videoBytesGenerated += frame.size; if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { PROFILE_WITH_START_TIME(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, "Time to first frame"); pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame = FALSE; @@ -104,6 +85,7 @@ PVOID sendVideoPackets(PVOID args) // Reset file index to ensure first frame sent upon SRTP ready is a key frame. fileIndex = 0; } + publishStatsForCanary(RTC_STATS_TYPE_OUTBOUND_RTP, pSampleConfiguration->sampleStreamingSessionList[i]); } MUTEX_UNLOCK(pSampleConfiguration->streamingSessionListReadLock); @@ -180,16 +162,122 @@ PVOID sendAudioPackets(PVOID args) return (PVOID) (ULONG_PTR) retStatus; } +VOID sampleVideoFrameHandlerCW(UINT64 customData, PFrame pFrame) +{ + PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; + publishStatsForCanary(RTC_STATS_TYPE_INBOUND_RTP, pSampleStreamingSession); +} + PVOID sampleReceiveAudioVideoFrame(PVOID args) { STATUS retStatus = STATUS_SUCCESS; PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) args; CHK_ERR(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); - CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pVideoRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleVideoFrameHandler)); - CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pAudioRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleAudioFrameHandler)); + CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pVideoRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleVideoFrameHandlerCW)); CleanUp: return (PVOID) (ULONG_PTR) retStatus; } +INT32 main(INT32 argc, CHAR* argv[]) +{ + STATUS retStatus = STATUS_SUCCESS; + UINT32 frameSize; + PSampleConfiguration pSampleConfiguration = NULL; + SignalingClientMetrics signalingClientMetrics; + auto config = CppInteg::Config(); + + Aws::SDKOptions options; + Aws::InitAPI(options); + { + SET_INSTRUMENTED_ALLOCATORS(); + // Initialize KVS WebRTC. This must be done before anything else, and must only be done once. + initKvsWebRtc(); + config.init(argc, argv); + + UINT32 logLevel = setLogLevel(); + createSampleConfiguration((PCHAR) config.channelName.value.c_str(), SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration); + + // Set the audio and video handlers + pSampleConfiguration->audioSource = sendAudioPackets; + pSampleConfiguration->videoSource = sendVideoPackets; + pSampleConfiguration->receiveAudioVideoSource = sampleReceiveAudioVideoFrame; + + if (argc > 2 && STRNCMP(argv[2], "1", 2) == 0) { + pSampleConfiguration->channelInfo.useMediaStorage = TRUE; + } + + ClientConfiguration clientConfig; + clientConfig.region = config.region.value; + CppInteg::CloudwatchMetricsMonitoring cwmonitoring(&config, &clientConfig); + cwmonitoring.init(&config); + +#ifdef ENABLE_DATA_CHANNEL + pSampleConfiguration->onDataChannel = onDataChannel; +#endif + pSampleConfiguration->mediaType = SAMPLE_STREAMING_AUDIO_VIDEO; + DLOGI("[KVS CW Master] Finished setting handlers"); + + // Check if the samples are present + + readFrameFromDisk(NULL, &frameSize, (PCHAR) "./h264SampleFrames/frame-0001.h264"); + DLOGI("[KVS Master] Checked sample video frame availability....available"); + + readFrameFromDisk(NULL, &frameSize, (PCHAR) "./opusSampleFrames/sample-001.opus"); + DLOGI("[KVS Master] Checked sample audio frame availability....available"); + + DLOGI("[KVS Master] KVS WebRTC initialization completed successfully"); + + PROFILE_CALL_WITH_START_END_T_OBJ( + retStatus = initSignaling(pSampleConfiguration, (PCHAR) SAMPLE_MASTER_CLIENT_ID), pSampleConfiguration->signalingClientMetrics.signalingStartTime, + pSampleConfiguration->signalingClientMetrics.signalingEndTime, pSampleConfiguration->signalingClientMetrics.signalingCallTime, + "Initialize signaling client and connect to the signaling channel"); + + DLOGI("[KVS Master] Channel %s set up done ", (PCHAR) config.channelName.value.c_str()); + + // Checking for termination + sessionCleanupWait(pSampleConfiguration); + DLOGI("[KVS Master] Streaming session terminated"); + } + if (retStatus != STATUS_SUCCESS) { + DLOGE("[KVS Master] Terminated with status code 0x%08x", retStatus); + } + + DLOGI("[KVS Master] Cleaning up...."); + if (pSampleConfiguration != NULL) { + // Kick of the termination sequence + ATOMIC_STORE_BOOL(&pSampleConfiguration->appTerminateFlag, TRUE); + + if (pSampleConfiguration->mediaSenderTid != INVALID_TID_VALUE) { + THREAD_JOIN(pSampleConfiguration->mediaSenderTid, NULL); + } + + retStatus = signalingClientGetMetrics(pSampleConfiguration->signalingClientHandle, &signalingClientMetrics); + if (retStatus == STATUS_SUCCESS) { + logSignalingClientStats(&signalingClientMetrics); + } else { + DLOGE("[KVS Master] signalingClientGetMetrics() operation returned status code: 0x%08x", retStatus); + } + retStatus = freeSignalingClient(&pSampleConfiguration->signalingClientHandle); + if (retStatus != STATUS_SUCCESS) { + DLOGE("[KVS Master] freeSignalingClient(): operation returned status code: 0x%08x", retStatus); + } + + retStatus = freeSampleConfiguration(&pSampleConfiguration); + if (retStatus != STATUS_SUCCESS) { + DLOGE("[KVS Master] freeSampleConfiguration(): operation returned status code: 0x%08x", retStatus); + } + } + DLOGI("[KVS Master] Cleanup done"); + CHK_LOG_ERR(retStatus); + + retStatus = RESET_INSTRUMENTED_ALLOCATORS(); + DLOGI("All SDK allocations freed? %s..0x%08x", retStatus == STATUS_SUCCESS ? "Yes" : "No", retStatus); + // https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html + // We can only return with 0 - 127. Some platforms treat exit code >= 128 + // to be a success code, which might give an unintended behaviour. + // Some platforms also treat 1 or 0 differently, so it's better to use + // EXIT_FAILURE and EXIT_SUCCESS macros for portability. + return STATUS_FAILED(retStatus) ? EXIT_FAILURE : EXIT_SUCCESS; +} \ No newline at end of file diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index b1532ab2ca..076565d192 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -1,11 +1,6 @@ cmake_minimum_required(VERSION 3.6.3) -project(KinesisVideoWebRTCClientSamples) - -set(CMAKE_CXX_STANDARD 11) # Adjust the version according to your needs - - -#set(OPEN_SRC_INSTALL_PREFIX "${CMAKE_CURRENT_SOURCE_DIR}/open-source" CACHE PATH "Libraries will be downloaded and build in this directory.") +project(KinesisVideoWebRTCClientSamples LANGUAGES C) message("OPEN_SRC_INSTALL_PREFIX=${OPEN_SRC_INSTALL_PREFIX}") @@ -52,6 +47,7 @@ endif() include_directories(${OPEN_SRC_INSTALL_PREFIX}/include) include_directories(${OPEN_SRC_INCLUDE_DIRS}) +include_directories(${CMAKE_CURRENT_SOURCE_DIR}) link_directories(${OPEN_SRC_INSTALL_PREFIX}/lib) # copy sample frames to this subproject build folder, in case developer runs sample program with command `kvsWebrtcClientMaster` from `build/samples` dir. @@ -63,14 +59,18 @@ file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/h265SampleFrames" DESTINATION .) add_executable( kvsWebrtcClientMaster Common.c + Utility.c + MetricsHandling.c kvsWebRTCClientMaster.c) -target_link_libraries(kvsWebrtcClientMaster kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} kvsCommonLws kvspicUtils websockets) +target_link_libraries(kvsWebrtcClientMaster kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} kvsCommonLws kvspicUtils) add_executable( kvsWebrtcClientViewer Common.c + Utility.c + MetricsHandling.c kvsWebRTCClientViewer.c) -target_link_libraries(kvsWebrtcClientViewer kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} kvsCommonLws kvspicUtils websockets) +target_link_libraries(kvsWebrtcClientViewer kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} kvsCommonLws kvspicUtils) add_executable( discoverNatBehavior @@ -81,6 +81,8 @@ if(GST_FOUND) add_executable( kvsWebrtcClientMasterGstSample Common.c + Utility.c + MetricsHandling.c GstAudioVideoReceiver.c kvsWebRTCClientMasterGstSample.c ) @@ -93,6 +95,8 @@ if(GST_FOUND) add_executable( kvsWebrtcClientViewerGstSample Common.c + Utility.c + MetricsHandling.c GstAudioVideoReceiver.c kvsWebRTCClientViewerGstSample.c ) diff --git a/samples/Common.c b/samples/Common.c index d512c4c559..8fa2b7eca0 100644 --- a/samples/Common.c +++ b/samples/Common.c @@ -1,5 +1,6 @@ #define LOG_CLASS "WebRtcSamples" #include "Samples.h" +#include SAMPLE_CONFIG_HEADER #define KVS_DEFAULT_MEDIA_SENDER_THREAD_STACK_SIZE 64 * 1024 #define KVS_MINIMUM_THREAD_STACK_SIZE 16 * 1024 @@ -15,18 +16,6 @@ VOID sigintHandler(INT32 sigNum) } } -UINT32 setLogLevel() -{ - PCHAR pLogLevel; - UINT32 logLevel = LOG_LEVEL_DEBUG; - if (NULL == (pLogLevel = GETENV(DEBUG_LOG_LEVEL_ENV_VAR)) || STATUS_SUCCESS != STRTOUI32(pLogLevel, NULL, 10, &logLevel) || - logLevel < LOG_LEVEL_VERBOSE || logLevel > LOG_LEVEL_SILENT) { - logLevel = LOG_LEVEL_WARN; - } - SET_LOGGER_LOG_LEVEL(logLevel); - return logLevel; -} - STATUS signalingCallFailed(STATUS status) { return (STATUS_SIGNALING_GET_TOKEN_CALL_FAILED == status || STATUS_SIGNALING_DESCRIBE_CALL_FAILED == status || @@ -108,35 +97,6 @@ STATUS signalingClientError(UINT64 customData, STATUS status, PCHAR msg, UINT32 return STATUS_SUCCESS; } -STATUS logSelectedIceCandidatesInformation(PSampleStreamingSession pSampleStreamingSession) -{ - ENTERS(); - STATUS retStatus = STATUS_SUCCESS; - RtcStats rtcMetrics; - - CHK(pSampleStreamingSession != NULL, STATUS_NULL_ARG); - rtcMetrics.requestedTypeOfStats = RTC_STATS_TYPE_LOCAL_CANDIDATE; - CHK_STATUS(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, NULL, &rtcMetrics)); - DLOGI("Local Candidate IP Address: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.address); - DLOGI("Local Candidate type: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.candidateType); - DLOGI("Local Candidate port: %d", rtcMetrics.rtcStatsObject.localIceCandidateStats.port); - DLOGI("Local Candidate priority: %d", rtcMetrics.rtcStatsObject.localIceCandidateStats.priority); - DLOGI("Local Candidate transport protocol: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.protocol); - DLOGI("Local Candidate relay protocol: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.relayProtocol); - DLOGI("Local Candidate Ice server source: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.url); - - rtcMetrics.requestedTypeOfStats = RTC_STATS_TYPE_REMOTE_CANDIDATE; - CHK_STATUS(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, NULL, &rtcMetrics)); - DLOGI("Remote Candidate IP Address: %s", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.address); - DLOGI("Remote Candidate type: %s", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.candidateType); - DLOGI("Remote Candidate port: %d", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.port); - DLOGI("Remote Candidate priority: %d", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.priority); - DLOGI("Remote Candidate transport protocol: %s", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.protocol); -CleanUp: - LEAVES(); - return retStatus; -} - STATUS handleAnswer(PSampleConfiguration pSampleConfiguration, PSampleStreamingSession pSampleStreamingSession, PSignalingMessage pSignalingMessage) { UNUSED_PARAM(pSampleConfiguration); @@ -418,7 +378,12 @@ STATUS initializePeerConnection(PSampleConfiguration pSampleConfiguration, PRtcP DLOGI("TWCC is : %s", configuration.kvsRtcConfiguration.disableSenderSideBandwidthEstimation ? "Disabled" : "Enabled"); // Set the ICE mode explicitly - configuration.iceTransportPolicy = ICE_TRANSPORT_POLICY_ALL; + + if (FORCE_TURN_ONLY) { + configuration.iceTransportPolicy = ICE_TRANSPORT_POLICY_RELAY; + } else { + configuration.iceTransportPolicy = ICE_TRANSPORT_POLICY_ALL; + } configuration.kvsRtcConfiguration.enableIceStats = pSampleConfiguration->enableIceStats; // Set the STUN server @@ -564,12 +529,13 @@ 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)); + + if (ENABLE_DATA_CHANNEL) { + if (pSampleConfiguration->onDataChannel != NULL) { + CHK_STATUS(peerConnectionOnDataChannel(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, + pSampleConfiguration->onDataChannel)); + } } -#endif CHK_STATUS(addSupportedCodec(pSampleStreamingSession->pPeerConnection, pSampleConfiguration->videoCodec)); CHK_STATUS(addSupportedCodec(pSampleStreamingSession->pPeerConnection, pSampleConfiguration->audioCodec)); @@ -850,30 +816,27 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE STATUS retStatus = STATUS_SUCCESS; PCHAR pAccessKey, pSecretKey, pSessionToken; PSampleConfiguration pSampleConfiguration = NULL; + PCHAR pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pIotCoreRoleAlias, pIotCoreCertificateId, pIotCoreThingName; CHK(ppSampleConfiguration != NULL, STATUS_NULL_ARG); CHK(NULL != (pSampleConfiguration = (PSampleConfiguration) MEMCALLOC(1, SIZEOF(SampleConfiguration))), STATUS_NOT_ENOUGH_MEMORY); - -#ifdef IOT_CORE_ENABLE_CREDENTIALS - PCHAR pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pIotCoreRoleAlias, pIotCoreCertificateId, pIotCoreThingName; - CHK_ERR((pIotCoreCredentialEndPoint = GETENV(IOT_CORE_CREDENTIAL_ENDPOINT)) != NULL, STATUS_INVALID_OPERATION, - "AWS_IOT_CORE_CREDENTIAL_ENDPOINT must be set"); - CHK_ERR((pIotCoreCert = GETENV(IOT_CORE_CERT)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_CERT must be set"); - CHK_ERR((pIotCorePrivateKey = GETENV(IOT_CORE_PRIVATE_KEY)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_PRIVATE_KEY must be set"); - CHK_ERR((pIotCoreRoleAlias = GETENV(IOT_CORE_ROLE_ALIAS)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_ROLE_ALIAS must be set"); - CHK_ERR((pIotCoreThingName = GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set"); -#else - CHK_ERR((pAccessKey = GETENV(ACCESS_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_ACCESS_KEY_ID must be set"); - CHK_ERR((pSecretKey = GETENV(SECRET_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_SECRET_ACCESS_KEY must be set"); -#endif - + if (IOT_CORE_ENABLE_CREDENTIALS) { + CHK_ERR((pIotCoreCredentialEndPoint = GETENV(IOT_CORE_CREDENTIAL_ENDPOINT)) != NULL, STATUS_INVALID_OPERATION, + "AWS_IOT_CORE_CREDENTIAL_ENDPOINT must be set"); + CHK_ERR((pIotCoreCert = GETENV(IOT_CORE_CERT)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_CERT must be set"); + CHK_ERR((pIotCorePrivateKey = GETENV(IOT_CORE_PRIVATE_KEY)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_PRIVATE_KEY must be set"); + CHK_ERR((pIotCoreRoleAlias = GETENV(IOT_CORE_ROLE_ALIAS)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_ROLE_ALIAS must be set"); + CHK_ERR((pIotCoreThingName = GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set"); + } else { + CHK_ERR((pAccessKey = GETENV(ACCESS_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_ACCESS_KEY_ID must be set"); + CHK_ERR((pSecretKey = GETENV(SECRET_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_SECRET_ACCESS_KEY must be set"); + } pSessionToken = GETENV(SESSION_TOKEN_ENV_VAR); if (pSessionToken != NULL && IS_EMPTY_STRING(pSessionToken)) { DLOGW("Session token is set but its value is empty. Ignoring."); pSessionToken = NULL; } - // If the env is set, we generate normal log files apart from filtered profile log files // If not set, we generate only the filtered profile log files if (NULL != GETENV(ENABLE_FILE_LOGGING)) { @@ -902,13 +865,13 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE CHK_STATUS(lookForSslCert(&pSampleConfiguration)); -#ifdef IOT_CORE_ENABLE_CREDENTIALS - CHK_STATUS(createLwsIotCredentialProvider(pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pSampleConfiguration->pCaCertPath, - pIotCoreRoleAlias, pIotCoreThingName, &pSampleConfiguration->pCredentialProvider)); -#else - CHK_STATUS( - createStaticCredentialProvider(pAccessKey, 0, pSecretKey, 0, pSessionToken, 0, MAX_UINT64, &pSampleConfiguration->pCredentialProvider)); -#endif + if (IOT_CORE_ENABLE_CREDENTIALS) { + CHK_STATUS(createLwsIotCredentialProvider(pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pSampleConfiguration->pCaCertPath, + pIotCoreRoleAlias, pIotCoreThingName, &pSampleConfiguration->pCredentialProvider)); + } else { + CHK_STATUS( + createStaticCredentialProvider(pAccessKey, 0, pSecretKey, 0, pSessionToken, 0, MAX_UINT64, &pSampleConfiguration->pCredentialProvider)); + } pSampleConfiguration->mediaSenderTid = INVALID_TID_VALUE; pSampleConfiguration->audioSenderTid = INVALID_TID_VALUE; @@ -918,20 +881,23 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE pSampleConfiguration->cvar = CVAR_CREATE(); pSampleConfiguration->streamingSessionListReadLock = MUTEX_CREATE(FALSE); pSampleConfiguration->signalingSendMessageLock = MUTEX_CREATE(FALSE); + /* This is ignored for master. Master can extract the info from offer. Viewer has to know if peer can trickle or * not ahead of time. */ - pSampleConfiguration->trickleIce = trickleIce; - pSampleConfiguration->useTurn = useTurn; - pSampleConfiguration->enableSendingMetricsToViewerViaDc = FALSE; + + pSampleConfiguration->trickleIce = USE_TRICKLE_ICE; + pSampleConfiguration->useTurn = USE_TURN; + pSampleConfiguration->enableSendingMetricsToViewerViaDc = ENABLE_TTFF_VIA_DC; pSampleConfiguration->receiveAudioVideoSource = NULL; pSampleConfiguration->channelInfo.version = CHANNEL_INFO_CURRENT_VERSION; - pSampleConfiguration->channelInfo.pChannelName = channelName; -#ifdef IOT_CORE_ENABLE_CREDENTIALS - if ((pIotCoreCertificateId = GETENV(IOT_CORE_CERTIFICATE_ID)) != NULL) { - pSampleConfiguration->channelInfo.pChannelName = pIotCoreCertificateId; + pSampleConfiguration->channelInfo.pChannelName = CHANNEL_NAME; + if (IOT_CORE_ENABLE_CREDENTIALS) { + if ((pIotCoreCertificateId = GETENV(IOT_CORE_CERTIFICATE_ID)) != NULL) { + pSampleConfiguration->channelInfo.pChannelName = pIotCoreCertificateId; + } } -#endif + pSampleConfiguration->channelInfo.pKmsKeyId = NULL; pSampleConfiguration->channelInfo.tagCount = 0; pSampleConfiguration->channelInfo.pTags = NULL; @@ -944,6 +910,7 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE pSampleConfiguration->channelInfo.reconnect = TRUE; pSampleConfiguration->channelInfo.pCertPath = pSampleConfiguration->pCaCertPath; pSampleConfiguration->channelInfo.messageTtl = 0; // Default is 60 seconds + pSampleConfiguration->channelInfo.useMediaStorage = ENABLE_STORAGE; pSampleConfiguration->signalingClientCallbacks.version = SIGNALING_CLIENT_CALLBACKS_CURRENT_VERSION; pSampleConfiguration->signalingClientCallbacks.errorReportFn = signalingClientError; @@ -1013,9 +980,9 @@ STATUS initSignaling(PSampleConfiguration pSampleConfiguration, PCHAR clientId) // Enable the processing of the messages CHK_STATUS(signalingClientFetchSync(pSampleConfiguration->signalingClientHandle)); -#ifdef ENABLE_DATA_CHANNEL - pSampleConfiguration->onDataChannel = onDataChannel; -#endif + if (ENABLE_DATA_CHANNEL) { + pSampleConfiguration->onDataChannel = onDataChannel; + } CHK_STATUS(signalingClientConnectSync(pSampleConfiguration->signalingClientHandle)); @@ -1064,109 +1031,6 @@ STATUS logSignalingClientStats(PSignalingClientMetrics pSignalingClientMetrics) return retStatus; } -STATUS getIceCandidatePairStatsCallback(UINT32 timerId, UINT64 currentTime, UINT64 customData) -{ - UNUSED_PARAM(timerId); - UNUSED_PARAM(currentTime); - STATUS retStatus = STATUS_SUCCESS; - PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; - UINT32 i; - UINT64 currentMeasureDuration = 0; - DOUBLE averagePacketsDiscardedOnSend = 0.0; - DOUBLE averageNumberOfPacketsSentPerSecond = 0.0; - DOUBLE averageNumberOfPacketsReceivedPerSecond = 0.0; - DOUBLE outgoingBitrate = 0.0; - DOUBLE incomingBitrate = 0.0; - BOOL locked = FALSE; - - CHK_WARN(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] getPeriodicStats(): Passed argument is NULL"); - - pSampleConfiguration->rtcIceCandidatePairMetrics.requestedTypeOfStats = RTC_STATS_TYPE_CANDIDATE_PAIR; - - // Use MUTEX_TRYLOCK to avoid possible dead lock when canceling timerQueue - if (!MUTEX_TRYLOCK(pSampleConfiguration->sampleConfigurationObjLock)) { - return retStatus; - } else { - locked = TRUE; - } - - for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { - if (STATUS_SUCCEEDED(rtcPeerConnectionGetMetrics(pSampleConfiguration->sampleStreamingSessionList[i]->pPeerConnection, NULL, - &pSampleConfiguration->rtcIceCandidatePairMetrics))) { - currentMeasureDuration = (pSampleConfiguration->rtcIceCandidatePairMetrics.timestamp - - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevTs) / - HUNDREDS_OF_NANOS_IN_A_SECOND; - DLOGD("Current duration: %" PRIu64 " seconds", currentMeasureDuration); - if (currentMeasureDuration > 0) { - DLOGD("Selected local candidate ID: %s", - pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.localCandidateId); - DLOGD("Selected remote candidate ID: %s", - pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.remoteCandidateId); - // TODO: Display state as a string for readability - DLOGD("Ice Candidate Pair state: %d", pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.state); - DLOGD("Nomination state: %s", - pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.nominated ? "nominated" - : "not nominated"); - averageNumberOfPacketsSentPerSecond = - (DOUBLE) (pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsSent - - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfPacketsSent) / - (DOUBLE) currentMeasureDuration; - DLOGD("Packet send rate: %lf pkts/sec", averageNumberOfPacketsSentPerSecond); - - averageNumberOfPacketsReceivedPerSecond = - (DOUBLE) (pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsReceived - - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfPacketsReceived) / - (DOUBLE) currentMeasureDuration; - DLOGD("Packet receive rate: %lf pkts/sec", averageNumberOfPacketsReceivedPerSecond); - - outgoingBitrate = (DOUBLE) ((pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.bytesSent - - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfBytesSent) * - 8.0) / - currentMeasureDuration; - DLOGD("Outgoing bit rate: %lf bps", outgoingBitrate); - - incomingBitrate = (DOUBLE) ((pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.bytesReceived - - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfBytesReceived) * - 8.0) / - currentMeasureDuration; - DLOGD("Incoming bit rate: %lf bps", incomingBitrate); - - averagePacketsDiscardedOnSend = - (DOUBLE) (pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsDiscardedOnSend - - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevPacketsDiscardedOnSend) / - (DOUBLE) currentMeasureDuration; - DLOGD("Packet discard rate: %lf pkts/sec", averagePacketsDiscardedOnSend); - - DLOGD("Current STUN request round trip time: %lf sec", - pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.currentRoundTripTime); - DLOGD("Number of STUN responses received: %llu", - pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.responsesReceived); - - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevTs = - pSampleConfiguration->rtcIceCandidatePairMetrics.timestamp; - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfPacketsSent = - pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsSent; - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfPacketsReceived = - pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsReceived; - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfBytesSent = - pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.bytesSent; - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfBytesReceived = - pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.bytesReceived; - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevPacketsDiscardedOnSend = - pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsDiscardedOnSend; - } - } - } - -CleanUp: - - if (locked) { - MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); - } - - return retStatus; -} - STATUS pregenerateCertTimerCallback(UINT32 timerId, UINT64 currentTime, UINT64 customData) { UNUSED_PARAM(timerId); @@ -1312,11 +1176,11 @@ STATUS freeSampleConfiguration(PSampleConfiguration* ppSampleConfiguration) CVAR_FREE(pSampleConfiguration->cvar); } -#ifdef IOT_CORE_ENABLE_CREDENTIALS - freeIotCredentialProvider(&pSampleConfiguration->pCredentialProvider); -#else - freeStaticCredentialProvider(&pSampleConfiguration->pCredentialProvider); -#endif + if (IOT_CORE_ENABLE_CREDENTIALS) { + freeIotCredentialProvider(&pSampleConfiguration->pCredentialProvider); + } else { + freeStaticCredentialProvider(&pSampleConfiguration->pCredentialProvider); + } if (pSampleConfiguration->pregeneratedCertificates != NULL) { stackQueueGetIterator(pSampleConfiguration->pregeneratedCertificates, &iterator); @@ -1751,7 +1615,6 @@ 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; @@ -1927,4 +1790,3 @@ VOID onDataChannel(UINT64 customData, PRtcDataChannel pRtcDataChannel) DLOGI("New DataChannel has been opened %s \n", pRtcDataChannel->name); dataChannelOnMessage(pRtcDataChannel, customData, onDataChannelMessage); } -#endif diff --git a/aws-sdk-integ/CloudwatchMetrics.c b/samples/Media.c similarity index 100% rename from aws-sdk-integ/CloudwatchMetrics.c rename to samples/Media.c diff --git a/samples/MetricsHandling.c b/samples/MetricsHandling.c new file mode 100644 index 0000000000..0fbe491c59 --- /dev/null +++ b/samples/MetricsHandling.c @@ -0,0 +1,203 @@ +#include "Samples.h" + +STATUS logSelectedIceCandidatesInformation(PSampleStreamingSession pSampleStreamingSession) +{ + ENTERS(); + STATUS retStatus = STATUS_SUCCESS; + RtcStats rtcMetrics; + + CHK(pSampleStreamingSession != NULL, STATUS_NULL_ARG); + rtcMetrics.requestedTypeOfStats = RTC_STATS_TYPE_LOCAL_CANDIDATE; + CHK_STATUS(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, NULL, &rtcMetrics)); + DLOGI("Local Candidate IP Address: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.address); + DLOGI("Local Candidate type: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.candidateType); + DLOGI("Local Candidate port: %d", rtcMetrics.rtcStatsObject.localIceCandidateStats.port); + DLOGI("Local Candidate priority: %d", rtcMetrics.rtcStatsObject.localIceCandidateStats.priority); + DLOGI("Local Candidate transport protocol: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.protocol); + DLOGI("Local Candidate relay protocol: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.relayProtocol); + DLOGI("Local Candidate Ice server source: %s", rtcMetrics.rtcStatsObject.localIceCandidateStats.url); + + rtcMetrics.requestedTypeOfStats = RTC_STATS_TYPE_REMOTE_CANDIDATE; + CHK_STATUS(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, NULL, &rtcMetrics)); + DLOGI("Remote Candidate IP Address: %s", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.address); + DLOGI("Remote Candidate type: %s", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.candidateType); + DLOGI("Remote Candidate port: %d", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.port); + DLOGI("Remote Candidate priority: %d", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.priority); + DLOGI("Remote Candidate transport protocol: %s", rtcMetrics.rtcStatsObject.remoteIceCandidateStats.protocol); +CleanUp: + LEAVES(); + return retStatus; +} + +STATUS getIceCandidatePairStatsCallback(UINT32 timerId, UINT64 currentTime, UINT64 customData) +{ + UNUSED_PARAM(timerId); + UNUSED_PARAM(currentTime); + STATUS retStatus = STATUS_SUCCESS; + PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; + UINT32 i; + UINT64 currentMeasureDuration = 0; + DOUBLE averagePacketsDiscardedOnSend = 0.0; + DOUBLE averageNumberOfPacketsSentPerSecond = 0.0; + DOUBLE averageNumberOfPacketsReceivedPerSecond = 0.0; + DOUBLE outgoingBitrate = 0.0; + DOUBLE incomingBitrate = 0.0; + BOOL locked = FALSE; + + CHK_WARN(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] getPeriodicStats(): Passed argument is NULL"); + + pSampleConfiguration->rtcIceCandidatePairMetrics.requestedTypeOfStats = RTC_STATS_TYPE_CANDIDATE_PAIR; + + // Use MUTEX_TRYLOCK to avoid possible dead lock when canceling timerQueue + if (!MUTEX_TRYLOCK(pSampleConfiguration->sampleConfigurationObjLock)) { + return retStatus; + } else { + locked = TRUE; + } + + for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { + if (STATUS_SUCCEEDED(rtcPeerConnectionGetMetrics(pSampleConfiguration->sampleStreamingSessionList[i]->pPeerConnection, NULL, + &pSampleConfiguration->rtcIceCandidatePairMetrics))) { + currentMeasureDuration = (pSampleConfiguration->rtcIceCandidatePairMetrics.timestamp - + pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevTs) / + HUNDREDS_OF_NANOS_IN_A_SECOND; + DLOGD("Current duration: %" PRIu64 " seconds", currentMeasureDuration); + if (currentMeasureDuration > 0) { + DLOGD("Selected local candidate ID: %s", + pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.localCandidateId); + DLOGD("Selected remote candidate ID: %s", + pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.remoteCandidateId); + // TODO: Display state as a string for readability + DLOGD("Ice Candidate Pair state: %d", pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.state); + DLOGD("Nomination state: %s", + pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.nominated ? "nominated" + : "not nominated"); + averageNumberOfPacketsSentPerSecond = + (DOUBLE) (pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsSent - + pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfPacketsSent) / + (DOUBLE) currentMeasureDuration; + DLOGD("Packet send rate: %lf pkts/sec", averageNumberOfPacketsSentPerSecond); + + averageNumberOfPacketsReceivedPerSecond = + (DOUBLE) (pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsReceived - + pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfPacketsReceived) / + (DOUBLE) currentMeasureDuration; + DLOGD("Packet receive rate: %lf pkts/sec", averageNumberOfPacketsReceivedPerSecond); + + outgoingBitrate = (DOUBLE) ((pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.bytesSent - + pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfBytesSent) * + 8.0) / + currentMeasureDuration; + DLOGD("Outgoing bit rate: %lf bps", outgoingBitrate); + + incomingBitrate = (DOUBLE) ((pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.bytesReceived - + pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfBytesReceived) * + 8.0) / + currentMeasureDuration; + DLOGD("Incoming bit rate: %lf bps", incomingBitrate); + + averagePacketsDiscardedOnSend = + (DOUBLE) (pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsDiscardedOnSend - + pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevPacketsDiscardedOnSend) / + (DOUBLE) currentMeasureDuration; + DLOGD("Packet discard rate: %lf pkts/sec", averagePacketsDiscardedOnSend); + + DLOGD("Current STUN request round trip time: %lf sec", + pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.currentRoundTripTime); + DLOGD("Number of STUN responses received: %llu", + pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.responsesReceived); + + pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevTs = + pSampleConfiguration->rtcIceCandidatePairMetrics.timestamp; + pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfPacketsSent = + pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsSent; + pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfPacketsReceived = + pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsReceived; + pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfBytesSent = + pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.bytesSent; + pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfBytesReceived = + pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.bytesReceived; + pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevPacketsDiscardedOnSend = + pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsDiscardedOnSend; + } + } + } + +CleanUp: + + if (locked) { + MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); + } + + return retStatus; +} + +STATUS populateOutgoingRtpMetricsContext(PSampleStreamingSession pSampleStreamingSession) +{ + DOUBLE currentDuration = 0; + + currentDuration = (DOUBLE) (pSampleStreamingSession->canaryMetrics.timestamp - pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevTs) / + HUNDREDS_OF_NANOS_IN_A_SECOND; + pSampleStreamingSession->canaryOutgoingRTPMetricsContext.framesPercentageDiscarded = + ((DOUBLE) (pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.framesDiscardedOnSend - + pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevFramesDiscardedOnSend) / + (DOUBLE) pSampleStreamingSession->canaryOutgoingRTPMetricsContext.videoFramesGenerated) * + 100.0; + pSampleStreamingSession->canaryOutgoingRTPMetricsContext.retxBytesPercentage = + (((DOUBLE) pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.retransmittedBytesSent - + (DOUBLE) (pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevRetxBytesSent)) / + (DOUBLE) pSampleStreamingSession->canaryOutgoingRTPMetricsContext.videoBytesGenerated) * + 100.0; + + // This flag ensures the reset of video bytes count is done only when this flag is set + pSampleStreamingSession->recorded = TRUE; + pSampleStreamingSession->canaryOutgoingRTPMetricsContext.averageFramesSentPerSecond = + ((DOUBLE) (pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.framesSent - + (DOUBLE) pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevFramesSent)) / + currentDuration; + pSampleStreamingSession->canaryOutgoingRTPMetricsContext.nacksPerSecond = + ((DOUBLE) pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.nackCount - + pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevNackCount) / + currentDuration; + pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevFramesSent = + pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.framesSent; + pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevTs = pSampleStreamingSession->canaryMetrics.timestamp; + pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevFramesDiscardedOnSend = + pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.framesDiscardedOnSend; + pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevNackCount = + pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.nackCount; + pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevRetxBytesSent = + pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.retransmittedBytesSent; + + return STATUS_SUCCESS; +} + +STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamingSession) +{ + DOUBLE currentDuration = 0; + currentDuration = (DOUBLE) (pSampleStreamingSession->canaryMetrics.timestamp - pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevTs) / + HUNDREDS_OF_NANOS_IN_A_SECOND; + pSampleStreamingSession->canaryIncomingRTPMetricsContext.packetReceiveRate = + (DOUBLE) (pSampleStreamingSession->canaryMetrics.rtcStatsObject.inboundRtpStreamStats.received.packetsReceived - + pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevPacketsReceived) / + currentDuration; + pSampleStreamingSession->canaryIncomingRTPMetricsContext.incomingBitRate = + ((DOUBLE) (pSampleStreamingSession->canaryMetrics.rtcStatsObject.inboundRtpStreamStats.bytesReceived - + pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevBytesReceived) / + currentDuration) / + 0.008; + pSampleStreamingSession->canaryIncomingRTPMetricsContext.framesDroppedPerSecond = + ((DOUBLE) pSampleStreamingSession->canaryMetrics.rtcStatsObject.inboundRtpStreamStats.received.framesDropped - + pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevFramesDropped) / + currentDuration; + + pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevPacketsReceived = + pSampleStreamingSession->canaryMetrics.rtcStatsObject.inboundRtpStreamStats.received.packetsReceived; + pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevBytesReceived = + pSampleStreamingSession->canaryMetrics.rtcStatsObject.inboundRtpStreamStats.bytesReceived; + pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevFramesDropped = + pSampleStreamingSession->canaryMetrics.rtcStatsObject.inboundRtpStreamStats.received.framesDropped; + pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevTs = pSampleStreamingSession->canaryMetrics.timestamp; + + return STATUS_SUCCESS; +} \ No newline at end of file diff --git a/samples/Samples.h b/samples/Samples.h index 4726269f95..eda9304a9a 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -12,6 +12,9 @@ extern "C" { #include +#define STRINGIZE(x) #x +#define INCLUDE_CONFIG(header) STRINGIZE(header) + #define NUMBER_OF_H264_FRAME_FILES 1500 #define NUMBER_OF_H265_FRAME_FILES 1500 #define NUMBER_OF_OPUS_FRAME_FILES 618 @@ -212,6 +215,7 @@ typedef struct { typedef VOID (*StreamSessionShutdownCallback)(UINT64, PSampleStreamingSession); typedef struct { +<<<<<<< HEAD MUTEX updateLock; UINT64 lastAdjustmentTimeMs; UINT64 currentVideoBitrate; @@ -220,6 +224,36 @@ typedef struct { UINT64 newAudioBitrate; DOUBLE averagePacketLoss; } TwccMetadata, *PTwccMetadata; +======= + UINT64 prevNumberOfPacketsSent; + UINT64 prevNumberOfPacketsReceived; + UINT64 prevNumberOfBytesSent; + UINT64 prevNumberOfBytesReceived; + UINT64 prevFramesDiscardedOnSend; + UINT64 prevTs; + UINT64 prevVideoFramesGenerated; + UINT64 prevFramesSent; + UINT64 prevNackCount; + UINT64 prevRetxBytesSent; + UINT64 videoFramesGenerated; + UINT64 videoBytesGenerated; + DOUBLE framesPercentageDiscarded; + DOUBLE nacksPerSecond; + DOUBLE averageFramesSentPerSecond; + DOUBLE retxBytesPercentage; +} OutgoingRTPMetricsContext, *POutgoingRTPMetricsContext; + +typedef struct { + UINT64 prevPacketsReceived; + UINT64 prevTs; + UINT64 prevBytesReceived; + UINT64 prevFramesDropped; + DOUBLE packetReceiveRate; + DOUBLE incomingBitRate; + DOUBLE framesDroppedPerSecond; +} IncomingRTPMetricsContext; +typedef IncomingRTPMetricsContext* PIncomingRTPMetricsContext; +>>>>>>> e33503d182 (Initial commit:rtp stats, config file) struct __SampleStreamingSession { volatile ATOMIC_BOOL terminateFlag; @@ -251,6 +285,10 @@ struct __SampleStreamingSession { CHAR pPeerConnectionMetricsMessage[MAX_PEER_CONNECTION_METRICS_MESSAGE_SIZE]; CHAR pSignalingClientMetricsMessage[MAX_SIGNALING_CLIENT_METRICS_MESSAGE_SIZE]; CHAR pIceAgentMetricsMessage[MAX_ICE_AGENT_METRICS_MESSAGE_SIZE]; + OutgoingRTPMetricsContext canaryOutgoingRTPMetricsContext; + IncomingRTPMetricsContext canaryIncomingRTPMetricsContext; + RtcStats canaryMetrics; + BOOL recorded; }; // TODO this should all be in a higher webrtccontext layer above PeerConnection @@ -262,6 +300,10 @@ typedef struct { } AsyncGetIceStruct; +typedef struct { + UINT64 customData; +} MetricsHookFunc, *PMetricsHookFunc; + VOID sigintHandler(INT32); STATUS readFrameFromDisk(PBYTE, PUINT32, PCHAR); PVOID receiveGstreamerAudioVideo(PVOID); @@ -269,7 +311,6 @@ PVOID sendVideoPackets(PVOID); PVOID sendAudioPackets(PVOID); PVOID sendGstreamerAudioVideo(PVOID); PVOID sampleReceiveAudioVideoFrame(PVOID); -PVOID getPeriodicIceCandidatePairStats(PVOID); STATUS getIceCandidatePairStatsCallback(UINT32, UINT64, UINT64); STATUS pregenerateCertTimerCallback(UINT32, UINT64, UINT64); STATUS createSampleConfiguration(PCHAR, SIGNALING_CHANNEL_ROLE_TYPE, BOOL, BOOL, UINT32, PSampleConfiguration*); @@ -307,6 +348,9 @@ STATUS initSignaling(PSampleConfiguration, PCHAR); BOOL sampleFilterNetworkInterfaces(UINT64, PCHAR); UINT32 setLogLevel(); +STATUS populateOutgoingRtpMetricsContext(PSampleStreamingSession pSampleStreamingSession); +STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamingSession); + #ifdef __cplusplus } #endif diff --git a/samples/Utility.c b/samples/Utility.c new file mode 100644 index 0000000000..12d6f7fc13 --- /dev/null +++ b/samples/Utility.c @@ -0,0 +1,30 @@ +#include "Samples.h" + +STATUS readFrameFromDisk(PBYTE pFrame, PUINT32 pSize, PCHAR frameFilePath) +{ + STATUS retStatus = STATUS_SUCCESS; + UINT64 size = 0; + CHK_ERR(pSize != NULL, STATUS_NULL_ARG, "[KVS Master] Invalid file size"); + size = *pSize; + // Get the size and read into frame + CHK_STATUS(readFile(frameFilePath, TRUE, pFrame, &size)); +CleanUp: + + if (pSize != NULL) { + *pSize = (UINT32) size; + } + + return retStatus; +} + +UINT32 setLogLevel() +{ + PCHAR pLogLevel; + UINT32 logLevel = LOG_LEVEL_DEBUG; + if (NULL == (pLogLevel = GETENV(DEBUG_LOG_LEVEL_ENV_VAR)) || STATUS_SUCCESS != STRTOUI32(pLogLevel, NULL, 10, &logLevel) || + logLevel < LOG_LEVEL_VERBOSE || logLevel > LOG_LEVEL_SILENT) { + logLevel = LOG_LEVEL_WARN; + } + SET_LOGGER_LOG_LEVEL(logLevel); + return logLevel; +} \ No newline at end of file diff --git a/samples/c_wrapper.cpp b/samples/c_wrapper.cpp deleted file mode 100644 index 68756468fd..0000000000 --- a/samples/c_wrapper.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include "c_wrapper.h" - -extern "C" { -AwsSdkHandle aws_sdk_init() { - Aws::SDKOptions options; - Aws::InitAPI(options); - // Return some handle or pointer to indicate success - return NULL; -} -} diff --git a/samples/c_wrapper.h b/samples/c_wrapper.h deleted file mode 100644 index a655bac11c..0000000000 --- a/samples/c_wrapper.h +++ /dev/null @@ -1,14 +0,0 @@ -#ifdef __cplusplus -extern "C" { -#endif - -// Declare C-compatible interface -typedef void* AwsSdkHandle; - -AwsSdkHandle aws_sdk_init(); -void aws_sdk_cleanup(AwsSdkHandle handle); -void aws_sdk_some_operation(AwsSdkHandle handle); - -#ifdef __cplusplus -} -#endif diff --git a/samples/config_default.h b/samples/config_default.h new file mode 100644 index 0000000000..ccaac69612 --- /dev/null +++ b/samples/config_default.h @@ -0,0 +1,8 @@ +// +// Created by Sampath Kumar, Divya on 5/7/24. +// + +#ifndef KVS_SDK_CONFIG_DEFAULT_H +#define KVS_SDK_CONFIG_DEFAULT_H + +#endif // KVS_SDK_CONFIG_DEFAULT_H diff --git a/samples/kvsMetricsMonitoring.c b/samples/kvsMetricsMonitoring.c index 4fbfe96b3a..fbfaf96e2e 100644 --- a/samples/kvsMetricsMonitoring.c +++ b/samples/kvsMetricsMonitoring.c @@ -1,38 +1,28 @@ #include "Samples.h" -STATUS initMetricsModule(UINT64 metrics) { - if(metrics & ICE_CANDIDATE_PAIR_METRICS) { - +STATUS initMetricsModule(UINT64 metrics) +{ + if (metrics & ICE_CANDIDATE_PAIR_METRICS) { } - if(metrics & ICE_SERVER_METRICS) { - + if (metrics & ICE_SERVER_METRICS) { } - if(metrics & DATA_CHANNEL_METRICS) { - + if (metrics & DATA_CHANNEL_METRICS) { } - if(metrics & INBOUND_RTP_METRICS) { - + if (metrics & INBOUND_RTP_METRICS) { } - if(metrics & ICE_LOCAL_CANDIDATE_METRICS) { - + if (metrics & ICE_LOCAL_CANDIDATE_METRICS) { } - if(metrics & OUTBOUND_RTP_METRICS) { - + if (metrics & OUTBOUND_RTP_METRICS) { } - if(metrics & ICE_REMOTE_CANDIDATE_METRICS) { - + if (metrics & ICE_REMOTE_CANDIDATE_METRICS) { } - if(metrics & REMOTE_INBOUND_RTP_METRICS) { - + if (metrics & REMOTE_INBOUND_RTP_METRICS) { } - if(metrics & REMOTE_OUTBOUND_RTP_METRICS) { - + if (metrics & REMOTE_OUTBOUND_RTP_METRICS) { } - if(metrics & TRANSPORT_METRICS) { - + if (metrics & TRANSPORT_METRICS) { } - if(metrics & ALL_METRICS) { - + if (metrics & ALL_METRICS) { } return STATUS_SUCCESS; } \ No newline at end of file diff --git a/samples/kvsWebRTCClientMaster.c b/samples/kvsWebRTCClientMaster.c index 17411238a0..a1b06b0a8a 100644 --- a/samples/kvsWebRTCClientMaster.c +++ b/samples/kvsWebRTCClientMaster.c @@ -1,4 +1,4 @@ -#include "Samples.h" +#include "../samples/Samples.h" extern PSampleConfiguration gSampleConfiguration; @@ -20,13 +20,6 @@ INT32 main(INT32 argc, CHAR* argv[]) signal(SIGINT, sigintHandler); #endif -#ifdef IOT_CORE_ENABLE_CREDENTIALS - CHK_ERR((pChannelName = argc > 1 ? argv[1] : GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, - "AWS_IOT_CORE_THING_NAME must be set"); -#else - pChannelName = argc > 1 ? argv[1] : SAMPLE_CHANNEL_NAME; -#endif - CHK_STATUS(createSampleConfiguration(pChannelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration)); if (argc > 3) { @@ -139,23 +132,6 @@ INT32 main(INT32 argc, CHAR* argv[]) return STATUS_FAILED(retStatus) ? EXIT_FAILURE : EXIT_SUCCESS; } -STATUS readFrameFromDisk(PBYTE pFrame, PUINT32 pSize, PCHAR frameFilePath) -{ - STATUS retStatus = STATUS_SUCCESS; - UINT64 size = 0; - CHK_ERR(pSize != NULL, STATUS_NULL_ARG, "[KVS Master] Invalid file size"); - size = *pSize; - // Get the size and read into frame - CHK_STATUS(readFile(frameFilePath, TRUE, pFrame, &size)); -CleanUp: - - if (pSize != NULL) { - *pSize = (UINT32) size; - } - - return retStatus; -} - PVOID sendVideoPackets(PVOID args) { STATUS retStatus = STATUS_SUCCESS; diff --git a/samples/sample_config.h b/samples/sample_config.h new file mode 100644 index 0000000000..358b85dfe8 --- /dev/null +++ b/samples/sample_config.h @@ -0,0 +1,11 @@ +#ifndef KVS_SDK_SAMPLE_CONFIG_H +#define KVS_SDK_SAMPLE_CONFIG_H + +#define USE_TRICKLE_ICE TRUE +#define FORCE_TURN_ONLY FALSE +#define CHANNEL_NAME (PCHAR) "test" +#define USE_TURN TRUE +#define ENABLE_TTFF_VIA_DC FALSE +#define IOT_CORE_ENABLE_CREDENTIALS FALSE +#define ENABLE_STORAGE FALSE +#endif // KVS_SDK_SAMPLE_CONFIG_H From b0e2d6047a8e8f7e005e866c49782a49780e9b3a Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 9 May 2024 15:52:20 -0700 Subject: [PATCH 04/64] Rename, include logs and metrics --- CMakeLists.txt | 2 +- .../CloudwatchMetricsMonitoring.cpp | 183 -------- .../CloudwatchMetricsMonitoring.h | 27 -- aws-cpp-sdk-integ/Config.cpp | 274 ----------- aws-cpp-sdk-integ/Config.h | 66 --- .../CMakeLists.txt | 6 +- cloudwatch-integ/Cloudwatch.cpp | 82 ++++ cloudwatch-integ/Cloudwatch.h | 31 ++ cloudwatch-integ/CloudwatchLogs.cpp | 116 +++++ cloudwatch-integ/CloudwatchLogs.h | 28 ++ cloudwatch-integ/CloudwatchMonitoring.cpp | 433 ++++++++++++++++++ cloudwatch-integ/CloudwatchMonitoring.h | 37 ++ .../Include.h | 0 cloudwatch-integ/config_periodic.h | 12 + .../kvsWebRTCClientMasterCloudwatch.cpp | 24 +- samples/Common.c | 26 +- samples/MetricsHandling.c | 48 +- samples/Samples.h | 23 +- samples/config_default.h | 4 - samples/kvsMetricsMonitoring.c | 28 -- samples/sample_config.h | 4 + 21 files changed, 799 insertions(+), 655 deletions(-) delete mode 100644 aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.cpp delete mode 100644 aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.h delete mode 100644 aws-cpp-sdk-integ/Config.cpp delete mode 100644 aws-cpp-sdk-integ/Config.h rename {aws-cpp-sdk-integ => cloudwatch-integ}/CMakeLists.txt (90%) create mode 100644 cloudwatch-integ/Cloudwatch.cpp create mode 100644 cloudwatch-integ/Cloudwatch.h create mode 100644 cloudwatch-integ/CloudwatchLogs.cpp create mode 100644 cloudwatch-integ/CloudwatchLogs.h create mode 100644 cloudwatch-integ/CloudwatchMonitoring.cpp create mode 100644 cloudwatch-integ/CloudwatchMonitoring.h rename {aws-cpp-sdk-integ => cloudwatch-integ}/Include.h (100%) create mode 100644 cloudwatch-integ/config_periodic.h rename {aws-cpp-sdk-integ => cloudwatch-integ}/kvsWebRTCClientMasterCloudwatch.cpp (93%) delete mode 100644 samples/kvsMetricsMonitoring.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 8eb43dc366..81ee123f51 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -493,7 +493,7 @@ if (BUILD_SAMPLE) add_subdirectory(samples) endif() -add_subdirectory(aws-cpp-sdk-integ) +add_subdirectory(cloudwatch-integ) if(BUILD_TEST) # adding ZLIB because aws sdk static link seems to be broken when zlib is needed diff --git a/aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.cpp b/aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.cpp deleted file mode 100644 index 48dc133d54..0000000000 --- a/aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.cpp +++ /dev/null @@ -1,183 +0,0 @@ -#include "Include.h" -#include "Config.h" -#include "CloudwatchMetricsMonitoring.h" - -namespace CppInteg { - CloudwatchMetricsMonitoring::CloudwatchMetricsMonitoring(PConfig pConfig, ClientConfiguration* pClientConfig) : pConfig(pConfig), client(*pClientConfig) - { - pConfig->isStorage ? this->isStorage = true : this->isStorage = false; - } - - STATUS CloudwatchMetricsMonitoring::init(CppInteg::PConfig pConfig) - { - ENTERS(); - STATUS retStatus = STATUS_SUCCESS; - ClientConfiguration clientConfig; - - clientConfig.region = pConfig->region.value; - auto& instance = getInstanceImpl(pConfig, &clientConfig); - - this->isStorage ? this->channelDimension.SetName(INDIVIDUAL_STORAGE_CW_DIMENSION) : this->channelDimension.SetName(INDIVIDUAL_CW_DIMENSION); - this->channelDimension.SetValue(pConfig->channelName.value); - - this->isStorage ? this->labelDimension.SetName(AGGREGATE_STORAGE_CW_DIMENSION) : this->labelDimension.SetName(AGGREGATE_CW_DIMENSION); - this->labelDimension.SetValue(pConfig->label.value); - CleanUp: - - LEAVES(); - return retStatus; - } - - static const CHAR* unitToString(const Aws::CloudWatch::Model::StandardUnit& unit) - { - switch (unit) { - case Aws::CloudWatch::Model::StandardUnit::Count: - return "Count"; - case Aws::CloudWatch::Model::StandardUnit::Count_Second: - return "Count_Second"; - case Aws::CloudWatch::Model::StandardUnit::Milliseconds: - return "Milliseconds"; - case Aws::CloudWatch::Model::StandardUnit::Percent: - return "Percent"; - case Aws::CloudWatch::Model::StandardUnit::None: - return "None"; - case Aws::CloudWatch::Model::StandardUnit::Kilobits_Second: - return "Kilobits_Second"; - default: - return "Unknown unit"; - } - } - - CloudwatchMetricsMonitoring& CloudwatchMetricsMonitoring::getInstance() - { - return getInstanceImpl(); - } - - CloudwatchMetricsMonitoring& CloudwatchMetricsMonitoring::getInstanceImpl(CppInteg::PConfig pConfig, ClientConfiguration* pClientConfig) - { - static CloudwatchMetricsMonitoring instance{pConfig, pClientConfig}; - return instance; - } - - VOID CloudwatchMetricsMonitoring::deinit() - { - auto& instance = getInstance(); - while (this->pendingMetrics.load() > 0) { - THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_MILLISECOND * 500); - } - } - - VOID CloudwatchMetricsMonitoring::push(const MetricDatum& datum) - { - Aws::CloudWatch::Model::PutMetricDataRequest cwRequest; - MetricDatum single = datum; - MetricDatum aggregated = datum; - - single.AddDimensions(this->channelDimension); - single.AddDimensions(this->labelDimension); - - cwRequest.SetNamespace(DEFAULT_CLOUDWATCH_NAMESPACE); - cwRequest.AddMetricData(single); - - - auto asyncHandler = [this](const Aws::CloudWatch::CloudWatchClient* cwClient, const Aws::CloudWatch::Model::PutMetricDataRequest& request, - const Aws::CloudWatch::Model::PutMetricDataOutcome& outcome, - const std::shared_ptr& context) { - UNUSED_PARAM(cwClient); - UNUSED_PARAM(request); - UNUSED_PARAM(context); - - if (!outcome.IsSuccess()) { - DLOGE("Failed to put sample metric data: %s", outcome.GetError().GetMessage().c_str()); - } else { - DLOGS("Successfully put sample metric data"); - } - this->pendingMetrics--; - }; - this->pendingMetrics++; - this->client.PutMetricDataAsync(cwRequest, asyncHandler); - - std::stringstream ss; - - ss << "Emitted the following metric:\n\n"; - ss << " Name : " << datum.GetMetricName() << '\n'; - ss << " Unit : " << unitToString(datum.GetUnit()) << '\n'; - - ss << " Values : "; - auto& values = datum.GetValues(); - // If the datum uses single value, GetValues will be empty and the data will be accessible - // from GetValue - if (values.empty()) { - ss << datum.GetValue(); - } else { - for (auto i = 0; i < values.size(); i++) { - ss << values[i]; - if (i != values.size() - 1) { - ss << ", "; - } - } - } - ss << '\n'; - - ss << " Dimensions : "; - auto& dimensions = datum.GetDimensions(); - if (dimensions.empty()) { - ss << "N/A"; - } else { - ss << '\n'; - for (auto& dimension : dimensions) { - ss << " - " << dimension.GetName() << "\t: " << dimension.GetValue() << '\n'; - } - } - ss << '\n'; - - DLOGI("%s", ss.str().c_str()); - } - - VOID CloudwatchMetricsMonitoring::pushOutboundRtpStats(POutgoingRTPMetricsContext pOutboundRtpStats) - { - DLOGI("HEre"); - MetricDatum bytesDiscardedPercentageDatum, averageFramesRateDatum, nackRateDatum, retransmissionPercentDatum; - - bytesDiscardedPercentageDatum.SetMetricName("PercentageFrameDiscarded"); - bytesDiscardedPercentageDatum.SetValue(pOutboundRtpStats->framesPercentageDiscarded); - bytesDiscardedPercentageDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Percent); - this->push(bytesDiscardedPercentageDatum); - - averageFramesRateDatum.SetMetricName("FramesPerSecond"); - averageFramesRateDatum.SetValue(pOutboundRtpStats->averageFramesSentPerSecond); - averageFramesRateDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count_Second); - this->push(averageFramesRateDatum); - - nackRateDatum.SetMetricName("NackPerSecond"); - nackRateDatum.SetValue(pOutboundRtpStats->nacksPerSecond); - nackRateDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count_Second); - this->push(nackRateDatum); - - retransmissionPercentDatum.SetMetricName("PercentageFramesRetransmitted"); - retransmissionPercentDatum.SetValue(pOutboundRtpStats->retxBytesPercentage); - retransmissionPercentDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Percent); - this->push(retransmissionPercentDatum); - } - - VOID CloudwatchMetricsMonitoring::pushInboundRtpStats(PIncomingRTPMetricsContext pIncomingRtpStats) - { - MetricDatum incomingBitrateDatum, incomingPacketRate, incomingFrameDropRateDatum; - - incomingBitrateDatum.SetMetricName("IncomingBitRate"); - incomingBitrateDatum.SetValue(pIncomingRtpStats->incomingBitRate); - incomingBitrateDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Kilobits_Second); - this->push(incomingBitrateDatum); - - incomingPacketRate.SetMetricName("IncomingPacketsPerSecond"); - incomingPacketRate.SetValue(pIncomingRtpStats->packetReceiveRate); - incomingPacketRate.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count_Second); - this->push(incomingPacketRate); - - incomingFrameDropRateDatum.SetMetricName("IncomingFramesDroppedPerSecond"); - incomingFrameDropRateDatum.SetValue(pIncomingRtpStats->framesDroppedPerSecond); - incomingFrameDropRateDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count_Second); - this->push(incomingFrameDropRateDatum); - } - -} // namespace Canary diff --git a/aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.h b/aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.h deleted file mode 100644 index 2cb1ede301..0000000000 --- a/aws-cpp-sdk-integ/CloudwatchMetricsMonitoring.h +++ /dev/null @@ -1,27 +0,0 @@ -#pragma once - -#include "Config.h" -#include "../samples/Samples.h" -namespace CppInteg { - - class CloudwatchMetricsMonitoring { - public: - CloudwatchMetricsMonitoring(CppInteg::PConfig, ClientConfiguration*); - STATUS init(CppInteg::PConfig); - VOID deinit(); - static CloudwatchMetricsMonitoring& getInstance(); - VOID pushOutboundRtpStats(POutgoingRTPMetricsContext pOutboundRtpStats); - VOID pushInboundRtpStats(PIncomingRTPMetricsContext pIncomingRtpStats); - - private: - static CloudwatchMetricsMonitoring& getInstanceImpl(CppInteg::PConfig = nullptr, ClientConfiguration* = nullptr); - Dimension channelDimension; - Dimension labelDimension; - PConfig pConfig; - VOID push(const MetricDatum&); - CloudWatchClient client; - std::atomic pendingMetrics; - BOOL isStorage; - }; - -} // namespace Canary diff --git a/aws-cpp-sdk-integ/Config.cpp b/aws-cpp-sdk-integ/Config.cpp deleted file mode 100644 index 4b9cb6e3f4..0000000000 --- a/aws-cpp-sdk-integ/Config.cpp +++ /dev/null @@ -1,274 +0,0 @@ -#include "Config.h" - -namespace CppInteg { - - STATUS Config::init(INT32 argc, PCHAR argv[]) - { - // TODO: Probably also support command line args to fill the config - STATUS retStatus = STATUS_SUCCESS; - - CHK(argv != NULL, STATUS_NULL_ARG); - CHK_STATUS(initWithEnvVars()); - - // Need to impose a min duration - if (duration.value != 0 && duration.value < CANARY_MIN_DURATION) { - DLOGW("Canary duration should be at least %u seconds. Overriding with minimal duration.", - CANARY_MIN_DURATION / HUNDREDS_OF_NANOS_IN_A_SECOND); - duration.value = CANARY_MIN_DURATION; - } - - // Need to impose a min iteration duration - if (iterationDuration.value < CANARY_MIN_ITERATION_DURATION) { - DLOGW("Canary iterations duration should be at least %u seconds. Overriding with minimal iterations duration.", - CANARY_MIN_ITERATION_DURATION / HUNDREDS_OF_NANOS_IN_A_SECOND); - iterationDuration.value = CANARY_MIN_ITERATION_DURATION; - } - - CleanUp: - - return retStatus; - } - - BOOL strtobool(const CHAR* value) - { - if (STRCMPI(value, "on") == 0 || STRCMPI(value, "true") == 0) { - return TRUE; - } - - return FALSE; - } - - STATUS mustenv(CHAR const* pKey, Config::Value* pResult) - { - STATUS retStatus = STATUS_SUCCESS; - const CHAR* value; - - CHK(pResult != NULL, STATUS_NULL_ARG); - CHK(!pResult->initialized, retStatus); - - CHK_ERR((value = getenv(pKey)) != NULL, STATUS_INVALID_OPERATION, "%s must be set", pKey); - pResult->value = value; - pResult->initialized = TRUE; - - CleanUp: - - return retStatus; - } - - STATUS optenv(CHAR const* pKey, Config::Value* pResult, std::string defaultValue) - { - STATUS retStatus = STATUS_SUCCESS; - const CHAR* value; - - CHK(pResult != NULL, STATUS_NULL_ARG); - CHK(!pResult->initialized, retStatus); - - if (NULL != (value = getenv(pKey))) { - pResult->value = value; - } else { - pResult->value = defaultValue; - } - pResult->initialized = TRUE; - - CleanUp: - - return retStatus; - } - - STATUS mustenvBool(CHAR const* pKey, Config::Value* pResult) - { - STATUS retStatus = STATUS_SUCCESS; - Config::Value raw; - - CHK(pResult != NULL, STATUS_NULL_ARG); - CHK(!pResult->initialized, retStatus); - CHK_STATUS(mustenv(pKey, &raw)); - - pResult->value = strtobool(raw.value.c_str()); - pResult->initialized = TRUE; - - CleanUp: - - return retStatus; - } - - STATUS optenvBool(CHAR const* pKey, Config::Value* pResult, BOOL defVal) - { - STATUS retStatus = STATUS_SUCCESS; - Config::Value raw; - - CHK(pResult != NULL, STATUS_NULL_ARG); - CHK(!pResult->initialized, retStatus); - CHK_STATUS(optenv(pKey, &raw, "")); - if (!raw.value.empty()) { - pResult->value = strtobool(raw.value.c_str()); - } else { - pResult->value = defVal; - } - pResult->initialized = TRUE; - - CleanUp: - - return retStatus; - } - - STATUS mustenvUint64(CHAR const* pKey, Config::Value* pResult) - { - STATUS retStatus = STATUS_SUCCESS; - Config::Value raw; - - CHK(pResult != NULL, STATUS_NULL_ARG); - CHK(!pResult->initialized, retStatus); - CHK_STATUS(mustenv(pKey, &raw)); - - STRTOUI64((PCHAR) raw.value.c_str(), NULL, 10, &pResult->value); - pResult->initialized = TRUE; - - CleanUp: - - return retStatus; - } - - STATUS optenvUint64(CHAR const* pKey, Config::Value* pResult, UINT64 defVal) - { - STATUS retStatus = STATUS_SUCCESS; - Config::Value raw; - - CHK(pResult != NULL, STATUS_NULL_ARG); - CHK(!pResult->initialized, retStatus); - CHK_STATUS(optenv(pKey, &raw, "")); - if (!raw.value.empty()) { - STRTOUI64((PCHAR) raw.value.c_str(), NULL, 10, &pResult->value); - } else { - pResult->value = defVal; - } - pResult->initialized = TRUE; - - CleanUp: - - return retStatus; - } - - STATUS Config::initWithEnvVars() - { - STATUS retStatus = STATUS_SUCCESS; - Config::Value logLevel64; - std::stringstream defaultLogStreamName; - UINT64 fileSize; - - /* This is ignored for master. Master can extract the info from offer. Viewer has to know if peer can trickle or - * not ahead of time. */ - CHK_STATUS(optenvBool(CANARY_TRICKLE_ICE_ENV_VAR, &trickleIce, TRUE)); - CHK_STATUS(optenvBool(CANARY_USE_TURN_ENV_VAR, &useTurn, TRUE)); - CHK_STATUS(optenvBool(CANARY_FORCE_TURN_ENV_VAR, &forceTurn, FALSE)); - CHK_STATUS(optenvBool(CANARY_USE_IOT_CREDENTIALS_ENV_VAR, &useIotCredentialProvider, FALSE)); - CHK_STATUS(optenvBool(CANARY_RUN_IN_PROFILING_MODE_ENV_VAR, &isProfilingMode, FALSE)); - - CHK_STATUS(optenv(CANARY_VIDEO_CODEC_ENV_VAR, &videoCodec, CANARY_VIDEO_CODEC_H264)); - CHK_STATUS(optenv(CACERT_PATH_ENV_VAR, &caCertPath, KVS_CA_CERT_PATH)); - - if(useIotCredentialProvider.value == TRUE) { - CHK_STATUS(mustenv(IOT_CORE_CREDENTIAL_ENDPOINT_ENV_VAR, &iotCoreCredentialEndPointFile)); - CHK_STATUS(readFile((PCHAR)iotCoreCredentialEndPointFile.value.c_str(), TRUE, NULL, &fileSize)); - CHK_ERR(fileSize != 0, STATUS_WEBRTC_EMPTY_IOT_CRED_FILE, "Empty credential file"); - CHK_STATUS(readFile((PCHAR)iotCoreCredentialEndPointFile.value.c_str(), TRUE, iotEndpoint, &fileSize)); - iotEndpoint[fileSize - 1] = '\0'; - CHK_STATUS(mustenv(IOT_CORE_CERT_ENV_VAR, &iotCoreCert)); - CHK_STATUS(mustenv(IOT_CORE_PRIVATE_KEY_ENV_VAR, &iotCorePrivateKey)); - CHK_STATUS(mustenv(IOT_CORE_ROLE_ALIAS_ENV_VAR, &iotCoreRoleAlias)); - CHK_STATUS(mustenv(IOT_CORE_THING_NAME_ENV_VAR, &channelName)); - } - else { - CHK_STATUS(mustenv(ACCESS_KEY_ENV_VAR, &accessKey)); - CHK_STATUS(mustenv(SECRET_KEY_ENV_VAR, &secretKey)); - CHK_STATUS(optenv(CANARY_CHANNEL_NAME_ENV_VAR, &channelName, CANARY_DEFAULT_CHANNEL_NAME)); - } - CHK_STATUS(optenv(SESSION_TOKEN_ENV_VAR, &sessionToken, "")); - CHK_STATUS(optenv(DEFAULT_REGION_ENV_VAR, ®ion, DEFAULT_AWS_REGION)); - - // Set the logger log level - if (!logLevel.initialized) { - CHK_STATUS(optenvUint64(DEBUG_LOG_LEVEL_ENV_VAR, &logLevel64, LOG_LEVEL_WARN)); - logLevel.value = (UINT32) logLevel64.value; - logLevel.initialized = TRUE; - } - - CHK_STATUS(optenv(CANARY_ENDPOINT_ENV_VAR, &endpoint, "")); - CHK_STATUS(optenv(CANARY_LABEL_ENV_VAR, &label, CANARY_DEFAULT_LABEL)); - - CHK_STATUS(optenv(CANARY_CLIENT_ID_ENV_VAR, &clientId, CANARY_DEFAULT_CLIENT_ID)); - CHK_STATUS(optenvBool(CANARY_IS_MASTER_ENV_VAR, &isMaster, TRUE)); - CHK_STATUS(optenvBool(CANARY_RUN_BOTH_PEERS_ENV_VAR, &runBothPeers, FALSE)); - - CHK_STATUS(optenv(CANARY_LOG_GROUP_NAME_ENV_VAR, &this->logGroupName, CANARY_DEFAULT_LOG_GROUP_NAME)); - defaultLogStreamName << channelName.value << '-' << (isMaster.value ? "master" : "viewer") << '-' - << GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; - CHK_STATUS(optenv(CANARY_LOG_STREAM_NAME_ENV_VAR, &this->logStreamName, defaultLogStreamName.str())); - - if (!duration.initialized) { - CHK_STATUS(optenvUint64(CANARY_DURATION_IN_SECONDS_ENV_VAR, &duration, 0)); - duration.value *= HUNDREDS_OF_NANOS_IN_A_SECOND; - } - - // Iteration duration is an optional param - if (!iterationDuration.initialized) { - CHK_STATUS(optenvUint64(CANARY_ITERATION_IN_SECONDS_ENV_VAR, &iterationDuration, CANARY_DEFAULT_ITERATION_DURATION_IN_SECONDS)); - iterationDuration.value *= HUNDREDS_OF_NANOS_IN_A_SECOND; - } - - CHK_STATUS(optenvUint64(CANARY_BIT_RATE_ENV_VAR, &bitRate, CANARY_DEFAULT_BITRATE)); - CHK_STATUS(optenvUint64(CANARY_FRAME_RATE_ENV_VAR, &frameRate, CANARY_DEFAULT_FRAMERATE)); - - if (this->isStorage) { - CHK_STATUS(optenv(STORAGE_CANARY_FIRST_FRAME_TS_FILE_ENV_VAR, &storageFristFrameSentTSFileName, STORAGE_CANARY_DEFAULT_FIRST_FRAME_TS_FILE)); - } - - CleanUp: - - return retStatus; - } - - VOID Config::print() - { - DLOGD("Applied configuration:\n\n" - "\tEndpoint : %s\n" - "\tRegion : %s\n" - "\tLabel : %s\n" - "\tChannel Name : %s\n" - "\tClient ID : %s\n" - "\tRole : %s\n" - "\tTrickle ICE : %s\n" - "\tUse TURN : %s\n" - "\tLog Level : %u\n" - "\tLog Group : %s\n" - "\tLog Stream : %s\n" - "\tDuration : %lu seconds\n" - "\tVideo codec : %s\n" - "\tIteration : %lu seconds\n" - "\tRun both peers : %s\n" - "\tCredential type : %s\n" - "\tStorage : %s\n" - "\n", - this->endpoint.value.c_str(), this->region.value.c_str(), this->label.value.c_str(), this->channelName.value.c_str(), - this->clientId.value.c_str(), this->isMaster.value ? "Master" : "Viewer", this->trickleIce.value ? "True" : "False", - this->useTurn.value ? "True" : "False", this->logLevel.value, this->logGroupName.value.c_str(), this->logStreamName.value.c_str(), - this->duration.value / HUNDREDS_OF_NANOS_IN_A_SECOND, this->videoCodec.value.c_str(), this->iterationDuration.value / HUNDREDS_OF_NANOS_IN_A_SECOND, - this->runBothPeers.value ? "True" : "False", this->useIotCredentialProvider.value ? "IoT" : "Static", this->isStorage ? "True" : "False"); - if(this->useIotCredentialProvider.value) { - DLOGD("\tIoT endpoint : %s\n" - "\tIoT cert filename : %s\n" - "\tIoT private key filename : %s\n" - "\tIoT role alias : %s\n", - (PCHAR) this->iotEndpoint, - this->iotCoreCert.value.c_str(), - this->iotCorePrivateKey.value.c_str(), - this->iotCoreRoleAlias.value.c_str()); - } - if(this->isStorage) { - DLOGD("\n\n\tFirstFrameSentTSFileName : %s\n", - this->storageFristFrameSentTSFileName.value.c_str() - ); - } - } - -} // namespace Cloudwatch diff --git a/aws-cpp-sdk-integ/Config.h b/aws-cpp-sdk-integ/Config.h deleted file mode 100644 index a9fdc01836..0000000000 --- a/aws-cpp-sdk-integ/Config.h +++ /dev/null @@ -1,66 +0,0 @@ -#pragma once -#include "../samples/Samples.h" -#include "Include.h" -#include - -namespace CppInteg { - - class Config; - typedef Config* PConfig; - - class Config { - public: - STATUS init(INT32 argc, PCHAR argv[]); - template class Value { - public: - T value; - BOOL initialized = FALSE; - }; - - Value endpoint; - Value label; - Value channelName; - Value clientId; - Value videoCodec; - Value isMaster; - Value runBothPeers; - Value trickleIce; - Value useTurn; - Value forceTurn; - Value useIotCredentialProvider; - Value isProfilingMode; - - BOOL isStorage; - - // credentials - Value accessKey; - Value secretKey; - Value sessionToken; - Value region; - Value iotCoreCredentialEndPointFile; - Value iotCoreCert; - Value iotCorePrivateKey; - Value iotCoreRoleAlias; - - // logging - Value logLevel; - Value logGroupName; - Value logStreamName; - - Value duration; - Value iterationDuration; - Value bitRate; - Value frameRate; - - Value caCertPath; - Value storageFristFrameSentTSFileName; - - BYTE iotEndpoint[MAX_CONFIG_JSON_FILE_SIZE]; - - VOID print(); - - private: - STATUS initWithEnvVars(); - }; - -} // namespace Canary diff --git a/aws-cpp-sdk-integ/CMakeLists.txt b/cloudwatch-integ/CMakeLists.txt similarity index 90% rename from aws-cpp-sdk-integ/CMakeLists.txt rename to cloudwatch-integ/CMakeLists.txt index 1f324921ca..7b4057bbb8 100644 --- a/aws-cpp-sdk-integ/CMakeLists.txt +++ b/cloudwatch-integ/CMakeLists.txt @@ -15,11 +15,11 @@ find_package(AWSSDK REQUIRED COMPONENTS monitoring logs) add_executable( kvsWebrtcClientMasterCW ../samples/Common.c - ../samples/kvsMetricsMonitoring.c ../samples/Utility.c ../samples/MetricsHandling.c - Config.cpp - CloudwatchMetricsMonitoring.cpp + Cloudwatch.cpp + CloudwatchLogs.cpp + CloudwatchMonitoring.cpp kvsWebRTCClientMasterCloudwatch.cpp) target_link_libraries(kvsWebrtcClientMasterCW kvsWebrtcClient diff --git a/cloudwatch-integ/Cloudwatch.cpp b/cloudwatch-integ/Cloudwatch.cpp new file mode 100644 index 0000000000..f32c0ed17f --- /dev/null +++ b/cloudwatch-integ/Cloudwatch.cpp @@ -0,0 +1,82 @@ +#include "Include.h" +#include "Cloudwatch.h" + +namespace CppInteg { + +Cloudwatch::Cloudwatch(ClientConfiguration* pClientConfig) + : logs(pClientConfig), monitoring(pClientConfig), terminated(FALSE) +{ +} + +STATUS Cloudwatch::init(PCHAR channelName, PCHAR region, BOOL isMaster) +{ + ENTERS(); + STATUS retStatus = STATUS_SUCCESS; + ClientConfiguration clientConfig; + CreateLogGroupRequest createLogGroupRequest; + Aws::CloudWatchLogs::Model::CreateLogStreamOutcome createLogStreamOutcome; + CreateLogStreamRequest createLogStreamRequest; + + clientConfig.region = region; + auto& instance = getInstanceImpl(&clientConfig); + + if (STATUS_FAILED(instance.logs.init(channelName, region, isMaster))) { + DLOGW("Failed to create Cloudwatch logger, fallback to file logger"); + } else { + globalCustomLogPrintFn = logger; + } + + CHK_STATUS(instance.monitoring.init(channelName, region, isMaster)); + +CleanUp: + + LEAVES(); + return retStatus; +} + +Cloudwatch& Cloudwatch::getInstance() +{ + return getInstanceImpl(); +} + +Cloudwatch& Cloudwatch::getInstanceImpl(ClientConfiguration* pClientConfig) +{ + static Cloudwatch instance{pClientConfig}; + return instance; +} + +VOID Cloudwatch::deinit() +{ + auto& instance = getInstance(); + instance.logs.deinit(); + instance.monitoring.deinit(); + instance.terminated = TRUE; +} + +VOID Cloudwatch::logger(UINT32 level, PCHAR tag, PCHAR fmt, ...) +{ + CHAR logFmtString[MAX_LOG_FORMAT_LENGTH + 1]; + CHAR cwLogFmtString[MAX_LOG_FORMAT_LENGTH + 1]; + UINT32 logLevel = GET_LOGGER_LOG_LEVEL(); + UNUSED_PARAM(tag); + + if (level >= logLevel) { + addLogMetadata(logFmtString, (UINT32) ARRAY_SIZE(logFmtString), fmt, level); + + // Creating a copy to store the logFmtString for cloudwatch logging purpose + va_list valist, valist_cw; + va_start(valist_cw, fmt); + vsnprintf(cwLogFmtString, (SIZE_T) SIZEOF(cwLogFmtString), logFmtString, valist_cw); + va_end(valist_cw); + va_start(valist, fmt); + vprintf(logFmtString, valist); + va_end(valist); + + auto& instance = getInstance(); + if (!instance.terminated) { + instance.logs.push(cwLogFmtString); + } + } +} + +} // namespace Canary diff --git a/cloudwatch-integ/Cloudwatch.h b/cloudwatch-integ/Cloudwatch.h new file mode 100644 index 0000000000..eac06ee3eb --- /dev/null +++ b/cloudwatch-integ/Cloudwatch.h @@ -0,0 +1,31 @@ +#pragma once + +#include "Include.h" +#include "CloudwatchLogs.h" +#include "CloudwatchMonitoring.h" + +namespace CppInteg { + +class Cloudwatch { + public: + Cloudwatch() = delete; + Cloudwatch(Cloudwatch const&) = delete; + void operator=(Cloudwatch const&) = delete; + + CloudwatchLogs logs; + CloudwatchMonitoring monitoring; + + static Cloudwatch& getInstance(); + static STATUS init(PCHAR channelName, PCHAR region, BOOL isMaster); + static VOID deinit(); + static VOID logger(UINT32, PCHAR, PCHAR, ...); + + private: + static Cloudwatch& getInstanceImpl(ClientConfiguration* = nullptr); + + Cloudwatch(ClientConfiguration*); + BOOL terminated; +}; +typedef Cloudwatch* PCloudwatch; + +} // namespace Canary diff --git a/cloudwatch-integ/CloudwatchLogs.cpp b/cloudwatch-integ/CloudwatchLogs.cpp new file mode 100644 index 0000000000..7bc8318c68 --- /dev/null +++ b/cloudwatch-integ/CloudwatchLogs.cpp @@ -0,0 +1,116 @@ +#include "Include.h" +#include "CloudwatchLogs.h" + +namespace CppInteg { + +CloudwatchLogs::CloudwatchLogs(ClientConfiguration* pClientConfig) : client(*pClientConfig) +{ +} + +STATUS CloudwatchLogs::init(PCHAR channelName, PCHAR region, BOOL isMaster) +{ + STATUS retStatus = STATUS_SUCCESS; + CreateLogGroupRequest createLogGroupRequest; + Aws::CloudWatchLogs::Model::CreateLogStreamOutcome createLogStreamOutcome; + CreateLogStreamRequest createLogStreamRequest; + std::stringstream defaultLogStreamName; + defaultLogStreamName << channelName << '-' << (isMaster ? "master" : "viewer") << '-' + << GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + + this->logStreamName = defaultLogStreamName.str(); + this->logGroupName = CANARY_DEFAULT_LOG_GROUP_NAME; + + DLOGI("Log stream name: %s", this->logStreamName.c_str()); + + createLogGroupRequest.SetLogGroupName(this->logGroupName); + // ignore error since if this operation fails, CreateLogStream should fail as well. + // There might be some errors that can lead to successfull CreateLogStream, e.g. log group already exists. + this->client.CreateLogGroup(createLogGroupRequest); + + createLogStreamRequest.SetLogGroupName(this->logGroupName); + createLogStreamRequest.SetLogStreamName(this->logStreamName); + createLogStreamOutcome = this->client.CreateLogStream(createLogStreamRequest); + + CHK_ERR(createLogStreamOutcome.IsSuccess(), STATUS_INVALID_OPERATION, "Failed to create \"%s\" log stream: %s", + this->logStreamName.c_str(), createLogStreamOutcome.GetError().GetMessage().c_str()); + +CleanUp: + + return retStatus; +} + +VOID CloudwatchLogs::deinit() +{ + this->flush(TRUE); +} + +VOID CloudwatchLogs::push(string log) +{ + std::lock_guard lock(this->sync.mutex); + Aws::String awsCwString(log.c_str(), log.size()); + auto logEvent = + Aws::CloudWatchLogs::Model::InputLogEvent().WithMessage(awsCwString).WithTimestamp(GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); + this->logs.push_back(logEvent); + if (this->logs.size() >= MAX_CLOUDWATCH_LOG_COUNT) { + this->flush(); + } +} + +VOID CloudwatchLogs::flush(BOOL sync) +{ + std::unique_lock lock(this->sync.mutex); + if (this->logs.size() == 0) { + return; + } + auto pendingLogs = this->logs; + this->logs.clear(); + + // wait until previous logs have been flushed entirely + auto waitUntilFlushed = [this] { return !this->sync.pending.load(); }; + this->sync.await.wait(lock, waitUntilFlushed); + + auto request = Aws::CloudWatchLogs::Model::PutLogEventsRequest() + .WithLogGroupName(this->logGroupName) + .WithLogStreamName(this->logStreamName) + .WithLogEvents(pendingLogs); + + if (this->token != "") { + request.SetSequenceToken(this->token); + } + + if (!sync) { + auto asyncHandler = [this](const Aws::CloudWatchLogs::CloudWatchLogsClient* cwClientLog, + const Aws::CloudWatchLogs::Model::PutLogEventsRequest& request, + const Aws::CloudWatchLogs::Model::PutLogEventsOutcome& outcome, + const std::shared_ptr& context) { + UNUSED_PARAM(cwClientLog); + UNUSED_PARAM(request); + UNUSED_PARAM(context); + + if (!outcome.IsSuccess()) { + // Need to use printf so that we don't get into an infinite loop where we keep flushing + printf("Failed to push logs: %s\n", outcome.GetError().GetMessage().c_str()); + } else { + printf("Successfully pushed logs to cloudwatch\n"); + this->token = outcome.GetResult().GetNextSequenceToken(); + } + + this->sync.pending = FALSE; + this->sync.await.notify_one(); + }; + + this->sync.pending = TRUE; + this->client.PutLogEventsAsync(request, asyncHandler); + } else { + auto outcome = this->client.PutLogEvents(request); + if (!outcome.IsSuccess()) { + // Need to use printf so that we don't get into an infinite loop where we keep flushing + printf("Failed to push logs: %s\n", outcome.GetError().GetMessage().c_str()); + } else { + DLOGS("Successfully pushed logs to cloudwatch"); + this->token = outcome.GetResult().GetNextSequenceToken(); + } + } +} + +} // namespace Canary diff --git a/cloudwatch-integ/CloudwatchLogs.h b/cloudwatch-integ/CloudwatchLogs.h new file mode 100644 index 0000000000..636df08747 --- /dev/null +++ b/cloudwatch-integ/CloudwatchLogs.h @@ -0,0 +1,28 @@ +#pragma once + +namespace CppInteg { + +class CloudwatchLogs { + public: + CloudwatchLogs(ClientConfiguration*); + STATUS init(PCHAR channelName, PCHAR region, BOOL isMaster); + VOID deinit(); + VOID push(string log); + VOID flush(BOOL sync = FALSE); + std::string logGroupName, logStreamName; + + private: + class Synchronization { + public: + std::atomic pending; + std::recursive_mutex mutex; + std::condition_variable_any await; + }; + + CloudWatchLogsClient client; + Synchronization sync; + Aws::Vector logs; + Aws::String token; +}; + +} // namespace Canary diff --git a/cloudwatch-integ/CloudwatchMonitoring.cpp b/cloudwatch-integ/CloudwatchMonitoring.cpp new file mode 100644 index 0000000000..072b0f87cc --- /dev/null +++ b/cloudwatch-integ/CloudwatchMonitoring.cpp @@ -0,0 +1,433 @@ +#include "Include.h" +#include "CloudwatchMonitoring.h" + +namespace CppInteg { + +CloudwatchMonitoring::CloudwatchMonitoring(ClientConfiguration* pClientConfig) : client(*pClientConfig) +{ +} + +STATUS CloudwatchMonitoring::init(PCHAR channelName, PCHAR region, BOOL isMaster) +{ + STATUS retStatus = STATUS_SUCCESS; + + this->isStorage ? this->channelDimension.SetName(INDIVIDUAL_STORAGE_CW_DIMENSION) : this->channelDimension.SetName(INDIVIDUAL_CW_DIMENSION); + this->channelDimension.SetValue(channelName); + + this->isStorage ? this->labelDimension.SetName(AGGREGATE_STORAGE_CW_DIMENSION) : this->labelDimension.SetName(AGGREGATE_CW_DIMENSION); + this->labelDimension.SetValue("label"); + + return retStatus; +} + +VOID CloudwatchMonitoring::deinit() +{ + // need to wait all metrics to be flushed out, otherwise we'll get a segfault. + // https://docs.aws.amazon.com/sdk-for-cpp/v1/developer-guide/basic-use.html + // TODO: maybe add a timeout? But, this might cause a segfault if it hits a timeout. + while (this->pendingMetrics.load() > 0) { + THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_MILLISECOND * 500); + } +} + +static const CHAR* unitToString(const Aws::CloudWatch::Model::StandardUnit& unit) +{ + switch (unit) { + case Aws::CloudWatch::Model::StandardUnit::Count: + return "Count"; + case Aws::CloudWatch::Model::StandardUnit::Count_Second: + return "Count_Second"; + case Aws::CloudWatch::Model::StandardUnit::Milliseconds: + return "Milliseconds"; + case Aws::CloudWatch::Model::StandardUnit::Percent: + return "Percent"; + case Aws::CloudWatch::Model::StandardUnit::None: + return "None"; + case Aws::CloudWatch::Model::StandardUnit::Kilobits_Second: + return "Kilobits_Second"; + default: + return "Unknown unit"; + } +} + +VOID CloudwatchMonitoring::push(const MetricDatum& datum) +{ + Aws::CloudWatch::Model::PutMetricDataRequest cwRequest; + MetricDatum single = datum; + MetricDatum aggregated = datum; + + single.AddDimensions(this->channelDimension); + single.AddDimensions(this->labelDimension); + aggregated.AddDimensions(this->labelDimension); + + cwRequest.SetNamespace(DEFAULT_CLOUDWATCH_NAMESPACE); + cwRequest.AddMetricData(single); + cwRequest.AddMetricData(aggregated); + + auto asyncHandler = [this](const Aws::CloudWatch::CloudWatchClient* cwClient, const Aws::CloudWatch::Model::PutMetricDataRequest& request, + const Aws::CloudWatch::Model::PutMetricDataOutcome& outcome, + const std::shared_ptr& context) { + UNUSED_PARAM(cwClient); + UNUSED_PARAM(request); + UNUSED_PARAM(context); + + if (!outcome.IsSuccess()) { + DLOGE("Failed to put sample metric data: %s", outcome.GetError().GetMessage().c_str()); + } else { + DLOGS("Successfully put sample metric data"); + } + this->pendingMetrics--; + }; + this->pendingMetrics++; + this->client.PutMetricDataAsync(cwRequest, asyncHandler); + + std::stringstream ss; + + ss << "Emitted the following metric:\n\n"; + ss << " Name : " << datum.GetMetricName() << '\n'; + ss << " Unit : " << unitToString(datum.GetUnit()) << '\n'; + + ss << " Values : "; + auto& values = datum.GetValues(); + // If the datum uses single value, GetValues will be empty and the data will be accessible + // from GetValue + if (values.empty()) { + ss << datum.GetValue(); + } else { + for (auto i = 0; i < values.size(); i++) { + ss << values[i]; + if (i != values.size() - 1) { + ss << ", "; + } + } + } + ss << '\n'; + + ss << " Dimensions : "; + auto& dimensions = datum.GetDimensions(); + if (dimensions.empty()) { + ss << "N/A"; + } else { + ss << '\n'; + for (auto& dimension : dimensions) { + ss << " - " << dimension.GetName() << "\t: " << dimension.GetValue() << '\n'; + } + } + ss << '\n'; + + DLOGD("%s", ss.str().c_str()); +} + +VOID CloudwatchMonitoring::pushExitStatus(STATUS retStatus) +{ + MetricDatum datum; + Dimension statusDimension; + CHAR status[MAX_STATUS_CODE_LENGTH]; + + statusDimension.SetName("Code"); + SPRINTF(status, "0x%08x", retStatus); + statusDimension.SetValue(status); + + datum.SetMetricName("ExitStatus"); + datum.SetValue(1.0); + datum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count); + + datum.AddDimensions(statusDimension); + + this->push(datum); +} + +VOID CloudwatchMonitoring::pushSignalingRoundtripStatus(STATUS retStatus) +{ + MetricDatum datum; + Dimension statusDimension; + CHAR status[MAX_STATUS_CODE_LENGTH]; + + statusDimension.SetName("Code"); + SPRINTF(status, "0x%08x", retStatus); + statusDimension.SetValue(status); + + datum.SetMetricName("SignalingRoundtripStatus"); + datum.SetValue(1.0); + datum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count); + + datum.AddDimensions(statusDimension); + + this->push(datum); +} + +VOID CloudwatchMonitoring::pushSignalingRoundtripLatency(UINT64 delay, Aws::CloudWatch::Model::StandardUnit unit) +{ + MetricDatum datum; + + datum.SetMetricName("SignalingRoundtripLatency"); + datum.SetValue(delay); + datum.SetUnit(unit); + + this->push(datum); +} + +VOID CloudwatchMonitoring::pushSignalingConnectionDuration(UINT64 duration, Aws::CloudWatch::Model::StandardUnit unit) +{ + MetricDatum datum; + + datum.SetMetricName("SignalingConnectionDuration"); + datum.SetValue(duration); + datum.SetUnit(unit); + + this->push(datum); +} + +VOID CloudwatchMonitoring::pushTimeToFirstFrame(UINT64 timeToFirstFrame, Aws::CloudWatch::Model::StandardUnit unit) +{ + MetricDatum datum; + + datum.SetMetricName("TimeToFirstFrame"); + datum.SetValue(timeToFirstFrame); + datum.SetUnit(unit); + + this->push(datum); +} + + + +VOID CloudwatchMonitoring::pushStorageDisconnectToFrameSentTime(UINT64 storageDisconnectToFrameSentTime, Aws::CloudWatch::Model::StandardUnit unit) +{ + MetricDatum datum; + + datum.SetMetricName("StorageDisconnectToFrameSentTime"); + datum.SetValue(storageDisconnectToFrameSentTime); + datum.SetUnit(unit); + + this->push(datum); +} + +VOID CloudwatchMonitoring::pushJoinSessionTime(UINT64 joinSessionTime, Aws::CloudWatch::Model::StandardUnit unit) +{ + MetricDatum datum; + + datum.SetMetricName("JoinSessionTime"); + datum.SetValue(joinSessionTime); + datum.SetUnit(unit); + + this->push(datum); +} + +VOID CloudwatchMonitoring::pushSignalingInitDelay(UINT64 delay, Aws::CloudWatch::Model::StandardUnit unit) +{ + MetricDatum datum; + + datum.SetMetricName("SignalingInitDelay"); + datum.SetValue(delay); + datum.SetUnit(unit); + + this->push(datum); +} + +VOID CloudwatchMonitoring::pushICEHolePunchingDelay(UINT64 delay, Aws::CloudWatch::Model::StandardUnit unit) +{ + MetricDatum datum; + + datum.SetMetricName("ICEHolePunchingDelay"); + datum.SetValue(delay); + datum.SetUnit(unit); + + this->push(datum); +} + +VOID CloudwatchMonitoring::pushOutboundRtpStats(POutgoingRTPMetricsContext pOutboundRtpStats) +{ + MetricDatum bytesDiscardedPercentageDatum, averageFramesRateDatum, nackRateDatum, retransmissionPercentDatum; + + bytesDiscardedPercentageDatum.SetMetricName("PercentageFrameDiscarded"); + bytesDiscardedPercentageDatum.SetValue(pOutboundRtpStats->framesPercentageDiscarded); + bytesDiscardedPercentageDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Percent); + this->push(bytesDiscardedPercentageDatum); + + averageFramesRateDatum.SetMetricName("FramesPerSecond"); + averageFramesRateDatum.SetValue(pOutboundRtpStats->averageFramesSentPerSecond); + averageFramesRateDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count_Second); + this->push(averageFramesRateDatum); + + nackRateDatum.SetMetricName("NackPerSecond"); + nackRateDatum.SetValue(pOutboundRtpStats->nacksPerSecond); + nackRateDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count_Second); + this->push(nackRateDatum); + + retransmissionPercentDatum.SetMetricName("PercentageFramesRetransmitted"); + retransmissionPercentDatum.SetValue(pOutboundRtpStats->retxBytesPercentage); + retransmissionPercentDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Percent); + this->push(retransmissionPercentDatum); +} + +VOID CloudwatchMonitoring::pushPeerConnectionMetrics(PPeerConnectionMetrics pPeerConnectionMetrics) +{ + MetricDatum pcCreationDatum, dtlsSetupDatum, iceHolePunchingDatum; + + pcCreationDatum.SetMetricName("PcCreationTime"); + pcCreationDatum.SetValue(pPeerConnectionMetrics->peerConnectionStats.peerConnectionCreationTime); + pcCreationDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(pcCreationDatum); + + dtlsSetupDatum.SetMetricName("DtlsSetupTime"); + dtlsSetupDatum.SetValue(pPeerConnectionMetrics->peerConnectionStats.dtlsSessionSetupTime); + dtlsSetupDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(dtlsSetupDatum); + + iceHolePunchingDatum.SetMetricName("ICEHolePunchingDelay"); + iceHolePunchingDatum.SetValue(pPeerConnectionMetrics->peerConnectionStats.iceHolePunchingTime); + iceHolePunchingDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(iceHolePunchingDatum); +} + +VOID CloudwatchMonitoring::pushKvsIceAgentMetrics(PKvsIceAgentMetrics pKvsIceAgentMetrics) +{ + MetricDatum localCandidateGatheringDatum, hostCandidateSetupDatum, srflxCandidateSetUpDatum, + iceAgentSetupDatum, relayCandidateSetUpDatum, iceServerParseDatum, + iceCandidatePairNominationDatum, iceCandidateGatheringDatum; + + localCandidateGatheringDatum.SetMetricName("LocalCandidateGatheringTime"); + localCandidateGatheringDatum.SetValue(pKvsIceAgentMetrics->kvsIceAgentStats.localCandidateGatheringTime); + localCandidateGatheringDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(localCandidateGatheringDatum); + + hostCandidateSetupDatum.SetMetricName("HostCandidateSetUpTime"); + hostCandidateSetupDatum.SetValue(pKvsIceAgentMetrics->kvsIceAgentStats.hostCandidateSetUpTime); + hostCandidateSetupDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(hostCandidateSetupDatum); + + srflxCandidateSetUpDatum.SetMetricName("SrflxCandidateSetUpTime"); + srflxCandidateSetUpDatum.SetValue(pKvsIceAgentMetrics->kvsIceAgentStats.srflxCandidateSetUpTime); + srflxCandidateSetUpDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(srflxCandidateSetUpDatum); + + relayCandidateSetUpDatum.SetMetricName("RelayCandidateSetUpTime"); + relayCandidateSetUpDatum.SetValue(pKvsIceAgentMetrics->kvsIceAgentStats.relayCandidateSetUpTime); + relayCandidateSetUpDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(relayCandidateSetUpDatum); + + iceServerParseDatum.SetMetricName("IceServerResolutionTime"); + iceServerParseDatum.SetValue(pKvsIceAgentMetrics->kvsIceAgentStats.iceServerParsingTime); + iceServerParseDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(iceServerParseDatum); + + iceCandidatePairNominationDatum.SetMetricName("IceCandidatePairNominationTime"); + iceCandidatePairNominationDatum.SetValue(pKvsIceAgentMetrics->kvsIceAgentStats.iceCandidatePairNominationTime); + iceCandidatePairNominationDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(iceCandidatePairNominationDatum); + + iceCandidateGatheringDatum.SetMetricName("IcecandidateGatheringTime"); + iceCandidateGatheringDatum.SetValue(pKvsIceAgentMetrics->kvsIceAgentStats.candidateGatheringTime); + iceCandidateGatheringDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(iceCandidateGatheringDatum); + + iceAgentSetupDatum.SetMetricName("IceAgentSetUpTime"); + iceAgentSetupDatum.SetValue(pKvsIceAgentMetrics->kvsIceAgentStats.iceAgentSetUpTime); + iceAgentSetupDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(iceAgentSetupDatum); +} + +VOID CloudwatchMonitoring::pushSignalingClientMetrics(PSignalingClientMetrics pSignalingClientMetrics) +{ + MetricDatum offerToAnswerDatum, getTokenDatum, describeDatum, createDatum, endpointDatum, + iceConfigDatum, connectDatum, createClientDatum, fetchDatum, connectClientDatum, joinSessionToOfferDatum; + + UINT64 joinSessionToOffer, joinSessionCallTime; + + offerToAnswerDatum.SetMetricName("OfferToAnswerTime"); + offerToAnswerDatum.SetValue(pSignalingClientMetrics->signalingClientStats.offerToAnswerTime); + offerToAnswerDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(offerToAnswerDatum); + + getTokenDatum.SetMetricName("GetTokenTime"); + getTokenDatum.SetValue(pSignalingClientMetrics->signalingClientStats.getTokenCallTime); + getTokenDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(getTokenDatum); + + describeDatum.SetMetricName("DescribeCallTime"); + describeDatum.SetValue(pSignalingClientMetrics->signalingClientStats.describeCallTime); + describeDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(describeDatum); + + createDatum.SetMetricName("CreateCallTime"); + createDatum.SetValue(pSignalingClientMetrics->signalingClientStats.createCallTime); + createDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(createDatum); + + endpointDatum.SetMetricName("GetEndpointCallTime"); + endpointDatum.SetValue(pSignalingClientMetrics->signalingClientStats.getEndpointCallTime); + endpointDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(endpointDatum); + + iceConfigDatum.SetMetricName("GetIceConfigCallTime"); + iceConfigDatum.SetValue(pSignalingClientMetrics->signalingClientStats.getIceConfigCallTime); + iceConfigDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(iceConfigDatum); + + connectDatum.SetMetricName("ConnectCallTime"); + connectDatum.SetValue(pSignalingClientMetrics->signalingClientStats.connectCallTime); + connectDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(connectDatum); + + createClientDatum.SetMetricName("CreateClientTotalTime"); + createClientDatum.SetValue(pSignalingClientMetrics->signalingClientStats.createClientTime); + createClientDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(createClientDatum); + + fetchDatum.SetMetricName("FetchClientTotalTime"); + fetchDatum.SetValue(pSignalingClientMetrics->signalingClientStats.fetchClientTime); + fetchDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(fetchDatum); + + connectClientDatum.SetMetricName("ConnectClientTotalTime"); + connectClientDatum.SetValue(pSignalingClientMetrics->signalingClientStats.connectClientTime); + connectClientDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(connectClientDatum); + + if (this->isStorage) { + joinSessionToOffer = pSignalingClientMetrics->signalingClientStats.joinSessionToOfferRecvTime; + if (joinSessionToOffer > 0) { + joinSessionToOfferDatum.SetMetricName("JoinSessionToOfferReceived"); + joinSessionToOfferDatum.SetValue(joinSessionToOffer / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); + joinSessionToOfferDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + this->push(joinSessionToOfferDatum); + } + + joinSessionCallTime = (pSignalingClientMetrics->signalingClientStats.joinSessionCallTime); + if (joinSessionToOffer > 0) { + this->pushJoinSessionTime(joinSessionCallTime, Aws::CloudWatch::Model::StandardUnit::Milliseconds); + } + } +} + +VOID CloudwatchMonitoring::pushInboundRtpStats(PIncomingRTPMetricsContext pIncomingRtpStats) +{ + MetricDatum incomingBitrateDatum, incomingPacketRate, incomingFrameDropRateDatum; + + incomingBitrateDatum.SetMetricName("IncomingBitRate"); + incomingBitrateDatum.SetValue(pIncomingRtpStats->incomingBitRate); + incomingBitrateDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Kilobits_Second); + this->push(incomingBitrateDatum); + + incomingPacketRate.SetMetricName("IncomingPacketsPerSecond"); + incomingPacketRate.SetValue(pIncomingRtpStats->packetReceiveRate); + incomingPacketRate.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count_Second); + this->push(incomingPacketRate); + + incomingFrameDropRateDatum.SetMetricName("IncomingFramesDroppedPerSecond"); + incomingFrameDropRateDatum.SetValue(pIncomingRtpStats->framesDroppedPerSecond); + incomingFrameDropRateDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count_Second); + this->push(incomingFrameDropRateDatum); +} + +VOID CloudwatchMonitoring::pushRetryCount(UINT32 retryCount) +{ + MetricDatum currentRetryCountDatum; + + currentRetryCountDatum.SetMetricName("APICallRetryCount"); + currentRetryCountDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count); + currentRetryCountDatum.SetValue(retryCount); + this->push(currentRetryCountDatum); +} + +} // namespace Canary diff --git a/cloudwatch-integ/CloudwatchMonitoring.h b/cloudwatch-integ/CloudwatchMonitoring.h new file mode 100644 index 0000000000..a80109379f --- /dev/null +++ b/cloudwatch-integ/CloudwatchMonitoring.h @@ -0,0 +1,37 @@ +#pragma once + +#include "../samples/Samples.h" +namespace CppInteg { + +class CloudwatchMonitoring { + public: + CloudwatchMonitoring(ClientConfiguration*); + STATUS init(PCHAR channelName, PCHAR region, BOOL isMaster); + VOID deinit(); + VOID push(const MetricDatum&); + VOID pushExitStatus(STATUS); + VOID pushSignalingRoundtripStatus(STATUS); + VOID pushSignalingInitDelay(UINT64, Aws::CloudWatch::Model::StandardUnit); + VOID pushTimeToFirstFrame(UINT64, Aws::CloudWatch::Model::StandardUnit); + VOID pushSignalingRoundtripLatency(UINT64, Aws::CloudWatch::Model::StandardUnit); + VOID pushSignalingConnectionDuration(UINT64, Aws::CloudWatch::Model::StandardUnit); + VOID pushICEHolePunchingDelay(UINT64, Aws::CloudWatch::Model::StandardUnit); + VOID pushOutboundRtpStats(POutgoingRTPMetricsContext); + VOID pushInboundRtpStats(PIncomingRTPMetricsContext); + VOID pushPeerConnectionMetrics(PPeerConnectionMetrics); + VOID pushKvsIceAgentMetrics(PKvsIceAgentMetrics); + VOID pushSignalingClientMetrics(PSignalingClientMetrics); + VOID pushRetryCount(UINT32); + + VOID pushStorageDisconnectToFrameSentTime(UINT64, Aws::CloudWatch::Model::StandardUnit); + VOID pushJoinSessionTime(UINT64, Aws::CloudWatch::Model::StandardUnit); + + private: + Dimension channelDimension; + Dimension labelDimension; + CloudWatchClient client; + std::atomic pendingMetrics; + BOOL isStorage; +}; + +} // namespace CppInteg diff --git a/aws-cpp-sdk-integ/Include.h b/cloudwatch-integ/Include.h similarity index 100% rename from aws-cpp-sdk-integ/Include.h rename to cloudwatch-integ/Include.h diff --git a/cloudwatch-integ/config_periodic.h b/cloudwatch-integ/config_periodic.h new file mode 100644 index 0000000000..426e94e416 --- /dev/null +++ b/cloudwatch-integ/config_periodic.h @@ -0,0 +1,12 @@ +#ifndef KVS_SDK_SAMPLE_CONFIG_H +#define KVS_SDK_SAMPLE_CONFIG_H + +#define USE_TRICKLE_ICE TRUE +#define FORCE_TURN_ONLY FALSE +#define CHANNEL_NAME (PCHAR) "test" +#define USE_TURN TRUE +#define ENABLE_TTFF_VIA_DC FALSE +#define IOT_CORE_ENABLE_CREDENTIALS FALSE +#define ENABLE_STORAGE FALSE + +#endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/aws-cpp-sdk-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp similarity index 93% rename from aws-cpp-sdk-integ/kvsWebRTCClientMasterCloudwatch.cpp rename to cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 7275e9d9fc..5239337f34 100644 --- a/aws-cpp-sdk-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -1,7 +1,6 @@ #include #include "../samples/Samples.h" -#include "Config.h" -#include "CloudwatchMetricsMonitoring.h" +#include "Cloudwatch.h" STATUS publishStatsForCanary(RTC_STATS_TYPE statsType, PSampleStreamingSession pSampleStreamingSession) { @@ -11,12 +10,12 @@ STATUS publishStatsForCanary(RTC_STATS_TYPE statsType, PSampleStreamingSession p case RTC_STATS_TYPE_OUTBOUND_RTP: CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->canaryMetrics)); populateOutgoingRtpMetricsContext(pSampleStreamingSession); - CppInteg::CloudwatchMetricsMonitoring::getInstance().pushOutboundRtpStats(&pSampleStreamingSession->canaryOutgoingRTPMetricsContext); + CppInteg::Cloudwatch::getInstance().monitoring.pushOutboundRtpStats(&pSampleStreamingSession->canaryOutgoingRTPMetricsContext); break; case RTC_STATS_TYPE_INBOUND_RTP: CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->canaryMetrics)); populateIncomingRtpMetricsContext(pSampleStreamingSession); - CppInteg::CloudwatchMetricsMonitoring::getInstance().pushInboundRtpStats(&pSampleStreamingSession->canaryIncomingRTPMetricsContext); + CppInteg::Cloudwatch::getInstance().monitoring.pushInboundRtpStats(&pSampleStreamingSession->canaryIncomingRTPMetricsContext); break; default: CHK(FALSE, STATUS_NOT_IMPLEMENTED); @@ -186,18 +185,16 @@ INT32 main(INT32 argc, CHAR* argv[]) UINT32 frameSize; PSampleConfiguration pSampleConfiguration = NULL; SignalingClientMetrics signalingClientMetrics; - auto config = CppInteg::Config(); - + PCHAR region; Aws::SDKOptions options; Aws::InitAPI(options); { SET_INSTRUMENTED_ALLOCATORS(); // Initialize KVS WebRTC. This must be done before anything else, and must only be done once. initKvsWebRtc(); - config.init(argc, argv); UINT32 logLevel = setLogLevel(); - createSampleConfiguration((PCHAR) config.channelName.value.c_str(), SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration); + createSampleConfiguration(CHANNEL_NAME, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration); // Set the audio and video handlers pSampleConfiguration->audioSource = sendAudioPackets; @@ -208,10 +205,10 @@ INT32 main(INT32 argc, CHAR* argv[]) pSampleConfiguration->channelInfo.useMediaStorage = TRUE; } - ClientConfiguration clientConfig; - clientConfig.region = config.region.value; - CppInteg::CloudwatchMetricsMonitoring cwmonitoring(&config, &clientConfig); - cwmonitoring.init(&config); + if ((region = GETENV(DEFAULT_REGION_ENV_VAR)) == NULL) { + region = (PCHAR) DEFAULT_AWS_REGION; + } + CppInteg::Cloudwatch::init(CHANNEL_NAME, region, TRUE); #ifdef ENABLE_DATA_CHANNEL pSampleConfiguration->onDataChannel = onDataChannel; @@ -234,7 +231,7 @@ INT32 main(INT32 argc, CHAR* argv[]) pSampleConfiguration->signalingClientMetrics.signalingEndTime, pSampleConfiguration->signalingClientMetrics.signalingCallTime, "Initialize signaling client and connect to the signaling channel"); - DLOGI("[KVS Master] Channel %s set up done ", (PCHAR) config.channelName.value.c_str()); + DLOGI("[KVS Master] Channel %s set up done ", CHANNEL_NAME); // Checking for termination sessionCleanupWait(pSampleConfiguration); @@ -244,6 +241,7 @@ INT32 main(INT32 argc, CHAR* argv[]) DLOGE("[KVS Master] Terminated with status code 0x%08x", retStatus); } +CleanUp: DLOGI("[KVS Master] Cleaning up...."); if (pSampleConfiguration != NULL) { // Kick of the termination sequence diff --git a/samples/Common.c b/samples/Common.c index 8fa2b7eca0..756f4edd38 100644 --- a/samples/Common.c +++ b/samples/Common.c @@ -454,30 +454,6 @@ STATUS initializePeerConnection(PSampleConfiguration pSampleConfiguration, PRtcP return retStatus; } -// Return ICE server stats for a specific streaming session -STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession) -{ - ENTERS(); - STATUS retStatus = STATUS_SUCCESS; - RtcStats rtcmetrics; - UINT32 j = 0; - rtcmetrics.requestedTypeOfStats = RTC_STATS_TYPE_ICE_SERVER; - for (; j < pSampleStreamingSession->pSampleConfiguration->iceUriCount; j++) { - rtcmetrics.rtcStatsObject.iceServerStats.iceServerIndex = j; - CHK_STATUS(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, NULL, &rtcmetrics)); - DLOGD("ICE Server URL: %s", rtcmetrics.rtcStatsObject.iceServerStats.url); - DLOGD("ICE Server port: %d", rtcmetrics.rtcStatsObject.iceServerStats.port); - DLOGD("ICE Server protocol: %s", rtcmetrics.rtcStatsObject.iceServerStats.protocol); - DLOGD("Total requests sent:%" PRIu64, rtcmetrics.rtcStatsObject.iceServerStats.totalRequestsSent); - DLOGD("Total responses received: %" PRIu64, rtcmetrics.rtcStatsObject.iceServerStats.totalResponsesReceived); - DLOGD("Total round trip time: %" PRIu64 "ms", - rtcmetrics.rtcStatsObject.iceServerStats.totalRoundTripTime / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); - } -CleanUp: - LEAVES(); - return retStatus; -} - STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, PCHAR peerId, BOOL isMaster, PSampleStreamingSession* ppSampleStreamingSession) { @@ -509,7 +485,7 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P pSampleStreamingSession->pVideoRtcRtpTransceiver = NULL; pSampleStreamingSession->pSampleConfiguration = pSampleConfiguration; - pSampleStreamingSession->rtcMetricsHistory.prevTs = GETTIME(); + pSampleStreamingSession->rtpMetricsHistory.prevTs = GETTIME(); pSampleStreamingSession->peerConnectionMetrics.version = PEER_CONNECTION_METRICS_CURRENT_VERSION; pSampleStreamingSession->iceMetrics.version = ICE_AGENT_METRICS_CURRENT_VERSION; diff --git a/samples/MetricsHandling.c b/samples/MetricsHandling.c index 0fbe491c59..caad79089f 100644 --- a/samples/MetricsHandling.c +++ b/samples/MetricsHandling.c @@ -29,6 +29,30 @@ STATUS logSelectedIceCandidatesInformation(PSampleStreamingSession pSampleStream return retStatus; } +// Return ICE server stats for a specific streaming session +STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession) +{ + ENTERS(); + STATUS retStatus = STATUS_SUCCESS; + RtcStats rtcmetrics; + UINT32 j = 0; + rtcmetrics.requestedTypeOfStats = RTC_STATS_TYPE_ICE_SERVER; + for (; j < pSampleStreamingSession->pSampleConfiguration->iceUriCount; j++) { + rtcmetrics.rtcStatsObject.iceServerStats.iceServerIndex = j; + CHK_STATUS(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, NULL, &rtcmetrics)); + DLOGD("ICE Server URL: %s", rtcmetrics.rtcStatsObject.iceServerStats.url); + DLOGD("ICE Server port: %d", rtcmetrics.rtcStatsObject.iceServerStats.port); + DLOGD("ICE Server protocol: %s", rtcmetrics.rtcStatsObject.iceServerStats.protocol); + DLOGD("Total requests sent:%" PRIu64, rtcmetrics.rtcStatsObject.iceServerStats.totalRequestsSent); + DLOGD("Total responses received: %" PRIu64, rtcmetrics.rtcStatsObject.iceServerStats.totalResponsesReceived); + DLOGD("Total round trip time: %" PRIu64 "ms", + rtcmetrics.rtcStatsObject.iceServerStats.totalRoundTripTime / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); + } + CleanUp: + LEAVES(); + return retStatus; +} + STATUS getIceCandidatePairStatsCallback(UINT32 timerId, UINT64 currentTime, UINT64 customData) { UNUSED_PARAM(timerId); @@ -59,7 +83,7 @@ STATUS getIceCandidatePairStatsCallback(UINT32 timerId, UINT64 currentTime, UINT if (STATUS_SUCCEEDED(rtcPeerConnectionGetMetrics(pSampleConfiguration->sampleStreamingSessionList[i]->pPeerConnection, NULL, &pSampleConfiguration->rtcIceCandidatePairMetrics))) { currentMeasureDuration = (pSampleConfiguration->rtcIceCandidatePairMetrics.timestamp - - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevTs) / + pSampleConfiguration->sampleStreamingSessionList[i]->rtpMetricsHistory.prevTs) / HUNDREDS_OF_NANOS_IN_A_SECOND; DLOGD("Current duration: %" PRIu64 " seconds", currentMeasureDuration); if (currentMeasureDuration > 0) { @@ -74,31 +98,31 @@ STATUS getIceCandidatePairStatsCallback(UINT32 timerId, UINT64 currentTime, UINT : "not nominated"); averageNumberOfPacketsSentPerSecond = (DOUBLE) (pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsSent - - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfPacketsSent) / + pSampleConfiguration->sampleStreamingSessionList[i]->rtpMetricsHistory.prevNumberOfPacketsSent) / (DOUBLE) currentMeasureDuration; DLOGD("Packet send rate: %lf pkts/sec", averageNumberOfPacketsSentPerSecond); averageNumberOfPacketsReceivedPerSecond = (DOUBLE) (pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsReceived - - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfPacketsReceived) / + pSampleConfiguration->sampleStreamingSessionList[i]->rtpMetricsHistory.prevNumberOfPacketsReceived) / (DOUBLE) currentMeasureDuration; DLOGD("Packet receive rate: %lf pkts/sec", averageNumberOfPacketsReceivedPerSecond); outgoingBitrate = (DOUBLE) ((pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.bytesSent - - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfBytesSent) * + pSampleConfiguration->sampleStreamingSessionList[i]->rtpMetricsHistory.prevNumberOfBytesSent) * 8.0) / currentMeasureDuration; DLOGD("Outgoing bit rate: %lf bps", outgoingBitrate); incomingBitrate = (DOUBLE) ((pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.bytesReceived - - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfBytesReceived) * + pSampleConfiguration->sampleStreamingSessionList[i]->rtpMetricsHistory.prevNumberOfBytesReceived) * 8.0) / currentMeasureDuration; DLOGD("Incoming bit rate: %lf bps", incomingBitrate); averagePacketsDiscardedOnSend = (DOUBLE) (pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsDiscardedOnSend - - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevPacketsDiscardedOnSend) / + pSampleConfiguration->sampleStreamingSessionList[i]->rtpMetricsHistory.prevPacketsDiscardedOnSend) / (DOUBLE) currentMeasureDuration; DLOGD("Packet discard rate: %lf pkts/sec", averagePacketsDiscardedOnSend); @@ -107,17 +131,17 @@ STATUS getIceCandidatePairStatsCallback(UINT32 timerId, UINT64 currentTime, UINT DLOGD("Number of STUN responses received: %llu", pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.responsesReceived); - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevTs = + pSampleConfiguration->sampleStreamingSessionList[i]->rtpMetricsHistory.prevTs = pSampleConfiguration->rtcIceCandidatePairMetrics.timestamp; - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfPacketsSent = + pSampleConfiguration->sampleStreamingSessionList[i]->rtpMetricsHistory.prevNumberOfPacketsSent = pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsSent; - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfPacketsReceived = + pSampleConfiguration->sampleStreamingSessionList[i]->rtpMetricsHistory.prevNumberOfPacketsReceived = pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsReceived; - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfBytesSent = + pSampleConfiguration->sampleStreamingSessionList[i]->rtpMetricsHistory.prevNumberOfBytesSent = pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.bytesSent; - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevNumberOfBytesReceived = + pSampleConfiguration->sampleStreamingSessionList[i]->rtpMetricsHistory.prevNumberOfBytesReceived = pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.bytesReceived; - pSampleConfiguration->sampleStreamingSessionList[i]->rtcMetricsHistory.prevPacketsDiscardedOnSend = + pSampleConfiguration->sampleStreamingSessionList[i]->rtpMetricsHistory.prevPacketsDiscardedOnSend = pSampleConfiguration->rtcIceCandidatePairMetrics.rtcStatsObject.iceCandidatePairStats.packetsDiscardedOnSend; } } diff --git a/samples/Samples.h b/samples/Samples.h index eda9304a9a..26336de3f3 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -11,9 +11,7 @@ extern "C" { #endif #include - -#define STRINGIZE(x) #x -#define INCLUDE_CONFIG(header) STRINGIZE(header) +#include SAMPLE_CONFIG_HEADER #define NUMBER_OF_H264_FRAME_FILES 1500 #define NUMBER_OF_H265_FRAME_FILES 1500 @@ -112,20 +110,6 @@ typedef enum { RTSP_SOURCE, } SampleSourceType; -typedef enum { - ICE_CANDIDATE_PAIR_METRICS = 1 << 0, - ICE_SERVER_METRICS = 1 << 1, - DATA_CHANNEL_METRICS = 1 << 2, - INBOUND_RTP_METRICS = 1 << 4, - ICE_LOCAL_CANDIDATE_METRICS = 1 << 5, - OUTBOUND_RTP_METRICS = 1 << 6, - ICE_REMOTE_CANDIDATE_METRICS = 1 << 7, - REMOTE_INBOUND_RTP_METRICS = 1 << 8, - REMOTE_OUTBOUND_RTP_METRICS = 1 << 9, - TRANSPORT_METRICS = 1 << 10, - ALL_METRICS = 1 << 11 -} MetricsType; - typedef struct __SampleStreamingSession SampleStreamingSession; typedef struct __SampleStreamingSession* PSampleStreamingSession; @@ -136,7 +120,7 @@ typedef struct { UINT64 prevNumberOfBytesReceived; UINT64 prevPacketsDiscardedOnSend; UINT64 prevTs; -} RtcMetricsHistory, *PRtcMetricsHistory; +} RtpMetricsHistory, *PRtpMetricsHistory; typedef struct { volatile ATOMIC_BOOL appTerminateFlag; @@ -272,7 +256,7 @@ struct __SampleStreamingSession { CHAR peerId[MAX_SIGNALING_CLIENT_ID_LEN + 1]; TID receiveAudioVideoSenderTid; UINT64 startUpLatency; - RtcMetricsHistory rtcMetricsHistory; + RtpMetricsHistory rtpMetricsHistory; BOOL remoteCanTrickleIce; TwccMetadata twccMetadata; @@ -350,6 +334,7 @@ UINT32 setLogLevel(); STATUS populateOutgoingRtpMetricsContext(PSampleStreamingSession pSampleStreamingSession); STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamingSession); +STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession); #ifdef __cplusplus } diff --git a/samples/config_default.h b/samples/config_default.h index ccaac69612..5135c565ce 100644 --- a/samples/config_default.h +++ b/samples/config_default.h @@ -1,7 +1,3 @@ -// -// Created by Sampath Kumar, Divya on 5/7/24. -// - #ifndef KVS_SDK_CONFIG_DEFAULT_H #define KVS_SDK_CONFIG_DEFAULT_H diff --git a/samples/kvsMetricsMonitoring.c b/samples/kvsMetricsMonitoring.c deleted file mode 100644 index fbfaf96e2e..0000000000 --- a/samples/kvsMetricsMonitoring.c +++ /dev/null @@ -1,28 +0,0 @@ -#include "Samples.h" - -STATUS initMetricsModule(UINT64 metrics) -{ - if (metrics & ICE_CANDIDATE_PAIR_METRICS) { - } - if (metrics & ICE_SERVER_METRICS) { - } - if (metrics & DATA_CHANNEL_METRICS) { - } - if (metrics & INBOUND_RTP_METRICS) { - } - if (metrics & ICE_LOCAL_CANDIDATE_METRICS) { - } - if (metrics & OUTBOUND_RTP_METRICS) { - } - if (metrics & ICE_REMOTE_CANDIDATE_METRICS) { - } - if (metrics & REMOTE_INBOUND_RTP_METRICS) { - } - if (metrics & REMOTE_OUTBOUND_RTP_METRICS) { - } - if (metrics & TRANSPORT_METRICS) { - } - if (metrics & ALL_METRICS) { - } - return STATUS_SUCCESS; -} \ No newline at end of file diff --git a/samples/sample_config.h b/samples/sample_config.h index 358b85dfe8..eea752d8a0 100644 --- a/samples/sample_config.h +++ b/samples/sample_config.h @@ -8,4 +8,8 @@ #define ENABLE_TTFF_VIA_DC FALSE #define IOT_CORE_ENABLE_CREDENTIALS FALSE #define ENABLE_STORAGE FALSE + + + + #endif // KVS_SDK_SAMPLE_CONFIG_H From ec673a9cb889dbb3f1783e73ba0c7e454b354dab Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 17 May 2024 13:50:43 -0700 Subject: [PATCH 05/64] Rebased --- README.md | 2 +- cloudwatch-integ/CMakeLists.txt | 7 +- cloudwatch-integ/CloudwatchMonitoring.cpp | 4 +- cloudwatch-integ/CloudwatchMonitoring.h | 4 +- cloudwatch-integ/config_periodic.h | 1 + .../kvsWebRTCClientMasterCloudwatch.cpp | 14 +- samples/CMakeLists.txt | 41 ++-- samples/Samples.h | 30 ++- samples/{ => lib}/Common.c | 183 +----------------- samples/lib/DataChannelHandling.c | 177 +++++++++++++++++ samples/{ => lib}/Media.c | 0 samples/{ => lib}/MetricsHandling.c | 132 +++++++------ samples/{ => lib}/Utility.c | 2 +- samples/sample_config.h | 4 +- 14 files changed, 318 insertions(+), 283 deletions(-) rename samples/{ => lib}/Common.c (85%) create mode 100644 samples/lib/DataChannelHandling.c rename samples/{ => lib}/Media.c (100%) rename samples/{ => lib}/MetricsHandling.c (60%) rename samples/{ => lib}/Utility.c (97%) diff --git a/README.md b/README.md index 114891e447..c6a14225a1 100644 --- a/README.md +++ b/README.md @@ -450,7 +450,7 @@ The certificate generating function ([createCertificateAndKey](https://awslabs.g **Important Note: It is recommended to rotate the certificates often - preferably for every peer connection to avoid a compromised client weakening the security of the new connections.** Take `kvsWebRTCClientMaster` as sample, add `RtcCertificate certificates[CERT_COUNT];` to **SampleConfiguration** in [Samples.h](./samples/Samples.h). -Then pass in the pre-generated certificate in initializePeerConnection() in [Common.c](./samples/Common.c). +Then pass in the pre-generated certificate in initializePeerConnection() in [Common.c](samples/lib/Common.c). ```c configuration.certificates[0].pCertificate = pSampleConfiguration->certificates[0].pCertificate; diff --git a/cloudwatch-integ/CMakeLists.txt b/cloudwatch-integ/CMakeLists.txt index 7b4057bbb8..6918ae1ec9 100644 --- a/cloudwatch-integ/CMakeLists.txt +++ b/cloudwatch-integ/CMakeLists.txt @@ -14,9 +14,10 @@ find_package(AWSSDK REQUIRED COMPONENTS monitoring logs) add_executable( kvsWebrtcClientMasterCW - ../samples/Common.c - ../samples/Utility.c - ../samples/MetricsHandling.c + ../samples/lib/Common.c + ../samples/lib/Utility.c + ../samples/lib/MetricsHandling.c + ../samples/lib/DataChannelHandling.c Cloudwatch.cpp CloudwatchLogs.cpp CloudwatchMonitoring.cpp diff --git a/cloudwatch-integ/CloudwatchMonitoring.cpp b/cloudwatch-integ/CloudwatchMonitoring.cpp index 072b0f87cc..59b46e3471 100644 --- a/cloudwatch-integ/CloudwatchMonitoring.cpp +++ b/cloudwatch-integ/CloudwatchMonitoring.cpp @@ -235,7 +235,7 @@ VOID CloudwatchMonitoring::pushICEHolePunchingDelay(UINT64 delay, Aws::CloudWatc this->push(datum); } -VOID CloudwatchMonitoring::pushOutboundRtpStats(POutgoingRTPMetricsContext pOutboundRtpStats) +VOID CloudwatchMonitoring::pushOutboundRtpStats(POutgoingRTPStatsCtx pOutboundRtpStats) { MetricDatum bytesDiscardedPercentageDatum, averageFramesRateDatum, nackRateDatum, retransmissionPercentDatum; @@ -400,7 +400,7 @@ VOID CloudwatchMonitoring::pushSignalingClientMetrics(PSignalingClientMetrics pS } } -VOID CloudwatchMonitoring::pushInboundRtpStats(PIncomingRTPMetricsContext pIncomingRtpStats) +VOID CloudwatchMonitoring::pushInboundRtpStats(PIncomingRTPStatsCtx pIncomingRtpStats) { MetricDatum incomingBitrateDatum, incomingPacketRate, incomingFrameDropRateDatum; diff --git a/cloudwatch-integ/CloudwatchMonitoring.h b/cloudwatch-integ/CloudwatchMonitoring.h index a80109379f..f8ec0ea871 100644 --- a/cloudwatch-integ/CloudwatchMonitoring.h +++ b/cloudwatch-integ/CloudwatchMonitoring.h @@ -16,8 +16,8 @@ class CloudwatchMonitoring { VOID pushSignalingRoundtripLatency(UINT64, Aws::CloudWatch::Model::StandardUnit); VOID pushSignalingConnectionDuration(UINT64, Aws::CloudWatch::Model::StandardUnit); VOID pushICEHolePunchingDelay(UINT64, Aws::CloudWatch::Model::StandardUnit); - VOID pushOutboundRtpStats(POutgoingRTPMetricsContext); - VOID pushInboundRtpStats(PIncomingRTPMetricsContext); + VOID pushOutboundRtpStats(POutgoingRTPStatsCtx); + VOID pushInboundRtpStats(PIncomingRTPStatsCtx); VOID pushPeerConnectionMetrics(PPeerConnectionMetrics); VOID pushKvsIceAgentMetrics(PKvsIceAgentMetrics); VOID pushSignalingClientMetrics(PSignalingClientMetrics); diff --git a/cloudwatch-integ/config_periodic.h b/cloudwatch-integ/config_periodic.h index 426e94e416..ffeaf89657 100644 --- a/cloudwatch-integ/config_periodic.h +++ b/cloudwatch-integ/config_periodic.h @@ -8,5 +8,6 @@ #define ENABLE_TTFF_VIA_DC FALSE #define IOT_CORE_ENABLE_CREDENTIALS FALSE #define ENABLE_STORAGE FALSE +#define ENABLE_METRICS TRUE #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 5239337f34..f4cc2086ea 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -5,17 +5,17 @@ STATUS publishStatsForCanary(RTC_STATS_TYPE statsType, PSampleStreamingSession pSampleStreamingSession) { STATUS retStatus = STATUS_SUCCESS; - pSampleStreamingSession->canaryMetrics.requestedTypeOfStats = statsType; + pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = statsType; switch (statsType) { case RTC_STATS_TYPE_OUTBOUND_RTP: - CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->canaryMetrics)); + CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); populateOutgoingRtpMetricsContext(pSampleStreamingSession); - CppInteg::Cloudwatch::getInstance().monitoring.pushOutboundRtpStats(&pSampleStreamingSession->canaryOutgoingRTPMetricsContext); + CppInteg::Cloudwatch::getInstance().monitoring.pushOutboundRtpStats(&pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx); break; case RTC_STATS_TYPE_INBOUND_RTP: - CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->canaryMetrics)); + CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); populateIncomingRtpMetricsContext(pSampleStreamingSession); - CppInteg::Cloudwatch::getInstance().monitoring.pushInboundRtpStats(&pSampleStreamingSession->canaryIncomingRTPMetricsContext); + CppInteg::Cloudwatch::getInstance().monitoring.pushInboundRtpStats(&pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx); break; default: CHK(FALSE, STATUS_NOT_IMPLEMENTED); @@ -68,8 +68,8 @@ PVOID sendVideoPackets(PVOID args) MUTEX_LOCK(pSampleConfiguration->streamingSessionListReadLock); for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { status = writeFrame(pSampleConfiguration->sampleStreamingSessionList[i]->pVideoRtcRtpTransceiver, &frame); - pSampleConfiguration->sampleStreamingSessionList[i]->canaryOutgoingRTPMetricsContext.videoFramesGenerated++; - pSampleConfiguration->sampleStreamingSessionList[i]->canaryOutgoingRTPMetricsContext.videoBytesGenerated += frame.size; + pSampleConfiguration->sampleStreamingSessionList[i]->pStatsCtx->outgoingRTPStatsCtx.videoFramesGenerated++; + pSampleConfiguration->sampleStreamingSessionList[i]->pStatsCtx->outgoingRTPStatsCtx.videoBytesGenerated += frame.size; if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { PROFILE_WITH_START_TIME(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, "Time to first frame"); pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame = FALSE; diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 076565d192..18d76d0d9a 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -58,18 +58,21 @@ file(COPY "${CMAKE_CURRENT_SOURCE_DIR}/h265SampleFrames" DESTINATION .) add_executable( kvsWebrtcClientMaster - Common.c - Utility.c - MetricsHandling.c - kvsWebRTCClientMaster.c) + lib/Common.c + lib/Utility.c + lib/MetricsHandling.c + lib/DataChannelHandling.c + kvsWebRTCClientMaster.c) + target_link_libraries(kvsWebrtcClientMaster kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} kvsCommonLws kvspicUtils) add_executable( kvsWebrtcClientViewer - Common.c - Utility.c - MetricsHandling.c - kvsWebRTCClientViewer.c) + lib/Common.c + lib/Utility.c + lib/MetricsHandling.c + lib/DataChannelHandling.c + kvsWebRTCClientViewer.c) target_link_libraries(kvsWebrtcClientViewer kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} kvsCommonLws kvspicUtils) add_executable( @@ -80,11 +83,12 @@ target_link_libraries(discoverNatBehavior kvsWebrtcClient ${EXTRA_DEPS}) if(GST_FOUND) add_executable( kvsWebrtcClientMasterGstSample - Common.c - Utility.c - MetricsHandling.c - GstAudioVideoReceiver.c - kvsWebRTCClientMasterGstSample.c + lib/Common.c + lib/Utility.c + lib/MetricsHandling.c + GstAudioVideoReceiver.c + lib/DataChannelHandling.c + kvsWebRTCClientMasterGstSample.c ) target_link_libraries(kvsWebrtcClientMasterGstSample kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} ${GST_SAMPLE_LIBRARIES} kvsCommonLws kvspicUtils) @@ -94,11 +98,12 @@ if(GST_FOUND) add_executable( kvsWebrtcClientViewerGstSample - Common.c - Utility.c - MetricsHandling.c - GstAudioVideoReceiver.c - kvsWebRTCClientViewerGstSample.c + lib/Common.c + lib/Utility.c + lib/MetricsHandling.c + lib/DataChannelHandling.c + GstAudioVideoReceiver.c + kvsWebRTCClientViewerGstSample.c ) target_link_libraries(kvsWebrtcClientViewerGstSample kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} ${GST_SAMPLE_LIBRARIES} kvsCommonLws kvspicUtils) diff --git a/samples/Samples.h b/samples/Samples.h index 26336de3f3..269f1c6c18 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -13,6 +13,9 @@ extern "C" { #include #include SAMPLE_CONFIG_HEADER +#define KVS_DEFAULT_MEDIA_SENDER_THREAD_STACK_SIZE 64 * 1024 +#define KVS_MINIMUM_THREAD_STACK_SIZE 16 * 1024 + #define NUMBER_OF_H264_FRAME_FILES 1500 #define NUMBER_OF_H265_FRAME_FILES 1500 #define NUMBER_OF_OPUS_FRAME_FILES 618 @@ -199,7 +202,6 @@ typedef struct { typedef VOID (*StreamSessionShutdownCallback)(UINT64, PSampleStreamingSession); typedef struct { -<<<<<<< HEAD MUTEX updateLock; UINT64 lastAdjustmentTimeMs; UINT64 currentVideoBitrate; @@ -208,7 +210,8 @@ typedef struct { UINT64 newAudioBitrate; DOUBLE averagePacketLoss; } TwccMetadata, *PTwccMetadata; -======= + +typedef struct { UINT64 prevNumberOfPacketsSent; UINT64 prevNumberOfPacketsReceived; UINT64 prevNumberOfBytesSent; @@ -225,7 +228,9 @@ typedef struct { DOUBLE nacksPerSecond; DOUBLE averageFramesSentPerSecond; DOUBLE retxBytesPercentage; -} OutgoingRTPMetricsContext, *POutgoingRTPMetricsContext; + MUTEX outgoingRtpStatsLock; + BOOL recorded; +} OutgoingRTPStatsCtx, *POutgoingRTPStatsCtx; typedef struct { UINT64 prevPacketsReceived; @@ -235,9 +240,15 @@ typedef struct { DOUBLE packetReceiveRate; DOUBLE incomingBitRate; DOUBLE framesDroppedPerSecond; -} IncomingRTPMetricsContext; -typedef IncomingRTPMetricsContext* PIncomingRTPMetricsContext; ->>>>>>> e33503d182 (Initial commit:rtp stats, config file) + MUTEX incomingRtpStatsLock; +} IncomingRTPStatsCtx, *PIncomingRTPStatsCtx; + +typedef struct { + OutgoingRTPStatsCtx outgoingRTPStatsCtx; + IncomingRTPStatsCtx incomingRTPStatsCtx; + RtcStats kvsRtcStats; + MUTEX statsUpdateLock; +} StatsCtx, *PStatsCtx; struct __SampleStreamingSession { volatile ATOMIC_BOOL terminateFlag; @@ -269,10 +280,7 @@ struct __SampleStreamingSession { CHAR pPeerConnectionMetricsMessage[MAX_PEER_CONNECTION_METRICS_MESSAGE_SIZE]; CHAR pSignalingClientMetricsMessage[MAX_SIGNALING_CLIENT_METRICS_MESSAGE_SIZE]; CHAR pIceAgentMetricsMessage[MAX_ICE_AGENT_METRICS_MESSAGE_SIZE]; - OutgoingRTPMetricsContext canaryOutgoingRTPMetricsContext; - IncomingRTPMetricsContext canaryIncomingRTPMetricsContext; - RtcStats canaryMetrics; - BOOL recorded; + PStatsCtx pStatsCtx; }; // TODO this should all be in a higher webrtccontext layer above PeerConnection @@ -318,6 +326,8 @@ VOID sampleFrameHandler(UINT64, PFrame); VOID sampleBandwidthEstimationHandler(UINT64, DOUBLE); VOID sampleSenderBandwidthEstimationHandler(UINT64, UINT32, UINT32, UINT32, UINT32, UINT64); VOID onDataChannel(UINT64, PRtcDataChannel); +VOID onDataChannelMessage(UINT64, PRtcDataChannel, BOOL, PBYTE, UINT32); + VOID onConnectionStateChange(UINT64, RTC_PEER_CONNECTION_STATE); STATUS sessionCleanupWait(PSampleConfiguration); STATUS logSignalingClientStats(PSignalingClientMetrics); diff --git a/samples/Common.c b/samples/lib/Common.c similarity index 85% rename from samples/Common.c rename to samples/lib/Common.c index 756f4edd38..5b8353a544 100644 --- a/samples/Common.c +++ b/samples/lib/Common.c @@ -1,10 +1,7 @@ #define LOG_CLASS "WebRtcSamples" -#include "Samples.h" +#include "../Samples.h" #include SAMPLE_CONFIG_HEADER -#define KVS_DEFAULT_MEDIA_SENDER_THREAD_STACK_SIZE 64 * 1024 -#define KVS_MINIMUM_THREAD_STACK_SIZE 16 * 1024 - PSampleConfiguration gSampleConfiguration = NULL; VOID sigintHandler(INT32 sigNum) @@ -1589,180 +1586,4 @@ STATUS removeExpiredMessageQueues(PStackQueue pPendingQueue) CleanUp: return retStatus; -} - -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); -} +} \ No newline at end of file diff --git a/samples/lib/DataChannelHandling.c b/samples/lib/DataChannelHandling.c new file mode 100644 index 0000000000..7192105d90 --- /dev/null +++ b/samples/lib/DataChannelHandling.c @@ -0,0 +1,177 @@ +#include "../Samples.h" + +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); +} diff --git a/samples/Media.c b/samples/lib/Media.c similarity index 100% rename from samples/Media.c rename to samples/lib/Media.c diff --git a/samples/MetricsHandling.c b/samples/lib/MetricsHandling.c similarity index 60% rename from samples/MetricsHandling.c rename to samples/lib/MetricsHandling.c index caad79089f..849d9b2811 100644 --- a/samples/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -1,4 +1,14 @@ -#include "Samples.h" +#include "../Samples.h" + +STATUS setupMetricsCtx(PSampleStreamingSession pSampleStreamingSession) +{ + STATUS retStatus = STATUS_SUCCESS; + if (ENABLE_METRICS) { + CHK(NULL != (pSampleStreamingSession->pStatsCtx = (PStatsCtx) MEMCALLOC(1, SIZEOF(StatsCtx))), STATUS_NOT_ENOUGH_MEMORY); + } +CleanUp: + return retStatus; +} STATUS logSelectedIceCandidatesInformation(PSampleStreamingSession pSampleStreamingSession) { @@ -34,21 +44,28 @@ STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession) { ENTERS(); STATUS retStatus = STATUS_SUCCESS; - RtcStats rtcmetrics; UINT32 j = 0; - rtcmetrics.requestedTypeOfStats = RTC_STATS_TYPE_ICE_SERVER; + BOOL locked = TRUE; + CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up. Nothing to report"); + MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + locked = TRUE; + pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = RTC_STATS_TYPE_ICE_SERVER; for (; j < pSampleStreamingSession->pSampleConfiguration->iceUriCount; j++) { - rtcmetrics.rtcStatsObject.iceServerStats.iceServerIndex = j; - CHK_STATUS(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, NULL, &rtcmetrics)); - DLOGD("ICE Server URL: %s", rtcmetrics.rtcStatsObject.iceServerStats.url); - DLOGD("ICE Server port: %d", rtcmetrics.rtcStatsObject.iceServerStats.port); - DLOGD("ICE Server protocol: %s", rtcmetrics.rtcStatsObject.iceServerStats.protocol); - DLOGD("Total requests sent:%" PRIu64, rtcmetrics.rtcStatsObject.iceServerStats.totalRequestsSent); - DLOGD("Total responses received: %" PRIu64, rtcmetrics.rtcStatsObject.iceServerStats.totalResponsesReceived); + pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.iceServerIndex = j; + CHK_STATUS(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, NULL, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); + DLOGD("ICE Server URL: %s", pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.url); + DLOGD("ICE Server port: %d", pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.port); + DLOGD("ICE Server protocol: %s", pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.protocol); + DLOGD("Total requests sent:%" PRIu64, pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.totalRequestsSent); + DLOGD("Total responses received: %" PRIu64, + pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.totalResponsesReceived); DLOGD("Total round trip time: %" PRIu64 "ms", - rtcmetrics.rtcStatsObject.iceServerStats.totalRoundTripTime / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); + pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.totalRoundTripTime / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); + } +CleanUp: + if (locked) { + MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); } - CleanUp: LEAVES(); return retStatus; } @@ -160,38 +177,39 @@ STATUS populateOutgoingRtpMetricsContext(PSampleStreamingSession pSampleStreamin { DOUBLE currentDuration = 0; - currentDuration = (DOUBLE) (pSampleStreamingSession->canaryMetrics.timestamp - pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevTs) / + currentDuration = + (DOUBLE) (pSampleStreamingSession->pStatsCtx->kvsRtcStats.timestamp - pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.prevTs) / HUNDREDS_OF_NANOS_IN_A_SECOND; - pSampleStreamingSession->canaryOutgoingRTPMetricsContext.framesPercentageDiscarded = - ((DOUBLE) (pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.framesDiscardedOnSend - - pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevFramesDiscardedOnSend) / - (DOUBLE) pSampleStreamingSession->canaryOutgoingRTPMetricsContext.videoFramesGenerated) * + pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.framesPercentageDiscarded = + ((DOUBLE) (pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.outboundRtpStreamStats.framesDiscardedOnSend - + pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.prevFramesDiscardedOnSend) / + (DOUBLE) pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.videoFramesGenerated) * 100.0; - pSampleStreamingSession->canaryOutgoingRTPMetricsContext.retxBytesPercentage = - (((DOUBLE) pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.retransmittedBytesSent - - (DOUBLE) (pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevRetxBytesSent)) / - (DOUBLE) pSampleStreamingSession->canaryOutgoingRTPMetricsContext.videoBytesGenerated) * + pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.retxBytesPercentage = + (((DOUBLE) pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.outboundRtpStreamStats.retransmittedBytesSent - + (DOUBLE) (pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.prevRetxBytesSent)) / + (DOUBLE) pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.videoBytesGenerated) * 100.0; // This flag ensures the reset of video bytes count is done only when this flag is set - pSampleStreamingSession->recorded = TRUE; - pSampleStreamingSession->canaryOutgoingRTPMetricsContext.averageFramesSentPerSecond = - ((DOUBLE) (pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.framesSent - - (DOUBLE) pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevFramesSent)) / + pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.recorded = TRUE; + pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.averageFramesSentPerSecond = + ((DOUBLE) (pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.outboundRtpStreamStats.framesSent - + (DOUBLE) pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.prevFramesSent)) / currentDuration; - pSampleStreamingSession->canaryOutgoingRTPMetricsContext.nacksPerSecond = - ((DOUBLE) pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.nackCount - - pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevNackCount) / + pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.nacksPerSecond = + ((DOUBLE) pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.outboundRtpStreamStats.nackCount - + pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.prevNackCount) / currentDuration; - pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevFramesSent = - pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.framesSent; - pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevTs = pSampleStreamingSession->canaryMetrics.timestamp; - pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevFramesDiscardedOnSend = - pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.framesDiscardedOnSend; - pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevNackCount = - pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.nackCount; - pSampleStreamingSession->canaryOutgoingRTPMetricsContext.prevRetxBytesSent = - pSampleStreamingSession->canaryMetrics.rtcStatsObject.outboundRtpStreamStats.retransmittedBytesSent; + pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.prevFramesSent = + pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.outboundRtpStreamStats.framesSent; + pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.prevTs = pSampleStreamingSession->pStatsCtx->kvsRtcStats.timestamp; + pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.prevFramesDiscardedOnSend = + pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.outboundRtpStreamStats.framesDiscardedOnSend; + pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.prevNackCount = + pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.outboundRtpStreamStats.nackCount; + pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.prevRetxBytesSent = + pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.outboundRtpStreamStats.retransmittedBytesSent; return STATUS_SUCCESS; } @@ -199,29 +217,33 @@ STATUS populateOutgoingRtpMetricsContext(PSampleStreamingSession pSampleStreamin STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamingSession) { DOUBLE currentDuration = 0; - currentDuration = (DOUBLE) (pSampleStreamingSession->canaryMetrics.timestamp - pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevTs) / + STATUS retStatus = STATUS_SUCCESS; + CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up. Nothing to report"); + currentDuration = + (DOUBLE) (pSampleStreamingSession->pStatsCtx->kvsRtcStats.timestamp - pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.prevTs) / HUNDREDS_OF_NANOS_IN_A_SECOND; - pSampleStreamingSession->canaryIncomingRTPMetricsContext.packetReceiveRate = - (DOUBLE) (pSampleStreamingSession->canaryMetrics.rtcStatsObject.inboundRtpStreamStats.received.packetsReceived - - pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevPacketsReceived) / + pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.packetReceiveRate = + (DOUBLE) (pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.inboundRtpStreamStats.received.packetsReceived - + pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.prevPacketsReceived) / currentDuration; - pSampleStreamingSession->canaryIncomingRTPMetricsContext.incomingBitRate = - ((DOUBLE) (pSampleStreamingSession->canaryMetrics.rtcStatsObject.inboundRtpStreamStats.bytesReceived - - pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevBytesReceived) / + pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.incomingBitRate = + ((DOUBLE) (pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.inboundRtpStreamStats.bytesReceived - + pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.prevBytesReceived) / currentDuration) / 0.008; - pSampleStreamingSession->canaryIncomingRTPMetricsContext.framesDroppedPerSecond = - ((DOUBLE) pSampleStreamingSession->canaryMetrics.rtcStatsObject.inboundRtpStreamStats.received.framesDropped - - pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevFramesDropped) / + pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.framesDroppedPerSecond = + ((DOUBLE) pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.inboundRtpStreamStats.received.framesDropped - + pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.prevFramesDropped) / currentDuration; - pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevPacketsReceived = - pSampleStreamingSession->canaryMetrics.rtcStatsObject.inboundRtpStreamStats.received.packetsReceived; - pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevBytesReceived = - pSampleStreamingSession->canaryMetrics.rtcStatsObject.inboundRtpStreamStats.bytesReceived; - pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevFramesDropped = - pSampleStreamingSession->canaryMetrics.rtcStatsObject.inboundRtpStreamStats.received.framesDropped; - pSampleStreamingSession->canaryIncomingRTPMetricsContext.prevTs = pSampleStreamingSession->canaryMetrics.timestamp; + pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.prevPacketsReceived = + pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.inboundRtpStreamStats.received.packetsReceived; + pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.prevBytesReceived = + pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.inboundRtpStreamStats.bytesReceived; + pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.prevFramesDropped = + pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.inboundRtpStreamStats.received.framesDropped; + pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.prevTs = pSampleStreamingSession->pStatsCtx->kvsRtcStats.timestamp; - return STATUS_SUCCESS; +CleanUp: + return retStatus; } \ No newline at end of file diff --git a/samples/Utility.c b/samples/lib/Utility.c similarity index 97% rename from samples/Utility.c rename to samples/lib/Utility.c index 12d6f7fc13..8dfba21759 100644 --- a/samples/Utility.c +++ b/samples/lib/Utility.c @@ -1,4 +1,4 @@ -#include "Samples.h" +#include "../Samples.h" STATUS readFrameFromDisk(PBYTE pFrame, PUINT32 pSize, PCHAR frameFilePath) { diff --git a/samples/sample_config.h b/samples/sample_config.h index eea752d8a0..ea99bf1e8c 100644 --- a/samples/sample_config.h +++ b/samples/sample_config.h @@ -8,8 +8,6 @@ #define ENABLE_TTFF_VIA_DC FALSE #define IOT_CORE_ENABLE_CREDENTIALS FALSE #define ENABLE_STORAGE FALSE - - - +#define ENABLE_METRICS FALSE #endif // KVS_SDK_SAMPLE_CONFIG_H From e431aec7369666f800c108d848055dbcfd142f15 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Mon, 13 May 2024 16:25:59 -0700 Subject: [PATCH 06/64] Rearrange --- cloudwatch-integ/CMakeLists.txt | 2 + samples/CMakeLists.txt | 8 + samples/Samples.h | 2 + samples/lib/Common.c | 589 ------------------------------ samples/lib/Media.c | 42 +++ samples/lib/SignalingMsgHandler.c | 382 +++++++++++++++++++ samples/lib/Utility.c | 163 +++++++++ 7 files changed, 599 insertions(+), 589 deletions(-) create mode 100644 samples/lib/SignalingMsgHandler.c diff --git a/cloudwatch-integ/CMakeLists.txt b/cloudwatch-integ/CMakeLists.txt index 6918ae1ec9..3c4771fb31 100644 --- a/cloudwatch-integ/CMakeLists.txt +++ b/cloudwatch-integ/CMakeLists.txt @@ -18,6 +18,8 @@ add_executable( ../samples/lib/Utility.c ../samples/lib/MetricsHandling.c ../samples/lib/DataChannelHandling.c + ../samples/lib/SignalingMsgHandler.c + ../samples/lib/Media.c Cloudwatch.cpp CloudwatchLogs.cpp CloudwatchMonitoring.cpp diff --git a/samples/CMakeLists.txt b/samples/CMakeLists.txt index 18d76d0d9a..d2005dc57b 100644 --- a/samples/CMakeLists.txt +++ b/samples/CMakeLists.txt @@ -62,6 +62,8 @@ add_executable( lib/Utility.c lib/MetricsHandling.c lib/DataChannelHandling.c + lib/SignalingMsgHandler.c + lib/Media.c kvsWebRTCClientMaster.c) target_link_libraries(kvsWebrtcClientMaster kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} kvsCommonLws kvspicUtils) @@ -72,6 +74,8 @@ add_executable( lib/Utility.c lib/MetricsHandling.c lib/DataChannelHandling.c + lib/SignalingMsgHandler.c + lib/Media.c kvsWebRTCClientViewer.c) target_link_libraries(kvsWebrtcClientViewer kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} kvsCommonLws kvspicUtils) @@ -88,6 +92,8 @@ if(GST_FOUND) lib/MetricsHandling.c GstAudioVideoReceiver.c lib/DataChannelHandling.c + lib/SignalingMsgHandler.c + lib/Media.c kvsWebRTCClientMasterGstSample.c ) target_link_libraries(kvsWebrtcClientMasterGstSample kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} ${GST_SAMPLE_LIBRARIES} kvsCommonLws kvspicUtils) @@ -103,6 +109,8 @@ if(GST_FOUND) lib/MetricsHandling.c lib/DataChannelHandling.c GstAudioVideoReceiver.c + lib/SignalingMsgHandler.c + lib/Media.c kvsWebRTCClientViewerGstSample.c ) target_link_libraries(kvsWebrtcClientViewerGstSample kvsWebrtcClient kvsWebrtcSignalingClient ${EXTRA_DEPS} ${GST_SAMPLE_LIBRARIES} kvsCommonLws kvspicUtils) diff --git a/samples/Samples.h b/samples/Samples.h index 269f1c6c18..7c97f6a7de 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -345,6 +345,8 @@ UINT32 setLogLevel(); STATUS populateOutgoingRtpMetricsContext(PSampleStreamingSession pSampleStreamingSession); STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamingSession); STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession); +VOID onIceCandidateHandler(UINT64, PCHAR); +PVOID mediaSenderRoutine(PVOID); #ifdef __cplusplus } diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 5b8353a544..cda0bc117e 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -94,179 +94,6 @@ STATUS signalingClientError(UINT64 customData, STATUS status, PCHAR msg, UINT32 return STATUS_SUCCESS; } -STATUS handleAnswer(PSampleConfiguration pSampleConfiguration, PSampleStreamingSession pSampleStreamingSession, PSignalingMessage pSignalingMessage) -{ - UNUSED_PARAM(pSampleConfiguration); - STATUS retStatus = STATUS_SUCCESS; - PRtcSessionDescriptionInit pAnswerSessionDescriptionInit = NULL; - - pAnswerSessionDescriptionInit = (PRtcSessionDescriptionInit) MEMCALLOC(1, SIZEOF(RtcSessionDescriptionInit)); - - CHK_STATUS(deserializeSessionDescriptionInit(pSignalingMessage->payload, pSignalingMessage->payloadLen, pAnswerSessionDescriptionInit)); - CHK_STATUS(setRemoteDescription(pSampleStreamingSession->pPeerConnection, pAnswerSessionDescriptionInit)); - - // The audio video receive routine should be per streaming session - if (pSampleConfiguration->receiveAudioVideoSource != NULL) { - THREAD_CREATE(&pSampleStreamingSession->receiveAudioVideoSenderTid, pSampleConfiguration->receiveAudioVideoSource, - (PVOID) pSampleStreamingSession); - } -CleanUp: - - if (pAnswerSessionDescriptionInit != NULL) { - SAFE_MEMFREE(pAnswerSessionDescriptionInit); - } - - CHK_LOG_ERR(retStatus); - - return retStatus; -} - -PVOID mediaSenderRoutine(PVOID customData) -{ - STATUS retStatus = STATUS_SUCCESS; - PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; - CHK(pSampleConfiguration != NULL, STATUS_NULL_ARG); - pSampleConfiguration->videoSenderTid = INVALID_TID_VALUE; - pSampleConfiguration->audioSenderTid = INVALID_TID_VALUE; - - MUTEX_LOCK(pSampleConfiguration->sampleConfigurationObjLock); - while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->connected) && !ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { - CVAR_WAIT(pSampleConfiguration->cvar, pSampleConfiguration->sampleConfigurationObjLock, 5 * HUNDREDS_OF_NANOS_IN_A_SECOND); - } - MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); - - CHK(!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag), retStatus); - - if (pSampleConfiguration->videoSource != NULL) { - THREAD_CREATE_WITH_PARAMS(&pSampleConfiguration->videoSenderTid, pSampleConfiguration->videoSource, - KVS_DEFAULT_MEDIA_SENDER_THREAD_STACK_SIZE, (PVOID) pSampleConfiguration); - } - - if (pSampleConfiguration->audioSource != NULL) { - THREAD_CREATE_WITH_PARAMS(&pSampleConfiguration->audioSenderTid, pSampleConfiguration->audioSource, - KVS_DEFAULT_MEDIA_SENDER_THREAD_STACK_SIZE, (PVOID) pSampleConfiguration); - } - - if (pSampleConfiguration->videoSenderTid != INVALID_TID_VALUE) { - THREAD_JOIN(pSampleConfiguration->videoSenderTid, NULL); - } - - if (pSampleConfiguration->audioSenderTid != INVALID_TID_VALUE) { - THREAD_JOIN(pSampleConfiguration->audioSenderTid, NULL); - } - -CleanUp: - // clean the flag of the media thread. - ATOMIC_STORE_BOOL(&pSampleConfiguration->mediaThreadStarted, FALSE); - CHK_LOG_ERR(retStatus); - return NULL; -} - -STATUS handleOffer(PSampleConfiguration pSampleConfiguration, PSampleStreamingSession pSampleStreamingSession, PSignalingMessage pSignalingMessage) -{ - STATUS retStatus = STATUS_SUCCESS; - PRtcSessionDescriptionInit pOfferSessionDescriptionInit = NULL; - NullableBool canTrickle; - BOOL mediaThreadStarted; - - CHK(pSampleConfiguration != NULL && pSignalingMessage != NULL, STATUS_NULL_ARG); - - pOfferSessionDescriptionInit = (PRtcSessionDescriptionInit) MEMCALLOC(1, SIZEOF(RtcSessionDescriptionInit)); - MEMSET(&pSampleStreamingSession->answerSessionDescriptionInit, 0x00, SIZEOF(RtcSessionDescriptionInit)); - DLOGD("**offer:%s", pSignalingMessage->payload); - CHK_STATUS(deserializeSessionDescriptionInit(pSignalingMessage->payload, pSignalingMessage->payloadLen, pOfferSessionDescriptionInit)); - CHK_STATUS(setRemoteDescription(pSampleStreamingSession->pPeerConnection, pOfferSessionDescriptionInit)); - canTrickle = canTrickleIceCandidates(pSampleStreamingSession->pPeerConnection); - /* cannot be null after setRemoteDescription */ - CHECK(!NULLABLE_CHECK_EMPTY(canTrickle)); - pSampleStreamingSession->remoteCanTrickleIce = canTrickle.value; - CHK_STATUS(setLocalDescription(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->answerSessionDescriptionInit)); - - /* - * If remote support trickle ice, send answer now. Otherwise answer will be sent once ice candidate gathering is complete. - */ - if (pSampleStreamingSession->remoteCanTrickleIce) { - CHK_STATUS(createAnswer(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->answerSessionDescriptionInit)); - CHK_STATUS(respondWithAnswer(pSampleStreamingSession)); - } - - mediaThreadStarted = ATOMIC_EXCHANGE_BOOL(&pSampleConfiguration->mediaThreadStarted, TRUE); - if (!mediaThreadStarted) { - THREAD_CREATE_WITH_PARAMS(&pSampleConfiguration->mediaSenderTid, mediaSenderRoutine, KVS_MINIMUM_THREAD_STACK_SIZE, - (PVOID) pSampleConfiguration); - } - - // The audio video receive routine should be per streaming session - if (pSampleConfiguration->receiveAudioVideoSource != NULL) { - THREAD_CREATE(&pSampleStreamingSession->receiveAudioVideoSenderTid, pSampleConfiguration->receiveAudioVideoSource, - (PVOID) pSampleStreamingSession); - } -CleanUp: - if (pOfferSessionDescriptionInit != NULL) { - SAFE_MEMFREE(pOfferSessionDescriptionInit); - } - - CHK_LOG_ERR(retStatus); - - return retStatus; -} - -STATUS sendSignalingMessage(PSampleStreamingSession pSampleStreamingSession, PSignalingMessage pMessage) -{ - STATUS retStatus = STATUS_SUCCESS; - BOOL locked = FALSE; - PSampleConfiguration pSampleConfiguration; - // Validate the input params - CHK(pSampleStreamingSession != NULL && pSampleStreamingSession->pSampleConfiguration != NULL && pMessage != NULL, STATUS_NULL_ARG); - - pSampleConfiguration = pSampleStreamingSession->pSampleConfiguration; - - CHK(IS_VALID_MUTEX_VALUE(pSampleConfiguration->signalingSendMessageLock) && - IS_VALID_SIGNALING_CLIENT_HANDLE(pSampleConfiguration->signalingClientHandle), - STATUS_INVALID_OPERATION); - - MUTEX_LOCK(pSampleConfiguration->signalingSendMessageLock); - locked = TRUE; - CHK_STATUS(signalingClientSendMessageSync(pSampleConfiguration->signalingClientHandle, pMessage)); - if (pMessage->messageType == SIGNALING_MESSAGE_TYPE_ANSWER) { - CHK_STATUS(signalingClientGetMetrics(pSampleConfiguration->signalingClientHandle, &pSampleConfiguration->signalingClientMetrics)); - DLOGP("[Signaling offer received to answer sent time] %" PRIu64 " ms", - pSampleConfiguration->signalingClientMetrics.signalingClientStats.offerToAnswerTime); - } - -CleanUp: - - if (locked) { - MUTEX_UNLOCK(pSampleStreamingSession->pSampleConfiguration->signalingSendMessageLock); - } - - CHK_LOG_ERR(retStatus); - return retStatus; -} - -STATUS respondWithAnswer(PSampleStreamingSession pSampleStreamingSession) -{ - STATUS retStatus = STATUS_SUCCESS; - SignalingMessage message; - UINT32 buffLen = MAX_SIGNALING_MESSAGE_LEN; - - CHK_STATUS(serializeSessionDescriptionInit(&pSampleStreamingSession->answerSessionDescriptionInit, message.payload, &buffLen)); - - message.version = SIGNALING_MESSAGE_CURRENT_VERSION; - message.messageType = SIGNALING_MESSAGE_TYPE_ANSWER; - STRNCPY(message.peerClientId, pSampleStreamingSession->peerId, MAX_SIGNALING_CLIENT_ID_LEN); - message.payloadLen = (UINT32) STRLEN(message.payload); - // SNPRINTF appends null terminator, so we do not manually add it - SNPRINTF(message.correlationId, MAX_CORRELATION_ID_LEN, "%llu_%llu", GETTIME(), ATOMIC_INCREMENT(&pSampleStreamingSession->correlationIdPostFix)); - DLOGD("Responding With Answer With correlationId: %s", message.correlationId); - CHK_STATUS(sendSignalingMessage(pSampleStreamingSession, &message)); - -CleanUp: - - CHK_LOG_ERR(retStatus); - return retStatus; -} - BOOL sampleFilterNetworkInterfaces(UINT64 customData, PCHAR networkInt) { UNUSED_PARAM(customData); @@ -278,43 +105,6 @@ BOOL sampleFilterNetworkInterfaces(UINT64 customData, PCHAR networkInt) return useInterface; } -VOID onIceCandidateHandler(UINT64 customData, PCHAR candidateJson) -{ - STATUS retStatus = STATUS_SUCCESS; - PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; - SignalingMessage message; - - CHK(pSampleStreamingSession != NULL, STATUS_NULL_ARG); - - if (candidateJson == NULL) { - DLOGD("ice candidate gathering finished"); - ATOMIC_STORE_BOOL(&pSampleStreamingSession->candidateGatheringDone, TRUE); - - // if application is master and non-trickle ice, send answer now. - if (pSampleStreamingSession->pSampleConfiguration->channelInfo.channelRoleType == SIGNALING_CHANNEL_ROLE_TYPE_MASTER && - !pSampleStreamingSession->remoteCanTrickleIce) { - CHK_STATUS(createAnswer(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->answerSessionDescriptionInit)); - CHK_STATUS(respondWithAnswer(pSampleStreamingSession)); - } else if (pSampleStreamingSession->pSampleConfiguration->channelInfo.channelRoleType == SIGNALING_CHANNEL_ROLE_TYPE_VIEWER && - !pSampleStreamingSession->pSampleConfiguration->trickleIce) { - CVAR_BROADCAST(pSampleStreamingSession->pSampleConfiguration->cvar); - } - - } else if (pSampleStreamingSession->remoteCanTrickleIce && ATOMIC_LOAD_BOOL(&pSampleStreamingSession->peerIdReceived)) { - message.version = SIGNALING_MESSAGE_CURRENT_VERSION; - message.messageType = SIGNALING_MESSAGE_TYPE_ICE_CANDIDATE; - STRNCPY(message.peerClientId, pSampleStreamingSession->peerId, MAX_SIGNALING_CLIENT_ID_LEN); - message.payloadLen = (UINT32) STRNLEN(candidateJson, MAX_SIGNALING_MESSAGE_LEN); - STRNCPY(message.payload, candidateJson, message.payloadLen); - message.correlationId[0] = '\0'; - CHK_STATUS(sendSignalingMessage(pSampleStreamingSession, &message)); - } - -CleanUp: - - CHK_LOG_ERR(retStatus); -} - PVOID asyncGetIceConfigInfo(PVOID args) { STATUS retStatus = STATUS_SUCCESS; @@ -711,78 +501,6 @@ VOID sampleSenderBandwidthEstimationHandler(UINT64 customData, UINT32 txBytes, U videoBitrate, audioBitrate, txBytes, txPacketsCnt, rxBytes, rxPacketsCnt, duration / 10000ULL); } -STATUS handleRemoteCandidate(PSampleStreamingSession pSampleStreamingSession, PSignalingMessage pSignalingMessage) -{ - STATUS retStatus = STATUS_SUCCESS; - RtcIceCandidateInit iceCandidate; - CHK(pSampleStreamingSession != NULL && pSignalingMessage != NULL, STATUS_NULL_ARG); - - CHK_STATUS(deserializeRtcIceCandidateInit(pSignalingMessage->payload, pSignalingMessage->payloadLen, &iceCandidate)); - CHK_STATUS(addIceCandidate(pSampleStreamingSession->pPeerConnection, iceCandidate.candidate)); - -CleanUp: - - CHK_LOG_ERR(retStatus); - return retStatus; -} - -STATUS traverseDirectoryPEMFileScan(UINT64 customData, DIR_ENTRY_TYPES entryType, PCHAR fullPath, PCHAR fileName) -{ - UNUSED_PARAM(entryType); - UNUSED_PARAM(fullPath); - - PCHAR certName = (PCHAR) customData; - UINT32 fileNameLen = STRLEN(fileName); - - if (fileNameLen > ARRAY_SIZE(CA_CERT_PEM_FILE_EXTENSION) + 1 && - (STRCMPI(CA_CERT_PEM_FILE_EXTENSION, &fileName[fileNameLen - ARRAY_SIZE(CA_CERT_PEM_FILE_EXTENSION) + 1]) == 0)) { - certName[0] = FPATHSEPARATOR; - certName++; - STRCPY(certName, fileName); - } - - return STATUS_SUCCESS; -} - -STATUS lookForSslCert(PSampleConfiguration* ppSampleConfiguration) -{ - STATUS retStatus = STATUS_SUCCESS; - struct stat pathStat; - CHAR certName[MAX_PATH_LEN]; - PSampleConfiguration pSampleConfiguration = *ppSampleConfiguration; - - MEMSET(certName, 0x0, ARRAY_SIZE(certName)); - pSampleConfiguration->pCaCertPath = GETENV(CACERT_PATH_ENV_VAR); - - // if ca cert path is not set from the environment, try to use the one that cmake detected - if (pSampleConfiguration->pCaCertPath == NULL) { - CHK_ERR(STRNLEN(DEFAULT_KVS_CACERT_PATH, MAX_PATH_LEN) > 0, STATUS_INVALID_OPERATION, "No ca cert path given (error:%s)", strerror(errno)); - pSampleConfiguration->pCaCertPath = DEFAULT_KVS_CACERT_PATH; - } else { - // Check if the environment variable is a path - CHK(0 == FSTAT(pSampleConfiguration->pCaCertPath, &pathStat), STATUS_DIRECTORY_ENTRY_STAT_ERROR); - - if (S_ISDIR(pathStat.st_mode)) { - CHK_STATUS(traverseDirectory(pSampleConfiguration->pCaCertPath, (UINT64) &certName, /* iterate */ FALSE, traverseDirectoryPEMFileScan)); - - if (certName[0] != 0x0) { - STRCAT(pSampleConfiguration->pCaCertPath, certName); - } else { - DLOGW("Cert not found in path set...checking if CMake detected a path\n"); - CHK_ERR(STRNLEN(DEFAULT_KVS_CACERT_PATH, MAX_PATH_LEN) > 0, STATUS_INVALID_OPERATION, "No ca cert path given (error:%s)", - strerror(errno)); - DLOGI("CMake detected cert path\n"); - pSampleConfiguration->pCaCertPath = DEFAULT_KVS_CACERT_PATH; - } - } - } - -CleanUp: - - CHK_LOG_ERR(retStatus); - return retStatus; -} - STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE roleType, BOOL trickleIce, BOOL useTurn, UINT32 logLevel, PSampleConfiguration* ppSampleConfiguration) { @@ -1278,312 +996,5 @@ STATUS sessionCleanupWait(PSampleConfiguration pSampleConfiguration) } LEAVES(); - return retStatus; -} - -STATUS submitPendingIceCandidate(PPendingMessageQueue pPendingMessageQueue, PSampleStreamingSession pSampleStreamingSession) -{ - STATUS retStatus = STATUS_SUCCESS; - BOOL noPendingSignalingMessageForClient = FALSE; - PReceivedSignalingMessage pReceivedSignalingMessage = NULL; - UINT64 hashValue; - - CHK(pPendingMessageQueue != NULL && pPendingMessageQueue->messageQueue != NULL && pSampleStreamingSession != NULL, STATUS_NULL_ARG); - - do { - CHK_STATUS(stackQueueIsEmpty(pPendingMessageQueue->messageQueue, &noPendingSignalingMessageForClient)); - if (!noPendingSignalingMessageForClient) { - hashValue = 0; - CHK_STATUS(stackQueueDequeue(pPendingMessageQueue->messageQueue, &hashValue)); - pReceivedSignalingMessage = (PReceivedSignalingMessage) hashValue; - CHK(pReceivedSignalingMessage != NULL, STATUS_INTERNAL_ERROR); - if (pReceivedSignalingMessage->signalingMessage.messageType == SIGNALING_MESSAGE_TYPE_ICE_CANDIDATE) { - CHK_STATUS(handleRemoteCandidate(pSampleStreamingSession, &pReceivedSignalingMessage->signalingMessage)); - } - SAFE_MEMFREE(pReceivedSignalingMessage); - } - } while (!noPendingSignalingMessageForClient); - - CHK_STATUS(freeMessageQueue(pPendingMessageQueue)); - -CleanUp: - - SAFE_MEMFREE(pReceivedSignalingMessage); - CHK_LOG_ERR(retStatus); - return retStatus; -} - -STATUS signalingMessageReceived(UINT64 customData, PReceivedSignalingMessage pReceivedSignalingMessage) -{ - STATUS retStatus = STATUS_SUCCESS; - PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; - BOOL peerConnectionFound = FALSE, locked = FALSE, startStats = FALSE, freeStreamingSession = FALSE; - UINT32 clientIdHash; - UINT64 hashValue = 0; - PPendingMessageQueue pPendingMessageQueue = NULL; - PSampleStreamingSession pSampleStreamingSession = NULL; - PReceivedSignalingMessage pReceivedSignalingMessageCopy = NULL; - - CHK(pSampleConfiguration != NULL, STATUS_NULL_ARG); - - MUTEX_LOCK(pSampleConfiguration->sampleConfigurationObjLock); - locked = TRUE; - - clientIdHash = COMPUTE_CRC32((PBYTE) pReceivedSignalingMessage->signalingMessage.peerClientId, - (UINT32) STRLEN(pReceivedSignalingMessage->signalingMessage.peerClientId)); - CHK_STATUS(hashTableContains(pSampleConfiguration->pRtcPeerConnectionForRemoteClient, clientIdHash, &peerConnectionFound)); - if (peerConnectionFound) { - CHK_STATUS(hashTableGet(pSampleConfiguration->pRtcPeerConnectionForRemoteClient, clientIdHash, &hashValue)); - pSampleStreamingSession = (PSampleStreamingSession) hashValue; - } - - switch (pReceivedSignalingMessage->signalingMessage.messageType) { - case SIGNALING_MESSAGE_TYPE_OFFER: - // Check if we already have an ongoing master session with the same peer - CHK_ERR(!peerConnectionFound, STATUS_INVALID_OPERATION, "Peer connection %s is in progress", - pReceivedSignalingMessage->signalingMessage.peerClientId); - - /* - * Create new streaming session for each offer, then insert the client id and streaming session into - * pRtcPeerConnectionForRemoteClient for subsequent ice candidate messages. Lastly check if there is - * any ice candidate messages queued in pPendingSignalingMessageForRemoteClient. If so then submit - * all of them. - */ - - if (pSampleConfiguration->streamingSessionCount == ARRAY_SIZE(pSampleConfiguration->sampleStreamingSessionList)) { - DLOGW("Max simultaneous streaming session count reached."); - - // Need to remove the pending queue if any. - // This is a simple optimization as the session cleanup will - // handle the cleanup of pending message queue after a while - CHK_STATUS(getPendingMessageQueueForHash(pSampleConfiguration->pPendingSignalingMessageForRemoteClient, clientIdHash, TRUE, - &pPendingMessageQueue)); - - CHK(FALSE, retStatus); - } - CHK_STATUS(createSampleStreamingSession(pSampleConfiguration, pReceivedSignalingMessage->signalingMessage.peerClientId, TRUE, - &pSampleStreamingSession)); - freeStreamingSession = TRUE; - CHK_STATUS(handleOffer(pSampleConfiguration, pSampleStreamingSession, &pReceivedSignalingMessage->signalingMessage)); - CHK_STATUS(hashTablePut(pSampleConfiguration->pRtcPeerConnectionForRemoteClient, clientIdHash, (UINT64) pSampleStreamingSession)); - - // If there are any ice candidate messages in the queue for this client id, submit them now. - CHK_STATUS(getPendingMessageQueueForHash(pSampleConfiguration->pPendingSignalingMessageForRemoteClient, clientIdHash, TRUE, - &pPendingMessageQueue)); - if (pPendingMessageQueue != NULL) { - CHK_STATUS(submitPendingIceCandidate(pPendingMessageQueue, pSampleStreamingSession)); - - // NULL the pointer to avoid it being freed in the cleanup - pPendingMessageQueue = NULL; - } - - MUTEX_LOCK(pSampleConfiguration->streamingSessionListReadLock); - pSampleConfiguration->sampleStreamingSessionList[pSampleConfiguration->streamingSessionCount++] = pSampleStreamingSession; - MUTEX_UNLOCK(pSampleConfiguration->streamingSessionListReadLock); - freeStreamingSession = FALSE; - - startStats = pSampleConfiguration->iceCandidatePairStatsTimerId == MAX_UINT32; - break; - - case SIGNALING_MESSAGE_TYPE_ANSWER: - /* - * for viewer, pSampleStreamingSession should've already been created. insert the client id and - * streaming session into pRtcPeerConnectionForRemoteClient for subsequent ice candidate messages. - * Lastly check if there is any ice candidate messages queued in pPendingSignalingMessageForRemoteClient. - * If so then submit all of them. - */ - pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; - CHK_STATUS(handleAnswer(pSampleConfiguration, pSampleStreamingSession, &pReceivedSignalingMessage->signalingMessage)); - CHK_STATUS(hashTablePut(pSampleConfiguration->pRtcPeerConnectionForRemoteClient, clientIdHash, (UINT64) pSampleStreamingSession)); - - // If there are any ice candidate messages in the queue for this client id, submit them now. - CHK_STATUS(getPendingMessageQueueForHash(pSampleConfiguration->pPendingSignalingMessageForRemoteClient, clientIdHash, TRUE, - &pPendingMessageQueue)); - if (pPendingMessageQueue != NULL) { - CHK_STATUS(submitPendingIceCandidate(pPendingMessageQueue, pSampleStreamingSession)); - - // NULL the pointer to avoid it being freed in the cleanup - pPendingMessageQueue = NULL; - } - - startStats = pSampleConfiguration->iceCandidatePairStatsTimerId == MAX_UINT32; - CHK_STATUS(signalingClientGetMetrics(pSampleConfiguration->signalingClientHandle, &pSampleConfiguration->signalingClientMetrics)); - DLOGP("[Signaling offer sent to answer received time] %" PRIu64 " ms", - pSampleConfiguration->signalingClientMetrics.signalingClientStats.offerToAnswerTime); - break; - - case SIGNALING_MESSAGE_TYPE_ICE_CANDIDATE: - /* - * if peer connection hasn't been created, create an queue to store the ice candidate message. Otherwise - * submit the signaling message into the corresponding streaming session. - */ - if (!peerConnectionFound) { - CHK_STATUS(getPendingMessageQueueForHash(pSampleConfiguration->pPendingSignalingMessageForRemoteClient, clientIdHash, FALSE, - &pPendingMessageQueue)); - if (pPendingMessageQueue == NULL) { - CHK_STATUS(createMessageQueue(clientIdHash, &pPendingMessageQueue)); - CHK_STATUS(stackQueueEnqueue(pSampleConfiguration->pPendingSignalingMessageForRemoteClient, (UINT64) pPendingMessageQueue)); - } - - pReceivedSignalingMessageCopy = (PReceivedSignalingMessage) MEMCALLOC(1, SIZEOF(ReceivedSignalingMessage)); - - *pReceivedSignalingMessageCopy = *pReceivedSignalingMessage; - - CHK_STATUS(stackQueueEnqueue(pPendingMessageQueue->messageQueue, (UINT64) pReceivedSignalingMessageCopy)); - - // NULL the pointers to not free any longer - pPendingMessageQueue = NULL; - pReceivedSignalingMessageCopy = NULL; - } else { - CHK_STATUS(handleRemoteCandidate(pSampleStreamingSession, &pReceivedSignalingMessage->signalingMessage)); - } - break; - - default: - DLOGD("Unhandled signaling message type %u", pReceivedSignalingMessage->signalingMessage.messageType); - break; - } - - MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); - locked = FALSE; - - if (pSampleConfiguration->enableIceStats && startStats && - STATUS_FAILED(retStatus = timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, SAMPLE_STATS_DURATION, SAMPLE_STATS_DURATION, - getIceCandidatePairStatsCallback, (UINT64) pSampleConfiguration, - &pSampleConfiguration->iceCandidatePairStatsTimerId))) { - DLOGW("Failed to add getIceCandidatePairStatsCallback to add to timer queue (code 0x%08x). " - "Cannot pull ice candidate pair metrics periodically", - retStatus); - - // Reset the returned status - retStatus = STATUS_SUCCESS; - } - -CleanUp: - - SAFE_MEMFREE(pReceivedSignalingMessageCopy); - if (pPendingMessageQueue != NULL) { - freeMessageQueue(pPendingMessageQueue); - } - - if (freeStreamingSession && pSampleStreamingSession != NULL) { - freeSampleStreamingSession(&pSampleStreamingSession); - } - - if (locked) { - MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); - } - - CHK_LOG_ERR(retStatus); - return retStatus; -} - -STATUS createMessageQueue(UINT64 hashValue, PPendingMessageQueue* ppPendingMessageQueue) -{ - STATUS retStatus = STATUS_SUCCESS; - PPendingMessageQueue pPendingMessageQueue = NULL; - - CHK(ppPendingMessageQueue != NULL, STATUS_NULL_ARG); - - CHK(NULL != (pPendingMessageQueue = (PPendingMessageQueue) MEMCALLOC(1, SIZEOF(PendingMessageQueue))), STATUS_NOT_ENOUGH_MEMORY); - pPendingMessageQueue->hashValue = hashValue; - pPendingMessageQueue->createTime = GETTIME(); - CHK_STATUS(stackQueueCreate(&pPendingMessageQueue->messageQueue)); - -CleanUp: - - if (STATUS_FAILED(retStatus) && pPendingMessageQueue != NULL) { - freeMessageQueue(pPendingMessageQueue); - pPendingMessageQueue = NULL; - } - - if (ppPendingMessageQueue != NULL) { - *ppPendingMessageQueue = pPendingMessageQueue; - } - - return retStatus; -} - -STATUS freeMessageQueue(PPendingMessageQueue pPendingMessageQueue) -{ - STATUS retStatus = STATUS_SUCCESS; - - // free is idempotent - CHK(pPendingMessageQueue != NULL, retStatus); - - if (pPendingMessageQueue->messageQueue != NULL) { - stackQueueClear(pPendingMessageQueue->messageQueue, TRUE); - stackQueueFree(pPendingMessageQueue->messageQueue); - } - - MEMFREE(pPendingMessageQueue); - -CleanUp: - return retStatus; -} - -STATUS getPendingMessageQueueForHash(PStackQueue pPendingQueue, UINT64 clientHash, BOOL remove, PPendingMessageQueue* ppPendingMessageQueue) -{ - STATUS retStatus = STATUS_SUCCESS; - PPendingMessageQueue pPendingMessageQueue = NULL; - StackQueueIterator iterator; - BOOL iterate = TRUE; - UINT64 data; - - CHK(pPendingQueue != NULL && ppPendingMessageQueue != NULL, STATUS_NULL_ARG); - - CHK_STATUS(stackQueueGetIterator(pPendingQueue, &iterator)); - while (iterate && IS_VALID_ITERATOR(iterator)) { - CHK_STATUS(stackQueueIteratorGetItem(iterator, &data)); - CHK_STATUS(stackQueueIteratorNext(&iterator)); - - pPendingMessageQueue = (PPendingMessageQueue) data; - - if (clientHash == pPendingMessageQueue->hashValue) { - *ppPendingMessageQueue = pPendingMessageQueue; - iterate = FALSE; - - // Check if the item needs to be removed - if (remove) { - // This is OK to do as we are terminating the iterator anyway - CHK_STATUS(stackQueueRemoveItem(pPendingQueue, data)); - } - } - } - -CleanUp: - - return retStatus; -} - -STATUS removeExpiredMessageQueues(PStackQueue pPendingQueue) -{ - STATUS retStatus = STATUS_SUCCESS; - PPendingMessageQueue pPendingMessageQueue = NULL; - UINT32 i, count; - UINT64 data, curTime; - - CHK(pPendingQueue != NULL, STATUS_NULL_ARG); - - curTime = GETTIME(); - CHK_STATUS(stackQueueGetCount(pPendingQueue, &count)); - - // Dequeue and enqueue in order to not break the iterator while removing an item - for (i = 0; i < count; i++) { - CHK_STATUS(stackQueueDequeue(pPendingQueue, &data)); - - // Check for expiry - pPendingMessageQueue = (PPendingMessageQueue) data; - if (pPendingMessageQueue->createTime + SAMPLE_PENDING_MESSAGE_CLEANUP_DURATION < curTime) { - // Message queue has expired and needs to be freed - CHK_STATUS(freeMessageQueue(pPendingMessageQueue)); - } else { - // Enqueue back again as it's still valued - CHK_STATUS(stackQueueEnqueue(pPendingQueue, data)); - } - } - -CleanUp: - return retStatus; } \ No newline at end of file diff --git a/samples/lib/Media.c b/samples/lib/Media.c index e69de29bb2..71582a08cd 100644 --- a/samples/lib/Media.c +++ b/samples/lib/Media.c @@ -0,0 +1,42 @@ +#include "../Samples.h" + +PVOID mediaSenderRoutine(PVOID customData) +{ + STATUS retStatus = STATUS_SUCCESS; + PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; + CHK(pSampleConfiguration != NULL, STATUS_NULL_ARG); + pSampleConfiguration->videoSenderTid = INVALID_TID_VALUE; + pSampleConfiguration->audioSenderTid = INVALID_TID_VALUE; + + MUTEX_LOCK(pSampleConfiguration->sampleConfigurationObjLock); + while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->connected) && !ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { + CVAR_WAIT(pSampleConfiguration->cvar, pSampleConfiguration->sampleConfigurationObjLock, 5 * HUNDREDS_OF_NANOS_IN_A_SECOND); + } + MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); + + CHK(!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag), retStatus); + + if (pSampleConfiguration->videoSource != NULL) { + THREAD_CREATE_WITH_PARAMS(&pSampleConfiguration->videoSenderTid, pSampleConfiguration->videoSource, + KVS_DEFAULT_MEDIA_SENDER_THREAD_STACK_SIZE, (PVOID) pSampleConfiguration); + } + + if (pSampleConfiguration->audioSource != NULL) { + THREAD_CREATE_WITH_PARAMS(&pSampleConfiguration->audioSenderTid, pSampleConfiguration->audioSource, + KVS_DEFAULT_MEDIA_SENDER_THREAD_STACK_SIZE, (PVOID) pSampleConfiguration); + } + + if (pSampleConfiguration->videoSenderTid != INVALID_TID_VALUE) { + THREAD_JOIN(pSampleConfiguration->videoSenderTid, NULL); + } + + if (pSampleConfiguration->audioSenderTid != INVALID_TID_VALUE) { + THREAD_JOIN(pSampleConfiguration->audioSenderTid, NULL); + } + +CleanUp: + // clean the flag of the media thread. + ATOMIC_STORE_BOOL(&pSampleConfiguration->mediaThreadStarted, FALSE); + CHK_LOG_ERR(retStatus); + return NULL; +} \ No newline at end of file diff --git a/samples/lib/SignalingMsgHandler.c b/samples/lib/SignalingMsgHandler.c new file mode 100644 index 0000000000..60ca6613b0 --- /dev/null +++ b/samples/lib/SignalingMsgHandler.c @@ -0,0 +1,382 @@ +#include "../Samples.h" + +STATUS handleAnswer(PSampleConfiguration pSampleConfiguration, PSampleStreamingSession pSampleStreamingSession, PSignalingMessage pSignalingMessage) +{ + UNUSED_PARAM(pSampleConfiguration); + STATUS retStatus = STATUS_SUCCESS; + PRtcSessionDescriptionInit pAnswerSessionDescriptionInit = NULL; + + pAnswerSessionDescriptionInit = (PRtcSessionDescriptionInit) MEMCALLOC(1, SIZEOF(RtcSessionDescriptionInit)); + + CHK_STATUS(deserializeSessionDescriptionInit(pSignalingMessage->payload, pSignalingMessage->payloadLen, pAnswerSessionDescriptionInit)); + CHK_STATUS(setRemoteDescription(pSampleStreamingSession->pPeerConnection, pAnswerSessionDescriptionInit)); + + // The audio video receive routine should be per streaming session + if (pSampleConfiguration->receiveAudioVideoSource != NULL) { + THREAD_CREATE(&pSampleStreamingSession->receiveAudioVideoSenderTid, pSampleConfiguration->receiveAudioVideoSource, + (PVOID) pSampleStreamingSession); + } +CleanUp: + + if (pAnswerSessionDescriptionInit != NULL) { + SAFE_MEMFREE(pAnswerSessionDescriptionInit); + } + + CHK_LOG_ERR(retStatus); + + return retStatus; +} + +STATUS handleOffer(PSampleConfiguration pSampleConfiguration, PSampleStreamingSession pSampleStreamingSession, PSignalingMessage pSignalingMessage) +{ + STATUS retStatus = STATUS_SUCCESS; + PRtcSessionDescriptionInit pOfferSessionDescriptionInit = NULL; + NullableBool canTrickle; + BOOL mediaThreadStarted; + + CHK(pSampleConfiguration != NULL && pSignalingMessage != NULL, STATUS_NULL_ARG); + + pOfferSessionDescriptionInit = (PRtcSessionDescriptionInit) MEMCALLOC(1, SIZEOF(RtcSessionDescriptionInit)); + MEMSET(&pSampleStreamingSession->answerSessionDescriptionInit, 0x00, SIZEOF(RtcSessionDescriptionInit)); + DLOGD("**offer:%s", pSignalingMessage->payload); + CHK_STATUS(deserializeSessionDescriptionInit(pSignalingMessage->payload, pSignalingMessage->payloadLen, pOfferSessionDescriptionInit)); + CHK_STATUS(setRemoteDescription(pSampleStreamingSession->pPeerConnection, pOfferSessionDescriptionInit)); + canTrickle = canTrickleIceCandidates(pSampleStreamingSession->pPeerConnection); + /* cannot be null after setRemoteDescription */ + CHECK(!NULLABLE_CHECK_EMPTY(canTrickle)); + pSampleStreamingSession->remoteCanTrickleIce = canTrickle.value; + CHK_STATUS(setLocalDescription(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->answerSessionDescriptionInit)); + + /* + * If remote support trickle ice, send answer now. Otherwise answer will be sent once ice candidate gathering is complete. + */ + if (pSampleStreamingSession->remoteCanTrickleIce) { + CHK_STATUS(createAnswer(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->answerSessionDescriptionInit)); + CHK_STATUS(respondWithAnswer(pSampleStreamingSession)); + } + + mediaThreadStarted = ATOMIC_EXCHANGE_BOOL(&pSampleConfiguration->mediaThreadStarted, TRUE); + if (!mediaThreadStarted) { + THREAD_CREATE_WITH_PARAMS(&pSampleConfiguration->mediaSenderTid, mediaSenderRoutine, KVS_MINIMUM_THREAD_STACK_SIZE, + (PVOID) pSampleConfiguration); + } + + // The audio video receive routine should be per streaming session + if (pSampleConfiguration->receiveAudioVideoSource != NULL) { + THREAD_CREATE(&pSampleStreamingSession->receiveAudioVideoSenderTid, pSampleConfiguration->receiveAudioVideoSource, + (PVOID) pSampleStreamingSession); + } +CleanUp: + if (pOfferSessionDescriptionInit != NULL) { + SAFE_MEMFREE(pOfferSessionDescriptionInit); + } + + CHK_LOG_ERR(retStatus); + + return retStatus; +} + +STATUS sendSignalingMessage(PSampleStreamingSession pSampleStreamingSession, PSignalingMessage pMessage) +{ + STATUS retStatus = STATUS_SUCCESS; + BOOL locked = FALSE; + PSampleConfiguration pSampleConfiguration; + // Validate the input params + CHK(pSampleStreamingSession != NULL && pSampleStreamingSession->pSampleConfiguration != NULL && pMessage != NULL, STATUS_NULL_ARG); + + pSampleConfiguration = pSampleStreamingSession->pSampleConfiguration; + + CHK(IS_VALID_MUTEX_VALUE(pSampleConfiguration->signalingSendMessageLock) && + IS_VALID_SIGNALING_CLIENT_HANDLE(pSampleConfiguration->signalingClientHandle), + STATUS_INVALID_OPERATION); + + MUTEX_LOCK(pSampleConfiguration->signalingSendMessageLock); + locked = TRUE; + CHK_STATUS(signalingClientSendMessageSync(pSampleConfiguration->signalingClientHandle, pMessage)); + if (pMessage->messageType == SIGNALING_MESSAGE_TYPE_ANSWER) { + CHK_STATUS(signalingClientGetMetrics(pSampleConfiguration->signalingClientHandle, &pSampleConfiguration->signalingClientMetrics)); + DLOGP("[Signaling offer received to answer sent time] %" PRIu64 " ms", + pSampleConfiguration->signalingClientMetrics.signalingClientStats.offerToAnswerTime); + } + +CleanUp: + + if (locked) { + MUTEX_UNLOCK(pSampleStreamingSession->pSampleConfiguration->signalingSendMessageLock); + } + + CHK_LOG_ERR(retStatus); + return retStatus; +} + +STATUS respondWithAnswer(PSampleStreamingSession pSampleStreamingSession) +{ + STATUS retStatus = STATUS_SUCCESS; + SignalingMessage message; + UINT32 buffLen = MAX_SIGNALING_MESSAGE_LEN; + + CHK_STATUS(serializeSessionDescriptionInit(&pSampleStreamingSession->answerSessionDescriptionInit, message.payload, &buffLen)); + + message.version = SIGNALING_MESSAGE_CURRENT_VERSION; + message.messageType = SIGNALING_MESSAGE_TYPE_ANSWER; + STRNCPY(message.peerClientId, pSampleStreamingSession->peerId, MAX_SIGNALING_CLIENT_ID_LEN); + message.payloadLen = (UINT32) STRLEN(message.payload); + // SNPRINTF appends null terminator, so we do not manually add it + SNPRINTF(message.correlationId, MAX_CORRELATION_ID_LEN, "%llu_%llu", GETTIME(), ATOMIC_INCREMENT(&pSampleStreamingSession->correlationIdPostFix)); + DLOGD("Responding With Answer With correlationId: %s", message.correlationId); + CHK_STATUS(sendSignalingMessage(pSampleStreamingSession, &message)); + +CleanUp: + + CHK_LOG_ERR(retStatus); + return retStatus; +} + +VOID onIceCandidateHandler(UINT64 customData, PCHAR candidateJson) +{ + STATUS retStatus = STATUS_SUCCESS; + PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; + SignalingMessage message; + + CHK(pSampleStreamingSession != NULL, STATUS_NULL_ARG); + + if (candidateJson == NULL) { + DLOGD("ice candidate gathering finished"); + ATOMIC_STORE_BOOL(&pSampleStreamingSession->candidateGatheringDone, TRUE); + + // if application is master and non-trickle ice, send answer now. + if (pSampleStreamingSession->pSampleConfiguration->channelInfo.channelRoleType == SIGNALING_CHANNEL_ROLE_TYPE_MASTER && + !pSampleStreamingSession->remoteCanTrickleIce) { + CHK_STATUS(createAnswer(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->answerSessionDescriptionInit)); + CHK_STATUS(respondWithAnswer(pSampleStreamingSession)); + } else if (pSampleStreamingSession->pSampleConfiguration->channelInfo.channelRoleType == SIGNALING_CHANNEL_ROLE_TYPE_VIEWER && + !pSampleStreamingSession->pSampleConfiguration->trickleIce) { + CVAR_BROADCAST(pSampleStreamingSession->pSampleConfiguration->cvar); + } + + } else if (pSampleStreamingSession->remoteCanTrickleIce && ATOMIC_LOAD_BOOL(&pSampleStreamingSession->peerIdReceived)) { + message.version = SIGNALING_MESSAGE_CURRENT_VERSION; + message.messageType = SIGNALING_MESSAGE_TYPE_ICE_CANDIDATE; + STRNCPY(message.peerClientId, pSampleStreamingSession->peerId, MAX_SIGNALING_CLIENT_ID_LEN); + message.payloadLen = (UINT32) STRNLEN(candidateJson, MAX_SIGNALING_MESSAGE_LEN); + STRNCPY(message.payload, candidateJson, message.payloadLen); + message.correlationId[0] = '\0'; + CHK_STATUS(sendSignalingMessage(pSampleStreamingSession, &message)); + } + +CleanUp: + + CHK_LOG_ERR(retStatus); +} + +STATUS submitPendingIceCandidate(PPendingMessageQueue pPendingMessageQueue, PSampleStreamingSession pSampleStreamingSession) +{ + STATUS retStatus = STATUS_SUCCESS; + BOOL noPendingSignalingMessageForClient = FALSE; + PReceivedSignalingMessage pReceivedSignalingMessage = NULL; + UINT64 hashValue; + + CHK(pPendingMessageQueue != NULL && pPendingMessageQueue->messageQueue != NULL && pSampleStreamingSession != NULL, STATUS_NULL_ARG); + + do { + CHK_STATUS(stackQueueIsEmpty(pPendingMessageQueue->messageQueue, &noPendingSignalingMessageForClient)); + if (!noPendingSignalingMessageForClient) { + hashValue = 0; + CHK_STATUS(stackQueueDequeue(pPendingMessageQueue->messageQueue, &hashValue)); + pReceivedSignalingMessage = (PReceivedSignalingMessage) hashValue; + CHK(pReceivedSignalingMessage != NULL, STATUS_INTERNAL_ERROR); + if (pReceivedSignalingMessage->signalingMessage.messageType == SIGNALING_MESSAGE_TYPE_ICE_CANDIDATE) { + CHK_STATUS(handleRemoteCandidate(pSampleStreamingSession, &pReceivedSignalingMessage->signalingMessage)); + } + SAFE_MEMFREE(pReceivedSignalingMessage); + } + } while (!noPendingSignalingMessageForClient); + + CHK_STATUS(freeMessageQueue(pPendingMessageQueue)); + +CleanUp: + + SAFE_MEMFREE(pReceivedSignalingMessage); + CHK_LOG_ERR(retStatus); + return retStatus; +} + +STATUS signalingMessageReceived(UINT64 customData, PReceivedSignalingMessage pReceivedSignalingMessage) +{ + STATUS retStatus = STATUS_SUCCESS; + PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; + BOOL peerConnectionFound = FALSE, locked = FALSE, startStats = FALSE, freeStreamingSession = FALSE; + UINT32 clientIdHash; + UINT64 hashValue = 0; + PPendingMessageQueue pPendingMessageQueue = NULL; + PSampleStreamingSession pSampleStreamingSession = NULL; + PReceivedSignalingMessage pReceivedSignalingMessageCopy = NULL; + + CHK(pSampleConfiguration != NULL, STATUS_NULL_ARG); + + MUTEX_LOCK(pSampleConfiguration->sampleConfigurationObjLock); + locked = TRUE; + + clientIdHash = COMPUTE_CRC32((PBYTE) pReceivedSignalingMessage->signalingMessage.peerClientId, + (UINT32) STRLEN(pReceivedSignalingMessage->signalingMessage.peerClientId)); + CHK_STATUS(hashTableContains(pSampleConfiguration->pRtcPeerConnectionForRemoteClient, clientIdHash, &peerConnectionFound)); + if (peerConnectionFound) { + CHK_STATUS(hashTableGet(pSampleConfiguration->pRtcPeerConnectionForRemoteClient, clientIdHash, &hashValue)); + pSampleStreamingSession = (PSampleStreamingSession) hashValue; + } + + switch (pReceivedSignalingMessage->signalingMessage.messageType) { + case SIGNALING_MESSAGE_TYPE_OFFER: + // Check if we already have an ongoing master session with the same peer + CHK_ERR(!peerConnectionFound, STATUS_INVALID_OPERATION, "Peer connection %s is in progress", + pReceivedSignalingMessage->signalingMessage.peerClientId); + + /* + * Create new streaming session for each offer, then insert the client id and streaming session into + * pRtcPeerConnectionForRemoteClient for subsequent ice candidate messages. Lastly check if there is + * any ice candidate messages queued in pPendingSignalingMessageForRemoteClient. If so then submit + * all of them. + */ + + if (pSampleConfiguration->streamingSessionCount == ARRAY_SIZE(pSampleConfiguration->sampleStreamingSessionList)) { + DLOGW("Max simultaneous streaming session count reached."); + + // Need to remove the pending queue if any. + // This is a simple optimization as the session cleanup will + // handle the cleanup of pending message queue after a while + CHK_STATUS(getPendingMessageQueueForHash(pSampleConfiguration->pPendingSignalingMessageForRemoteClient, clientIdHash, TRUE, + &pPendingMessageQueue)); + + CHK(FALSE, retStatus); + } + CHK_STATUS(createSampleStreamingSession(pSampleConfiguration, pReceivedSignalingMessage->signalingMessage.peerClientId, TRUE, + &pSampleStreamingSession)); + freeStreamingSession = TRUE; + CHK_STATUS(handleOffer(pSampleConfiguration, pSampleStreamingSession, &pReceivedSignalingMessage->signalingMessage)); + CHK_STATUS(hashTablePut(pSampleConfiguration->pRtcPeerConnectionForRemoteClient, clientIdHash, (UINT64) pSampleStreamingSession)); + + // If there are any ice candidate messages in the queue for this client id, submit them now. + CHK_STATUS(getPendingMessageQueueForHash(pSampleConfiguration->pPendingSignalingMessageForRemoteClient, clientIdHash, TRUE, + &pPendingMessageQueue)); + if (pPendingMessageQueue != NULL) { + CHK_STATUS(submitPendingIceCandidate(pPendingMessageQueue, pSampleStreamingSession)); + + // NULL the pointer to avoid it being freed in the cleanup + pPendingMessageQueue = NULL; + } + + MUTEX_LOCK(pSampleConfiguration->streamingSessionListReadLock); + pSampleConfiguration->sampleStreamingSessionList[pSampleConfiguration->streamingSessionCount++] = pSampleStreamingSession; + MUTEX_UNLOCK(pSampleConfiguration->streamingSessionListReadLock); + freeStreamingSession = FALSE; + + startStats = pSampleConfiguration->iceCandidatePairStatsTimerId == MAX_UINT32; + break; + + case SIGNALING_MESSAGE_TYPE_ANSWER: + /* + * for viewer, pSampleStreamingSession should've already been created. insert the client id and + * streaming session into pRtcPeerConnectionForRemoteClient for subsequent ice candidate messages. + * Lastly check if there is any ice candidate messages queued in pPendingSignalingMessageForRemoteClient. + * If so then submit all of them. + */ + pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; + CHK_STATUS(handleAnswer(pSampleConfiguration, pSampleStreamingSession, &pReceivedSignalingMessage->signalingMessage)); + CHK_STATUS(hashTablePut(pSampleConfiguration->pRtcPeerConnectionForRemoteClient, clientIdHash, (UINT64) pSampleStreamingSession)); + + // If there are any ice candidate messages in the queue for this client id, submit them now. + CHK_STATUS(getPendingMessageQueueForHash(pSampleConfiguration->pPendingSignalingMessageForRemoteClient, clientIdHash, TRUE, + &pPendingMessageQueue)); + if (pPendingMessageQueue != NULL) { + CHK_STATUS(submitPendingIceCandidate(pPendingMessageQueue, pSampleStreamingSession)); + + // NULL the pointer to avoid it being freed in the cleanup + pPendingMessageQueue = NULL; + } + + startStats = pSampleConfiguration->iceCandidatePairStatsTimerId == MAX_UINT32; + CHK_STATUS(signalingClientGetMetrics(pSampleConfiguration->signalingClientHandle, &pSampleConfiguration->signalingClientMetrics)); + DLOGP("[Signaling offer sent to answer received time] %" PRIu64 " ms", + pSampleConfiguration->signalingClientMetrics.signalingClientStats.offerToAnswerTime); + break; + + case SIGNALING_MESSAGE_TYPE_ICE_CANDIDATE: + /* + * if peer connection hasn't been created, create an queue to store the ice candidate message. Otherwise + * submit the signaling message into the corresponding streaming session. + */ + if (!peerConnectionFound) { + CHK_STATUS(getPendingMessageQueueForHash(pSampleConfiguration->pPendingSignalingMessageForRemoteClient, clientIdHash, FALSE, + &pPendingMessageQueue)); + if (pPendingMessageQueue == NULL) { + CHK_STATUS(createMessageQueue(clientIdHash, &pPendingMessageQueue)); + CHK_STATUS(stackQueueEnqueue(pSampleConfiguration->pPendingSignalingMessageForRemoteClient, (UINT64) pPendingMessageQueue)); + } + + pReceivedSignalingMessageCopy = (PReceivedSignalingMessage) MEMCALLOC(1, SIZEOF(ReceivedSignalingMessage)); + + *pReceivedSignalingMessageCopy = *pReceivedSignalingMessage; + + CHK_STATUS(stackQueueEnqueue(pPendingMessageQueue->messageQueue, (UINT64) pReceivedSignalingMessageCopy)); + + // NULL the pointers to not free any longer + pPendingMessageQueue = NULL; + pReceivedSignalingMessageCopy = NULL; + } else { + CHK_STATUS(handleRemoteCandidate(pSampleStreamingSession, &pReceivedSignalingMessage->signalingMessage)); + } + break; + + default: + DLOGD("Unhandled signaling message type %u", pReceivedSignalingMessage->signalingMessage.messageType); + break; + } + + MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); + locked = FALSE; + + if (pSampleConfiguration->enableIceStats && startStats && + STATUS_FAILED(retStatus = timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, SAMPLE_STATS_DURATION, SAMPLE_STATS_DURATION, + getIceCandidatePairStatsCallback, (UINT64) pSampleConfiguration, + &pSampleConfiguration->iceCandidatePairStatsTimerId))) { + DLOGW("Failed to add getIceCandidatePairStatsCallback to add to timer queue (code 0x%08x). " + "Cannot pull ice candidate pair metrics periodically", + retStatus); + + // Reset the returned status + retStatus = STATUS_SUCCESS; + } + +CleanUp: + + SAFE_MEMFREE(pReceivedSignalingMessageCopy); + if (pPendingMessageQueue != NULL) { + freeMessageQueue(pPendingMessageQueue); + } + + if (freeStreamingSession && pSampleStreamingSession != NULL) { + freeSampleStreamingSession(&pSampleStreamingSession); + } + + if (locked) { + MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); + } + + CHK_LOG_ERR(retStatus); + return retStatus; +} + +STATUS handleRemoteCandidate(PSampleStreamingSession pSampleStreamingSession, PSignalingMessage pSignalingMessage) +{ + STATUS retStatus = STATUS_SUCCESS; + RtcIceCandidateInit iceCandidate; + CHK(pSampleStreamingSession != NULL && pSignalingMessage != NULL, STATUS_NULL_ARG); + + CHK_STATUS(deserializeRtcIceCandidateInit(pSignalingMessage->payload, pSignalingMessage->payloadLen, &iceCandidate)); + CHK_STATUS(addIceCandidate(pSampleStreamingSession->pPeerConnection, iceCandidate.candidate)); + +CleanUp: + + CHK_LOG_ERR(retStatus); + return retStatus; +} \ No newline at end of file diff --git a/samples/lib/Utility.c b/samples/lib/Utility.c index 8dfba21759..d798935135 100644 --- a/samples/lib/Utility.c +++ b/samples/lib/Utility.c @@ -27,4 +27,167 @@ UINT32 setLogLevel() } SET_LOGGER_LOG_LEVEL(logLevel); return logLevel; +} + +STATUS createMessageQueue(UINT64 hashValue, PPendingMessageQueue* ppPendingMessageQueue) +{ + STATUS retStatus = STATUS_SUCCESS; + PPendingMessageQueue pPendingMessageQueue = NULL; + + CHK(ppPendingMessageQueue != NULL, STATUS_NULL_ARG); + + CHK(NULL != (pPendingMessageQueue = (PPendingMessageQueue) MEMCALLOC(1, SIZEOF(PendingMessageQueue))), STATUS_NOT_ENOUGH_MEMORY); + pPendingMessageQueue->hashValue = hashValue; + pPendingMessageQueue->createTime = GETTIME(); + CHK_STATUS(stackQueueCreate(&pPendingMessageQueue->messageQueue)); + +CleanUp: + + if (STATUS_FAILED(retStatus) && pPendingMessageQueue != NULL) { + freeMessageQueue(pPendingMessageQueue); + pPendingMessageQueue = NULL; + } + + if (ppPendingMessageQueue != NULL) { + *ppPendingMessageQueue = pPendingMessageQueue; + } + + return retStatus; +} + +STATUS freeMessageQueue(PPendingMessageQueue pPendingMessageQueue) +{ + STATUS retStatus = STATUS_SUCCESS; + + // free is idempotent + CHK(pPendingMessageQueue != NULL, retStatus); + + if (pPendingMessageQueue->messageQueue != NULL) { + stackQueueClear(pPendingMessageQueue->messageQueue, TRUE); + stackQueueFree(pPendingMessageQueue->messageQueue); + } + + MEMFREE(pPendingMessageQueue); + +CleanUp: + return retStatus; +} + +STATUS getPendingMessageQueueForHash(PStackQueue pPendingQueue, UINT64 clientHash, BOOL remove, PPendingMessageQueue* ppPendingMessageQueue) +{ + STATUS retStatus = STATUS_SUCCESS; + PPendingMessageQueue pPendingMessageQueue = NULL; + StackQueueIterator iterator; + BOOL iterate = TRUE; + UINT64 data; + + CHK(pPendingQueue != NULL && ppPendingMessageQueue != NULL, STATUS_NULL_ARG); + + CHK_STATUS(stackQueueGetIterator(pPendingQueue, &iterator)); + while (iterate && IS_VALID_ITERATOR(iterator)) { + CHK_STATUS(stackQueueIteratorGetItem(iterator, &data)); + CHK_STATUS(stackQueueIteratorNext(&iterator)); + + pPendingMessageQueue = (PPendingMessageQueue) data; + + if (clientHash == pPendingMessageQueue->hashValue) { + *ppPendingMessageQueue = pPendingMessageQueue; + iterate = FALSE; + + // Check if the item needs to be removed + if (remove) { + // This is OK to do as we are terminating the iterator anyway + CHK_STATUS(stackQueueRemoveItem(pPendingQueue, data)); + } + } + } +CleanUp: + return retStatus; +} + +STATUS removeExpiredMessageQueues(PStackQueue pPendingQueue) +{ + STATUS retStatus = STATUS_SUCCESS; + PPendingMessageQueue pPendingMessageQueue = NULL; + UINT32 i, count; + UINT64 data, curTime; + + CHK(pPendingQueue != NULL, STATUS_NULL_ARG); + + curTime = GETTIME(); + CHK_STATUS(stackQueueGetCount(pPendingQueue, &count)); + + // Dequeue and enqueue in order to not break the iterator while removing an item + for (i = 0; i < count; i++) { + CHK_STATUS(stackQueueDequeue(pPendingQueue, &data)); + + // Check for expiry + pPendingMessageQueue = (PPendingMessageQueue) data; + if (pPendingMessageQueue->createTime + SAMPLE_PENDING_MESSAGE_CLEANUP_DURATION < curTime) { + // Message queue has expired and needs to be freed + CHK_STATUS(freeMessageQueue(pPendingMessageQueue)); + } else { + // Enqueue back again as it's still valued + CHK_STATUS(stackQueueEnqueue(pPendingQueue, data)); + } + } +CleanUp: + return retStatus; +} + +STATUS traverseDirectoryPEMFileScan(UINT64 customData, DIR_ENTRY_TYPES entryType, PCHAR fullPath, PCHAR fileName) +{ + UNUSED_PARAM(entryType); + UNUSED_PARAM(fullPath); + + PCHAR certName = (PCHAR) customData; + UINT32 fileNameLen = STRLEN(fileName); + + if (fileNameLen > ARRAY_SIZE(CA_CERT_PEM_FILE_EXTENSION) + 1 && + (STRCMPI(CA_CERT_PEM_FILE_EXTENSION, &fileName[fileNameLen - ARRAY_SIZE(CA_CERT_PEM_FILE_EXTENSION) + 1]) == 0)) { + certName[0] = FPATHSEPARATOR; + certName++; + STRCPY(certName, fileName); + } + + return STATUS_SUCCESS; +} + +STATUS lookForSslCert(PSampleConfiguration* ppSampleConfiguration) +{ + STATUS retStatus = STATUS_SUCCESS; + struct stat pathStat; + CHAR certName[MAX_PATH_LEN]; + PSampleConfiguration pSampleConfiguration = *ppSampleConfiguration; + + MEMSET(certName, 0x0, ARRAY_SIZE(certName)); + pSampleConfiguration->pCaCertPath = GETENV(CACERT_PATH_ENV_VAR); + + // if ca cert path is not set from the environment, try to use the one that cmake detected + if (pSampleConfiguration->pCaCertPath == NULL) { + CHK_ERR(STRNLEN(DEFAULT_KVS_CACERT_PATH, MAX_PATH_LEN) > 0, STATUS_INVALID_OPERATION, "No ca cert path given (error:%s)", strerror(errno)); + pSampleConfiguration->pCaCertPath = DEFAULT_KVS_CACERT_PATH; + } else { + // Check if the environment variable is a path + CHK(0 == FSTAT(pSampleConfiguration->pCaCertPath, &pathStat), STATUS_DIRECTORY_ENTRY_STAT_ERROR); + + if (S_ISDIR(pathStat.st_mode)) { + CHK_STATUS(traverseDirectory(pSampleConfiguration->pCaCertPath, (UINT64) &certName, /* iterate */ FALSE, traverseDirectoryPEMFileScan)); + + if (certName[0] != 0x0) { + STRCAT(pSampleConfiguration->pCaCertPath, certName); + } else { + DLOGW("Cert not found in path set...checking if CMake detected a path\n"); + CHK_ERR(STRNLEN(DEFAULT_KVS_CACERT_PATH, MAX_PATH_LEN) > 0, STATUS_INVALID_OPERATION, "No ca cert path given (error:%s)", + strerror(errno)); + DLOGI("CMake detected cert path\n"); + pSampleConfiguration->pCaCertPath = DEFAULT_KVS_CACERT_PATH; + } + } + } + +CleanUp: + + CHK_LOG_ERR(retStatus); + return retStatus; } \ No newline at end of file From 6c2402de6ad642acf5ca2935c5812a5133bf6c29 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Mon, 13 May 2024 17:37:41 -0700 Subject: [PATCH 07/64] Stop time --- cloudwatch-integ/config_periodic.h | 2 ++ .../kvsWebRTCClientMasterCloudwatch.cpp | 2 +- samples/Samples.h | 3 ++- samples/lib/Common.c | 13 +++++++++++++ samples/sample_config.h | 2 ++ 5 files changed, 20 insertions(+), 2 deletions(-) diff --git a/cloudwatch-integ/config_periodic.h b/cloudwatch-integ/config_periodic.h index ffeaf89657..580325b7a1 100644 --- a/cloudwatch-integ/config_periodic.h +++ b/cloudwatch-integ/config_periodic.h @@ -9,5 +9,7 @@ #define IOT_CORE_ENABLE_CREDENTIALS FALSE #define ENABLE_STORAGE FALSE #define ENABLE_METRICS TRUE +#define SAMPLE_PRE_GENERATE_CERT TRUE +#define SAMPLE_RUN_TIME (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index f4cc2086ea..e8ff9f8e33 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -194,7 +194,7 @@ INT32 main(INT32 argc, CHAR* argv[]) initKvsWebRtc(); UINT32 logLevel = setLogLevel(); - createSampleConfiguration(CHANNEL_NAME, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration); + CHK_STATUS(createSampleConfiguration(CHANNEL_NAME, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration)); // Set the audio and video handlers pSampleConfiguration->audioSource = sendAudioPackets; diff --git a/samples/Samples.h b/samples/Samples.h index 7c97f6a7de..3208b181cc 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -49,7 +49,6 @@ extern "C" { #define SAMPLE_STATS_DURATION (60 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define SAMPLE_VIDEO_FRAME_DURATION (HUNDREDS_OF_NANOS_IN_A_SECOND / DEFAULT_FPS_VALUE) -#define SAMPLE_PRE_GENERATE_CERT TRUE #define SAMPLE_PRE_GENERATE_CERT_PERIOD (1000 * HUNDREDS_OF_NANOS_IN_A_MILLISECOND) #define SAMPLE_SESSION_CLEANUP_WAIT_PERIOD (5 * HUNDREDS_OF_NANOS_IN_A_SECOND) @@ -176,6 +175,7 @@ typedef struct { MUTEX signalingSendMessageLock; UINT32 pregenerateCertTimerId; + UINT32 terminateId; PStackQueue pregeneratedCertificates; // Max MAX_RTCCONFIGURATION_CERTIFICATES certificates PCHAR rtspUri; @@ -347,6 +347,7 @@ STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamin STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession); VOID onIceCandidateHandler(UINT64, PCHAR); PVOID mediaSenderRoutine(PVOID); +STATUS setupMetricsCtx(PSampleStreamingSession); #ifdef __cplusplus } diff --git a/samples/lib/Common.c b/samples/lib/Common.c index cda0bc117e..048a1ace8d 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -13,6 +13,16 @@ VOID sigintHandler(INT32 sigNum) } } +STATUS terminate(UINT32 timerId, UINT64 currentTime, UINT64 customData) +{ + DLOGI("Terminate"); + if (gSampleConfiguration != NULL) { + ATOMIC_STORE_BOOL(&gSampleConfiguration->interrupted, TRUE); + CVAR_BROADCAST(gSampleConfiguration->cvar); + } + return STATUS_SUCCESS; +} + STATUS signalingCallFailed(STATUS status) { return (STATUS_SIGNALING_GET_TOKEN_CALL_FAILED == status || STATUS_SIGNALING_DESCRIBE_CALL_FAILED == status || @@ -339,6 +349,7 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P sampleSenderBandwidthEstimationHandler)); } pSampleStreamingSession->startUpLatency = 0; + CHK_STATUS(setupMetricsCtx(pSampleStreamingSession)); CleanUp: if (STATUS_FAILED(retStatus) && pSampleStreamingSession != NULL) { @@ -645,6 +656,8 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE CHK_STATUS(hashTableCreateWithParams(SAMPLE_HASH_TABLE_BUCKET_COUNT, SAMPLE_HASH_TABLE_BUCKET_LENGTH, &pSampleConfiguration->pRtcPeerConnectionForRemoteClient)); + CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, SAMPLE_RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, + (UINT64) pSampleConfiguration, &pSampleConfiguration->terminateId)); CleanUp: if (STATUS_FAILED(retStatus)) { diff --git a/samples/sample_config.h b/samples/sample_config.h index ea99bf1e8c..ef8451c45f 100644 --- a/samples/sample_config.h +++ b/samples/sample_config.h @@ -9,5 +9,7 @@ #define IOT_CORE_ENABLE_CREDENTIALS FALSE #define ENABLE_STORAGE FALSE #define ENABLE_METRICS FALSE +#define SAMPLE_PRE_GENERATE_CERT TRUE +#define SAMPLE_RUN_TIME (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) #endif // KVS_SDK_SAMPLE_CONFIG_H From 47e72fc5ebb8c165ba929789ca9a9beaf2c91e96 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 14 May 2024 16:12:26 -0700 Subject: [PATCH 08/64] Add viewer --- cloudwatch-integ/CMakeLists.txt | 19 ++ .../kvsWebRTCClientMasterCloudwatch.cpp | 15 +- .../kvsWebRTCClientViewerCloudwatch.cpp | 190 ++++++++++++++++++ 3 files changed, 217 insertions(+), 7 deletions(-) create mode 100644 cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp diff --git a/cloudwatch-integ/CMakeLists.txt b/cloudwatch-integ/CMakeLists.txt index 3c4771fb31..1515fc52c5 100644 --- a/cloudwatch-integ/CMakeLists.txt +++ b/cloudwatch-integ/CMakeLists.txt @@ -30,3 +30,22 @@ target_link_libraries(kvsWebrtcClientMasterCW ${EXTRA_DEPS} kvsCommonLws kvspicUtils websockets kvssdp kvsstun ${AWSSDK_LINK_LIBRARIES}) + +add_executable( + kvsWebrtcClientViewerCW + ../samples/lib/Common.c + ../samples/lib/Utility.c + ../samples/lib/MetricsHandling.c + ../samples/lib/DataChannelHandling.c + ../samples/lib/SignalingMsgHandler.c + ../samples/lib/Media.c + Cloudwatch.cpp + CloudwatchLogs.cpp + CloudwatchMonitoring.cpp + kvsWebRTCClientViewerCloudwatch.cpp) +target_link_libraries(kvsWebrtcClientViewerCW + kvsWebrtcClient + kvsWebrtcSignalingClient + ${EXTRA_DEPS} + kvsCommonLws kvspicUtils websockets kvssdp kvsstun + ${AWSSDK_LINK_LIBRARIES}) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index e8ff9f8e33..1f02c5f61f 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -210,9 +210,10 @@ INT32 main(INT32 argc, CHAR* argv[]) } CppInteg::Cloudwatch::init(CHANNEL_NAME, region, TRUE); -#ifdef ENABLE_DATA_CHANNEL - pSampleConfiguration->onDataChannel = onDataChannel; -#endif + if(ENABLE_DATA_CHANNEL) { + pSampleConfiguration->onDataChannel = onDataChannel; + } + pSampleConfiguration->mediaType = SAMPLE_STREAMING_AUDIO_VIDEO; DLOGI("[KVS CW Master] Finished setting handlers"); @@ -234,11 +235,11 @@ INT32 main(INT32 argc, CHAR* argv[]) DLOGI("[KVS Master] Channel %s set up done ", CHANNEL_NAME); // Checking for termination - sessionCleanupWait(pSampleConfiguration); + CHK_STATUS(sessionCleanupWait(pSampleConfiguration)); DLOGI("[KVS Master] Streaming session terminated"); - } - if (retStatus != STATUS_SUCCESS) { - DLOGE("[KVS Master] Terminated with status code 0x%08x", retStatus); + if (retStatus != STATUS_SUCCESS) { + DLOGE("[KVS Master] Terminated with status code 0x%08x", retStatus); + } } CleanUp: diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp new file mode 100644 index 0000000000..abcaadae89 --- /dev/null +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -0,0 +1,190 @@ +#include +#include "../samples/Samples.h" +#include "Cloudwatch.h" + +extern PSampleConfiguration gSampleConfiguration; + +#ifdef ENABLE_DATA_CHANNEL + +// onMessage callback for a message received by the viewer on a data channel +VOID dataChannelOnMessageCallback(UINT64 customData, PRtcDataChannel pDataChannel, BOOL isBinary, PBYTE pMessage, UINT32 pMessageLen) +{ + UNUSED_PARAM(customData); + UNUSED_PARAM(pDataChannel); + if (isBinary) { + DLOGI("DataChannel Binary Message"); + } else { + DLOGI("DataChannel String Message: %.*s", pMessageLen, pMessage); + } +} + +// onOpen callback for the onOpen event of a viewer created data channel +VOID dataChannelOnOpenCallback(UINT64 customData, PRtcDataChannel pDataChannel) +{ + STATUS retStatus = STATUS_SUCCESS; + DLOGI("New DataChannel has been opened %s ", pDataChannel->name); + dataChannelOnMessage(pDataChannel, customData, dataChannelOnMessageCallback); + ATOMIC_INCREMENT((PSIZE_T) customData); + // Sending first message to the master over the data channel + retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) VIEWER_DATA_CHANNEL_MESSAGE, STRLEN(VIEWER_DATA_CHANNEL_MESSAGE)); + if (retStatus != STATUS_SUCCESS) { + DLOGI("[KVS Viewer] dataChannelSend(): operation returned status code: 0x%08x ", retStatus); + } +} +#endif + +INT32 main(INT32 argc, CHAR* argv[]) +{ + STATUS retStatus = STATUS_SUCCESS; + RtcSessionDescriptionInit offerSessionDescriptionInit; + UINT32 buffLen = 0; + SignalingMessage message; + PSampleConfiguration pSampleConfiguration = NULL; + PSampleStreamingSession pSampleStreamingSession = NULL; + BOOL locked = FALSE; + CHAR clientId[256]; + PCHAR region; + Aws::SDKOptions options; + Aws::InitAPI(options); + { + SET_INSTRUMENTED_ALLOCATORS(); + UINT32 logLevel = setLogLevel(); + +#ifndef _WIN32 + signal(SIGINT, sigintHandler); +#endif + + CHK_STATUS(createSampleConfiguration(CHANNEL_NAME, SIGNALING_CHANNEL_ROLE_TYPE_VIEWER, TRUE, TRUE, logLevel, &pSampleConfiguration)); + pSampleConfiguration->mediaType = SAMPLE_STREAMING_AUDIO_VIDEO; + + // Initialize KVS WebRTC. This must be done before anything else, and must only be done once. + CHK_STATUS(initKvsWebRtc()); + DLOGI("[KVS Viewer] KVS WebRTC initialization completed successfully"); + + if(ENABLE_DATA_CHANNEL) { + pSampleConfiguration->onDataChannel = onDataChannel; + } + + if ((region = GETENV(DEFAULT_REGION_ENV_VAR)) == NULL) { + region = (PCHAR) DEFAULT_AWS_REGION; + } + CppInteg::Cloudwatch::init(CHANNEL_NAME, region, FALSE); + + SNPRINTF(clientId, SIZEOF(clientId), "%s_%u", SAMPLE_VIEWER_CLIENT_ID, RAND() % MAX_UINT32); + CHK_STATUS(initSignaling(pSampleConfiguration, clientId)); + DLOGI("[KVS Viewer] Signaling client connection established"); + + // Initialize streaming session + MUTEX_LOCK(pSampleConfiguration->sampleConfigurationObjLock); + locked = TRUE; + CHK_STATUS(createSampleStreamingSession(pSampleConfiguration, NULL, FALSE, &pSampleStreamingSession)); + DLOGI("[KVS Viewer] Creating streaming session...completed"); + pSampleConfiguration->sampleStreamingSessionList[pSampleConfiguration->streamingSessionCount++] = pSampleStreamingSession; + + MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); + locked = FALSE; + + MEMSET(&offerSessionDescriptionInit, 0x00, SIZEOF(RtcSessionDescriptionInit)); + + offerSessionDescriptionInit.useTrickleIce = pSampleStreamingSession->remoteCanTrickleIce; + CHK_STATUS(setLocalDescription(pSampleStreamingSession->pPeerConnection, &offerSessionDescriptionInit)); + DLOGI("[KVS Viewer] Completed setting local description"); + + CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pAudioRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleAudioFrameHandler)); + CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pVideoRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleVideoFrameHandler)); + + if (!pSampleConfiguration->trickleIce) { + DLOGI("[KVS Viewer] Non trickle ice. Wait for Candidate collection to complete"); + MUTEX_LOCK(pSampleConfiguration->sampleConfigurationObjLock); + locked = TRUE; + + while (!ATOMIC_LOAD_BOOL(&pSampleStreamingSession->candidateGatheringDone)) { + CHK_WARN(!ATOMIC_LOAD_BOOL(&pSampleStreamingSession->terminateFlag), STATUS_OPERATION_TIMED_OUT, + "application terminated and candidate gathering still not done"); + CVAR_WAIT(pSampleConfiguration->cvar, pSampleConfiguration->sampleConfigurationObjLock, 5 * HUNDREDS_OF_NANOS_IN_A_SECOND); + } + + MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); + locked = FALSE; + + DLOGI("[KVS Viewer] Candidate collection completed"); + } + + CHK_STATUS(createOffer(pSampleStreamingSession->pPeerConnection, &offerSessionDescriptionInit)); + DLOGI("[KVS Viewer] Offer creation successful"); + + DLOGI("[KVS Viewer] Generating JSON of session description...."); + CHK_STATUS(serializeSessionDescriptionInit(&offerSessionDescriptionInit, NULL, &buffLen)); + + if (buffLen >= SIZEOF(message.payload)) { + DLOGE("[KVS Viewer] serializeSessionDescriptionInit(): operation returned status code: 0x%08x ", STATUS_INVALID_OPERATION); + retStatus = STATUS_INVALID_OPERATION; + goto CleanUp; + } + + CHK_STATUS(serializeSessionDescriptionInit(&offerSessionDescriptionInit, message.payload, &buffLen)); + + message.version = SIGNALING_MESSAGE_CURRENT_VERSION; + message.messageType = SIGNALING_MESSAGE_TYPE_OFFER; + STRCPY(message.peerClientId, SAMPLE_MASTER_CLIENT_ID); + message.payloadLen = (buffLen / SIZEOF(CHAR)) - 1; + message.correlationId[0] = '\0'; + + CHK_STATUS(signalingClientSendMessageSync(pSampleConfiguration->signalingClientHandle, &message)); + if(ENABLE_DATA_CHANNEL) { + PRtcDataChannel pDataChannel = NULL; + PRtcPeerConnection pPeerConnection = pSampleStreamingSession->pPeerConnection; + SIZE_T datachannelLocalOpenCount = 0; + + // Creating a new datachannel on the peer connection of the existing sample streaming session + CHK_STATUS(createDataChannel(pPeerConnection, CHANNEL_NAME, NULL, &pDataChannel)); + DLOGI("[KVS Viewer] Creating data channel...completed"); + + // Setting a callback for when the data channel is open + CHK_STATUS(dataChannelOnOpen(pDataChannel, (UINT64) &datachannelLocalOpenCount, dataChannelOnOpenCallback)); + DLOGI("[KVS Viewer] Data Channel open now..."); + } + + // Block until interrupted + while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted) && !ATOMIC_LOAD_BOOL(&pSampleStreamingSession->terminateFlag)) { + THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_SECOND); + } + } + +CleanUp: + + if (retStatus != STATUS_SUCCESS) { + DLOGE("[KVS Viewer] Terminated with status code 0x%08x", retStatus); + } + + DLOGI("[KVS Viewer] Cleaning up...."); + + if (locked) { + MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); + } + + if (pSampleConfiguration->enableFileLogging) { + freeFileLogger(); + } + if (pSampleConfiguration != NULL) { + retStatus = freeSignalingClient(&pSampleConfiguration->signalingClientHandle); + if (retStatus != STATUS_SUCCESS) { + DLOGE("[KVS Viewer] freeSignalingClient(): operation returned status code: 0x%08x ", retStatus); + } + + retStatus = freeSampleConfiguration(&pSampleConfiguration); + if (retStatus != STATUS_SUCCESS) { + DLOGE("[KVS Viewer] freeSampleConfiguration(): operation returned status code: 0x%08x ", retStatus); + } + } + DLOGI("[KVS Viewer] Cleanup done"); + + RESET_INSTRUMENTED_ALLOCATORS(); + + // https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html + // We can only return with 0 - 127. Some platforms treat exit code >= 128 + // to be a success code, which might give an unintended behaviour. + // Some platforms also treat 1 or 0 differently, so it's better to use + // EXIT_FAILURE and EXIT_SUCCESS macros for portability. + return STATUS_FAILED(retStatus) ? EXIT_FAILURE : EXIT_SUCCESS; +} From 37f17de91769d8c39fdaeb9fb99f3f69677d1460 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 14 May 2024 17:30:45 -0700 Subject: [PATCH 09/64] Add profiling --- cloudwatch-integ/Include.h | 4 --- cloudwatch-integ/config_periodic.h | 1 + .../kvsWebRTCClientMasterCloudwatch.cpp | 32 ++++++++++++++++++- samples/Samples.h | 15 ++++----- samples/lib/Common.c | 20 +++++------- samples/lib/DataChannelHandling.c | 13 ++++---- samples/lib/MetricsHandling.c | 17 +++++++++- 7 files changed, 70 insertions(+), 32 deletions(-) diff --git a/cloudwatch-integ/Include.h b/cloudwatch-integ/Include.h index 580b1fe6e4..afa049a2a8 100644 --- a/cloudwatch-integ/Include.h +++ b/cloudwatch-integ/Include.h @@ -97,10 +97,6 @@ #define STATUS_SIGNALING_CANARY_ANSWER_PAYLOAD_MISMATCH STATUS_SIGNALING_CANARY_BASE + 0x00000004 #define STATUS_SIGNALING_CANARY_OFFER_PAYLOAD_MISMATCH STATUS_SIGNALING_CANARY_BASE + 0x00000005 -#define STATUS_WEBRTC_CANARY_BASE 0x74000000 -#define STATUS_WEBRTC_EMPTY_IOT_CRED_FILE STATUS_WEBRTC_CANARY_BASE + 0x00000001 -#define STATUS_WAITING_ON_FIRST_FRAME STATUS_WEBRTC_CANARY_BASE + 0x00000002 - #define CANARY_VIDEO_FRAMES_PATH (PCHAR) "./assets/h264SampleFrames/frame-%04d.h264" #define CANARY_AUDIO_FRAMES_PATH (PCHAR) "./assets/opusSampleFrames/sample-%03d.opus" diff --git a/cloudwatch-integ/config_periodic.h b/cloudwatch-integ/config_periodic.h index 580325b7a1..46111d1990 100644 --- a/cloudwatch-integ/config_periodic.h +++ b/cloudwatch-integ/config_periodic.h @@ -11,5 +11,6 @@ #define ENABLE_METRICS TRUE #define SAMPLE_PRE_GENERATE_CERT TRUE #define SAMPLE_RUN_TIME (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define USE_STORAGE FALSE #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 1f02c5f61f..dc71dcf06f 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -24,6 +24,34 @@ STATUS publishStatsForCanary(RTC_STATS_TYPE statsType, PSampleStreamingSession p return retStatus; } +VOID sendProfilingMetrics(PSampleConfiguration pSampleConfiguration) +{ + STATUS retStatus = STATUS_SUCCESS; + PSampleStreamingSession pSampleStreamingSession = NULL; + + if(pSampleConfiguration == NULL) { + return; + } + + while((pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]) == NULL) { + DLOGI("NULL"); + THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_MILLISECOND * 100); + } + while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted)) { + retStatus = getSdkTimeProfile(pSampleConfiguration->sampleStreamingSessionList[0]); + + if(STATUS_SUCCEEDED(retStatus)) { + CppInteg::Cloudwatch::getInstance().monitoring.pushSignalingClientMetrics(&pSampleConfiguration->signalingClientMetrics); + CppInteg::Cloudwatch::getInstance().monitoring.pushPeerConnectionMetrics(&pSampleStreamingSession->pStatsCtx->peerConnectionMetrics); + CppInteg::Cloudwatch::getInstance().monitoring.pushKvsIceAgentMetrics(&pSampleStreamingSession->pStatsCtx->iceMetrics); + return; + } else { + DLOGI("Waiting on streaming to start 0x%08x", retStatus); + } + THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_MILLISECOND * 100); + } +} + PVOID sendVideoPackets(PVOID args) { STATUS retStatus = STATUS_SUCCESS; @@ -201,7 +229,7 @@ INT32 main(INT32 argc, CHAR* argv[]) pSampleConfiguration->videoSource = sendVideoPackets; pSampleConfiguration->receiveAudioVideoSource = sampleReceiveAudioVideoFrame; - if (argc > 2 && STRNCMP(argv[2], "1", 2) == 0) { + if (USE_STORAGE) { pSampleConfiguration->channelInfo.useMediaStorage = TRUE; } @@ -234,6 +262,8 @@ INT32 main(INT32 argc, CHAR* argv[]) DLOGI("[KVS Master] Channel %s set up done ", CHANNEL_NAME); + std::thread pushProfilingThread(sendProfilingMetrics, pSampleConfiguration); + pushProfilingThread.join(); // Checking for termination CHK_STATUS(sessionCleanupWait(pSampleConfiguration)); DLOGI("[KVS Master] Streaming session terminated"); diff --git a/samples/Samples.h b/samples/Samples.h index 3208b181cc..946e73a971 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -101,6 +101,9 @@ extern "C" { #define MIN_AUDIO_BITRATE_BPS 4000 // Unit bits/sec. Value could change based on codec. #define MAX_AUDIO_BITRATE_BPS 650000 // Unit bits/sec. Value could change based on codec. +#define STATUS_WEBRTC_SAMPLE_BASE 0x74000000 +#define STATUS_WAITING_ON_FIRST_FRAME STATUS_WEBRTC_SAMPLE_BASE + 0x00000001 + typedef enum { SAMPLE_STREAMING_VIDEO_ONLY, SAMPLE_STREAMING_AUDIO_VIDEO, @@ -151,7 +154,6 @@ typedef struct { startRoutine videoSource; startRoutine receiveAudioVideoSource; RtcOnDataChannel onDataChannel; - SignalingClientMetrics signalingClientMetrics; PStackQueue pPendingSignalingMessageForRemoteClient; PHashTable pRtcPeerConnectionForRemoteClient; @@ -182,6 +184,7 @@ typedef struct { UINT32 logLevel; BOOL enableIceStats; BOOL enableTwcc; + SignalingClientMetrics signalingClientMetrics; } SampleConfiguration, *PSampleConfiguration; typedef struct { @@ -246,6 +249,8 @@ typedef struct { typedef struct { OutgoingRTPStatsCtx outgoingRTPStatsCtx; IncomingRTPStatsCtx incomingRTPStatsCtx; + PeerConnectionMetrics peerConnectionMetrics; + KvsIceAgentMetrics iceMetrics; RtcStats kvsRtcStats; MUTEX statsUpdateLock; } StatsCtx, *PStatsCtx; @@ -275,8 +280,6 @@ struct __SampleStreamingSession { StreamSessionShutdownCallback shutdownCallback; UINT64 shutdownCallbackCustomData; UINT64 offerReceiveTime; - PeerConnectionMetrics peerConnectionMetrics; - KvsIceAgentMetrics iceMetrics; CHAR pPeerConnectionMetricsMessage[MAX_PEER_CONNECTION_METRICS_MESSAGE_SIZE]; CHAR pSignalingClientMetricsMessage[MAX_SIGNALING_CLIENT_METRICS_MESSAGE_SIZE]; CHAR pIceAgentMetricsMessage[MAX_ICE_AGENT_METRICS_MESSAGE_SIZE]; @@ -292,10 +295,6 @@ typedef struct { } AsyncGetIceStruct; -typedef struct { - UINT64 customData; -} MetricsHookFunc, *PMetricsHookFunc; - VOID sigintHandler(INT32); STATUS readFrameFromDisk(PBYTE, PUINT32, PCHAR); PVOID receiveGstreamerAudioVideo(PVOID); @@ -348,7 +347,7 @@ STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession); VOID onIceCandidateHandler(UINT64, PCHAR); PVOID mediaSenderRoutine(PVOID); STATUS setupMetricsCtx(PSampleStreamingSession); - +STATUS getSdkTimeProfile(PSampleStreamingSession); #ifdef __cplusplus } #endif diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 048a1ace8d..439f89dffa 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -44,12 +44,6 @@ VOID onConnectionStateChange(UINT64 customData, RTC_PEER_CONNECTION_STATE newSta case RTC_PEER_CONNECTION_STATE_CONNECTED: ATOMIC_STORE_BOOL(&pSampleConfiguration->connected, TRUE); CVAR_BROADCAST(pSampleConfiguration->cvar); - - pSampleStreamingSession->peerConnectionMetrics.peerConnectionStats.peerConnectionConnectedTime = - GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; - CHK_STATUS(peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->peerConnectionMetrics)); - CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->iceMetrics)); - if (pSampleConfiguration->enableIceStats) { CHK_LOG_ERR(logSelectedIceCandidatesInformation(pSampleStreamingSession)); } @@ -271,6 +265,8 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P pSampleStreamingSession->offerReceiveTime = GETTIME(); CHK(pSampleStreamingSession != NULL, STATUS_NOT_ENOUGH_MEMORY); + CHK_STATUS(setupMetricsCtx(pSampleStreamingSession)); + if (isMaster) { STRCPY(pSampleStreamingSession->peerId, peerId); } else { @@ -284,20 +280,21 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P pSampleStreamingSession->pSampleConfiguration = pSampleConfiguration; pSampleStreamingSession->rtpMetricsHistory.prevTs = GETTIME(); - pSampleStreamingSession->peerConnectionMetrics.version = PEER_CONNECTION_METRICS_CURRENT_VERSION; - pSampleStreamingSession->iceMetrics.version = ICE_AGENT_METRICS_CURRENT_VERSION; - // if we're the viewer, we control the trickle ice mode pSampleStreamingSession->remoteCanTrickleIce = !isMaster && pSampleConfiguration->trickleIce; ATOMIC_STORE_BOOL(&pSampleStreamingSession->terminateFlag, FALSE); ATOMIC_STORE_BOOL(&pSampleStreamingSession->candidateGatheringDone, FALSE); - pSampleStreamingSession->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime = GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; - if (pSampleConfiguration->enableTwcc) { pSampleStreamingSession->twccMetadata.updateLock = MUTEX_CREATE(TRUE); } + + pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime = + GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + // Flag to enable SDK to calculate selected ice server, local, remote and candidate pair stats. + pSampleConfiguration->enableIceStats = FALSE; + CHK_STATUS(initializePeerConnection(pSampleConfiguration, &pSampleStreamingSession->pPeerConnection)); CHK_STATUS(peerConnectionOnIceCandidate(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, onIceCandidateHandler)); CHK_STATUS( @@ -349,7 +346,6 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P sampleSenderBandwidthEstimationHandler)); } pSampleStreamingSession->startUpLatency = 0; - CHK_STATUS(setupMetricsCtx(pSampleStreamingSession)); CleanUp: if (STATUS_FAILED(retStatus) && pSampleStreamingSession != NULL) { diff --git a/samples/lib/DataChannelHandling.c b/samples/lib/DataChannelHandling.c index 7192105d90..d4ecdcfedc 100644 --- a/samples/lib/DataChannelHandling.c +++ b/samples/lib/DataChannelHandling.c @@ -128,17 +128,18 @@ VOID onDataChannelMessage(UINT64 customData, PRtcDataChannel pDataChannel, BOOL pSampleConfiguration->signalingClientMetrics.signalingClientStats.connectEndTime); DLOGI("Sending signaling metrics to the viewer: %s", pSampleStreamingSession->pSignalingClientMetricsMessage); - CHK_STATUS(peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->peerConnectionMetrics)); + CHK_STATUS( + peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->pStatsCtx->peerConnectionMetrics)); SNPRINTF(pSampleStreamingSession->pPeerConnectionMetricsMessage, MAX_PEER_CONNECTION_METRICS_MESSAGE_SIZE, PEER_CONNECTION_METRICS_JSON_TEMPLATE, - pSampleStreamingSession->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime, - pSampleStreamingSession->peerConnectionMetrics.peerConnectionStats.peerConnectionConnectedTime); + pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime, + pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.peerConnectionConnectedTime); DLOGI("Sending peer-connection metrics to the viewer: %s", pSampleStreamingSession->pPeerConnectionMetricsMessage); - CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->iceMetrics)); + CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->pStatsCtx->iceMetrics)); SNPRINTF(pSampleStreamingSession->pIceAgentMetricsMessage, MAX_ICE_AGENT_METRICS_MESSAGE_SIZE, ICE_AGENT_METRICS_JSON_TEMPLATE, - pSampleStreamingSession->iceMetrics.kvsIceAgentStats.candidateGatheringStartTime, - pSampleStreamingSession->iceMetrics.kvsIceAgentStats.candidateGatheringEndTime); + pSampleStreamingSession->pStatsCtx->iceMetrics.kvsIceAgentStats.candidateGatheringStartTime, + pSampleStreamingSession->pStatsCtx->iceMetrics.kvsIceAgentStats.candidateGatheringEndTime); DLOGI("Sending ice-agent metrics to the viewer: %s", pSampleStreamingSession->pIceAgentMetricsMessage); retStatus = dataChannelSend(pDataChannel, FALSE, (PBYTE) pSampleStreamingSession->pSignalingClientMetricsMessage, diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index 849d9b2811..6233031887 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -246,4 +246,19 @@ STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamin CleanUp: return retStatus; -} \ No newline at end of file +} + +STATUS getSdkTimeProfile(PSampleStreamingSession pSampleStreamingSession) +{ + STATUS retStatus = STATUS_SUCCESS; + CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up. Nothing to report"); + CHK(!pSampleStreamingSession->firstFrame, STATUS_WAITING_ON_FIRST_FRAME); + + pSampleStreamingSession->pSampleConfiguration->signalingClientMetrics.version = SIGNALING_CLIENT_METRICS_CURRENT_VERSION; + CHK_STATUS(signalingClientGetMetrics(pSampleStreamingSession->pSampleConfiguration->signalingClientHandle, + &pSampleStreamingSession->pSampleConfiguration->signalingClientMetrics)); + CHK_STATUS(peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->pStatsCtx->peerConnectionMetrics)); + CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->pStatsCtx->iceMetrics)); +CleanUp: + return retStatus; +} From 1bc1763781628513b7d7d1d25dfac3ce66f4df99 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Mon, 20 May 2024 14:31:37 -0700 Subject: [PATCH 10/64] E2E added, only video --- cloudwatch-integ/CloudwatchMonitoring.cpp | 25 ++++ cloudwatch-integ/CloudwatchMonitoring.h | 1 + cloudwatch-integ/Include.h | 64 +-------- cloudwatch-integ/config_periodic.h | 5 +- .../kvsWebRTCClientMasterCloudwatch.cpp | 130 +++++++++--------- .../kvsWebRTCClientViewerCloudwatch.cpp | 71 +++++++++- samples/Samples.h | 7 + samples/lib/Common.c | 2 +- 8 files changed, 176 insertions(+), 129 deletions(-) diff --git a/cloudwatch-integ/CloudwatchMonitoring.cpp b/cloudwatch-integ/CloudwatchMonitoring.cpp index 59b46e3471..feda82b7fe 100644 --- a/cloudwatch-integ/CloudwatchMonitoring.cpp +++ b/cloudwatch-integ/CloudwatchMonitoring.cpp @@ -430,4 +430,29 @@ VOID CloudwatchMonitoring::pushRetryCount(UINT32 retryCount) this->push(currentRetryCountDatum); } +VOID CloudwatchMonitoring::pushEndToEndMetrics(PEndToEndMetricsCtx pEndToEndMetricsCtx) +{ + MetricDatum endToEndLatencyDatum, sizeMatchDatum; + DOUBLE latency = pEndToEndMetricsCtx->frameLatencyAvg / (DOUBLE) HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + + // TODO: due to https://github.com/aws-samples/amazon-kinesis-video-streams-demos/issues/96, + // it's not clear why the emitted metric shows -nan. Since -nan is a string that's outputted + // from Datum's value stringify implementation, we should try to get the original value by + // printing it ourself. + // + // If the issues doesn't exist anymore, please remove this as this is intended for debugging only. + // The generic metric logging should be sufficient. + DLOGI("Current end-to-end frame latency: %4.2lf", latency); + endToEndLatencyDatum.SetMetricName("EndToEndFrameLatency"); + endToEndLatencyDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); + endToEndLatencyDatum.SetValue(latency); + this->push(endToEndLatencyDatum); + + sizeMatchDatum.SetMetricName("FrameSizeMatch"); + sizeMatchDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count); + sizeMatchDatum.SetValue(pEndToEndMetricsCtx->sizeMatchAvg); + DLOGI("Size match? %d", pEndToEndMetricsCtx->sizeMatchAvg); + this->push(sizeMatchDatum); +} + } // namespace Canary diff --git a/cloudwatch-integ/CloudwatchMonitoring.h b/cloudwatch-integ/CloudwatchMonitoring.h index f8ec0ea871..b24e99f0fe 100644 --- a/cloudwatch-integ/CloudwatchMonitoring.h +++ b/cloudwatch-integ/CloudwatchMonitoring.h @@ -21,6 +21,7 @@ class CloudwatchMonitoring { VOID pushPeerConnectionMetrics(PPeerConnectionMetrics); VOID pushKvsIceAgentMetrics(PKvsIceAgentMetrics); VOID pushSignalingClientMetrics(PSignalingClientMetrics); + VOID pushEndToEndMetrics(PEndToEndMetricsCtx); VOID pushRetryCount(UINT32); VOID pushStorageDisconnectToFrameSentTime(UINT64, Aws::CloudWatch::Model::StandardUnit); diff --git a/cloudwatch-integ/Include.h b/cloudwatch-integ/Include.h index afa049a2a8..1548821d7a 100644 --- a/cloudwatch-integ/Include.h +++ b/cloudwatch-integ/Include.h @@ -7,33 +7,11 @@ #define DEFAULT_FILE_LOGGING_BUFFER_SIZE (200 * 1024) #define MAX_CLOUDWATCH_LOG_COUNT 128 -#define MAX_CONCURRENT_CONNECTIONS 10 -#define MAX_TURN_SERVERS 1 #define MAX_STATUS_CODE_LENGTH 16 -#define MAX_CONFIG_JSON_TOKENS 128 -#define MAX_CONFIG_JSON_VALUE_SIZE 256 -#define MAX_CONFIG_JSON_FILE_SIZE 1024 #define MAX_CONTROL_PLANE_URI_CHAR_LEN 256 -#define MAX_UINT64_DIGIT_COUNT 20 #define NUMBER_OF_H264_FRAME_FILES 1500 #define NUMBER_OF_OPUS_FRAME_FILES 618 -#define SAMPLE_VIDEO_FRAME_DURATION (HUNDREDS_OF_NANOS_IN_A_SECOND / DEFAULT_FPS_VALUE) -#define SAMPLE_AUDIO_FRAME_DURATION (20 * HUNDREDS_OF_NANOS_IN_A_MILLISECOND) - -#define ASYNC_ICE_CONFIG_INFO_WAIT_TIMEOUT (3 * HUNDREDS_OF_NANOS_IN_A_SECOND) -#define ICE_CONFIG_INFO_POLL_PERIOD (20 * HUNDREDS_OF_NANOS_IN_A_MILLISECOND) - -#define CA_CERT_PEM_FILE_EXTENSION ".pem" -#define SIGNALING_CANARY_MASTER_CLIENT_ID "CANARY_MASTER" -#define SIGNALING_CANARY_VIEWER_CLIENT_ID "CANARY_VIEWER" -#define SIGNALING_CANARY_START_DELAY (100 * HUNDREDS_OF_NANOS_IN_A_MILLISECOND) -#define SIGNALING_CANARY_MIN_SESSION_PERIOD (20 * HUNDREDS_OF_NANOS_IN_A_SECOND) -#define SIGNALING_CANARY_OFFER "Signaling canary offer" -#define SIGNALING_CANARY_ANSWER "Signaling canary answer" -#define SIGNALING_CANARY_ROUNDTRIP_TIMEOUT (10 * HUNDREDS_OF_NANOS_IN_A_SECOND) -#define SIGNALING_CANARY_CHANNEL_NAME (PCHAR) "ScaryTestChannel_" -#define SIGNALING_CANARY_MAX_CONSECUTIVE_ITERATION_FAILURE_COUNT 5 #define CANARY_METADATA_SIZE (SIZEOF(UINT64) + SIZEOF(UINT32) + SIZEOF(UINT32)) #define ANNEX_B_NALU_SIZE 4 @@ -47,40 +25,14 @@ #define CANARY_MIN_DURATION (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define CANARY_MIN_ITERATION_DURATION (15 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define END_TO_END_METRICS_INVOCATION_PERIOD (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) -#define CANARY_ENDPOINT_ENV_VAR "CANARY_ENDPOINT" -#define CANARY_LABEL_ENV_VAR "CANARY_LABEL" -#define CANARY_CHANNEL_NAME_ENV_VAR "CANARY_CHANNEL_NAME" -#define CANARY_CLIENT_ID_ENV_VAR "CANARY_CLIENT_ID" -#define CANARY_TRICKLE_ICE_ENV_VAR "CANARY_TRICKLE_ICE" -#define CANARY_IS_MASTER_ENV_VAR "CANARY_IS_MASTER" -#define CANARY_USE_TURN_ENV_VAR "CANARY_USE_TURN" -#define CANARY_LOG_GROUP_NAME_ENV_VAR "CANARY_LOG_GROUP_NAME" -#define CANARY_LOG_STREAM_NAME_ENV_VAR "CANARY_LOG_STREAM_NAME" -#define CANARY_CERT_PATH_ENV_VAR "CANARY_CERT_PATH" -#define CANARY_DURATION_IN_SECONDS_ENV_VAR "CANARY_DURATION_IN_SECONDS" -#define CANARY_VIDEO_CODEC_ENV_VAR "CANARY_VIDEO_CODEC" -#define CANARY_ITERATION_IN_SECONDS_ENV_VAR "CANARY_ITERATION_IN_SECONDS" -#define CANARY_FORCE_TURN_ENV_VAR "CANARY_FORCE_TURN" -#define CANARY_BIT_RATE_ENV_VAR "CANARY_DATARATE_IN_BITS_PER_SECOND" -#define CANARY_FRAME_RATE_ENV_VAR "CANARY_FRAME_RATE" -#define CANARY_RUN_BOTH_PEERS_ENV_VAR "CANARY_RUN_BOTH_PEERS" -#define CANARY_USE_IOT_CREDENTIALS_ENV_VAR "CANARY_USE_IOT_PROVIDER" -#define CANARY_RUN_IN_PROFILING_MODE_ENV_VAR "CANARY_IS_PROFILING_MODE" -#define IOT_CORE_CREDENTIAL_ENDPOINT_ENV_VAR "AWS_IOT_CORE_CREDENTIAL_ENDPOINT" -#define IOT_CORE_CERT_ENV_VAR "AWS_IOT_CORE_CERT" -#define IOT_CORE_PRIVATE_KEY_ENV_VAR "AWS_IOT_CORE_PRIVATE_KEY" -#define IOT_CORE_ROLE_ALIAS_ENV_VAR "AWS_IOT_CORE_ROLE_ALIAS" -#define IOT_CORE_THING_NAME_ENV_VAR "AWS_IOT_CORE_THING_NAME" #define STORAGE_CANARY_FIRST_FRAME_TS_FILE_ENV_VAR "STORAGE_CANARY_FIRST_FRAME_TS_FILE" #define CANARY_DEFAULT_LABEL "ScaryTestLabel" #define CANARY_DEFAULT_CHANNEL_NAME "ScaryTestStream" -#define CANARY_VIDEO_CODEC_H264 "h264" -#define CANARY_VIDEO_CODEC_H265 "h265" #define CANARY_DEFAULT_CLIENT_ID "DefaultClientId" #define CANARY_DEFAULT_LOG_GROUP_NAME "DefaultLogGroupName" -#define CANARY_DEFAULT_LOG_GROUP_NAME "DefaultLogGroupName" #define FIRST_FRAME_TS_FILE_PATH "../" #define STORAGE_CANARY_DEFAULT_FIRST_FRAME_TS_FILE "DefaultFirstFrameSentTSFileName.txt" @@ -89,20 +41,6 @@ #define AGGREGATE_STORAGE_CW_DIMENSION "StorageWebRTCSDKCanaryLabel" #define AGGREGATE_CW_DIMENSION "WebRTCSDKCanaryLabel" -// Signaling Canary error definitions -#define STATUS_SIGNALING_CANARY_BASE 0x73000000 -#define STATUS_SIGNALING_CANARY_UNEXPECTED_MESSAGE STATUS_SIGNALING_CANARY_BASE + 0x00000001 -#define STATUS_SIGNALING_CANARY_ANSWER_CID_MISMATCH STATUS_SIGNALING_CANARY_BASE + 0x00000002 -#define STATUS_SIGNALING_CANARY_OFFER_CID_MISMATCH STATUS_SIGNALING_CANARY_BASE + 0x00000003 -#define STATUS_SIGNALING_CANARY_ANSWER_PAYLOAD_MISMATCH STATUS_SIGNALING_CANARY_BASE + 0x00000004 -#define STATUS_SIGNALING_CANARY_OFFER_PAYLOAD_MISMATCH STATUS_SIGNALING_CANARY_BASE + 0x00000005 - -#define CANARY_VIDEO_FRAMES_PATH (PCHAR) "./assets/h264SampleFrames/frame-%04d.h264" -#define CANARY_AUDIO_FRAMES_PATH (PCHAR) "./assets/opusSampleFrames/sample-%03d.opus" - -#define METRICS_INVOCATION_PERIOD (60 * HUNDREDS_OF_NANOS_IN_A_SECOND) -#define END_TO_END_METRICS_INVOCATION_PERIOD (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) -#define KVS_METRICS_INVOCATION_PERIOD (5 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define CANARY_METADATA_SIZE (SIZEOF(UINT64) + SIZEOF(UINT32) + SIZEOF(UINT32)) #define MAX_CALL_RETRY_COUNT 10 diff --git a/cloudwatch-integ/config_periodic.h b/cloudwatch-integ/config_periodic.h index 46111d1990..f35acb18ae 100644 --- a/cloudwatch-integ/config_periodic.h +++ b/cloudwatch-integ/config_periodic.h @@ -12,5 +12,8 @@ #define SAMPLE_PRE_GENERATE_CERT TRUE #define SAMPLE_RUN_TIME (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define USE_STORAGE FALSE - +#define AUDIO_CODEC RTC_CODEC_OPUS +#define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#define DEFAULT_BITRATE (250 * 1024) +#define DEFAULT_FRAMERATE 30 #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index dc71dcf06f..4980fa24cc 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -34,7 +34,6 @@ VOID sendProfilingMetrics(PSampleConfiguration pSampleConfiguration) } while((pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]) == NULL) { - DLOGI("NULL"); THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_MILLISECOND * 100); } while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted)) { @@ -52,47 +51,76 @@ VOID sendProfilingMetrics(PSampleConfiguration pSampleConfiguration) } } +VOID addMetadataToFrameData(PBYTE buffer, PFrame pFrame) +{ + PBYTE pCurPtr = buffer + ANNEX_B_NALU_SIZE; + putUnalignedInt64BigEndian((PINT64) pCurPtr, pFrame->presentationTs); + pCurPtr += SIZEOF(UINT64); + putUnalignedInt32BigEndian((PINT32) pCurPtr, pFrame->size); + pCurPtr += SIZEOF(UINT32); + putUnalignedInt32BigEndian((PINT32) pCurPtr, COMPUTE_CRC32(buffer, pFrame->size)); +} + +VOID createMockFrames(PBYTE buffer, PFrame pFrame) +{ + UINT32 i; + // For decoding purposes, the first 4 bytes need to be a NALu + putUnalignedInt32BigEndian((PINT32) buffer, 0x00000001); + for (i = ANNEX_B_NALU_SIZE + CANARY_METADATA_SIZE; i < pFrame->size; i++) { + buffer[i] = RAND(); + } + addMetadataToFrameData(buffer, pFrame); +} + PVOID sendVideoPackets(PVOID args) { STATUS retStatus = STATUS_SUCCESS; - PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) args; - RtcEncoderStats encoderStats; + STATUS status = STATUS_SUCCESS; Frame frame; - UINT32 fileIndex = 0, frameSize; - CHAR filePath[MAX_PATH_LEN + 1]; - STATUS status; UINT32 i; - UINT64 startTime, lastFrameTime, elapsed; - MEMSET(&encoderStats, 0x00, SIZEOF(RtcEncoderStats)); - CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); + UINT32 hexStrLen = 0; + UINT32 actualFrameSize = 0; + UINT32 frameSizeWithoutNalu = 0; + UINT32 minFrameSize = CANARY_METADATA_SIZE + ((DEFAULT_BITRATE / 8) / DEFAULT_FRAMERATE); + UINT32 maxFrameSize = (CANARY_METADATA_SIZE + ((DEFAULT_BITRATE / 8) / DEFAULT_FRAMERATE)) * 2; + PBYTE frameData = NULL; + PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) args; - frame.presentationTs = 0; - startTime = GETTIME(); - lastFrameTime = startTime; + frameData = (PBYTE) MEMALLOC(maxFrameSize); - while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { - fileIndex = fileIndex % NUMBER_OF_H264_FRAME_FILES + 1; - SNPRINTF(filePath, MAX_PATH_LEN, "./h264SampleFrames/frame-%04d.h264", fileIndex); + // We allocate a bigger buffer to accomodate the hex encoded string + frame.frameData = (PBYTE) MEMALLOC(maxFrameSize * 3 + 1 + ANNEX_B_NALU_SIZE); + frame.version = FRAME_CURRENT_VERSION; + frame.presentationTs = GETTIME(); - CHK_STATUS(readFrameFromDisk(NULL, &frameSize, filePath)); + while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { - // Re-alloc if needed - if (frameSize > pSampleConfiguration->videoBufferSize) { - pSampleConfiguration->pVideoFrameBuffer = (PBYTE) MEMREALLOC(pSampleConfiguration->pVideoFrameBuffer, frameSize); - CHK_ERR(pSampleConfiguration->pVideoFrameBuffer != NULL, STATUS_NOT_ENOUGH_MEMORY, "[KVS Master] Failed to allocate video frame buffer"); - pSampleConfiguration->videoBufferSize = frameSize; + // This is the actual frame size that includes the metadata and the actual frame data + // It generates a number between 1082 and 2164 but the actual frame.size may be larger + // because hexStrLen will vary + actualFrameSize = (RAND() % (maxFrameSize - minFrameSize + 1)) + minFrameSize; + frameSizeWithoutNalu = actualFrameSize - ANNEX_B_NALU_SIZE; + + frame.size = actualFrameSize; + createMockFrames(frameData, &frame); + + // Hex encode the data (without the ANNEX-B NALu) to ensure parts of random frame data is not skipped if they + // are the same as the ANNEX-B NALu + CHK_STATUS(hexEncode(frame.frameData + ANNEX_B_NALU_SIZE, frameSizeWithoutNalu, NULL, &hexStrLen)); + + // This re-alloc is done in case the estimated size does not match the actual requirement. + // We do not want to constantly malloc within a loop. Hence, we re-allocate only if required + // Either ways, the realloc should not happen + if (hexStrLen != (frameSizeWithoutNalu * 2 + 1)) { + DLOGW("Re allocating...this should not happen...something might be wrong"); + frame.frameData = (PBYTE) REALLOC(frame.frameData, hexStrLen + ANNEX_B_NALU_SIZE); + CHK_ERR(frame.frameData != NULL, STATUS_NOT_ENOUGH_MEMORY, "Failed to realloc media buffer"); } + CHK_STATUS(hexEncode(frameData + ANNEX_B_NALU_SIZE, frameSizeWithoutNalu, (PCHAR)(frame.frameData + ANNEX_B_NALU_SIZE), &hexStrLen)); + MEMCPY(frame.frameData, frameData, ANNEX_B_NALU_SIZE); - frame.frameData = pSampleConfiguration->pVideoFrameBuffer; - frame.size = frameSize; - - CHK_STATUS(readFrameFromDisk(frame.frameData, &frameSize, filePath)); - - // based on bitrate of samples/h264SampleFrames/frame-* - encoderStats.width = 640; - encoderStats.height = 480; - encoderStats.targetBitrate = 262000; - frame.presentationTs += SAMPLE_VIDEO_FRAME_DURATION; + // We must update the size to reflect the original data with hex encoded data + frame.size = hexStrLen + ANNEX_B_NALU_SIZE; MUTEX_LOCK(pSampleConfiguration->streamingSessionListReadLock); for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { status = writeFrame(pSampleConfiguration->sampleStreamingSessionList[i]->pVideoRtcRtpTransceiver, &frame); @@ -102,34 +130,22 @@ PVOID sendVideoPackets(PVOID args) PROFILE_WITH_START_TIME(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, "Time to first frame"); pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame = FALSE; } - encoderStats.encodeTimeMsec = 4; // update encode time to an arbitrary number to demonstrate stats update - updateEncoderStats(pSampleConfiguration->sampleStreamingSessionList[i]->pVideoRtcRtpTransceiver, &encoderStats); if (status != STATUS_SRTP_NOT_READY_YET) { if (status != STATUS_SUCCESS) { DLOGV("writeFrame() failed with 0x%08x", status); } - } else { - // Reset file index to ensure first frame sent upon SRTP ready is a key frame. - fileIndex = 0; } publishStatsForCanary(RTC_STATS_TYPE_OUTBOUND_RTP, pSampleConfiguration->sampleStreamingSessionList[i]); } MUTEX_UNLOCK(pSampleConfiguration->streamingSessionListReadLock); - - // Adjust sleep in the case the sleep itself and writeFrame take longer than expected. Since sleep makes sure that the thread - // will be paused at least until the given amount, we can assume that there's no too early frame scenario. - // Also, it's very unlikely to have a delay greater than SAMPLE_VIDEO_FRAME_DURATION, so the logic assumes that this is always - // true for simplicity. - elapsed = lastFrameTime - startTime; - THREAD_SLEEP(SAMPLE_VIDEO_FRAME_DURATION - elapsed % SAMPLE_VIDEO_FRAME_DURATION); - lastFrameTime = GETTIME(); + THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_SECOND / DEFAULT_FRAME_RATE); + frame.presentationTs = GETTIME(); } - CleanUp: - DLOGI("[KVS Master] Closing video thread"); - CHK_LOG_ERR(retStatus); - return (PVOID) (ULONG_PTR) retStatus; + SAFE_MEMFREE(frame.frameData); + SAFE_MEMFREE(frameData); + return NULL; } PVOID sendAudioPackets(PVOID args) @@ -195,18 +211,6 @@ VOID sampleVideoFrameHandlerCW(UINT64 customData, PFrame pFrame) publishStatsForCanary(RTC_STATS_TYPE_INBOUND_RTP, pSampleStreamingSession); } -PVOID sampleReceiveAudioVideoFrame(PVOID args) -{ - STATUS retStatus = STATUS_SUCCESS; - PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) args; - CHK_ERR(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); - CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pVideoRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleVideoFrameHandlerCW)); - - CleanUp: - - return (PVOID) (ULONG_PTR) retStatus; -} - INT32 main(INT32 argc, CHAR* argv[]) { STATUS retStatus = STATUS_SUCCESS; @@ -227,7 +231,9 @@ INT32 main(INT32 argc, CHAR* argv[]) // Set the audio and video handlers pSampleConfiguration->audioSource = sendAudioPackets; pSampleConfiguration->videoSource = sendVideoPackets; - pSampleConfiguration->receiveAudioVideoSource = sampleReceiveAudioVideoFrame; + pSampleConfiguration->receiveAudioVideoSource = NULL; + pSampleConfiguration->audioCodec = AUDIO_CODEC; + pSampleConfiguration->videoCodec = VIDEO_CODEC; if (USE_STORAGE) { pSampleConfiguration->channelInfo.useMediaStorage = TRUE; @@ -272,7 +278,7 @@ INT32 main(INT32 argc, CHAR* argv[]) } } -CleanUp: + CleanUp: DLOGI("[KVS Master] Cleaning up...."); if (pSampleConfiguration != NULL) { // Kick of the termination sequence diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index abcaadae89..1489ef2199 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -33,6 +33,67 @@ VOID dataChannelOnOpenCallback(UINT64 customData, PRtcDataChannel pDataChannel) } #endif +STATUS publishEndToEndMetrics(PSampleStreamingSession pSampleStreamingSession) +{ + STATUS retStatus = STATUS_SUCCESS; + CHK(pSampleStreamingSession != NULL, STATUS_NULL_ARG); + CppInteg::Cloudwatch::getInstance().monitoring.pushEndToEndMetrics(&pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx); +CleanUp: + return STATUS_SUCCESS; +} + +STATUS endToendStatsCallback(UINT32 timerId, UINT64 currentTime, UINT64 customData) +{ + UNUSED_PARAM(timerId); + UNUSED_PARAM(currentTime); + STATUS retStatus = STATUS_SUCCESS; + PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; + if (!(ATOMIC_LOAD_BOOL(&pSampleStreamingSession->pSampleConfiguration->appTerminateFlag))) { + CHK_STATUS(publishEndToEndMetrics(pSampleStreamingSession)); + } else { + retStatus = STATUS_TIMER_QUEUE_STOP_SCHEDULING; + } +CleanUp: + return retStatus; +} + + +VOID videoFrameHandler(UINT64 customData, PFrame pFrame) +{ + PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; + // Parse packet and ad e2e metrics + PBYTE frameDataPtr = pFrame->frameData + ANNEX_B_NALU_SIZE; + UINT32 rawPacketSize = 0; + // Get size of hex encoded data + hexDecode((PCHAR) frameDataPtr, pFrame->size - ANNEX_B_NALU_SIZE, NULL, &rawPacketSize); + PBYTE rawPacket = (PBYTE) MEMCALLOC(1, (rawPacketSize * SIZEOF(BYTE))); + hexDecode((PCHAR) frameDataPtr, pFrame->size - ANNEX_B_NALU_SIZE, rawPacket, &rawPacketSize); + + // Extract the timestamp field from raw packet + frameDataPtr = rawPacket; + UINT64 receivedTs = getUnalignedInt64BigEndian((PINT64)(frameDataPtr)); + frameDataPtr += SIZEOF(UINT64); + UINT32 receivedSize = getUnalignedInt32BigEndian((PINT32)(frameDataPtr)); + + pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.frameLatencyAvg = + EMA_ACCUMULATOR_GET_NEXT(pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.frameLatencyAvg, GETTIME() - receivedTs); + + // Do a size match of the raw packet. Since raw packet does not contain the NALu, the + // comparison would be rawPacketSize + ANNEX_B_NALU_SIZE and the received size + if (rawPacketSize + ANNEX_B_NALU_SIZE == receivedSize) { + pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.sizeMatchAvg = EMA_ACCUMULATOR_GET_NEXT(pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.sizeMatchAvg, 1); + } else { + pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.sizeMatchAvg = EMA_ACCUMULATOR_GET_NEXT(pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.sizeMatchAvg, 0); + } + SAFE_MEMFREE(rawPacket); +} + +VOID audioFrameHandler(UINT64 customData, PFrame pFrame) +{ + UNUSED_PARAM(customData); + DLOGD("Audio Frame received. TrackId: %" PRIu64 ", Size: %u, Flags %u", pFrame->trackId, pFrame->size, pFrame->flags); +} + INT32 main(INT32 argc, CHAR* argv[]) { STATUS retStatus = STATUS_SUCCESS; @@ -44,6 +105,7 @@ INT32 main(INT32 argc, CHAR* argv[]) BOOL locked = FALSE; CHAR clientId[256]; PCHAR region; + UINT32 e2eTimerId = MAX_UINT32; Aws::SDKOptions options; Aws::InitAPI(options); { @@ -56,6 +118,8 @@ INT32 main(INT32 argc, CHAR* argv[]) CHK_STATUS(createSampleConfiguration(CHANNEL_NAME, SIGNALING_CHANNEL_ROLE_TYPE_VIEWER, TRUE, TRUE, logLevel, &pSampleConfiguration)); pSampleConfiguration->mediaType = SAMPLE_STREAMING_AUDIO_VIDEO; + pSampleConfiguration->audioCodec = AUDIO_CODEC; + pSampleConfiguration->videoCodec = VIDEO_CODEC; // Initialize KVS WebRTC. This must be done before anything else, and must only be done once. CHK_STATUS(initKvsWebRtc()); @@ -90,8 +154,8 @@ INT32 main(INT32 argc, CHAR* argv[]) CHK_STATUS(setLocalDescription(pSampleStreamingSession->pPeerConnection, &offerSessionDescriptionInit)); DLOGI("[KVS Viewer] Completed setting local description"); - CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pAudioRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleAudioFrameHandler)); - CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pVideoRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleVideoFrameHandler)); + CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pAudioRtcRtpTransceiver, (UINT64) pSampleStreamingSession, audioFrameHandler)); + CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pVideoRtcRtpTransceiver, (UINT64) pSampleStreamingSession, videoFrameHandler)); if (!pSampleConfiguration->trickleIce) { DLOGI("[KVS Viewer] Non trickle ice. Wait for Candidate collection to complete"); @@ -145,6 +209,9 @@ INT32 main(INT32 argc, CHAR* argv[]) DLOGI("[KVS Viewer] Data Channel open now..."); } + CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, END_TO_END_METRICS_INVOCATION_PERIOD, END_TO_END_METRICS_INVOCATION_PERIOD, + endToendStatsCallback, (UINT64) pSampleStreamingSession, &e2eTimerId)); + // Block until interrupted while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted) && !ATOMIC_LOAD_BOOL(&pSampleStreamingSession->terminateFlag)) { THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_SECOND); diff --git a/samples/Samples.h b/samples/Samples.h index 946e73a971..2bb1a9019a 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -235,6 +235,12 @@ typedef struct { BOOL recorded; } OutgoingRTPStatsCtx, *POutgoingRTPStatsCtx; +typedef struct { + DOUBLE frameLatencyAvg; + DOUBLE dataMatchAvg; + DOUBLE sizeMatchAvg; +} EndToEndMetricsCtx, *PEndToEndMetricsCtx; + typedef struct { UINT64 prevPacketsReceived; UINT64 prevTs; @@ -249,6 +255,7 @@ typedef struct { typedef struct { OutgoingRTPStatsCtx outgoingRTPStatsCtx; IncomingRTPStatsCtx incomingRTPStatsCtx; + EndToEndMetricsCtx endToEndMetricsCtx; PeerConnectionMetrics peerConnectionMetrics; KvsIceAgentMetrics iceMetrics; RtcStats kvsRtcStats; diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 439f89dffa..805b80f52b 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -18,6 +18,7 @@ STATUS terminate(UINT32 timerId, UINT64 currentTime, UINT64 customData) DLOGI("Terminate"); if (gSampleConfiguration != NULL) { ATOMIC_STORE_BOOL(&gSampleConfiguration->interrupted, TRUE); + ATOMIC_STORE_BOOL(&gSampleConfiguration->appTerminateFlag, TRUE); CVAR_BROADCAST(gSampleConfiguration->cvar); } return STATUS_SUCCESS; @@ -289,7 +290,6 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P pSampleStreamingSession->twccMetadata.updateLock = MUTEX_CREATE(TRUE); } - pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime = GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; // Flag to enable SDK to calculate selected ice server, local, remote and candidate pair stats. From 1d68bb0bf890e244839c8cc367386cfabfb54658 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Mon, 20 May 2024 16:03:45 -0700 Subject: [PATCH 11/64] Rearrange, restore original samples --- CMakeLists.txt | 6 - cloudwatch-integ/CMakeLists.txt | 5 + cloudwatch-integ/CloudwatchLogs.cpp | 2 +- cloudwatch-integ/Include.h | 23 ++-- .../kvsWebRTCClientMasterCloudwatch.cpp | 20 ++-- .../kvsWebRTCClientViewerCloudwatch.cpp | 6 +- samples/Samples.h | 7 +- samples/lib/Common.c | 111 +++++++++--------- samples/lib/MetricsHandling.c | 9 +- samples/sample_config.h | 15 --- 10 files changed, 97 insertions(+), 107 deletions(-) delete mode 100644 samples/sample_config.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 81ee123f51..e2b4da1af4 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,12 +34,6 @@ option(THREAD_SANITIZER "Build with ThreadSanitizer." OFF) option(UNDEFINED_BEHAVIOR_SANITIZER "Build with UndefinedBehaviorSanitizer." OFF) option(LINK_PROFILER "Link gperftools profiler" OFF) - -set(SAMPLE_CONFIG_HEADER "" CACHE FILEPATH "Config header") - -add_definitions(-DSAMPLE_CONFIG_HEADER="${SAMPLE_CONFIG_HEADER}") -message(STATUS ${SAMPLE_CONFIG_HEADER}) - if(WIN32) set(EXT_PTHREAD_INCLUDE_DIR "" CACHE PATH "Path to the PThread dir") set(EXT_PTHREAD_LIBRARIES "" CACHE FILEPATH "Path to PThread libraries") diff --git a/cloudwatch-integ/CMakeLists.txt b/cloudwatch-integ/CMakeLists.txt index 1515fc52c5..7ed93ff8f6 100644 --- a/cloudwatch-integ/CMakeLists.txt +++ b/cloudwatch-integ/CMakeLists.txt @@ -12,6 +12,11 @@ link_directories(${OPEN_SRC_INSTALL_PREFIX}/lib) find_package(ZLIB REQUIRED) find_package(AWSSDK REQUIRED COMPONENTS monitoring logs) +set(SAMPLE_CONFIG_HEADER "config_periodic.h" CACHE FILEPATH "Config header") + +add_definitions(-DSAMPLE_CONFIG_HEADER="${SAMPLE_CONFIG_HEADER}") +message(STATUS ${SAMPLE_CONFIG_HEADER}) + add_executable( kvsWebrtcClientMasterCW ../samples/lib/Common.c diff --git a/cloudwatch-integ/CloudwatchLogs.cpp b/cloudwatch-integ/CloudwatchLogs.cpp index 7bc8318c68..28f361402f 100644 --- a/cloudwatch-integ/CloudwatchLogs.cpp +++ b/cloudwatch-integ/CloudwatchLogs.cpp @@ -18,7 +18,7 @@ STATUS CloudwatchLogs::init(PCHAR channelName, PCHAR region, BOOL isMaster) << GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; this->logStreamName = defaultLogStreamName.str(); - this->logGroupName = CANARY_DEFAULT_LOG_GROUP_NAME; + this->logGroupName = CLOUDWATCH_DEFAULT_LOG_GROUP_NAME; DLOGI("Log stream name: %s", this->logStreamName.c_str()); diff --git a/cloudwatch-integ/Include.h b/cloudwatch-integ/Include.h index 1548821d7a..278cafd080 100644 --- a/cloudwatch-integ/Include.h +++ b/cloudwatch-integ/Include.h @@ -1,5 +1,7 @@ #pragma once +#include SAMPLE_CONFIG_HEADER + #define DEFAULT_CLOUDWATCH_NAMESPACE "KinesisVideoSDKWebRTC" #define DEFAULT_FPS_VALUE 25 // TODO: This value shouldn't matter. But, since we don't allow NULL value, we have to set to a value @@ -13,26 +15,17 @@ #define NUMBER_OF_H264_FRAME_FILES 1500 #define NUMBER_OF_OPUS_FRAME_FILES 618 -#define CANARY_METADATA_SIZE (SIZEOF(UINT64) + SIZEOF(UINT32) + SIZEOF(UINT32)) +#define FRAME_METADATA_SIZE (SIZEOF(UINT64) + SIZEOF(UINT32) + SIZEOF(UINT32)) #define ANNEX_B_NALU_SIZE 4 -#define CANARY_DEFAULT_FRAMERATE 30 -#define CANARY_DEFAULT_BITRATE (250 * 1024) - -#define CANARY_DEFAULT_ITERATION_DURATION_IN_SECONDS 30 - -#define CANARY_DEFAULT_VIEWER_INIT_DELAY (5 * HUNDREDS_OF_NANOS_IN_A_SECOND) - -#define CANARY_MIN_DURATION (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) -#define CANARY_MIN_ITERATION_DURATION (15 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define END_TO_END_METRICS_INVOCATION_PERIOD (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define STORAGE_CANARY_FIRST_FRAME_TS_FILE_ENV_VAR "STORAGE_CANARY_FIRST_FRAME_TS_FILE" -#define CANARY_DEFAULT_LABEL "ScaryTestLabel" -#define CANARY_DEFAULT_CHANNEL_NAME "ScaryTestStream" -#define CANARY_DEFAULT_CLIENT_ID "DefaultClientId" -#define CANARY_DEFAULT_LOG_GROUP_NAME "DefaultLogGroupName" +#define CLOUDWATCH_DEFAULT_LABEL "ScaryTestLabel" +#define CLOUDWATCH_DEFAULT_CHANNEL_NAME "ScaryTestStream" +#define CLOUDWATCH_DEFAULT_CLIENT_ID "DefaultClientId" +#define CLOUDWATCH_DEFAULT_LOG_GROUP_NAME "DefaultLogGroupName" #define FIRST_FRAME_TS_FILE_PATH "../" #define STORAGE_CANARY_DEFAULT_FIRST_FRAME_TS_FILE "DefaultFirstFrameSentTSFileName.txt" @@ -41,8 +34,6 @@ #define AGGREGATE_STORAGE_CW_DIMENSION "StorageWebRTCSDKCanaryLabel" #define AGGREGATE_CW_DIMENSION "WebRTCSDKCanaryLabel" -#define CANARY_METADATA_SIZE (SIZEOF(UINT64) + SIZEOF(UINT32) + SIZEOF(UINT32)) - #define MAX_CALL_RETRY_COUNT 10 #include diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 4980fa24cc..211ca19918 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -66,7 +66,7 @@ VOID createMockFrames(PBYTE buffer, PFrame pFrame) UINT32 i; // For decoding purposes, the first 4 bytes need to be a NALu putUnalignedInt32BigEndian((PINT32) buffer, 0x00000001); - for (i = ANNEX_B_NALU_SIZE + CANARY_METADATA_SIZE; i < pFrame->size; i++) { + for (i = ANNEX_B_NALU_SIZE + FRAME_METADATA_SIZE; i < pFrame->size; i++) { buffer[i] = RAND(); } addMetadataToFrameData(buffer, pFrame); @@ -81,8 +81,8 @@ PVOID sendVideoPackets(PVOID args) UINT32 hexStrLen = 0; UINT32 actualFrameSize = 0; UINT32 frameSizeWithoutNalu = 0; - UINT32 minFrameSize = CANARY_METADATA_SIZE + ((DEFAULT_BITRATE / 8) / DEFAULT_FRAMERATE); - UINT32 maxFrameSize = (CANARY_METADATA_SIZE + ((DEFAULT_BITRATE / 8) / DEFAULT_FRAMERATE)) * 2; + UINT32 minFrameSize = FRAME_METADATA_SIZE + ((DEFAULT_BITRATE / 8) / DEFAULT_FRAMERATE); + UINT32 maxFrameSize = (FRAME_METADATA_SIZE + ((DEFAULT_BITRATE / 8) / DEFAULT_FRAMERATE)) * 2; PBYTE frameData = NULL; PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) args; @@ -218,6 +218,7 @@ INT32 main(INT32 argc, CHAR* argv[]) PSampleConfiguration pSampleConfiguration = NULL; SignalingClientMetrics signalingClientMetrics; PCHAR region; + UINT32 terminateId = MAX_UINT32; Aws::SDKOptions options; Aws::InitAPI(options); { @@ -226,7 +227,7 @@ INT32 main(INT32 argc, CHAR* argv[]) initKvsWebRtc(); UINT32 logLevel = setLogLevel(); - CHK_STATUS(createSampleConfiguration(CHANNEL_NAME, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration)); + CHK_STATUS(createSampleConfiguration(CHANNEL_NAME, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, USE_TRICKLE_ICE, USE_TURN, logLevel, &pSampleConfiguration)); // Set the audio and video handlers pSampleConfiguration->audioSource = sendAudioPackets; @@ -234,10 +235,9 @@ INT32 main(INT32 argc, CHAR* argv[]) pSampleConfiguration->receiveAudioVideoSource = NULL; pSampleConfiguration->audioCodec = AUDIO_CODEC; pSampleConfiguration->videoCodec = VIDEO_CODEC; - - if (USE_STORAGE) { - pSampleConfiguration->channelInfo.useMediaStorage = TRUE; - } + pSampleConfiguration->forceTurn = FORCE_TURN_ONLY; + pSampleConfiguration->enableMetrics = ENABLE_METRICS; + pSampleConfiguration->channelInfo.useMediaStorage = USE_STORAGE; if ((region = GETENV(DEFAULT_REGION_ENV_VAR)) == NULL) { region = (PCHAR) DEFAULT_AWS_REGION; @@ -271,6 +271,10 @@ INT32 main(INT32 argc, CHAR* argv[]) std::thread pushProfilingThread(sendProfilingMetrics, pSampleConfiguration); pushProfilingThread.join(); // Checking for termination + + CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, SAMPLE_RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, + (UINT64) pSampleConfiguration, &terminateId)); + CHK_STATUS(sessionCleanupWait(pSampleConfiguration)); DLOGI("[KVS Master] Streaming session terminated"); if (retStatus != STATUS_SUCCESS) { diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index 1489ef2199..ba2b81c311 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -91,7 +91,6 @@ VOID videoFrameHandler(UINT64 customData, PFrame pFrame) VOID audioFrameHandler(UINT64 customData, PFrame pFrame) { UNUSED_PARAM(customData); - DLOGD("Audio Frame received. TrackId: %" PRIu64 ", Size: %u, Flags %u", pFrame->trackId, pFrame->size, pFrame->flags); } INT32 main(INT32 argc, CHAR* argv[]) @@ -116,10 +115,13 @@ INT32 main(INT32 argc, CHAR* argv[]) signal(SIGINT, sigintHandler); #endif - CHK_STATUS(createSampleConfiguration(CHANNEL_NAME, SIGNALING_CHANNEL_ROLE_TYPE_VIEWER, TRUE, TRUE, logLevel, &pSampleConfiguration)); + CHK_STATUS(createSampleConfiguration(CHANNEL_NAME, SIGNALING_CHANNEL_ROLE_TYPE_VIEWER, USE_TRICKLE_ICE, USE_TURN, logLevel, &pSampleConfiguration)); pSampleConfiguration->mediaType = SAMPLE_STREAMING_AUDIO_VIDEO; pSampleConfiguration->audioCodec = AUDIO_CODEC; pSampleConfiguration->videoCodec = VIDEO_CODEC; + pSampleConfiguration->forceTurn = FORCE_TURN_ONLY; + pSampleConfiguration->enableMetrics = ENABLE_METRICS; + pSampleConfiguration->channelInfo.useMediaStorage = USE_STORAGE; // Initialize KVS WebRTC. This must be done before anything else, and must only be done once. CHK_STATUS(initKvsWebRtc()); diff --git a/samples/Samples.h b/samples/Samples.h index 2bb1a9019a..a8d05530e3 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -11,11 +11,9 @@ extern "C" { #endif #include -#include SAMPLE_CONFIG_HEADER #define KVS_DEFAULT_MEDIA_SENDER_THREAD_STACK_SIZE 64 * 1024 #define KVS_MINIMUM_THREAD_STACK_SIZE 16 * 1024 - #define NUMBER_OF_H264_FRAME_FILES 1500 #define NUMBER_OF_H265_FRAME_FILES 1500 #define NUMBER_OF_OPUS_FRAME_FILES 618 @@ -49,6 +47,7 @@ extern "C" { #define SAMPLE_STATS_DURATION (60 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define SAMPLE_VIDEO_FRAME_DURATION (HUNDREDS_OF_NANOS_IN_A_SECOND / DEFAULT_FPS_VALUE) +#define SAMPLE_PRE_GENERATE_CERT TRUE #define SAMPLE_PRE_GENERATE_CERT_PERIOD (1000 * HUNDREDS_OF_NANOS_IN_A_MILLISECOND) #define SAMPLE_SESSION_CLEANUP_WAIT_PERIOD (5 * HUNDREDS_OF_NANOS_IN_A_SECOND) @@ -177,13 +176,14 @@ typedef struct { MUTEX signalingSendMessageLock; UINT32 pregenerateCertTimerId; - UINT32 terminateId; PStackQueue pregeneratedCertificates; // Max MAX_RTCCONFIGURATION_CERTIFICATES certificates PCHAR rtspUri; UINT32 logLevel; BOOL enableIceStats; BOOL enableTwcc; + BOOL forceTurn; + BOOL enableMetrics; SignalingClientMetrics signalingClientMetrics; } SampleConfiguration, *PSampleConfiguration; @@ -355,6 +355,7 @@ VOID onIceCandidateHandler(UINT64, PCHAR); PVOID mediaSenderRoutine(PVOID); STATUS setupMetricsCtx(PSampleStreamingSession); STATUS getSdkTimeProfile(PSampleStreamingSession); +STATUS terminate(UINT32 timerId, UINT64 currentTime, UINT64 customData); #ifdef __cplusplus } #endif diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 805b80f52b..27d2375329 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -1,6 +1,5 @@ #define LOG_CLASS "WebRtcSamples" #include "../Samples.h" -#include SAMPLE_CONFIG_HEADER PSampleConfiguration gSampleConfiguration = NULL; @@ -13,9 +12,17 @@ VOID sigintHandler(INT32 sigNum) } } +STATUS signalingCallFailed(STATUS status) +{ + return (STATUS_SIGNALING_GET_TOKEN_CALL_FAILED == status || STATUS_SIGNALING_DESCRIBE_CALL_FAILED == status || + STATUS_SIGNALING_CREATE_CALL_FAILED == status || STATUS_SIGNALING_GET_ENDPOINT_CALL_FAILED == status || + STATUS_SIGNALING_GET_ICE_CONFIG_CALL_FAILED == status || STATUS_SIGNALING_CONNECT_CALL_FAILED == status || + STATUS_SIGNALING_DESCRIBE_MEDIA_CALL_FAILED == status); +} + STATUS terminate(UINT32 timerId, UINT64 currentTime, UINT64 customData) { - DLOGI("Terminate"); + DLOGI("Terminating the app"); if (gSampleConfiguration != NULL) { ATOMIC_STORE_BOOL(&gSampleConfiguration->interrupted, TRUE); ATOMIC_STORE_BOOL(&gSampleConfiguration->appTerminateFlag, TRUE); @@ -24,14 +31,6 @@ STATUS terminate(UINT32 timerId, UINT64 currentTime, UINT64 customData) return STATUS_SUCCESS; } -STATUS signalingCallFailed(STATUS status) -{ - return (STATUS_SIGNALING_GET_TOKEN_CALL_FAILED == status || STATUS_SIGNALING_DESCRIBE_CALL_FAILED == status || - STATUS_SIGNALING_CREATE_CALL_FAILED == status || STATUS_SIGNALING_GET_ENDPOINT_CALL_FAILED == status || - STATUS_SIGNALING_GET_ICE_CONFIG_CALL_FAILED == status || STATUS_SIGNALING_CONNECT_CALL_FAILED == status || - STATUS_SIGNALING_DESCRIBE_MEDIA_CALL_FAILED == status); -} - VOID onConnectionStateChange(UINT64 customData, RTC_PEER_CONNECTION_STATE newState) { STATUS retStatus = STATUS_SUCCESS; @@ -171,7 +170,7 @@ STATUS initializePeerConnection(PSampleConfiguration pSampleConfiguration, PRtcP // Set the ICE mode explicitly - if (FORCE_TURN_ONLY) { + if (pSampleConfiguration->forceTurn) { configuration.iceTransportPolicy = ICE_TRANSPORT_POLICY_RELAY; } else { configuration.iceTransportPolicy = ICE_TRANSPORT_POLICY_ALL; @@ -266,8 +265,6 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P pSampleStreamingSession->offerReceiveTime = GETTIME(); CHK(pSampleStreamingSession != NULL, STATUS_NOT_ENOUGH_MEMORY); - CHK_STATUS(setupMetricsCtx(pSampleStreamingSession)); - if (isMaster) { STRCPY(pSampleStreamingSession->peerId, peerId); } else { @@ -290,8 +287,12 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P pSampleStreamingSession->twccMetadata.updateLock = MUTEX_CREATE(TRUE); } - pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime = - GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + if(pSampleConfiguration->enableMetrics) { + CHK_STATUS(setupMetricsCtx(pSampleStreamingSession)); + pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime = + GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + } + // Flag to enable SDK to calculate selected ice server, local, remote and candidate pair stats. pSampleConfiguration->enableIceStats = FALSE; @@ -346,6 +347,7 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P sampleSenderBandwidthEstimationHandler)); } pSampleStreamingSession->startUpLatency = 0; + CleanUp: if (STATUS_FAILED(retStatus) && pSampleStreamingSession != NULL) { @@ -519,17 +521,17 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE CHK(ppSampleConfiguration != NULL, STATUS_NULL_ARG); CHK(NULL != (pSampleConfiguration = (PSampleConfiguration) MEMCALLOC(1, SIZEOF(SampleConfiguration))), STATUS_NOT_ENOUGH_MEMORY); - if (IOT_CORE_ENABLE_CREDENTIALS) { - CHK_ERR((pIotCoreCredentialEndPoint = GETENV(IOT_CORE_CREDENTIAL_ENDPOINT)) != NULL, STATUS_INVALID_OPERATION, - "AWS_IOT_CORE_CREDENTIAL_ENDPOINT must be set"); - CHK_ERR((pIotCoreCert = GETENV(IOT_CORE_CERT)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_CERT must be set"); - CHK_ERR((pIotCorePrivateKey = GETENV(IOT_CORE_PRIVATE_KEY)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_PRIVATE_KEY must be set"); - CHK_ERR((pIotCoreRoleAlias = GETENV(IOT_CORE_ROLE_ALIAS)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_ROLE_ALIAS must be set"); - CHK_ERR((pIotCoreThingName = GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set"); - } else { - CHK_ERR((pAccessKey = GETENV(ACCESS_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_ACCESS_KEY_ID must be set"); - CHK_ERR((pSecretKey = GETENV(SECRET_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_SECRET_ACCESS_KEY must be set"); - } +#ifdef IOT_CORE_ENABLE_CREDENTIALS + CHK_ERR((pIotCoreCredentialEndPoint = GETENV(IOT_CORE_CREDENTIAL_ENDPOINT)) != NULL, STATUS_INVALID_OPERATION, + "AWS_IOT_CORE_CREDENTIAL_ENDPOINT must be set"); + CHK_ERR((pIotCoreCert = GETENV(IOT_CORE_CERT)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_CERT must be set"); + CHK_ERR((pIotCorePrivateKey = GETENV(IOT_CORE_PRIVATE_KEY)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_PRIVATE_KEY must be set"); + CHK_ERR((pIotCoreRoleAlias = GETENV(IOT_CORE_ROLE_ALIAS)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_ROLE_ALIAS must be set"); + CHK_ERR((pIotCoreThingName = GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set"); +#else + CHK_ERR((pAccessKey = GETENV(ACCESS_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_ACCESS_KEY_ID must be set"); + CHK_ERR((pSecretKey = GETENV(SECRET_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_SECRET_ACCESS_KEY must be set"); +#endif pSessionToken = GETENV(SESSION_TOKEN_ENV_VAR); if (pSessionToken != NULL && IS_EMPTY_STRING(pSessionToken)) { DLOGW("Session token is set but its value is empty. Ignoring."); @@ -563,13 +565,13 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE CHK_STATUS(lookForSslCert(&pSampleConfiguration)); - if (IOT_CORE_ENABLE_CREDENTIALS) { - CHK_STATUS(createLwsIotCredentialProvider(pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pSampleConfiguration->pCaCertPath, - pIotCoreRoleAlias, pIotCoreThingName, &pSampleConfiguration->pCredentialProvider)); - } else { - CHK_STATUS( - createStaticCredentialProvider(pAccessKey, 0, pSecretKey, 0, pSessionToken, 0, MAX_UINT64, &pSampleConfiguration->pCredentialProvider)); - } +#ifdef IOT_CORE_ENABLE_CREDENTIALS + CHK_STATUS(createLwsIotCredentialProvider(pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pSampleConfiguration->pCaCertPath, + pIotCoreRoleAlias, pIotCoreThingName, &pSampleConfiguration->pCredentialProvider)); +#else + CHK_STATUS( + createStaticCredentialProvider(pAccessKey, 0, pSecretKey, 0, pSessionToken, 0, MAX_UINT64, &pSampleConfiguration->pCredentialProvider)); +#endif pSampleConfiguration->mediaSenderTid = INVALID_TID_VALUE; pSampleConfiguration->audioSenderTid = INVALID_TID_VALUE; @@ -579,22 +581,23 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE pSampleConfiguration->cvar = CVAR_CREATE(); pSampleConfiguration->streamingSessionListReadLock = MUTEX_CREATE(FALSE); pSampleConfiguration->signalingSendMessageLock = MUTEX_CREATE(FALSE); + pSampleConfiguration->forceTurn = FALSE; /* This is ignored for master. Master can extract the info from offer. Viewer has to know if peer can trickle or * not ahead of time. */ - pSampleConfiguration->trickleIce = USE_TRICKLE_ICE; - pSampleConfiguration->useTurn = USE_TURN; - pSampleConfiguration->enableSendingMetricsToViewerViaDc = ENABLE_TTFF_VIA_DC; + pSampleConfiguration->trickleIce = trickleIce; + pSampleConfiguration->useTurn = useTurn; + pSampleConfiguration->enableSendingMetricsToViewerViaDc = FALSE; pSampleConfiguration->receiveAudioVideoSource = NULL; pSampleConfiguration->channelInfo.version = CHANNEL_INFO_CURRENT_VERSION; - pSampleConfiguration->channelInfo.pChannelName = CHANNEL_NAME; - if (IOT_CORE_ENABLE_CREDENTIALS) { - if ((pIotCoreCertificateId = GETENV(IOT_CORE_CERTIFICATE_ID)) != NULL) { - pSampleConfiguration->channelInfo.pChannelName = pIotCoreCertificateId; - } + pSampleConfiguration->channelInfo.pChannelName = channelName; +#ifdef IOT_CORE_ENABLE_CREDENTIALS + if ((pIotCoreCertificateId = GETENV(IOT_CORE_CERTIFICATE_ID)) != NULL) { + pSampleConfiguration->channelInfo.pChannelName = pIotCoreCertificateId; } +#endif pSampleConfiguration->channelInfo.pKmsKeyId = NULL; pSampleConfiguration->channelInfo.tagCount = 0; @@ -608,7 +611,6 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE pSampleConfiguration->channelInfo.reconnect = TRUE; pSampleConfiguration->channelInfo.pCertPath = pSampleConfiguration->pCaCertPath; pSampleConfiguration->channelInfo.messageTtl = 0; // Default is 60 seconds - pSampleConfiguration->channelInfo.useMediaStorage = ENABLE_STORAGE; pSampleConfiguration->signalingClientCallbacks.version = SIGNALING_CLIENT_CALLBACKS_CURRENT_VERSION; pSampleConfiguration->signalingClientCallbacks.errorReportFn = signalingClientError; @@ -640,20 +642,17 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE CHK_STATUS(stackQueueCreate(&pSampleConfiguration->pregeneratedCertificates)); // Start the cert pre-gen timer callback - if (SAMPLE_PRE_GENERATE_CERT) { - CHK_LOG_ERR(retStatus = - timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, 0, SAMPLE_PRE_GENERATE_CERT_PERIOD, pregenerateCertTimerCallback, - (UINT64) pSampleConfiguration, &pSampleConfiguration->pregenerateCertTimerId)); - } +#ifdef SAMPLE_PRE_GENERATE_CERT + CHK_LOG_ERR(retStatus = + timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, 0, SAMPLE_PRE_GENERATE_CERT_PERIOD, pregenerateCertTimerCallback, + (UINT64) pSampleConfiguration, &pSampleConfiguration->pregenerateCertTimerId)); +#endif pSampleConfiguration->iceUriCount = 0; CHK_STATUS(stackQueueCreate(&pSampleConfiguration->pPendingSignalingMessageForRemoteClient)); CHK_STATUS(hashTableCreateWithParams(SAMPLE_HASH_TABLE_BUCKET_COUNT, SAMPLE_HASH_TABLE_BUCKET_LENGTH, &pSampleConfiguration->pRtcPeerConnectionForRemoteClient)); - - CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, SAMPLE_RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, - (UINT64) pSampleConfiguration, &pSampleConfiguration->terminateId)); CleanUp: if (STATUS_FAILED(retStatus)) { @@ -876,11 +875,13 @@ STATUS freeSampleConfiguration(PSampleConfiguration* ppSampleConfiguration) CVAR_FREE(pSampleConfiguration->cvar); } - if (IOT_CORE_ENABLE_CREDENTIALS) { - freeIotCredentialProvider(&pSampleConfiguration->pCredentialProvider); - } else { - freeStaticCredentialProvider(&pSampleConfiguration->pCredentialProvider); - } +#ifdef IOT_CORE_ENABLE_CREDENTIALS + freeIotCredentialProvider(&pSampleConfiguration->pCredentialProvider); +} +else +{ + freeStaticCredentialProvider(&pSampleConfiguration->pCredentialProvider); +#endif if (pSampleConfiguration->pregeneratedCertificates != NULL) { stackQueueGetIterator(pSampleConfiguration->pregeneratedCertificates, &iterator); diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index 6233031887..e1ad14aad0 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -3,7 +3,14 @@ STATUS setupMetricsCtx(PSampleStreamingSession pSampleStreamingSession) { STATUS retStatus = STATUS_SUCCESS; - if (ENABLE_METRICS) { + if(pSampleStreamingSession == NULL) { + DLOGI("NUll"); + } + if(pSampleStreamingSession->pSampleConfiguration == NULL) { + DLOGI("bykkbedk"); + } + CHK(pSampleStreamingSession != NULL && pSampleStreamingSession->pSampleConfiguration != NULL, STATUS_NULL_ARG); + if (pSampleStreamingSession->pSampleConfiguration->enableMetrics) { CHK(NULL != (pSampleStreamingSession->pStatsCtx = (PStatsCtx) MEMCALLOC(1, SIZEOF(StatsCtx))), STATUS_NOT_ENOUGH_MEMORY); } CleanUp: diff --git a/samples/sample_config.h b/samples/sample_config.h deleted file mode 100644 index ef8451c45f..0000000000 --- a/samples/sample_config.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef KVS_SDK_SAMPLE_CONFIG_H -#define KVS_SDK_SAMPLE_CONFIG_H - -#define USE_TRICKLE_ICE TRUE -#define FORCE_TURN_ONLY FALSE -#define CHANNEL_NAME (PCHAR) "test" -#define USE_TURN TRUE -#define ENABLE_TTFF_VIA_DC FALSE -#define IOT_CORE_ENABLE_CREDENTIALS FALSE -#define ENABLE_STORAGE FALSE -#define ENABLE_METRICS FALSE -#define SAMPLE_PRE_GENERATE_CERT TRUE -#define SAMPLE_RUN_TIME (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) - -#endif // KVS_SDK_SAMPLE_CONFIG_H From bdc40c2b3b22f2df3c4db92ad0ee95b26f6b77e5 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 21 May 2024 13:30:15 -0700 Subject: [PATCH 12/64] iot, label names --- cloudwatch-integ/CloudwatchLogs.cpp | 2 +- cloudwatch-integ/Include.h | 5 +- cloudwatch-integ/config_periodic.h | 5 +- .../kvsWebRTCClientMasterCloudwatch.cpp | 12 +++- .../kvsWebRTCClientViewerCloudwatch.cpp | 11 ++- samples/Samples.h | 4 +- samples/kvsWebRTCClientMaster.c | 7 ++ samples/lib/Common.c | 67 ++++++++++--------- 8 files changed, 66 insertions(+), 47 deletions(-) diff --git a/cloudwatch-integ/CloudwatchLogs.cpp b/cloudwatch-integ/CloudwatchLogs.cpp index 28f361402f..56e30ef947 100644 --- a/cloudwatch-integ/CloudwatchLogs.cpp +++ b/cloudwatch-integ/CloudwatchLogs.cpp @@ -18,7 +18,7 @@ STATUS CloudwatchLogs::init(PCHAR channelName, PCHAR region, BOOL isMaster) << GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; this->logStreamName = defaultLogStreamName.str(); - this->logGroupName = CLOUDWATCH_DEFAULT_LOG_GROUP_NAME; + this->logGroupName = LOG_GROUP_NAME; DLOGI("Log stream name: %s", this->logStreamName.c_str()); diff --git a/cloudwatch-integ/Include.h b/cloudwatch-integ/Include.h index 278cafd080..8a40b135d2 100644 --- a/cloudwatch-integ/Include.h +++ b/cloudwatch-integ/Include.h @@ -15,6 +15,7 @@ #define NUMBER_OF_H264_FRAME_FILES 1500 #define NUMBER_OF_OPUS_FRAME_FILES 618 +#define CHANNEL_NAME_TEMPLATE (PCHAR) "%s-%s" #define FRAME_METADATA_SIZE (SIZEOF(UINT64) + SIZEOF(UINT32) + SIZEOF(UINT32)) #define ANNEX_B_NALU_SIZE 4 @@ -22,10 +23,6 @@ #define STORAGE_CANARY_FIRST_FRAME_TS_FILE_ENV_VAR "STORAGE_CANARY_FIRST_FRAME_TS_FILE" -#define CLOUDWATCH_DEFAULT_LABEL "ScaryTestLabel" -#define CLOUDWATCH_DEFAULT_CHANNEL_NAME "ScaryTestStream" -#define CLOUDWATCH_DEFAULT_CLIENT_ID "DefaultClientId" -#define CLOUDWATCH_DEFAULT_LOG_GROUP_NAME "DefaultLogGroupName" #define FIRST_FRAME_TS_FILE_PATH "../" #define STORAGE_CANARY_DEFAULT_FIRST_FRAME_TS_FILE "DefaultFirstFrameSentTSFileName.txt" diff --git a/cloudwatch-integ/config_periodic.h b/cloudwatch-integ/config_periodic.h index f35acb18ae..44c1ee62a6 100644 --- a/cloudwatch-integ/config_periodic.h +++ b/cloudwatch-integ/config_periodic.h @@ -3,7 +3,8 @@ #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE -#define CHANNEL_NAME (PCHAR) "test" +#define RUNNER_LABEL (PCHAR) "WebrtcPeriodicOpenSSL" +#define SCENARIO_LABEL (PCHAR) "OpenSSLPeriodic" #define USE_TURN TRUE #define ENABLE_TTFF_VIA_DC FALSE #define IOT_CORE_ENABLE_CREDENTIALS FALSE @@ -11,6 +12,8 @@ #define ENABLE_METRICS TRUE #define SAMPLE_PRE_GENERATE_CERT TRUE #define SAMPLE_RUN_TIME (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" +#define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" #define USE_STORAGE FALSE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 211ca19918..c52669a3b7 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -219,6 +219,8 @@ INT32 main(INT32 argc, CHAR* argv[]) SignalingClientMetrics signalingClientMetrics; PCHAR region; UINT32 terminateId = MAX_UINT32; + CHAR channelName[MAX_CHANNEL_NAME_LEN]; + PCHAR channelNamePrefix; Aws::SDKOptions options; Aws::InitAPI(options); { @@ -227,7 +229,11 @@ INT32 main(INT32 argc, CHAR* argv[]) initKvsWebRtc(); UINT32 logLevel = setLogLevel(); - CHK_STATUS(createSampleConfiguration(CHANNEL_NAME, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, USE_TRICKLE_ICE, USE_TURN, logLevel, &pSampleConfiguration)); + + channelNamePrefix = argc > 1 ? argv[1] : CHANNEL_NAME_PREFIX; + SNPRINTF(channelName, SIZEOF(channelName), CHANNEL_NAME_TEMPLATE, channelNamePrefix, RUNNER_LABEL); + + CHK_STATUS(createSampleConfiguration(channelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, USE_TRICKLE_ICE, USE_TURN, logLevel, &pSampleConfiguration)); // Set the audio and video handlers pSampleConfiguration->audioSource = sendAudioPackets; @@ -242,7 +248,7 @@ INT32 main(INT32 argc, CHAR* argv[]) if ((region = GETENV(DEFAULT_REGION_ENV_VAR)) == NULL) { region = (PCHAR) DEFAULT_AWS_REGION; } - CppInteg::Cloudwatch::init(CHANNEL_NAME, region, TRUE); + CppInteg::Cloudwatch::init(channelName, region, TRUE); if(ENABLE_DATA_CHANNEL) { pSampleConfiguration->onDataChannel = onDataChannel; @@ -266,7 +272,7 @@ INT32 main(INT32 argc, CHAR* argv[]) pSampleConfiguration->signalingClientMetrics.signalingEndTime, pSampleConfiguration->signalingClientMetrics.signalingCallTime, "Initialize signaling client and connect to the signaling channel"); - DLOGI("[KVS Master] Channel %s set up done ", CHANNEL_NAME); + DLOGI("[KVS Master] Channel %s set up done ", channelName); std::thread pushProfilingThread(sendProfilingMetrics, pSampleConfiguration); pushProfilingThread.join(); diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index ba2b81c311..5618d5424b 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -104,6 +104,8 @@ INT32 main(INT32 argc, CHAR* argv[]) BOOL locked = FALSE; CHAR clientId[256]; PCHAR region; + CHAR channelName[MAX_CHANNEL_NAME_LEN]; + PCHAR channelNamePrefix; UINT32 e2eTimerId = MAX_UINT32; Aws::SDKOptions options; Aws::InitAPI(options); @@ -115,7 +117,10 @@ INT32 main(INT32 argc, CHAR* argv[]) signal(SIGINT, sigintHandler); #endif - CHK_STATUS(createSampleConfiguration(CHANNEL_NAME, SIGNALING_CHANNEL_ROLE_TYPE_VIEWER, USE_TRICKLE_ICE, USE_TURN, logLevel, &pSampleConfiguration)); + channelNamePrefix = argc > 1 ? argv[1] : CHANNEL_NAME_PREFIX; + SNPRINTF(channelName, SIZEOF(channelName), CHANNEL_NAME_TEMPLATE, channelNamePrefix, RUNNER_LABEL); + + CHK_STATUS(createSampleConfiguration(channelName, SIGNALING_CHANNEL_ROLE_TYPE_VIEWER, USE_TRICKLE_ICE, USE_TURN, logLevel, &pSampleConfiguration)); pSampleConfiguration->mediaType = SAMPLE_STREAMING_AUDIO_VIDEO; pSampleConfiguration->audioCodec = AUDIO_CODEC; pSampleConfiguration->videoCodec = VIDEO_CODEC; @@ -134,7 +139,7 @@ INT32 main(INT32 argc, CHAR* argv[]) if ((region = GETENV(DEFAULT_REGION_ENV_VAR)) == NULL) { region = (PCHAR) DEFAULT_AWS_REGION; } - CppInteg::Cloudwatch::init(CHANNEL_NAME, region, FALSE); + CppInteg::Cloudwatch::init(channelName, region, FALSE); SNPRINTF(clientId, SIZEOF(clientId), "%s_%u", SAMPLE_VIEWER_CLIENT_ID, RAND() % MAX_UINT32); CHK_STATUS(initSignaling(pSampleConfiguration, clientId)); @@ -203,7 +208,7 @@ INT32 main(INT32 argc, CHAR* argv[]) SIZE_T datachannelLocalOpenCount = 0; // Creating a new datachannel on the peer connection of the existing sample streaming session - CHK_STATUS(createDataChannel(pPeerConnection, CHANNEL_NAME, NULL, &pDataChannel)); + CHK_STATUS(createDataChannel(pPeerConnection, channelName, NULL, &pDataChannel)); DLOGI("[KVS Viewer] Creating data channel...completed"); // Setting a callback for when the data channel is open diff --git a/samples/Samples.h b/samples/Samples.h index a8d05530e3..e7d1007e59 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -71,8 +71,8 @@ extern "C" { #define IOT_CORE_THING_NAME ((PCHAR) "AWS_IOT_CORE_THING_NAME") #define IOT_CORE_CERTIFICATE_ID ((PCHAR) "AWS_IOT_CORE_CERTIFICATE_ID") -/* Uncomment the following line in order to enable IoT credentials checks in the provided samples */ -// #define IOT_CORE_ENABLE_CREDENTIALS 1 +/* Set to TRUE to enable credentials */ +#define IOT_CORE_ENABLE_CREDENTIALS FALSE #define MASTER_DATA_CHANNEL_MESSAGE "This message is from the KVS Master" #define VIEWER_DATA_CHANNEL_MESSAGE "This message is from the KVS Viewer" diff --git a/samples/kvsWebRTCClientMaster.c b/samples/kvsWebRTCClientMaster.c index a1b06b0a8a..7d817470f4 100644 --- a/samples/kvsWebRTCClientMaster.c +++ b/samples/kvsWebRTCClientMaster.c @@ -20,6 +20,13 @@ INT32 main(INT32 argc, CHAR* argv[]) signal(SIGINT, sigintHandler); #endif + if(IOT_CORE_ENABLE_CREDENTIALS) { + CHK_ERR((pChannelName = argc > 1 ? argv[1] : GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, + "AWS_IOT_CORE_THING_NAME must be set"); + } else { + pChannelName = argc > 1 ? argv[1] : SAMPLE_CHANNEL_NAME; + } + CHK_STATUS(createSampleConfiguration(pChannelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration)); if (argc > 3) { diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 27d2375329..a8d81d8544 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -301,12 +301,12 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P CHK_STATUS( peerConnectionOnConnectionStateChange(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, onConnectionStateChange)); - if (ENABLE_DATA_CHANNEL) { +#ifdef ENABLE_DATA_CHANNEL if (pSampleConfiguration->onDataChannel != NULL) { CHK_STATUS(peerConnectionOnDataChannel(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, pSampleConfiguration->onDataChannel)); } - } +#endif CHK_STATUS(addSupportedCodec(pSampleStreamingSession->pPeerConnection, pSampleConfiguration->videoCodec)); CHK_STATUS(addSupportedCodec(pSampleStreamingSession->pPeerConnection, pSampleConfiguration->audioCodec)); @@ -521,17 +521,18 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE CHK(ppSampleConfiguration != NULL, STATUS_NULL_ARG); CHK(NULL != (pSampleConfiguration = (PSampleConfiguration) MEMCALLOC(1, SIZEOF(SampleConfiguration))), STATUS_NOT_ENOUGH_MEMORY); -#ifdef IOT_CORE_ENABLE_CREDENTIALS - CHK_ERR((pIotCoreCredentialEndPoint = GETENV(IOT_CORE_CREDENTIAL_ENDPOINT)) != NULL, STATUS_INVALID_OPERATION, - "AWS_IOT_CORE_CREDENTIAL_ENDPOINT must be set"); - CHK_ERR((pIotCoreCert = GETENV(IOT_CORE_CERT)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_CERT must be set"); - CHK_ERR((pIotCorePrivateKey = GETENV(IOT_CORE_PRIVATE_KEY)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_PRIVATE_KEY must be set"); - CHK_ERR((pIotCoreRoleAlias = GETENV(IOT_CORE_ROLE_ALIAS)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_ROLE_ALIAS must be set"); - CHK_ERR((pIotCoreThingName = GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set"); -#else - CHK_ERR((pAccessKey = GETENV(ACCESS_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_ACCESS_KEY_ID must be set"); - CHK_ERR((pSecretKey = GETENV(SECRET_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_SECRET_ACCESS_KEY must be set"); -#endif + if(IOT_CORE_ENABLE_CREDENTIALS) { + CHK_ERR((pIotCoreCredentialEndPoint = GETENV(IOT_CORE_CREDENTIAL_ENDPOINT)) != NULL, STATUS_INVALID_OPERATION, + "AWS_IOT_CORE_CREDENTIAL_ENDPOINT must be set"); + CHK_ERR((pIotCoreCert = GETENV(IOT_CORE_CERT)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_CERT must be set"); + CHK_ERR((pIotCorePrivateKey = GETENV(IOT_CORE_PRIVATE_KEY)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_PRIVATE_KEY must be set"); + CHK_ERR((pIotCoreRoleAlias = GETENV(IOT_CORE_ROLE_ALIAS)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_ROLE_ALIAS must be set"); + CHK_ERR((pIotCoreThingName = GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set"); + } else { + CHK_ERR((pAccessKey = GETENV(ACCESS_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_ACCESS_KEY_ID must be set"); + CHK_ERR((pSecretKey = GETENV(SECRET_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_SECRET_ACCESS_KEY must be set"); + } + pSessionToken = GETENV(SESSION_TOKEN_ENV_VAR); if (pSessionToken != NULL && IS_EMPTY_STRING(pSessionToken)) { DLOGW("Session token is set but its value is empty. Ignoring."); @@ -565,13 +566,13 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE CHK_STATUS(lookForSslCert(&pSampleConfiguration)); -#ifdef IOT_CORE_ENABLE_CREDENTIALS - CHK_STATUS(createLwsIotCredentialProvider(pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pSampleConfiguration->pCaCertPath, - pIotCoreRoleAlias, pIotCoreThingName, &pSampleConfiguration->pCredentialProvider)); -#else - CHK_STATUS( - createStaticCredentialProvider(pAccessKey, 0, pSecretKey, 0, pSessionToken, 0, MAX_UINT64, &pSampleConfiguration->pCredentialProvider)); -#endif + if(IOT_CORE_ENABLE_CREDENTIALS) { + CHK_STATUS(createLwsIotCredentialProvider(pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pSampleConfiguration->pCaCertPath, + pIotCoreRoleAlias, pIotCoreThingName, &pSampleConfiguration->pCredentialProvider)); + } else { + CHK_STATUS( + createStaticCredentialProvider(pAccessKey, 0, pSecretKey, 0, pSessionToken, 0, MAX_UINT64, &pSampleConfiguration->pCredentialProvider)); + } pSampleConfiguration->mediaSenderTid = INVALID_TID_VALUE; pSampleConfiguration->audioSenderTid = INVALID_TID_VALUE; @@ -593,11 +594,12 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE pSampleConfiguration->channelInfo.version = CHANNEL_INFO_CURRENT_VERSION; pSampleConfiguration->channelInfo.pChannelName = channelName; -#ifdef IOT_CORE_ENABLE_CREDENTIALS - if ((pIotCoreCertificateId = GETENV(IOT_CORE_CERTIFICATE_ID)) != NULL) { - pSampleConfiguration->channelInfo.pChannelName = pIotCoreCertificateId; + + if(IOT_CORE_ENABLE_CREDENTIALS) { + if ((pIotCoreCertificateId = GETENV(IOT_CORE_CERTIFICATE_ID)) != NULL) { + pSampleConfiguration->channelInfo.pChannelName = pIotCoreCertificateId; + } } -#endif pSampleConfiguration->channelInfo.pKmsKeyId = NULL; pSampleConfiguration->channelInfo.tagCount = 0; @@ -679,9 +681,9 @@ STATUS initSignaling(PSampleConfiguration pSampleConfiguration, PCHAR clientId) // Enable the processing of the messages CHK_STATUS(signalingClientFetchSync(pSampleConfiguration->signalingClientHandle)); - if (ENABLE_DATA_CHANNEL) { +#ifdef ENABLE_DATA_CHANNEL pSampleConfiguration->onDataChannel = onDataChannel; - } +#endif CHK_STATUS(signalingClientConnectSync(pSampleConfiguration->signalingClientHandle)); @@ -875,13 +877,12 @@ STATUS freeSampleConfiguration(PSampleConfiguration* ppSampleConfiguration) CVAR_FREE(pSampleConfiguration->cvar); } -#ifdef IOT_CORE_ENABLE_CREDENTIALS - freeIotCredentialProvider(&pSampleConfiguration->pCredentialProvider); -} -else -{ - freeStaticCredentialProvider(&pSampleConfiguration->pCredentialProvider); -#endif + if(IOT_CORE_ENABLE_CREDENTIALS) { + freeIotCredentialProvider(&pSampleConfiguration->pCredentialProvider); + } else + { + freeStaticCredentialProvider(&pSampleConfiguration->pCredentialProvider); + } if (pSampleConfiguration->pregeneratedCertificates != NULL) { stackQueueGetIterator(pSampleConfiguration->pregeneratedCertificates, &iterator); From e2e9e973285bab25ed96ce4da5e8cacb18d83dcb Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 21 May 2024 13:41:26 -0700 Subject: [PATCH 13/64] run time --- cloudwatch-integ/config_periodic.h | 2 +- cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cloudwatch-integ/config_periodic.h b/cloudwatch-integ/config_periodic.h index 44c1ee62a6..c48b84adb4 100644 --- a/cloudwatch-integ/config_periodic.h +++ b/cloudwatch-integ/config_periodic.h @@ -11,7 +11,7 @@ #define ENABLE_STORAGE FALSE #define ENABLE_METRICS TRUE #define SAMPLE_PRE_GENERATE_CERT TRUE -#define SAMPLE_RUN_TIME (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define RUN_TIME (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" #define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" #define USE_STORAGE FALSE diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index c52669a3b7..245d73b2c0 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -278,7 +278,7 @@ INT32 main(INT32 argc, CHAR* argv[]) pushProfilingThread.join(); // Checking for termination - CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, SAMPLE_RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, + CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, (UINT64) pSampleConfiguration, &terminateId)); CHK_STATUS(sessionCleanupWait(pSampleConfiguration)); From 57801123c8986be8f7b12649cb3950d971cab9c6 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 21 May 2024 14:40:01 -0700 Subject: [PATCH 14/64] terminate in viewer --- cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index 5618d5424b..7969f782ab 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -107,6 +107,7 @@ INT32 main(INT32 argc, CHAR* argv[]) CHAR channelName[MAX_CHANNEL_NAME_LEN]; PCHAR channelNamePrefix; UINT32 e2eTimerId = MAX_UINT32; + UINT32 terminateId = MAX_UINT32; Aws::SDKOptions options; Aws::InitAPI(options); { @@ -218,7 +219,8 @@ INT32 main(INT32 argc, CHAR* argv[]) CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, END_TO_END_METRICS_INVOCATION_PERIOD, END_TO_END_METRICS_INVOCATION_PERIOD, endToendStatsCallback, (UINT64) pSampleStreamingSession, &e2eTimerId)); - + CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, + (UINT64) pSampleConfiguration, &terminateId)); // Block until interrupted while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted) && !ATOMIC_LOAD_BOOL(&pSampleStreamingSession->terminateFlag)) { THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_SECOND); From 8211ae661039777d8da049ab151a0daa23aaf2a4 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 21 May 2024 15:43:52 -0700 Subject: [PATCH 15/64] aws cpp target arch --- CMake/Dependencies/libawscpp-CMakeLists.txt | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/CMake/Dependencies/libawscpp-CMakeLists.txt b/CMake/Dependencies/libawscpp-CMakeLists.txt index 8bfdec6ce2..92f4976837 100644 --- a/CMake/Dependencies/libawscpp-CMakeLists.txt +++ b/CMake/Dependencies/libawscpp-CMakeLists.txt @@ -2,6 +2,17 @@ cmake_minimum_required(VERSION 3.6.3) project(libawscpp-download NONE) include(ExternalProject) +if(CMAKE_SYSTEM_NAME STREQUAL "Linux") + message(STATUS "Configuring for Linux") + set(TARGET_ARCH LINUX) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Darwin") + message(STATUS "Configuring for macOS") + set(TARGET_ARCH APPLE) +elseif(CMAKE_SYSTEM_NAME STREQUAL "Windows") + message(STATUS "Configuring for Windows") + set(TARGET_ARCH WINDOWS) +endif() + ExternalProject_Add(libawscpp-download GIT_REPOSITORY https://github.com/aws/aws-sdk-cpp.git GIT_TAG 1.11.143 @@ -10,7 +21,7 @@ ExternalProject_Add(libawscpp-download -DENABLE_TESTING=OFF -DBUILD_ONLY=${BUILD_ONLY} -DCMAKE_INSTALL_PREFIX=${OPEN_SRC_INSTALL_PREFIX} - -DTARGET_ARCH=APPLE + -DTARGET_ARCH=${TARGET_ARCH} -DCUSTOM_MEMORY_MANAGEMENT=OFF BUILD_ALWAYS TRUE TEST_COMMAND "" From 487210de265af51dd781497708bf9850320cbe72 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 21 May 2024 16:35:33 -0700 Subject: [PATCH 16/64] TTFF --- cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 245d73b2c0..7c2030f094 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -84,6 +84,7 @@ PVOID sendVideoPackets(PVOID args) UINT32 minFrameSize = FRAME_METADATA_SIZE + ((DEFAULT_BITRATE / 8) / DEFAULT_FRAMERATE); UINT32 maxFrameSize = (FRAME_METADATA_SIZE + ((DEFAULT_BITRATE / 8) / DEFAULT_FRAMERATE)) * 2; PBYTE frameData = NULL; + UINT64 firstFrameTime = 0; PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) args; frameData = (PBYTE) MEMALLOC(maxFrameSize); @@ -127,7 +128,8 @@ PVOID sendVideoPackets(PVOID args) pSampleConfiguration->sampleStreamingSessionList[i]->pStatsCtx->outgoingRTPStatsCtx.videoFramesGenerated++; pSampleConfiguration->sampleStreamingSessionList[i]->pStatsCtx->outgoingRTPStatsCtx.videoBytesGenerated += frame.size; if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { - PROFILE_WITH_START_TIME(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, "Time to first frame"); + PROFILE_WITH_START_TIME_OBJ(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, firstFrameTime, "Time to first frame"); + CppInteg::Cloudwatch::getInstance().monitoring.pushTimeToFirstFrame(firstFrameTime, Aws::CloudWatch::Model::StandardUnit::Milliseconds); pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame = FALSE; } if (status != STATUS_SRTP_NOT_READY_YET) { From 4f7ff5d9bacb5a64771f2d73422acb2542f1e782 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Wed, 22 May 2024 10:36:45 -0700 Subject: [PATCH 17/64] logging... --- cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 7c2030f094..f80e07daea 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -227,14 +227,15 @@ INT32 main(INT32 argc, CHAR* argv[]) Aws::InitAPI(options); { SET_INSTRUMENTED_ALLOCATORS(); + printf("Initializing...."); + UINT32 logLevel = setLogLevel(); // Initialize KVS WebRTC. This must be done before anything else, and must only be done once. initKvsWebRtc(); - - UINT32 logLevel = setLogLevel(); - + DLOGI("Here1"); channelNamePrefix = argc > 1 ? argv[1] : CHANNEL_NAME_PREFIX; + DLOGI("Here2"); SNPRINTF(channelName, SIZEOF(channelName), CHANNEL_NAME_TEMPLATE, channelNamePrefix, RUNNER_LABEL); - + DLOGI("Here3"); CHK_STATUS(createSampleConfiguration(channelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, USE_TRICKLE_ICE, USE_TURN, logLevel, &pSampleConfiguration)); // Set the audio and video handlers From 5af0d8f78d4ad5ecf07e4d13956499823a9c7c69 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Wed, 22 May 2024 10:57:28 -0700 Subject: [PATCH 18/64] more logging --- cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index f80e07daea..6c8e1b0272 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -215,10 +215,10 @@ VOID sampleVideoFrameHandlerCW(UINT64 customData, PFrame pFrame) INT32 main(INT32 argc, CHAR* argv[]) { + printf("Starting...."); STATUS retStatus = STATUS_SUCCESS; UINT32 frameSize; PSampleConfiguration pSampleConfiguration = NULL; - SignalingClientMetrics signalingClientMetrics; PCHAR region; UINT32 terminateId = MAX_UINT32; CHAR channelName[MAX_CHANNEL_NAME_LEN]; @@ -300,13 +300,7 @@ INT32 main(INT32 argc, CHAR* argv[]) if (pSampleConfiguration->mediaSenderTid != INVALID_TID_VALUE) { THREAD_JOIN(pSampleConfiguration->mediaSenderTid, NULL); } - - retStatus = signalingClientGetMetrics(pSampleConfiguration->signalingClientHandle, &signalingClientMetrics); - if (retStatus == STATUS_SUCCESS) { - logSignalingClientStats(&signalingClientMetrics); - } else { - DLOGE("[KVS Master] signalingClientGetMetrics() operation returned status code: 0x%08x", retStatus); - } + retStatus = freeSignalingClient(&pSampleConfiguration->signalingClientHandle); if (retStatus != STATUS_SUCCESS) { DLOGE("[KVS Master] freeSignalingClient(): operation returned status code: 0x%08x", retStatus); From e45405bd963ddac7c101e624a0e71ec8c5f9275c Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 23 May 2024 16:52:20 -0700 Subject: [PATCH 19/64] use shared libs instead --- CMake/Dependencies/libawscpp-CMakeLists.txt | 3 ++- CMakeLists.txt | 18 ++++++++++-------- .../kvsWebRTCClientMasterCloudwatch.cpp | 14 ++++---------- 3 files changed, 16 insertions(+), 19 deletions(-) diff --git a/CMake/Dependencies/libawscpp-CMakeLists.txt b/CMake/Dependencies/libawscpp-CMakeLists.txt index 92f4976837..76c260a31a 100644 --- a/CMake/Dependencies/libawscpp-CMakeLists.txt +++ b/CMake/Dependencies/libawscpp-CMakeLists.txt @@ -17,10 +17,11 @@ ExternalProject_Add(libawscpp-download GIT_REPOSITORY https://github.com/aws/aws-sdk-cpp.git GIT_TAG 1.11.143 LIST_SEPARATOR "|" - CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF + CMAKE_ARGS -DBUILD_SHARED_LIBS=ON -DENABLE_TESTING=OFF -DBUILD_ONLY=${BUILD_ONLY} -DCMAKE_INSTALL_PREFIX=${OPEN_SRC_INSTALL_PREFIX} + -DCMAKE_PREFIX_PATH=${OPEN_SRC_INSTALL_PREFIX} -DTARGET_ARCH=${TARGET_ARCH} -DCUSTOM_MEMORY_MANAGEMENT=OFF BUILD_ALWAYS TRUE diff --git a/CMakeLists.txt b/CMakeLists.txt index e2b4da1af4..d77c5f3541 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -252,17 +252,19 @@ if(BUILD_DEPENDENCIES) build_dependency(gperftools) endif() - if(AWS_SDK_INTEG) - message(STATUS "Building...") - set(BUILD_ARGS - -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} - -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} - -DBUILD_ONLY=monitoring|logs) - build_dependency(awscpp ${BUILD_ARGS}) - endif() message(STATUS "Finished building dependencies.") endif() + +if(AWS_SDK_INTEG) + message(STATUS "Building...") + set(BUILD_ARGS + -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} + -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} + -DBUILD_ONLY=monitoring|logs) + build_dependency(awscpp ${BUILD_ARGS}) +endif() + # building kvsCommonLws also builds kvspic set(BUILD_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 6c8e1b0272..aab1319e38 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -224,6 +224,7 @@ INT32 main(INT32 argc, CHAR* argv[]) CHAR channelName[MAX_CHANNEL_NAME_LEN]; PCHAR channelNamePrefix; Aws::SDKOptions options; + options.httpOptions.installSigPipeHandler = true; Aws::InitAPI(options); { SET_INSTRUMENTED_ALLOCATORS(); @@ -260,14 +261,6 @@ INT32 main(INT32 argc, CHAR* argv[]) pSampleConfiguration->mediaType = SAMPLE_STREAMING_AUDIO_VIDEO; DLOGI("[KVS CW Master] Finished setting handlers"); - // Check if the samples are present - - readFrameFromDisk(NULL, &frameSize, (PCHAR) "./h264SampleFrames/frame-0001.h264"); - DLOGI("[KVS Master] Checked sample video frame availability....available"); - - readFrameFromDisk(NULL, &frameSize, (PCHAR) "./opusSampleFrames/sample-001.opus"); - DLOGI("[KVS Master] Checked sample audio frame availability....available"); - DLOGI("[KVS Master] KVS WebRTC initialization completed successfully"); PROFILE_CALL_WITH_START_END_T_OBJ( @@ -291,7 +284,8 @@ INT32 main(INT32 argc, CHAR* argv[]) } } - CleanUp: +CleanUp: + Aws::ShutdownAPI(options); DLOGI("[KVS Master] Cleaning up...."); if (pSampleConfiguration != NULL) { // Kick of the termination sequence @@ -300,7 +294,7 @@ INT32 main(INT32 argc, CHAR* argv[]) if (pSampleConfiguration->mediaSenderTid != INVALID_TID_VALUE) { THREAD_JOIN(pSampleConfiguration->mediaSenderTid, NULL); } - + retStatus = freeSignalingClient(&pSampleConfiguration->signalingClientHandle); if (retStatus != STATUS_SUCCESS) { DLOGE("[KVS Master] freeSignalingClient(): operation returned status code: 0x%08x", retStatus); From d3b1c698eb57c447727058b15c683a4daf2ef528 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 24 May 2024 16:33:09 -0700 Subject: [PATCH 20/64] Clean up cred provider --- cloudwatch-integ/CMakeLists.txt | 8 +-- cloudwatch-integ/Include.h | 2 + .../configs/lr_iot_h264_mbedtls.h | 31 +++++++++++ .../configs/lr_iot_h264_openssl.h | 20 +++++++ .../configs/lr_static_h265_openssl.h | 20 +++++++ cloudwatch-integ/configs/p_iot_h265_mbedtls.h | 22 ++++++++ .../p_iot_h265_openssl.h} | 6 +-- .../configs/p_static_h264_mbedtls.h | 20 +++++++ .../kvsWebRTCClientMasterCloudwatch.cpp | 7 +-- .../kvsWebRTCClientViewerCloudwatch.cpp | 1 + samples/Samples.h | 31 +++++------ samples/kvsWebRTCClientMaster.c | 4 +- samples/kvsWebRTCClientMasterGstSample.c | 2 +- samples/kvsWebRTCClientViewer.c | 1 + samples/kvsWebRTCClientViewerGstSample.c | 1 + samples/lib/Common.c | 52 ++++--------------- samples/lib/MetricsHandling.c | 4 +- samples/lib/Utility.c | 43 ++++++++++++++- 18 files changed, 198 insertions(+), 77 deletions(-) create mode 100644 cloudwatch-integ/configs/lr_iot_h264_mbedtls.h create mode 100644 cloudwatch-integ/configs/lr_iot_h264_openssl.h create mode 100644 cloudwatch-integ/configs/lr_static_h265_openssl.h create mode 100644 cloudwatch-integ/configs/p_iot_h265_mbedtls.h rename cloudwatch-integ/{config_periodic.h => configs/p_iot_h265_openssl.h} (85%) create mode 100644 cloudwatch-integ/configs/p_static_h264_mbedtls.h diff --git a/cloudwatch-integ/CMakeLists.txt b/cloudwatch-integ/CMakeLists.txt index 7ed93ff8f6..a07a742b36 100644 --- a/cloudwatch-integ/CMakeLists.txt +++ b/cloudwatch-integ/CMakeLists.txt @@ -12,22 +12,22 @@ link_directories(${OPEN_SRC_INSTALL_PREFIX}/lib) find_package(ZLIB REQUIRED) find_package(AWSSDK REQUIRED COMPONENTS monitoring logs) -set(SAMPLE_CONFIG_HEADER "config_periodic.h" CACHE FILEPATH "Config header") +set(SAMPLE_CONFIG_HEADER "configs/lr_iot_h264_openssl.h" CACHE FILEPATH "Config header") add_definitions(-DSAMPLE_CONFIG_HEADER="${SAMPLE_CONFIG_HEADER}") message(STATUS ${SAMPLE_CONFIG_HEADER}) add_executable( kvsWebrtcClientMasterCW + Cloudwatch.cpp + CloudwatchLogs.cpp + CloudwatchMonitoring.cpp ../samples/lib/Common.c ../samples/lib/Utility.c ../samples/lib/MetricsHandling.c ../samples/lib/DataChannelHandling.c ../samples/lib/SignalingMsgHandler.c ../samples/lib/Media.c - Cloudwatch.cpp - CloudwatchLogs.cpp - CloudwatchMonitoring.cpp kvsWebRTCClientMasterCloudwatch.cpp) target_link_libraries(kvsWebrtcClientMasterCW kvsWebrtcClient diff --git a/cloudwatch-integ/Include.h b/cloudwatch-integ/Include.h index 8a40b135d2..09348d20d3 100644 --- a/cloudwatch-integ/Include.h +++ b/cloudwatch-integ/Include.h @@ -33,6 +33,8 @@ #define MAX_CALL_RETRY_COUNT 10 +#define DEFAULT_BITRATE (250 * 8) +#define DEFAULT_FRAMERATE 30 #include #include diff --git a/cloudwatch-integ/configs/lr_iot_h264_mbedtls.h b/cloudwatch-integ/configs/lr_iot_h264_mbedtls.h new file mode 100644 index 0000000000..e880eed590 --- /dev/null +++ b/cloudwatch-integ/configs/lr_iot_h264_mbedtls.h @@ -0,0 +1,31 @@ +#ifndef KVS_SDK_SAMPLE_CONFIG_H +#define KVS_SDK_SAMPLE_CONFIG_H + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define USE_TRICKLE_ICE TRUE +#define FORCE_TURN_ONLY FALSE +#define RUNNER_LABEL (PCHAR) "WebrtcLongRunningMBedTLS" +#define SCENARIO_LABEL (PCHAR) "WebrtcLongRunning" +#define USE_TURN TRUE +#define ENABLE_TTFF_VIA_DC FALSE +#define USE_IOT TRUE +#define ENABLE_STORAGE FALSE +#define ENABLE_METRICS TRUE +#define SAMPLE_PRE_GENERATE_CERT TRUE +#define RUN_TIME (12 * HUNDREDS_OF_NANOS_IN_AN_HOUR) +#define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" +#define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" +#define USE_STORAGE FALSE +#define AUDIO_CODEC RTC_CODEC_OPUS +#define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE + +#ifdef __cplusplus +} +#endif + +#endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/lr_iot_h264_openssl.h b/cloudwatch-integ/configs/lr_iot_h264_openssl.h new file mode 100644 index 0000000000..8ef8019207 --- /dev/null +++ b/cloudwatch-integ/configs/lr_iot_h264_openssl.h @@ -0,0 +1,20 @@ +#ifndef KVS_SDK_SAMPLE_CONFIG_H +#define KVS_SDK_SAMPLE_CONFIG_H + +#define USE_TRICKLE_ICE TRUE +#define FORCE_TURN_ONLY FALSE +#define RUNNER_LABEL (PCHAR) "WebrtcPeriodicOpenSSL" +#define SCENARIO_LABEL (PCHAR) "OpenSSLPeriodic" +#define USE_TURN TRUE +#define ENABLE_TTFF_VIA_DC FALSE +#define USE_IOT FALSE +#define ENABLE_STORAGE FALSE +#define ENABLE_METRICS TRUE +#define SAMPLE_PRE_GENERATE_CERT TRUE +#define RUN_TIME (12 * HUNDREDS_OF_NANOS_IN_AN_HOUR) +#define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" +#define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" +#define USE_STORAGE FALSE +#define AUDIO_CODEC RTC_CODEC_OPUS +#define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/lr_static_h265_openssl.h b/cloudwatch-integ/configs/lr_static_h265_openssl.h new file mode 100644 index 0000000000..0135df6515 --- /dev/null +++ b/cloudwatch-integ/configs/lr_static_h265_openssl.h @@ -0,0 +1,20 @@ +#ifndef KVS_SDK_SAMPLE_CONFIG_H +#define KVS_SDK_SAMPLE_CONFIG_H + +#define USE_TRICKLE_ICE TRUE +#define FORCE_TURN_ONLY FALSE +#define RUNNER_LABEL (PCHAR) "WebrtcLongRunningStaticOpenSSL-H265" +#define SCENARIO_LABEL (PCHAR) "WebrtcLongRunning" +#define USE_TURN TRUE +#define ENABLE_TTFF_VIA_DC FALSE +#define USE_IOT FALSE +#define ENABLE_STORAGE FALSE +#define ENABLE_METRICS TRUE +#define SAMPLE_PRE_GENERATE_CERT TRUE +#define RUN_TIME (12 * HUNDREDS_OF_NANOS_IN_A_HOUR) +#define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" +#define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" +#define USE_STORAGE FALSE +#define AUDIO_CODEC RTC_CODEC_OPUS +#define VIDEO_CODEC RTC_CODEC_H265 +#endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/p_iot_h265_mbedtls.h b/cloudwatch-integ/configs/p_iot_h265_mbedtls.h new file mode 100644 index 0000000000..05ec049d3c --- /dev/null +++ b/cloudwatch-integ/configs/p_iot_h265_mbedtls.h @@ -0,0 +1,22 @@ +#ifndef KVS_SDK_SAMPLE_CONFIG_H +#define KVS_SDK_SAMPLE_CONFIG_H + +#define USE_TRICKLE_ICE TRUE +#define FORCE_TURN_ONLY FALSE +#define RUNNER_LABEL (PCHAR) "WebrtcPeriodicMbedTLS" +#define SCENARIO_LABEL (PCHAR) "MBedTLSPeriodic" +#define USE_TURN TRUE +#define ENABLE_TTFF_VIA_DC FALSE +#define USE_IOT TRUE +#define ENABLE_STORAGE FALSE +#define ENABLE_METRICS TRUE +#define SAMPLE_PRE_GENERATE_CERT TRUE +#define RUN_TIME (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" +#define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" +#define USE_STORAGE FALSE +#define AUDIO_CODEC RTC_CODEC_OPUS +#define VIDEO_CODEC RTC_CODEC_H265 +#define DEFAULT_BITRATE (250 * 1024) +#define DEFAULT_FRAMERATE 30 +#endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/config_periodic.h b/cloudwatch-integ/configs/p_iot_h265_openssl.h similarity index 85% rename from cloudwatch-integ/config_periodic.h rename to cloudwatch-integ/configs/p_iot_h265_openssl.h index c48b84adb4..6724d1a325 100644 --- a/cloudwatch-integ/config_periodic.h +++ b/cloudwatch-integ/configs/p_iot_h265_openssl.h @@ -3,11 +3,11 @@ #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE -#define RUNNER_LABEL (PCHAR) "WebrtcPeriodicOpenSSL" +#define RUNNER_LABEL (PCHAR) "WebrtcPeriodicOpenSSL-H265" #define SCENARIO_LABEL (PCHAR) "OpenSSLPeriodic" #define USE_TURN TRUE #define ENABLE_TTFF_VIA_DC FALSE -#define IOT_CORE_ENABLE_CREDENTIALS FALSE +#define USE_IOT TRUE #define ENABLE_STORAGE FALSE #define ENABLE_METRICS TRUE #define SAMPLE_PRE_GENERATE_CERT TRUE @@ -16,7 +16,7 @@ #define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" #define USE_STORAGE FALSE #define AUDIO_CODEC RTC_CODEC_OPUS -#define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#define VIDEO_CODEC RTC_CODEC_H265 #define DEFAULT_BITRATE (250 * 1024) #define DEFAULT_FRAMERATE 30 #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/p_static_h264_mbedtls.h b/cloudwatch-integ/configs/p_static_h264_mbedtls.h new file mode 100644 index 0000000000..67db2bb604 --- /dev/null +++ b/cloudwatch-integ/configs/p_static_h264_mbedtls.h @@ -0,0 +1,20 @@ +#ifndef KVS_SDK_SAMPLE_CONFIG_H +#define KVS_SDK_SAMPLE_CONFIG_H + +#define USE_TRICKLE_ICE TRUE +#define FORCE_TURN_ONLY FALSE +#define RUNNER_LABEL (PCHAR) "WebrtcPeriodicStaticMbedTLS" +#define SCENARIO_LABEL (PCHAR) "MbedTLSPeriodic" +#define USE_TURN TRUE +#define ENABLE_TTFF_VIA_DC FALSE +#define USE_IOT TRUE +#define ENABLE_STORAGE FALSE +#define ENABLE_METRICS TRUE +#define SAMPLE_PRE_GENERATE_CERT TRUE +#define RUN_TIME (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" +#define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" +#define USE_STORAGE FALSE +#define AUDIO_CODEC RTC_CODEC_OPUS +#define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index aab1319e38..06f5125356 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -215,7 +215,6 @@ VOID sampleVideoFrameHandlerCW(UINT64 customData, PFrame pFrame) INT32 main(INT32 argc, CHAR* argv[]) { - printf("Starting...."); STATUS retStatus = STATUS_SUCCESS; UINT32 frameSize; PSampleConfiguration pSampleConfiguration = NULL; @@ -228,17 +227,13 @@ INT32 main(INT32 argc, CHAR* argv[]) Aws::InitAPI(options); { SET_INSTRUMENTED_ALLOCATORS(); - printf("Initializing...."); UINT32 logLevel = setLogLevel(); // Initialize KVS WebRTC. This must be done before anything else, and must only be done once. initKvsWebRtc(); - DLOGI("Here1"); channelNamePrefix = argc > 1 ? argv[1] : CHANNEL_NAME_PREFIX; - DLOGI("Here2"); SNPRINTF(channelName, SIZEOF(channelName), CHANNEL_NAME_TEMPLATE, channelNamePrefix, RUNNER_LABEL); - DLOGI("Here3"); CHK_STATUS(createSampleConfiguration(channelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, USE_TRICKLE_ICE, USE_TURN, logLevel, &pSampleConfiguration)); - + CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, USE_IOT)); // Set the audio and video handlers pSampleConfiguration->audioSource = sendAudioPackets; pSampleConfiguration->videoSource = sendVideoPackets; diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index 7969f782ab..2202ff60ef 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -122,6 +122,7 @@ INT32 main(INT32 argc, CHAR* argv[]) SNPRINTF(channelName, SIZEOF(channelName), CHANNEL_NAME_TEMPLATE, channelNamePrefix, RUNNER_LABEL); CHK_STATUS(createSampleConfiguration(channelName, SIGNALING_CHANNEL_ROLE_TYPE_VIEWER, USE_TRICKLE_ICE, USE_TURN, logLevel, &pSampleConfiguration)); + CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, USE_IOT)); pSampleConfiguration->mediaType = SAMPLE_STREAMING_AUDIO_VIDEO; pSampleConfiguration->audioCodec = AUDIO_CODEC; pSampleConfiguration->videoCodec = VIDEO_CODEC; diff --git a/samples/Samples.h b/samples/Samples.h index e7d1007e59..8286941b9f 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -14,19 +14,19 @@ extern "C" { #define KVS_DEFAULT_MEDIA_SENDER_THREAD_STACK_SIZE 64 * 1024 #define KVS_MINIMUM_THREAD_STACK_SIZE 16 * 1024 -#define NUMBER_OF_H264_FRAME_FILES 1500 -#define NUMBER_OF_H265_FRAME_FILES 1500 -#define NUMBER_OF_OPUS_FRAME_FILES 618 -#define DEFAULT_FPS_VALUE 25 -#define DEFAULT_VIDEO_HEIGHT_PIXELS 720 -#define DEFAULT_VIDEO_WIDTH_PIXELS 1280 -#define DEFAULT_AUDIO_OPUS_CHANNELS 2 -#define DEFAULT_AUDIO_AAC_CHANNELS 2 -#define DEFAULT_AUDIO_OPUS_SAMPLE_RATE_HZ 48000 -#define DEFAULT_AUDIO_AAC_SAMPLE_RATE_HZ 16000 -#define DEFAULT_AUDIO_OPUS_BITS_PER_SAMPLE 16 -#define DEFAULT_AUDIO_AAC_BITS_PER_SAMPLE 16 -#define DEFAULT_MAX_CONCURRENT_STREAMING_SESSION 10 +#define NUMBER_OF_H264_FRAME_FILES 1500 +#define NUMBER_OF_H265_FRAME_FILES 1500 +#define NUMBER_OF_OPUS_FRAME_FILES 618 +#define DEFAULT_FPS_VALUE 25 +#define DEFAULT_VIDEO_HEIGHT_PIXELS 720 +#define DEFAULT_VIDEO_WIDTH_PIXELS 1280 +#define DEFAULT_AUDIO_OPUS_CHANNELS 2 +#define DEFAULT_AUDIO_AAC_CHANNELS 2 +#define DEFAULT_AUDIO_OPUS_SAMPLE_RATE_HZ 48000 +#define DEFAULT_AUDIO_AAC_SAMPLE_RATE_HZ 16000 +#define DEFAULT_AUDIO_OPUS_BITS_PER_SAMPLE 16 +#define DEFAULT_AUDIO_AAC_BITS_PER_SAMPLE 16 +#define DEFAULT_MAX_CONCURRENT_STREAMING_SESSION 10 #define AUDIO_CODEC_NAME_ALAW "alaw" #define AUDIO_CODEC_NAME_MULAW "mulaw" @@ -71,8 +71,7 @@ extern "C" { #define IOT_CORE_THING_NAME ((PCHAR) "AWS_IOT_CORE_THING_NAME") #define IOT_CORE_CERTIFICATE_ID ((PCHAR) "AWS_IOT_CORE_CERTIFICATE_ID") -/* Set to TRUE to enable credentials */ -#define IOT_CORE_ENABLE_CREDENTIALS FALSE +#define IOT_CORE_ENABLE_CREDENTIALS FALSE #define MASTER_DATA_CHANNEL_MESSAGE "This message is from the KVS Master" #define VIEWER_DATA_CHANNEL_MESSAGE "This message is from the KVS Viewer" @@ -184,6 +183,7 @@ typedef struct { BOOL enableTwcc; BOOL forceTurn; BOOL enableMetrics; + BOOL useIot; SignalingClientMetrics signalingClientMetrics; } SampleConfiguration, *PSampleConfiguration; @@ -356,6 +356,7 @@ PVOID mediaSenderRoutine(PVOID); STATUS setupMetricsCtx(PSampleStreamingSession); STATUS getSdkTimeProfile(PSampleStreamingSession); STATUS terminate(UINT32 timerId, UINT64 currentTime, UINT64 customData); +STATUS setUpCredentialProvider(PSampleConfiguration pSampleConfiguration, BOOL useIot); #ifdef __cplusplus } #endif diff --git a/samples/kvsWebRTCClientMaster.c b/samples/kvsWebRTCClientMaster.c index 7d817470f4..9418c55825 100644 --- a/samples/kvsWebRTCClientMaster.c +++ b/samples/kvsWebRTCClientMaster.c @@ -20,7 +20,7 @@ INT32 main(INT32 argc, CHAR* argv[]) signal(SIGINT, sigintHandler); #endif - if(IOT_CORE_ENABLE_CREDENTIALS) { + if (IOT_CORE_ENABLE_CREDENTIALS) { CHK_ERR((pChannelName = argc > 1 ? argv[1] : GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set"); } else { @@ -28,7 +28,7 @@ INT32 main(INT32 argc, CHAR* argv[]) } CHK_STATUS(createSampleConfiguration(pChannelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration)); - + CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, IOT_CORE_ENABLE_CREDENTIALS)); if (argc > 3) { if (!STRCMP(argv[3], AUDIO_CODEC_NAME_AAC)) { audioCodec = RTC_CODEC_AAC; diff --git a/samples/kvsWebRTCClientMasterGstSample.c b/samples/kvsWebRTCClientMasterGstSample.c index 6b60070d9f..3e3c837793 100644 --- a/samples/kvsWebRTCClientMasterGstSample.c +++ b/samples/kvsWebRTCClientMasterGstSample.c @@ -396,7 +396,7 @@ INT32 main(INT32 argc, CHAR* argv[]) #endif CHK_STATUS(createSampleConfiguration(pChannelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration)); - + CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, IOT_CORE_ENABLE_CREDENTIALS)); if (argc > 3 && STRCMP(argv[3], "testsrc") == 0) { if (argc > 4) { if (!STRCMP(argv[4], AUDIO_CODEC_NAME_AAC)) { diff --git a/samples/kvsWebRTCClientViewer.c b/samples/kvsWebRTCClientViewer.c index bc60e12cad..e3a8b1da45 100644 --- a/samples/kvsWebRTCClientViewer.c +++ b/samples/kvsWebRTCClientViewer.c @@ -82,6 +82,7 @@ INT32 main(INT32 argc, CHAR* argv[]) } CHK_STATUS(createSampleConfiguration(pChannelName, SIGNALING_CHANNEL_ROLE_TYPE_VIEWER, TRUE, TRUE, logLevel, &pSampleConfiguration)); + CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, IOT_CORE_ENABLE_CREDENTIALS)); pSampleConfiguration->mediaType = SAMPLE_STREAMING_AUDIO_VIDEO; pSampleConfiguration->audioCodec = audioCodec; pSampleConfiguration->videoCodec = videoCodec; diff --git a/samples/kvsWebRTCClientViewerGstSample.c b/samples/kvsWebRTCClientViewerGstSample.c index 18ac6625a4..e9060dffa2 100644 --- a/samples/kvsWebRTCClientViewerGstSample.c +++ b/samples/kvsWebRTCClientViewerGstSample.c @@ -76,6 +76,7 @@ INT32 main(INT32 argc, CHAR* argv[]) } CHK_STATUS(createSampleConfiguration(pChannelName, SIGNALING_CHANNEL_ROLE_TYPE_VIEWER, TRUE, TRUE, logLevel, &pSampleConfiguration)); + CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, IOT_CORE_ENABLE_CREDENTIALS)); pSampleConfiguration->mediaType = SAMPLE_STREAMING_AUDIO_VIDEO; pSampleConfiguration->receiveAudioVideoSource = receiveGstreamerAudioVideo; pSampleConfiguration->audioCodec = audioCodec; diff --git a/samples/lib/Common.c b/samples/lib/Common.c index a8d81d8544..bbd3edb50d 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -287,10 +287,10 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P pSampleStreamingSession->twccMetadata.updateLock = MUTEX_CREATE(TRUE); } - if(pSampleConfiguration->enableMetrics) { + if (pSampleConfiguration->enableMetrics) { CHK_STATUS(setupMetricsCtx(pSampleStreamingSession)); pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime = - GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; } // Flag to enable SDK to calculate selected ice server, local, remote and candidate pair stats. @@ -302,10 +302,10 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P peerConnectionOnConnectionStateChange(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, onConnectionStateChange)); #ifdef ENABLE_DATA_CHANNEL - if (pSampleConfiguration->onDataChannel != NULL) { - CHK_STATUS(peerConnectionOnDataChannel(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, - pSampleConfiguration->onDataChannel)); - } + if (pSampleConfiguration->onDataChannel != NULL) { + CHK_STATUS(peerConnectionOnDataChannel(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, + pSampleConfiguration->onDataChannel)); + } #endif CHK_STATUS(addSupportedCodec(pSampleStreamingSession->pPeerConnection, pSampleConfiguration->videoCodec)); @@ -521,23 +521,7 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE CHK(ppSampleConfiguration != NULL, STATUS_NULL_ARG); CHK(NULL != (pSampleConfiguration = (PSampleConfiguration) MEMCALLOC(1, SIZEOF(SampleConfiguration))), STATUS_NOT_ENOUGH_MEMORY); - if(IOT_CORE_ENABLE_CREDENTIALS) { - CHK_ERR((pIotCoreCredentialEndPoint = GETENV(IOT_CORE_CREDENTIAL_ENDPOINT)) != NULL, STATUS_INVALID_OPERATION, - "AWS_IOT_CORE_CREDENTIAL_ENDPOINT must be set"); - CHK_ERR((pIotCoreCert = GETENV(IOT_CORE_CERT)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_CERT must be set"); - CHK_ERR((pIotCorePrivateKey = GETENV(IOT_CORE_PRIVATE_KEY)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_PRIVATE_KEY must be set"); - CHK_ERR((pIotCoreRoleAlias = GETENV(IOT_CORE_ROLE_ALIAS)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_ROLE_ALIAS must be set"); - CHK_ERR((pIotCoreThingName = GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set"); - } else { - CHK_ERR((pAccessKey = GETENV(ACCESS_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_ACCESS_KEY_ID must be set"); - CHK_ERR((pSecretKey = GETENV(SECRET_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_SECRET_ACCESS_KEY must be set"); - } - pSessionToken = GETENV(SESSION_TOKEN_ENV_VAR); - if (pSessionToken != NULL && IS_EMPTY_STRING(pSessionToken)) { - DLOGW("Session token is set but its value is empty. Ignoring."); - pSessionToken = NULL; - } // If the env is set, we generate normal log files apart from filtered profile log files // If not set, we generate only the filtered profile log files if (NULL != GETENV(ENABLE_FILE_LOGGING)) { @@ -564,16 +548,6 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE pSampleConfiguration->channelInfo.pRegion = DEFAULT_AWS_REGION; } - CHK_STATUS(lookForSslCert(&pSampleConfiguration)); - - if(IOT_CORE_ENABLE_CREDENTIALS) { - CHK_STATUS(createLwsIotCredentialProvider(pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pSampleConfiguration->pCaCertPath, - pIotCoreRoleAlias, pIotCoreThingName, &pSampleConfiguration->pCredentialProvider)); - } else { - CHK_STATUS( - createStaticCredentialProvider(pAccessKey, 0, pSecretKey, 0, pSessionToken, 0, MAX_UINT64, &pSampleConfiguration->pCredentialProvider)); - } - pSampleConfiguration->mediaSenderTid = INVALID_TID_VALUE; pSampleConfiguration->audioSenderTid = INVALID_TID_VALUE; pSampleConfiguration->videoSenderTid = INVALID_TID_VALUE; @@ -595,12 +569,6 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE pSampleConfiguration->channelInfo.version = CHANNEL_INFO_CURRENT_VERSION; pSampleConfiguration->channelInfo.pChannelName = channelName; - if(IOT_CORE_ENABLE_CREDENTIALS) { - if ((pIotCoreCertificateId = GETENV(IOT_CORE_CERTIFICATE_ID)) != NULL) { - pSampleConfiguration->channelInfo.pChannelName = pIotCoreCertificateId; - } - } - pSampleConfiguration->channelInfo.pKmsKeyId = NULL; pSampleConfiguration->channelInfo.tagCount = 0; pSampleConfiguration->channelInfo.pTags = NULL; @@ -611,7 +579,6 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE pSampleConfiguration->channelInfo.asyncIceServerConfig = TRUE; // has no effect pSampleConfiguration->channelInfo.retry = TRUE; pSampleConfiguration->channelInfo.reconnect = TRUE; - pSampleConfiguration->channelInfo.pCertPath = pSampleConfiguration->pCaCertPath; pSampleConfiguration->channelInfo.messageTtl = 0; // Default is 60 seconds pSampleConfiguration->signalingClientCallbacks.version = SIGNALING_CLIENT_CALLBACKS_CURRENT_VERSION; @@ -682,7 +649,7 @@ STATUS initSignaling(PSampleConfiguration pSampleConfiguration, PCHAR clientId) CHK_STATUS(signalingClientFetchSync(pSampleConfiguration->signalingClientHandle)); #ifdef ENABLE_DATA_CHANNEL - pSampleConfiguration->onDataChannel = onDataChannel; + pSampleConfiguration->onDataChannel = onDataChannel; #endif CHK_STATUS(signalingClientConnectSync(pSampleConfiguration->signalingClientHandle)); @@ -877,10 +844,9 @@ STATUS freeSampleConfiguration(PSampleConfiguration* ppSampleConfiguration) CVAR_FREE(pSampleConfiguration->cvar); } - if(IOT_CORE_ENABLE_CREDENTIALS) { + if (IOT_CORE_ENABLE_CREDENTIALS) { freeIotCredentialProvider(&pSampleConfiguration->pCredentialProvider); - } else - { + } else { freeStaticCredentialProvider(&pSampleConfiguration->pCredentialProvider); } diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index e1ad14aad0..7a878a9447 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -3,10 +3,10 @@ STATUS setupMetricsCtx(PSampleStreamingSession pSampleStreamingSession) { STATUS retStatus = STATUS_SUCCESS; - if(pSampleStreamingSession == NULL) { + if (pSampleStreamingSession == NULL) { DLOGI("NUll"); } - if(pSampleStreamingSession->pSampleConfiguration == NULL) { + if (pSampleStreamingSession->pSampleConfiguration == NULL) { DLOGI("bykkbedk"); } CHK(pSampleStreamingSession != NULL && pSampleStreamingSession->pSampleConfiguration != NULL, STATUS_NULL_ARG); diff --git a/samples/lib/Utility.c b/samples/lib/Utility.c index d798935135..94781bddcf 100644 --- a/samples/lib/Utility.c +++ b/samples/lib/Utility.c @@ -190,4 +190,45 @@ STATUS lookForSslCert(PSampleConfiguration* ppSampleConfiguration) CHK_LOG_ERR(retStatus); return retStatus; -} \ No newline at end of file +} + +STATUS setUpCredentialProvider(PSampleConfiguration pSampleConfiguration, BOOL useIot) +{ + STATUS retStatus = STATUS_SUCCESS; + PCHAR pAccessKey, pSecretKey, pSessionToken; + PCHAR pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pIotCoreRoleAlias, pIotCoreCertificateId, pIotCoreThingName; + CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "Set up pSampleConfiguration first by invoking createSampleConfiguration"); + + pSampleConfiguration->useIot = useIot; + CHK_WARN(pSampleConfiguration->pCredentialProvider == NULL, STATUS_SUCCESS, "Credential provider already set, nothing to do"); + + CHK_STATUS(lookForSslCert(&pSampleConfiguration)); + pSampleConfiguration->channelInfo.pCertPath = pSampleConfiguration->pCaCertPath; + if (useIot) { + DLOGI("USE IOT"); + CHK_ERR((pIotCoreCredentialEndPoint = GETENV(IOT_CORE_CREDENTIAL_ENDPOINT)) != NULL, STATUS_INVALID_OPERATION, + "AWS_IOT_CORE_CREDENTIAL_ENDPOINT must be set"); + CHK_ERR((pIotCoreCert = GETENV(IOT_CORE_CERT)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_CERT must be set"); + CHK_ERR((pIotCorePrivateKey = GETENV(IOT_CORE_PRIVATE_KEY)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_PRIVATE_KEY must be set"); + CHK_ERR((pIotCoreRoleAlias = GETENV(IOT_CORE_ROLE_ALIAS)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_ROLE_ALIAS must be set"); + CHK_ERR((pIotCoreThingName = GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set"); + CHK_STATUS(createLwsIotCredentialProvider(pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pSampleConfiguration->pCaCertPath, + pIotCoreRoleAlias, pIotCoreThingName, &pSampleConfiguration->pCredentialProvider)); + if ((pIotCoreCertificateId = GETENV(IOT_CORE_CERTIFICATE_ID)) != NULL) { + pSampleConfiguration->channelInfo.pChannelName = pIotCoreCertificateId; + } + } else { + DLOGI("USE no"); + CHK_ERR((pAccessKey = GETENV(ACCESS_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_ACCESS_KEY_ID must be set"); + CHK_ERR((pSecretKey = GETENV(SECRET_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_SECRET_ACCESS_KEY must be set"); + pSessionToken = GETENV(SESSION_TOKEN_ENV_VAR); + if (pSessionToken != NULL && IS_EMPTY_STRING(pSessionToken)) { + DLOGW("Session token is set but its value is empty. Ignoring."); + pSessionToken = NULL; + } + CHK_STATUS( + createStaticCredentialProvider(pAccessKey, 0, pSecretKey, 0, pSessionToken, 0, MAX_UINT64, &pSampleConfiguration->pCredentialProvider)); + } +CleanUp: + return retStatus; +} From 94f1149b99e0957d78b9995ddb188244f0cffe69 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Wed, 29 May 2024 15:15:25 -0700 Subject: [PATCH 21/64] Storage periodic --- cloudwatch-integ/Cloudwatch.cpp | 6 +- cloudwatch-integ/Cloudwatch.h | 2 +- cloudwatch-integ/CloudwatchLogs.cpp | 13 +- cloudwatch-integ/CloudwatchLogs.h | 2 +- cloudwatch-integ/CloudwatchMonitoring.cpp | 8 +- cloudwatch-integ/CloudwatchMonitoring.h | 2 +- cloudwatch-integ/Include.h | 5 +- cloudwatch-integ/configs/storage_extended.h | 4 + cloudwatch-integ/configs/storage_periodic.h | 20 ++ .../configs/storage_single_reconnect.h | 8 + .../configs/storage_sub_reconnect.h | 8 + .../kvsWebRTCClientMasterCloudwatch.cpp | 201 +++++++++++++++--- .../kvsWebRTCClientViewerCloudwatch.cpp | 44 +++- samples/Samples.h | 1 + samples/lib/Common.c | 1 + 15 files changed, 278 insertions(+), 47 deletions(-) create mode 100644 cloudwatch-integ/configs/storage_extended.h create mode 100644 cloudwatch-integ/configs/storage_periodic.h create mode 100644 cloudwatch-integ/configs/storage_single_reconnect.h create mode 100644 cloudwatch-integ/configs/storage_sub_reconnect.h diff --git a/cloudwatch-integ/Cloudwatch.cpp b/cloudwatch-integ/Cloudwatch.cpp index f32c0ed17f..65a4fa3c60 100644 --- a/cloudwatch-integ/Cloudwatch.cpp +++ b/cloudwatch-integ/Cloudwatch.cpp @@ -8,7 +8,7 @@ Cloudwatch::Cloudwatch(ClientConfiguration* pClientConfig) { } -STATUS Cloudwatch::init(PCHAR channelName, PCHAR region, BOOL isMaster) +STATUS Cloudwatch::init(PCHAR channelName, PCHAR region, BOOL isMaster, BOOL isStorage) { ENTERS(); STATUS retStatus = STATUS_SUCCESS; @@ -20,13 +20,13 @@ STATUS Cloudwatch::init(PCHAR channelName, PCHAR region, BOOL isMaster) clientConfig.region = region; auto& instance = getInstanceImpl(&clientConfig); - if (STATUS_FAILED(instance.logs.init(channelName, region, isMaster))) { + if (STATUS_FAILED(instance.logs.init(channelName, region, isMaster, isStorage))) { DLOGW("Failed to create Cloudwatch logger, fallback to file logger"); } else { globalCustomLogPrintFn = logger; } - CHK_STATUS(instance.monitoring.init(channelName, region, isMaster)); + CHK_STATUS(instance.monitoring.init(channelName, region, isMaster, isStorage)); CleanUp: diff --git a/cloudwatch-integ/Cloudwatch.h b/cloudwatch-integ/Cloudwatch.h index eac06ee3eb..d91e5f3a70 100644 --- a/cloudwatch-integ/Cloudwatch.h +++ b/cloudwatch-integ/Cloudwatch.h @@ -16,7 +16,7 @@ class Cloudwatch { CloudwatchMonitoring monitoring; static Cloudwatch& getInstance(); - static STATUS init(PCHAR channelName, PCHAR region, BOOL isMaster); + static STATUS init(PCHAR channelName, PCHAR region, BOOL isMaster, BOOL isStorage); static VOID deinit(); static VOID logger(UINT32, PCHAR, PCHAR, ...); diff --git a/cloudwatch-integ/CloudwatchLogs.cpp b/cloudwatch-integ/CloudwatchLogs.cpp index 56e30ef947..798cc3d678 100644 --- a/cloudwatch-integ/CloudwatchLogs.cpp +++ b/cloudwatch-integ/CloudwatchLogs.cpp @@ -7,15 +7,22 @@ CloudwatchLogs::CloudwatchLogs(ClientConfiguration* pClientConfig) : client(*pCl { } -STATUS CloudwatchLogs::init(PCHAR channelName, PCHAR region, BOOL isMaster) +STATUS CloudwatchLogs::init(PCHAR channelName, PCHAR region, BOOL isMaster, BOOL isStorage) { STATUS retStatus = STATUS_SUCCESS; CreateLogGroupRequest createLogGroupRequest; Aws::CloudWatchLogs::Model::CreateLogStreamOutcome createLogStreamOutcome; CreateLogStreamRequest createLogStreamRequest; std::stringstream defaultLogStreamName; - defaultLogStreamName << channelName << '-' << (isMaster ? "master" : "viewer") << '-' - << GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + if(isStorage) { + defaultLogStreamName << channelName << '-' << "StorageMaster" << '-' + << GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + + } else { + defaultLogStreamName << channelName << '-' << (isMaster ? "master" : "viewer") << '-' + << GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + + } this->logStreamName = defaultLogStreamName.str(); this->logGroupName = LOG_GROUP_NAME; diff --git a/cloudwatch-integ/CloudwatchLogs.h b/cloudwatch-integ/CloudwatchLogs.h index 636df08747..e63b50d418 100644 --- a/cloudwatch-integ/CloudwatchLogs.h +++ b/cloudwatch-integ/CloudwatchLogs.h @@ -5,7 +5,7 @@ namespace CppInteg { class CloudwatchLogs { public: CloudwatchLogs(ClientConfiguration*); - STATUS init(PCHAR channelName, PCHAR region, BOOL isMaster); + STATUS init(PCHAR channelName, PCHAR region, BOOL isMaster, BOOL isStorage); VOID deinit(); VOID push(string log); VOID flush(BOOL sync = FALSE); diff --git a/cloudwatch-integ/CloudwatchMonitoring.cpp b/cloudwatch-integ/CloudwatchMonitoring.cpp index feda82b7fe..c19422ee22 100644 --- a/cloudwatch-integ/CloudwatchMonitoring.cpp +++ b/cloudwatch-integ/CloudwatchMonitoring.cpp @@ -7,15 +7,15 @@ CloudwatchMonitoring::CloudwatchMonitoring(ClientConfiguration* pClientConfig) : { } -STATUS CloudwatchMonitoring::init(PCHAR channelName, PCHAR region, BOOL isMaster) +STATUS CloudwatchMonitoring::init(PCHAR channelName, PCHAR region, BOOL isMaster, BOOL isStorage) { STATUS retStatus = STATUS_SUCCESS; - this->isStorage ? this->channelDimension.SetName(INDIVIDUAL_STORAGE_CW_DIMENSION) : this->channelDimension.SetName(INDIVIDUAL_CW_DIMENSION); + isStorage ? this->channelDimension.SetName(INDIVIDUAL_STORAGE_CW_DIMENSION) : this->channelDimension.SetName(INDIVIDUAL_CW_DIMENSION); this->channelDimension.SetValue(channelName); - this->isStorage ? this->labelDimension.SetName(AGGREGATE_STORAGE_CW_DIMENSION) : this->labelDimension.SetName(AGGREGATE_CW_DIMENSION); - this->labelDimension.SetValue("label"); + isStorage ? this->labelDimension.SetName(AGGREGATE_STORAGE_CW_DIMENSION) : this->labelDimension.SetName(AGGREGATE_CW_DIMENSION); + this->labelDimension.SetValue(SCENARIO_LABEL); return retStatus; } diff --git a/cloudwatch-integ/CloudwatchMonitoring.h b/cloudwatch-integ/CloudwatchMonitoring.h index b24e99f0fe..afebd63889 100644 --- a/cloudwatch-integ/CloudwatchMonitoring.h +++ b/cloudwatch-integ/CloudwatchMonitoring.h @@ -6,7 +6,7 @@ namespace CppInteg { class CloudwatchMonitoring { public: CloudwatchMonitoring(ClientConfiguration*); - STATUS init(PCHAR channelName, PCHAR region, BOOL isMaster); + STATUS init(PCHAR channelName, PCHAR region, BOOL isMaster, BOOL isStorage); VOID deinit(); VOID push(const MetricDatum&); VOID pushExitStatus(STATUS); diff --git a/cloudwatch-integ/Include.h b/cloudwatch-integ/Include.h index 09348d20d3..7c7a3f2ee6 100644 --- a/cloudwatch-integ/Include.h +++ b/cloudwatch-integ/Include.h @@ -11,6 +11,7 @@ #define MAX_CLOUDWATCH_LOG_COUNT 128 #define MAX_STATUS_CODE_LENGTH 16 #define MAX_CONTROL_PLANE_URI_CHAR_LEN 256 +#define MAX_UINT64_DIGIT_COUNT 20 #define NUMBER_OF_H264_FRAME_FILES 1500 #define NUMBER_OF_OPUS_FRAME_FILES 618 @@ -23,8 +24,8 @@ #define STORAGE_CANARY_FIRST_FRAME_TS_FILE_ENV_VAR "STORAGE_CANARY_FIRST_FRAME_TS_FILE" -#define FIRST_FRAME_TS_FILE_PATH "../" -#define STORAGE_CANARY_DEFAULT_FIRST_FRAME_TS_FILE "DefaultFirstFrameSentTSFileName.txt" +#define FIRST_FRAME_TS_FILE_PATH (PCHAR) "/tmp/" +#define STORAGE_CANARY_DEFAULT_FIRST_FRAME_TS_FILE (PCHAR) "DefaultFirstFrameSentTSFileName.txt" #define INDIVIDUAL_STORAGE_CW_DIMENSION "StorageWebRTCSDKCanaryChannelName" #define INDIVIDUAL_CW_DIMENSION "WebRTCSDKCanaryChannelName" diff --git a/cloudwatch-integ/configs/storage_extended.h b/cloudwatch-integ/configs/storage_extended.h new file mode 100644 index 0000000000..47131ef614 --- /dev/null +++ b/cloudwatch-integ/configs/storage_extended.h @@ -0,0 +1,4 @@ +#ifndef KVS_SDK_STORAGE_EXTENDED_H +#define KVS_SDK_STORAGE_EXTENDED_H + +#endif //KVS_SDK_STORAGE_EXTENDED_H diff --git a/cloudwatch-integ/configs/storage_periodic.h b/cloudwatch-integ/configs/storage_periodic.h new file mode 100644 index 0000000000..7aa206f840 --- /dev/null +++ b/cloudwatch-integ/configs/storage_periodic.h @@ -0,0 +1,20 @@ +#ifndef KVS_SDK_SAMPLE_CONFIG_H +#define KVS_SDK_SAMPLE_CONFIG_H + +#define USE_TRICKLE_ICE TRUE +#define FORCE_TURN_ONLY FALSE +#define RUNNER_LABEL (PCHAR) "StoragePeriodic" +#define SCENARIO_LABEL (PCHAR) "StoragePeriodic" +#define USE_TURN TRUE +#define ENABLE_TTFF_VIA_DC FALSE +#define USE_IOT FALSE +#define ENABLE_STORAGE TRUE +#define ENABLE_METRICS TRUE +#define SAMPLE_PRE_GENERATE_CERT TRUE +#define RUN_TIME (300 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" +#define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" +#define USE_STORAGE TRUE +#define AUDIO_CODEC RTC_CODEC_OPUS +#define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/storage_single_reconnect.h b/cloudwatch-integ/configs/storage_single_reconnect.h new file mode 100644 index 0000000000..e1eedbb81e --- /dev/null +++ b/cloudwatch-integ/configs/storage_single_reconnect.h @@ -0,0 +1,8 @@ +// +// Created by Sampath Kumar, Divya on 5/29/24. +// + +#ifndef KVS_SDK_STORAGE_SINGLE_RECONNECT_H +#define KVS_SDK_STORAGE_SINGLE_RECONNECT_H + +#endif //KVS_SDK_STORAGE_SINGLE_RECONNECT_H diff --git a/cloudwatch-integ/configs/storage_sub_reconnect.h b/cloudwatch-integ/configs/storage_sub_reconnect.h new file mode 100644 index 0000000000..0382abda9d --- /dev/null +++ b/cloudwatch-integ/configs/storage_sub_reconnect.h @@ -0,0 +1,8 @@ +// +// Created by Sampath Kumar, Divya on 5/29/24. +// + +#ifndef KVS_SDK_STORAGE_SUB_RECONNECT_H +#define KVS_SDK_STORAGE_SUB_RECONNECT_H + +#endif //KVS_SDK_STORAGE_SUB_RECONNECT_H diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 06f5125356..d34bb8620d 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -2,6 +2,32 @@ #include "../samples/Samples.h" #include "Cloudwatch.h" +// Save first-frame-sent time to file for consumer-end access. +STATUS writeFirstFrameSentTimeToFile(PCHAR fileName) { + STATUS retStatus = STATUS_SUCCESS; + DLOGI("Writing to %s file", fileName); + UINT64 currentTimeMilliS = GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + CHAR cuurrentTimeChars[MAX_UINT64_DIGIT_COUNT + 1]; // +1 accounts for null terminator + UINT64 writeSize = SPRINTF(cuurrentTimeChars, "%llu", currentTimeMilliS); + CHK_STATUS(writeFile((PCHAR) fileName, false, false, static_cast(static_cast(cuurrentTimeChars)), writeSize)); + CleanUp: + return retStatus; +} + +VOID calculateDisconnectToFrameSentTime(PSampleConfiguration pSampleConfiguration) +{ + UINT64 disconnectTime = pSampleConfiguration->storageDisconnectedTime; + if (disconnectTime != 0) { + DOUBLE storageDisconnectToFrameSentTime = (DOUBLE) (GETTIME() - disconnectTime) / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + CppInteg::Cloudwatch::getInstance().monitoring.pushStorageDisconnectToFrameSentTime(storageDisconnectToFrameSentTime, + Aws::CloudWatch::Model::StandardUnit::Milliseconds); + DLOGI("Setting storageDisconnectedTime to zero (not set)"); + pSampleConfiguration->storageDisconnectedTime = 0; + } else { + DLOGI("Not sending storageDisconnectToFrameSentTime metric, storageDisconnectedTime is zero (not set)"); + } +} + STATUS publishStatsForCanary(RTC_STATS_TYPE statsType, PSampleStreamingSession pSampleStreamingSession) { STATUS retStatus = STATUS_SUCCESS; @@ -72,7 +98,7 @@ VOID createMockFrames(PBYTE buffer, PFrame pFrame) addMetadataToFrameData(buffer, pFrame); } -PVOID sendVideoPackets(PVOID args) +PVOID sendMockVideoPackets(PVOID args) { STATUS retStatus = STATUS_SUCCESS; STATUS status = STATUS_SUCCESS; @@ -130,6 +156,7 @@ PVOID sendVideoPackets(PVOID args) if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { PROFILE_WITH_START_TIME_OBJ(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, firstFrameTime, "Time to first frame"); CppInteg::Cloudwatch::getInstance().monitoring.pushTimeToFirstFrame(firstFrameTime, Aws::CloudWatch::Model::StandardUnit::Milliseconds); + pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame = FALSE; } if (status != STATUS_SRTP_NOT_READY_YET) { @@ -137,7 +164,7 @@ PVOID sendVideoPackets(PVOID args) DLOGV("writeFrame() failed with 0x%08x", status); } } - publishStatsForCanary(RTC_STATS_TYPE_OUTBOUND_RTP, pSampleConfiguration->sampleStreamingSessionList[i]); + CHK_STATUS(publishStatsForCanary(RTC_STATS_TYPE_OUTBOUND_RTP, pSampleConfiguration->sampleStreamingSessionList[i])); } MUTEX_UNLOCK(pSampleConfiguration->streamingSessionListReadLock); THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_SECOND / DEFAULT_FRAME_RATE); @@ -150,13 +177,96 @@ PVOID sendVideoPackets(PVOID args) return NULL; } -PVOID sendAudioPackets(PVOID args) +PVOID sendRealVideoPackets(PVOID args) { STATUS retStatus = STATUS_SUCCESS; PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) args; Frame frame; UINT32 fileIndex = 0, frameSize; CHAR filePath[MAX_PATH_LEN + 1]; + STATUS status; + UINT32 i; + UINT64 startTime, lastFrameTime, elapsed; + CHAR tsFileName[MAX_PATH_LEN + 1]; + UINT64 firstFrameTime = 0; + CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); + + frame.presentationTs = 0; + startTime = GETTIME(); + lastFrameTime = startTime; + + while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { + fileIndex = fileIndex % NUMBER_OF_H264_FRAME_FILES + 1; + if (pSampleConfiguration->videoCodec == RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE) { + SNPRINTF(filePath, MAX_PATH_LEN, "./h264SampleFrames/frame-%04d.h264", fileIndex); + } else if (pSampleConfiguration->videoCodec == RTC_CODEC_H265) { + SNPRINTF(filePath, MAX_PATH_LEN, "./h265SampleFrames/frame-%04d.h265", fileIndex); + } + + CHK_STATUS(readFrameFromDisk(NULL, &frameSize, filePath)); + + // Re-alloc if needed + if (frameSize > pSampleConfiguration->videoBufferSize) { + pSampleConfiguration->pVideoFrameBuffer = (PBYTE) MEMREALLOC(pSampleConfiguration->pVideoFrameBuffer, frameSize); + CHK_ERR(pSampleConfiguration->pVideoFrameBuffer != NULL, STATUS_NOT_ENOUGH_MEMORY, "[KVS Master] Failed to allocate video frame buffer"); + pSampleConfiguration->videoBufferSize = frameSize; + } + + frame.frameData = pSampleConfiguration->pVideoFrameBuffer; + frame.size = frameSize; + + CHK_STATUS(readFrameFromDisk(frame.frameData, &frameSize, filePath)); + + // based on bitrate of samples/h264SampleFrames/frame-* + frame.presentationTs += SAMPLE_VIDEO_FRAME_DURATION; + MUTEX_LOCK(pSampleConfiguration->streamingSessionListReadLock); + for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { + status = writeFrame(pSampleConfiguration->sampleStreamingSessionList[i]->pVideoRtcRtpTransceiver, &frame); + if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { + SNPRINTF(tsFileName, SIZEOF(tsFileName), "%s%s", FIRST_FRAME_TS_FILE_PATH, STORAGE_CANARY_DEFAULT_FIRST_FRAME_TS_FILE); + CHK_STATUS(writeFirstFrameSentTimeToFile(tsFileName)); + PROFILE_WITH_START_TIME_OBJ(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, firstFrameTime, "Time to first frame"); + CppInteg::Cloudwatch::getInstance().monitoring.pushTimeToFirstFrame(firstFrameTime, + Aws::CloudWatch::Model::StandardUnit::Milliseconds); + calculateDisconnectToFrameSentTime(pSampleConfiguration); + pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame = FALSE; + } + if (status != STATUS_SRTP_NOT_READY_YET) { + if (status != STATUS_SUCCESS) { + DLOGV("writeFrame() failed with 0x%08x", status); + } + } else { + // Reset file index to ensure first frame sent upon SRTP ready is a key frame. + fileIndex = 0; + } + } + MUTEX_UNLOCK(pSampleConfiguration->streamingSessionListReadLock); + + // Adjust sleep in the case the sleep itself and writeFrame take longer than expected. Since sleep makes sure that the thread + // will be paused at least until the given amount, we can assume that there's no too early frame scenario. + // Also, it's very unlikely to have a delay greater than SAMPLE_VIDEO_FRAME_DURATION, so the logic assumes that this is always + // true for simplicity. + elapsed = lastFrameTime - startTime; + THREAD_SLEEP(SAMPLE_VIDEO_FRAME_DURATION - elapsed % SAMPLE_VIDEO_FRAME_DURATION); + lastFrameTime = GETTIME(); + } + + CleanUp: + DLOGI("[KVS Master] Closing video thread"); + CHK_LOG_ERR(retStatus); + + return (PVOID) (ULONG_PTR) retStatus; +} + +PVOID sendRealAudioPackets(PVOID args) +{ + STATUS retStatus = STATUS_SUCCESS; + PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) args; + Frame frame; + UINT32 fileIndex = 0, frameSize; + CHAR filePath[MAX_PATH_LEN + 1]; + CHAR tsFileName[MAX_PATH_LEN + 1]; + UINT64 firstFrameTime = 0; UINT32 i; STATUS status; @@ -165,7 +275,12 @@ PVOID sendAudioPackets(PVOID args) while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { fileIndex = fileIndex % NUMBER_OF_OPUS_FRAME_FILES + 1; - SNPRINTF(filePath, MAX_PATH_LEN, "./opusSampleFrames/sample-%03d.opus", fileIndex); + + if (pSampleConfiguration->audioCodec == RTC_CODEC_AAC) { + SNPRINTF(filePath, MAX_PATH_LEN, "./aacSampleFrames/sample-%03d.aac", fileIndex); + } else if (pSampleConfiguration->audioCodec == RTC_CODEC_OPUS) { + SNPRINTF(filePath, MAX_PATH_LEN, "./opusSampleFrames/sample-%03d.opus", fileIndex); + } CHK_STATUS(readFrameFromDisk(NULL, &frameSize, filePath)); @@ -190,7 +305,13 @@ PVOID sendAudioPackets(PVOID args) if (status != STATUS_SUCCESS) { DLOGV("writeFrame() failed with 0x%08x", status); } else if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { - PROFILE_WITH_START_TIME(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, "Time to first frame"); + SNPRINTF(tsFileName, SIZEOF(tsFileName), "%s%s", FIRST_FRAME_TS_FILE_PATH, STORAGE_CANARY_DEFAULT_FIRST_FRAME_TS_FILE); + CHK_STATUS(writeFirstFrameSentTimeToFile(tsFileName)); + PROFILE_WITH_START_TIME_OBJ(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, firstFrameTime, "Time to first frame"); + CppInteg::Cloudwatch::getInstance().monitoring.pushTimeToFirstFrame(firstFrameTime, + Aws::CloudWatch::Model::StandardUnit::Milliseconds); + + calculateDisconnectToFrameSentTime(pSampleConfiguration); pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame = FALSE; } } else { @@ -207,12 +328,6 @@ PVOID sendAudioPackets(PVOID args) return (PVOID) (ULONG_PTR) retStatus; } -VOID sampleVideoFrameHandlerCW(UINT64 customData, PFrame pFrame) -{ - PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; - publishStatsForCanary(RTC_STATS_TYPE_INBOUND_RTP, pSampleStreamingSession); -} - INT32 main(INT32 argc, CHAR* argv[]) { STATUS retStatus = STATUS_SUCCESS; @@ -229,32 +344,39 @@ INT32 main(INT32 argc, CHAR* argv[]) SET_INSTRUMENTED_ALLOCATORS(); UINT32 logLevel = setLogLevel(); // Initialize KVS WebRTC. This must be done before anything else, and must only be done once. - initKvsWebRtc(); + CHK_STATUS(initKvsWebRtc()); channelNamePrefix = argc > 1 ? argv[1] : CHANNEL_NAME_PREFIX; SNPRINTF(channelName, SIZEOF(channelName), CHANNEL_NAME_TEMPLATE, channelNamePrefix, RUNNER_LABEL); - CHK_STATUS(createSampleConfiguration(channelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, USE_TRICKLE_ICE, USE_TURN, logLevel, &pSampleConfiguration)); - CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, USE_IOT)); - // Set the audio and video handlers - pSampleConfiguration->audioSource = sendAudioPackets; - pSampleConfiguration->videoSource = sendVideoPackets; - pSampleConfiguration->receiveAudioVideoSource = NULL; - pSampleConfiguration->audioCodec = AUDIO_CODEC; - pSampleConfiguration->videoCodec = VIDEO_CODEC; + CHK_STATUS(createSampleConfiguration(channelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration)); + CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, IOT_CORE_ENABLE_CREDENTIALS)); + pSampleConfiguration->forceTurn = FORCE_TURN_ONLY; pSampleConfiguration->enableMetrics = ENABLE_METRICS; - pSampleConfiguration->channelInfo.useMediaStorage = USE_STORAGE; + pSampleConfiguration->channelInfo.useMediaStorage = ENABLE_STORAGE; + pSampleConfiguration->audioCodec = AUDIO_CODEC; + pSampleConfiguration->videoCodec = VIDEO_CODEC; + + if(pSampleConfiguration->channelInfo.useMediaStorage) { + pSampleConfiguration->audioSource = sendRealAudioPackets; + pSampleConfiguration->videoSource = sendRealVideoPackets; + pSampleConfiguration->receiveAudioVideoSource = NULL; + } else { + pSampleConfiguration->audioSource = sendRealAudioPackets; + pSampleConfiguration->videoSource = sendMockVideoPackets; + pSampleConfiguration->receiveAudioVideoSource = NULL; + } if ((region = GETENV(DEFAULT_REGION_ENV_VAR)) == NULL) { region = (PCHAR) DEFAULT_AWS_REGION; } - CppInteg::Cloudwatch::init(channelName, region, TRUE); + CppInteg::Cloudwatch::init(channelName, region, TRUE, pSampleConfiguration->channelInfo.useMediaStorage); if(ENABLE_DATA_CHANNEL) { pSampleConfiguration->onDataChannel = onDataChannel; } pSampleConfiguration->mediaType = SAMPLE_STREAMING_AUDIO_VIDEO; - DLOGI("[KVS CW Master] Finished setting handlers"); + DLOGI("[KVS Master] Finished setting handlers"); DLOGI("[KVS Master] KVS WebRTC initialization completed successfully"); @@ -266,21 +388,22 @@ INT32 main(INT32 argc, CHAR* argv[]) DLOGI("[KVS Master] Channel %s set up done ", channelName); std::thread pushProfilingThread(sendProfilingMetrics, pSampleConfiguration); - pushProfilingThread.join(); - // Checking for termination CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, (UINT64) pSampleConfiguration, &terminateId)); + // Checking for termination CHK_STATUS(sessionCleanupWait(pSampleConfiguration)); DLOGI("[KVS Master] Streaming session terminated"); - if (retStatus != STATUS_SUCCESS) { - DLOGE("[KVS Master] Terminated with status code 0x%08x", retStatus); - } + pushProfilingThread.join(); } CleanUp: - Aws::ShutdownAPI(options); + + if (retStatus != STATUS_SUCCESS) { + DLOGE("[KVS Master] Terminated with status code 0x%08x", retStatus); + } + DLOGI("[KVS Master] Cleaning up...."); if (pSampleConfiguration != NULL) { // Kick of the termination sequence @@ -305,10 +428,28 @@ INT32 main(INT32 argc, CHAR* argv[]) retStatus = RESET_INSTRUMENTED_ALLOCATORS(); DLOGI("All SDK allocations freed? %s..0x%08x", retStatus == STATUS_SUCCESS ? "Yes" : "No", retStatus); + + CppInteg::Cloudwatch::getInstance().monitoring.pushExitStatus(retStatus); + CppInteg::Cloudwatch::deinit(); + Aws::ShutdownAPI(options); + // https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html // We can only return with 0 - 127. Some platforms treat exit code >= 128 // to be a success code, which might give an unintended behaviour. // Some platforms also treat 1 or 0 differently, so it's better to use // EXIT_FAILURE and EXIT_SUCCESS macros for portability. return STATUS_FAILED(retStatus) ? EXIT_FAILURE : EXIT_SUCCESS; -} \ No newline at end of file +} + +PVOID sampleReceiveAudioVideoFrame(PVOID args) +{ + STATUS retStatus = STATUS_SUCCESS; + PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) args; + CHK_ERR(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); + CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pVideoRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleVideoFrameHandler)); + CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pAudioRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleAudioFrameHandler)); + + CleanUp: + + return (PVOID) (ULONG_PTR) retStatus; +} diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index 2202ff60ef..d31fb0ccc6 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -33,6 +33,29 @@ VOID dataChannelOnOpenCallback(UINT64 customData, PRtcDataChannel pDataChannel) } #endif +STATUS publishStatsForCanary(RTC_STATS_TYPE statsType, PSampleStreamingSession pSampleStreamingSession) +{ + STATUS retStatus = STATUS_SUCCESS; + pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = statsType; + switch (statsType) { + case RTC_STATS_TYPE_OUTBOUND_RTP: + CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); + populateOutgoingRtpMetricsContext(pSampleStreamingSession); + CppInteg::Cloudwatch::getInstance().monitoring.pushOutboundRtpStats(&pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx); + break; + case RTC_STATS_TYPE_INBOUND_RTP: + DLOGI("Inbound"); + CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); + populateIncomingRtpMetricsContext(pSampleStreamingSession); + CppInteg::Cloudwatch::getInstance().monitoring.pushInboundRtpStats(&pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx); + break; + default: + CHK(FALSE, STATUS_NOT_IMPLEMENTED); + } + CleanUp: + return retStatus; +} + STATUS publishEndToEndMetrics(PSampleStreamingSession pSampleStreamingSession) { STATUS retStatus = STATUS_SUCCESS; @@ -57,6 +80,20 @@ STATUS endToendStatsCallback(UINT32 timerId, UINT64 currentTime, UINT64 customDa return retStatus; } +STATUS inboundStatsCallback(UINT32 timerId, UINT64 currentTime, UINT64 customData) { + UNUSED_PARAM(timerId); + UNUSED_PARAM(currentTime); + STATUS retStatus = STATUS_SUCCESS; + PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; + if (!(ATOMIC_LOAD_BOOL(&pSampleStreamingSession->pSampleConfiguration->appTerminateFlag))) { + publishStatsForCanary(RTC_STATS_TYPE_INBOUND_RTP, pSampleStreamingSession); + } else { + retStatus = STATUS_TIMER_QUEUE_STOP_SCHEDULING; + } +CleanUp: + return retStatus; +} + VOID videoFrameHandler(UINT64 customData, PFrame pFrame) { @@ -108,6 +145,7 @@ INT32 main(INT32 argc, CHAR* argv[]) PCHAR channelNamePrefix; UINT32 e2eTimerId = MAX_UINT32; UINT32 terminateId = MAX_UINT32; + UINT32 inboundTimerId = MAX_UINT32; Aws::SDKOptions options; Aws::InitAPI(options); { @@ -128,7 +166,7 @@ INT32 main(INT32 argc, CHAR* argv[]) pSampleConfiguration->videoCodec = VIDEO_CODEC; pSampleConfiguration->forceTurn = FORCE_TURN_ONLY; pSampleConfiguration->enableMetrics = ENABLE_METRICS; - pSampleConfiguration->channelInfo.useMediaStorage = USE_STORAGE; + pSampleConfiguration->receiveAudioVideoSource = NULL; // Initialize KVS WebRTC. This must be done before anything else, and must only be done once. CHK_STATUS(initKvsWebRtc()); @@ -141,7 +179,7 @@ INT32 main(INT32 argc, CHAR* argv[]) if ((region = GETENV(DEFAULT_REGION_ENV_VAR)) == NULL) { region = (PCHAR) DEFAULT_AWS_REGION; } - CppInteg::Cloudwatch::init(channelName, region, FALSE); + CppInteg::Cloudwatch::init(channelName, region, FALSE, FALSE); SNPRINTF(clientId, SIZEOF(clientId), "%s_%u", SAMPLE_VIEWER_CLIENT_ID, RAND() % MAX_UINT32); CHK_STATUS(initSignaling(pSampleConfiguration, clientId)); @@ -222,6 +260,8 @@ INT32 main(INT32 argc, CHAR* argv[]) endToendStatsCallback, (UINT64) pSampleStreamingSession, &e2eTimerId)); CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, (UINT64) pSampleConfiguration, &terminateId)); + CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, END_TO_END_METRICS_INVOCATION_PERIOD, END_TO_END_METRICS_INVOCATION_PERIOD, + inboundStatsCallback, (UINT64) pSampleStreamingSession, &inboundTimerId)); // Block until interrupted while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted) && !ATOMIC_LOAD_BOOL(&pSampleStreamingSession->terminateFlag)) { THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_SECOND); diff --git a/samples/Samples.h b/samples/Samples.h index 8286941b9f..2ec59bd7a6 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -184,6 +184,7 @@ typedef struct { BOOL forceTurn; BOOL enableMetrics; BOOL useIot; + UINT64 storageDisconnectedTime; SignalingClientMetrics signalingClientMetrics; } SampleConfiguration, *PSampleConfiguration; diff --git a/samples/lib/Common.c b/samples/lib/Common.c index bbd3edb50d..38e9c376c8 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -56,6 +56,7 @@ VOID onConnectionStateChange(UINT64 customData, RTC_PEER_CONNECTION_STATE newSta DLOGD("p2p connection disconnected"); ATOMIC_STORE_BOOL(&pSampleStreamingSession->terminateFlag, TRUE); CVAR_BROADCAST(pSampleConfiguration->cvar); + pSampleConfiguration->storageDisconnectedTime = GETTIME(); // explicit fallthrough default: ATOMIC_STORE_BOOL(&pSampleConfiguration->connected, FALSE); From a2918678fed7e695f70846c670918034ef4e2377 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 4 Jun 2024 13:50:51 -0700 Subject: [PATCH 22/64] Update config --- cloudwatch-integ/configs/storage_extended.h | 22 +++++++++++++--- .../configs/storage_single_reconnect.h | 26 ++++++++++++++----- .../configs/storage_sub_reconnect.h | 26 ++++++++++++++----- 3 files changed, 57 insertions(+), 17 deletions(-) diff --git a/cloudwatch-integ/configs/storage_extended.h b/cloudwatch-integ/configs/storage_extended.h index 47131ef614..ed957bc1e9 100644 --- a/cloudwatch-integ/configs/storage_extended.h +++ b/cloudwatch-integ/configs/storage_extended.h @@ -1,4 +1,20 @@ -#ifndef KVS_SDK_STORAGE_EXTENDED_H -#define KVS_SDK_STORAGE_EXTENDED_H +#ifndef KVS_SDK_SAMPLE_CONFIG_H +#define KVS_SDK_SAMPLE_CONFIG_H -#endif //KVS_SDK_STORAGE_EXTENDED_H +#define USE_TRICKLE_ICE TRUE +#define FORCE_TURN_ONLY FALSE +#define RUNNER_LABEL (PCHAR) "StoragePeriodic" +#define SCENARIO_LABEL (PCHAR) "StoragePeriodic" +#define USE_TURN TRUE +#define ENABLE_TTFF_VIA_DC FALSE +#define USE_IOT FALSE +#define ENABLE_STORAGE TRUE +#define ENABLE_METRICS TRUE +#define SAMPLE_PRE_GENERATE_CERT TRUE +#define RUN_TIME (43200 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" +#define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" +#define USE_STORAGE TRUE +#define AUDIO_CODEC RTC_CODEC_OPUS +#define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/storage_single_reconnect.h b/cloudwatch-integ/configs/storage_single_reconnect.h index e1eedbb81e..46eb032f62 100644 --- a/cloudwatch-integ/configs/storage_single_reconnect.h +++ b/cloudwatch-integ/configs/storage_single_reconnect.h @@ -1,8 +1,20 @@ -// -// Created by Sampath Kumar, Divya on 5/29/24. -// +#ifndef KVS_SDK_SAMPLE_CONFIG_H +#define KVS_SDK_SAMPLE_CONFIG_H -#ifndef KVS_SDK_STORAGE_SINGLE_RECONNECT_H -#define KVS_SDK_STORAGE_SINGLE_RECONNECT_H - -#endif //KVS_SDK_STORAGE_SINGLE_RECONNECT_H +#define USE_TRICKLE_ICE TRUE +#define FORCE_TURN_ONLY FALSE +#define RUNNER_LABEL (PCHAR) "StoragePeriodic" +#define SCENARIO_LABEL (PCHAR) "StoragePeriodic" +#define USE_TURN TRUE +#define ENABLE_TTFF_VIA_DC FALSE +#define USE_IOT FALSE +#define ENABLE_STORAGE TRUE +#define ENABLE_METRICS TRUE +#define SAMPLE_PRE_GENERATE_CERT TRUE +#define RUN_TIME (3900 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" +#define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" +#define USE_STORAGE TRUE +#define AUDIO_CODEC RTC_CODEC_OPUS +#define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/storage_sub_reconnect.h b/cloudwatch-integ/configs/storage_sub_reconnect.h index 0382abda9d..7050810e49 100644 --- a/cloudwatch-integ/configs/storage_sub_reconnect.h +++ b/cloudwatch-integ/configs/storage_sub_reconnect.h @@ -1,8 +1,20 @@ -// -// Created by Sampath Kumar, Divya on 5/29/24. -// +#ifndef KVS_SDK_SAMPLE_CONFIG_H +#define KVS_SDK_SAMPLE_CONFIG_H -#ifndef KVS_SDK_STORAGE_SUB_RECONNECT_H -#define KVS_SDK_STORAGE_SUB_RECONNECT_H - -#endif //KVS_SDK_STORAGE_SUB_RECONNECT_H +#define USE_TRICKLE_ICE TRUE +#define FORCE_TURN_ONLY FALSE +#define RUNNER_LABEL (PCHAR) "StoragePeriodic" +#define SCENARIO_LABEL (PCHAR) "StoragePeriodic" +#define USE_TURN TRUE +#define ENABLE_TTFF_VIA_DC FALSE +#define USE_IOT FALSE +#define ENABLE_STORAGE TRUE +#define ENABLE_METRICS TRUE +#define SAMPLE_PRE_GENERATE_CERT TRUE +#define RUN_TIME (2700 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" +#define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" +#define USE_STORAGE TRUE +#define AUDIO_CODEC RTC_CODEC_OPUS +#define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#endif // KVS_SDK_SAMPLE_CONFIG_H From 23c524e0ef989de4040338ee6b2e4416aa866eb1 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 4 Jun 2024 15:01:46 -0700 Subject: [PATCH 23/64] fix labels and storage --- cloudwatch-integ/CloudwatchMonitoring.cpp | 2 +- cloudwatch-integ/configs/storage_extended.h | 4 ++-- cloudwatch-integ/configs/storage_single_reconnect.h | 4 ++-- cloudwatch-integ/configs/storage_sub_reconnect.h | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/cloudwatch-integ/CloudwatchMonitoring.cpp b/cloudwatch-integ/CloudwatchMonitoring.cpp index c19422ee22..cf89472f9e 100644 --- a/cloudwatch-integ/CloudwatchMonitoring.cpp +++ b/cloudwatch-integ/CloudwatchMonitoring.cpp @@ -10,7 +10,7 @@ CloudwatchMonitoring::CloudwatchMonitoring(ClientConfiguration* pClientConfig) : STATUS CloudwatchMonitoring::init(PCHAR channelName, PCHAR region, BOOL isMaster, BOOL isStorage) { STATUS retStatus = STATUS_SUCCESS; - + this->isStorage = isStorage; isStorage ? this->channelDimension.SetName(INDIVIDUAL_STORAGE_CW_DIMENSION) : this->channelDimension.SetName(INDIVIDUAL_CW_DIMENSION); this->channelDimension.SetValue(channelName); diff --git a/cloudwatch-integ/configs/storage_extended.h b/cloudwatch-integ/configs/storage_extended.h index ed957bc1e9..b6de502160 100644 --- a/cloudwatch-integ/configs/storage_extended.h +++ b/cloudwatch-integ/configs/storage_extended.h @@ -3,8 +3,8 @@ #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE -#define RUNNER_LABEL (PCHAR) "StoragePeriodic" -#define SCENARIO_LABEL (PCHAR) "StoragePeriodic" +#define RUNNER_LABEL (PCHAR) "StorageExtended" +#define SCENARIO_LABEL (PCHAR) "StorageExtended" #define USE_TURN TRUE #define ENABLE_TTFF_VIA_DC FALSE #define USE_IOT FALSE diff --git a/cloudwatch-integ/configs/storage_single_reconnect.h b/cloudwatch-integ/configs/storage_single_reconnect.h index 46eb032f62..456e6aca1a 100644 --- a/cloudwatch-integ/configs/storage_single_reconnect.h +++ b/cloudwatch-integ/configs/storage_single_reconnect.h @@ -3,8 +3,8 @@ #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE -#define RUNNER_LABEL (PCHAR) "StoragePeriodic" -#define SCENARIO_LABEL (PCHAR) "StoragePeriodic" +#define RUNNER_LABEL (PCHAR) "StorageSingleReconnect" +#define SCENARIO_LABEL (PCHAR) "StorageSingleReconnect" #define USE_TURN TRUE #define ENABLE_TTFF_VIA_DC FALSE #define USE_IOT FALSE diff --git a/cloudwatch-integ/configs/storage_sub_reconnect.h b/cloudwatch-integ/configs/storage_sub_reconnect.h index 7050810e49..43b105804c 100644 --- a/cloudwatch-integ/configs/storage_sub_reconnect.h +++ b/cloudwatch-integ/configs/storage_sub_reconnect.h @@ -3,8 +3,8 @@ #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE -#define RUNNER_LABEL (PCHAR) "StoragePeriodic" -#define SCENARIO_LABEL (PCHAR) "StoragePeriodic" +#define RUNNER_LABEL (PCHAR) "StorageSubReconnect" +#define SCENARIO_LABEL (PCHAR) "StorageSubReconnect" #define USE_TURN TRUE #define ENABLE_TTFF_VIA_DC FALSE #define USE_IOT FALSE From 48ac30804671817290299adcc93e7b0b19f46bfd Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 4 Jun 2024 15:32:16 -0700 Subject: [PATCH 24/64] Remove file --- cloudwatch-integ/Include.h | 2 +- cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/cloudwatch-integ/Include.h b/cloudwatch-integ/Include.h index 7c7a3f2ee6..3d4062d863 100644 --- a/cloudwatch-integ/Include.h +++ b/cloudwatch-integ/Include.h @@ -25,7 +25,7 @@ #define STORAGE_CANARY_FIRST_FRAME_TS_FILE_ENV_VAR "STORAGE_CANARY_FIRST_FRAME_TS_FILE" #define FIRST_FRAME_TS_FILE_PATH (PCHAR) "/tmp/" -#define STORAGE_CANARY_DEFAULT_FIRST_FRAME_TS_FILE (PCHAR) "DefaultFirstFrameSentTSFileName.txt" +#define STORAGE_DEFAULT_FIRST_FRAME_TS_FILE (PCHAR) "DefaultFirstFrameSentTSFileName.txt" #define INDIVIDUAL_STORAGE_CW_DIMENSION "StorageWebRTCSDKCanaryChannelName" #define INDIVIDUAL_CW_DIMENSION "WebRTCSDKCanaryChannelName" diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index d34bb8620d..c72d9fffba 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -223,7 +223,7 @@ PVOID sendRealVideoPackets(PVOID args) for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { status = writeFrame(pSampleConfiguration->sampleStreamingSessionList[i]->pVideoRtcRtpTransceiver, &frame); if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { - SNPRINTF(tsFileName, SIZEOF(tsFileName), "%s%s", FIRST_FRAME_TS_FILE_PATH, STORAGE_CANARY_DEFAULT_FIRST_FRAME_TS_FILE); + SNPRINTF(tsFileName, SIZEOF(tsFileName), "%s%s", FIRST_FRAME_TS_FILE_PATH, STORAGE_DEFAULT_FIRST_FRAME_TS_FILE); CHK_STATUS(writeFirstFrameSentTimeToFile(tsFileName)); PROFILE_WITH_START_TIME_OBJ(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, firstFrameTime, "Time to first frame"); CppInteg::Cloudwatch::getInstance().monitoring.pushTimeToFirstFrame(firstFrameTime, @@ -305,7 +305,7 @@ PVOID sendRealAudioPackets(PVOID args) if (status != STATUS_SUCCESS) { DLOGV("writeFrame() failed with 0x%08x", status); } else if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { - SNPRINTF(tsFileName, SIZEOF(tsFileName), "%s%s", FIRST_FRAME_TS_FILE_PATH, STORAGE_CANARY_DEFAULT_FIRST_FRAME_TS_FILE); + SNPRINTF(tsFileName, SIZEOF(tsFileName), "%s%s", FIRST_FRAME_TS_FILE_PATH, STORAGE_DEFAULT_FIRST_FRAME_TS_FILE); CHK_STATUS(writeFirstFrameSentTimeToFile(tsFileName)); PROFILE_WITH_START_TIME_OBJ(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, firstFrameTime, "Time to first frame"); CppInteg::Cloudwatch::getInstance().monitoring.pushTimeToFirstFrame(firstFrameTime, @@ -338,7 +338,8 @@ INT32 main(INT32 argc, CHAR* argv[]) CHAR channelName[MAX_CHANNEL_NAME_LEN]; PCHAR channelNamePrefix; Aws::SDKOptions options; - options.httpOptions.installSigPipeHandler = true; + options.httpOptions.installSigPipeHandler = TRUE; + CHAR tsFileName[MAX_PATH_LEN + 1]; Aws::InitAPI(options); { SET_INSTRUMENTED_ALLOCATORS(); @@ -428,7 +429,7 @@ INT32 main(INT32 argc, CHAR* argv[]) retStatus = RESET_INSTRUMENTED_ALLOCATORS(); DLOGI("All SDK allocations freed? %s..0x%08x", retStatus == STATUS_SUCCESS ? "Yes" : "No", retStatus); - + SNPRINTF(tsFileName, SIZEOF(tsFileName), "%s%s", FIRST_FRAME_TS_FILE_PATH, STORAGE_DEFAULT_FIRST_FRAME_TS_FILE); CppInteg::Cloudwatch::getInstance().monitoring.pushExitStatus(retStatus); CppInteg::Cloudwatch::deinit(); Aws::ShutdownAPI(options); From 6d0953ea67f268b9af565c7bd0a66cdfaa354eff Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 4 Jun 2024 16:31:17 -0700 Subject: [PATCH 25/64] use iot disable --- cloudwatch-integ/configs/p_static_h264_mbedtls.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudwatch-integ/configs/p_static_h264_mbedtls.h b/cloudwatch-integ/configs/p_static_h264_mbedtls.h index 67db2bb604..c2f74c2304 100644 --- a/cloudwatch-integ/configs/p_static_h264_mbedtls.h +++ b/cloudwatch-integ/configs/p_static_h264_mbedtls.h @@ -7,7 +7,7 @@ #define SCENARIO_LABEL (PCHAR) "MbedTLSPeriodic" #define USE_TURN TRUE #define ENABLE_TTFF_VIA_DC FALSE -#define USE_IOT TRUE +#define USE_IOT FALSE #define ENABLE_STORAGE FALSE #define ENABLE_METRICS TRUE #define SAMPLE_PRE_GENERATE_CERT TRUE From 0eb9d47cfe16bb3da144d5a476ec1f2b404532da Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Wed, 5 Jun 2024 13:56:00 -0700 Subject: [PATCH 26/64] Scripts --- scripts/cert_setup.sh | 23 +++++++++++ scripts/generate-iot-credential.sh | 66 ++++++++++++++---------------- 2 files changed, 53 insertions(+), 36 deletions(-) create mode 100755 scripts/cert_setup.sh diff --git a/scripts/cert_setup.sh b/scripts/cert_setup.sh new file mode 100755 index 0000000000..36efdc5a41 --- /dev/null +++ b/scripts/cert_setup.sh @@ -0,0 +1,23 @@ +#!/bin/bash + +prefix=$1 +thingName="${prefix}_thing" +thingTypeName="${prefix}_thing_type" +iotPolicyName="${prefix}_policy" +kvsPolicyName="${prefix}_policy" +iotRoleName="${prefix}_role" +iotRoleAlias="${prefix}_role_alias" +iotCert="${prefix}_certificate.pem" +iotPublicKey="${prefix}_public.key" +iotPrivateKey="${prefix}_private.key" + +# Create the certificate to which you must attach the policy for IoT that you created above. +aws --profile default iot create-keys-and-certificate --set-as-active --certificate-pem-outfile $iotCert --public-key-outfile $iotPublicKey --private-key-outfile $iotPrivateKey > certificate +# Attach the policy for IoT (KvsCameraIoTPolicy created above) to this certificate. +aws --profile default iot attach-policy --policy-name $iotPolicyName --target $(jq --raw-output '.certificateArn' certificate) +# Attach your IoT thing (kvs_example_camera_stream) to the certificate you just created: +aws --profile default iot attach-thing-principal --thing-name $thingName --principal $(jq --raw-output '.certificateArn' certificate) +# In order to authorize requests through the IoT credentials provider, you need the IoT credentials endpoint which is unique to your AWS account ID. You can use the following command to get the IoT credentials endpoint. +aws --profile default iot describe-endpoint --endpoint-type iot:CredentialProvider --output text > iot-credential-provider.txt +# In addition to the X.509 cerficiate created above, you must also have a CA certificate to establish trust with the back-end service through TLS. You can get the CA certificate using the following command: +curl --silent 'https://www.amazontrust.com/repository/SFSRootCAG2.pem' --output cacert.pem \ No newline at end of file diff --git a/scripts/generate-iot-credential.sh b/scripts/generate-iot-credential.sh index ae3b3c720b..6d800d8701 100755 --- a/scripts/generate-iot-credential.sh +++ b/scripts/generate-iot-credential.sh @@ -2,15 +2,17 @@ # You need to setup your aws cli first, because this script is based on aws cli. # You can use this script to setup environment variables in the shell which samples run on. # https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/how-iot.html -thingName="webrtc_iot_thing" -thingTypeName="webrtc_iot_thing_type" -iotPolicyName="webrtc_iot_policy" -kvsPolicyName="webrtc_policy" -iotRoleName="webrtc_iot_role" -iotRoleAlias="webrtc_iot_role_alias" -iotCert="webrtc_iot_certifcate.pem" -iotPublicKey="webrtc_iot_public.key" -iotPrivateKey="webrtc_iot_private.key" + +prefix=$1 +thingName="${prefix}_thing" +thingTypeName="${prefix}_thing_type" +iotPolicyName="${prefix}_policy" +kvsPolicyName="${prefix}_policy" +iotRoleName="${prefix}_role" +iotRoleAlias="${prefix}_role_alias" +iotCert="${prefix}_certificate.pem" +iotPublicKey="${prefix}_public.key" +iotPrivateKey="${prefix}_private.key" # Step 1: Create an IoT Thing Type and an IoT Thing # The following example command creates a thing type $thingTypeName @@ -65,18 +67,18 @@ cat > iot-policy-document.json < certificate -# Attach the policy for IoT (KvsCameraIoTPolicy created above) to this certificate. -aws --profile default iot attach-policy --policy-name $iotPolicyName --target $(jq --raw-output '.certificateArn' certificate) -# Attach your IoT thing (kvs_example_camera_stream) to the certificate you just created: -aws --profile default iot attach-thing-principal --thing-name $thingName --principal $(jq --raw-output '.certificateArn' certificate) -# In order to authorize requests through the IoT credentials provider, you need the IoT credentials endpoint which is unique to your AWS account ID. You can use the following command to get the IoT credentials endpoint. -aws --profile default iot describe-endpoint --endpoint-type iot:CredentialProvider --output text > iot-credential-provider.txt -# In addition to the X.509 cerficiate created above, you must also have a CA certificate to establish trust with the back-end service through TLS. You can get the CA certificate using the following command: -curl --silent 'https://www.amazontrust.com/repository/SFSRootCAG2.pem' --output cacert.pem - - -export AWS_IOT_CORE_CREDENTIAL_ENDPOINT=$(cat iot-credential-provider.txt) -export AWS_IOT_CORE_CERT=$(pwd)"/"$iotCert -export AWS_IOT_CORE_PRIVATE_KEY=$(pwd)"/"$iotPrivateKey -export AWS_IOT_CORE_ROLE_ALIAS=$iotRoleAlias -export AWS_IOT_CORE_THING_NAME=$thingName - +# aws --profile default iot create-keys-and-certificate --set-as-active --certificate-pem-outfile $iotCert --public-key-outfile $iotPublicKey --private-key-outfile $iotPrivateKey > certificate +# # Attach the policy for IoT (KvsCameraIoTPolicy created above) to this certificate. +# aws --profile default iot attach-policy --policy-name $iotPolicyName --target $(jq --raw-output '.certificateArn' certificate) +# # Attach your IoT thing (kvs_example_camera_stream) to the certificate you just created: +# aws --profile default iot attach-thing-principal --thing-name $thingName --principal $(jq --raw-output '.certificateArn' certificate) +# # In order to authorize requests through the IoT credentials provider, you need the IoT credentials endpoint which is unique to your AWS account ID. You can use the following command to get the IoT credentials endpoint. +# aws --profile default iot describe-endpoint --endpoint-type iot:CredentialProvider --output text > iot-credential-provider.txt +# # In addition to the X.509 cerficiate created above, you must also have a CA certificate to establish trust with the back-end service through TLS. You can get the CA certificate using the following command: +# curl --silent 'https://www.amazontrust.com/repository/SFSRootCAG2.pem' --output cacert.pem From 68ac66da3910c183692f4389ac55ce2cce11e4f9 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Wed, 5 Jun 2024 14:28:38 -0700 Subject: [PATCH 27/64] iot try --- cloudwatch-integ/configs/lr_iot_h264_openssl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudwatch-integ/configs/lr_iot_h264_openssl.h b/cloudwatch-integ/configs/lr_iot_h264_openssl.h index 8ef8019207..85bf37e53b 100644 --- a/cloudwatch-integ/configs/lr_iot_h264_openssl.h +++ b/cloudwatch-integ/configs/lr_iot_h264_openssl.h @@ -7,7 +7,7 @@ #define SCENARIO_LABEL (PCHAR) "OpenSSLPeriodic" #define USE_TURN TRUE #define ENABLE_TTFF_VIA_DC FALSE -#define USE_IOT FALSE +#define USE_IOT TRUE #define ENABLE_STORAGE FALSE #define ENABLE_METRICS TRUE #define SAMPLE_PRE_GENERATE_CERT TRUE From 6bacd1eb2011f7899b6fb9be7ef7aadcbbfdbf26 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Wed, 5 Jun 2024 15:40:45 -0700 Subject: [PATCH 28/64] fix use iot in master --- .../kvsWebRTCClientMasterCloudwatch.cpp | 15 ++++++++++++--- samples/lib/Common.c | 1 + 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index c72d9fffba..38e118e7c0 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -346,10 +346,19 @@ INT32 main(INT32 argc, CHAR* argv[]) UINT32 logLevel = setLogLevel(); // Initialize KVS WebRTC. This must be done before anything else, and must only be done once. CHK_STATUS(initKvsWebRtc()); - channelNamePrefix = argc > 1 ? argv[1] : CHANNEL_NAME_PREFIX; - SNPRINTF(channelName, SIZEOF(channelName), CHANNEL_NAME_TEMPLATE, channelNamePrefix, RUNNER_LABEL); + + if (USE_IOT) { + DLOGI("Here"); + PCHAR pChannelName; + CHK_ERR((pChannelName = GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set since USE_IOT is enabled"); + STRNCPY(channelName, pChannelName, SIZEOF(channelName)); + } else { + channelNamePrefix = argc > 1 ? argv[1] : CHANNEL_NAME_PREFIX; + SNPRINTF(channelName, SIZEOF(channelName), CHANNEL_NAME_TEMPLATE, channelNamePrefix, RUNNER_LABEL); + } + DLOGI("Here: %s", channelName); CHK_STATUS(createSampleConfiguration(channelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration)); - CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, IOT_CORE_ENABLE_CREDENTIALS)); + CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, USE_IOT)); pSampleConfiguration->forceTurn = FORCE_TURN_ONLY; pSampleConfiguration->enableMetrics = ENABLE_METRICS; diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 38e9c376c8..4d8e49571a 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -568,6 +568,7 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE pSampleConfiguration->receiveAudioVideoSource = NULL; pSampleConfiguration->channelInfo.version = CHANNEL_INFO_CURRENT_VERSION; + DLOGI("Channel name: %s", channelName); pSampleConfiguration->channelInfo.pChannelName = channelName; pSampleConfiguration->channelInfo.pKmsKeyId = NULL; From 16c0a4cec17a3aa9041daca84a786e0edf6c84a1 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Wed, 5 Jun 2024 15:41:23 -0700 Subject: [PATCH 29/64] Fix for viewer too --- .../kvsWebRTCClientViewerCloudwatch.cpp | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index d31fb0ccc6..db29c08a95 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -155,10 +155,15 @@ INT32 main(INT32 argc, CHAR* argv[]) #ifndef _WIN32 signal(SIGINT, sigintHandler); #endif - - channelNamePrefix = argc > 1 ? argv[1] : CHANNEL_NAME_PREFIX; - SNPRINTF(channelName, SIZEOF(channelName), CHANNEL_NAME_TEMPLATE, channelNamePrefix, RUNNER_LABEL); - + if (USE_IOT) { + DLOGI("Here"); + PCHAR pChannelName; + CHK_ERR((pChannelName = GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set since USE_IOT is enabled"); + STRNCPY(channelName, pChannelName, SIZEOF(channelName)); + } else { + channelNamePrefix = argc > 1 ? argv[1] : CHANNEL_NAME_PREFIX; + SNPRINTF(channelName, SIZEOF(channelName), CHANNEL_NAME_TEMPLATE, channelNamePrefix, RUNNER_LABEL); + } CHK_STATUS(createSampleConfiguration(channelName, SIGNALING_CHANNEL_ROLE_TYPE_VIEWER, USE_TRICKLE_ICE, USE_TURN, logLevel, &pSampleConfiguration)); CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, USE_IOT)); pSampleConfiguration->mediaType = SAMPLE_STREAMING_AUDIO_VIDEO; From f1f5728b0e919db3f28942030a9fd5757914ebfb Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Wed, 5 Jun 2024 16:09:14 -0700 Subject: [PATCH 30/64] fix labels --- cloudwatch-integ/configs/lr_iot_h264_openssl.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/cloudwatch-integ/configs/lr_iot_h264_openssl.h b/cloudwatch-integ/configs/lr_iot_h264_openssl.h index 85bf37e53b..1c2daed7c8 100644 --- a/cloudwatch-integ/configs/lr_iot_h264_openssl.h +++ b/cloudwatch-integ/configs/lr_iot_h264_openssl.h @@ -3,8 +3,8 @@ #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE -#define RUNNER_LABEL (PCHAR) "WebrtcPeriodicOpenSSL" -#define SCENARIO_LABEL (PCHAR) "OpenSSLPeriodic" +#define RUNNER_LABEL (PCHAR) "WebrtcLongRunningOpenSSL" +#define SCENARIO_LABEL (PCHAR) "WebrtcLongRunning" #define USE_TURN TRUE #define ENABLE_TTFF_VIA_DC FALSE #define USE_IOT TRUE From 385e85bc6d44fe5cd308504fa87153c8c966b211 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 6 Jun 2024 15:40:28 -0700 Subject: [PATCH 31/64] Change namespace --- cloudwatch-integ/Include.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudwatch-integ/Include.h b/cloudwatch-integ/Include.h index 3d4062d863..6640bcd418 100644 --- a/cloudwatch-integ/Include.h +++ b/cloudwatch-integ/Include.h @@ -2,7 +2,7 @@ #include SAMPLE_CONFIG_HEADER -#define DEFAULT_CLOUDWATCH_NAMESPACE "KinesisVideoSDKWebRTC" +#define DEFAULT_CLOUDWATCH_NAMESPACE "KinesisVideoSDKCanary" #define DEFAULT_FPS_VALUE 25 // TODO: This value shouldn't matter. But, since we don't allow NULL value, we have to set to a value #define DEFAULT_VIEWER_PEER_ID "ConsumerViewer" From 45c65d3411d6a74567a48648486d599377d4fc3e Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 6 Jun 2024 16:03:57 -0700 Subject: [PATCH 32/64] build fix --- cloudwatch-integ/configs/lr_static_h265_openssl.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudwatch-integ/configs/lr_static_h265_openssl.h b/cloudwatch-integ/configs/lr_static_h265_openssl.h index 0135df6515..56287f3d23 100644 --- a/cloudwatch-integ/configs/lr_static_h265_openssl.h +++ b/cloudwatch-integ/configs/lr_static_h265_openssl.h @@ -11,7 +11,7 @@ #define ENABLE_STORAGE FALSE #define ENABLE_METRICS TRUE #define SAMPLE_PRE_GENERATE_CERT TRUE -#define RUN_TIME (12 * HUNDREDS_OF_NANOS_IN_A_HOUR) +#define RUN_TIME (12 * HUNDREDS_OF_NANOS_IN_AN_HOUR) #define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" #define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" #define USE_STORAGE FALSE From f2d91dff812423140b4ba6772c15c4cb448cad0c Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 6 Jun 2024 16:05:39 -0700 Subject: [PATCH 33/64] Fix defines --- cloudwatch-integ/Include.h | 2 -- cloudwatch-integ/configs/lr_iot_h264_mbedtls.h | 2 ++ cloudwatch-integ/configs/lr_iot_h264_openssl.h | 2 ++ cloudwatch-integ/configs/lr_static_h265_openssl.h | 2 ++ cloudwatch-integ/configs/p_static_h264_mbedtls.h | 2 ++ cloudwatch-integ/configs/storage_extended.h | 2 ++ cloudwatch-integ/configs/storage_periodic.h | 2 ++ cloudwatch-integ/configs/storage_single_reconnect.h | 2 ++ cloudwatch-integ/configs/storage_sub_reconnect.h | 2 ++ 9 files changed, 16 insertions(+), 2 deletions(-) diff --git a/cloudwatch-integ/Include.h b/cloudwatch-integ/Include.h index 6640bcd418..b39691ab51 100644 --- a/cloudwatch-integ/Include.h +++ b/cloudwatch-integ/Include.h @@ -34,8 +34,6 @@ #define MAX_CALL_RETRY_COUNT 10 -#define DEFAULT_BITRATE (250 * 8) -#define DEFAULT_FRAMERATE 30 #include #include diff --git a/cloudwatch-integ/configs/lr_iot_h264_mbedtls.h b/cloudwatch-integ/configs/lr_iot_h264_mbedtls.h index e880eed590..c12ec9d4bd 100644 --- a/cloudwatch-integ/configs/lr_iot_h264_mbedtls.h +++ b/cloudwatch-integ/configs/lr_iot_h264_mbedtls.h @@ -23,6 +23,8 @@ extern "C" { #define USE_STORAGE FALSE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#define DEFAULT_BITRATE (250 * 1024) +#define DEFAULT_FRAMERATE 30 #ifdef __cplusplus } diff --git a/cloudwatch-integ/configs/lr_iot_h264_openssl.h b/cloudwatch-integ/configs/lr_iot_h264_openssl.h index 1c2daed7c8..1bb652cfa7 100644 --- a/cloudwatch-integ/configs/lr_iot_h264_openssl.h +++ b/cloudwatch-integ/configs/lr_iot_h264_openssl.h @@ -17,4 +17,6 @@ #define USE_STORAGE FALSE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#define DEFAULT_BITRATE (250 * 1024) +#define DEFAULT_FRAMERATE 30 #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/lr_static_h265_openssl.h b/cloudwatch-integ/configs/lr_static_h265_openssl.h index 56287f3d23..9ed9860298 100644 --- a/cloudwatch-integ/configs/lr_static_h265_openssl.h +++ b/cloudwatch-integ/configs/lr_static_h265_openssl.h @@ -17,4 +17,6 @@ #define USE_STORAGE FALSE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H265 +#define DEFAULT_BITRATE (250 * 1024) +#define DEFAULT_FRAMERATE 30 #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/p_static_h264_mbedtls.h b/cloudwatch-integ/configs/p_static_h264_mbedtls.h index c2f74c2304..a48e6ad570 100644 --- a/cloudwatch-integ/configs/p_static_h264_mbedtls.h +++ b/cloudwatch-integ/configs/p_static_h264_mbedtls.h @@ -17,4 +17,6 @@ #define USE_STORAGE FALSE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#define DEFAULT_BITRATE (250 * 1024) +#define DEFAULT_FRAMERATE 30 #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/storage_extended.h b/cloudwatch-integ/configs/storage_extended.h index b6de502160..681b92c5d1 100644 --- a/cloudwatch-integ/configs/storage_extended.h +++ b/cloudwatch-integ/configs/storage_extended.h @@ -17,4 +17,6 @@ #define USE_STORAGE TRUE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#define DEFAULT_BITRATE (250 * 1024) +#define DEFAULT_FRAMERATE 30 #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/storage_periodic.h b/cloudwatch-integ/configs/storage_periodic.h index 7aa206f840..359725f1fb 100644 --- a/cloudwatch-integ/configs/storage_periodic.h +++ b/cloudwatch-integ/configs/storage_periodic.h @@ -17,4 +17,6 @@ #define USE_STORAGE TRUE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#define DEFAULT_BITRATE (250 * 1024) +#define DEFAULT_FRAMERATE 30 #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/storage_single_reconnect.h b/cloudwatch-integ/configs/storage_single_reconnect.h index 456e6aca1a..993d88f19d 100644 --- a/cloudwatch-integ/configs/storage_single_reconnect.h +++ b/cloudwatch-integ/configs/storage_single_reconnect.h @@ -17,4 +17,6 @@ #define USE_STORAGE TRUE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#define DEFAULT_BITRATE (250 * 1024) +#define DEFAULT_FRAMERATE 30 #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/storage_sub_reconnect.h b/cloudwatch-integ/configs/storage_sub_reconnect.h index 43b105804c..690672f912 100644 --- a/cloudwatch-integ/configs/storage_sub_reconnect.h +++ b/cloudwatch-integ/configs/storage_sub_reconnect.h @@ -17,4 +17,6 @@ #define USE_STORAGE TRUE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#define DEFAULT_BITRATE (250 * 1024) +#define DEFAULT_FRAMERATE 30 #endif // KVS_SDK_SAMPLE_CONFIG_H From 41d817113f45cdfb945da9255845c49bb9c84088 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 7 Jun 2024 10:24:26 -0700 Subject: [PATCH 34/64] fix segfault iot --- cloudwatch-integ/CloudwatchMonitoring.cpp | 11 ----------- cloudwatch-integ/CloudwatchMonitoring.h | 1 - samples/lib/Common.c | 2 +- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/cloudwatch-integ/CloudwatchMonitoring.cpp b/cloudwatch-integ/CloudwatchMonitoring.cpp index cf89472f9e..c78bab29da 100644 --- a/cloudwatch-integ/CloudwatchMonitoring.cpp +++ b/cloudwatch-integ/CloudwatchMonitoring.cpp @@ -224,17 +224,6 @@ VOID CloudwatchMonitoring::pushSignalingInitDelay(UINT64 delay, Aws::CloudWatch: this->push(datum); } -VOID CloudwatchMonitoring::pushICEHolePunchingDelay(UINT64 delay, Aws::CloudWatch::Model::StandardUnit unit) -{ - MetricDatum datum; - - datum.SetMetricName("ICEHolePunchingDelay"); - datum.SetValue(delay); - datum.SetUnit(unit); - - this->push(datum); -} - VOID CloudwatchMonitoring::pushOutboundRtpStats(POutgoingRTPStatsCtx pOutboundRtpStats) { MetricDatum bytesDiscardedPercentageDatum, averageFramesRateDatum, nackRateDatum, retransmissionPercentDatum; diff --git a/cloudwatch-integ/CloudwatchMonitoring.h b/cloudwatch-integ/CloudwatchMonitoring.h index afebd63889..b7df51bd00 100644 --- a/cloudwatch-integ/CloudwatchMonitoring.h +++ b/cloudwatch-integ/CloudwatchMonitoring.h @@ -15,7 +15,6 @@ class CloudwatchMonitoring { VOID pushTimeToFirstFrame(UINT64, Aws::CloudWatch::Model::StandardUnit); VOID pushSignalingRoundtripLatency(UINT64, Aws::CloudWatch::Model::StandardUnit); VOID pushSignalingConnectionDuration(UINT64, Aws::CloudWatch::Model::StandardUnit); - VOID pushICEHolePunchingDelay(UINT64, Aws::CloudWatch::Model::StandardUnit); VOID pushOutboundRtpStats(POutgoingRTPStatsCtx); VOID pushInboundRtpStats(PIncomingRTPStatsCtx); VOID pushPeerConnectionMetrics(PPeerConnectionMetrics); diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 4d8e49571a..835723b6ff 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -846,7 +846,7 @@ STATUS freeSampleConfiguration(PSampleConfiguration* ppSampleConfiguration) CVAR_FREE(pSampleConfiguration->cvar); } - if (IOT_CORE_ENABLE_CREDENTIALS) { + if (pSampleConfiguration->useIot) { freeIotCredentialProvider(&pSampleConfiguration->pCredentialProvider); } else { freeStaticCredentialProvider(&pSampleConfiguration->pCredentialProvider); From 302d6a22210c34e0b423c005ca4c37983aae195f Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 7 Jun 2024 11:52:20 -0700 Subject: [PATCH 35/64] error checks, move to C threads to be consistent --- cloudwatch-integ/CloudwatchMonitoring.cpp | 14 ++++++++++++++ .../kvsWebRTCClientMasterCloudwatch.cpp | 18 +++++++++++------- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/cloudwatch-integ/CloudwatchMonitoring.cpp b/cloudwatch-integ/CloudwatchMonitoring.cpp index c78bab29da..d0677b6eb9 100644 --- a/cloudwatch-integ/CloudwatchMonitoring.cpp +++ b/cloudwatch-integ/CloudwatchMonitoring.cpp @@ -253,6 +253,10 @@ VOID CloudwatchMonitoring::pushPeerConnectionMetrics(PPeerConnectionMetrics pPee { MetricDatum pcCreationDatum, dtlsSetupDatum, iceHolePunchingDatum; + if(pPeerConnectionMetrics == NULL) { + DLOGE("Peer connection metrics object is NULL. Cannot go further"); + return; + } pcCreationDatum.SetMetricName("PcCreationTime"); pcCreationDatum.SetValue(pPeerConnectionMetrics->peerConnectionStats.peerConnectionCreationTime); pcCreationDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); @@ -275,6 +279,11 @@ VOID CloudwatchMonitoring::pushKvsIceAgentMetrics(PKvsIceAgentMetrics pKvsIceAge iceAgentSetupDatum, relayCandidateSetUpDatum, iceServerParseDatum, iceCandidatePairNominationDatum, iceCandidateGatheringDatum; + if(pKvsIceAgentMetrics == NULL) { + DLOGE("ICE agent metrics object is NULL. Cannot go further"); + return; + } + localCandidateGatheringDatum.SetMetricName("LocalCandidateGatheringTime"); localCandidateGatheringDatum.SetValue(pKvsIceAgentMetrics->kvsIceAgentStats.localCandidateGatheringTime); localCandidateGatheringDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); @@ -323,6 +332,11 @@ VOID CloudwatchMonitoring::pushSignalingClientMetrics(PSignalingClientMetrics pS UINT64 joinSessionToOffer, joinSessionCallTime; + if(pSignalingClientMetrics == NULL) { + DLOGE("Signaling metrics object is NULL. Cannot go further"); + return; + } + offerToAnswerDatum.SetMetricName("OfferToAnswerTime"); offerToAnswerDatum.SetValue(pSignalingClientMetrics->signalingClientStats.offerToAnswerTime); offerToAnswerDatum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Milliseconds); diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 38e118e7c0..88212e128b 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -50,13 +50,13 @@ STATUS publishStatsForCanary(RTC_STATS_TYPE statsType, PSampleStreamingSession p return retStatus; } -VOID sendProfilingMetrics(PSampleConfiguration pSampleConfiguration) +PVOID sendProfilingMetrics(PVOID customData) { STATUS retStatus = STATUS_SUCCESS; PSampleStreamingSession pSampleStreamingSession = NULL; - + PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; if(pSampleConfiguration == NULL) { - return; + return NULL; } while((pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]) == NULL) { @@ -69,12 +69,15 @@ VOID sendProfilingMetrics(PSampleConfiguration pSampleConfiguration) CppInteg::Cloudwatch::getInstance().monitoring.pushSignalingClientMetrics(&pSampleConfiguration->signalingClientMetrics); CppInteg::Cloudwatch::getInstance().monitoring.pushPeerConnectionMetrics(&pSampleStreamingSession->pStatsCtx->peerConnectionMetrics); CppInteg::Cloudwatch::getInstance().monitoring.pushKvsIceAgentMetrics(&pSampleStreamingSession->pStatsCtx->iceMetrics); - return; - } else { + return NULL; + } else if(retStatus == STATUS_WAITING_ON_FIRST_FRAME) { DLOGI("Waiting on streaming to start 0x%08x", retStatus); + } else { + DLOGE("Failed to get profiling stats. (0x%08x)", retStatus); } THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_MILLISECOND * 100); } + return NULL; } VOID addMetadataToFrameData(PBYTE buffer, PFrame pFrame) @@ -340,6 +343,7 @@ INT32 main(INT32 argc, CHAR* argv[]) Aws::SDKOptions options; options.httpOptions.installSigPipeHandler = TRUE; CHAR tsFileName[MAX_PATH_LEN + 1]; + TID profilingThread; Aws::InitAPI(options); { SET_INSTRUMENTED_ALLOCATORS(); @@ -397,7 +401,7 @@ INT32 main(INT32 argc, CHAR* argv[]) DLOGI("[KVS Master] Channel %s set up done ", channelName); - std::thread pushProfilingThread(sendProfilingMetrics, pSampleConfiguration); + THREAD_CREATE(&profilingThread, sendProfilingMetrics, (PVOID) pSampleConfiguration); CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, (UINT64) pSampleConfiguration, &terminateId)); @@ -405,7 +409,7 @@ INT32 main(INT32 argc, CHAR* argv[]) // Checking for termination CHK_STATUS(sessionCleanupWait(pSampleConfiguration)); DLOGI("[KVS Master] Streaming session terminated"); - pushProfilingThread.join(); + THREAD_JOIN(profilingThread, NULL); } CleanUp: From e151c22bdb10ef2e7a76f63a16931c96461f7e6f Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 7 Jun 2024 12:26:36 -0700 Subject: [PATCH 36/64] More debugging --- cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp | 8 ++++++-- samples/lib/MetricsHandling.c | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 88212e128b..dcb547d452 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -67,8 +67,12 @@ PVOID sendProfilingMetrics(PVOID customData) if(STATUS_SUCCEEDED(retStatus)) { CppInteg::Cloudwatch::getInstance().monitoring.pushSignalingClientMetrics(&pSampleConfiguration->signalingClientMetrics); - CppInteg::Cloudwatch::getInstance().monitoring.pushPeerConnectionMetrics(&pSampleStreamingSession->pStatsCtx->peerConnectionMetrics); - CppInteg::Cloudwatch::getInstance().monitoring.pushKvsIceAgentMetrics(&pSampleStreamingSession->pStatsCtx->iceMetrics); + if(pSampleStreamingSession->pStatsCtx != NULL) { + CppInteg::Cloudwatch::getInstance().monitoring.pushPeerConnectionMetrics(&pSampleStreamingSession->pStatsCtx->peerConnectionMetrics); + CppInteg::Cloudwatch::getInstance().monitoring.pushKvsIceAgentMetrics(&pSampleStreamingSession->pStatsCtx->iceMetrics); + } else { + DLOGE("StatsCtx uninitialized. If metrics is enabled, this should not happen"); + } return NULL; } else if(retStatus == STATUS_WAITING_ON_FIRST_FRAME) { DLOGI("Waiting on streaming to start 0x%08x", retStatus); diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index 7a878a9447..835f84be37 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -7,7 +7,7 @@ STATUS setupMetricsCtx(PSampleStreamingSession pSampleStreamingSession) DLOGI("NUll"); } if (pSampleStreamingSession->pSampleConfiguration == NULL) { - DLOGI("bykkbedk"); + DLOGI("Null config"); } CHK(pSampleStreamingSession != NULL && pSampleStreamingSession->pSampleConfiguration != NULL, STATUS_NULL_ARG); if (pSampleStreamingSession->pSampleConfiguration->enableMetrics) { @@ -265,6 +265,7 @@ STATUS getSdkTimeProfile(PSampleStreamingSession pSampleStreamingSession) CHK_STATUS(signalingClientGetMetrics(pSampleStreamingSession->pSampleConfiguration->signalingClientHandle, &pSampleStreamingSession->pSampleConfiguration->signalingClientMetrics)); CHK_STATUS(peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->pStatsCtx->peerConnectionMetrics)); + DLOGI("Stats here: %d, %d, %d, %d", pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.dtlsSessionSetupTime, pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.peerConnectionCreationTime, pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.stunDnsResolutionTime, pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.iceHolePunchingTime); CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->pStatsCtx->iceMetrics)); CleanUp: return retStatus; From 1661c1fcb10934b44e0f8a8334bfff61d2434448 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 7 Jun 2024 12:57:42 -0700 Subject: [PATCH 37/64] Double pointer --- cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp | 8 ++++---- samples/Samples.h | 2 +- samples/lib/MetricsHandling.c | 3 ++- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index dcb547d452..bdcb844870 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -53,21 +53,21 @@ STATUS publishStatsForCanary(RTC_STATS_TYPE statsType, PSampleStreamingSession p PVOID sendProfilingMetrics(PVOID customData) { STATUS retStatus = STATUS_SUCCESS; - PSampleStreamingSession pSampleStreamingSession = NULL; PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; if(pSampleConfiguration == NULL) { return NULL; } - while((pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]) == NULL) { + while((pSampleConfiguration->sampleStreamingSessionList[0]) == NULL) { THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_MILLISECOND * 100); } while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted)) { - retStatus = getSdkTimeProfile(pSampleConfiguration->sampleStreamingSessionList[0]); + PSampleStreamingSession pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; + retStatus = getSdkTimeProfile(&pSampleStreamingSession); if(STATUS_SUCCEEDED(retStatus)) { CppInteg::Cloudwatch::getInstance().monitoring.pushSignalingClientMetrics(&pSampleConfiguration->signalingClientMetrics); - if(pSampleStreamingSession->pStatsCtx != NULL) { + if(pSampleConfiguration->sampleStreamingSessionList[0]->pStatsCtx != NULL) { CppInteg::Cloudwatch::getInstance().monitoring.pushPeerConnectionMetrics(&pSampleStreamingSession->pStatsCtx->peerConnectionMetrics); CppInteg::Cloudwatch::getInstance().monitoring.pushKvsIceAgentMetrics(&pSampleStreamingSession->pStatsCtx->iceMetrics); } else { diff --git a/samples/Samples.h b/samples/Samples.h index 2ec59bd7a6..305ed3fe26 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -355,7 +355,7 @@ STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession); VOID onIceCandidateHandler(UINT64, PCHAR); PVOID mediaSenderRoutine(PVOID); STATUS setupMetricsCtx(PSampleStreamingSession); -STATUS getSdkTimeProfile(PSampleStreamingSession); +STATUS getSdkTimeProfile(PSampleStreamingSession*); STATUS terminate(UINT32 timerId, UINT64 currentTime, UINT64 customData); STATUS setUpCredentialProvider(PSampleConfiguration pSampleConfiguration, BOOL useIot); #ifdef __cplusplus diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index 835f84be37..af5bbef463 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -255,9 +255,10 @@ STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamin return retStatus; } -STATUS getSdkTimeProfile(PSampleStreamingSession pSampleStreamingSession) +STATUS getSdkTimeProfile(PSampleStreamingSession* ppSampleStreamingSession) { STATUS retStatus = STATUS_SUCCESS; + PSampleStreamingSession pSampleStreamingSession = *ppSampleStreamingSession; CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up. Nothing to report"); CHK(!pSampleStreamingSession->firstFrame, STATUS_WAITING_ON_FIRST_FRAME); From 148bbd55b98683eec8ea77fa90aa8320e7e268f6 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Mon, 10 Jun 2024 16:22:26 -0700 Subject: [PATCH 38/64] timers fix --- cloudwatch-integ/Include.h | 4 +- .../kvsWebRTCClientMasterCloudwatch.cpp | 78 +++++++++---------- samples/Samples.h | 4 +- samples/lib/Common.c | 5 +- samples/lib/DataChannelHandling.c | 12 +-- samples/lib/MetricsHandling.c | 5 +- 6 files changed, 53 insertions(+), 55 deletions(-) diff --git a/cloudwatch-integ/Include.h b/cloudwatch-integ/Include.h index b39691ab51..fcaf5860bb 100644 --- a/cloudwatch-integ/Include.h +++ b/cloudwatch-integ/Include.h @@ -20,8 +20,6 @@ #define FRAME_METADATA_SIZE (SIZEOF(UINT64) + SIZEOF(UINT32) + SIZEOF(UINT32)) #define ANNEX_B_NALU_SIZE 4 -#define END_TO_END_METRICS_INVOCATION_PERIOD (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) - #define STORAGE_CANARY_FIRST_FRAME_TS_FILE_ENV_VAR "STORAGE_CANARY_FIRST_FRAME_TS_FILE" #define FIRST_FRAME_TS_FILE_PATH (PCHAR) "/tmp/" @@ -33,6 +31,8 @@ #define AGGREGATE_CW_DIMENSION "WebRTCSDKCanaryLabel" #define MAX_CALL_RETRY_COUNT 10 +#define OUTBOUND_RTP_STATS_TIMER_INTERVAL (60 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define END_TO_END_METRICS_INVOCATION_PERIOD (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) #include diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index bdcb844870..74ae8eb040 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -28,26 +28,19 @@ VOID calculateDisconnectToFrameSentTime(PSampleConfiguration pSampleConfiguratio } } -STATUS publishStatsForCanary(RTC_STATS_TYPE statsType, PSampleStreamingSession pSampleStreamingSession) -{ +STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customData) { STATUS retStatus = STATUS_SUCCESS; - pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = statsType; - switch (statsType) { - case RTC_STATS_TYPE_OUTBOUND_RTP: - CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); - populateOutgoingRtpMetricsContext(pSampleStreamingSession); - CppInteg::Cloudwatch::getInstance().monitoring.pushOutboundRtpStats(&pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx); - break; - case RTC_STATS_TYPE_INBOUND_RTP: - CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); - populateIncomingRtpMetricsContext(pSampleStreamingSession); - CppInteg::Cloudwatch::getInstance().monitoring.pushInboundRtpStats(&pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx); - break; - default: - CHK(FALSE, STATUS_NOT_IMPLEMENTED); + PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; + + CHK_WARN(pSampleStreamingSession != NULL && pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats ctx object not set up"); + pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = RTC_STATS_TYPE_OUTBOUND_RTP; + if (!ATOMIC_LOAD_BOOL(&pSampleStreamingSession->pSampleConfiguration->appTerminateFlag)) { + CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); + CHK_STATUS(populateOutgoingRtpMetricsContext(pSampleStreamingSession)); + CppInteg::Cloudwatch::getInstance().monitoring.pushOutboundRtpStats(&pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx); } - CleanUp: - return retStatus; +CleanUp: + return STATUS_SUCCESS; } PVOID sendProfilingMetrics(PVOID customData) @@ -68,8 +61,8 @@ PVOID sendProfilingMetrics(PVOID customData) if(STATUS_SUCCEEDED(retStatus)) { CppInteg::Cloudwatch::getInstance().monitoring.pushSignalingClientMetrics(&pSampleConfiguration->signalingClientMetrics); if(pSampleConfiguration->sampleStreamingSessionList[0]->pStatsCtx != NULL) { - CppInteg::Cloudwatch::getInstance().monitoring.pushPeerConnectionMetrics(&pSampleStreamingSession->pStatsCtx->peerConnectionMetrics); - CppInteg::Cloudwatch::getInstance().monitoring.pushKvsIceAgentMetrics(&pSampleStreamingSession->pStatsCtx->iceMetrics); + CppInteg::Cloudwatch::getInstance().monitoring.pushPeerConnectionMetrics(&pSampleStreamingSession->peerConnectionMetrics); + CppInteg::Cloudwatch::getInstance().monitoring.pushKvsIceAgentMetrics(&pSampleStreamingSession->iceMetrics); } else { DLOGE("StatsCtx uninitialized. If metrics is enabled, this should not happen"); } @@ -119,7 +112,7 @@ PVOID sendMockVideoPackets(PVOID args) PBYTE frameData = NULL; UINT64 firstFrameTime = 0; PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) args; - + UINT32 outboundStatsTimerId = MAX_UINT32; frameData = (PBYTE) MEMALLOC(maxFrameSize); // We allocate a bigger buffer to accomodate the hex encoded string @@ -127,6 +120,13 @@ PVOID sendMockVideoPackets(PVOID args) frame.version = FRAME_CURRENT_VERSION; frame.presentationTs = GETTIME(); + if(pSampleConfiguration->enableMetrics) { + CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, OUTBOUND_RTP_STATS_TIMER_INTERVAL, + OUTBOUND_RTP_STATS_TIMER_INTERVAL, + publishStatsForCanary, + (UINT64) pSampleConfiguration->sampleStreamingSessionList[0], + &outboundStatsTimerId)); + } while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { // This is the actual frame size that includes the metadata and the actual frame data @@ -158,8 +158,11 @@ PVOID sendMockVideoPackets(PVOID args) MUTEX_LOCK(pSampleConfiguration->streamingSessionListReadLock); for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { status = writeFrame(pSampleConfiguration->sampleStreamingSessionList[i]->pVideoRtcRtpTransceiver, &frame); - pSampleConfiguration->sampleStreamingSessionList[i]->pStatsCtx->outgoingRTPStatsCtx.videoFramesGenerated++; - pSampleConfiguration->sampleStreamingSessionList[i]->pStatsCtx->outgoingRTPStatsCtx.videoBytesGenerated += frame.size; + if(pSampleConfiguration->enableMetrics) { + pSampleConfiguration->sampleStreamingSessionList[i]->pStatsCtx->outgoingRTPStatsCtx.videoFramesGenerated++; + pSampleConfiguration->sampleStreamingSessionList[i]->pStatsCtx->outgoingRTPStatsCtx.videoBytesGenerated += frame.size; + } + if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { PROFILE_WITH_START_TIME_OBJ(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, firstFrameTime, "Time to first frame"); CppInteg::Cloudwatch::getInstance().monitoring.pushTimeToFirstFrame(firstFrameTime, Aws::CloudWatch::Model::StandardUnit::Milliseconds); @@ -171,7 +174,6 @@ PVOID sendMockVideoPackets(PVOID args) DLOGV("writeFrame() failed with 0x%08x", status); } } - CHK_STATUS(publishStatsForCanary(RTC_STATS_TYPE_OUTBOUND_RTP, pSampleConfiguration->sampleStreamingSessionList[i])); } MUTEX_UNLOCK(pSampleConfiguration->streamingSessionListReadLock); THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_SECOND / DEFAULT_FRAME_RATE); @@ -196,12 +198,18 @@ PVOID sendRealVideoPackets(PVOID args) UINT64 startTime, lastFrameTime, elapsed; CHAR tsFileName[MAX_PATH_LEN + 1]; UINT64 firstFrameTime = 0; + UINT32 outboundStatsTimerId = MAX_UINT32; CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); frame.presentationTs = 0; startTime = GETTIME(); lastFrameTime = startTime; + if(pSampleConfiguration->enableMetrics) { + CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, OUTBOUND_RTP_STATS_TIMER_INTERVAL, OUTBOUND_RTP_STATS_TIMER_INTERVAL, + publishStatsForCanary, (UINT64) pSampleConfiguration->sampleStreamingSessionList[0], &outboundStatsTimerId)); + + } while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { fileIndex = fileIndex % NUMBER_OF_H264_FRAME_FILES + 1; if (pSampleConfiguration->videoCodec == RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE) { @@ -229,6 +237,10 @@ PVOID sendRealVideoPackets(PVOID args) MUTEX_LOCK(pSampleConfiguration->streamingSessionListReadLock); for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { status = writeFrame(pSampleConfiguration->sampleStreamingSessionList[i]->pVideoRtcRtpTransceiver, &frame); + if(pSampleConfiguration->enableMetrics) { + pSampleConfiguration->sampleStreamingSessionList[i]->pStatsCtx->outgoingRTPStatsCtx.videoFramesGenerated++; + pSampleConfiguration->sampleStreamingSessionList[i]->pStatsCtx->outgoingRTPStatsCtx.videoBytesGenerated += frame.size; + } if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { SNPRINTF(tsFileName, SIZEOF(tsFileName), "%s%s", FIRST_FRAME_TS_FILE_PATH, STORAGE_DEFAULT_FIRST_FRAME_TS_FILE); CHK_STATUS(writeFirstFrameSentTimeToFile(tsFileName)); @@ -341,7 +353,7 @@ INT32 main(INT32 argc, CHAR* argv[]) UINT32 frameSize; PSampleConfiguration pSampleConfiguration = NULL; PCHAR region; - UINT32 terminateId = MAX_UINT32; + UINT32 terminateTimerId = MAX_UINT32; CHAR channelName[MAX_CHANNEL_NAME_LEN]; PCHAR channelNamePrefix; Aws::SDKOptions options; @@ -408,8 +420,7 @@ INT32 main(INT32 argc, CHAR* argv[]) THREAD_CREATE(&profilingThread, sendProfilingMetrics, (PVOID) pSampleConfiguration); CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, - (UINT64) pSampleConfiguration, &terminateId)); - + (UINT64) pSampleConfiguration, &terminateTimerId)); // Checking for termination CHK_STATUS(sessionCleanupWait(pSampleConfiguration)); DLOGI("[KVS Master] Streaming session terminated"); @@ -458,16 +469,3 @@ INT32 main(INT32 argc, CHAR* argv[]) // EXIT_FAILURE and EXIT_SUCCESS macros for portability. return STATUS_FAILED(retStatus) ? EXIT_FAILURE : EXIT_SUCCESS; } - -PVOID sampleReceiveAudioVideoFrame(PVOID args) -{ - STATUS retStatus = STATUS_SUCCESS; - PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) args; - CHK_ERR(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); - CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pVideoRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleVideoFrameHandler)); - CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pAudioRtcRtpTransceiver, (UINT64) pSampleStreamingSession, sampleAudioFrameHandler)); - - CleanUp: - - return (PVOID) (ULONG_PTR) retStatus; -} diff --git a/samples/Samples.h b/samples/Samples.h index 305ed3fe26..d1df35a99c 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -257,8 +257,6 @@ typedef struct { OutgoingRTPStatsCtx outgoingRTPStatsCtx; IncomingRTPStatsCtx incomingRTPStatsCtx; EndToEndMetricsCtx endToEndMetricsCtx; - PeerConnectionMetrics peerConnectionMetrics; - KvsIceAgentMetrics iceMetrics; RtcStats kvsRtcStats; MUTEX statsUpdateLock; } StatsCtx, *PStatsCtx; @@ -291,6 +289,8 @@ struct __SampleStreamingSession { CHAR pPeerConnectionMetricsMessage[MAX_PEER_CONNECTION_METRICS_MESSAGE_SIZE]; CHAR pSignalingClientMetricsMessage[MAX_SIGNALING_CLIENT_METRICS_MESSAGE_SIZE]; CHAR pIceAgentMetricsMessage[MAX_ICE_AGENT_METRICS_MESSAGE_SIZE]; + PeerConnectionMetrics peerConnectionMetrics; + KvsIceAgentMetrics iceMetrics; PStatsCtx pStatsCtx; }; diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 835723b6ff..73f010595e 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -290,13 +290,14 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P if (pSampleConfiguration->enableMetrics) { CHK_STATUS(setupMetricsCtx(pSampleStreamingSession)); - pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime = - GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; } // Flag to enable SDK to calculate selected ice server, local, remote and candidate pair stats. pSampleConfiguration->enableIceStats = FALSE; + pSampleStreamingSession->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime = + GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + CHK_STATUS(initializePeerConnection(pSampleConfiguration, &pSampleStreamingSession->pPeerConnection)); CHK_STATUS(peerConnectionOnIceCandidate(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, onIceCandidateHandler)); CHK_STATUS( diff --git a/samples/lib/DataChannelHandling.c b/samples/lib/DataChannelHandling.c index d4ecdcfedc..e366b6fdae 100644 --- a/samples/lib/DataChannelHandling.c +++ b/samples/lib/DataChannelHandling.c @@ -129,17 +129,17 @@ VOID onDataChannelMessage(UINT64 customData, PRtcDataChannel pDataChannel, BOOL DLOGI("Sending signaling metrics to the viewer: %s", pSampleStreamingSession->pSignalingClientMetricsMessage); CHK_STATUS( - peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->pStatsCtx->peerConnectionMetrics)); + peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->peerConnectionMetrics)); SNPRINTF(pSampleStreamingSession->pPeerConnectionMetricsMessage, MAX_PEER_CONNECTION_METRICS_MESSAGE_SIZE, PEER_CONNECTION_METRICS_JSON_TEMPLATE, - pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime, - pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.peerConnectionConnectedTime); + 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->pStatsCtx->iceMetrics)); + CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->iceMetrics)); SNPRINTF(pSampleStreamingSession->pIceAgentMetricsMessage, MAX_ICE_AGENT_METRICS_MESSAGE_SIZE, ICE_AGENT_METRICS_JSON_TEMPLATE, - pSampleStreamingSession->pStatsCtx->iceMetrics.kvsIceAgentStats.candidateGatheringStartTime, - pSampleStreamingSession->pStatsCtx->iceMetrics.kvsIceAgentStats.candidateGatheringEndTime); + 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, diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index af5bbef463..198fcded34 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -265,9 +265,8 @@ STATUS getSdkTimeProfile(PSampleStreamingSession* ppSampleStreamingSession) pSampleStreamingSession->pSampleConfiguration->signalingClientMetrics.version = SIGNALING_CLIENT_METRICS_CURRENT_VERSION; CHK_STATUS(signalingClientGetMetrics(pSampleStreamingSession->pSampleConfiguration->signalingClientHandle, &pSampleStreamingSession->pSampleConfiguration->signalingClientMetrics)); - CHK_STATUS(peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->pStatsCtx->peerConnectionMetrics)); - DLOGI("Stats here: %d, %d, %d, %d", pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.dtlsSessionSetupTime, pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.peerConnectionCreationTime, pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.stunDnsResolutionTime, pSampleStreamingSession->pStatsCtx->peerConnectionMetrics.peerConnectionStats.iceHolePunchingTime); - CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->pStatsCtx->iceMetrics)); + CHK_STATUS(peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->peerConnectionMetrics)); + CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->iceMetrics)); CleanUp: return retStatus; } From d210b91557899965928ab341fe675cb83f69a4e3 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Mon, 10 Jun 2024 17:17:25 -0700 Subject: [PATCH 39/64] mini refactor --- .../kvsWebRTCClientViewerCloudwatch.cpp | 22 +++++-------------- 1 file changed, 5 insertions(+), 17 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index db29c08a95..778ca7a641 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -36,23 +36,11 @@ VOID dataChannelOnOpenCallback(UINT64 customData, PRtcDataChannel pDataChannel) STATUS publishStatsForCanary(RTC_STATS_TYPE statsType, PSampleStreamingSession pSampleStreamingSession) { STATUS retStatus = STATUS_SUCCESS; - pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = statsType; - switch (statsType) { - case RTC_STATS_TYPE_OUTBOUND_RTP: - CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); - populateOutgoingRtpMetricsContext(pSampleStreamingSession); - CppInteg::Cloudwatch::getInstance().monitoring.pushOutboundRtpStats(&pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx); - break; - case RTC_STATS_TYPE_INBOUND_RTP: - DLOGI("Inbound"); - CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); - populateIncomingRtpMetricsContext(pSampleStreamingSession); - CppInteg::Cloudwatch::getInstance().monitoring.pushInboundRtpStats(&pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx); - break; - default: - CHK(FALSE, STATUS_NOT_IMPLEMENTED); - } - CleanUp: + pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = RTC_STATS_TYPE_INBOUND_RTP; + CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); + populateIncomingRtpMetricsContext(pSampleStreamingSession); + CppInteg::Cloudwatch::getInstance().monitoring.pushInboundRtpStats(&pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx); +CleanUp: return retStatus; } From cb6b765d12191b3c975e792408de6f2068472e13 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 13 Jun 2024 08:21:35 -0700 Subject: [PATCH 40/64] shutdown api viewer --- cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp | 3 +-- cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 74ae8eb040..a264b7a5e4 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -368,7 +368,6 @@ INT32 main(INT32 argc, CHAR* argv[]) CHK_STATUS(initKvsWebRtc()); if (USE_IOT) { - DLOGI("Here"); PCHAR pChannelName; CHK_ERR((pChannelName = GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set since USE_IOT is enabled"); STRNCPY(channelName, pChannelName, SIZEOF(channelName)); @@ -376,7 +375,6 @@ INT32 main(INT32 argc, CHAR* argv[]) channelNamePrefix = argc > 1 ? argv[1] : CHANNEL_NAME_PREFIX; SNPRINTF(channelName, SIZEOF(channelName), CHANNEL_NAME_TEMPLATE, channelNamePrefix, RUNNER_LABEL); } - DLOGI("Here: %s", channelName); CHK_STATUS(createSampleConfiguration(channelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration)); CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, USE_IOT)); @@ -458,6 +456,7 @@ INT32 main(INT32 argc, CHAR* argv[]) retStatus = RESET_INSTRUMENTED_ALLOCATORS(); DLOGI("All SDK allocations freed? %s..0x%08x", retStatus == STATUS_SUCCESS ? "Yes" : "No", retStatus); SNPRINTF(tsFileName, SIZEOF(tsFileName), "%s%s", FIRST_FRAME_TS_FILE_PATH, STORAGE_DEFAULT_FIRST_FRAME_TS_FILE); + FREMOVE(tsFileName); CppInteg::Cloudwatch::getInstance().monitoring.pushExitStatus(retStatus); CppInteg::Cloudwatch::deinit(); Aws::ShutdownAPI(options); diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index 778ca7a641..2d051ce471 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -291,6 +291,10 @@ INT32 main(INT32 argc, CHAR* argv[]) RESET_INSTRUMENTED_ALLOCATORS(); + CppInteg::Cloudwatch::getInstance().monitoring.pushExitStatus(retStatus); + CppInteg::Cloudwatch::deinit(); + Aws::ShutdownAPI(options); + // https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html // We can only return with 0 - 127. Some platforms treat exit code >= 128 // to be a success code, which might give an unintended behaviour. From fc318dcc00af4a4e5791cb66fdf81fb6a5db1613 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 13 Jun 2024 11:58:05 -0700 Subject: [PATCH 41/64] Change path to workspace --- CMakeLists.txt | 1 - cloudwatch-integ/Include.h | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d77c5f3541..3b9118dfd5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -255,7 +255,6 @@ if(BUILD_DEPENDENCIES) message(STATUS "Finished building dependencies.") endif() - if(AWS_SDK_INTEG) message(STATUS "Building...") set(BUILD_ARGS diff --git a/cloudwatch-integ/Include.h b/cloudwatch-integ/Include.h index fcaf5860bb..b1c0f4aa8d 100644 --- a/cloudwatch-integ/Include.h +++ b/cloudwatch-integ/Include.h @@ -22,7 +22,7 @@ #define STORAGE_CANARY_FIRST_FRAME_TS_FILE_ENV_VAR "STORAGE_CANARY_FIRST_FRAME_TS_FILE" -#define FIRST_FRAME_TS_FILE_PATH (PCHAR) "/tmp/" +#define FIRST_FRAME_TS_FILE_PATH (PCHAR) "../../" #define STORAGE_DEFAULT_FIRST_FRAME_TS_FILE (PCHAR) "DefaultFirstFrameSentTSFileName.txt" #define INDIVIDUAL_STORAGE_CW_DIMENSION "StorageWebRTCSDKCanaryChannelName" From c8ebd0423859605b9d72e9afe0280faea9b10d61 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 13 Jun 2024 15:14:37 -0700 Subject: [PATCH 42/64] Nits, misses --- CMake/Dependencies/libawscpp-CMakeLists.txt | 2 +- CMakeLists.txt | 10 ++-- cloudwatch-integ/Cloudwatch.cpp | 2 +- cloudwatch-integ/CloudwatchMonitoring.cpp | 52 ------------------- cloudwatch-integ/CloudwatchMonitoring.h | 4 -- cloudwatch-integ/Include.h | 10 ++-- .../kvsWebRTCClientMasterCloudwatch.cpp | 35 ++++++++----- .../kvsWebRTCClientViewerCloudwatch.cpp | 7 +-- samples/Samples.h | 5 +- samples/kvsWebRTCClientViewer.c | 3 +- samples/kvsWebRTCClientViewerGstSample.c | 3 +- samples/lib/Common.c | 26 ++++++---- samples/lib/MetricsHandling.c | 27 +++++----- 13 files changed, 71 insertions(+), 115 deletions(-) diff --git a/CMake/Dependencies/libawscpp-CMakeLists.txt b/CMake/Dependencies/libawscpp-CMakeLists.txt index 76c260a31a..088e34cd86 100644 --- a/CMake/Dependencies/libawscpp-CMakeLists.txt +++ b/CMake/Dependencies/libawscpp-CMakeLists.txt @@ -15,7 +15,7 @@ endif() ExternalProject_Add(libawscpp-download GIT_REPOSITORY https://github.com/aws/aws-sdk-cpp.git - GIT_TAG 1.11.143 + GIT_TAG 1.11.217 LIST_SEPARATOR "|" CMAKE_ARGS -DBUILD_SHARED_LIBS=ON -DENABLE_TESTING=OFF diff --git a/CMakeLists.txt b/CMakeLists.txt index 3b9118dfd5..6b2d53b3cd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -21,7 +21,7 @@ option(ENABLE_DATA_CHANNEL "Enable support for data channel" ON) option(ENABLE_KVS_THREADPOOL "Enable support for KVS thread pool in signaling" ON) option(INSTRUMENTED_ALLOCATORS "Enable memory instrumentation" OFF) option(ENABLE_AWS_SDK_IN_TESTS "Enable support for compiling AWS SDKs for tests" ON) -option(AWS_SDK_INTEG "Enable integration samples with cloudwatch" ON) +option(ENABLE_AWS_SDK_INTEG "Enable building samples with cloudwatch" OFF) # Developer Flags option(BUILD_TEST "Build the testing tree." OFF) @@ -255,8 +255,7 @@ if(BUILD_DEPENDENCIES) message(STATUS "Finished building dependencies.") endif() -if(AWS_SDK_INTEG) - message(STATUS "Building...") +if(ENABLE_AWS_SDK_INTEG) set(BUILD_ARGS -DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE} -DCMAKE_C_FLAGS=${CMAKE_C_FLAGS} @@ -488,8 +487,9 @@ if (BUILD_SAMPLE) add_subdirectory(samples) endif() -add_subdirectory(cloudwatch-integ) - +if(ENABLE_AWS_SDK_INTEG) + add_subdirectory(cloudwatch-integ) +endif() if(BUILD_TEST) # adding ZLIB because aws sdk static link seems to be broken when zlib is needed if(NOT WIN32) diff --git a/cloudwatch-integ/Cloudwatch.cpp b/cloudwatch-integ/Cloudwatch.cpp index 65a4fa3c60..9d02af316b 100644 --- a/cloudwatch-integ/Cloudwatch.cpp +++ b/cloudwatch-integ/Cloudwatch.cpp @@ -21,7 +21,7 @@ STATUS Cloudwatch::init(PCHAR channelName, PCHAR region, BOOL isMaster, BOOL isS auto& instance = getInstanceImpl(&clientConfig); if (STATUS_FAILED(instance.logs.init(channelName, region, isMaster, isStorage))) { - DLOGW("Failed to create Cloudwatch logger, fallback to file logger"); + DLOGW("Failed to create Cloudwatch logger"); } else { globalCustomLogPrintFn = logger; } diff --git a/cloudwatch-integ/CloudwatchMonitoring.cpp b/cloudwatch-integ/CloudwatchMonitoring.cpp index d0677b6eb9..693792c5ba 100644 --- a/cloudwatch-integ/CloudwatchMonitoring.cpp +++ b/cloudwatch-integ/CloudwatchMonitoring.cpp @@ -137,47 +137,6 @@ VOID CloudwatchMonitoring::pushExitStatus(STATUS retStatus) this->push(datum); } -VOID CloudwatchMonitoring::pushSignalingRoundtripStatus(STATUS retStatus) -{ - MetricDatum datum; - Dimension statusDimension; - CHAR status[MAX_STATUS_CODE_LENGTH]; - - statusDimension.SetName("Code"); - SPRINTF(status, "0x%08x", retStatus); - statusDimension.SetValue(status); - - datum.SetMetricName("SignalingRoundtripStatus"); - datum.SetValue(1.0); - datum.SetUnit(Aws::CloudWatch::Model::StandardUnit::Count); - - datum.AddDimensions(statusDimension); - - this->push(datum); -} - -VOID CloudwatchMonitoring::pushSignalingRoundtripLatency(UINT64 delay, Aws::CloudWatch::Model::StandardUnit unit) -{ - MetricDatum datum; - - datum.SetMetricName("SignalingRoundtripLatency"); - datum.SetValue(delay); - datum.SetUnit(unit); - - this->push(datum); -} - -VOID CloudwatchMonitoring::pushSignalingConnectionDuration(UINT64 duration, Aws::CloudWatch::Model::StandardUnit unit) -{ - MetricDatum datum; - - datum.SetMetricName("SignalingConnectionDuration"); - datum.SetValue(duration); - datum.SetUnit(unit); - - this->push(datum); -} - VOID CloudwatchMonitoring::pushTimeToFirstFrame(UINT64 timeToFirstFrame, Aws::CloudWatch::Model::StandardUnit unit) { MetricDatum datum; @@ -213,17 +172,6 @@ VOID CloudwatchMonitoring::pushJoinSessionTime(UINT64 joinSessionTime, Aws::Clou this->push(datum); } -VOID CloudwatchMonitoring::pushSignalingInitDelay(UINT64 delay, Aws::CloudWatch::Model::StandardUnit unit) -{ - MetricDatum datum; - - datum.SetMetricName("SignalingInitDelay"); - datum.SetValue(delay); - datum.SetUnit(unit); - - this->push(datum); -} - VOID CloudwatchMonitoring::pushOutboundRtpStats(POutgoingRTPStatsCtx pOutboundRtpStats) { MetricDatum bytesDiscardedPercentageDatum, averageFramesRateDatum, nackRateDatum, retransmissionPercentDatum; diff --git a/cloudwatch-integ/CloudwatchMonitoring.h b/cloudwatch-integ/CloudwatchMonitoring.h index b7df51bd00..ac8ffcf22a 100644 --- a/cloudwatch-integ/CloudwatchMonitoring.h +++ b/cloudwatch-integ/CloudwatchMonitoring.h @@ -10,11 +10,7 @@ class CloudwatchMonitoring { VOID deinit(); VOID push(const MetricDatum&); VOID pushExitStatus(STATUS); - VOID pushSignalingRoundtripStatus(STATUS); - VOID pushSignalingInitDelay(UINT64, Aws::CloudWatch::Model::StandardUnit); VOID pushTimeToFirstFrame(UINT64, Aws::CloudWatch::Model::StandardUnit); - VOID pushSignalingRoundtripLatency(UINT64, Aws::CloudWatch::Model::StandardUnit); - VOID pushSignalingConnectionDuration(UINT64, Aws::CloudWatch::Model::StandardUnit); VOID pushOutboundRtpStats(POutgoingRTPStatsCtx); VOID pushInboundRtpStats(PIncomingRTPStatsCtx); VOID pushPeerConnectionMetrics(PPeerConnectionMetrics); diff --git a/cloudwatch-integ/Include.h b/cloudwatch-integ/Include.h index b1c0f4aa8d..f1824c85e6 100644 --- a/cloudwatch-integ/Include.h +++ b/cloudwatch-integ/Include.h @@ -3,7 +3,6 @@ #include SAMPLE_CONFIG_HEADER #define DEFAULT_CLOUDWATCH_NAMESPACE "KinesisVideoSDKCanary" -#define DEFAULT_FPS_VALUE 25 // TODO: This value shouldn't matter. But, since we don't allow NULL value, we have to set to a value #define DEFAULT_VIEWER_PEER_ID "ConsumerViewer" #define DEFAULT_FILE_LOGGING_BUFFER_SIZE (200 * 1024) @@ -20,19 +19,16 @@ #define FRAME_METADATA_SIZE (SIZEOF(UINT64) + SIZEOF(UINT32) + SIZEOF(UINT32)) #define ANNEX_B_NALU_SIZE 4 -#define STORAGE_CANARY_FIRST_FRAME_TS_FILE_ENV_VAR "STORAGE_CANARY_FIRST_FRAME_TS_FILE" - -#define FIRST_FRAME_TS_FILE_PATH (PCHAR) "../../" -#define STORAGE_DEFAULT_FIRST_FRAME_TS_FILE (PCHAR) "DefaultFirstFrameSentTSFileName.txt" +#define FIRST_FRAME_TS_FILE_PATH (PCHAR) "../../" +#define STORAGE_DEFAULT_FIRST_FRAME_TS_FILE (PCHAR) "DefaultFirstFrameSentTSFileName.txt" #define INDIVIDUAL_STORAGE_CW_DIMENSION "StorageWebRTCSDKCanaryChannelName" #define INDIVIDUAL_CW_DIMENSION "WebRTCSDKCanaryChannelName" #define AGGREGATE_STORAGE_CW_DIMENSION "StorageWebRTCSDKCanaryLabel" #define AGGREGATE_CW_DIMENSION "WebRTCSDKCanaryLabel" -#define MAX_CALL_RETRY_COUNT 10 #define OUTBOUND_RTP_STATS_TIMER_INTERVAL (60 * HUNDREDS_OF_NANOS_IN_A_SECOND) -#define END_TO_END_METRICS_INVOCATION_PERIOD (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) +#define END_TO_END_METRICS_INVOCATION_PERIOD (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) #include diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index a264b7a5e4..db77b13516 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -6,10 +6,11 @@ STATUS writeFirstFrameSentTimeToFile(PCHAR fileName) { STATUS retStatus = STATUS_SUCCESS; DLOGI("Writing to %s file", fileName); - UINT64 currentTimeMilliS = GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; - CHAR cuurrentTimeChars[MAX_UINT64_DIGIT_COUNT + 1]; // +1 accounts for null terminator - UINT64 writeSize = SPRINTF(cuurrentTimeChars, "%llu", currentTimeMilliS); - CHK_STATUS(writeFile((PCHAR) fileName, false, false, static_cast(static_cast(cuurrentTimeChars)), writeSize)); + UINT64 currentTimeMillis = GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + CHAR currentTimeChars[MAX_UINT64_DIGIT_COUNT + 1]; // +1 accounts for null terminator + UINT64 writeSize = SNPRINTF(currentTimeChars, SIZEOF(currentTimeChars), "%llu", currentTimeMillis); + DLOGI("Timestamp written to file: %s", currentTimeChars); + CHK_STATUS(writeFile((PCHAR) fileName, false, false, static_cast(static_cast(currentTimeChars)), writeSize)); CleanUp: return retStatus; } @@ -111,10 +112,12 @@ PVOID sendMockVideoPackets(PVOID args) UINT32 maxFrameSize = (FRAME_METADATA_SIZE + ((DEFAULT_BITRATE / 8) / DEFAULT_FRAMERATE)) * 2; PBYTE frameData = NULL; UINT64 firstFrameTime = 0; - PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) args; UINT32 outboundStatsTimerId = MAX_UINT32; frameData = (PBYTE) MEMALLOC(maxFrameSize); + PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) args; + CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session not set up"); + // We allocate a bigger buffer to accomodate the hex encoded string frame.frameData = (PBYTE) MEMALLOC(maxFrameSize * 3 + 1 + ANNEX_B_NALU_SIZE); frame.version = FRAME_CURRENT_VERSION; @@ -176,14 +179,15 @@ PVOID sendMockVideoPackets(PVOID args) } } MUTEX_UNLOCK(pSampleConfiguration->streamingSessionListReadLock); - THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_SECOND / DEFAULT_FRAME_RATE); + THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_SECOND / DEFAULT_FRAMERATE); frame.presentationTs = GETTIME(); } - CleanUp: - +CleanUp: + DLOGI("[KVS Master] Closing video thread"); + CHK_LOG_ERR(retStatus); SAFE_MEMFREE(frame.frameData); SAFE_MEMFREE(frameData); - return NULL; + return (PVOID) (ULONG_PTR) retStatus;; } PVOID sendRealVideoPackets(PVOID args) @@ -199,11 +203,14 @@ PVOID sendRealVideoPackets(PVOID args) CHAR tsFileName[MAX_PATH_LEN + 1]; UINT64 firstFrameTime = 0; UINT32 outboundStatsTimerId = MAX_UINT32; - CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); + CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session not set up"); frame.presentationTs = 0; startTime = GETTIME(); lastFrameTime = startTime; + SNPRINTF(tsFileName, SIZEOF(tsFileName), "%s%s", FIRST_FRAME_TS_FILE_PATH, STORAGE_DEFAULT_FIRST_FRAME_TS_FILE); + // Delete file if it exists + FREMOVE(tsFileName); if(pSampleConfiguration->enableMetrics) { CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, OUTBOUND_RTP_STATS_TIMER_INTERVAL, OUTBOUND_RTP_STATS_TIMER_INTERVAL, @@ -242,7 +249,6 @@ PVOID sendRealVideoPackets(PVOID args) pSampleConfiguration->sampleStreamingSessionList[i]->pStatsCtx->outgoingRTPStatsCtx.videoBytesGenerated += frame.size; } if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { - SNPRINTF(tsFileName, SIZEOF(tsFileName), "%s%s", FIRST_FRAME_TS_FILE_PATH, STORAGE_DEFAULT_FIRST_FRAME_TS_FILE); CHK_STATUS(writeFirstFrameSentTimeToFile(tsFileName)); PROFILE_WITH_START_TIME_OBJ(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, firstFrameTime, "Time to first frame"); CppInteg::Cloudwatch::getInstance().monitoring.pushTimeToFirstFrame(firstFrameTime, @@ -270,7 +276,7 @@ PVOID sendRealVideoPackets(PVOID args) lastFrameTime = GETTIME(); } - CleanUp: +CleanUp: DLOGI("[KVS Master] Closing video thread"); CHK_LOG_ERR(retStatus); @@ -292,6 +298,10 @@ PVOID sendRealAudioPackets(PVOID args) CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); frame.presentationTs = 0; + SNPRINTF(tsFileName, SIZEOF(tsFileName), "%s%s", FIRST_FRAME_TS_FILE_PATH, STORAGE_DEFAULT_FIRST_FRAME_TS_FILE); + // Delete file if it exists + FREMOVE(tsFileName); + while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { fileIndex = fileIndex % NUMBER_OF_OPUS_FRAME_FILES + 1; @@ -324,7 +334,6 @@ PVOID sendRealAudioPackets(PVOID args) if (status != STATUS_SUCCESS) { DLOGV("writeFrame() failed with 0x%08x", status); } else if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { - SNPRINTF(tsFileName, SIZEOF(tsFileName), "%s%s", FIRST_FRAME_TS_FILE_PATH, STORAGE_DEFAULT_FIRST_FRAME_TS_FILE); CHK_STATUS(writeFirstFrameSentTimeToFile(tsFileName)); PROFILE_WITH_START_TIME_OBJ(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, firstFrameTime, "Time to first frame"); CppInteg::Cloudwatch::getInstance().monitoring.pushTimeToFirstFrame(firstFrameTime, diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index 2d051ce471..92dbb25320 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -4,8 +4,6 @@ extern PSampleConfiguration gSampleConfiguration; -#ifdef ENABLE_DATA_CHANNEL - // onMessage callback for a message received by the viewer on a data channel VOID dataChannelOnMessageCallback(UINT64 customData, PRtcDataChannel pDataChannel, BOOL isBinary, PBYTE pMessage, UINT32 pMessageLen) { @@ -31,7 +29,6 @@ VOID dataChannelOnOpenCallback(UINT64 customData, PRtcDataChannel pDataChannel) DLOGI("[KVS Viewer] dataChannelSend(): operation returned status code: 0x%08x ", retStatus); } } -#endif STATUS publishStatsForCanary(RTC_STATS_TYPE statsType, PSampleStreamingSession pSampleStreamingSession) { @@ -144,7 +141,6 @@ INT32 main(INT32 argc, CHAR* argv[]) signal(SIGINT, sigintHandler); #endif if (USE_IOT) { - DLOGI("Here"); PCHAR pChannelName; CHK_ERR((pChannelName = GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set since USE_IOT is enabled"); STRNCPY(channelName, pChannelName, SIZEOF(channelName)); @@ -289,7 +285,8 @@ INT32 main(INT32 argc, CHAR* argv[]) } DLOGI("[KVS Viewer] Cleanup done"); - RESET_INSTRUMENTED_ALLOCATORS(); + retStatus = RESET_INSTRUMENTED_ALLOCATORS(); + DLOGI("All SDK allocations freed? %s..0x%08x", retStatus == STATUS_SUCCESS ? "Yes" : "No", retStatus); CppInteg::Cloudwatch::getInstance().monitoring.pushExitStatus(retStatus); CppInteg::Cloudwatch::deinit(); diff --git a/samples/Samples.h b/samples/Samples.h index d1df35a99c..f8ac01841f 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -356,8 +356,9 @@ VOID onIceCandidateHandler(UINT64, PCHAR); PVOID mediaSenderRoutine(PVOID); STATUS setupMetricsCtx(PSampleStreamingSession); STATUS getSdkTimeProfile(PSampleStreamingSession*); -STATUS terminate(UINT32 timerId, UINT64 currentTime, UINT64 customData); -STATUS setUpCredentialProvider(PSampleConfiguration pSampleConfiguration, BOOL useIot); +STATUS terminate(UINT32, UINT64, UINT64); +STATUS setUpCredentialProvider(PSampleConfiguration, BOOL); +STATUS freeMetricsCtx(PSampleStreamingSession* ppSampleStreamingSession); #ifdef __cplusplus } #endif diff --git a/samples/kvsWebRTCClientViewer.c b/samples/kvsWebRTCClientViewer.c index e3a8b1da45..f9d74f028e 100644 --- a/samples/kvsWebRTCClientViewer.c +++ b/samples/kvsWebRTCClientViewer.c @@ -203,7 +203,8 @@ INT32 main(INT32 argc, CHAR* argv[]) } DLOGI("[KVS Viewer] Cleanup done"); - RESET_INSTRUMENTED_ALLOCATORS(); + retStatus = RESET_INSTRUMENTED_ALLOCATORS(); + DLOGI("All SDK allocations freed? %s..0x%08x", retStatus == STATUS_SUCCESS ? "Yes" : "No", retStatus); // https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html // We can only return with 0 - 127. Some platforms treat exit code >= 128 diff --git a/samples/kvsWebRTCClientViewerGstSample.c b/samples/kvsWebRTCClientViewerGstSample.c index e9060dffa2..f2a1130a3e 100644 --- a/samples/kvsWebRTCClientViewerGstSample.c +++ b/samples/kvsWebRTCClientViewerGstSample.c @@ -209,7 +209,8 @@ INT32 main(INT32 argc, CHAR* argv[]) } DLOGI("[KVS Gstreamer Viewer] Cleanup done"); - RESET_INSTRUMENTED_ALLOCATORS(); + retStatus = RESET_INSTRUMENTED_ALLOCATORS(); + DLOGI("All SDK allocations freed? %s..0x%08x", retStatus == STATUS_SUCCESS ? "Yes" : "No", retStatus); // https://www.gnu.org/software/libc/manual/html_node/Exit-Status.html // We can only return with 0 - 127. Some platforms treat exit code >= 128 diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 73f010595e..6bfa9b5cee 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -3,6 +3,18 @@ PSampleConfiguration gSampleConfiguration = NULL; + +STATUS terminate(UINT32 timerId, UINT64 currentTime, UINT64 customData) +{ + DLOGI("Terminating the app"); + if (gSampleConfiguration != NULL) { + ATOMIC_STORE_BOOL(&gSampleConfiguration->interrupted, TRUE); + ATOMIC_STORE_BOOL(&gSampleConfiguration->appTerminateFlag, TRUE); + CVAR_BROADCAST(gSampleConfiguration->cvar); + } + return STATUS_SUCCESS; +} + VOID sigintHandler(INT32 sigNum) { UNUSED_PARAM(sigNum); @@ -20,17 +32,6 @@ STATUS signalingCallFailed(STATUS status) STATUS_SIGNALING_DESCRIBE_MEDIA_CALL_FAILED == status); } -STATUS terminate(UINT32 timerId, UINT64 currentTime, UINT64 customData) -{ - DLOGI("Terminating the app"); - if (gSampleConfiguration != NULL) { - ATOMIC_STORE_BOOL(&gSampleConfiguration->interrupted, TRUE); - ATOMIC_STORE_BOOL(&gSampleConfiguration->appTerminateFlag, TRUE); - CVAR_BROADCAST(gSampleConfiguration->cvar); - } - return STATUS_SUCCESS; -} - VOID onConnectionStateChange(UINT64 customData, RTC_PEER_CONNECTION_STATE newState) { STATUS retStatus = STATUS_SUCCESS; @@ -405,6 +406,9 @@ STATUS freeSampleStreamingSession(PSampleStreamingSession* ppSampleStreamingSess } } + if(pSampleConfiguration->enableMetrics) { + CHK_LOG_ERR(freeMetricsCtx(&pSampleStreamingSession)); + } CHK_LOG_ERR(closePeerConnection(pSampleStreamingSession->pPeerConnection)); CHK_LOG_ERR(freePeerConnection(&pSampleStreamingSession->pPeerConnection)); SAFE_MEMFREE(pSampleStreamingSession); diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index 198fcded34..c68e47d269 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -3,12 +3,6 @@ STATUS setupMetricsCtx(PSampleStreamingSession pSampleStreamingSession) { STATUS retStatus = STATUS_SUCCESS; - if (pSampleStreamingSession == NULL) { - DLOGI("NUll"); - } - if (pSampleStreamingSession->pSampleConfiguration == NULL) { - DLOGI("Null config"); - } CHK(pSampleStreamingSession != NULL && pSampleStreamingSession->pSampleConfiguration != NULL, STATUS_NULL_ARG); if (pSampleStreamingSession->pSampleConfiguration->enableMetrics) { CHK(NULL != (pSampleStreamingSession->pStatsCtx = (PStatsCtx) MEMCALLOC(1, SIZEOF(StatsCtx))), STATUS_NOT_ENOUGH_MEMORY); @@ -52,10 +46,8 @@ STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession) ENTERS(); STATUS retStatus = STATUS_SUCCESS; UINT32 j = 0; - BOOL locked = TRUE; CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up. Nothing to report"); - MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); - locked = TRUE; + pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = RTC_STATS_TYPE_ICE_SERVER; for (; j < pSampleStreamingSession->pSampleConfiguration->iceUriCount; j++) { pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.iceServerIndex = j; @@ -70,9 +62,6 @@ STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession) pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.totalRoundTripTime / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); } CleanUp: - if (locked) { - MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); - } LEAVES(); return retStatus; } @@ -270,3 +259,17 @@ STATUS getSdkTimeProfile(PSampleStreamingSession* ppSampleStreamingSession) CleanUp: return retStatus; } + +STATUS freeMetricsCtx(PSampleStreamingSession* ppSampleStreamingSession) { + STATUS retStatus = STATUS_SUCCESS; + PSampleStreamingSession pSampleStreamingSession = NULL; + + CHK(ppSampleStreamingSession != NULL, STATUS_NULL_ARG); + + pSampleStreamingSession = *ppSampleStreamingSession; + if (pSampleStreamingSession->pSampleConfiguration->enableMetrics) { + SAFE_MEMFREE(pSampleStreamingSession->pStatsCtx); + } +CleanUp: + return retStatus; +} \ No newline at end of file From 64958792d9ab65025dd8a60cee34c6a350b10d86 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 13 Jun 2024 16:30:39 -0700 Subject: [PATCH 43/64] Mutex --- .../kvsWebRTCClientViewerCloudwatch.cpp | 15 +++++++++++---- samples/lib/MetricsHandling.c | 2 ++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index 92dbb25320..09dbdd62c2 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -83,6 +83,7 @@ STATUS inboundStatsCallback(UINT32 timerId, UINT64 currentTime, UINT64 customDat VOID videoFrameHandler(UINT64 customData, PFrame pFrame) { PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; + PStatsCtx pStatsCtx = pSampleStreamingSession->pStatsCtx; // Parse packet and ad e2e metrics PBYTE frameDataPtr = pFrame->frameData + ANNEX_B_NALU_SIZE; UINT32 rawPacketSize = 0; @@ -97,17 +98,23 @@ VOID videoFrameHandler(UINT64 customData, PFrame pFrame) frameDataPtr += SIZEOF(UINT64); UINT32 receivedSize = getUnalignedInt32BigEndian((PINT32)(frameDataPtr)); - pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.frameLatencyAvg = - EMA_ACCUMULATOR_GET_NEXT(pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.frameLatencyAvg, GETTIME() - receivedTs); + if(pSampleStreamingSession == NULL || pStatsCtx == NULL) { + DLOGW("Streaming session freed. Doing nothing"); + return; + } + MUTEX_LOCK(pStatsCtx->statsUpdateLock); + pStatsCtx->endToEndMetricsCtx.frameLatencyAvg = + EMA_ACCUMULATOR_GET_NEXT(pStatsCtx->endToEndMetricsCtx.frameLatencyAvg, GETTIME() - receivedTs); // Do a size match of the raw packet. Since raw packet does not contain the NALu, the // comparison would be rawPacketSize + ANNEX_B_NALU_SIZE and the received size if (rawPacketSize + ANNEX_B_NALU_SIZE == receivedSize) { - pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.sizeMatchAvg = EMA_ACCUMULATOR_GET_NEXT(pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.sizeMatchAvg, 1); + pStatsCtx->endToEndMetricsCtx.sizeMatchAvg = EMA_ACCUMULATOR_GET_NEXT(pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.sizeMatchAvg, 1); } else { - pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.sizeMatchAvg = EMA_ACCUMULATOR_GET_NEXT(pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.sizeMatchAvg, 0); + pStatsCtx->endToEndMetricsCtx.sizeMatchAvg = EMA_ACCUMULATOR_GET_NEXT(pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx.sizeMatchAvg, 0); } SAFE_MEMFREE(rawPacket); + MUTEX_UNLOCK(pStatsCtx->statsUpdateLock); } VOID audioFrameHandler(UINT64 customData, PFrame pFrame) diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index c68e47d269..9279564a8c 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -7,6 +7,7 @@ STATUS setupMetricsCtx(PSampleStreamingSession pSampleStreamingSession) if (pSampleStreamingSession->pSampleConfiguration->enableMetrics) { CHK(NULL != (pSampleStreamingSession->pStatsCtx = (PStatsCtx) MEMCALLOC(1, SIZEOF(StatsCtx))), STATUS_NOT_ENOUGH_MEMORY); } + pSampleStreamingSession->pStatsCtx->statsUpdateLock = MUTEX_CREATE(TRUE); CleanUp: return retStatus; } @@ -268,6 +269,7 @@ STATUS freeMetricsCtx(PSampleStreamingSession* ppSampleStreamingSession) { pSampleStreamingSession = *ppSampleStreamingSession; if (pSampleStreamingSession->pSampleConfiguration->enableMetrics) { + MUTEX_FREE(pSampleStreamingSession->pStatsCtx->statsUpdateLock); SAFE_MEMFREE(pSampleStreamingSession->pStatsCtx); } CleanUp: From e60285fa737e8fdc72f445f8ead126ee5c4366dc Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 13 Jun 2024 17:27:49 -0700 Subject: [PATCH 44/64] locks, ref counts --- .../kvsWebRTCClientMasterCloudwatch.cpp | 26 +++++- .../kvsWebRTCClientViewerCloudwatch.cpp | 34 ++++++++ samples/Samples.h | 3 +- samples/lib/Common.c | 2 +- samples/lib/MetricsHandling.c | 83 +++++++++++++++++-- 5 files changed, 135 insertions(+), 13 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index db77b13516..fecf773ebb 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -2,6 +2,8 @@ #include "../samples/Samples.h" #include "Cloudwatch.h" +UINT32 outboundStatsTimerId = MAX_UINT32; + // Save first-frame-sent time to file for consumer-end access. STATUS writeFirstFrameSentTimeToFile(PCHAR fileName) { STATUS retStatus = STATUS_SUCCESS; @@ -39,6 +41,8 @@ STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customDa CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); CHK_STATUS(populateOutgoingRtpMetricsContext(pSampleStreamingSession)); CppInteg::Cloudwatch::getInstance().monitoring.pushOutboundRtpStats(&pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx); + } else { + retStatus = STATUS_TIMER_QUEUE_STOP_SCHEDULING; } CleanUp: return STATUS_SUCCESS; @@ -112,7 +116,6 @@ PVOID sendMockVideoPackets(PVOID args) UINT32 maxFrameSize = (FRAME_METADATA_SIZE + ((DEFAULT_BITRATE / 8) / DEFAULT_FRAMERATE)) * 2; PBYTE frameData = NULL; UINT64 firstFrameTime = 0; - UINT32 outboundStatsTimerId = MAX_UINT32; frameData = (PBYTE) MEMALLOC(maxFrameSize); PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) args; @@ -202,7 +205,6 @@ PVOID sendRealVideoPackets(PVOID args) UINT64 startTime, lastFrameTime, elapsed; CHAR tsFileName[MAX_PATH_LEN + 1]; UINT64 firstFrameTime = 0; - UINT32 outboundStatsTimerId = MAX_UINT32; CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session not set up"); frame.presentationTs = 0; @@ -454,6 +456,26 @@ INT32 main(INT32 argc, CHAR* argv[]) DLOGE("[KVS Master] freeSignalingClient(): operation returned status code: 0x%08x", retStatus); } + // Free all timer created here that belong to SampleConfiguration timer handle before invoking freeSampleConfiguration + if (IS_VALID_TIMER_QUEUE_HANDLE(pSampleConfiguration->timerQueueHandle)) { + if (outboundStatsTimerId != MAX_UINT32) { + retStatus = timerQueueCancelTimer(pSampleConfiguration->timerQueueHandle, outboundStatsTimerId, + (UINT64) pSampleConfiguration); + if (STATUS_FAILED(retStatus)) { + DLOGE("Failed to cancel outbound stats timer with: 0x%08x", retStatus); + } + outboundStatsTimerId = MAX_UINT32; + } + + if (terminateTimerId != MAX_UINT32) { + retStatus = timerQueueCancelTimer(pSampleConfiguration->timerQueueHandle, terminateTimerId, + (UINT64) pSampleConfiguration); + if (STATUS_FAILED(retStatus)) { + DLOGE("Failed to cancel terminate timer with: 0x%08x", retStatus); + } + terminateTimerId = MAX_UINT32; + } + } retStatus = freeSampleConfiguration(&pSampleConfiguration); if (retStatus != STATUS_SUCCESS) { DLOGE("[KVS Master] freeSampleConfiguration(): operation returned status code: 0x%08x", retStatus); diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index 09dbdd62c2..e9f3ea7425 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -103,6 +103,10 @@ VOID videoFrameHandler(UINT64 customData, PFrame pFrame) return; } MUTEX_LOCK(pStatsCtx->statsUpdateLock); + if(pStatsCtx == NULL) { + DLOGW("pStatsCtx freed"); + return; + } pStatsCtx->endToEndMetricsCtx.frameLatencyAvg = EMA_ACCUMULATOR_GET_NEXT(pStatsCtx->endToEndMetricsCtx.frameLatencyAvg, GETTIME() - receivedTs); @@ -285,6 +289,36 @@ INT32 main(INT32 argc, CHAR* argv[]) DLOGE("[KVS Viewer] freeSignalingClient(): operation returned status code: 0x%08x ", retStatus); } + // Free all timer created here that belong to SampleConfiguration timer handle before invoking freeSampleConfiguration + if (IS_VALID_TIMER_QUEUE_HANDLE(pSampleConfiguration->timerQueueHandle)) { + if (inboundTimerId != MAX_UINT32) { + retStatus = timerQueueCancelTimer(pSampleConfiguration->timerQueueHandle, inboundTimerId, + (UINT64) pSampleConfiguration); + if (STATUS_FAILED(retStatus)) { + DLOGE("Failed to cancel inbound stats timer with: 0x%08x", retStatus); + } + inboundTimerId = MAX_UINT32; + } + + if (e2eTimerId != MAX_UINT32) { + retStatus = timerQueueCancelTimer(pSampleConfiguration->timerQueueHandle, e2eTimerId, + (UINT64) pSampleConfiguration); + if (STATUS_FAILED(retStatus)) { + DLOGE("Failed to cancel e2e timer with: 0x%08x", retStatus); + } + e2eTimerId = MAX_UINT32; + } + + if (terminateId != MAX_UINT32) { + retStatus = timerQueueCancelTimer(pSampleConfiguration->timerQueueHandle, terminateId, + (UINT64) pSampleConfiguration); + if (STATUS_FAILED(retStatus)) { + DLOGE("Failed to cancel terminate timer with: 0x%08x", retStatus); + } + terminateId = MAX_UINT32; + } + } + retStatus = freeSampleConfiguration(&pSampleConfiguration); if (retStatus != STATUS_SUCCESS) { DLOGE("[KVS Viewer] freeSampleConfiguration(): operation returned status code: 0x%08x ", retStatus); diff --git a/samples/Samples.h b/samples/Samples.h index f8ac01841f..a25f2d57a2 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -259,6 +259,7 @@ typedef struct { EndToEndMetricsCtx endToEndMetricsCtx; RtcStats kvsRtcStats; MUTEX statsUpdateLock; + volatile SIZE_T statsContextRefCnt; } StatsCtx, *PStatsCtx; struct __SampleStreamingSession { @@ -358,7 +359,7 @@ STATUS setupMetricsCtx(PSampleStreamingSession); STATUS getSdkTimeProfile(PSampleStreamingSession*); STATUS terminate(UINT32, UINT64, UINT64); STATUS setUpCredentialProvider(PSampleConfiguration, BOOL); -STATUS freeMetricsCtx(PSampleStreamingSession* ppSampleStreamingSession); +STATUS freeMetricsCtx(PStatsCtx*); #ifdef __cplusplus } #endif diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 6bfa9b5cee..1526c4fa28 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -407,7 +407,7 @@ STATUS freeSampleStreamingSession(PSampleStreamingSession* ppSampleStreamingSess } if(pSampleConfiguration->enableMetrics) { - CHK_LOG_ERR(freeMetricsCtx(&pSampleStreamingSession)); + CHK_LOG_ERR(freeMetricsCtx(&pSampleStreamingSession->pStatsCtx)); } CHK_LOG_ERR(closePeerConnection(pSampleStreamingSession->pPeerConnection)); CHK_LOG_ERR(freePeerConnection(&pSampleStreamingSession->pPeerConnection)); diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index 9279564a8c..c459000e0a 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -12,6 +12,20 @@ STATUS setupMetricsCtx(PSampleStreamingSession pSampleStreamingSession) return retStatus; } +VOID acquireMetricsCtx(PStatsCtx pStatsCtx) +{ + if (pStatsCtx != NULL) { + ATOMIC_INCREMENT(&pStatsCtx->statsContextRefCnt); + } +} + +VOID releaseMetricsCtx(PStatsCtx pStatsCtx) +{ + if (pStatsCtx != NULL) { + ATOMIC_DECREMENT(&pStatsCtx->statsContextRefCnt); + } +} + STATUS logSelectedIceCandidatesInformation(PSampleStreamingSession pSampleStreamingSession) { ENTERS(); @@ -47,8 +61,14 @@ STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession) ENTERS(); STATUS retStatus = STATUS_SUCCESS; UINT32 j = 0; - CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up. Nothing to report"); + BOOL locked = FALSE; + + acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); + CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up (if interested set enableMetrics flag too). Nothing to report"); + + MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + locked = TRUE; pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = RTC_STATS_TYPE_ICE_SERVER; for (; j < pSampleStreamingSession->pSampleConfiguration->iceUriCount; j++) { pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.iceServerIndex = j; @@ -63,6 +83,10 @@ STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession) pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.totalRoundTripTime / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); } CleanUp: + if(locked) { + MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + } + releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); LEAVES(); return retStatus; } @@ -173,6 +197,15 @@ STATUS getIceCandidatePairStatsCallback(UINT32 timerId, UINT64 currentTime, UINT STATUS populateOutgoingRtpMetricsContext(PSampleStreamingSession pSampleStreamingSession) { DOUBLE currentDuration = 0; + BOOL locked = FALSE; + STATUS retStatus = STATUS_SUCCESS; + + acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); + + CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up. Nothing to report"); + + MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + locked = TRUE; currentDuration = (DOUBLE) (pSampleStreamingSession->pStatsCtx->kvsRtcStats.timestamp - pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.prevTs) / @@ -207,7 +240,11 @@ STATUS populateOutgoingRtpMetricsContext(PSampleStreamingSession pSampleStreamin pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.outboundRtpStreamStats.nackCount; pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.prevRetxBytesSent = pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.outboundRtpStreamStats.retransmittedBytesSent; - +CleanUp: + if(locked) { + MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + } + releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); return STATUS_SUCCESS; } @@ -215,7 +252,14 @@ STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamin { DOUBLE currentDuration = 0; STATUS retStatus = STATUS_SUCCESS; + BOOL locked = FALSE; + + acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); + CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up. Nothing to report"); + + MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + locked = TRUE; currentDuration = (DOUBLE) (pSampleStreamingSession->pStatsCtx->kvsRtcStats.timestamp - pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.prevTs) / HUNDREDS_OF_NANOS_IN_A_SECOND; @@ -242,6 +286,10 @@ STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamin pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.prevTs = pSampleStreamingSession->pStatsCtx->kvsRtcStats.timestamp; CleanUp: + if(locked) { + MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + } + releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); return retStatus; } @@ -249,7 +297,14 @@ STATUS getSdkTimeProfile(PSampleStreamingSession* ppSampleStreamingSession) { STATUS retStatus = STATUS_SUCCESS; PSampleStreamingSession pSampleStreamingSession = *ppSampleStreamingSession; + BOOL locked = FALSE; + + acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up. Nothing to report"); + + MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + locked = TRUE; + CHK(!pSampleStreamingSession->firstFrame, STATUS_WAITING_ON_FIRST_FRAME); pSampleStreamingSession->pSampleConfiguration->signalingClientMetrics.version = SIGNALING_CLIENT_METRICS_CURRENT_VERSION; @@ -258,20 +313,30 @@ STATUS getSdkTimeProfile(PSampleStreamingSession* ppSampleStreamingSession) CHK_STATUS(peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->peerConnectionMetrics)); CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->iceMetrics)); CleanUp: + if(locked) { + MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + } + releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); return retStatus; } -STATUS freeMetricsCtx(PSampleStreamingSession* ppSampleStreamingSession) { +STATUS freeMetricsCtx(PStatsCtx* ppStatsCtx) { STATUS retStatus = STATUS_SUCCESS; - PSampleStreamingSession pSampleStreamingSession = NULL; + PStatsCtx pStatsCtx = NULL; - CHK(ppSampleStreamingSession != NULL, STATUS_NULL_ARG); + CHK(pStatsCtx != NULL, STATUS_NULL_ARG); - pSampleStreamingSession = *ppSampleStreamingSession; - if (pSampleStreamingSession->pSampleConfiguration->enableMetrics) { - MUTEX_FREE(pSampleStreamingSession->pStatsCtx->statsUpdateLock); - SAFE_MEMFREE(pSampleStreamingSession->pStatsCtx); + pStatsCtx = *ppStatsCtx; + + while (ATOMIC_LOAD(&pStatsCtx->statsContextRefCnt) > 0) { + THREAD_SLEEP(100 * HUNDREDS_OF_NANOS_IN_A_MILLISECOND); } + DLOGI("All references freed for stats ctx object"); + MUTEX_LOCK(pStatsCtx->statsUpdateLock); + MUTEX_UNLOCK(pStatsCtx->statsUpdateLock); + MUTEX_FREE(pStatsCtx->statsUpdateLock); + SAFE_MEMFREE(pStatsCtx); + *ppStatsCtx = NULL; CleanUp: return retStatus; } \ No newline at end of file From 2e5daafcabdf45052faf0d14f4f1e35b32aa2621 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 13 Jun 2024 21:11:31 -0700 Subject: [PATCH 45/64] more sync --- cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp | 8 ++++---- samples/Samples.h | 2 ++ samples/lib/Common.c | 3 ++- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index fecf773ebb..b572366a78 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -33,7 +33,8 @@ VOID calculateDisconnectToFrameSentTime(PSampleConfiguration pSampleConfiguratio STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customData) { STATUS retStatus = STATUS_SUCCESS; - PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; + PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; + PSampleStreamingSession pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; CHK_WARN(pSampleStreamingSession != NULL && pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats ctx object not set up"); pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = RTC_STATS_TYPE_OUTBOUND_RTP; @@ -130,7 +131,7 @@ PVOID sendMockVideoPackets(PVOID args) CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, OUTBOUND_RTP_STATS_TIMER_INTERVAL, OUTBOUND_RTP_STATS_TIMER_INTERVAL, publishStatsForCanary, - (UINT64) pSampleConfiguration->sampleStreamingSessionList[0], + (UINT64) pSampleConfiguration, &outboundStatsTimerId)); } while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { @@ -216,8 +217,7 @@ PVOID sendRealVideoPackets(PVOID args) if(pSampleConfiguration->enableMetrics) { CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, OUTBOUND_RTP_STATS_TIMER_INTERVAL, OUTBOUND_RTP_STATS_TIMER_INTERVAL, - publishStatsForCanary, (UINT64) pSampleConfiguration->sampleStreamingSessionList[0], &outboundStatsTimerId)); - + publishStatsForCanary, (UINT64) pSampleConfiguration, &outboundStatsTimerId)); } while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { fileIndex = fileIndex % NUMBER_OF_H264_FRAME_FILES + 1; diff --git a/samples/Samples.h b/samples/Samples.h index a25f2d57a2..0aaffa8e6f 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -360,6 +360,8 @@ STATUS getSdkTimeProfile(PSampleStreamingSession*); STATUS terminate(UINT32, UINT64, UINT64); STATUS setUpCredentialProvider(PSampleConfiguration, BOOL); STATUS freeMetricsCtx(PStatsCtx*); +VOID acquireMetricsCtx(PStatsCtx); +VOID releaseMetricsCtx(PStatsCtx); #ifdef __cplusplus } #endif diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 1526c4fa28..2f6578c930 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -249,7 +249,7 @@ STATUS initializePeerConnection(PSampleConfiguration pSampleConfiguration, PRtcP STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, PCHAR peerId, BOOL isMaster, PSampleStreamingSession* ppSampleStreamingSession) -{ +{ DLOGI("Create sample streaming session call"); STATUS retStatus = STATUS_SUCCESS; RtcMediaStreamTrack videoTrack, audioTrack; PSampleStreamingSession pSampleStreamingSession = NULL; @@ -290,6 +290,7 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P } if (pSampleConfiguration->enableMetrics) { + DLOGI("Setting up metrics context"); CHK_STATUS(setupMetricsCtx(pSampleStreamingSession)); } From dfef40b8051fba29dcba7bdd08b6414146f4f579 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 14 Jun 2024 10:14:03 -0700 Subject: [PATCH 46/64] more locking --- .../kvsWebRTCClientMasterCloudwatch.cpp | 30 ++++- .../kvsWebRTCClientViewerCloudwatch.cpp | 114 ++++++++++++------ samples/lib/MetricsHandling.c | 24 ++-- 3 files changed, 119 insertions(+), 49 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index b572366a78..84fb814386 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -34,9 +34,25 @@ VOID calculateDisconnectToFrameSentTime(PSampleConfiguration pSampleConfiguratio STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customData) { STATUS retStatus = STATUS_SUCCESS; PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; - PSampleStreamingSession pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; + PSampleStreamingSession pSampleStreamingSession = NULL; + BOOL sampleConfigurationObjLocked = FALSE; + BOOL statsLocked = FALSE; - CHK_WARN(pSampleStreamingSession != NULL && pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats ctx object not set up"); + CHK_WARN(pSampleConfiguration != NULL, STATUS_NULL_ARG, "Sample config object not set up"); + + // Use MUTEX_TRYLOCK to avoid possible dead lock when canceling timerQueue + if (!MUTEX_TRYLOCK(pSampleConfiguration->sampleConfigurationObjLock)) { + return retStatus; + } else { + sampleConfigurationObjLocked = TRUE; + } + + pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; + CHK_WARN(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "Streaming session object not set up"); + acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); + CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats ctx object not set up"); + MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + statsLocked = TRUE; pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = RTC_STATS_TYPE_OUTBOUND_RTP; if (!ATOMIC_LOAD_BOOL(&pSampleStreamingSession->pSampleConfiguration->appTerminateFlag)) { CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); @@ -46,6 +62,16 @@ STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customDa retStatus = STATUS_TIMER_QUEUE_STOP_SCHEDULING; } CleanUp: + if(statsLocked) { + MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + } + if(pSampleStreamingSession != NULL) { + releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); + } + if (sampleConfigurationObjLocked) { + MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); + } + return STATUS_SUCCESS; } diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index e9f3ea7425..288de06794 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -30,56 +30,96 @@ VOID dataChannelOnOpenCallback(UINT64 customData, PRtcDataChannel pDataChannel) } } -STATUS publishStatsForCanary(RTC_STATS_TYPE statsType, PSampleStreamingSession pSampleStreamingSession) +STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customData) { STATUS retStatus = STATUS_SUCCESS; + PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; + PSampleStreamingSession pSampleStreamingSession = NULL; + BOOL sampleConfigurationObjLocked = FALSE; + BOOL statsLocked = FALSE; + + CHK_WARN(pSampleConfiguration != NULL, STATUS_NULL_ARG, "Sample config object not set up"); + + // Use MUTEX_TRYLOCK to avoid possible dead lock when canceling timerQueue + if (!MUTEX_TRYLOCK(pSampleConfiguration->sampleConfigurationObjLock)) { + return retStatus; + } else { + sampleConfigurationObjLocked = TRUE; + } + + pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; + CHK_WARN(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "Streaming session object not set up"); + acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); + CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats ctx object not set up"); + MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + statsLocked = TRUE; pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = RTC_STATS_TYPE_INBOUND_RTP; - CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, pSampleStreamingSession->pVideoRtcRtpTransceiver, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); - populateIncomingRtpMetricsContext(pSampleStreamingSession); - CppInteg::Cloudwatch::getInstance().monitoring.pushInboundRtpStats(&pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx); + if (!ATOMIC_LOAD_BOOL(&pSampleStreamingSession->pSampleConfiguration->appTerminateFlag)) { + CHK_LOG_ERR(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, + pSampleStreamingSession->pVideoRtcRtpTransceiver, + &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); + populateIncomingRtpMetricsContext(pSampleStreamingSession); + CppInteg::Cloudwatch::getInstance().monitoring.pushInboundRtpStats( + &pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx); + } else { + retStatus = STATUS_TIMER_QUEUE_STOP_SCHEDULING; + } CleanUp: + if(statsLocked) { + MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + } + if(pSampleStreamingSession != NULL) { + releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); + } + if (sampleConfigurationObjLocked) { + MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); + } return retStatus; } -STATUS publishEndToEndMetrics(PSampleStreamingSession pSampleStreamingSession) +STATUS publishEndToEndMetrics(UINT32 timerId, UINT64 currentTime, UINT64 customData) { STATUS retStatus = STATUS_SUCCESS; - CHK(pSampleStreamingSession != NULL, STATUS_NULL_ARG); - CppInteg::Cloudwatch::getInstance().monitoring.pushEndToEndMetrics(&pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx); -CleanUp: - return STATUS_SUCCESS; -} + PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; + PSampleStreamingSession pSampleStreamingSession = NULL; + BOOL sampleConfigurationObjLocked = FALSE; + BOOL statsLocked = FALSE; -STATUS endToendStatsCallback(UINT32 timerId, UINT64 currentTime, UINT64 customData) -{ - UNUSED_PARAM(timerId); - UNUSED_PARAM(currentTime); - STATUS retStatus = STATUS_SUCCESS; - PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; - if (!(ATOMIC_LOAD_BOOL(&pSampleStreamingSession->pSampleConfiguration->appTerminateFlag))) { - CHK_STATUS(publishEndToEndMetrics(pSampleStreamingSession)); + CHK_WARN(pSampleConfiguration != NULL, STATUS_NULL_ARG, "Sample config object not set up"); + + // Use MUTEX_TRYLOCK to avoid possible dead lock when canceling timerQueue + if (!MUTEX_TRYLOCK(pSampleConfiguration->sampleConfigurationObjLock)) { + return retStatus; } else { - retStatus = STATUS_TIMER_QUEUE_STOP_SCHEDULING; + sampleConfigurationObjLocked = TRUE; } -CleanUp: - return retStatus; -} -STATUS inboundStatsCallback(UINT32 timerId, UINT64 currentTime, UINT64 customData) { - UNUSED_PARAM(timerId); - UNUSED_PARAM(currentTime); - STATUS retStatus = STATUS_SUCCESS; - PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; - if (!(ATOMIC_LOAD_BOOL(&pSampleStreamingSession->pSampleConfiguration->appTerminateFlag))) { - publishStatsForCanary(RTC_STATS_TYPE_INBOUND_RTP, pSampleStreamingSession); + pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; + CHK_WARN(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "Streaming session object not set up"); + acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); + CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats ctx object not set up"); + MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + statsLocked = TRUE; + + if (!ATOMIC_LOAD_BOOL(&pSampleStreamingSession->pSampleConfiguration->appTerminateFlag)) { + CppInteg::Cloudwatch::getInstance().monitoring.pushEndToEndMetrics( + &pSampleStreamingSession->pStatsCtx->endToEndMetricsCtx); } else { - retStatus = STATUS_TIMER_QUEUE_STOP_SCHEDULING; + retStatus = STATUS_TIMER_QUEUE_STOP_SCHEDULING; } CleanUp: - return retStatus; + if(statsLocked) { + MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); + } + if(pSampleStreamingSession != NULL) { + releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); + } + if (sampleConfigurationObjLocked) { + MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); + } + return STATUS_SUCCESS; } - VOID videoFrameHandler(UINT64 customData, PFrame pFrame) { PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; @@ -121,11 +161,6 @@ VOID videoFrameHandler(UINT64 customData, PFrame pFrame) MUTEX_UNLOCK(pStatsCtx->statsUpdateLock); } -VOID audioFrameHandler(UINT64 customData, PFrame pFrame) -{ - UNUSED_PARAM(customData); -} - INT32 main(INT32 argc, CHAR* argv[]) { STATUS retStatus = STATUS_SUCCESS; @@ -201,7 +236,6 @@ INT32 main(INT32 argc, CHAR* argv[]) CHK_STATUS(setLocalDescription(pSampleStreamingSession->pPeerConnection, &offerSessionDescriptionInit)); DLOGI("[KVS Viewer] Completed setting local description"); - CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pAudioRtcRtpTransceiver, (UINT64) pSampleStreamingSession, audioFrameHandler)); CHK_STATUS(transceiverOnFrame(pSampleStreamingSession->pVideoRtcRtpTransceiver, (UINT64) pSampleStreamingSession, videoFrameHandler)); if (!pSampleConfiguration->trickleIce) { @@ -257,11 +291,11 @@ INT32 main(INT32 argc, CHAR* argv[]) } CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, END_TO_END_METRICS_INVOCATION_PERIOD, END_TO_END_METRICS_INVOCATION_PERIOD, - endToendStatsCallback, (UINT64) pSampleStreamingSession, &e2eTimerId)); + publishEndToEndMetrics, (UINT64) pSampleConfiguration, &e2eTimerId)); CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, (UINT64) pSampleConfiguration, &terminateId)); CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, END_TO_END_METRICS_INVOCATION_PERIOD, END_TO_END_METRICS_INVOCATION_PERIOD, - inboundStatsCallback, (UINT64) pSampleStreamingSession, &inboundTimerId)); + publishStatsForCanary, (UINT64) pSampleConfiguration, &inboundTimerId)); // Block until interrupted while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted) && !ATOMIC_LOAD_BOOL(&pSampleStreamingSession->terminateFlag)) { THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_SECOND); diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index c459000e0a..51558942b5 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -63,6 +63,8 @@ STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession) UINT32 j = 0; BOOL locked = FALSE; + CHK_WARN(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "Sample streaming session object NULL"); + acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up (if interested set enableMetrics flag too). Nothing to report"); @@ -86,7 +88,9 @@ STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession) if(locked) { MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); } - releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); + if(pSampleStreamingSession != NULL) { + releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); + } LEAVES(); return retStatus; } @@ -106,9 +110,7 @@ STATUS getIceCandidatePairStatsCallback(UINT32 timerId, UINT64 currentTime, UINT DOUBLE incomingBitrate = 0.0; BOOL locked = FALSE; - CHK_WARN(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] getPeriodicStats(): Passed argument is NULL"); - - pSampleConfiguration->rtcIceCandidatePairMetrics.requestedTypeOfStats = RTC_STATS_TYPE_CANDIDATE_PAIR; + CHK_WARN(pSampleConfiguration != NULL, STATUS_NULL_ARG, "getPeriodicStats(): Passed argument is NULL"); // Use MUTEX_TRYLOCK to avoid possible dead lock when canceling timerQueue if (!MUTEX_TRYLOCK(pSampleConfiguration->sampleConfigurationObjLock)) { @@ -117,6 +119,8 @@ STATUS getIceCandidatePairStatsCallback(UINT32 timerId, UINT64 currentTime, UINT locked = TRUE; } + pSampleConfiguration->rtcIceCandidatePairMetrics.requestedTypeOfStats = RTC_STATS_TYPE_CANDIDATE_PAIR; + for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { if (STATUS_SUCCEEDED(rtcPeerConnectionGetMetrics(pSampleConfiguration->sampleStreamingSessionList[i]->pPeerConnection, NULL, &pSampleConfiguration->rtcIceCandidatePairMetrics))) { @@ -244,7 +248,9 @@ STATUS populateOutgoingRtpMetricsContext(PSampleStreamingSession pSampleStreamin if(locked) { MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); } - releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); + if(pSampleStreamingSession != NULL) { + releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); + } return STATUS_SUCCESS; } @@ -289,7 +295,9 @@ STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamin if(locked) { MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); } - releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); + if(pSampleStreamingSession != NULL) { + releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); + } return retStatus; } @@ -316,7 +324,9 @@ STATUS getSdkTimeProfile(PSampleStreamingSession* ppSampleStreamingSession) if(locked) { MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); } - releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); + if(pSampleStreamingSession != NULL) { + releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); + } return retStatus; } From 9303587953cd572283b28220217e6be617645668 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 14 Jun 2024 10:18:44 -0700 Subject: [PATCH 47/64] nit cleanup --- cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 84fb814386..31a268b124 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -92,12 +92,8 @@ PVOID sendProfilingMetrics(PVOID customData) if(STATUS_SUCCEEDED(retStatus)) { CppInteg::Cloudwatch::getInstance().monitoring.pushSignalingClientMetrics(&pSampleConfiguration->signalingClientMetrics); - if(pSampleConfiguration->sampleStreamingSessionList[0]->pStatsCtx != NULL) { - CppInteg::Cloudwatch::getInstance().monitoring.pushPeerConnectionMetrics(&pSampleStreamingSession->peerConnectionMetrics); - CppInteg::Cloudwatch::getInstance().monitoring.pushKvsIceAgentMetrics(&pSampleStreamingSession->iceMetrics); - } else { - DLOGE("StatsCtx uninitialized. If metrics is enabled, this should not happen"); - } + CppInteg::Cloudwatch::getInstance().monitoring.pushPeerConnectionMetrics(&pSampleStreamingSession->peerConnectionMetrics); + CppInteg::Cloudwatch::getInstance().monitoring.pushKvsIceAgentMetrics(&pSampleStreamingSession->iceMetrics); return NULL; } else if(retStatus == STATUS_WAITING_ON_FIRST_FRAME) { DLOGI("Waiting on streaming to start 0x%08x", retStatus); @@ -195,7 +191,6 @@ PVOID sendMockVideoPackets(PVOID args) pSampleConfiguration->sampleStreamingSessionList[i]->pStatsCtx->outgoingRTPStatsCtx.videoFramesGenerated++; pSampleConfiguration->sampleStreamingSessionList[i]->pStatsCtx->outgoingRTPStatsCtx.videoBytesGenerated += frame.size; } - if (pSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { PROFILE_WITH_START_TIME_OBJ(pSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, firstFrameTime, "Time to first frame"); CppInteg::Cloudwatch::getInstance().monitoring.pushTimeToFirstFrame(firstFrameTime, Aws::CloudWatch::Model::StandardUnit::Milliseconds); From f13f3f6622a34ca7aea0a1ab301706b004f4fa4f Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 14 Jun 2024 10:41:34 -0700 Subject: [PATCH 48/64] switch ref count args --- .../kvsWebRTCClientMasterCloudwatch.cpp | 11 ++-- .../kvsWebRTCClientViewerCloudwatch.cpp | 18 ++---- samples/Samples.h | 4 +- samples/lib/DataChannelHandling.c | 3 +- samples/lib/MetricsHandling.c | 59 +++++++------------ 5 files changed, 35 insertions(+), 60 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 31a268b124..e0161ec959 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -40,7 +40,7 @@ STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customDa CHK_WARN(pSampleConfiguration != NULL, STATUS_NULL_ARG, "Sample config object not set up"); - // Use MUTEX_TRYLOCK to avoid possible dead lock when canceling timerQueue + // Use MUTEX_TRYLOCK to avoid possible deadlock when canceling timerQueue if (!MUTEX_TRYLOCK(pSampleConfiguration->sampleConfigurationObjLock)) { return retStatus; } else { @@ -48,9 +48,8 @@ STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customDa } pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; - CHK_WARN(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "Streaming session object not set up"); - acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); - CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats ctx object not set up"); + acquireMetricsCtx(pSampleStreamingSession); + CHK_WARN(pSampleStreamingSession != NULL || pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats ctx object not set up"); MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); statsLocked = TRUE; pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = RTC_STATS_TYPE_OUTBOUND_RTP; @@ -65,9 +64,7 @@ STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customDa if(statsLocked) { MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); } - if(pSampleStreamingSession != NULL) { - releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); - } + releaseMetricsCtx(pSampleStreamingSession); if (sampleConfigurationObjLocked) { MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); } diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index 288de06794..41bdb161e8 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -48,9 +48,8 @@ STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customDa } pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; - CHK_WARN(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "Streaming session object not set up"); - acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); - CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats ctx object not set up"); + acquireMetricsCtx(pSampleStreamingSession); + CHK_WARN(pSampleStreamingSession != NULL || pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats ctx object not set up"); MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); statsLocked = TRUE; pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = RTC_STATS_TYPE_INBOUND_RTP; @@ -68,9 +67,7 @@ STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customDa if(statsLocked) { MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); } - if(pSampleStreamingSession != NULL) { - releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); - } + releaseMetricsCtx(pSampleStreamingSession); if (sampleConfigurationObjLocked) { MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); } @@ -95,9 +92,8 @@ STATUS publishEndToEndMetrics(UINT32 timerId, UINT64 currentTime, UINT64 customD } pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; - CHK_WARN(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "Streaming session object not set up"); - acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); - CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats ctx object not set up"); + acquireMetricsCtx(pSampleStreamingSession); + CHK_WARN(pSampleStreamingSession != NULL || pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats ctx object not set up"); MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); statsLocked = TRUE; @@ -111,9 +107,7 @@ STATUS publishEndToEndMetrics(UINT32 timerId, UINT64 currentTime, UINT64 customD if(statsLocked) { MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); } - if(pSampleStreamingSession != NULL) { - releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); - } + releaseMetricsCtx(pSampleStreamingSession); if (sampleConfigurationObjLocked) { MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); } diff --git a/samples/Samples.h b/samples/Samples.h index 0aaffa8e6f..f839b5b75e 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -360,8 +360,8 @@ STATUS getSdkTimeProfile(PSampleStreamingSession*); STATUS terminate(UINT32, UINT64, UINT64); STATUS setUpCredentialProvider(PSampleConfiguration, BOOL); STATUS freeMetricsCtx(PStatsCtx*); -VOID acquireMetricsCtx(PStatsCtx); -VOID releaseMetricsCtx(PStatsCtx); +VOID acquireMetricsCtx(PSampleStreamingSession); +VOID releaseMetricsCtx(PSampleStreamingSession); #ifdef __cplusplus } #endif diff --git a/samples/lib/DataChannelHandling.c b/samples/lib/DataChannelHandling.c index e366b6fdae..7192105d90 100644 --- a/samples/lib/DataChannelHandling.c +++ b/samples/lib/DataChannelHandling.c @@ -128,8 +128,7 @@ VOID onDataChannelMessage(UINT64 customData, PRtcDataChannel pDataChannel, BOOL pSampleConfiguration->signalingClientMetrics.signalingClientStats.connectEndTime); DLOGI("Sending signaling metrics to the viewer: %s", pSampleStreamingSession->pSignalingClientMetricsMessage); - CHK_STATUS( - peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->peerConnectionMetrics)); + 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, diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index 51558942b5..6d7828302e 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -12,17 +12,17 @@ STATUS setupMetricsCtx(PSampleStreamingSession pSampleStreamingSession) return retStatus; } -VOID acquireMetricsCtx(PStatsCtx pStatsCtx) +VOID acquireMetricsCtx(PSampleStreamingSession pSampleStreamingSession) { - if (pStatsCtx != NULL) { - ATOMIC_INCREMENT(&pStatsCtx->statsContextRefCnt); + if (pSampleStreamingSession != NULL && pSampleStreamingSession->pStatsCtx != NULL) { + ATOMIC_INCREMENT(&pSampleStreamingSession->pStatsCtx->statsContextRefCnt); } } -VOID releaseMetricsCtx(PStatsCtx pStatsCtx) +VOID releaseMetricsCtx(PSampleStreamingSession pSampleStreamingSession) { - if (pStatsCtx != NULL) { - ATOMIC_DECREMENT(&pStatsCtx->statsContextRefCnt); + if (pSampleStreamingSession != NULL && pSampleStreamingSession->pStatsCtx != NULL) { + ATOMIC_DECREMENT(&pSampleStreamingSession->pStatsCtx->statsContextRefCnt); } } @@ -65,9 +65,10 @@ STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession) CHK_WARN(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "Sample streaming session object NULL"); - acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); + acquireMetricsCtx(pSampleStreamingSession); - CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up (if interested set enableMetrics flag too). Nothing to report"); + CHK_WARN(pSampleStreamingSession != NULL && pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, + "Stats object not set up (if interested set enableMetrics flag too). Nothing to report"); MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); locked = TRUE; @@ -85,12 +86,10 @@ STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession) pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.totalRoundTripTime / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); } CleanUp: - if(locked) { + if (locked) { MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); } - if(pSampleStreamingSession != NULL) { - releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); - } + releaseMetricsCtx(pSampleStreamingSession); LEAVES(); return retStatus; } @@ -204,7 +203,7 @@ STATUS populateOutgoingRtpMetricsContext(PSampleStreamingSession pSampleStreamin BOOL locked = FALSE; STATUS retStatus = STATUS_SUCCESS; - acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); + acquireMetricsCtx(pSampleStreamingSession); CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up. Nothing to report"); @@ -245,12 +244,10 @@ STATUS populateOutgoingRtpMetricsContext(PSampleStreamingSession pSampleStreamin pSampleStreamingSession->pStatsCtx->outgoingRTPStatsCtx.prevRetxBytesSent = pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.outboundRtpStreamStats.retransmittedBytesSent; CleanUp: - if(locked) { + if (locked) { MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); } - if(pSampleStreamingSession != NULL) { - releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); - } + releaseMetricsCtx(pSampleStreamingSession); return STATUS_SUCCESS; } @@ -260,9 +257,10 @@ STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamin STATUS retStatus = STATUS_SUCCESS; BOOL locked = FALSE; - acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); + acquireMetricsCtx(pSampleStreamingSession); - CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up. Nothing to report"); + CHK_WARN(pSampleStreamingSession != NULL && pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, + "Stats object not set up. Nothing to report"); MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); locked = TRUE; @@ -292,12 +290,10 @@ STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamin pSampleStreamingSession->pStatsCtx->incomingRTPStatsCtx.prevTs = pSampleStreamingSession->pStatsCtx->kvsRtcStats.timestamp; CleanUp: - if(locked) { + if (locked) { MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); } - if(pSampleStreamingSession != NULL) { - releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); - } + releaseMetricsCtx(pSampleStreamingSession); return retStatus; } @@ -305,14 +301,8 @@ STATUS getSdkTimeProfile(PSampleStreamingSession* ppSampleStreamingSession) { STATUS retStatus = STATUS_SUCCESS; PSampleStreamingSession pSampleStreamingSession = *ppSampleStreamingSession; - BOOL locked = FALSE; - - acquireMetricsCtx(pSampleStreamingSession->pStatsCtx); - CHK_WARN(pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats object not set up. Nothing to report"); - - MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); - locked = TRUE; + CHK_WARN(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "Streaming session object not set up. Nothing to report"); CHK(!pSampleStreamingSession->firstFrame, STATUS_WAITING_ON_FIRST_FRAME); pSampleStreamingSession->pSampleConfiguration->signalingClientMetrics.version = SIGNALING_CLIENT_METRICS_CURRENT_VERSION; @@ -321,16 +311,11 @@ STATUS getSdkTimeProfile(PSampleStreamingSession* ppSampleStreamingSession) CHK_STATUS(peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->peerConnectionMetrics)); CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->iceMetrics)); CleanUp: - if(locked) { - MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); - } - if(pSampleStreamingSession != NULL) { - releaseMetricsCtx(pSampleStreamingSession->pStatsCtx); - } return retStatus; } -STATUS freeMetricsCtx(PStatsCtx* ppStatsCtx) { +STATUS freeMetricsCtx(PStatsCtx* ppStatsCtx) +{ STATUS retStatus = STATUS_SUCCESS; PStatsCtx pStatsCtx = NULL; From 2f01d7e82d73f5de525a6396983d559fd096bb70 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 14 Jun 2024 12:12:52 -0700 Subject: [PATCH 49/64] use cw_config_header instead --- cloudwatch-integ/CMakeLists.txt | 6 +++--- cloudwatch-integ/Include.h | 2 +- samples/Samples.h | 2 -- samples/kvsWebRTCClientMaster.c | 1 + samples/lib/Common.c | 8 +++----- samples/lib/Utility.c | 8 ++------ 6 files changed, 10 insertions(+), 17 deletions(-) diff --git a/cloudwatch-integ/CMakeLists.txt b/cloudwatch-integ/CMakeLists.txt index a07a742b36..008b40b82b 100644 --- a/cloudwatch-integ/CMakeLists.txt +++ b/cloudwatch-integ/CMakeLists.txt @@ -12,10 +12,10 @@ link_directories(${OPEN_SRC_INSTALL_PREFIX}/lib) find_package(ZLIB REQUIRED) find_package(AWSSDK REQUIRED COMPONENTS monitoring logs) -set(SAMPLE_CONFIG_HEADER "configs/lr_iot_h264_openssl.h" CACHE FILEPATH "Config header") +set(CW_CONFIG_HEADER "configs/lr_static_h265_openssl.h" CACHE FILEPATH "Config header for the cloudwatch integrated demo") -add_definitions(-DSAMPLE_CONFIG_HEADER="${SAMPLE_CONFIG_HEADER}") -message(STATUS ${SAMPLE_CONFIG_HEADER}) +add_definitions(-DCW_CONFIG_HEADER="${CW_CONFIG_HEADER}") +message(STATUS "Config header set to ${CW_CONFIG_HEADER}") add_executable( kvsWebrtcClientMasterCW diff --git a/cloudwatch-integ/Include.h b/cloudwatch-integ/Include.h index f1824c85e6..c03be773d9 100644 --- a/cloudwatch-integ/Include.h +++ b/cloudwatch-integ/Include.h @@ -1,6 +1,6 @@ #pragma once -#include SAMPLE_CONFIG_HEADER +#include CW_CONFIG_HEADER #define DEFAULT_CLOUDWATCH_NAMESPACE "KinesisVideoSDKCanary" // TODO: This value shouldn't matter. But, since we don't allow NULL value, we have to set to a value diff --git a/samples/Samples.h b/samples/Samples.h index f839b5b75e..0ed8f0794d 100644 --- a/samples/Samples.h +++ b/samples/Samples.h @@ -232,7 +232,6 @@ typedef struct { DOUBLE nacksPerSecond; DOUBLE averageFramesSentPerSecond; DOUBLE retxBytesPercentage; - MUTEX outgoingRtpStatsLock; BOOL recorded; } OutgoingRTPStatsCtx, *POutgoingRTPStatsCtx; @@ -250,7 +249,6 @@ typedef struct { DOUBLE packetReceiveRate; DOUBLE incomingBitRate; DOUBLE framesDroppedPerSecond; - MUTEX incomingRtpStatsLock; } IncomingRTPStatsCtx, *PIncomingRTPStatsCtx; typedef struct { diff --git a/samples/kvsWebRTCClientMaster.c b/samples/kvsWebRTCClientMaster.c index 9418c55825..1aa20e86cc 100644 --- a/samples/kvsWebRTCClientMaster.c +++ b/samples/kvsWebRTCClientMaster.c @@ -29,6 +29,7 @@ INT32 main(INT32 argc, CHAR* argv[]) CHK_STATUS(createSampleConfiguration(pChannelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration)); CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, IOT_CORE_ENABLE_CREDENTIALS)); + pSampleConfiguration->forceTurn = TRUE; if (argc > 3) { if (!STRCMP(argv[3], AUDIO_CODEC_NAME_AAC)) { audioCodec = RTC_CODEC_AAC; diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 2f6578c930..9eff7d6224 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -3,7 +3,6 @@ PSampleConfiguration gSampleConfiguration = NULL; - STATUS terminate(UINT32 timerId, UINT64 currentTime, UINT64 customData) { DLOGI("Terminating the app"); @@ -249,7 +248,7 @@ STATUS initializePeerConnection(PSampleConfiguration pSampleConfiguration, PRtcP STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, PCHAR peerId, BOOL isMaster, PSampleStreamingSession* ppSampleStreamingSession) -{ DLOGI("Create sample streaming session call"); +{ STATUS retStatus = STATUS_SUCCESS; RtcMediaStreamTrack videoTrack, audioTrack; PSampleStreamingSession pSampleStreamingSession = NULL; @@ -297,8 +296,7 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P // Flag to enable SDK to calculate selected ice server, local, remote and candidate pair stats. pSampleConfiguration->enableIceStats = FALSE; - pSampleStreamingSession->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime = - GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; + pSampleStreamingSession->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime = GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; CHK_STATUS(initializePeerConnection(pSampleConfiguration, &pSampleStreamingSession->pPeerConnection)); CHK_STATUS(peerConnectionOnIceCandidate(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, onIceCandidateHandler)); @@ -407,7 +405,7 @@ STATUS freeSampleStreamingSession(PSampleStreamingSession* ppSampleStreamingSess } } - if(pSampleConfiguration->enableMetrics) { + if (pSampleConfiguration->enableMetrics) { CHK_LOG_ERR(freeMetricsCtx(&pSampleStreamingSession->pStatsCtx)); } CHK_LOG_ERR(closePeerConnection(pSampleStreamingSession->pPeerConnection)); diff --git a/samples/lib/Utility.c b/samples/lib/Utility.c index 94781bddcf..448c89c5ea 100644 --- a/samples/lib/Utility.c +++ b/samples/lib/Utility.c @@ -196,7 +196,7 @@ STATUS setUpCredentialProvider(PSampleConfiguration pSampleConfiguration, BOOL u { STATUS retStatus = STATUS_SUCCESS; PCHAR pAccessKey, pSecretKey, pSessionToken; - PCHAR pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pIotCoreRoleAlias, pIotCoreCertificateId, pIotCoreThingName; + PCHAR pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pIotCoreRoleAlias, pIotCoreThingName; CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "Set up pSampleConfiguration first by invoking createSampleConfiguration"); pSampleConfiguration->useIot = useIot; @@ -205,7 +205,7 @@ STATUS setUpCredentialProvider(PSampleConfiguration pSampleConfiguration, BOOL u CHK_STATUS(lookForSslCert(&pSampleConfiguration)); pSampleConfiguration->channelInfo.pCertPath = pSampleConfiguration->pCaCertPath; if (useIot) { - DLOGI("USE IOT"); + DLOGI("USE IOT Credential provider"); CHK_ERR((pIotCoreCredentialEndPoint = GETENV(IOT_CORE_CREDENTIAL_ENDPOINT)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_CREDENTIAL_ENDPOINT must be set"); CHK_ERR((pIotCoreCert = GETENV(IOT_CORE_CERT)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_CERT must be set"); @@ -214,11 +214,7 @@ STATUS setUpCredentialProvider(PSampleConfiguration pSampleConfiguration, BOOL u CHK_ERR((pIotCoreThingName = GETENV(IOT_CORE_THING_NAME)) != NULL, STATUS_INVALID_OPERATION, "AWS_IOT_CORE_THING_NAME must be set"); CHK_STATUS(createLwsIotCredentialProvider(pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pSampleConfiguration->pCaCertPath, pIotCoreRoleAlias, pIotCoreThingName, &pSampleConfiguration->pCredentialProvider)); - if ((pIotCoreCertificateId = GETENV(IOT_CORE_CERTIFICATE_ID)) != NULL) { - pSampleConfiguration->channelInfo.pChannelName = pIotCoreCertificateId; - } } else { - DLOGI("USE no"); CHK_ERR((pAccessKey = GETENV(ACCESS_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_ACCESS_KEY_ID must be set"); CHK_ERR((pSecretKey = GETENV(SECRET_KEY_ENV_VAR)) != NULL, STATUS_INVALID_OPERATION, "AWS_SECRET_ACCESS_KEY must be set"); pSessionToken = GETENV(SESSION_TOKEN_ENV_VAR); From 3d49d9625723076bfc83a63e40effb2f80bf6258 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 14 Jun 2024 12:37:40 -0700 Subject: [PATCH 50/64] runner label fix --- cloudwatch-integ/configs/p_iot_h265_mbedtls.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudwatch-integ/configs/p_iot_h265_mbedtls.h b/cloudwatch-integ/configs/p_iot_h265_mbedtls.h index 05ec049d3c..fbe2ad78ec 100644 --- a/cloudwatch-integ/configs/p_iot_h265_mbedtls.h +++ b/cloudwatch-integ/configs/p_iot_h265_mbedtls.h @@ -3,7 +3,7 @@ #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE -#define RUNNER_LABEL (PCHAR) "WebrtcPeriodicMbedTLS" +#define RUNNER_LABEL (PCHAR) "WebrtcPeriodicMBedTLS-H265" #define SCENARIO_LABEL (PCHAR) "MBedTLSPeriodic" #define USE_TURN TRUE #define ENABLE_TTFF_VIA_DC FALSE From e2529577e3b96df9a054a6163733a7c7c8a3a90b Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 14 Jun 2024 15:37:36 -0700 Subject: [PATCH 51/64] fix enableIceStats --- samples/lib/Common.c | 12 ++++------- samples/lib/MetricsHandling.c | 39 +++++++++++------------------------ 2 files changed, 16 insertions(+), 35 deletions(-) diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 9eff7d6224..b651e74f6d 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -293,9 +293,6 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P CHK_STATUS(setupMetricsCtx(pSampleStreamingSession)); } - // Flag to enable SDK to calculate selected ice server, local, remote and candidate pair stats. - pSampleConfiguration->enableIceStats = FALSE; - pSampleStreamingSession->peerConnectionMetrics.peerConnectionStats.peerConnectionStartTime = GETTIME() / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; CHK_STATUS(initializePeerConnection(pSampleConfiguration, &pSampleStreamingSession->pPeerConnection)); @@ -404,7 +401,10 @@ STATUS freeSampleStreamingSession(PSampleStreamingSession* ppSampleStreamingSess MUTEX_FREE(pSampleStreamingSession->twccMetadata.updateLock); } } - + DLOGI("Here....%s", pSampleConfiguration->enableIceStats ? "Enabled" : "Disabled"); + if (pSampleConfiguration->enableIceStats) { + CHK_LOG_ERR(gatherIceServerStats(pSampleStreamingSession)); + } if (pSampleConfiguration->enableMetrics) { CHK_LOG_ERR(freeMetricsCtx(&pSampleStreamingSession->pStatsCtx)); } @@ -769,7 +769,6 @@ STATUS freeSampleConfiguration(PSampleConfiguration* ppSampleConfiguration) pSampleConfiguration = *ppSampleConfiguration; CHK(pSampleConfiguration != NULL, retStatus); - if (IS_VALID_TIMER_QUEUE_HANDLE(pSampleConfiguration->timerQueueHandle)) { if (pSampleConfiguration->iceCandidatePairStatsTimerId != MAX_UINT32) { retStatus = timerQueueCancelTimer(pSampleConfiguration->timerQueueHandle, pSampleConfiguration->iceCandidatePairStatsTimerId, @@ -815,9 +814,6 @@ STATUS freeSampleConfiguration(PSampleConfiguration* ppSampleConfiguration) } for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { - if (pSampleConfiguration->enableIceStats) { - CHK_LOG_ERR(gatherIceServerStats(pSampleConfiguration->sampleStreamingSessionList[i])); - } freeSampleStreamingSession(&pSampleConfiguration->sampleStreamingSessionList[i]); } if (locked) { diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index 6d7828302e..aea0f5961f 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -55,41 +55,27 @@ STATUS logSelectedIceCandidatesInformation(PSampleStreamingSession pSampleStream return retStatus; } -// Return ICE server stats for a specific streaming session STATUS gatherIceServerStats(PSampleStreamingSession pSampleStreamingSession) { ENTERS(); STATUS retStatus = STATUS_SUCCESS; + RtcStats rtcmetrics; UINT32 j = 0; - BOOL locked = FALSE; - - CHK_WARN(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "Sample streaming session object NULL"); - - acquireMetricsCtx(pSampleStreamingSession); + rtcmetrics.requestedTypeOfStats = RTC_STATS_TYPE_ICE_SERVER; - CHK_WARN(pSampleStreamingSession != NULL && pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, - "Stats object not set up (if interested set enableMetrics flag too). Nothing to report"); - - MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); - locked = TRUE; - pSampleStreamingSession->pStatsCtx->kvsRtcStats.requestedTypeOfStats = RTC_STATS_TYPE_ICE_SERVER; + CHK_WARN(pSampleStreamingSession != NULL, STATUS_NULL_ARG, "gatherIceServerStats(): Passed argument is NULL"); for (; j < pSampleStreamingSession->pSampleConfiguration->iceUriCount; j++) { - pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.iceServerIndex = j; - CHK_STATUS(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, NULL, &pSampleStreamingSession->pStatsCtx->kvsRtcStats)); - DLOGD("ICE Server URL: %s", pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.url); - DLOGD("ICE Server port: %d", pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.port); - DLOGD("ICE Server protocol: %s", pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.protocol); - DLOGD("Total requests sent:%" PRIu64, pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.totalRequestsSent); - DLOGD("Total responses received: %" PRIu64, - pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.totalResponsesReceived); + rtcmetrics.rtcStatsObject.iceServerStats.iceServerIndex = j; + CHK_STATUS(rtcPeerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, NULL, &rtcmetrics)); + DLOGD("ICE Server URL: %s", rtcmetrics.rtcStatsObject.iceServerStats.url); + DLOGD("ICE Server port: %d", rtcmetrics.rtcStatsObject.iceServerStats.port); + DLOGD("ICE Server protocol: %s", rtcmetrics.rtcStatsObject.iceServerStats.protocol); + DLOGD("Total requests sent:%" PRIu64, rtcmetrics.rtcStatsObject.iceServerStats.totalRequestsSent); + DLOGD("Total responses received: %" PRIu64, rtcmetrics.rtcStatsObject.iceServerStats.totalResponsesReceived); DLOGD("Total round trip time: %" PRIu64 "ms", - pSampleStreamingSession->pStatsCtx->kvsRtcStats.rtcStatsObject.iceServerStats.totalRoundTripTime / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); + rtcmetrics.rtcStatsObject.iceServerStats.totalRoundTripTime / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); } CleanUp: - if (locked) { - MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); - } - releaseMetricsCtx(pSampleStreamingSession); LEAVES(); return retStatus; } @@ -319,9 +305,8 @@ STATUS freeMetricsCtx(PStatsCtx* ppStatsCtx) STATUS retStatus = STATUS_SUCCESS; PStatsCtx pStatsCtx = NULL; - CHK(pStatsCtx != NULL, STATUS_NULL_ARG); - pStatsCtx = *ppStatsCtx; + CHK(pStatsCtx != NULL, STATUS_NULL_ARG); while (ATOMIC_LOAD(&pStatsCtx->statsContextRefCnt) > 0) { THREAD_SLEEP(100 * HUNDREDS_OF_NANOS_IN_A_MILLISECOND); From b12f0d7174a300a0e0bd3846fa6b6f6694a1b033 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 14 Jun 2024 15:44:30 -0700 Subject: [PATCH 52/64] Cleanup --- samples/config_default.h | 4 ---- samples/kvsWebRTCClientMaster.c | 1 - scripts/generate-iot-credential.sh | 14 +------------- 3 files changed, 1 insertion(+), 18 deletions(-) delete mode 100644 samples/config_default.h diff --git a/samples/config_default.h b/samples/config_default.h deleted file mode 100644 index 5135c565ce..0000000000 --- a/samples/config_default.h +++ /dev/null @@ -1,4 +0,0 @@ -#ifndef KVS_SDK_CONFIG_DEFAULT_H -#define KVS_SDK_CONFIG_DEFAULT_H - -#endif // KVS_SDK_CONFIG_DEFAULT_H diff --git a/samples/kvsWebRTCClientMaster.c b/samples/kvsWebRTCClientMaster.c index 1aa20e86cc..9418c55825 100644 --- a/samples/kvsWebRTCClientMaster.c +++ b/samples/kvsWebRTCClientMaster.c @@ -29,7 +29,6 @@ INT32 main(INT32 argc, CHAR* argv[]) CHK_STATUS(createSampleConfiguration(pChannelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration)); CHK_STATUS(setUpCredentialProvider(pSampleConfiguration, IOT_CORE_ENABLE_CREDENTIALS)); - pSampleConfiguration->forceTurn = TRUE; if (argc > 3) { if (!STRCMP(argv[3], AUDIO_CODEC_NAME_AAC)) { audioCodec = RTC_CODEC_AAC; diff --git a/scripts/generate-iot-credential.sh b/scripts/generate-iot-credential.sh index 6d800d8701..fb12dc4ca7 100755 --- a/scripts/generate-iot-credential.sh +++ b/scripts/generate-iot-credential.sh @@ -84,18 +84,6 @@ cat > iot-policy-document.json < certificate -# # Attach the policy for IoT (KvsCameraIoTPolicy created above) to this certificate. -# aws --profile default iot attach-policy --policy-name $iotPolicyName --target $(jq --raw-output '.certificateArn' certificate) -# # Attach your IoT thing (kvs_example_camera_stream) to the certificate you just created: -# aws --profile default iot attach-thing-principal --thing-name $thingName --principal $(jq --raw-output '.certificateArn' certificate) -# # In order to authorize requests through the IoT credentials provider, you need the IoT credentials endpoint which is unique to your AWS account ID. You can use the following command to get the IoT credentials endpoint. -# aws --profile default iot describe-endpoint --endpoint-type iot:CredentialProvider --output text > iot-credential-provider.txt -# # In addition to the X.509 cerficiate created above, you must also have a CA certificate to establish trust with the back-end service through TLS. You can get the CA certificate using the following command: -# curl --silent 'https://www.amazontrust.com/repository/SFSRootCAG2.pem' --output cacert.pem +aws --profile default iot create-policy --policy-name $iotPolicyName --policy-document 'file://iot-policy-document.json' From 85bb9036c1a89968f3d26d4d7820ba750031fbaf Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 14 Jun 2024 16:04:23 -0700 Subject: [PATCH 53/64] no data channel build fix --- cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp | 4 ++-- cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp | 11 ++++++----- samples/lib/DataChannelHandling.c | 3 +++ 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index e0161ec959..1af6e3a8d7 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -428,9 +428,9 @@ INT32 main(INT32 argc, CHAR* argv[]) } CppInteg::Cloudwatch::init(channelName, region, TRUE, pSampleConfiguration->channelInfo.useMediaStorage); - if(ENABLE_DATA_CHANNEL) { +#ifdef ENABLE_DATA_CHANNEL pSampleConfiguration->onDataChannel = onDataChannel; - } +#endif pSampleConfiguration->mediaType = SAMPLE_STREAMING_AUDIO_VIDEO; DLOGI("[KVS Master] Finished setting handlers"); diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index 41bdb161e8..7ba9b3ef7e 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -4,6 +4,7 @@ extern PSampleConfiguration gSampleConfiguration; +#ifdef ENABLE_DATA_CHANNEL // onMessage callback for a message received by the viewer on a data channel VOID dataChannelOnMessageCallback(UINT64 customData, PRtcDataChannel pDataChannel, BOOL isBinary, PBYTE pMessage, UINT32 pMessageLen) { @@ -29,6 +30,7 @@ VOID dataChannelOnOpenCallback(UINT64 customData, PRtcDataChannel pDataChannel) DLOGI("[KVS Viewer] dataChannelSend(): operation returned status code: 0x%08x ", retStatus); } } +#endif STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customData) { @@ -201,10 +203,9 @@ INT32 main(INT32 argc, CHAR* argv[]) CHK_STATUS(initKvsWebRtc()); DLOGI("[KVS Viewer] KVS WebRTC initialization completed successfully"); - if(ENABLE_DATA_CHANNEL) { +#ifdef ENABLE_DATA_CHANNEL pSampleConfiguration->onDataChannel = onDataChannel; - } - +#endif if ((region = GETENV(DEFAULT_REGION_ENV_VAR)) == NULL) { region = (PCHAR) DEFAULT_AWS_REGION; } @@ -270,7 +271,7 @@ INT32 main(INT32 argc, CHAR* argv[]) message.correlationId[0] = '\0'; CHK_STATUS(signalingClientSendMessageSync(pSampleConfiguration->signalingClientHandle, &message)); - if(ENABLE_DATA_CHANNEL) { +#ifdef ENABLE_DATA_CHANNEL PRtcDataChannel pDataChannel = NULL; PRtcPeerConnection pPeerConnection = pSampleStreamingSession->pPeerConnection; SIZE_T datachannelLocalOpenCount = 0; @@ -283,7 +284,7 @@ INT32 main(INT32 argc, CHAR* argv[]) CHK_STATUS(dataChannelOnOpen(pDataChannel, (UINT64) &datachannelLocalOpenCount, dataChannelOnOpenCallback)); DLOGI("[KVS Viewer] Data Channel open now..."); } - +#endif CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, END_TO_END_METRICS_INVOCATION_PERIOD, END_TO_END_METRICS_INVOCATION_PERIOD, publishEndToEndMetrics, (UINT64) pSampleConfiguration, &e2eTimerId)); CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, diff --git a/samples/lib/DataChannelHandling.c b/samples/lib/DataChannelHandling.c index 7192105d90..a5ba69ccfd 100644 --- a/samples/lib/DataChannelHandling.c +++ b/samples/lib/DataChannelHandling.c @@ -1,5 +1,6 @@ #include "../Samples.h" +#ifdef ENABLE_DATA_CHANNEL VOID onDataChannelMessage(UINT64 customData, PRtcDataChannel pDataChannel, BOOL isBinary, PBYTE pMessage, UINT32 pMessageLen) { STATUS retStatus = STATUS_SUCCESS; @@ -175,3 +176,5 @@ VOID onDataChannel(UINT64 customData, PRtcDataChannel pRtcDataChannel) DLOGI("New DataChannel has been opened %s \n", pRtcDataChannel->name); dataChannelOnMessage(pRtcDataChannel, customData, onDataChannelMessage); } + +#endif \ No newline at end of file From 7e65b91271f0407bc65d8f049f967f9d0f3da2e0 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 14 Jun 2024 19:26:02 -0700 Subject: [PATCH 54/64] newline --- samples/lib/Common.c | 2 +- samples/lib/DataChannelHandling.c | 2 +- samples/lib/Media.c | 2 +- samples/lib/MetricsHandling.c | 2 +- samples/lib/SignalingMsgHandler.c | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/samples/lib/Common.c b/samples/lib/Common.c index b651e74f6d..9ea156e6be 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -976,4 +976,4 @@ STATUS sessionCleanupWait(PSampleConfiguration pSampleConfiguration) LEAVES(); return retStatus; -} \ No newline at end of file +} diff --git a/samples/lib/DataChannelHandling.c b/samples/lib/DataChannelHandling.c index a5ba69ccfd..71124ba334 100644 --- a/samples/lib/DataChannelHandling.c +++ b/samples/lib/DataChannelHandling.c @@ -177,4 +177,4 @@ VOID onDataChannel(UINT64 customData, PRtcDataChannel pRtcDataChannel) dataChannelOnMessage(pRtcDataChannel, customData, onDataChannelMessage); } -#endif \ No newline at end of file +#endif diff --git a/samples/lib/Media.c b/samples/lib/Media.c index 71582a08cd..dd56fcbe70 100644 --- a/samples/lib/Media.c +++ b/samples/lib/Media.c @@ -39,4 +39,4 @@ PVOID mediaSenderRoutine(PVOID customData) ATOMIC_STORE_BOOL(&pSampleConfiguration->mediaThreadStarted, FALSE); CHK_LOG_ERR(retStatus); return NULL; -} \ No newline at end of file +} diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index aea0f5961f..a7d4d84c7a 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -319,4 +319,4 @@ STATUS freeMetricsCtx(PStatsCtx* ppStatsCtx) *ppStatsCtx = NULL; CleanUp: return retStatus; -} \ No newline at end of file +} diff --git a/samples/lib/SignalingMsgHandler.c b/samples/lib/SignalingMsgHandler.c index 60ca6613b0..ba1d39bb5f 100644 --- a/samples/lib/SignalingMsgHandler.c +++ b/samples/lib/SignalingMsgHandler.c @@ -379,4 +379,4 @@ STATUS handleRemoteCandidate(PSampleStreamingSession pSampleStreamingSession, PS CHK_LOG_ERR(retStatus); return retStatus; -} \ No newline at end of file +} From d6b5e3c98376ca24b00b9c8ec2eebd1939179296 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 14 Jun 2024 20:40:27 -0700 Subject: [PATCH 55/64] unused var --- samples/lib/Common.c | 1 - 1 file changed, 1 deletion(-) diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 9ea156e6be..f1146bd536 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -521,7 +521,6 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE STATUS retStatus = STATUS_SUCCESS; PCHAR pAccessKey, pSecretKey, pSessionToken; PSampleConfiguration pSampleConfiguration = NULL; - PCHAR pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pIotCoreRoleAlias, pIotCoreCertificateId, pIotCoreThingName; CHK(ppSampleConfiguration != NULL, STATUS_NULL_ARG); From 2756e80c6d3efdca252e99e8f517a5ac89a5d1f8 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 14 Jun 2024 21:57:29 -0700 Subject: [PATCH 56/64] more unused var --- cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp | 2 ++ cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp | 4 ++++ samples/lib/Common.c | 4 +++- 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 1af6e3a8d7..2fa3cb37bc 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -32,6 +32,8 @@ VOID calculateDisconnectToFrameSentTime(PSampleConfiguration pSampleConfiguratio } STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customData) { + UNUSED_PARAM(timerId); + UNUSED_PARAM(currentTime); STATUS retStatus = STATUS_SUCCESS; PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; PSampleStreamingSession pSampleStreamingSession = NULL; diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index 7ba9b3ef7e..206a164e95 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -34,6 +34,8 @@ VOID dataChannelOnOpenCallback(UINT64 customData, PRtcDataChannel pDataChannel) STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customData) { + UNUSED_PARAM(timerId); + UNUSED_PARAM(currentTime); STATUS retStatus = STATUS_SUCCESS; PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; PSampleStreamingSession pSampleStreamingSession = NULL; @@ -78,6 +80,8 @@ STATUS publishStatsForCanary(UINT32 timerId, UINT64 currentTime, UINT64 customDa STATUS publishEndToEndMetrics(UINT32 timerId, UINT64 currentTime, UINT64 customData) { + UNUSED_PARAM(timerId); + UNUSED_PARAM(currentTime); STATUS retStatus = STATUS_SUCCESS; PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; PSampleStreamingSession pSampleStreamingSession = NULL; diff --git a/samples/lib/Common.c b/samples/lib/Common.c index f1146bd536..62b79239ff 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -5,6 +5,9 @@ PSampleConfiguration gSampleConfiguration = NULL; STATUS terminate(UINT32 timerId, UINT64 currentTime, UINT64 customData) { + UNUSED_PARAM(timerId); + UNUSED_PARAM(currentTime); + UNUSED_PARAM(customData); DLOGI("Terminating the app"); if (gSampleConfiguration != NULL) { ATOMIC_STORE_BOOL(&gSampleConfiguration->interrupted, TRUE); @@ -519,7 +522,6 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE PSampleConfiguration* ppSampleConfiguration) { STATUS retStatus = STATUS_SUCCESS; - PCHAR pAccessKey, pSecretKey, pSessionToken; PSampleConfiguration pSampleConfiguration = NULL; CHK(ppSampleConfiguration != NULL, STATUS_NULL_ARG); From eae9f3334bb79b46145c7c47ad20ce9f8663d4a5 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Fri, 14 Jun 2024 22:04:41 -0700 Subject: [PATCH 57/64] misplaced braces --- cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index 206a164e95..2a85abe394 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -287,7 +287,6 @@ INT32 main(INT32 argc, CHAR* argv[]) // Setting a callback for when the data channel is open CHK_STATUS(dataChannelOnOpen(pDataChannel, (UINT64) &datachannelLocalOpenCount, dataChannelOnOpenCallback)); DLOGI("[KVS Viewer] Data Channel open now..."); - } #endif CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, END_TO_END_METRICS_INVOCATION_PERIOD, END_TO_END_METRICS_INVOCATION_PERIOD, publishEndToEndMetrics, (UINT64) pSampleConfiguration, &e2eTimerId)); From d48fa7892232f291dc2b9ef4a1480e1f2e0a8255 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 20 Jun 2024 08:19:30 -0700 Subject: [PATCH 58/64] fixes --- cloudwatch-integ/configs/lr_iot_h264_openssl.h | 12 ++++++++++++ cloudwatch-integ/configs/lr_static_h265_openssl.h | 9 +++++++++ cloudwatch-integ/configs/p_iot_h265_mbedtls.h | 9 +++++++++ cloudwatch-integ/configs/p_iot_h265_openssl.h | 9 +++++++++ cloudwatch-integ/configs/p_static_h264_mbedtls.h | 9 +++++++++ cloudwatch-integ/configs/storage_extended.h | 9 +++++++++ cloudwatch-integ/configs/storage_periodic.h | 9 +++++++++ cloudwatch-integ/configs/storage_single_reconnect.h | 9 +++++++++ cloudwatch-integ/configs/storage_sub_reconnect.h | 9 +++++++++ 9 files changed, 84 insertions(+) diff --git a/cloudwatch-integ/configs/lr_iot_h264_openssl.h b/cloudwatch-integ/configs/lr_iot_h264_openssl.h index 1bb652cfa7..6083ec55b8 100644 --- a/cloudwatch-integ/configs/lr_iot_h264_openssl.h +++ b/cloudwatch-integ/configs/lr_iot_h264_openssl.h @@ -1,6 +1,12 @@ #ifndef KVS_SDK_SAMPLE_CONFIG_H #define KVS_SDK_SAMPLE_CONFIG_H +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE #define RUNNER_LABEL (PCHAR) "WebrtcLongRunningOpenSSL" @@ -19,4 +25,10 @@ #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE #define DEFAULT_BITRATE (250 * 1024) #define DEFAULT_FRAMERATE 30 +#ifdef __cplusplus +} +#endif + #endif // KVS_SDK_SAMPLE_CONFIG_H + + diff --git a/cloudwatch-integ/configs/lr_static_h265_openssl.h b/cloudwatch-integ/configs/lr_static_h265_openssl.h index 9ed9860298..013dac7029 100644 --- a/cloudwatch-integ/configs/lr_static_h265_openssl.h +++ b/cloudwatch-integ/configs/lr_static_h265_openssl.h @@ -1,6 +1,11 @@ #ifndef KVS_SDK_SAMPLE_CONFIG_H #define KVS_SDK_SAMPLE_CONFIG_H +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE #define RUNNER_LABEL (PCHAR) "WebrtcLongRunningStaticOpenSSL-H265" @@ -19,4 +24,8 @@ #define VIDEO_CODEC RTC_CODEC_H265 #define DEFAULT_BITRATE (250 * 1024) #define DEFAULT_FRAMERATE 30 +#ifdef __cplusplus +} +#endif + #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/p_iot_h265_mbedtls.h b/cloudwatch-integ/configs/p_iot_h265_mbedtls.h index fbe2ad78ec..8003758c52 100644 --- a/cloudwatch-integ/configs/p_iot_h265_mbedtls.h +++ b/cloudwatch-integ/configs/p_iot_h265_mbedtls.h @@ -1,6 +1,11 @@ #ifndef KVS_SDK_SAMPLE_CONFIG_H #define KVS_SDK_SAMPLE_CONFIG_H +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE #define RUNNER_LABEL (PCHAR) "WebrtcPeriodicMBedTLS-H265" @@ -19,4 +24,8 @@ #define VIDEO_CODEC RTC_CODEC_H265 #define DEFAULT_BITRATE (250 * 1024) #define DEFAULT_FRAMERATE 30 +#ifdef __cplusplus +} +#endif + #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/p_iot_h265_openssl.h b/cloudwatch-integ/configs/p_iot_h265_openssl.h index 6724d1a325..4a9dfbefd9 100644 --- a/cloudwatch-integ/configs/p_iot_h265_openssl.h +++ b/cloudwatch-integ/configs/p_iot_h265_openssl.h @@ -1,6 +1,11 @@ #ifndef KVS_SDK_SAMPLE_CONFIG_H #define KVS_SDK_SAMPLE_CONFIG_H +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE #define RUNNER_LABEL (PCHAR) "WebrtcPeriodicOpenSSL-H265" @@ -19,4 +24,8 @@ #define VIDEO_CODEC RTC_CODEC_H265 #define DEFAULT_BITRATE (250 * 1024) #define DEFAULT_FRAMERATE 30 +#ifdef __cplusplus +} +#endif + #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/p_static_h264_mbedtls.h b/cloudwatch-integ/configs/p_static_h264_mbedtls.h index a48e6ad570..264c1f93fd 100644 --- a/cloudwatch-integ/configs/p_static_h264_mbedtls.h +++ b/cloudwatch-integ/configs/p_static_h264_mbedtls.h @@ -1,6 +1,11 @@ #ifndef KVS_SDK_SAMPLE_CONFIG_H #define KVS_SDK_SAMPLE_CONFIG_H +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE #define RUNNER_LABEL (PCHAR) "WebrtcPeriodicStaticMbedTLS" @@ -19,4 +24,8 @@ #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE #define DEFAULT_BITRATE (250 * 1024) #define DEFAULT_FRAMERATE 30 +#ifdef __cplusplus +} +#endif + #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/storage_extended.h b/cloudwatch-integ/configs/storage_extended.h index 681b92c5d1..5de07aba3f 100644 --- a/cloudwatch-integ/configs/storage_extended.h +++ b/cloudwatch-integ/configs/storage_extended.h @@ -1,6 +1,11 @@ #ifndef KVS_SDK_SAMPLE_CONFIG_H #define KVS_SDK_SAMPLE_CONFIG_H +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE #define RUNNER_LABEL (PCHAR) "StorageExtended" @@ -19,4 +24,8 @@ #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE #define DEFAULT_BITRATE (250 * 1024) #define DEFAULT_FRAMERATE 30 +#ifdef __cplusplus +} +#endif + #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/storage_periodic.h b/cloudwatch-integ/configs/storage_periodic.h index 359725f1fb..ac73448f51 100644 --- a/cloudwatch-integ/configs/storage_periodic.h +++ b/cloudwatch-integ/configs/storage_periodic.h @@ -1,6 +1,11 @@ #ifndef KVS_SDK_SAMPLE_CONFIG_H #define KVS_SDK_SAMPLE_CONFIG_H +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE #define RUNNER_LABEL (PCHAR) "StoragePeriodic" @@ -19,4 +24,8 @@ #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE #define DEFAULT_BITRATE (250 * 1024) #define DEFAULT_FRAMERATE 30 +#ifdef __cplusplus +} +#endif + #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/storage_single_reconnect.h b/cloudwatch-integ/configs/storage_single_reconnect.h index 993d88f19d..0ccc3370f6 100644 --- a/cloudwatch-integ/configs/storage_single_reconnect.h +++ b/cloudwatch-integ/configs/storage_single_reconnect.h @@ -1,6 +1,11 @@ #ifndef KVS_SDK_SAMPLE_CONFIG_H #define KVS_SDK_SAMPLE_CONFIG_H +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE #define RUNNER_LABEL (PCHAR) "StorageSingleReconnect" @@ -19,4 +24,8 @@ #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE #define DEFAULT_BITRATE (250 * 1024) #define DEFAULT_FRAMERATE 30 +#ifdef __cplusplus +} +#endif + #endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/storage_sub_reconnect.h b/cloudwatch-integ/configs/storage_sub_reconnect.h index 690672f912..8eba854053 100644 --- a/cloudwatch-integ/configs/storage_sub_reconnect.h +++ b/cloudwatch-integ/configs/storage_sub_reconnect.h @@ -1,6 +1,11 @@ #ifndef KVS_SDK_SAMPLE_CONFIG_H #define KVS_SDK_SAMPLE_CONFIG_H +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE #define RUNNER_LABEL (PCHAR) "StorageSubReconnect" @@ -19,4 +24,8 @@ #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE #define DEFAULT_BITRATE (250 * 1024) #define DEFAULT_FRAMERATE 30 +#ifdef __cplusplus +} +#endif + #endif // KVS_SDK_SAMPLE_CONFIG_H From b96ac9817bd90bc6fcec22e8b53ba859bdd71bf7 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 20 Jun 2024 08:30:06 -0700 Subject: [PATCH 59/64] CI fixes (macos12), potential infinite loop bug fix --- .github/workflows/ci.yml | 6 +++--- .../kvsWebRTCClientMasterCloudwatch.cpp | 8 +++++++- .../kvsWebRTCClientViewerCloudwatch.cpp | 19 ++----------------- src/source/Ice/TurnConnection.c | 2 +- src/source/PeerConnection/Rtcp.c | 9 +++++++++ src/source/Sctp/Sctp.c | 4 +++- src/source/Signaling/LwsApiCalls.c | 5 +++++ src/source/Stun/Stun.c | 2 ++ 8 files changed, 32 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index f183f6fd2b..c2b890f366 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,7 +23,7 @@ jobs: run: | bash scripts/check-clang.sh mac-os-build-clang: - runs-on: macos-11 + runs-on: macos-12 env: CC: /usr/bin/clang CXX: /usr/bin/clang++ @@ -49,7 +49,7 @@ jobs: cd build ./tst/webrtc_client_test mac-os-build-gcc: - runs-on: macos-11 + runs-on: macos-12 env: CC: gcc CXX: g++ @@ -104,7 +104,7 @@ jobs: cd build ./tst/webrtc_client_test static-build-mac: - runs-on: macos-11 + runs-on: macos-12 env: AWS_KVS_LOG_LEVEL: 2 permissions: diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index 2fa3cb37bc..f98dad7625 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -82,10 +82,16 @@ PVOID sendProfilingMetrics(PVOID customData) return NULL; } - while((pSampleConfiguration->sampleStreamingSessionList[0]) == NULL) { + while((pSampleConfiguration->sampleStreamingSessionList[0]) == NULL || !ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted) || !(ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag))) { THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_MILLISECOND * 100); } while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted)) { + if (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted) || + !(ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag))) { + DLOGW("Terminated before we could profile"); + } + } + while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted) || !(ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag))) { PSampleStreamingSession pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; retStatus = getSdkTimeProfile(&pSampleStreamingSession); diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index 2a85abe394..cfab4f9ff0 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -83,21 +83,9 @@ STATUS publishEndToEndMetrics(UINT32 timerId, UINT64 currentTime, UINT64 customD UNUSED_PARAM(timerId); UNUSED_PARAM(currentTime); STATUS retStatus = STATUS_SUCCESS; - PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; - PSampleStreamingSession pSampleStreamingSession = NULL; - BOOL sampleConfigurationObjLocked = FALSE; + PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; BOOL statsLocked = FALSE; - CHK_WARN(pSampleConfiguration != NULL, STATUS_NULL_ARG, "Sample config object not set up"); - - // Use MUTEX_TRYLOCK to avoid possible dead lock when canceling timerQueue - if (!MUTEX_TRYLOCK(pSampleConfiguration->sampleConfigurationObjLock)) { - return retStatus; - } else { - sampleConfigurationObjLocked = TRUE; - } - - pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; acquireMetricsCtx(pSampleStreamingSession); CHK_WARN(pSampleStreamingSession != NULL || pSampleStreamingSession->pStatsCtx != NULL, STATUS_NULL_ARG, "Stats ctx object not set up"); MUTEX_LOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); @@ -114,9 +102,6 @@ STATUS publishEndToEndMetrics(UINT32 timerId, UINT64 currentTime, UINT64 customD MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); } releaseMetricsCtx(pSampleStreamingSession); - if (sampleConfigurationObjLocked) { - MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); - } return STATUS_SUCCESS; } @@ -289,7 +274,7 @@ INT32 main(INT32 argc, CHAR* argv[]) DLOGI("[KVS Viewer] Data Channel open now..."); #endif CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, END_TO_END_METRICS_INVOCATION_PERIOD, END_TO_END_METRICS_INVOCATION_PERIOD, - publishEndToEndMetrics, (UINT64) pSampleConfiguration, &e2eTimerId)); + publishEndToEndMetrics, (UINT64) pSampleStreamingSession, &e2eTimerId)); CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, (UINT64) pSampleConfiguration, &terminateId)); CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, END_TO_END_METRICS_INVOCATION_PERIOD, END_TO_END_METRICS_INVOCATION_PERIOD, diff --git a/src/source/Ice/TurnConnection.c b/src/source/Ice/TurnConnection.c index 7761b757a9..2d9fda4fcf 100644 --- a/src/source/Ice/TurnConnection.c +++ b/src/source/Ice/TurnConnection.c @@ -1032,7 +1032,7 @@ STATUS checkTurnPeerConnections(PTurnConnection pTurnConnection) PStunAttributeAddress pStunAttributeAddress = NULL; PStunAttributeChannelNumber pStunAttributeChannelNumber = NULL; UINT32 i = 0; - + UNUSED_PARAM(sendStatus); // turn mutex is assumed to be locked. CHK(pTurnConnection != NULL, STATUS_NULL_ARG); for (i = 0; i < pTurnConnection->turnPeerCount; ++i) { diff --git a/src/source/PeerConnection/Rtcp.c b/src/source/PeerConnection/Rtcp.c index 4702561784..b4dde063cf 100644 --- a/src/source/PeerConnection/Rtcp.c +++ b/src/source/PeerConnection/Rtcp.c @@ -87,6 +87,15 @@ static STATUS onRtcpReceiverReport(PRtcpPacket pRtcpPacket, PKvsPeerConnection p UINT32 rttPropDelayMsec = 0, rttPropDelay, delaySinceLastSR, lastSR, interarrivalJitter, extHiSeqNumReceived, cumulativeLost, senderSSRC, ssrc1; UINT64 currentTimeNTP = convertTimestampToNTP(GETTIME()); + UNUSED_PARAM(rttPropDelayMsec); + UNUSED_PARAM(rttPropDelay); + UNUSED_PARAM(delaySinceLastSR); + UNUSED_PARAM(lastSR); + UNUSED_PARAM(interarrivalJitter); + UNUSED_PARAM(extHiSeqNumReceived); + UNUSED_PARAM(cumulativeLost); + UNUSED_PARAM(senderSSRC); + CHK(pKvsPeerConnection != NULL && pRtcpPacket != NULL, STATUS_NULL_ARG); // https://tools.ietf.org/html/rfc3550#section-6.4.2 if (pRtcpPacket->payloadLength != RTCP_PACKET_RECEIVER_REPORT_MINLEN) { diff --git a/src/source/Sctp/Sctp.c b/src/source/Sctp/Sctp.c index 2af922e0cd..cd49fa6ab4 100644 --- a/src/source/Sctp/Sctp.c +++ b/src/source/Sctp/Sctp.c @@ -365,6 +365,8 @@ INT32 onSctpInboundPacket(struct socket* sock, union sctp_sockstore addr, PVOID if (data != NULL) { free(data); } - + if (STATUS_FAILED(retStatus)) { + return -1; + } return 1; } diff --git a/src/source/Signaling/LwsApiCalls.c b/src/source/Signaling/LwsApiCalls.c index b696157da7..9dc5199636 100644 --- a/src/source/Signaling/LwsApiCalls.c +++ b/src/source/Signaling/LwsApiCalls.c @@ -37,6 +37,7 @@ INT32 lwsHttpCallbackRoutine(struct lws* wsi, enum lws_callback_reasons reason, PStateMachineState pStateMachineState; BOOL skewMapContains = FALSE; + UNUSED_PARAM(logLevel); DLOGV("HTTPS callback with reason %d", reason); // Early check before accessing the custom data field to see if we are interested in processing the message @@ -1493,6 +1494,10 @@ STATUS joinStorageSessionLws(PSignalingClient pSignalingClient, UINT64 time) PCHAR pResponseStr; UINT32 resultLen; + UNUSED_PARAM(pResponseStr); + UNUSED_PARAM(pLwsCallInfo); + UNUSED_PARAM(resultLen); + CHK(pSignalingClient != NULL, STATUS_NULL_ARG); CHK(pSignalingClient->channelEndpointWebrtc[0] != '\0', STATUS_INTERNAL_ERROR); diff --git a/src/source/Stun/Stun.c b/src/source/Stun/Stun.c index 4e52b6c03a..68c88623bd 100644 --- a/src/source/Stun/Stun.c +++ b/src/source/Stun/Stun.c @@ -379,6 +379,8 @@ STATUS deserializeStunPacket(PBYTE pStunBuffer, UINT32 bufferSize, PBYTE passwor UINT8 *pErrorPhrase, *pBuffer = NULL; UINT16 errorPhraseLength, channelNumber, buffereLength, errorCode; + UNUSED_PARAM(pStunAttributeFingerprint); + CHK(pStunBuffer != NULL && ppStunPacket != NULL, STATUS_NULL_ARG); CHK(bufferSize >= STUN_HEADER_LEN, STATUS_INVALID_ARG); From d9d95586bf99c2d63959414eb8c2f42d097b6ea4 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 20 Jun 2024 09:03:44 -0700 Subject: [PATCH 60/64] unused var --- samples/lib/MetricsHandling.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/samples/lib/MetricsHandling.c b/samples/lib/MetricsHandling.c index a7d4d84c7a..4d5ce06c82 100644 --- a/samples/lib/MetricsHandling.c +++ b/samples/lib/MetricsHandling.c @@ -234,7 +234,7 @@ STATUS populateOutgoingRtpMetricsContext(PSampleStreamingSession pSampleStreamin MUTEX_UNLOCK(pSampleStreamingSession->pStatsCtx->statsUpdateLock); } releaseMetricsCtx(pSampleStreamingSession); - return STATUS_SUCCESS; + return retStatus; } STATUS populateIncomingRtpMetricsContext(PSampleStreamingSession pSampleStreamingSession) From 33437f7516d3c6e884425d4bfed1ae8cc7d59a89 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 20 Jun 2024 10:17:01 -0700 Subject: [PATCH 61/64] unused --- cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp | 11 +++++------ samples/lib/Common.c | 3 ++- tst/JitterBufferFunctionalityTest.cpp | 2 -- 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index f98dad7625..a789856ad7 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -82,20 +82,19 @@ PVOID sendProfilingMetrics(PVOID customData) return NULL; } - while((pSampleConfiguration->sampleStreamingSessionList[0]) == NULL || !ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted) || !(ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag))) { + while((pSampleConfiguration->sampleStreamingSessionList[0]) == NULL && (!(ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted)) || (!(ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag))))) { THREAD_SLEEP(HUNDREDS_OF_NANOS_IN_A_MILLISECOND * 100); } - while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted)) { - if (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted) || - !(ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag))) { - DLOGW("Terminated before we could profile"); - } + if(ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted) || (ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag))) { + DLOGW("Terminated before we could profile"); + return NULL; } while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted) || !(ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag))) { PSampleStreamingSession pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[0]; retStatus = getSdkTimeProfile(&pSampleStreamingSession); if(STATUS_SUCCEEDED(retStatus)) { + DLOGI("Gathered time profile"); CppInteg::Cloudwatch::getInstance().monitoring.pushSignalingClientMetrics(&pSampleConfiguration->signalingClientMetrics); CppInteg::Cloudwatch::getInstance().monitoring.pushPeerConnectionMetrics(&pSampleStreamingSession->peerConnectionMetrics); CppInteg::Cloudwatch::getInstance().monitoring.pushKvsIceAgentMetrics(&pSampleStreamingSession->iceMetrics); diff --git a/samples/lib/Common.c b/samples/lib/Common.c index 62b79239ff..9075823f4f 100644 --- a/samples/lib/Common.c +++ b/samples/lib/Common.c @@ -404,8 +404,9 @@ STATUS freeSampleStreamingSession(PSampleStreamingSession* ppSampleStreamingSess MUTEX_FREE(pSampleStreamingSession->twccMetadata.updateLock); } } - DLOGI("Here....%s", pSampleConfiguration->enableIceStats ? "Enabled" : "Disabled"); + if (pSampleConfiguration->enableIceStats) { + DLOGI("ICE Stats enabled"); CHK_LOG_ERR(gatherIceServerStats(pSampleStreamingSession)); } if (pSampleConfiguration->enableMetrics) { diff --git a/tst/JitterBufferFunctionalityTest.cpp b/tst/JitterBufferFunctionalityTest.cpp index 53f4e0ee48..927403541c 100644 --- a/tst/JitterBufferFunctionalityTest.cpp +++ b/tst/JitterBufferFunctionalityTest.cpp @@ -1146,11 +1146,9 @@ TEST_F(JitterBufferFunctionalityTest, timestampOverflowTest) UINT32 pktCount = 7; UINT32 startingSequenceNumber = 0; UINT32 missingSequenceNumber = 0; - UINT32 firstSequenceNumber = 0; initializeJitterBuffer(4, 0, pktCount); srand(time(0)); startingSequenceNumber = rand()%UINT16_MAX; - firstSequenceNumber = startingSequenceNumber - 1; // First frame "1" mPRtpPackets[0]->payloadLength = 1; From 1c268a059da5bad71356265c6ea9ddba10097499 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Thu, 20 Jun 2024 16:04:50 -0700 Subject: [PATCH 62/64] threadpool lib build --- CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 6b2d53b3cd..0430a9925d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -468,7 +468,14 @@ if(COMPILER_WARNINGS) target_compile_options(kvsWebrtcSignalingClient PUBLIC -Wall -Werror -pedantic -Wextra -Wno-unknown-warning-option) endif() -install(TARGETS kvsWebrtcClient kvsWebrtcSignalingClient kvsWebRtcThreadpool +if(ENABLE_KVS_THREADPOOL) + install(TARGETS kvsWebRtcThreadpool + LIBRARY DESTINATION lib + ARCHIVE DESTINATION lib + ) +endif() + +install(TARGETS kvsWebrtcClient kvsWebrtcSignalingClient LIBRARY DESTINATION lib ARCHIVE DESTINATION lib ) From 68a8480cb533ffed8c27e5b8ad331c1a6d707546 Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Tue, 25 Jun 2024 09:46:19 -0700 Subject: [PATCH 63/64] fix scenario label --- cloudwatch-integ/configs/p_iot_h265_mbedtls.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cloudwatch-integ/configs/p_iot_h265_mbedtls.h b/cloudwatch-integ/configs/p_iot_h265_mbedtls.h index 8003758c52..396af91cc2 100644 --- a/cloudwatch-integ/configs/p_iot_h265_mbedtls.h +++ b/cloudwatch-integ/configs/p_iot_h265_mbedtls.h @@ -9,7 +9,7 @@ extern "C" { #define USE_TRICKLE_ICE TRUE #define FORCE_TURN_ONLY FALSE #define RUNNER_LABEL (PCHAR) "WebrtcPeriodicMBedTLS-H265" -#define SCENARIO_LABEL (PCHAR) "MBedTLSPeriodic" +#define SCENARIO_LABEL (PCHAR) "MbedTLSPeriodic" #define USE_TURN TRUE #define ENABLE_TTFF_VIA_DC FALSE #define USE_IOT TRUE From 7a4a2bc7939b4a941edb4ba39cc0df0aa5156f4f Mon Sep 17 00:00:00 2001 From: Divya Sampath Kumar Date: Mon, 1 Jul 2024 13:13:14 -0700 Subject: [PATCH 64/64] Readme --- README.md | 6 +- cloudwatch-integ/CMakeLists.txt | 2 +- cloudwatch-integ/README.md | 125 ++++++++++++++++++ cloudwatch-integ/configs/default_config.h | 32 +++++ .../configs/lr_iot_h264_mbedtls.h | 1 - .../configs/lr_iot_h264_openssl.h | 1 - .../configs/lr_static_h265_openssl.h | 1 - cloudwatch-integ/configs/p_iot_h265_mbedtls.h | 1 - cloudwatch-integ/configs/p_iot_h265_openssl.h | 1 - .../configs/p_static_h264_mbedtls.h | 1 - cloudwatch-integ/configs/storage_extended.h | 1 - cloudwatch-integ/configs/storage_periodic.h | 1 - .../configs/storage_single_reconnect.h | 1 - .../configs/storage_sub_reconnect.h | 1 - .../kvsWebRTCClientMasterCloudwatch.cpp | 6 +- .../kvsWebRTCClientViewerCloudwatch.cpp | 8 +- 16 files changed, 170 insertions(+), 19 deletions(-) create mode 100644 cloudwatch-integ/README.md create mode 100644 cloudwatch-integ/configs/default_config.h diff --git a/README.md b/README.md index c6a14225a1..d2510cc0ee 100644 --- a/README.md +++ b/README.md @@ -251,11 +251,9 @@ The SDK also tracks entry and exit of functions which increases the verbosity of `add_definitions(-DLOG_STREAMING)` Note: This log level is extremely VERBOSE and could flood the files if using file based logging strategy. -
- Time-to-first-frame breakdown metrics +### Time-to-first-frame breakdown metrics to JS viewer -There is a flag in the sample application which (pSampleConfiguration->enableSendingMetricsToViewerViaDc) can be set to TRUE to send metrics from the master to the [JS viewer](https://awslabs.github.io/amazon-kinesis-video-streams-webrtc-sdk-js/examples/index.html). This helps get a detailed breakdown of time-to-first-frame and all the processes and API calls on master and the viewer both. This is intended to be used with the KVS WebRTC C SDK running as the master and the JS SDK as the viewer. The master sends peer, ice-agent, signaling and data-channel metrics to the viewer which are plotted ~ 20 seconds after the viewer is started. Since the timeline plot is intended to understand the time-to-first-frame, the sample web page needs to be refreshed and the master needs to be restarted if a new / updated plot is needed. While using the SDK in this mode, it is expected that all datachannel messages are JSON messages. This feature is only meant to be used for a single viewer at a time. -
+There is a flag in the sample application which (`pSampleConfiguration->enableSendingMetricsToViewerViaDc`) can be set to TRUE to send metrics from the master to the [JS viewer](https://awslabs.github.io/amazon-kinesis-video-streams-webrtc-sdk-js/examples/index.html). This helps get a detailed breakdown of time-to-first-frame and all the processes and API calls on master and the viewer both. This is intended to be used with the KVS WebRTC C SDK running as the master and the JS SDK as the viewer. The master sends peer, ice-agent, signaling and data-channel metrics to the viewer which are plotted ~ 20 seconds after the viewer is started. Since the timeline plot is intended to understand the time-to-first-frame, the sample web page needs to be refreshed and the master needs to be restarted if a new / updated plot is needed. While using the SDK in this mode, it is expected that all datachannel messages are JSON messages. This feature is only meant to be used for a single viewer at a time. ### Set path to SSL CA certificate (**Optional**) diff --git a/cloudwatch-integ/CMakeLists.txt b/cloudwatch-integ/CMakeLists.txt index 008b40b82b..b2404c2eb3 100644 --- a/cloudwatch-integ/CMakeLists.txt +++ b/cloudwatch-integ/CMakeLists.txt @@ -12,7 +12,7 @@ link_directories(${OPEN_SRC_INSTALL_PREFIX}/lib) find_package(ZLIB REQUIRED) find_package(AWSSDK REQUIRED COMPONENTS monitoring logs) -set(CW_CONFIG_HEADER "configs/lr_static_h265_openssl.h" CACHE FILEPATH "Config header for the cloudwatch integrated demo") +set(CW_CONFIG_HEADER "configs/default_config.h" CACHE FILEPATH "Config header for the cloudwatch integrated demo") add_definitions(-DCW_CONFIG_HEADER="${CW_CONFIG_HEADER}") message(STATUS "Config header set to ${CW_CONFIG_HEADER}") diff --git a/cloudwatch-integ/README.md b/cloudwatch-integ/README.md new file mode 100644 index 0000000000..d0d129fb02 --- /dev/null +++ b/cloudwatch-integ/README.md @@ -0,0 +1,125 @@ +

+ Cloudwatch Integration with Amazon Kinesis Video Streams C WebRTC SDK +
+

+ +The SDK integrates with [AWS SDK CPP](https://github.com/aws/aws-sdk-cpp) to publish runtime performance metrics of the SDK and logs generated by the SDK. + +## Configuration + +The cloudwatch integration demo can be run with different configurations. The list of options that are configurable: +1. `USE_TRICKLE_ICE`: Set this to TRUE, to enable trickle ICE +2. `FORCE_TURN_ONLY`: Set this to TRUE to force TURN usage. By enabling this flag, the connection established would purely be a relay candidate based connection +3. `RUNNER_LABEL`: This label is used as a suffix in the channel name. +4. `SCENARIO_LABEL`: This label is useful in publishing aggregated performance metrics over multiple configurations. For example, if you would like to aggregate outbound frame rate across 5 different cameras, set this label to get an aggregated metric on cloudwatch dashboard +5. `USE_TURN`: Set this to TRUE if the SDK should gather TURN candidates. If set to FALSE, only host and server reflexive candidates are gathered +6. `ENABLE_TTFF_VIA_DC`: Set this to TRUE if timing components of time to first frame should be sent to the JS viewer via data channel. For more information on this feature, refer to +7. `USE_IOT`: Set this to TRUE to use IoT credential provider with the SDK. For more information on setting up an IoT thing, check [SetUp IoT thing](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/how-iot.html) +8. `ENABLE_STORAGE`: Set this to TRUE to run the master peer with storage configuration. For more information on this feature, refer to [WebRTC Storage](https://docs.aws.amazon.com/kinesisvideostreams/latest/dg/API_Operations_Amazon_Kinesis_Video_WebRTC_Storage.html) +9. `ENABLE_METRICS`: Set this to TRUE to allow the demo to collect metrics to publish to cloudwatch. +10. `SAMPLE_PRE_GENERATE_CERT`: Set this to TRUE to allow the SDK to pre-generate certs. For more information on this, refer to [Pre-gen certs](https://github.com/awslabs/amazon-kinesis-video-streams-webrtc-sdk-c?tab=readme-ov-file#use-pre-generated-certificates) +11. `RUN_TIME`: Set this value to the desired run time of the SDK. Set to 0 to collect metrics forever (till application exits by other means) +12. `LOG_GROUP_NAME`: Set this to the desired string to store the logs in cloudwatch. For more information on cloudwatch log groups and streams refer to [cloudwatch logs](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Working-with-log-groups-and-streams.html) +13. `CHANNEL_NAME_PREFIX`: This value is used as a prefix for channel name. The channel name in this demo is of the format -. The prefix can also be passed in as a command line arg if prefered. +14. `AUDIO_CODEC`: Set the desired audio codec from the list of supported `RTC_CODEC`. The allowed values are available [here](https://awslabs.github.io/amazon-kinesis-video-streams-webrtc-sdk-c/group__PublicEnums.html#ga93240fd6a0e599dfb0c69ca76e406665) +15. `VIDEO_CODEC`: Set the desired video codec from the list of supported `RTC_CODEC`. The allowed values are available [here](https://awslabs.github.io/amazon-kinesis-video-streams-webrtc-sdk-c/group__PublicEnums.html#ga93240fd6a0e599dfb0c69ca76e406665) +16. `DEFAULT_BITRATE`: If sending mock frames, this value is useful to test the SDK under different bitrate. +17. `DEFAULT_FRAMERATE`: If sending mock frames, this value is useful to test the SDK under different frame rate conditions. + +The demo project uses a config header file approach to set these values up. The user of the demo is free to modify the applications to set it up any other way. More information on configuring the demo with a custom config file will be available in the next section. + +## Build + +To set up this project, in addition to other desired options, run: + +```shell +mkdir -p amazon-kinesis-video-streams-demos/canary/webrtc-c/build +cd amazon-kinesis-video-streams-demos/canary/webrtc-c/build +cmake .. -DENABLE_AWS_SDK_INTEG=ON +make +``` + +The demo comes with a list of different config files users can choose from. The preset config files are available in the [configs](add link here) folder. By default, the demo is configured to run with `default_config.h`. However, demo users are free to set up their own config file and pass in the absolute path to the file while configuring the demo. To do so, do the following: +```shell +cd amazon-kinesis-video-streams-demos/canary/webrtc-c/build +cmake .. -DENABLE_AWS_SDK_INTEG=ON -DCW_CONFIG_HEADER= +make +``` + +## Run + +To run the demo as master, from the build directory, run: + +```shell +./cloudwatch-integ/kvsWebrtcClientMasterCW +``` + +OR, + +```shell +./cloudwatch-integ/kvsWebrtcClientMasterCW +``` + +To run the demo as viewer, from the build directory, run: + +```shell +./cloudwatch-integ/kvsWebrtcClientViewerCW +``` + +OR, + +```shell +./cloudwatch-integ/kvsWebrtcClientViewerCW +``` + +## Cloudwatch metrics + +The Cloudwatch namespace is set to `KinesisVideoSDKCanary`. Each metric listed below will be emitted twice, one with a label dimension and the other with label and channel dimensions. By omitting the channel dimension, metrics that come from different channel names by with the same label will be aggregated. This can be really useful for a scenario where we want to logically group metrics from different runs, e.g. we have a periodic start/stop scenario and we want to run this scenario with different sets of devices. While it's useful to aggregate these metrics, it's also equally important to keep metrics with the channel dimension to keep the granular access to these metrics. + +| Category | Metric | Unit | Frequency (seconds) | Description | +|--------------------|--------------------------------|-------------------|----------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Shutdown | ExitStatus | Count | - | Every time the Canary runs, it'll post exactly once. If successful, the code will be 0x00000000. | +| Initialization | SignalingInitDelay | Milliseconds | - | Measure the time it takes for Signaling from creation to connected. | +| Initialization | ICEHolePunchingDelay | Milliseconds | - | Measure the time it takes for ICE agent to successfully connect to the other peer. | +| End to End | EndToEndFrameLatency | Milliseconds | 30 | The delay from sending the frame to when the frame is received on the other end | +| End to End | FrameSizeMatch | None | 30 | The decoded canary data (header + frame data) at the receiver end is compared with the received size as part of header). If equal, 1.0 is pushed as a metric, else 0.0 is pushed | +| Outbound RTP Stats | FramesPerSecond | Count_Second | 60 | Measures the rate at which frames are sent out from the master. This is calculated using outboundRtpStats | +| Outbound RTP Stats | PercentageFrameDiscarded | Percent | 60 | This expresses the percentage of frames that dropped on the sending path within a given time interval. This is calculated using outboundRtpStats | +| Outbound RTP Stats | PercentageFramesRetransmitted | Percent | 60 | This expresses the percentage of frames that are retransmitted on the sending path within a given time interval. This is calculated using outboundRtpStats | +| Outbound RTP Stats | NackPerSecond | Count_Second | 60 | Rate at which Nacks are received by master. This is calculated using outboundRtpStats | +| Inbound RTP Stats | IncomingBitRate | Kilobits_Second | 60 | Measures the rate at which frame bits are received by master. This is calculated using inboundRtpStats | +| Inbound RTP Stats | IncomingPacketsPerSecond | Count_Second | 60 | Measures the rate at which packets are received by the master. This is calculated using inboundRtpStats | +| Inbound RTP Stats | IncomingFramesDroppedPerSecond | Count_Second | 60 | Rate at which the incoming frames are dropped. This is calculated using inboundRtpStats | +| End to End | SignalingRoundtripLatency | Milliseconds | 15 | Measure the roundtrip latency from sending an offer to receive an answer | +| Shutdown | ExitStatus | Count | - | Every time the Canary runs, it'll post exactly once. If successful, the code will be 0x00000000. | +| Signaling | CreateCallTime | Milliseconds | - | Measures time taken to create channel | +| Signaling | GetEndpointCallTime | Milliseconds | - | Measures time taken to get data endpoint | +| Signaling | GetTokenTime | Milliseconds | - | Measures time taken to get credentials (AKID or IoT) | +| Signaling | DescribeCallTime | Milliseconds | - | Measures time taken to describe the channel | +| Signaling | GetIceConfigCallTime | Milliseconds | - | Measures time taken to retrieve ICE server config | +| Signaling | ConnectCallTime | Milliseconds | - | Measures time taken to connect to the signaling channel | +| Signaling | CreateClientTotalTime | Milliseconds | - | Measures time taken to retrieve AWS credentials to get started with making signaling calls | +| Signaling | FetchClientTotalTime | Milliseconds | - | Measures time taken to describe, create channel (if applicable) followed by a describe to get the details, get endpoint and get ICE config | +| Signaling | ConnectClientTotalTime | Milliseconds | - | Measures time taken to connect to the signaling as master/viewer | +| Signaling | OfferToAnswerTime | Milliseconds | - | Measures time taken to send out an answer once the offer is received. | +| ICE | LocalCandidateGatheringTime | Milliseconds | - | Measures time taken to gather candidate from local interfaces | +| ICE | HostCandidateSetUpTime | Milliseconds | - | Measures time taken to create socket connections for local candidates and also creates candidate pairs with the available remote candidates | +| ICE | SrflxCandidateSetUpTime | Milliseconds | - | Measures time taken to create socket connections for srflx candidates | +| ICE | RelayCandidateSetUpTime | Milliseconds | - | Measures time taken to create socket connections for relay candidates. Candidate pair formation is done periodically in a timer callback as and when relay address is obtained | +| ICE | IceServerResolutionTime | Milliseconds | - | Measures time taken to DNS resolve ICE URLs | +| ICE | IceCandidatePairNominationTime | Milliseconds | - | Measures time taken to complete nomination of ICE candidate pair | +| ICE | IcecandidateGatheringTime | Milliseconds | - | Measures time taken from starting gathering to when candidate gathering is done i.e when connectivity checks for all the pairs have been sent out or gathering times out. | +| ICE | IceAgentSetUpTime | Milliseconds | - | Measures time taken to complete connectivity checks | +| Peer | PcCreationTime | Milliseconds | - | Measures time taken to create peer connection object after receiving offer | +| Peer | DtlsSetupTime | Milliseconds | - | Measures time taken to complete DTLS initialization process | +| Peer | ICEHolePunchingDelay | Milliseconds | - | Measures time taken from start of connectivity checks to when the candidate pair is nominated and peer connection established | +| Total | TimeToFirstFrame | Milliseconds | - | Measures time taken from offer to sending out first frame | + +## Cloudwatch logs + +The demo emits cloudwatch logs to the Log group `WebrtcSDK` by default. To use a different one, you can set the `LOG_GROUP_NAME` in your config file. The log stream name template is ``, where, mode values are `master`, `viewer` or `StorageMaster` and timestamp is epoch value. + + + + + diff --git a/cloudwatch-integ/configs/default_config.h b/cloudwatch-integ/configs/default_config.h new file mode 100644 index 0000000000..99c1bb9202 --- /dev/null +++ b/cloudwatch-integ/configs/default_config.h @@ -0,0 +1,32 @@ +#ifndef KVS_SDK_SAMPLE_CONFIG_H +#define KVS_SDK_SAMPLE_CONFIG_H + +#pragma once + +#ifdef __cplusplus +extern "C" { +#endif + +#define USE_TRICKLE_ICE TRUE +#define FORCE_TURN_ONLY FALSE +#define RUNNER_LABEL (PCHAR) "testChannel" +#define SCENARIO_LABEL (PCHAR) "LongRun" +#define USE_TURN TRUE +#define ENABLE_TTFF_VIA_DC FALSE +#define USE_IOT TRUE +#define ENABLE_STORAGE FALSE +#define ENABLE_METRICS TRUE +#define SAMPLE_PRE_GENERATE_CERT TRUE +#define RUN_TIME 0 +#define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" +#define CHANNEL_NAME_PREFIX (PCHAR) "sample" +#define AUDIO_CODEC RTC_CODEC_OPUS +#define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE +#define DEFAULT_BITRATE (250 * 1024) +#define DEFAULT_FRAMERATE 30 + +#ifdef __cplusplus +} +#endif + +#endif // KVS_SDK_SAMPLE_CONFIG_H diff --git a/cloudwatch-integ/configs/lr_iot_h264_mbedtls.h b/cloudwatch-integ/configs/lr_iot_h264_mbedtls.h index c12ec9d4bd..d7d45e544d 100644 --- a/cloudwatch-integ/configs/lr_iot_h264_mbedtls.h +++ b/cloudwatch-integ/configs/lr_iot_h264_mbedtls.h @@ -20,7 +20,6 @@ extern "C" { #define RUN_TIME (12 * HUNDREDS_OF_NANOS_IN_AN_HOUR) #define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" #define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" -#define USE_STORAGE FALSE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE #define DEFAULT_BITRATE (250 * 1024) diff --git a/cloudwatch-integ/configs/lr_iot_h264_openssl.h b/cloudwatch-integ/configs/lr_iot_h264_openssl.h index 6083ec55b8..fe76c99135 100644 --- a/cloudwatch-integ/configs/lr_iot_h264_openssl.h +++ b/cloudwatch-integ/configs/lr_iot_h264_openssl.h @@ -20,7 +20,6 @@ extern "C" { #define RUN_TIME (12 * HUNDREDS_OF_NANOS_IN_AN_HOUR) #define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" #define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" -#define USE_STORAGE FALSE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE #define DEFAULT_BITRATE (250 * 1024) diff --git a/cloudwatch-integ/configs/lr_static_h265_openssl.h b/cloudwatch-integ/configs/lr_static_h265_openssl.h index 013dac7029..118f151473 100644 --- a/cloudwatch-integ/configs/lr_static_h265_openssl.h +++ b/cloudwatch-integ/configs/lr_static_h265_openssl.h @@ -19,7 +19,6 @@ extern "C" { #define RUN_TIME (12 * HUNDREDS_OF_NANOS_IN_AN_HOUR) #define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" #define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" -#define USE_STORAGE FALSE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H265 #define DEFAULT_BITRATE (250 * 1024) diff --git a/cloudwatch-integ/configs/p_iot_h265_mbedtls.h b/cloudwatch-integ/configs/p_iot_h265_mbedtls.h index 396af91cc2..30f0a3aafc 100644 --- a/cloudwatch-integ/configs/p_iot_h265_mbedtls.h +++ b/cloudwatch-integ/configs/p_iot_h265_mbedtls.h @@ -19,7 +19,6 @@ extern "C" { #define RUN_TIME (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" #define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" -#define USE_STORAGE FALSE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H265 #define DEFAULT_BITRATE (250 * 1024) diff --git a/cloudwatch-integ/configs/p_iot_h265_openssl.h b/cloudwatch-integ/configs/p_iot_h265_openssl.h index 4a9dfbefd9..004407bedf 100644 --- a/cloudwatch-integ/configs/p_iot_h265_openssl.h +++ b/cloudwatch-integ/configs/p_iot_h265_openssl.h @@ -19,7 +19,6 @@ extern "C" { #define RUN_TIME (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" #define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" -#define USE_STORAGE FALSE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H265 #define DEFAULT_BITRATE (250 * 1024) diff --git a/cloudwatch-integ/configs/p_static_h264_mbedtls.h b/cloudwatch-integ/configs/p_static_h264_mbedtls.h index 264c1f93fd..e7055f73c5 100644 --- a/cloudwatch-integ/configs/p_static_h264_mbedtls.h +++ b/cloudwatch-integ/configs/p_static_h264_mbedtls.h @@ -19,7 +19,6 @@ extern "C" { #define RUN_TIME (30 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" #define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" -#define USE_STORAGE FALSE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE #define DEFAULT_BITRATE (250 * 1024) diff --git a/cloudwatch-integ/configs/storage_extended.h b/cloudwatch-integ/configs/storage_extended.h index 5de07aba3f..63227e221f 100644 --- a/cloudwatch-integ/configs/storage_extended.h +++ b/cloudwatch-integ/configs/storage_extended.h @@ -19,7 +19,6 @@ extern "C" { #define RUN_TIME (43200 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" #define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" -#define USE_STORAGE TRUE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE #define DEFAULT_BITRATE (250 * 1024) diff --git a/cloudwatch-integ/configs/storage_periodic.h b/cloudwatch-integ/configs/storage_periodic.h index ac73448f51..2a766c6db4 100644 --- a/cloudwatch-integ/configs/storage_periodic.h +++ b/cloudwatch-integ/configs/storage_periodic.h @@ -19,7 +19,6 @@ extern "C" { #define RUN_TIME (300 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" #define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" -#define USE_STORAGE TRUE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE #define DEFAULT_BITRATE (250 * 1024) diff --git a/cloudwatch-integ/configs/storage_single_reconnect.h b/cloudwatch-integ/configs/storage_single_reconnect.h index 0ccc3370f6..882bb6007c 100644 --- a/cloudwatch-integ/configs/storage_single_reconnect.h +++ b/cloudwatch-integ/configs/storage_single_reconnect.h @@ -19,7 +19,6 @@ extern "C" { #define RUN_TIME (3900 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" #define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" -#define USE_STORAGE TRUE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE #define DEFAULT_BITRATE (250 * 1024) diff --git a/cloudwatch-integ/configs/storage_sub_reconnect.h b/cloudwatch-integ/configs/storage_sub_reconnect.h index 8eba854053..f057715fbe 100644 --- a/cloudwatch-integ/configs/storage_sub_reconnect.h +++ b/cloudwatch-integ/configs/storage_sub_reconnect.h @@ -19,7 +19,6 @@ extern "C" { #define RUN_TIME (2700 * HUNDREDS_OF_NANOS_IN_A_SECOND) #define LOG_GROUP_NAME (PCHAR) "WebrtcSDK" #define CHANNEL_NAME_PREFIX (PCHAR) "DEFAULT" -#define USE_STORAGE TRUE #define AUDIO_CODEC RTC_CODEC_OPUS #define VIDEO_CODEC RTC_CODEC_H264_PROFILE_42E01F_LEVEL_ASYMMETRY_ALLOWED_PACKETIZATION_MODE #define DEFAULT_BITRATE (250 * 1024) diff --git a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp index a789856ad7..803d24c8cf 100644 --- a/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientMasterCloudwatch.cpp @@ -453,8 +453,10 @@ INT32 main(INT32 argc, CHAR* argv[]) THREAD_CREATE(&profilingThread, sendProfilingMetrics, (PVOID) pSampleConfiguration); - CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, - (UINT64) pSampleConfiguration, &terminateTimerId)); + if(RUN_TIME != 0) { + CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, + (UINT64) pSampleConfiguration, &terminateTimerId)); + } // Checking for termination CHK_STATUS(sessionCleanupWait(pSampleConfiguration)); DLOGI("[KVS Master] Streaming session terminated"); diff --git a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp index cfab4f9ff0..e26a4a8526 100644 --- a/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp +++ b/cloudwatch-integ/kvsWebRTCClientViewerCloudwatch.cpp @@ -275,8 +275,12 @@ INT32 main(INT32 argc, CHAR* argv[]) #endif CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, END_TO_END_METRICS_INVOCATION_PERIOD, END_TO_END_METRICS_INVOCATION_PERIOD, publishEndToEndMetrics, (UINT64) pSampleStreamingSession, &e2eTimerId)); - CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, RUN_TIME, TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, - (UINT64) pSampleConfiguration, &terminateId)); + + if(RUN_TIME != 0) { + CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, RUN_TIME, + TIMER_QUEUE_SINGLE_INVOCATION_PERIOD, terminate, + (UINT64) pSampleConfiguration, &terminateId)); + } CHK_STATUS(timerQueueAddTimer(pSampleConfiguration->timerQueueHandle, END_TO_END_METRICS_INVOCATION_PERIOD, END_TO_END_METRICS_INVOCATION_PERIOD, publishStatsForCanary, (UINT64) pSampleConfiguration, &inboundTimerId)); // Block until interrupted