Search in sources :

Example 1 with VideoRecorder

use of com.aws.iot.edgeconnectorforkvs.videorecorder.VideoRecorder in project aws-iot-greengrass-edge-connector-for-kinesis-video-stream by awslabs.

the class EdgeConnectorForKVSServiceTest method test_StopLiveVideoStreaming_ProcessLock_Timeout.

@Test
public void test_StopLiveVideoStreaming_ProcessLock_Timeout(@TempDir Path tempDir) throws IOException, InterruptedException {
    // when
    List<EdgeConnectorForKVSConfiguration> edgeConnectorForKVSConfigurationList = new ArrayList();
    VideoRecorder videoRecorder = Mockito.mock(VideoRecorder.class);
    VideoUploader videoUploader = Mockito.mock(VideoUploader.class);
    PipedInputStream pipedInputStream = Mockito.mock(PipedInputStream.class);
    PipedOutputStream pipedOutputStream = Mockito.mock(PipedOutputStream.class);
    doNothing().when(videoUploader).close();
    doNothing().when(pipedOutputStream).flush();
    doNothing().when(pipedOutputStream).close();
    doNothing().when(pipedInputStream).close();
    doNothing().when(videoRecorder).stopRecording();
    ReentrantLock processLock = Mockito.mock(ReentrantLock.class);
    EdgeConnectorForKVSConfiguration edgeConnectorForKVSConfiguration = Mockito.spy(EdgeConnectorForKVSConfiguration.class);
    when(edgeConnectorForKVSConfiguration.getKinesisVideoStreamName()).thenReturn(MOCK_KINESIS_VIDEO_STREAM_NAME);
    when(edgeConnectorForKVSConfiguration.getLiveStreamingStartTime()).thenReturn(START_TIME_ALWAYS);
    when(edgeConnectorForKVSConfiguration.getCaptureStartTime()).thenReturn(START_TIME_ALWAYS);
    doNothing().when(edgeConnectorForKVSConfiguration).setVideoRecorder(any());
    when(edgeConnectorForKVSConfiguration.getVideoRecorder()).thenReturn(videoRecorder);
    when(edgeConnectorForKVSConfiguration.getVideoRecordFolderPath()).thenReturn(tempDir);
    doNothing().when(edgeConnectorForKVSConfiguration).setVideoUploader(any());
    when(edgeConnectorForKVSConfiguration.getVideoUploader()).thenReturn(videoUploader);
    when(edgeConnectorForKVSConfiguration.getRecordingRequestsCount()).thenReturn(1);
    doNothing().when(edgeConnectorForKVSConfiguration).setInputStream(any());
    when(edgeConnectorForKVSConfiguration.getInputStream()).thenReturn(pipedInputStream);
    doNothing().when(edgeConnectorForKVSConfiguration).setOutputStream(any());
    when(edgeConnectorForKVSConfiguration.getOutputStream()).thenReturn(pipedOutputStream);
    doNothing().when(edgeConnectorForKVSConfiguration).setProcessLock(any());
    when(edgeConnectorForKVSConfiguration.getProcessLock()).thenReturn(processLock);
    when(processLock.tryLock(anyLong(), any())).thenReturn(false);
    edgeConnectorForKVSConfigurationList.add(edgeConnectorForKVSConfiguration);
    // Mock for initConfiguration
    when(siteWiseManager.initEdgeConnectorForKVSServiceConfiguration(any())).thenReturn(edgeConnectorForKVSConfigurationList);
    // Mock for initSecretsManager
    when(secretsClient.getSecretValue(any())).thenReturn(gson.toJson(secretMap));
    // then
    edgeConnectorForKVSService.setUpSharedEdgeConnectorForKVSService();
    edgeConnectorForKVSService.setUpCameraLevelEdgeConnectorForKVSService(edgeConnectorForKVSConfiguration);
    Thread.sleep(2000);
    edgeConnectorForKVSService.schedulerStopTaskCallback(Constants.JobType.LIVE_VIDEO_STREAMING, MOCK_KINESIS_VIDEO_STREAM_NAME);
    Thread.sleep(1000);
    // verify
    assertEquals(true, edgeConnectorForKVSConfiguration.getFatalStatus().get());
}
Also used : ReentrantLock(java.util.concurrent.locks.ReentrantLock) VideoUploader(com.aws.iot.edgeconnectorforkvs.videouploader.VideoUploader) ArrayList(java.util.ArrayList) EdgeConnectorForKVSConfiguration(com.aws.iot.edgeconnectorforkvs.model.EdgeConnectorForKVSConfiguration) VideoRecorder(com.aws.iot.edgeconnectorforkvs.videorecorder.VideoRecorder) PipedOutputStream(java.io.PipedOutputStream) PipedInputStream(java.io.PipedInputStream) Test(org.junit.jupiter.api.Test)

