STATUS stopStream()

in src/client/src/Stream.c [445:550]


STATUS stopStream(PKinesisVideoStream pKinesisVideoStream)
{
    ENTERS();
    STATUS retStatus = STATUS_SUCCESS;
    PKinesisVideoClient pKinesisVideoClient;
    UINT64 duration, viewByteSize;
    UINT32 i, sessionCount;
    BOOL streamLocked = FALSE, clientLocked = FALSE, streamsListLock = FALSE, notSent = FALSE;
    PUploadHandleInfo pUploadHandleInfo = NULL;
    UINT64 item;

    CHK(pKinesisVideoStream != NULL && pKinesisVideoStream->pKinesisVideoClient != NULL, STATUS_NULL_ARG);
    pKinesisVideoClient = pKinesisVideoStream->pKinesisVideoClient;

    retStatus = frameOrderCoordinatorFlush(pKinesisVideoStream);
    if (STATUS_FAILED(retStatus)) {
        DLOGE("frameOrderCoordinatorFlush failed with 0x%08x", retStatus);
        retStatus = STATUS_SUCCESS;
    }

    // Lock the stream
    pKinesisVideoClient->clientCallbacks.lockMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoStream->base.lock);
    streamLocked = TRUE;

    // It's a no-op if stop has been called
    CHK(!pKinesisVideoStream->streamStopped, retStatus);

    // Set the stream end flag
    pKinesisVideoStream->streamStopped = TRUE;

    // Notify in case of an OFFLINE stream
    if (IS_OFFLINE_STREAMING_MODE(pKinesisVideoStream->streamInfo.streamCaps.streamingType)) {
        pKinesisVideoClient->clientCallbacks.signalConditionVariableFn(pKinesisVideoClient->clientCallbacks.customData,
                                                                       pKinesisVideoStream->bufferAvailabilityCondition);
    }

    // Lock the client
    pKinesisVideoClient->clientCallbacks.lockMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoClient->base.lock);
    clientLocked = TRUE;

    // Get the duration from current point to the head
    // Get the size of the allocation from current point to the head
    CHK_STATUS(getAvailableViewSize(pKinesisVideoStream, &duration, &viewByteSize));

    // Pulse the data available callback so the callee will know of a state change
    CHK_STATUS(stackQueueGetCount(pKinesisVideoStream->pUploadInfoQueue, &sessionCount));

    // Check if we have any content left and whether we have any metadata left to be send
    CHK_STATUS(checkForNotSentMetadata(pKinesisVideoStream, &notSent));

    // Package the frames if needed to be sent
    if (notSent) {
        CHK_STATUS(packageNotSentMetadata(pKinesisVideoStream));
    }

    for (i = 0; i < sessionCount; i++) {
        CHK_STATUS(stackQueueGetAt(pKinesisVideoStream->pUploadInfoQueue, i, &item));
        pUploadHandleInfo = (PUploadHandleInfo) item;
        CHK(pUploadHandleInfo != NULL, STATUS_INTERNAL_ERROR);

        // Call the notification callback to unblock potentially blocked listener for the first non terminated upload handle
        // The unblocked handle will unblock subsequent handles once it's done. Therefore break the loop
        if (pUploadHandleInfo->state != UPLOAD_HANDLE_STATE_TERMINATED) {
            // If we have sent all the data but still have metadata then we will
            // "mock" some duration and set the size to the not sent metadata size
            // in order not to close the network upload handler.
            if (notSent && (duration == 0)) {
                duration = 1;
                viewByteSize = pKinesisVideoStream->metadataTracker.size + pKinesisVideoStream->eosTracker.size;
            }

            CHK_STATUS(pKinesisVideoClient->clientCallbacks.streamDataAvailableFn(
                pKinesisVideoClient->clientCallbacks.customData, TO_STREAM_HANDLE(pKinesisVideoStream), pKinesisVideoStream->streamInfo.name,
                pUploadHandleInfo->handle, duration,
                viewByteSize + pKinesisVideoStream->curViewItem.viewItem.length - pKinesisVideoStream->curViewItem.offset));
            break;
        }
    }

    // Check if we need to call stream closed callback
    if (!notSent && viewByteSize == 0 && sessionCount == 0 && // If we have active handle, then eventually one of the handle will call streamClosedFn
        !pKinesisVideoStream->metadataTracker.send && !pKinesisVideoStream->eosTracker.send) {
        CHK_STATUS(notifyStreamClosed(pKinesisVideoStream, pUploadHandleInfo == NULL ? INVALID_UPLOAD_HANDLE_VALUE : pUploadHandleInfo->handle));
    }

    // Unlock the client as we no longer need it locked
    pKinesisVideoClient->clientCallbacks.unlockMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoClient->base.lock);
    clientLocked = FALSE;

    // Unlock the stream (even though it will be unlocked in the cleanup)
    pKinesisVideoClient->clientCallbacks.unlockMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoStream->base.lock);
    streamLocked = FALSE;

CleanUp:

    if (clientLocked) {
        pKinesisVideoClient->clientCallbacks.unlockMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoClient->base.lock);
    }

    if (streamLocked) {
        pKinesisVideoClient->clientCallbacks.unlockMutexFn(pKinesisVideoClient->clientCallbacks.customData, pKinesisVideoStream->base.lock);
    }

    LEAVES();
    return retStatus;
}