STATUS createKinesisVideoClient()

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;
}