Example 2 with VideoRecorder

use of com.aws.iot.edgeconnectorforkvs.videorecorder.VideoRecorder in project aws-iot-greengrass-edge-connector-for-kinesis-video-stream by awslabs.

the class EdgeConnectorForKVSService method stopLiveVideoStreaming.

private void stopLiveVideoStreaming(EdgeConnectorForKVSConfiguration edgeConnectorForKVSConfiguration) throws IOException {
    ReentrantLock processLock = edgeConnectorForKVSConfiguration.getProcessLock();
    try {
        if (processLock.tryLock(INIT_LOCK_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)) {
            log.info("Stop Live Video Streaming Called for " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName());
            log.info("Calling function " + Constants.getCallingFunctionName(2));
            // Stop video recording provided there's no scheduled / mqtt based live streaming in progress
            edgeConnectorForKVSConfiguration.setLiveStreamingRequestsCount(edgeConnectorForKVSConfiguration.getLiveStreamingRequestsCount() - 1);
            if (edgeConnectorForKVSConfiguration.getLiveStreamingRequestsCount() > 0) {
                log.info("Live Streaming is being used by multiple tasks. Requests Count " + edgeConnectorForKVSConfiguration.getLiveStreamingRequestsCount());
                return;
            }
            log.info("Live Steaming Requests Count is 0. Stopping.");
            VideoRecorder videoRecorder = edgeConnectorForKVSConfiguration.getVideoRecorder();
            VideoUploader videoUploader = edgeConnectorForKVSConfiguration.getVideoUploader();
            log.info("Toggle output stream off for KVS Stream: " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName());
            videoRecorder.toggleAppDataOutputStream(false);
            log.info("Close video uploader for KVS Stream: " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName());
            videoUploader.close();
            // Manually flush input stream
            flushInputStream(edgeConnectorForKVSConfiguration.getInputStream());
            edgeConnectorForKVSConfiguration.getInputStream().close();
            edgeConnectorForKVSConfiguration.getOutputStream().close();
            // Stop recording if it was kicked-off only for this live streaming
            stopRecordingJob(edgeConnectorForKVSConfiguration);
        } else {
            log.error("Stop uploading for " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName() + " timeout, re-init camera to restart the process.");
            edgeConnectorForKVSConfiguration.getFatalStatus().set(true);
        }
    } catch (InterruptedException e) {
        log.error("Stop uploading for " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName() + " has been interrupted, re-init camera to restart the process.");
        edgeConnectorForKVSConfiguration.getFatalStatus().set(true);
    } finally {
        if (processLock.isHeldByCurrentThread())
            processLock.unlock();
    }
}
Also used : ReentrantLock(java.util.concurrent.locks.ReentrantLock) VideoUploader(com.aws.iot.edgeconnectorforkvs.videouploader.VideoUploader) VideoRecorder(com.aws.iot.edgeconnectorforkvs.videorecorder.VideoRecorder)

Example 3 with VideoRecorder

use of com.aws.iot.edgeconnectorforkvs.videorecorder.VideoRecorder in project aws-iot-greengrass-edge-connector-for-kinesis-video-stream by awslabs.

