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());
}
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();
}
}
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);
}
}
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);
}
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");
}
Aggregations