in src/client/src/Client.c [1453:1572]
STATUS freeKinesisVideoClientInternal(PKinesisVideoClient pKinesisVideoClient, STATUS failStatus)
{
STATUS retStatus = STATUS_SUCCESS, freeStreamStatus = STATUS_SUCCESS, freeStateMachineStatus = STATUS_SUCCESS, freeHeapStatus = STATUS_SUCCESS;
UINT32 i = 0;
BOOL locked = FALSE;
// Call is idempotent
CHK(pKinesisVideoClient != NULL && !pKinesisVideoClient->base.shutdown, retStatus);
pKinesisVideoClient->base.shutdown = TRUE;
// Lock the streamListLock for iteration
if (IS_VALID_MUTEX_VALUE(pKinesisVideoClient->base.streamListLock)) {
pKinesisVideoClient->clientCallbacks.lockMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoClient->base.streamListLock);
locked = TRUE;
}
// Call stream shutdowns first
for (i = 0; i < pKinesisVideoClient->deviceInfo.streamCount; i++) {
if (NULL != pKinesisVideoClient->streams[i]) {
// Call is idempotent so NULL is OK
shutdownStream(pKinesisVideoClient->streams[i], FALSE);
}
}
// unlock the streamListLock after iteration
if (locked) {
pKinesisVideoClient->clientCallbacks.unlockMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoClient->base.streamListLock);
locked = FALSE;
}
// Shutdown client
pKinesisVideoClient->clientCallbacks.clientShutdownFn(pKinesisVideoClient->clientCallbacks.customData, TO_CLIENT_HANDLE(pKinesisVideoClient));
// After the shutdown
semaphoreLock(pKinesisVideoClient->base.shutdownSemaphore);
semaphoreWaitUntilClear(pKinesisVideoClient->base.shutdownSemaphore, CLIENT_SHUTDOWN_SEMAPHORE_TIMEOUT);
// Need to stop scheduling callbacks
// This must happen outside the streamslist lock because the callbacks acquire that lock
// and shutdown won't return until callbacks have completed so we'll deadlock
if (IS_VALID_TIMER_QUEUE_HANDLE(pKinesisVideoClient->timerQueueHandle)) {
timerQueueShutdown(pKinesisVideoClient->timerQueueHandle);
}
// Lock the streamListLock for iteration
if (IS_VALID_MUTEX_VALUE(pKinesisVideoClient->base.streamListLock)) {
pKinesisVideoClient->clientCallbacks.lockMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoClient->base.streamListLock);
locked = TRUE;
}
// Release the underlying objects
for (i = 0; i < pKinesisVideoClient->deviceInfo.streamCount; i++) {
if (NULL != pKinesisVideoClient->streams[i]) {
// Call is idempotent so NULL is OK
retStatus = freeStream(pKinesisVideoClient->streams[i]);
freeStreamStatus = STATUS_FAILED(retStatus) ? retStatus : freeStreamStatus;
}
}
// unlock and free the streamListLock
if (locked) {
pKinesisVideoClient->clientCallbacks.unlockMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoClient->base.streamListLock);
pKinesisVideoClient->clientCallbacks.freeMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoClient->base.streamListLock);
locked = FALSE;
}
// Release the state machine
freeStateMachineStatus = freeStateMachine(pKinesisVideoClient->base.pStateMachine);
// Release the condition variable if set
if (IS_VALID_CVAR_VALUE(pKinesisVideoClient->base.ready)) {
// Broadcast in any case
pKinesisVideoClient->clientCallbacks.broadcastConditionVariableFn(pKinesisVideoClient->clientCallbacks.customData,
pKinesisVideoClient->base.ready);
// Free the condition variable
pKinesisVideoClient->clientCallbacks.freeConditionVariableFn(pKinesisVideoClient->clientCallbacks.customData,
pKinesisVideoClient->base.ready);
pKinesisVideoClient->base.ready = INVALID_CVAR_VALUE;
}
if (IS_VALID_MUTEX_VALUE(pKinesisVideoClient->base.lock)) {
pKinesisVideoClient->clientCallbacks.freeMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoClient->base.lock);
}
if (IS_VALID_SEMAPHORE_HANDLE(pKinesisVideoClient->base.shutdownSemaphore)) {
semaphoreFree(&pKinesisVideoClient->base.shutdownSemaphore);
}
if (IS_VALID_TIMER_QUEUE_HANDLE(pKinesisVideoClient->timerQueueHandle)) {
timerQueueFree(&pKinesisVideoClient->timerQueueHandle);
}
// Reset the stored allocators if replaced
if (STATUS_SUCCEEDED(failStatus) && pKinesisVideoClient->deviceInfo.storageInfo.storageType == DEVICE_STORAGE_TYPE_IN_MEM_CONTENT_STORE_ALLOC) {
globalMemAlloc = pKinesisVideoClient->storedMemAlloc;
globalMemAlignAlloc = pKinesisVideoClient->storedMemAlignAlloc;
globalMemCalloc = pKinesisVideoClient->storedMemCalloc;
globalMemFree = pKinesisVideoClient->storedMemFree;
// Reset the singleton instance
gKinesisVideoClient = NULL;
}
// Release the heap
if (pKinesisVideoClient->pHeap) {
heapDebugCheckAllocator(pKinesisVideoClient->pHeap, TRUE);
freeHeapStatus = heapRelease(pKinesisVideoClient->pHeap);
}
DLOGD("Total allocated memory %" PRIu64, pKinesisVideoClient->totalAllocationSize);
// Release the object
MEMFREE(pKinesisVideoClient);
CleanUp:
return retStatus | freeStreamStatus | freeHeapStatus | freeStateMachineStatus;
}