the class EdgeConnectorForKVSService method startRecordingJob.

private void startRecordingJob(EdgeConnectorForKVSConfiguration edgeConnectorForKVSConfiguration) {
    VideoRecorder videoRecorder = null;
    ReentrantLock processLock = edgeConnectorForKVSConfiguration.getProcessLock();
    try {
        if (processLock.tryLock(INIT_LOCK_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)) {
            log.info("Start Recording called for " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName());
            log.info("Calling function " + Constants.getCallingFunctionName(2));
            edgeConnectorForKVSConfiguration.setRecordingRequestsCount(edgeConnectorForKVSConfiguration.getRecordingRequestsCount() + 1);
            if (edgeConnectorForKVSConfiguration.getRecordingRequestsCount() > 1) {
                log.info("Recording already running. Requests Count: " + edgeConnectorForKVSConfiguration.getRecordingRequestsCount());
                return;
            }
            VideoRecorderBuilder builder = new VideoRecorderBuilder(new StatusCallback() {

                @Override
                public void notifyStatus(VideoRecorderBase recorder, RecorderStatus status, String description) {
                    String pipeLineName = recorder.getPipeline().getName();
                    log.info("Recorder[" + pipeLineName + "] status changed callback: " + status);
                    // Camera level restart is in progress
                    if (status.equals(RecorderStatus.FAILED) && edgeConnectorForKVSConfiguration.getRecordingRequestsCount() > 0) {
                        log.warn("Recorder failed due to errors. Pipeline name: " + pipeLineName);
                        log.warn("Trying restart recorder");
                        recorderService.submit(() -> {
                            restartRecorder(recorder);
                        });
                    }
                }

                private void restartRecorder(@NonNull VideoRecorderBase recorder) {
                    recorder.stopRecording();
                    try {
                        Thread.sleep(restartSleepTime);
                    } catch (InterruptedException e) {
                        log.error("Thread sleep interrupted.");
                    }
                    recorder.startRecording();
                    log.info("Restart Recording for pipeline recorder " + recorder.getPipeline().getName());
                }
            });
            PipedOutputStream outputStream = new PipedOutputStream();
            builder.registerCamera(CameraType.RTSP, edgeConnectorForKVSConfiguration.getRtspStreamURL());
            builder.registerFileSink(ContainerType.MATROSKA, videoRecordingRootPath + edgeConnectorForKVSConfiguration.getSiteWiseAssetId() + PATH_DELIMITER + "video");
            builder.registerAppDataCallback(ContainerType.MATROSKA, new GStreamerAppDataCallback());
            builder.registerAppDataOutputStream(ContainerType.MATROSKA, outputStream);
            videoRecorder = builder.construct();
            edgeConnectorForKVSConfiguration.setVideoRecorder(videoRecorder);
            edgeConnectorForKVSConfiguration.setOutputStream(outputStream);
            log.info("Recorder for " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName() + " has been initialized");
        } else {
            // Recorder cannot init. Will retry in the method end
            log.error("Fail to init recorder for " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName());
        }
    } catch (InterruptedException e) {
        log.error("Init recorder process for " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName() + " has been interrupted, re-init camera to restart the process.");
        edgeConnectorForKVSConfiguration.getFatalStatus().set(true);
    } finally {
        if (processLock.isHeldByCurrentThread())
            processLock.unlock();
    }
    if (videoRecorder != null) {
        log.info("Start recording for " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName());
        videoRecorder.startRecording();
    } else {
        log.error("Fail to init recorder for " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName());
        edgeConnectorForKVSConfiguration.getFatalStatus().set(true);
    }
}
Also used : ReentrantLock(java.util.concurrent.locks.ReentrantLock) GStreamerAppDataCallback(com.aws.iot.edgeconnectorforkvs.videorecorder.callback.GStreamerAppDataCallback) VideoRecorderBuilder(com.aws.iot.edgeconnectorforkvs.videorecorder.VideoRecorderBuilder) RecorderStatus(com.aws.iot.edgeconnectorforkvs.videorecorder.model.RecorderStatus) VideoRecorderBase(com.aws.iot.edgeconnectorforkvs.videorecorder.base.VideoRecorderBase) VideoRecorder(com.aws.iot.edgeconnectorforkvs.videorecorder.VideoRecorder) StatusCallback(com.aws.iot.edgeconnectorforkvs.videorecorder.callback.StatusCallback) PipedOutputStream(java.io.PipedOutputStream)

