in src/client/src/Client.c [100:263]
STATUS createKinesisVideoClient(PDeviceInfo pDeviceInfo, PClientCallbacks pClientCallbacks, PCLIENT_HANDLE pClientHandle)
{
ENTERS();
STATUS retStatus = STATUS_SUCCESS;
PKinesisVideoClient pKinesisVideoClient = NULL;
PStateMachine pStateMachine = NULL;
BOOL tearDownOnError = TRUE;
UINT32 allocationSize, heapFlags, tagsSize;
// Check the input params
CHK(pDeviceInfo != NULL && pClientHandle != NULL, STATUS_NULL_ARG);
// Set the return client handle first
*pClientHandle = INVALID_CLIENT_HANDLE_VALUE;
// Validate the input structs
CHK_STATUS(validateDeviceInfo(pDeviceInfo));
// Validate the callbacks. Set default callbacks.
CHK_STATUS(validateClientCallbacks(pDeviceInfo, pClientCallbacks));
// Report the creation after the validation as we might have the overwritten logger.
DLOGI("Creating Kinesis Video Client");
// Get the max tags structure size
CHK_STATUS(packageTags(pDeviceInfo->tagCount, pDeviceInfo->tags, 0, NULL, &tagsSize));
// Allocate the main struct with an array of stream pointers following the structure and the array of tags following it
// NOTE: The calloc will Zero the fields
allocationSize = SIZEOF(KinesisVideoClient) + pDeviceInfo->streamCount * SIZEOF(PKinesisVideoStream) + tagsSize;
pKinesisVideoClient = (PKinesisVideoClient) MEMCALLOC(1, allocationSize);
CHK(pKinesisVideoClient != NULL, STATUS_NOT_ENOUGH_MEMORY);
// Set the basics
pKinesisVideoClient->base.identifier = KINESIS_VIDEO_OBJECT_IDENTIFIER_CLIENT;
pKinesisVideoClient->base.version = KINESIS_VIDEO_CLIENT_CURRENT_VERSION;
pKinesisVideoClient->certAuthInfo.version = AUTH_INFO_CURRENT_VERSION;
pKinesisVideoClient->tokenAuthInfo.version = AUTH_INFO_CURRENT_VERSION;
// Set the auth size and type
pKinesisVideoClient->certAuthInfo.type = AUTH_INFO_UNDEFINED;
pKinesisVideoClient->certAuthInfo.size = 0;
pKinesisVideoClient->tokenAuthInfo.type = AUTH_INFO_UNDEFINED;
pKinesisVideoClient->tokenAuthInfo.size = 0;
// Set the initial stream count
pKinesisVideoClient->streamCount = 0;
// Set prehook to null
pKinesisVideoClient->timerCallbackPreHookFunc = NULL;
pKinesisVideoClient->hookCustomData = 0;
// Set the client to not-ready
pKinesisVideoClient->clientReady = FALSE;
// Set the streams pointer right after the struct
pKinesisVideoClient->streams = (PKinesisVideoStream*) (pKinesisVideoClient + 1);
// Copy the structures in their entirety
MEMCPY(&pKinesisVideoClient->clientCallbacks, pClientCallbacks, SIZEOF(ClientCallbacks));
// Fix-up the defaults if needed
// IMPORTANT!!! The calloc allocator will zero the memory which will also act as a
// sentinel value in case of an earlier version of the structure
// is used and the remaining fields are not copied
fixupDeviceInfo(&pKinesisVideoClient->deviceInfo, pDeviceInfo);
// Fix-up the name of the device if not specified
if (pKinesisVideoClient->deviceInfo.name[0] == '\0') {
createRandomName(pKinesisVideoClient->deviceInfo.name, DEFAULT_DEVICE_NAME_LEN, pKinesisVideoClient->clientCallbacks.getRandomNumberFn,
pKinesisVideoClient->clientCallbacks.customData);
}
// Set logger log level
SET_LOGGER_LOG_LEVEL(pKinesisVideoClient->deviceInfo.clientInfo.loggerLogLevel);
#ifndef ALIGNED_MEMORY_MODEL
// In case of in-content-store memory allocation, we need to ensure the heap is aligned
CHK(pKinesisVideoClient->deviceInfo.storageInfo.storageType != DEVICE_STORAGE_TYPE_IN_MEM_CONTENT_STORE_ALLOC,
STATUS_NON_ALIGNED_HEAP_WITH_IN_CONTENT_STORE_ALLOCATORS);
#endif
// Create the storage
heapFlags = pKinesisVideoClient->deviceInfo.storageInfo.storageType == DEVICE_STORAGE_TYPE_IN_MEM ||
pKinesisVideoClient->deviceInfo.storageInfo.storageType == DEVICE_STORAGE_TYPE_IN_MEM_CONTENT_STORE_ALLOC
? MEMORY_BASED_HEAP_FLAGS
: FILE_BASED_HEAP_FLAGS;
CHK_STATUS(heapInitialize(pKinesisVideoClient->deviceInfo.storageInfo.storageSize, pKinesisVideoClient->deviceInfo.storageInfo.spillRatio,
heapFlags, pKinesisVideoClient->deviceInfo.storageInfo.rootDirectory, &pKinesisVideoClient->pHeap));
// Using content store allocator if needed
// IMPORTANT! This will not be multi-client-safe
if (pKinesisVideoClient->deviceInfo.storageInfo.storageType == DEVICE_STORAGE_TYPE_IN_MEM_CONTENT_STORE_ALLOC) {
CHK_STATUS(setContentStoreAllocator(pKinesisVideoClient));
}
// Initialize the the ready state condition variable
pKinesisVideoClient->base.ready = pKinesisVideoClient->clientCallbacks.createConditionVariableFn(pKinesisVideoClient->clientCallbacks.customData);
CHK(IS_VALID_CVAR_VALUE(pKinesisVideoClient->base.ready), STATUS_NOT_ENOUGH_MEMORY);
// Set the tags pointer to point after the array of streams
pKinesisVideoClient->deviceInfo.tags = (PTag)((PKinesisVideoStream*) (pKinesisVideoClient + 1) + pDeviceInfo->streamCount);
// Package the tags after the structure
CHK_STATUS(packageTags(pDeviceInfo->tagCount, pDeviceInfo->tags, tagsSize, pKinesisVideoClient->deviceInfo.tags, NULL));
pKinesisVideoClient->deviceInfo.tagCount = pDeviceInfo->tagCount;
// Create the client lock
pKinesisVideoClient->base.lock = pKinesisVideoClient->clientCallbacks.createMutexFn(pKinesisVideoClient->clientCallbacks.customData, TRUE);
// Create lock for streams list
pKinesisVideoClient->base.streamListLock =
pKinesisVideoClient->clientCallbacks.createMutexFn(pKinesisVideoClient->clientCallbacks.customData, TRUE);
// Create the state machine and step it
CHK_STATUS(createStateMachine(CLIENT_STATE_MACHINE_STATES, CLIENT_STATE_MACHINE_STATE_COUNT, TO_CUSTOM_DATA(pKinesisVideoClient),
pKinesisVideoClient->clientCallbacks.getCurrentTimeFn, pKinesisVideoClient->clientCallbacks.customData,
&pStateMachine));
pKinesisVideoClient->base.pStateMachine = pStateMachine;
if (pKinesisVideoClient->deviceInfo.clientInfo.automaticStreamingFlags == AUTOMATIC_STREAMING_INTERMITTENT_PRODUCER) {
if (!IS_VALID_TIMER_QUEUE_HANDLE(pKinesisVideoClient->timerQueueHandle)) {
// Create timer queue
CHK_STATUS(timerQueueCreate(&pKinesisVideoClient->timerQueueHandle));
// Store callback in client so we can override in tests
pKinesisVideoClient->timerCallbackFunc = checkIntermittentProducerCallback;
CHK_STATUS(timerQueueAddTimer(pKinesisVideoClient->timerQueueHandle, INTERMITTENT_PRODUCER_TIMER_START_DELAY,
pKinesisVideoClient->deviceInfo.clientInfo.reservedCallbackPeriod, pKinesisVideoClient->timerCallbackFunc,
(UINT64) pKinesisVideoClient, &pKinesisVideoClient->timerId));
}
}
// Set the call result to unknown to start
pKinesisVideoClient->base.result = SERVICE_CALL_RESULT_NOT_SET;
pKinesisVideoClient->base.shutdown = FALSE;
// Create sequencing semaphore
CHK_STATUS(semaphoreCreate(MAX_PIC_REENTRANCY_COUNT, &pKinesisVideoClient->base.shutdownSemaphore));
// Assign the created object
*pClientHandle = TO_CLIENT_HANDLE(pKinesisVideoClient);
tearDownOnError = FALSE;
// Call to transition the state machine
// NOTE: This is called after the setting of the newly created
// object to the OUT parameter as this might evaluate to a service
// call which might fail. The clients can still choose to proceed
// with some further processing with a valid object.
CHK_STATUS(stepStateMachine(pKinesisVideoClient->base.pStateMachine));
CleanUp:
CHK_LOG_ERR(retStatus);
if (STATUS_FAILED(retStatus) && tearDownOnError) {
freeKinesisVideoClientInternal(pKinesisVideoClient, retStatus);
}
LEAVES();
return retStatus;
}