diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fff420c9..660e472b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -18,7 +18,7 @@ jobs: contents: read strategy: matrix: - os: [ macos-10.15, ubuntu-18.04, windows-2019 ] + os: [ macos-10.15, ubuntu-18.04, windows-2019] java: [ 8, 11, 16 ] steps: - name: Checkout the repository diff --git a/README.md b/README.md index a7e51c32..919f4aef 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ $ mvn clean compile assembly:single Start the demo app ``` -$ java -classpath target/amazon-kinesis-video-streams-producer-sdk-java-1.12.0-jar-with-dependencies.jar -Daws.accessKeyId= -Daws.secretKey= -Dkvs-stream= -Djava.library.path= -Dlog4j.configurationFile=log4j2.xml com.amazonaws.kinesisvideo.demoapp.DemoAppMain +$ java -classpath target/amazon-kinesis-video-streams-producer-sdk-java-1.12.1-jar-with-dependencies.jar -Daws.accessKeyId= -Daws.secretKey= -Dkvs-stream= -Djava.library.path= -Dlog4j.configurationFile=log4j2.xml com.amazonaws.kinesisvideo.demoapp.DemoAppMain ``` ##### Run API and functionality tests @@ -134,6 +134,10 @@ The repository is using `develop` branch as the aggregation and all of the featu ## Release Notes +### Release 1.12.1 (May 2022) +* Allow updating automaticStreamingFlags (default: AUTOMATIC_STREAMING_INTERMITTENT_PRODUCER) in ClientInfo +* Allow updating storePressurePolicy (default: CONTENT_STORE_PRESSURE_POLICY_DROP_TAIL_ITEM) in StreamInfo + ### Release 1.12.0 (February 2022) * Update guice from 4.2.3 to 5.1.0 * Update junit from 4.13.1 to 4.13.2 diff --git a/pom.xml b/pom.xml index 635d2c7b..e4b89894 100644 --- a/pom.xml +++ b/pom.xml @@ -15,7 +15,7 @@ com.amazonaws amazon-kinesis-video-streams-producer-sdk-java Amazon Kinesis Video Streams Producer SDK Java - 1.12.0 + 1.12.1 The Amazon Kinesis Video Streams Producer SDK for Java enables Java developers to ingest data into Amazon Kinesis Video. diff --git a/src/main/java/com/amazonaws/kinesisvideo/java/mediasource/file/ImageFileMediaSource.java b/src/main/java/com/amazonaws/kinesisvideo/java/mediasource/file/ImageFileMediaSource.java index 23a453a9..df31072b 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/java/mediasource/file/ImageFileMediaSource.java +++ b/src/main/java/com/amazonaws/kinesisvideo/java/mediasource/file/ImageFileMediaSource.java @@ -18,7 +18,7 @@ import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.REQUEST_FRAGMENT_ACKS; import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.RETENTION_ONE_HOUR; import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.USE_FRAME_TIMECODES; -import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.VERSION_ZERO; +import static com.amazonaws.kinesisvideo.util.StreamInfoConstants.VERSION_TWO; import javax.annotation.Nonnull; import javax.annotation.Nullable; @@ -83,7 +83,7 @@ public MediaSourceConfiguration getConfiguration() { @Override public StreamInfo getStreamInfo() throws KinesisVideoException { - return new StreamInfo(VERSION_ZERO, + return new StreamInfo(VERSION_TWO, streamName, StreamInfo.StreamingType.STREAMING_TYPE_REALTIME, imageFileMediaSourceConfiguration.getContentType(), diff --git a/src/main/java/com/amazonaws/kinesisvideo/producer/ClientInfo.java b/src/main/java/com/amazonaws/kinesisvideo/producer/ClientInfo.java index bd1f6f46..22995784 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/producer/ClientInfo.java +++ b/src/main/java/com/amazonaws/kinesisvideo/producer/ClientInfo.java @@ -11,9 +11,23 @@ public class ClientInfo { /** * Current version for the structure as defined in the native code */ - public static final int CLIENT_INFO_CURRENT_VERSION = 0; + public static final int CLIENT_INFO_CURRENT_VERSION = 2; public static final int DEFAULT_LOG_LEVEL = 4; + public static enum AutomaticStreamingFlags { + AUTOMATIC_STREAMING_INTERMITTENT_PRODUCER(0), AUTOMATIC_STREAMING_ALWAYS_CONTINUOUS(256); + private final int streamingFlagValue; + + private AutomaticStreamingFlags(int streamingFlagValue) { + this.streamingFlagValue = streamingFlagValue; + } + + public int getStreamingFlagValue() { + return streamingFlagValue; + } + + } + private final int mVersion; private final long mCreateClientTimeout; private final long mCreateStreamTimeout; @@ -21,6 +35,7 @@ public class ClientInfo { private final long mOfflineBufferAvailabilityTimeout; private final int mLogLevel; private final boolean mLogMetric; + private final AutomaticStreamingFlags mAutomaticStreamingFlags; public ClientInfo() { mVersion = CLIENT_INFO_CURRENT_VERSION; @@ -30,18 +45,27 @@ public ClientInfo() { mOfflineBufferAvailabilityTimeout = 0L; mLogLevel = DEFAULT_LOG_LEVEL; mLogMetric = true; + mAutomaticStreamingFlags = AutomaticStreamingFlags.AUTOMATIC_STREAMING_INTERMITTENT_PRODUCER; } public ClientInfo(final long createClientTimeout, final long createStreamTimeout, final long stopStreamTimeout, - final long offlineBufferAvailabilityTimeout, - final int logLevel, final boolean logMetric) { + final long offlineBufferAvailabilityTimeout, final int logLevel, + final boolean logMetric) { + this(createClientTimeout, createStreamTimeout, stopStreamTimeout, offlineBufferAvailabilityTimeout, + logLevel, logMetric, AutomaticStreamingFlags.AUTOMATIC_STREAMING_INTERMITTENT_PRODUCER); + } + + public ClientInfo(final long createClientTimeout, final long createStreamTimeout, final long stopStreamTimeout, + final long offlineBufferAvailabilityTimeout, final int logLevel, + final boolean logMetric, final AutomaticStreamingFlags flag) { mVersion = CLIENT_INFO_CURRENT_VERSION; mCreateClientTimeout = createClientTimeout; mCreateStreamTimeout = createStreamTimeout; mStopStreamTimeout = stopStreamTimeout; mOfflineBufferAvailabilityTimeout = offlineBufferAvailabilityTimeout; - mLogLevel = DEFAULT_LOG_LEVEL; + mLogLevel = logLevel; mLogMetric = logMetric; + mAutomaticStreamingFlags = flag; } public int getVersion() { @@ -71,4 +95,8 @@ public int getLoggerLogLevel() { public boolean getLogMetric() { return mLogMetric; } + + public int getAutomaticStreamingFlags() { + return mAutomaticStreamingFlags.getStreamingFlagValue(); + } } diff --git a/src/main/java/com/amazonaws/kinesisvideo/producer/StreamInfo.java b/src/main/java/com/amazonaws/kinesisvideo/producer/StreamInfo.java index 412b9446..97a0fd83 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/producer/StreamInfo.java +++ b/src/main/java/com/amazonaws/kinesisvideo/producer/StreamInfo.java @@ -29,7 +29,7 @@ public class StreamInfo { * StreamInfo structure current version. * IMPORTANT: Must be kept in sync with the native counterpart. */ - public static final int STREAM_INFO_CURRENT_VERSION = 1; + public static final int STREAM_INFO_CURRENT_VERSION = 2; /** * Streaming types that must correspond to the native counterparts @@ -113,6 +113,34 @@ public int getIntValue() { } } + /** + * Storage pressure policy that must correspond to the native counterparts + */ + public static enum StorePressurePolicy { + /** + * Return an error STATUS_STORE_OUT_OF_MEMORY when we have no available storage when putting frame. + * The value of 0 is the default. + */ + CONTENT_STORE_PRESSURE_POLICY_OOM(0), + + /** + * Evict the earliest frames to make space for the new frame being put. + * Might result in dropped frame callbacks fired. + */ + CONTENT_STORE_PRESSURE_POLICY_DROP_TAIL_ITEM(1); + + private int value; + + private StorePressurePolicy(final int i) { + value = i; + } + + public int getIntValue() { + return value; + } + } + + private final int mVersion; private final String mName; private final StreamingType mStreamingType; @@ -139,6 +167,7 @@ public int getIntValue() { private final TrackInfo[] mTrackInfoList; private final UUID mSegmentUuid; private final FrameOrderMode mFrameOrderMode; + private final StorePressurePolicy mStorePressurePolicy; /** * Generates a track name from a content type @@ -262,6 +291,26 @@ public StreamInfo(final int version, @Nullable final String name, @Nonnull final @Nullable final UUID segmentUuid, @Nonnull final TrackInfo[] trackInfoList, FrameOrderMode frameOrderMode) { + this(version, name, streamingType, contentType, kmsKeyId, retentionPeriod, adaptive, maxLatency, + fragmentDuration, keyFrameFragmentation, frameTimecodes, absoluteFragmentTimes, fragmentAcks, + recoverOnError, avgBandwidthBps, frameRate, bufferDuration, replayDuration, + connectionStalenessDuration, timecodeScale, recalculateMetrics, tags, + nalAdaptationFlags, segmentUuid, trackInfoList, frameOrderMode, + StorePressurePolicy.CONTENT_STORE_PRESSURE_POLICY_DROP_TAIL_ITEM); + } + + public StreamInfo(final int version, @Nullable final String name, @Nonnull final StreamingType streamingType, + @Nonnull final String contentType, @Nullable final String kmsKeyId, final long retentionPeriod, + final boolean adaptive, final long maxLatency, final long fragmentDuration, + final boolean keyFrameFragmentation, final boolean frameTimecodes, + final boolean absoluteFragmentTimes, final boolean fragmentAcks, final boolean recoverOnError, + final int avgBandwidthBps, final int frameRate, final long bufferDuration, + final long replayDuration, final long connectionStalenessDuration, final long timecodeScale, + final boolean recalculateMetrics, @Nullable final Tag[] tags, + @Nonnull final NalAdaptationFlags nalAdaptationFlags, + @Nullable final UUID segmentUuid, + @Nonnull final TrackInfo[] trackInfoList, + FrameOrderMode frameOrderMode, StorePressurePolicy storePressurePolicy) { mVersion = version; mName = name; mStreamingType = streamingType; @@ -288,6 +337,7 @@ public StreamInfo(final int version, @Nullable final String name, @Nonnull final mSegmentUuid = segmentUuid; mTrackInfoList = trackInfoList; mFrameOrderMode = frameOrderMode; + mStorePressurePolicy = storePressurePolicy; } public int getVersion() { @@ -466,4 +516,8 @@ public int getNalAdaptationFlags() { public int getFrameOrderMode() { return mFrameOrderMode.intValue(); } + + public int getStorePressurePolicy() { + return mStorePressurePolicy.getIntValue(); + } } diff --git a/src/main/java/com/amazonaws/kinesisvideo/util/StreamInfoConstants.java b/src/main/java/com/amazonaws/kinesisvideo/util/StreamInfoConstants.java index 6fc84afd..3522db5a 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/util/StreamInfoConstants.java +++ b/src/main/java/com/amazonaws/kinesisvideo/util/StreamInfoConstants.java @@ -22,6 +22,8 @@ public final class StreamInfoConstants { public static final boolean RELATIVE_FRAGMENT_TIMECODES = false; public static final String NO_KMS_KEY_ID = null; public static final int VERSION_ZERO = 0; + public static final int VERSION_ONE = 1; + public static final int VERSION_TWO = 2; public static final long MAX_LATENCY_ZERO = 0L; // latency set to 0 will never trigger latency pressure callback public static final long MAX_LATENCY = 120L * HUNDREDS_OF_NANOS_IN_A_SECOND; public static final long NO_RETENTION = 0L; diff --git a/src/main/resources/lib/mac/libKinesisVideoProducerJNI.dylib b/src/main/resources/lib/mac/libKinesisVideoProducerJNI.dylib index 0306f79d..8bb26c36 100755 Binary files a/src/main/resources/lib/mac/libKinesisVideoProducerJNI.dylib and b/src/main/resources/lib/mac/libKinesisVideoProducerJNI.dylib differ diff --git a/src/main/resources/lib/ubuntu/libKinesisVideoProducerJNI.so b/src/main/resources/lib/ubuntu/libKinesisVideoProducerJNI.so index 4a0354ad..cf979e37 100755 Binary files a/src/main/resources/lib/ubuntu/libKinesisVideoProducerJNI.so and b/src/main/resources/lib/ubuntu/libKinesisVideoProducerJNI.so differ diff --git a/src/main/resources/lib/windows/KinesisVideoProducerJNI.dll b/src/main/resources/lib/windows/KinesisVideoProducerJNI.dll index d7ec53f5..b7816a3a 100644 Binary files a/src/main/resources/lib/windows/KinesisVideoProducerJNI.dll and b/src/main/resources/lib/windows/KinesisVideoProducerJNI.dll differ diff --git a/src/test/java/com/amazonaws/kinesisvideo/common/ProducerFunctionalityTest.java b/src/test/java/com/amazonaws/kinesisvideo/common/ProducerFunctionalityTest.java index 513135e8..f90706f3 100644 --- a/src/test/java/com/amazonaws/kinesisvideo/common/ProducerFunctionalityTest.java +++ b/src/test/java/com/amazonaws/kinesisvideo/common/ProducerFunctionalityTest.java @@ -403,7 +403,6 @@ public void offlineModeTokenRotationBlockOnSpace() { * produced after the pause. The pause will cause the state machine to change state to a new session. * The new session will not roll back as the previous one was closed with a persisted ACK received. */ - @Ignore @Test public void realtimeIntermittentNoLatencyPressureEofr() { KinesisVideoProducerStream kinesisVideoProducerStream; @@ -495,9 +494,8 @@ public void realtimeIntermittentNoLatencyPressureEofr() { } /** - * This test is disabled as Java SDK does not support Auto-intermittent Producer yet + * This test is tests Intermittent Producer under latency pressure */ - @Ignore @Test public void realtimeAutoIntermittentLatencyPressure() { KinesisVideoProducerStream kinesisVideoProducerStream; @@ -518,7 +516,6 @@ public void realtimeAutoIntermittentLatencyPressure() { deviceInfo_ = new DeviceInfo(DEVICE_VERSION, DEVICE_NAME, storageInfo_, NUMBER_OF_STREAMS, null); - createProducer(); keyFrameInterval_ = 60; diff --git a/src/test/java/com/amazonaws/kinesisvideo/common/ProducerTestBase.java b/src/test/java/com/amazonaws/kinesisvideo/common/ProducerTestBase.java index 4a7f2546..b8702264 100644 --- a/src/test/java/com/amazonaws/kinesisvideo/common/ProducerTestBase.java +++ b/src/test/java/com/amazonaws/kinesisvideo/common/ProducerTestBase.java @@ -8,6 +8,7 @@ import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.kinesisvideo.auth.DefaultAuthCallbacks; import com.amazonaws.kinesisvideo.client.KinesisVideoClientConfiguration; +import com.amazonaws.kinesisvideo.internal.producer.jni.NativeKinesisVideoProducerJni; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import com.amazonaws.kinesisvideo.demoapp.auth.AuthHelper; @@ -59,9 +60,7 @@ public class ProducerTestBase { protected StorageInfo storageInfo_ = new StorageInfo(0, StorageInfo.DeviceStorageType.DEVICE_STORAGE_TYPE_IN_MEM, STORAGE_SIZE_MEGS, SPILL_RATIO_PERCENT, STORAGE_PATH); - - protected DeviceInfo deviceInfo_ = new DeviceInfo(DEVICE_VERSION, - DEVICE_NAME, storageInfo_, NUMBER_OF_STREAMS, null); + protected DeviceInfo deviceInfo_; private final Logger log = LogManager.getLogger(ProducerTestBase.class); // flags that are updated in case of various events like overflow, error, pressure, etc. @@ -108,6 +107,17 @@ protected long getFragmentDurationMs() { * This method is used to create a KinesisVideoProducer which is used by the later methods */ protected void createProducer() { + deviceInfo_ = new DeviceInfo(DEVICE_VERSION, + DEVICE_NAME, storageInfo_, NUMBER_OF_STREAMS, null, + "JNI " + NativeKinesisVideoProducerJni.EXPECTED_LIBRARY_VERSION, + new ClientInfo()); + createProducer(deviceInfo_); + } + + /** + * This method is used to create a KinesisVideoProducer which is used by the later methods + */ + protected void createProducer(DeviceInfo deviceInfo) { reset(); // reset all flags to initial values so that they can be modified by the stream and storage callbacks @@ -137,9 +147,8 @@ protected void createProducer() { storageCallbacks, defaultServiceCallbacks, streamCallbacks); - try { - kinesisVideoProducer = kinesisVideoClient.initializeNewKinesisVideoProducer(deviceInfo_); + kinesisVideoProducer = kinesisVideoClient.initializeNewKinesisVideoProducer(deviceInfo); } catch(Exception e) { e.printStackTrace(); fail(); @@ -167,7 +176,7 @@ protected KinesisVideoProducerStream createTestStream(String streamName, StreamI (byte) 0x88, (byte) 0x46, (byte) 0xE0, (byte) 0x01, (byte) 0x00, (byte) 0x04, (byte) 0x28, (byte) 0xCE, (byte) 0x1F, (byte) 0x20}; - StreamInfo streamInfo = new StreamInfo(VERSION_ZERO, + StreamInfo streamInfo = new StreamInfo(VERSION_TWO, streamName, streamingType, "video/h264",