Example 4 with VideoRecorder

use of com.aws.iot.edgeconnectorforkvs.videorecorder.VideoRecorder in project aws-iot-greengrass-edge-connector-for-kinesis-video-stream by awslabs.

the class EdgeConnectorForKVSService method startLiveVideoStreaming.

private void startLiveVideoStreaming(EdgeConnectorForKVSConfiguration edgeConnectorForKVSConfiguration) throws IOException, InterruptedException {
    ReentrantLock processLock = edgeConnectorForKVSConfiguration.getProcessLock();
    try {
        if (processLock.tryLock(INIT_LOCK_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)) {
            log.info("Start Live Video Streaming Called for " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName());
            log.info("Calling function " + Constants.getCallingFunctionName(2));
            edgeConnectorForKVSConfiguration.setLiveStreamingRequestsCount(edgeConnectorForKVSConfiguration.getLiveStreamingRequestsCount() + 1);
            if (edgeConnectorForKVSConfiguration.getLiveStreamingRequestsCount() > 1) {
                log.info("Live Streaming already running. Requests Count: " + edgeConnectorForKVSConfiguration.getLiveStreamingRequestsCount());
                return;
            }
        } else {
            log.error("Start uploading for " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName() + " timeout, re-init camera to restart the process.");
            edgeConnectorForKVSConfiguration.getFatalStatus().set(true);
        }
    } catch (InterruptedException e) {
        log.error("Start uploading for " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName() + " has been interrupted, re-init camera to restart the process.");
        edgeConnectorForKVSConfiguration.getFatalStatus().set(true);
    } finally {
        if (processLock.isHeldByCurrentThread())
            processLock.unlock();
    }
    // kick-off recording if it wasn't already started
    Future<?> future = recorderService.submit(() -> {
        startRecordingJob(edgeConnectorForKVSConfiguration);
    });
    try {
        // startRecordingJob is a blocking call, so we wait
        // upto 5 seconds for the recording to start before
        // we start live streaming below
        future.get(RECORDING_JOB_WAIT_TIME_IN_SECS, TimeUnit.SECONDS);
    } catch (InterruptedException ex) {
        log.error("Start Live Streaming Interrupted Exception: " + ex.getMessage());
    } catch (ExecutionException ex) {
        log.error("Start Live Streaming Execution Exception: " + ex.getMessage());
    } catch (TimeoutException ex) {
    // Ignore this exception, it is expected since
    // startRecordingJob is a blocking call
    }
    VideoRecorder videoRecorder = edgeConnectorForKVSConfiguration.getVideoRecorder();
    VideoUploader videoUploader = edgeConnectorForKVSConfiguration.getVideoUploader();
    do {
        PipedOutputStream outputStream = new PipedOutputStream();
        PipedInputStream inputStream = new PipedInputStream();
        // Toggle to false before switching outputStream (may not be required)
        videoRecorder.toggleAppDataOutputStream(false);
        edgeConnectorForKVSConfiguration.setOutputStream(outputStream);
        edgeConnectorForKVSConfiguration.setInputStream(inputStream);
        outputStream.connect(inputStream);
        videoRecorder.setAppDataOutputStream(outputStream);
        log.info("Connected streams for KVS Stream: " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName());
        videoRecorder.toggleAppDataOutputStream(true);
        log.info("Turned on outputStream in recorder and start uploading!");
        Date dateNow = new Date();
        try {
            videoUploader.uploadStream(inputStream, dateNow, new StatusChangedCallBack(), new UploadCallBack(dateNow, edgeConnectorForKVSConfiguration));
        } catch (Exception exception) {
            if (processLock.tryLock(INIT_LOCK_TIMEOUT_IN_SECONDS, TimeUnit.SECONDS)) {
                log.error("Failed to upload stream: {}", exception.getMessage());
                AtomicBoolean isRecorderToggleOff = new AtomicBoolean();
                Thread toggleRecorderOffThreaed = new Thread(() -> {
                    log.info("Waiting for toggling recorder off");
                    videoRecorder.toggleAppDataOutputStream(false);
                    try {
                        TimeUnit.MILLISECONDS.sleep(2000);
                    } catch (InterruptedException e) {
                        log.error("toggleRecorderOffThread exception: " + e.getMessage());
                    }
                    isRecorderToggleOff.set(true);
                    log.info("Toggling recorder off");
                });
                toggleRecorderOffThreaed.start();
                log.info("InputStream is flushing");
                try {
                    int bytesAvailable = inputStream.available();
                    while (!isRecorderToggleOff.get() || bytesAvailable > 0) {
                        byte[] b = new byte[bytesAvailable];
                        inputStream.read(b);
                        bytesAvailable = inputStream.available();
                    }
                } catch (IOException e) {
                    log.error("Exception flush inputStream: " + e.getMessage());
                } finally {
                    if (processLock.isHeldByCurrentThread())
                        processLock.unlock();
                }
                log.info("InputStream is flushed");
                outputStream.close();
                inputStream.close();
            } else {
                log.error("Restart uploading for " + edgeConnectorForKVSConfiguration.getKinesisVideoStreamName() + " timeout, re-init camera to restart the process.");
                edgeConnectorForKVSConfiguration.getFatalStatus().set(true);
                if (processLock.isHeldByCurrentThread())
                    processLock.unlock();
                break;
            }
        }
    } while (retryOnFail && edgeConnectorForKVSConfiguration.getLiveStreamingRequestsCount() > 0);
}
Also used : ReentrantLock(java.util.concurrent.locks.ReentrantLock) VideoUploader(com.aws.iot.edgeconnectorforkvs.videouploader.VideoUploader) StatusChangedCallBack(com.aws.iot.edgeconnectorforkvs.videouploader.callback.StatusChangedCallBack) VideoRecorder(com.aws.iot.edgeconnectorforkvs.videorecorder.VideoRecorder) PipedOutputStream(java.io.PipedOutputStream) PipedInputStream(java.io.PipedInputStream) IOException(java.io.IOException) Date(java.util.Date) TimeoutException(java.util.concurrent.TimeoutException) EdgeConnectorForKVSException(com.aws.iot.edgeconnectorforkvs.model.exceptions.EdgeConnectorForKVSException) EdgeConnectorForKVSUnrecoverableException(com.aws.iot.edgeconnectorforkvs.model.exceptions.EdgeConnectorForKVSUnrecoverableException) IOException(java.io.IOException) ExecutionException(java.util.concurrent.ExecutionException) UploadCallBack(com.aws.iot.edgeconnectorforkvs.videouploader.callback.UploadCallBack) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) ExecutionException(java.util.concurrent.ExecutionException) TimeoutException(java.util.concurrent.TimeoutException)

