diff --git a/samples/webrtc/source/Common.c b/samples/webrtc/source/Common.c index 6991c21..9704aca 100644 --- a/samples/webrtc/source/Common.c +++ b/samples/webrtc/source/Common.c @@ -27,6 +27,18 @@ 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 || @@ -37,7 +49,6 @@ STATUS signalingCallFailed(STATUS status) VOID onDataChannelMessage(UINT64 customData, PRtcDataChannel pDataChannel, BOOL isBinary, PBYTE pMessage, UINT32 pMessageLen) { UNUSED_PARAM(customData); - UNUSED_PARAM(pDataChannel); if (isBinary) { DLOGI("DataChannel Binary Message"); } else { @@ -61,7 +72,6 @@ VOID onConnectionStateChange(UINT64 customData, RTC_PEER_CONNECTION_STATE newSta { STATUS retStatus = STATUS_SUCCESS; PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; - CHK(pSampleStreamingSession != NULL && pSampleStreamingSession->pSampleConfiguration != NULL, STATUS_INTERNAL_ERROR); PSampleConfiguration pSampleConfiguration = pSampleStreamingSession->pSampleConfiguration; @@ -71,6 +81,10 @@ 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); + + CHK_STATUS(peerConnectionGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->peerConnectionMetrics)); + CHK_STATUS(iceAgentGetMetrics(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->iceMetrics)); + if (STATUS_FAILED(retStatus = logSelectedIceCandidatesInformation(pSampleStreamingSession))) { DLOGW("Failed to get information about selected Ice candidates: 0x%08x", retStatus); } @@ -86,6 +100,7 @@ VOID onConnectionStateChange(UINT64 customData, RTC_PEER_CONNECTION_STATE newSta default: ATOMIC_STORE_BOOL(&pSampleConfiguration->connected, FALSE); CVAR_BROADCAST(pSampleConfiguration->cvar); + break; } @@ -174,7 +189,9 @@ PVOID mediaSenderRoutine(PVOID customData) { STATUS retStatus = STATUS_SUCCESS; PSampleConfiguration pSampleConfiguration = (PSampleConfiguration) customData; - TID videoSenderTid = INVALID_TID_VALUE, audioSenderTid = INVALID_TID_VALUE; + 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)) { @@ -185,19 +202,19 @@ PVOID mediaSenderRoutine(PVOID customData) CHK(!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag), retStatus); if (pSampleConfiguration->videoSource != NULL) { - THREAD_CREATE(&videoSenderTid, pSampleConfiguration->videoSource, (PVOID) pSampleConfiguration); + THREAD_CREATE(&pSampleConfiguration->videoSenderTid, pSampleConfiguration->videoSource, (PVOID) pSampleConfiguration); } if (pSampleConfiguration->audioSource != NULL) { - THREAD_CREATE(&audioSenderTid, pSampleConfiguration->audioSource, (PVOID) pSampleConfiguration); + THREAD_CREATE(&pSampleConfiguration->audioSenderTid, pSampleConfiguration->audioSource, (PVOID) pSampleConfiguration); } - if (videoSenderTid != INVALID_TID_VALUE) { - THREAD_JOIN(videoSenderTid, NULL); + if (pSampleConfiguration->videoSenderTid != INVALID_TID_VALUE) { + THREAD_JOIN(pSampleConfiguration->videoSenderTid, NULL); } - if (audioSenderTid != INVALID_TID_VALUE) { - THREAD_JOIN(audioSenderTid, NULL); + if (pSampleConfiguration->audioSenderTid != INVALID_TID_VALUE) { + THREAD_JOIN(pSampleConfiguration->audioSenderTid, NULL); } CleanUp: @@ -233,8 +250,6 @@ STATUS handleOffer(PSampleConfiguration pSampleConfiguration, PSampleStreamingSe if (pSampleStreamingSession->remoteCanTrickleIce) { CHK_STATUS(createAnswer(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->answerSessionDescriptionInit)); CHK_STATUS(respondWithAnswer(pSampleStreamingSession)); - DLOGD("time taken to send answer %" PRIu64 " ms", - (GETTIME() - pSampleStreamingSession->offerReceiveTime) / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); } mediaThreadStarted = ATOMIC_EXCHANGE_BOOL(&pSampleConfiguration->mediaThreadStarted, TRUE); @@ -258,16 +273,23 @@ STATUS sendSignalingMessage(PSampleStreamingSession pSampleStreamingSession, PSi { STATUS retStatus = STATUS_SUCCESS; BOOL locked = FALSE; - + PSampleConfiguration pSampleConfiguration; // Validate the input params CHK(pSampleStreamingSession != NULL && pSampleStreamingSession->pSampleConfiguration != NULL && pMessage != NULL, STATUS_NULL_ARG); - CHK(IS_VALID_MUTEX_VALUE(pSampleStreamingSession->pSampleConfiguration->signalingSendMessageLock) && - IS_VALID_SIGNALING_CLIENT_HANDLE(pSampleStreamingSession->pSampleConfiguration->signalingClientHandle), + + pSampleConfiguration = pSampleStreamingSession->pSampleConfiguration; + + CHK(IS_VALID_MUTEX_VALUE(pSampleConfiguration->signalingSendMessageLock) && + IS_VALID_SIGNALING_CLIENT_HANDLE(pSampleConfiguration->signalingClientHandle), STATUS_INVALID_OPERATION); - MUTEX_LOCK(pSampleStreamingSession->pSampleConfiguration->signalingSendMessageLock); + MUTEX_LOCK(pSampleConfiguration->signalingSendMessageLock); locked = TRUE; - CHK_STATUS(signalingClientSendMessageSync(pSampleStreamingSession->pSampleConfiguration->signalingClientHandle, pMessage)); + CHK_STATUS(signalingClientSendMessageSync(pSampleConfiguration->signalingClientHandle, pMessage)); + if (pMessage->messageType == SIGNALING_MESSAGE_TYPE_ANSWER) { + CHK_STATUS(signalingClientGetMetrics(pSampleConfiguration->signalingClientHandle, &pSampleConfiguration->signalingClientMetrics)); + DLOGP("[Signaling offer to answer] %" PRIu64 " ms", pSampleConfiguration->signalingClientMetrics.signalingClientStats.offerToAnswerTime); + } CleanUp: @@ -329,8 +351,6 @@ VOID onIceCandidateHandler(UINT64 customData, PCHAR candidateJson) !pSampleStreamingSession->remoteCanTrickleIce) { CHK_STATUS(createAnswer(pSampleStreamingSession->pPeerConnection, &pSampleStreamingSession->answerSessionDescriptionInit)); CHK_STATUS(respondWithAnswer(pSampleStreamingSession)); - DLOGD("time taken to send answer %" PRIu64 " ms", - (GETTIME() - pSampleStreamingSession->offerReceiveTime) / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); } else if (pSampleStreamingSession->pSampleConfiguration->channelInfo.channelRoleType == SIGNALING_CHANNEL_ROLE_TYPE_VIEWER && !pSampleStreamingSession->pSampleConfiguration->trickleIce) { CVAR_BROADCAST(pSampleStreamingSession->pSampleConfiguration->cvar); @@ -400,7 +420,7 @@ STATUS initializePeerConnection(PSampleConfiguration pSampleConfiguration, PRtcP RtcConfiguration configuration; UINT32 i, j, iceConfigCount, uriCount = 0, maxTurnServer = 1; PIceConfigInfo pIceConfigInfo; - UINT64 data, curTime; + UINT64 data; PRtcCertificate pRtcCertificate = NULL; CHK(pSampleConfiguration != NULL && ppRtcPeerConnection != NULL, STATUS_NULL_ARG); @@ -440,7 +460,7 @@ STATUS initializePeerConnection(PSampleConfiguration pSampleConfiguration, PRtcP * if configuration.iceServers[uriCount + 1].urls is "turn:ip:port?transport=tcp" then ICE will try TURN over TCP/TLS * if configuration.iceServers[uriCount + 1].urls is "turns:ip:port?transport=udp", it's currently ignored because sdk dont do TURN * over DTLS yet. if configuration.iceServers[uriCount + 1].urls is "turns:ip:port?transport=tcp" then ICE will try TURN over TCP/TLS - * if configuration.iceServers[uriCount + 1].urls is "turn:ip:port" then ICE will try both TURN over UPD and TCP/TLS + * if configuration.iceServers[uriCount + 1].urls is "turn:ip:port" then ICE will try both TURN over UDP and TCP/TLS * * It's recommended to not pass too many TURN iceServers to configuration because it will slow down ice gathering in non-trickle mode. */ @@ -478,10 +498,7 @@ STATUS initializePeerConnection(PSampleConfiguration pSampleConfiguration, PRtcP configuration.certificates[0] = *pRtcCertificate; } - curTime = GETTIME(); CHK_STATUS(createPeerConnection(&configuration, ppRtcPeerConnection)); - DLOGD("time taken to create peer connection %" PRIu64 " ms", (GETTIME() - curTime) / HUNDREDS_OF_NANOS_IN_A_MILLISECOND); - CleanUp: CHK_LOG_ERR(retStatus); @@ -533,6 +550,8 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P CHK((isMaster && peerId != NULL) || !isMaster, STATUS_INVALID_ARG); pSampleStreamingSession = (PSampleStreamingSession) MEMCALLOC(1, SIZEOF(SampleStreamingSession)); + pSampleStreamingSession->firstFrame = TRUE; + pSampleStreamingSession->offerReceiveTime = GETTIME(); CHK(pSampleStreamingSession != NULL, STATUS_NOT_ENOUGH_MEMORY); if (isMaster) { @@ -542,8 +561,15 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P } ATOMIC_STORE_BOOL(&pSampleStreamingSession->peerIdReceived, TRUE); + pSampleStreamingSession->pAudioRtcRtpTransceiver = NULL; + pSampleStreamingSession->pVideoRtcRtpTransceiver = NULL; + pSampleStreamingSession->pSampleConfiguration = pSampleConfiguration; pSampleStreamingSession->rtcMetricsHistory.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; @@ -589,7 +615,6 @@ STATUS createSampleStreamingSession(PSampleConfiguration pSampleConfiguration, P // twcc bandwidth estimation CHK_STATUS(peerConnectionOnSenderBandwidthEstimation(pSampleStreamingSession->pPeerConnection, (UINT64) pSampleStreamingSession, sampleSenderBandwidthEstimationHandler)); - pSampleStreamingSession->firstFrame = TRUE; pSampleStreamingSession->startUpLatency = 0; CleanUp: @@ -648,7 +673,6 @@ STATUS freeSampleStreamingSession(PSampleStreamingSession* ppSampleStreamingSess CHK_LOG_ERR(retStatus); - DLOGD("Freed streaming session"); return retStatus; } @@ -667,16 +691,16 @@ STATUS streamingSessionOnShutdown(PSampleStreamingSession pSampleStreamingSessio return retStatus; } -VOID sampleFrameHandler(UINT64 customData, PFrame pFrame) +VOID sampleVideoFrameHandler(UINT64 customData, PFrame pFrame) { UNUSED_PARAM(customData); - DLOGV("Frame received. TrackId: %" PRIu64 ", Size: %u, Flags %u", pFrame->trackId, pFrame->size, pFrame->flags); - PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) customData; - if (pSampleStreamingSession->firstFrame) { - pSampleStreamingSession->firstFrame = FALSE; - pSampleStreamingSession->startUpLatency = (GETTIME() - pSampleStreamingSession->offerReceiveTime) / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; - printf("Start up latency from offer to first frame: %" PRIu64 "ms\n", pSampleStreamingSession->startUpLatency); - } + DLOGV("Video Frame received. TrackId: %" PRIu64 ", Size: %u, Flags %u", pFrame->trackId, pFrame->size, pFrame->flags); +} + +VOID sampleAudioFrameHandler(UINT64 customData, PFrame pFrame) +{ + UNUSED_PARAM(customData); + DLOGV("Audio Frame received. TrackId: %" PRIu64 ", Size: %u, Flags %u", pFrame->trackId, pFrame->size, pFrame->flags); } VOID sampleBandwidthEstimationHandler(UINT64 customData, DOUBLE maximumBitrate) @@ -780,20 +804,19 @@ STATUS lookForSslCert(PSampleConfiguration* ppSampleConfiguration) return retStatus; } -STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE roleType, BOOL trickleIce, BOOL useTurn, +STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE roleType, BOOL trickleIce, BOOL useTurn, UINT32 logLevel, PSampleConfiguration* ppSampleConfiguration) { STATUS retStatus = STATUS_SUCCESS; - PCHAR pAccessKey, pSecretKey, pSessionToken, pLogLevel; + PCHAR pAccessKey, pSecretKey, pSessionToken; PSampleConfiguration pSampleConfiguration = NULL; - UINT32 logLevel = LOG_LEVEL_DEBUG; 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, pIotCoreThingName; + PCHAR pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pIotCoreRoleAlias; 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"); @@ -805,24 +828,37 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE #endif pSessionToken = getenv(SESSION_TOKEN_ENV_VAR); - pSampleConfiguration->enableFileLogging = FALSE; + + // 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)) { - pSampleConfiguration->enableFileLogging = TRUE; + retStatus = createFileLoggerWithLevelFiltering(FILE_LOGGING_BUFFER_SIZE, MAX_NUMBER_OF_LOG_FILES, (PCHAR) FILE_LOGGER_LOG_FILE_DIRECTORY_PATH, + TRUE, TRUE, TRUE, LOG_LEVEL_PROFILE, NULL); + + if (retStatus != STATUS_SUCCESS) { + DLOGW("[KVS Master] createFileLogger(): operation returned status code: 0x%08x", retStatus); + } else { + pSampleConfiguration->enableFileLogging = TRUE; + pSampleConfiguration->enableFileLogging = TRUE; + pSampleConfiguration->enableFileLogging = TRUE; + } + } else { + retStatus = createFileLoggerWithLevelFiltering(FILE_LOGGING_BUFFER_SIZE, MAX_NUMBER_OF_LOG_FILES, (PCHAR) FILE_LOGGER_LOG_FILE_DIRECTORY_PATH, + TRUE, TRUE, FALSE, LOG_LEVEL_PROFILE, NULL); + + if (retStatus != STATUS_SUCCESS) { + DLOGW("[KVS Master] createFileLogger(): operation returned status code: 0x%08x", retStatus); + } else { + pSampleConfiguration->enableFileLogging = TRUE; + } } + if ((pSampleConfiguration->channelInfo.pRegion = getenv(DEFAULT_REGION_ENV_VAR)) == NULL) { pSampleConfiguration->channelInfo.pRegion = DEFAULT_AWS_REGION; } CHK_STATUS(lookForSslCert(&pSampleConfiguration)); - // Set the logger log level - 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); - #ifdef IOT_CORE_ENABLE_CREDENTIALS CHK_STATUS(createLwsIotCredentialProvider(pIotCoreCredentialEndPoint, pIotCoreCert, pIotCorePrivateKey, pSampleConfiguration->pCaCertPath, pIotCoreRoleAlias, channelName, &pSampleConfiguration->pCredentialProvider)); @@ -832,6 +868,8 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE #endif pSampleConfiguration->mediaSenderTid = INVALID_TID_VALUE; + pSampleConfiguration->audioSenderTid = INVALID_TID_VALUE; + pSampleConfiguration->videoSenderTid = INVALID_TID_VALUE; pSampleConfiguration->signalingClientHandle = INVALID_SIGNALING_CLIENT_HANDLE_VALUE; pSampleConfiguration->sampleConfigurationObjLock = MUTEX_CREATE(TRUE); pSampleConfiguration->cvar = CVAR_CREATE(); @@ -866,8 +904,11 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE pSampleConfiguration->clientInfo.loggingLevel = logLevel; pSampleConfiguration->clientInfo.cacheFilePath = NULL; // Use the default path pSampleConfiguration->clientInfo.signalingClientCreationMaxRetryAttempts = CREATE_SIGNALING_CLIENT_RETRY_ATTEMPTS_SENTINEL_VALUE; + pSampleConfiguration->clientInfo.signalingMessagesMinimumThreads = KVS_SIGNALING_THREADPOOL_MIN; + pSampleConfiguration->clientInfo.signalingMessagesMaximumThreads = KVS_SIGNALING_THREADPOOL_MAX; pSampleConfiguration->iceCandidatePairStatsTimerId = MAX_UINT32; pSampleConfiguration->pregenerateCertTimerId = MAX_UINT32; + pSampleConfiguration->signalingClientMetrics.version = SIGNALING_CLIENT_METRICS_CURRENT_VERSION; ATOMIC_STORE_BOOL(&pSampleConfiguration->interrupted, FALSE); ATOMIC_STORE_BOOL(&pSampleConfiguration->mediaThreadStarted, FALSE); @@ -905,6 +946,38 @@ STATUS createSampleConfiguration(PCHAR channelName, SIGNALING_CHANNEL_ROLE_TYPE return retStatus; } +STATUS initSignaling(PSampleConfiguration pSampleConfiguration, PCHAR clientId) +{ + STATUS retStatus = STATUS_SUCCESS; + SignalingClientMetrics signalingClientMetrics = pSampleConfiguration->signalingClientMetrics; + pSampleConfiguration->signalingClientCallbacks.messageReceivedFn = signalingMessageReceived; + STRCPY(pSampleConfiguration->clientInfo.clientId, clientId); + CHK_STATUS(createSignalingClientSync(&pSampleConfiguration->clientInfo, &pSampleConfiguration->channelInfo, + &pSampleConfiguration->signalingClientCallbacks, pSampleConfiguration->pCredentialProvider, + &pSampleConfiguration->signalingClientHandle)); + + // Enable the processing of the messages + CHK_STATUS(signalingClientFetchSync(pSampleConfiguration->signalingClientHandle)); + CHK_STATUS(signalingClientConnectSync(pSampleConfiguration->signalingClientHandle)); + + signalingClientGetMetrics(pSampleConfiguration->signalingClientHandle, &signalingClientMetrics); + + // Logging this here since the logs in signaling library do not get routed to file + DLOGP("[Signaling Get token] %" PRIu64 " ms", signalingClientMetrics.signalingClientStats.getTokenCallTime); + DLOGP("[Signaling Describe] %" PRIu64 " ms", signalingClientMetrics.signalingClientStats.describeCallTime); + DLOGP("[Signaling Create Channel] %" PRIu64 " ms", signalingClientMetrics.signalingClientStats.createCallTime); + DLOGP("[Signaling Get endpoint] %" PRIu64 " ms", signalingClientMetrics.signalingClientStats.getEndpointCallTime); + DLOGP("[Signaling Get ICE config] %" PRIu64 " ms", signalingClientMetrics.signalingClientStats.getIceConfigCallTime); + DLOGP("[Signaling Connect] %" PRIu64 " ms", signalingClientMetrics.signalingClientStats.connectCallTime); + DLOGP("[Signaling create client] %" PRIu64 " ms", signalingClientMetrics.signalingClientStats.createClientTime); + DLOGP("[Signaling fetch client] %" PRIu64 " ms", signalingClientMetrics.signalingClientStats.fetchClientTime); + DLOGP("[Signaling connect client] %" PRIu64 " ms", signalingClientMetrics.signalingClientStats.connectClientTime); + pSampleConfiguration->signalingClientMetrics = signalingClientMetrics; + gSampleConfiguration = pSampleConfiguration; +CleanUp: + return retStatus; +} + STATUS logSignalingClientStats(PSignalingClientMetrics pSignalingClientMetrics) { ENTERS(); @@ -947,9 +1020,12 @@ STATUS getIceCandidatePairStatsCallback(UINT32 timerId, UINT64 currentTime, UINT pSampleConfiguration->rtcIceCandidatePairMetrics.requestedTypeOfStats = RTC_STATS_TYPE_CANDIDATE_PAIR; - // We need to execute this under the object lock due to race conditions that it could pose - MUTEX_LOCK(pSampleConfiguration->sampleConfigurationObjLock); - locked = TRUE; + // 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, @@ -1092,7 +1168,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, @@ -1192,7 +1267,9 @@ STATUS freeSampleConfiguration(PSampleConfiguration* ppSampleConfiguration) CHK_LOG_ERR(stackQueueFree(pSampleConfiguration->pregeneratedCertificates)); pSampleConfiguration->pregeneratedCertificates = NULL; } - + if (pSampleConfiguration->enableFileLogging) { + freeFileLogger(); + } SAFE_MEMFREE(*ppSampleConfiguration); CleanUp: @@ -1207,7 +1284,7 @@ STATUS sessionCleanupWait(PSampleConfiguration pSampleConfiguration) STATUS retStatus = STATUS_SUCCESS; PSampleStreamingSession pSampleStreamingSession = NULL; UINT32 i, clientIdHash; - BOOL locked = FALSE, peerConnectionFound = FALSE; + BOOL sampleConfigurationObjLockLocked = FALSE, streamingSessionListReadLockLocked = FALSE, peerConnectionFound = FALSE; SIGNALING_CLIENT_STATE signalingClientState; CHK(pSampleConfiguration != NULL, STATUS_NULL_ARG); @@ -1215,7 +1292,7 @@ STATUS sessionCleanupWait(PSampleConfiguration pSampleConfiguration) while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->interrupted)) { // Keep the main set of operations interlocked until cvar wait which would atomically unlock MUTEX_LOCK(pSampleConfiguration->sampleConfigurationObjLock); - locked = TRUE; + sampleConfigurationObjLockLocked = TRUE; // scan and cleanup terminated streaming session for (i = 0; i < pSampleConfiguration->streamingSessionCount; ++i) { @@ -1223,6 +1300,7 @@ STATUS sessionCleanupWait(PSampleConfiguration pSampleConfiguration) pSampleStreamingSession = pSampleConfiguration->sampleStreamingSessionList[i]; MUTEX_LOCK(pSampleConfiguration->streamingSessionListReadLock); + streamingSessionListReadLockLocked = TRUE; // swap with last element and decrement count pSampleConfiguration->streamingSessionCount--; @@ -1237,6 +1315,7 @@ STATUS sessionCleanupWait(PSampleConfiguration pSampleConfiguration) } MUTEX_UNLOCK(pSampleConfiguration->streamingSessionListReadLock); + streamingSessionListReadLockLocked = FALSE; CHK_STATUS(freeSampleStreamingSession(&pSampleStreamingSession)); } @@ -1271,17 +1350,21 @@ STATUS sessionCleanupWait(PSampleConfiguration pSampleConfiguration) // periodically wake up and clean up terminated streaming session CVAR_WAIT(pSampleConfiguration->cvar, pSampleConfiguration->sampleConfigurationObjLock, SAMPLE_SESSION_CLEANUP_WAIT_PERIOD); MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); - locked = FALSE; + sampleConfigurationObjLockLocked = FALSE; } CleanUp: CHK_LOG_ERR(retStatus); - if (locked) { + if (sampleConfigurationObjLockLocked) { MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); } + if (streamingSessionListReadLockLocked) { + MUTEX_UNLOCK(pSampleConfiguration->streamingSessionListReadLock); + } + LEAVES(); return retStatus; } @@ -1354,6 +1437,7 @@ STATUS signalingMessageReceived(UINT64 customData, PReceivedSignalingMessage pRe * 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."); @@ -1367,7 +1451,6 @@ STATUS signalingMessageReceived(UINT64 customData, PReceivedSignalingMessage pRe } CHK_STATUS(createSampleStreamingSession(pSampleConfiguration, pReceivedSignalingMessage->signalingMessage.peerClientId, TRUE, &pSampleStreamingSession)); - pSampleStreamingSession->offerReceiveTime = GETTIME(); MUTEX_LOCK(pSampleConfiguration->streamingSessionListReadLock); pSampleConfiguration->sampleStreamingSessionList[pSampleConfiguration->streamingSessionCount++] = pSampleStreamingSession; MUTEX_UNLOCK(pSampleConfiguration->streamingSessionListReadLock); @@ -1408,6 +1491,10 @@ STATUS signalingMessageReceived(UINT64 customData, PReceivedSignalingMessage pRe // 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 to answer] %" PRIu64 " ms", pSampleConfiguration->signalingClientMetrics.signalingClientStats.offerToAnswerTime); break; case SIGNALING_MESSAGE_TYPE_ICE_CANDIDATE: diff --git a/samples/webrtc/source/Samples.h b/samples/webrtc/source/Samples.h index 578debd..e396ffb 100644 --- a/samples/webrtc/source/Samples.h +++ b/samples/webrtc/source/Samples.h @@ -48,7 +48,7 @@ extern "C" { #define CA_CERT_PEM_FILE_EXTENSION ".pem" -#define FILE_LOGGING_BUFFER_SIZE (100 * 1024) +#define FILE_LOGGING_BUFFER_SIZE (10 * 1024) #define MAX_NUMBER_OF_LOG_FILES 5 #define SAMPLE_HASH_TABLE_BUCKET_COUNT 50 @@ -59,10 +59,18 @@ extern "C" { #define IOT_CORE_PRIVATE_KEY ((PCHAR) "AWS_IOT_CORE_PRIVATE_KEY") #define IOT_CORE_ROLE_ALIAS ((PCHAR) "AWS_IOT_CORE_ROLE_ALIAS") #define IOT_CORE_THING_NAME ((PCHAR) "AWS_IOT_CORE_THING_NAME") +#define IOT_CORE_CERTIFICATE_ID ((PCHAR) "AWS_IOT_CORE_CERTIFICATE_ID") #define MASTER_DATA_CHANNEL_MESSAGE "This message is from the KVS Master" #define VIEWER_DATA_CHANNEL_MESSAGE "This message is from the KVS Viewer" +// Signaling client threadpool for handling messages +#define KVS_SIGNALING_THREADPOOL_MIN 3 +#define KVS_SIGNALING_THREADPOOL_MAX 5 + +// comment out this line to disable the feature +#define KVS_USE_SIGNALING_CHANNEL_THREADPOOL 1 + /* Uncomment the following line in order to enable IoT credentials checks in the provided samples */ // #define IOT_CORE_ENABLE_CREDENTIALS 1 @@ -74,6 +82,12 @@ typedef enum { SAMPLE_STREAMING_AUDIO_VIDEO, } SampleStreamingMediaType; +typedef enum { + TEST_SOURCE, + DEVICE_SOURCE, + RTSP_SOURCE, +} SampleSourceType; + typedef struct __SampleStreamingSession SampleStreamingSession; typedef struct __SampleStreamingSession* PSampleStreamingSession; @@ -92,7 +106,7 @@ typedef struct { volatile ATOMIC_BOOL mediaThreadStarted; volatile ATOMIC_BOOL recreateSignalingClient; volatile ATOMIC_BOOL connected; - BOOL useTestSrc; + SampleSourceType srcType; ChannelInfo channelInfo; PCHAR pCaCertPath; PAwsCredentialProvider pCredentialProvider; @@ -102,6 +116,8 @@ typedef struct { PBYTE pVideoFrameBuffer; UINT32 videoBufferSize; TID mediaSenderTid; + TID audioSenderTid; + TID videoSenderTid; TIMER_QUEUE_HANDLE timerQueueHandle; UINT32 iceCandidatePairStatsTimerId; SampleStreamingMediaType mediaType; @@ -109,6 +125,7 @@ typedef struct { startRoutine videoSource; startRoutine receiveAudioVideoSource; RtcOnDataChannel onDataChannel; + SignalingClientMetrics signalingClientMetrics; PStackQueue pPendingSignalingMessageForRemoteClient; PHashTable pRtcPeerConnectionForRemoteClient; @@ -131,6 +148,7 @@ typedef struct { UINT32 pregenerateCertTimerId; PStackQueue pregeneratedCertificates; // Max MAX_RTCCONFIGURATION_CERTIFICATES certificates + UINT32 logLevel; } SampleConfiguration, *PSampleConfiguration; typedef struct { @@ -145,6 +163,7 @@ struct __SampleStreamingSession { volatile ATOMIC_BOOL terminateFlag; volatile ATOMIC_BOOL candidateGatheringDone; volatile ATOMIC_BOOL peerIdReceived; + volatile ATOMIC_BOOL firstFrame; volatile SIZE_T frameIndex; PRtcPeerConnection pPeerConnection; PRtcRtpTransceiver pVideoRtcRtpTransceiver; @@ -155,15 +174,16 @@ struct __SampleStreamingSession { UINT64 videoTimestamp; CHAR peerId[MAX_SIGNALING_CLIENT_ID_LEN + 1]; TID receiveAudioVideoSenderTid; - UINT64 offerReceiveTime; UINT64 startUpLatency; - BOOL firstFrame; RtcMetricsHistory rtcMetricsHistory; BOOL remoteCanTrickleIce; // this is called when the SampleStreamingSession is being freed StreamSessionShutdownCallback shutdownCallback; UINT64 shutdownCallbackCustomData; + UINT64 offerReceiveTime; + PeerConnectionMetrics peerConnectionMetrics; + KvsIceAgentMetrics iceMetrics; }; VOID sigintHandler(INT32); @@ -171,11 +191,11 @@ STATUS readFrameFromDisk(PBYTE, PUINT32, PCHAR); PVOID sendVideoPackets(PVOID); PVOID sendAudioPackets(PVOID); PVOID sendGstreamerAudioVideo(PVOID); -PVOID sampleReceiveAudioVideoFrame(PVOID args); +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, PSampleConfiguration*); +STATUS createSampleConfiguration(PCHAR, SIGNALING_CHANNEL_ROLE_TYPE, BOOL, BOOL, UINT32, PSampleConfiguration*); STATUS freeSampleConfiguration(PSampleConfiguration*); STATUS signalingClientStateChanged(UINT64, SIGNALING_CLIENT_STATE); STATUS signalingMessageReceived(UINT64, PReceivedSignalingMessage); @@ -190,7 +210,8 @@ STATUS streamingSessionOnShutdown(PSampleStreamingSession, UINT64, StreamSession STATUS sendSignalingMessage(PSampleStreamingSession, PSignalingMessage); STATUS respondWithAnswer(PSampleStreamingSession); STATUS resetSampleConfigurationState(PSampleConfiguration); -VOID sampleFrameHandler(UINT64, PFrame); +VOID sampleVideoFrameHandler(UINT64, PFrame); +VOID sampleAudioFrameHandler(UINT64, PFrame); VOID sampleBandwidthEstimationHandler(UINT64, DOUBLE); VOID sampleSenderBandwidthEstimationHandler(UINT64, UINT32, UINT32, UINT32, UINT32, UINT64); VOID onDataChannel(UINT64, PRtcDataChannel); @@ -204,7 +225,9 @@ STATUS freeMessageQueue(PPendingMessageQueue); STATUS submitPendingIceCandidate(PPendingMessageQueue, PSampleStreamingSession); STATUS removeExpiredMessageQueues(PStackQueue); STATUS getPendingMessageQueueForHash(PStackQueue, UINT64, BOOL, PPendingMessageQueue*); +STATUS initSignaling(PSampleConfiguration, PCHAR); BOOL sampleFilterNetworkInterfaces(UINT64, PCHAR); +UINT32 setLogLevel(); #ifdef __cplusplus } diff --git a/samples/webrtc/source/kvsWebRTCClientMaster.c b/samples/webrtc/source/kvsWebRTCClientMaster.c index b3cee2e..86e37b7 100644 --- a/samples/webrtc/source/kvsWebRTCClientMaster.c +++ b/samples/webrtc/source/kvsWebRTCClientMaster.c @@ -30,7 +30,7 @@ static VideoCapturerHandle videoCapturerHandle = NULL; static void sessionOnShutdown(UINT64 customData, PSampleStreamingSession pSampleStreamingSession) { - printf("Shut down session %s\n", pSampleStreamingSession->peerId); + DLOGD("Shut down session %s\n", pSampleStreamingSession->peerId); audioPlayerReleaseStream(audioPlayerHandle); } @@ -43,12 +43,12 @@ static void remoteAudioFrameHandler(UINT64 customData, PFrame pFrame) if (pSampleStreamingSession->firstFrame) { pSampleStreamingSession->firstFrame = FALSE; pSampleStreamingSession->startUpLatency = (GETTIME() - pSampleStreamingSession->offerReceiveTime) / HUNDREDS_OF_NANOS_IN_A_MILLISECOND; - printf("Start up latency from offer to first frame: %" PRIu64 "ms\n", pSampleStreamingSession->startUpLatency); + DLOGI("Start up latency from offer to first frame: %" PRIu64 "ms\n", pSampleStreamingSession->startUpLatency); streamingSessionOnShutdown(pSampleStreamingSession, NULL, sessionOnShutdown); if (audioPlayerAcquireStream(audioPlayerHandle)) { - printf("audioPlayerAcquireStream failed"); + DLOGE("audioPlayerAcquireStream failed"); } } @@ -70,7 +70,7 @@ static void writeFrameToAllSessions(const UINT64 timestamp, PVOID pData, const S } else if (!STRNCMP(trackId, SAMPLE_AUDIO_TRACK_ID, STRLEN(SAMPLE_AUDIO_TRACK_ID))) { isVideo = FALSE; } else { - printf("unknown trackId: %s", trackId); + DLOGE("unknown trackId: %s", trackId); return; } @@ -83,9 +83,10 @@ static void writeFrameToAllSessions(const UINT64 timestamp, PVOID pData, const S } if (status != STATUS_SRTP_NOT_READY_YET) { if (status != STATUS_SUCCESS) { -#ifdef VERBOSE - printf("writeFrame() failed with 0x%08x\n", status); -#endif + DLOGV("writeFrame() failed with 0x%08x", status); + } else if (gSampleConfiguration->sampleStreamingSessionList[i]->firstFrame && status == STATUS_SUCCESS) { + PROFILE_WITH_START_TIME(gSampleConfiguration->sampleStreamingSessionList[i]->offerReceiveTime, "Time to first frame"); + gSampleConfiguration->sampleStreamingSessionList[i]->firstFrame = FALSE; } } } @@ -97,11 +98,12 @@ INT32 main(INT32 argc, CHAR* argv[]) STATUS retStatus = STATUS_SUCCESS; UINT32 frameSize; PSampleConfiguration pSampleConfiguration = NULL; - SignalingClientMetrics signalingClientMetrics; PCHAR pChannelName; + SignalingClientMetrics signalingClientMetrics; signalingClientMetrics.version = SIGNALING_CLIENT_METRICS_CURRENT_VERSION; SET_INSTRUMENTED_ALLOCATORS(); + UINT32 logLevel = setLogLevel(); #ifndef _WIN32 signal(SIGINT, sigintHandler); @@ -159,22 +161,7 @@ INT32 main(INT32 argc, CHAR* argv[]) pChannelName = argc > 1 ? argv[1] : SAMPLE_CHANNEL_NAME; #endif - retStatus = createSampleConfiguration(pChannelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, &pSampleConfiguration); - if (retStatus != STATUS_SUCCESS) { - printf("[KVS Master] createSampleConfiguration(): operation returned status code: 0x%08x \n", retStatus); - goto CleanUp; - } - - printf("[KVS Master] Created signaling channel %s\n", pChannelName); - - if (pSampleConfiguration->enableFileLogging) { - retStatus = - createFileLogger(FILE_LOGGING_BUFFER_SIZE, MAX_NUMBER_OF_LOG_FILES, (PCHAR) FILE_LOGGER_LOG_FILE_DIRECTORY_PATH, TRUE, TRUE, NULL); - if (retStatus != STATUS_SUCCESS) { - printf("[KVS Master] createFileLogger(): operation returned status code: 0x%08x \n", retStatus); - pSampleConfiguration->enableFileLogging = FALSE; - } - } + CHK_STATUS(createSampleConfiguration(pChannelName, SIGNALING_CHANNEL_ROLE_TYPE_MASTER, TRUE, TRUE, logLevel, &pSampleConfiguration)); // Set the audio and video handlers if (videoCapturerHandle) { @@ -190,105 +177,52 @@ INT32 main(INT32 argc, CHAR* argv[]) pSampleConfiguration->receiveAudioVideoSource = sampleReceiveAudioVideoFrame; } pSampleConfiguration->onDataChannel = onDataChannel; - printf("[KVS Master] Finished setting audio and video handlers\n"); + DLOGI("[KVS Master] Finished setting handlers"); // Initialize KVS WebRTC. This must be done before anything else, and must only be done once. - retStatus = initKvsWebRtc(); - if (retStatus != STATUS_SUCCESS) { - printf("[KVS Master] initKvsWebRtc(): operation returned status code: 0x%08x \n", retStatus); - goto CleanUp; - } - printf("[KVS Master] KVS WebRTC initialization completed successfully\n"); - - pSampleConfiguration->signalingClientCallbacks.messageReceivedFn = signalingMessageReceived; - - strcpy(pSampleConfiguration->clientInfo.clientId, SAMPLE_MASTER_CLIENT_ID); - - retStatus = createSignalingClientSync(&pSampleConfiguration->clientInfo, &pSampleConfiguration->channelInfo, - &pSampleConfiguration->signalingClientCallbacks, pSampleConfiguration->pCredentialProvider, - &pSampleConfiguration->signalingClientHandle); - if (retStatus != STATUS_SUCCESS) { - printf("[KVS Master] createSignalingClientSync(): operation returned status code: 0x%08x \n", retStatus); - goto CleanUp; - } - printf("[KVS Master] Signaling client created successfully\n"); - - // Enable the processing of the messages - retStatus = signalingClientFetchSync(pSampleConfiguration->signalingClientHandle); - if (retStatus != STATUS_SUCCESS) { - printf("[KVS Master] signalingClientFetchSync(): operation returned status code: 0x%08x \n", retStatus); - goto CleanUp; - } - - retStatus = signalingClientConnectSync(pSampleConfiguration->signalingClientHandle); - if (retStatus != STATUS_SUCCESS) { - printf("[KVS Master] signalingClientConnectSync(): operation returned status code: 0x%08x \n", retStatus); - goto CleanUp; - } - printf("[KVS Master] Signaling client connection to socket established\n"); - - gSampleConfiguration = pSampleConfiguration; + CHK_STATUS(initKvsWebRtc()); + DLOGI("[KVS Master] KVS WebRTC initialization completed successfully"); - printf("[KVS Master] Channel %s set up done \n", pChannelName); + CHK_STATUS(initSignaling(pSampleConfiguration, SAMPLE_MASTER_CLIENT_ID)); + DLOGI("[KVS Master] Channel %s set up done ", pChannelName); // Checking for termination - retStatus = sessionCleanupWait(pSampleConfiguration); - if (retStatus != STATUS_SUCCESS) { - printf("[KVS Master] sessionCleanupWait(): operation returned status code: 0x%08x \n", retStatus); - goto CleanUp; - } - - printf("[KVS Master] Streaming session terminated\n"); + CHK_STATUS(sessionCleanupWait(pSampleConfiguration)); + DLOGI("[KVS Master] Streaming session terminated"); CleanUp: if (retStatus != STATUS_SUCCESS) { - printf("[KVS Master] Terminated with status code 0x%08x\n", retStatus); + DLOGE("[KVS Master] Terminated with status code 0x%08x", retStatus); } - printf("[KVS Master] Cleaning up....\n"); + DLOGI("[KVS Master] Cleaning up...."); if (pSampleConfiguration != NULL) { // Kick of the termination sequence ATOMIC_STORE_BOOL(&pSampleConfiguration->appTerminateFlag, TRUE); - if (IS_VALID_MUTEX_VALUE(pSampleConfiguration->sampleConfigurationObjLock)) { - MUTEX_LOCK(pSampleConfiguration->sampleConfigurationObjLock); - } - - // Cancel the media thread - if (pSampleConfiguration->mediaThreadStarted) { - DLOGD("Canceling media thread"); - THREAD_CANCEL(pSampleConfiguration->mediaSenderTid); - } - - if (IS_VALID_MUTEX_VALUE(pSampleConfiguration->sampleConfigurationObjLock)) { - MUTEX_UNLOCK(pSampleConfiguration->sampleConfigurationObjLock); - } - if (pSampleConfiguration->mediaSenderTid != INVALID_TID_VALUE) { THREAD_JOIN(pSampleConfiguration->mediaSenderTid, NULL); } - if (pSampleConfiguration->enableFileLogging) { - freeFileLogger(); - } retStatus = signalingClientGetMetrics(pSampleConfiguration->signalingClientHandle, &signalingClientMetrics); if (retStatus == STATUS_SUCCESS) { logSignalingClientStats(&signalingClientMetrics); } else { - printf("[KVS Master] signalingClientGetMetrics() operation returned status code: 0x%08x\n", retStatus); + DLOGE("[KVS Master] signalingClientGetMetrics() operation returned status code: 0x%08x", retStatus); } retStatus = freeSignalingClient(&pSampleConfiguration->signalingClientHandle); if (retStatus != STATUS_SUCCESS) { - printf("[KVS Master] freeSignalingClient(): operation returned status code: 0x%08x\n", retStatus); + DLOGE("[KVS Master] freeSignalingClient(): operation returned status code: 0x%08x", retStatus); } retStatus = freeSampleConfiguration(&pSampleConfiguration); if (retStatus != STATUS_SUCCESS) { - printf("[KVS Master] freeSampleConfiguration(): operation returned status code: 0x%08x", retStatus); + DLOGE("[KVS Master] freeSampleConfiguration(): operation returned status code: 0x%08x", retStatus); } } - printf("[KVS Master] Cleanup done\n"); + DLOGI("[KVS Master] Cleanup done"); + CHK_LOG_ERR(retStatus); /* Media Interface Destruct */ if (audioCapturerHandle) { @@ -327,21 +261,13 @@ PVOID sendVideoPackets(PVOID args) UINT64 timestamp = 0; SIZE_T frameSize = 0; - if (pSampleConfiguration == NULL) { - printf("[KVS Master] sendVideoPackets(): operation returned status code: 0x%08x \n", STATUS_NULL_ARG); - goto CleanUp; - } + CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); pFrameBuffer = MEMALLOC(VIDEO_FRAME_BUFFER_SIZE_BYTES); - if (!pFrameBuffer) { - printf("[KVS Master] OOM \n"); - goto CleanUp; - } - - if (videoCapturerAcquireStream(videoCapturerHandle)) { - goto CleanUp; - } + CHK_ERR(pFrameBuffer != NULL, STATUS_NOT_ENOUGH_MEMORY, "[KVS Master] OOM when allocating buffer"); + CHK_ERR(videoCapturerHandle != NULL, STATUS_NULL_ARG, "[KVS Master] VideoCapturerHandle is NULL"); + CHK_ERR(videoCapturerAcquireStream(videoCapturerHandle) == 0, STATUS_INVALID_OPERATION, "[KVS Master] Acquire video stream failed"); int getFrameStatus = 0; while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { @@ -356,11 +282,12 @@ PVOID sendVideoPackets(PVOID args) usleep(1000); break; default: - printf("videoCapturerGetFrame failed\n"); + DLOGE("videoCapturerGetFrame failed"); } } CleanUp: + DLOGI("[KVS Master] Closing video thread"); videoCapturerReleaseStream(videoCapturerHandle); @@ -380,21 +307,13 @@ PVOID sendAudioPackets(PVOID args) UINT64 timestamp = 0; SIZE_T frameSize = 0; - if (pSampleConfiguration == NULL) { - printf("[KVS Master] sendAudioPackets(): operation returned status code: 0x%08x \n", STATUS_NULL_ARG); - goto CleanUp; - } + CHK_ERR(pSampleConfiguration != NULL, STATUS_NULL_ARG, "[KVS Master] Streaming session is NULL"); pFrameBuffer = MEMALLOC(AUDIO_FRAME_BUFFER_SIZE_BYTES); - if (!pFrameBuffer) { - printf("[KVS Master] OOM \n"); - goto CleanUp; - } - - if (audioCapturerAcquireStream(audioCapturerHandle)) { - goto CleanUp; - } + CHK_ERR(pFrameBuffer != NULL, STATUS_NOT_ENOUGH_MEMORY, "[KVS Master] OOM when allocating buffer"); + CHK_ERR(audioCapturerHandle != NULL, STATUS_NULL_ARG, "[KVS Master] AudioCapturerHandle is NULL"); + CHK_ERR(audioCapturerAcquireStream(audioCapturerHandle) == 0, STATUS_INVALID_OPERATION, "[KVS Master] Acquire audio stream failed"); int getFrameStatus = 0; while (!ATOMIC_LOAD_BOOL(&pSampleConfiguration->appTerminateFlag)) { @@ -409,11 +328,12 @@ PVOID sendAudioPackets(PVOID args) usleep(1000); break; default: - printf("audioCapturerGetFrame failed\n"); + DLOGE("audioCapturerGetFrame failed"); } } CleanUp: + DLOGI("[KVS Master] closing audio thread"); audioCapturerReleaseStream(audioCapturerHandle); @@ -429,16 +349,9 @@ PVOID sampleReceiveAudioVideoFrame(PVOID args) { STATUS retStatus = STATUS_SUCCESS; PSampleStreamingSession pSampleStreamingSession = (PSampleStreamingSession) args; - if (pSampleStreamingSession == NULL) { - printf("[KVS Master] sampleReceiveAudioVideoFrame(): operation returned status code: 0x%08x \n", STATUS_NULL_ARG); - goto CleanUp; - } - - retStatus = transceiverOnFrame(pSampleStreamingSession->pAudioRtcRtpTransceiver, (UINT64) pSampleStreamingSession, remoteAudioFrameHandler); - if (retStatus != STATUS_SUCCESS) { - printf("[KVS Master] transceiverOnFrame(): operation returned status code: 0x%08x \n", retStatus); - goto CleanUp; - } + 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, remoteAudioFrameHandler)); CleanUp: