Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Incorporating PIC state machine level retry changes into webrtc signaling state machine #1326

Merged
merged 10 commits into from
Nov 22, 2021
2 changes: 1 addition & 1 deletion CMake/Dependencies/libkvsCommonLws-CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ include(ExternalProject)

ExternalProject_Add(libkvsCommonLws-download
GIT_REPOSITORY https://github.com/awslabs/amazon-kinesis-video-streams-producer-c.git
GIT_TAG 99c1a8cd8cec88f99c9c4ce3944b53ae341d1491
GIT_TAG 9a995a5793b4024f19912be9a319993b1e16005c
PREFIX ${CMAKE_CURRENT_BINARY_DIR}/build
CMAKE_ARGS
-DCMAKE_INSTALL_PREFIX=${OPEN_SRC_INSTALL_PREFIX}
Expand Down
17 changes: 17 additions & 0 deletions src/include/com/amazonaws/kinesis/video/webrtcclient/Include.h
Original file line number Diff line number Diff line change
Expand Up @@ -653,6 +653,8 @@ extern "C" {
typedef UINT64 SIGNALING_CLIENT_HANDLE;
typedef SIGNALING_CLIENT_HANDLE* PSIGNALING_CLIENT_HANDLE;

typedef PKvsRetryStrategy PSignalingClientRetryStrategy;

/**
* @brief This is a sentinel indicating an invalid handle value
*/
Expand Down Expand Up @@ -1867,6 +1869,21 @@ PUBLIC_API PCHAR getNatBehaviorStr(NAT_BEHAVIOR natBehavior);
PUBLIC_API STATUS createSignalingClientSync(PSignalingClientInfo, PChannelInfo, PSignalingClientCallbacks, PAwsCredentialProvider,
PSIGNALING_CLIENT_HANDLE);

/**
* @brief Creates a Signaling client and returns a handle to it
*
* @param[in] PSignalingClientInfo Signaling client info
* @param[in] PChannelInfo Signaling channel info to use/create a channel
* @param[in] PSignalingClientCallbacks Signaling callbacks for event notifications
* @param[in] PAwsCredentialProvider Credential provider for auth integration
* @param[in] PSignalingClientRetryStrategy Optional parameter indicating retry strategy. If not provided, SDK will use default retry strategy
* @param[out] PSIGNALING_CLIENT_HANDLE Returned signaling client handle
*
* @return STATUS code of the execution. STATUS_SUCCESS on success
*/
PUBLIC_API STATUS createSignalingClientSyncWithRetryStrategy(PSignalingClientInfo, PChannelInfo, PSignalingClientCallbacks, PAwsCredentialProvider,
PSignalingClientRetryStrategy, PSIGNALING_CLIENT_HANDLE);

/**
* @brief Frees the Signaling client object
*
Expand Down
12 changes: 12 additions & 0 deletions src/source/Signaling/Client.c
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,14 @@

STATUS createSignalingClientSync(PSignalingClientInfo pClientInfo, PChannelInfo pChannelInfo, PSignalingClientCallbacks pCallbacks,
PAwsCredentialProvider pCredentialProvider, PSIGNALING_CLIENT_HANDLE pSignalingHandle)
{
return createSignalingClientSyncWithRetryStrategy(pClientInfo, pChannelInfo, pCallbacks,
pCredentialProvider, NULL, pSignalingHandle);
}

STATUS createSignalingClientSyncWithRetryStrategy(PSignalingClientInfo pClientInfo, PChannelInfo pChannelInfo,
PSignalingClientCallbacks pCallbacks, PAwsCredentialProvider pCredentialProvider,
PSignalingClientRetryStrategy pSignalingClientRetryStrategy, PSIGNALING_CLIENT_HANDLE pSignalingHandle)
{
ENTERS();
STATUS retStatus = STATUS_SUCCESS;
Expand All @@ -16,6 +24,10 @@ STATUS createSignalingClientSync(PSignalingClientInfo pClientInfo, PChannelInfo
MEMSET(&signalingClientInfoInternal, 0x00, SIZEOF(signalingClientInfoInternal));
signalingClientInfoInternal.signalingClientInfo = *pClientInfo;

if (pSignalingClientRetryStrategy != NULL) {
signalingClientInfoInternal.kvsRetryStrategy = *(pSignalingClientRetryStrategy);
}

CHK_STATUS(createSignalingSync(&signalingClientInfoInternal, pChannelInfo, pCallbacks, pCredentialProvider, &pSignalingClient));

*pSignalingHandle = TO_SIGNALING_CLIENT_HANDLE(pSignalingClient);
Expand Down
66 changes: 66 additions & 0 deletions src/source/Signaling/Signaling.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ STATUS createSignalingSync(PSignalingClientInfoInternal pClientInfo, PChannelInf
CHK_STATUS(validateSignalingCallbacks(pSignalingClient, pCallbacks));
CHK_STATUS(validateSignalingClientInfo(pSignalingClient, pClientInfo));

configureClientWithRetryStrategy(pSignalingClient);

// Set invalid call times
pSignalingClient->describeTime = INVALID_TIMESTAMP_VALUE;
pSignalingClient->createTime = INVALID_TIMESTAMP_VALUE;
Expand Down Expand Up @@ -205,6 +207,8 @@ STATUS freeSignaling(PSignalingClient* ppSignalingClient)
MUTEX_UNLOCK(pSignalingClient->lwsServiceLock);
}

freeClientRetryStrategy(pSignalingClient);

freeStateMachine(pSignalingClient->pStateMachine);

freeChannelInfo(&pSignalingClient->pChannelInfo);
Expand Down Expand Up @@ -527,6 +531,68 @@ STATUS validateSignalingClientInfo(PSignalingClient pSignalingClient, PSignaling
return retStatus;
}

STATUS setupDefaultKvsRetryStrategy(PSignalingClient pSignalingClient) {
ENTERS();
STATUS retStatus = STATUS_SUCCESS;

// Use default as exponential backoff wait
pSignalingClient->clientInfo.kvsRetryStrategy.createRetryStrategyFn = exponentialBackoffRetryStrategyCreate;
pSignalingClient->clientInfo.kvsRetryStrategy.freeRetryStrategyFn = exponentialBackoffRetryStrategyFree;
pSignalingClient->clientInfo.kvsRetryStrategy.executeRetryStrategyFn = getExponentialBackoffRetryStrategyWaitTime;
pSignalingClient->clientInfo.kvsRetryStrategy.retryStrategyType = KVS_RETRY_STRATEGY_EXPONENTIAL_BACKOFF_WAIT;

CleanUp:
LEAVES();
return retStatus;
}

STATUS configureClientWithRetryStrategy(PSignalingClient pSignalingClient) {
ENTERS();
PRetryStrategy pRetryStrategy = NULL;
STATUS retStatus = STATUS_SUCCESS;
KVS_RETRY_STRATEGY_TYPE defaultKvsRetryStrategyType = KVS_RETRY_STRATEGY_EXPONENTIAL_BACKOFF_WAIT;

CHK(pSignalingClient != NULL, STATUS_NULL_ARG);

// If the user has already provided retry strategy, then use it. Otherwise use default retry strategy.
// KVS_RETRY_STRATEGY_DISABLED value is 0.
if (pSignalingClient->clientInfo.kvsRetryStrategy.retryStrategyType == KVS_RETRY_STRATEGY_DISABLED) {
DLOGD("User did not provide KVS retry strategy. Configuring signaling client with default KVS retry strategy.");
CHK_STATUS(setupDefaultKvsRetryStrategy(pSignalingClient));
} else {
DLOGD("Using user provided KVS retry strategy for signaling client");
}

if (pSignalingClient->clientInfo.kvsRetryStrategy.createRetryStrategyFn != NULL) {
CHK_STATUS(pSignalingClient->clientInfo.kvsRetryStrategy.createRetryStrategyFn(
NULL /* use default retry strategy configuration */, &pRetryStrategy));
pSignalingClient->clientInfo.kvsRetryStrategy.pRetryStrategy = pRetryStrategy;
}