Example 5 with VideoRecorder

use of com.aws.iot.edgeconnectorforkvs.videorecorder.VideoRecorder in project aws-iot-greengrass-edge-connector-for-kinesis-video-stream by awslabs.

the class EdgeConnectorForKVSService method cleanUpEdgeConnectorForKVSService.

@Synchronized
public void cleanUpEdgeConnectorForKVSService(EdgeConnectorForKVSConfiguration restartNeededConfiguration) {
    // DeInit all cameras if camera level restart failed
    if (restartNeededConfiguration == null) {
        log.info("Edge connector for KVS service is cleaning up for all cameras");
        jobScheduler.stopAllCameras();
        edgeConnectorForKVSConfigurationList.forEach(configuration -> {
            // Deinit video uploader
            deInitVideoUploaders(configuration);
            VideoRecorder videoRecorder = configuration.getVideoRecorder();
            // Deinit video recorder if video recorder is not closed by deInitVideoUploaders
            if (videoRecorder != null && !videoRecorder.getStatus().equals(RecorderStatus.STOPPED)) {
                // Unlock the processing lock so we can stop the recorder
                if (configuration.getProcessLock().isHeldByCurrentThread()) {
                    configuration.getProcessLock().unlock();
                }
                deInitVideoRecorders(configuration);
            }
        });
    } else {
        log.info("Edge connector for KVS service is cleaning up for this camera: KVS stream: " + restartNeededConfiguration.getKinesisVideoStreamName() + ", siteWise ID: " + restartNeededConfiguration.getSiteWiseAssetId());
        // Stop scheduler for failed cameras only
        jobScheduler.stop(restartNeededConfiguration);
        // Deinit video uploader
        deInitVideoUploaders(restartNeededConfiguration);
        // Deinit video recorder if video recorder is not closed by deInitVideoUploaders
        VideoRecorder restartNeededVideoRecorder = restartNeededConfiguration.getVideoRecorder();
        if (restartNeededVideoRecorder != null && !restartNeededVideoRecorder.getStatus().equals(RecorderStatus.STOPPED)) {
            // Unlock the processing lock so we can stop the recorder
            if (restartNeededConfiguration.getProcessLock().isHeldByCurrentThread()) {
                restartNeededConfiguration.getProcessLock().unlock();
            }
            deInitVideoRecorders(restartNeededConfiguration);
        }
    }
    log.info("Edge connector for KVS service is cleaned up");
}
Also used : VideoRecorder(com.aws.iot.edgeconnectorforkvs.videorecorder.VideoRecorder) Synchronized(lombok.Synchronized)

Aggregations

VideoRecorder (com.aws.iot.edgeconnectorforkvs.videorecorder.VideoRecorder)13 VideoUploader (com.aws.iot.edgeconnectorforkvs.videouploader.VideoUploader)10 EdgeConnectorForKVSConfiguration (com.aws.iot.edgeconnectorforkvs.model.EdgeConnectorForKVSConfiguration)8 ArrayList (java.util.ArrayList)8 Test (org.junit.jupiter.api.Test)8 PipedOutputStream (java.io.PipedOutputStream)7 ReentrantLock (java.util.concurrent.locks.ReentrantLock)7 PipedInputStream (java.io.PipedInputStream)4 VideoUploadRequestEvent (com.aws.iot.edgeconnectorforkvs.handler.VideoUploadRequestEvent)2 KvsStreamingException (com.aws.iot.edgeconnectorforkvs.videouploader.model.exceptions.KvsStreamingException)2 EdgeConnectorForKVSException (com.aws.iot.edgeconnectorforkvs.model.exceptions.EdgeConnectorForKVSException)1 EdgeConnectorForKVSUnrecoverableException (com.aws.iot.edgeconnectorforkvs.model.exceptions.EdgeConnectorForKVSUnrecoverableException)1 VideoRecorderBuilder (com.aws.iot.edgeconnectorforkvs.videorecorder.VideoRecorderBuilder)1 VideoRecorderBase (com.aws.iot.edgeconnectorforkvs.videorecorder.base.VideoRecorderBase)1 GStreamerAppDataCallback (com.aws.iot.edgeconnectorforkvs.videorecorder.callback.GStreamerAppDataCallback)1 StatusCallback (com.aws.iot.edgeconnectorforkvs.videorecorder.callback.StatusCallback)1 RecorderStatus (com.aws.iot.edgeconnectorforkvs.videorecorder.model.RecorderStatus)1 StatusChangedCallBack (com.aws.iot.edgeconnectorforkvs.videouploader.callback.StatusChangedCallBack)1 UploadCallBack (com.aws.iot.edgeconnectorforkvs.videouploader.callback.UploadCallBack)1 IOException (java.io.IOException)1