CleanUp:

LEAVES();
return retStatus;
}

STATUS freeClientRetryStrategy(PSignalingClient pSignalingClient) {
ENTERS();
STATUS retStatus = STATUS_SUCCESS;

CHK(pSignalingClient != NULL &&
pSignalingClient->clientInfo.kvsRetryStrategy.pRetryStrategy != NULL &&
pSignalingClient->clientInfo.kvsRetryStrategy.freeRetryStrategyFn != NULL, STATUS_SUCCESS);

CHK_STATUS(pSignalingClient->clientInfo.kvsRetryStrategy.freeRetryStrategyFn(
&(pSignalingClient->clientInfo.kvsRetryStrategy.pRetryStrategy)));
pSignalingClient->clientInfo.kvsRetryStrategy.pRetryStrategy = NULL;

CleanUp:

LEAVES();
return retStatus;
}

STATUS validateIceConfiguration(PSignalingClient pSignalingClient)
{
ENTERS();
Expand Down
7 changes: 7 additions & 0 deletions src/source/Signaling/Signaling.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ typedef struct {
SignalingApiCallHookFunc connectPostHookFn;
SignalingApiCallHookFunc deletePreHookFn;
SignalingApiCallHookFunc deletePostHookFn;

// Retry strategy for the client and all the streams under it
KvsRetryStrategy kvsRetryStrategy;
} SignalingClientInfoInternal, *PSignalingClientInfoInternal;

/**
Expand Down Expand Up @@ -305,6 +308,10 @@ STATUS validateSignalingCallbacks(PSignalingClient, PSignalingClientCallbacks);
STATUS validateSignalingClientInfo(PSignalingClient, PSignalingClientInfoInternal);
STATUS validateIceConfiguration(PSignalingClient);

STATUS configureClientWithRetryStrategy(PSignalingClient);
STATUS setupDefaultKvsRetryStrategy(PSignalingClient);
STATUS freeClientRetryStrategy(PSignalingClient);

STATUS signalingStoreOngoingMessage(PSignalingClient, PSignalingMessage);
STATUS signalingRemoveOngoingMessage(PSignalingClient, PCHAR);
STATUS signalingGetOngoingMessage(PSignalingClient, PCHAR, PCHAR, PSignalingMessage*);
Expand Down
168 changes: 139 additions & 29 deletions src/source/Signaling/StateMachine.c
Original file line number Diff line number Diff line change
Expand Up @@ -7,47 +7,157 @@
/**
* Static definitions of the states
*/
// /Users/akatey/kvs_git_workspace/amazon-kinesis-video-streams-webrtc-sdk-c/open-source/include/com/amazonaws/kinesis/video/state/Include.h
StateMachineState SIGNALING_STATE_MACHINE_STATES[] = {
{SIGNALING_STATE_NEW, SIGNALING_STATE_NONE | SIGNALING_STATE_NEW, fromNewSignalingState, executeNewSignalingState, INFINITE_RETRY_COUNT_SENTINEL,
STATUS_SIGNALING_INVALID_READY_STATE},
{SIGNALING_STATE_GET_TOKEN,
{
SIGNALING_STATE_NEW, SIGNALING_STATE_NONE | SIGNALING_STATE_NEW,
fromNewSignalingState,
executeNewSignalingState,
defaultSignalingStateTransitionHook,
INFINITE_RETRY_COUNT_SENTINEL,
STATUS_SIGNALING_INVALID_READY_STATE
Copy link
Contributor

Choose a reason for hiding this comment

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

Indent off

},
{
SIGNALING_STATE_GET_TOKEN,
SIGNALING_STATE_NEW | SIGNALING_STATE_DESCRIBE | SIGNALING_STATE_CREATE | SIGNALING_STATE_GET_ENDPOINT | SIGNALING_STATE_GET_ICE_CONFIG |
SIGNALING_STATE_READY | SIGNALING_STATE_CONNECT | SIGNALING_STATE_CONNECTED | SIGNALING_STATE_DELETE | SIGNALING_STATE_GET_TOKEN,
fromGetTokenSignalingState, executeGetTokenSignalingState, SIGNALING_STATES_DEFAULT_RETRY_COUNT, STATUS_SIGNALING_GET_TOKEN_CALL_FAILED},
{SIGNALING_STATE_DESCRIBE,
SIGNALING_STATE_GET_TOKEN | SIGNALING_STATE_CREATE | SIGNALING_STATE_GET_ENDPOINT | SIGNALING_STATE_GET_ICE_CONFIG | SIGNALING_STATE_CONNECT |
fromGetTokenSignalingState,
executeGetTokenSignalingState,
defaultSignalingStateTransitionHook,
SIGNALING_STATES_DEFAULT_RETRY_COUNT,
STATUS_SIGNALING_GET_TOKEN_CALL_FAILED
},
{
SIGNALING_STATE_DESCRIBE,
SIGNALING_STATE_GET_TOKEN | SIGNALING_STATE_CREATE | SIGNALING_STATE_GET_ENDPOINT | SIGNALING_STATE_GET_ICE_CONFIG | SIGNALING_STATE_CONNECT |
SIGNALING_STATE_CONNECTED | SIGNALING_STATE_DELETE | SIGNALING_STATE_DESCRIBE,
fromDescribeSignalingState, executeDescribeSignalingState, SIGNALING_STATES_DEFAULT_RETRY_COUNT, STATUS_SIGNALING_DESCRIBE_CALL_FAILED},
{SIGNALING_STATE_CREATE, SIGNALING_STATE_DESCRIBE | SIGNALING_STATE_CREATE, fromCreateSignalingState, executeCreateSignalingState,
SIGNALING_STATES_DEFAULT_RETRY_COUNT, STATUS_SIGNALING_CREATE_CALL_FAILED},
{SIGNALING_STATE_GET_ENDPOINT,
SIGNALING_STATE_DESCRIBE | SIGNALING_STATE_CREATE | SIGNALING_STATE_GET_TOKEN | SIGNALING_STATE_READY | SIGNALING_STATE_CONNECT |
fromDescribeSignalingState,
executeDescribeSignalingState,
defaultSignalingStateTransitionHook,
SIGNALING_STATES_DEFAULT_RETRY_COUNT,
STATUS_SIGNALING_DESCRIBE_CALL_FAILED
},
{
SIGNALING_STATE_CREATE,
SIGNALING_STATE_DESCRIBE | SIGNALING_STATE_CREATE,
fromCreateSignalingState,
executeCreateSignalingState,
defaultSignalingStateTransitionHook,
SIGNALING_STATES_DEFAULT_RETRY_COUNT,
STATUS_SIGNALING_CREATE_CALL_FAILED
},
{
SIGNALING_STATE_GET_ENDPOINT,
SIGNALING_STATE_DESCRIBE | SIGNALING_STATE_CREATE | SIGNALING_STATE_GET_TOKEN | SIGNALING_STATE_READY | SIGNALING_STATE_CONNECT |
SIGNALING_STATE_CONNECTED | SIGNALING_STATE_GET_ENDPOINT,
fromGetEndpointSignalingState, executeGetEndpointSignalingState, SIGNALING_STATES_DEFAULT_RETRY_COUNT,
STATUS_SIGNALING_GET_ENDPOINT_CALL_FAILED},
{SIGNALING_STATE_GET_ICE_CONFIG,
SIGNALING_STATE_DESCRIBE | SIGNALING_STATE_CONNECT | SIGNALING_STATE_CONNECTED | SIGNALING_STATE_GET_ENDPOINT | SIGNALING_STATE_READY |
fromGetEndpointSignalingState,
executeGetEndpointSignalingState,
defaultSignalingStateTransitionHook,
SIGNALING_STATES_DEFAULT_RETRY_COUNT,
STATUS_SIGNALING_GET_ENDPOINT_CALL_FAILED
},
{
SIGNALING_STATE_GET_ICE_CONFIG,
SIGNALING_STATE_DESCRIBE | SIGNALING_STATE_CONNECT | SIGNALING_STATE_CONNECTED | SIGNALING_STATE_GET_ENDPOINT | SIGNALING_STATE_READY |
SIGNALING_STATE_GET_ICE_CONFIG,
fromGetIceConfigSignalingState, executeGetIceConfigSignalingState, SIGNALING_STATES_DEFAULT_RETRY_COUNT,
STATUS_SIGNALING_GET_ICE_CONFIG_CALL_FAILED},
{SIGNALING_STATE_READY, SIGNALING_STATE_GET_ICE_CONFIG | SIGNALING_STATE_DISCONNECTED | SIGNALING_STATE_READY, fromReadySignalingState,
executeReadySignalingState, INFINITE_RETRY_COUNT_SENTINEL, STATUS_SIGNALING_READY_CALLBACK_FAILED},
{SIGNALING_STATE_CONNECT, SIGNALING_STATE_READY | SIGNALING_STATE_DISCONNECTED | SIGNALING_STATE_CONNECTED | SIGNALING_STATE_CONNECT,
fromConnectSignalingState, executeConnectSignalingState, INFINITE_RETRY_COUNT_SENTINEL, STATUS_SIGNALING_CONNECT_CALL_FAILED},
{SIGNALING_STATE_CONNECTED, SIGNALING_STATE_CONNECT | SIGNALING_STATE_CONNECTED, fromConnectedSignalingState, executeConnectedSignalingState,
INFINITE_RETRY_COUNT_SENTINEL, STATUS_SIGNALING_CONNECTED_CALLBACK_FAILED},
{SIGNALING_STATE_DISCONNECTED, SIGNALING_STATE_CONNECT | SIGNALING_STATE_CONNECTED, fromDisconnectedSignalingState,
executeDisconnectedSignalingState, SIGNALING_STATES_DEFAULT_RETRY_COUNT, STATUS_SIGNALING_DISCONNECTED_CALLBACK_FAILED},
{SIGNALING_STATE_DELETE,
fromGetIceConfigSignalingState,
executeGetIceConfigSignalingState,
defaultSignalingStateTransitionHook,
SIGNALING_STATES_DEFAULT_RETRY_COUNT,
STATUS_SIGNALING_GET_ICE_CONFIG_CALL_FAILED
},
{
SIGNALING_STATE_READY,
SIGNALING_STATE_GET_ICE_CONFIG | SIGNALING_STATE_DISCONNECTED | SIGNALING_STATE_READY,
fromReadySignalingState,
executeReadySignalingState,
defaultSignalingStateTransitionHook,
INFINITE_RETRY_COUNT_SENTINEL, STATUS_SIGNALING_READY_CALLBACK_FAILED
},
{
SIGNALING_STATE_CONNECT,
SIGNALING_STATE_READY | SIGNALING_STATE_DISCONNECTED | SIGNALING_STATE_CONNECTED | SIGNALING_STATE_CONNECT,
fromConnectSignalingState,
executeConnectSignalingState,
defaultSignalingStateTransitionHook,
INFINITE_RETRY_COUNT_SENTINEL,
STATUS_SIGNALING_CONNECT_CALL_FAILED
},
{
SIGNALING_STATE_CONNECTED,
SIGNALING_STATE_CONNECT | SIGNALING_STATE_CONNECTED,
fromConnectedSignalingState,
executeConnectedSignalingState,
defaultSignalingStateTransitionHook,
INFINITE_RETRY_COUNT_SENTINEL,
STATUS_SIGNALING_CONNECTED_CALLBACK_FAILED
},
{
SIGNALING_STATE_DISCONNECTED,
SIGNALING_STATE_CONNECT | SIGNALING_STATE_CONNECTED,
fromDisconnectedSignalingState,
executeDisconnectedSignalingState,
defaultSignalingStateTransitionHook,
SIGNALING_STATES_DEFAULT_RETRY_COUNT,
STATUS_SIGNALING_DISCONNECTED_CALLBACK_FAILED
},
{
SIGNALING_STATE_DELETE,
SIGNALING_STATE_GET_TOKEN | SIGNALING_STATE_DESCRIBE | SIGNALING_STATE_CREATE | SIGNALING_STATE_GET_ENDPOINT | SIGNALING_STATE_GET_ICE_CONFIG |
SIGNALING_STATE_READY | SIGNALING_STATE_CONNECT | SIGNALING_STATE_CONNECTED | SIGNALING_STATE_DISCONNECTED | SIGNALING_STATE_DELETE,
fromDeleteSignalingState, executeDeleteSignalingState, SIGNALING_STATES_DEFAULT_RETRY_COUNT, STATUS_SIGNALING_DELETE_CALL_FAILED},
{SIGNALING_STATE_DELETED, SIGNALING_STATE_DELETE | SIGNALING_STATE_DELETED, fromDeletedSignalingState, executeDeletedSignalingState,
INFINITE_RETRY_COUNT_SENTINEL, STATUS_SIGNALING_DELETE_CALL_FAILED},
fromDeleteSignalingState,
executeDeleteSignalingState,
defaultSignalingStateTransitionHook,
SIGNALING_STATES_DEFAULT_RETRY_COUNT,
STATUS_SIGNALING_DELETE_CALL_FAILED
},
{
SIGNALING_STATE_DELETED,
SIGNALING_STATE_DELETE | SIGNALING_STATE_DELETED,
fromDeletedSignalingState,
executeDeletedSignalingState,
defaultSignalingStateTransitionHook,
INFINITE_RETRY_COUNT_SENTINEL,
STATUS_SIGNALING_DELETE_CALL_FAILED
},
};

UINT32 SIGNALING_STATE_MACHINE_STATE_COUNT = ARRAY_SIZE(SIGNALING_STATE_MACHINE_STATES);

STATUS defaultSignalingStateTransitionHook(
UINT64 customData /* customData should be PSignalingClient */,
PUINT64 stateTransitionWaitTime) {
ENTERS();
STATUS retStatus = STATUS_SUCCESS;
PSignalingClient pSignalingClient = NULL;
PKvsRetryStrategy pKvsRetryStrategy = NULL;
UINT64 retryWaitTime = 0;

pSignalingClient = SIGNALING_CLIENT_FROM_CUSTOM_DATA(customData);
CHK(pSignalingClient != NULL && stateTransitionWaitTime != NULL, STATUS_NULL_ARG);

pKvsRetryStrategy = &(pSignalingClient->clientInfo.kvsRetryStrategy);

// result > SERVICE_CALL_RESULT_OK covers case for -
// result != SERVICE_CALL_RESULT_NOT_SET and != SERVICE_CALL_RESULT_OK
// If we support any other 2xx service call results, the condition
// should change to (pSignalingClient->result > 299 && ...)
CHK(pSignalingClient->result > SERVICE_CALL_RESULT_OK &&
pKvsRetryStrategy != NULL &&
pKvsRetryStrategy->pRetryStrategy != NULL &&
pKvsRetryStrategy->executeRetryStrategyFn != NULL, STATUS_SUCCESS);

DLOGD("Signaling Client base result is [%u]. Executing KVS retry handler of retry strategy type [%u]",
pSignalingClient->result, pKvsRetryStrategy->retryStrategyType);
pKvsRetryStrategy->executeRetryStrategyFn(pKvsRetryStrategy->pRetryStrategy, &retryWaitTime);
*stateTransitionWaitTime = retryWaitTime;

CleanUp:

LEAVES();
return retStatus;
}

STATUS stepSignalingStateMachine(PSignalingClient pSignalingClient, STATUS status)
{
ENTERS();
Expand Down
2 changes: 2 additions & 0 deletions src/source/Signaling/StateMachine.h
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,8 @@ STATUS executeDeleteSignalingState(UINT64, UINT64);
STATUS fromDeletedSignalingState(UINT64, PUINT64);
STATUS executeDeletedSignalingState(UINT64, UINT64);

STATUS defaultSignalingStateTransitionHook(UINT64, PUINT64);

#ifdef __cplusplus
}
#endif
Expand Down