diff --git a/.github/matrix.yaml b/.github/matrix.yaml index a6b766d40..45afa037a 100644 --- a/.github/matrix.yaml +++ b/.github/matrix.yaml @@ -6,6 +6,7 @@ matrix: name: macos-aarch64 - os: ubuntu-22.04 name: ubuntu-22.04 + upload_coverage: true - os: windows-2022 name: windows-2022 java: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2042e36c7..63196b625 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -43,7 +43,7 @@ jobs: runs-on: ${{ matrix.platform.os }} env: - BRANCH_NAME: develop + BRANCH_NAME: jni-clientinfo steps: - name: Checkout the repository @@ -155,9 +155,18 @@ jobs: - name: Run tests run: | - mvn clean test -DargLine="-Daws.accessKeyId=${AWS_ACCESS_KEY_ID} -Daws.secretKey=${AWS_SECRET_ACCESS_KEY} -Daws.sessionToken=${AWS_SESSION_TOKEN} -Djava.library.path=${JNI_FOLDER} -Dlog4j.configurationFile=log4j2.xml" + mvn clean verify -DargLine="-Daws.accessKeyId=${AWS_ACCESS_KEY_ID} -Daws.secretKey=${AWS_SECRET_ACCESS_KEY} -Daws.sessionToken=${AWS_SESSION_TOKEN} -Djava.library.path=${JNI_FOLDER} -Dlog4j.configurationFile=log4j2.xml" shell: bash + - name: Upload code coverage + # Only upload code coverage once + if: ${{ matrix.upload_coverage == true }} + uses: codecov/codecov-action@v4 + with: + token: ${{ secrets.CODECOV_TOKEN }} + files: target/site/jacoco/jacoco.xml + fail_ci_if_error: true + run-samples: needs: - load-matrix diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml deleted file mode 100644 index ff3d2cbd6..000000000 --- a/.github/workflows/code-coverage.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Code coverage report - -on: - push: - branches: - - develop - - master - pull_request: - branches: - - develop - - master - -jobs: - code-coverage: - runs-on: ubuntu-latest - permissions: - id-token: write - contents: read - - steps: - - name: Checkout the repository - uses: actions/checkout@v4 - - - name: Set up JDK 11 - uses: actions/setup-java@v4 - with: - java-version: 11 - distribution: 'adopt' - - - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v4 - with: - role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }} - aws-region: ${{ secrets.AWS_REGION }} - - - name: Run tests - run: | - mvn clean verify -DargLine="\ - -Daws.accessKeyId=${AWS_ACCESS_KEY_ID} \ - -Daws.secretKey=${AWS_SECRET_ACCESS_KEY} \ - -Daws.sessionToken=${AWS_SESSION_TOKEN} \ - -Djava.library.path=src/main/resources/lib/ubuntu/ \ - -Dlog4j.configurationFile=log4j2.xml" - shell: bash - - - name: Upload coverage reports to Codecov - uses: codecov/codecov-action@v4 - with: - token: ${{ secrets.CODECOV_TOKEN }} - files: target/site/jacoco/jacoco.xml - fail_ci_if_error: true diff --git a/.gitignore b/.gitignore index 6aa446dea..369c8d7b0 100644 --- a/.gitignore +++ b/.gitignore @@ -9,6 +9,8 @@ cm-file .DS_Store target +out/ +src/main/resources/META-INF/* logs -hs_err_pid*.log - +*.log +*.log.* diff --git a/src/main/java/com/amazonaws/kinesisvideo/internal/producer/KinesisVideoProducer.java b/src/main/java/com/amazonaws/kinesisvideo/internal/producer/KinesisVideoProducer.java index a239f68d8..b373b2f98 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/internal/producer/KinesisVideoProducer.java +++ b/src/main/java/com/amazonaws/kinesisvideo/internal/producer/KinesisVideoProducer.java @@ -64,7 +64,7 @@ public interface KinesisVideoProducer { * Creates Kinesis Video stream * * @param streamInfo Stream information {@link StreamInfo} object - * @param streamCallbacks Optional stream callnbacks {@link StreamCallbacks} + * @param streamCallbacks Optional stream callbacks {@link StreamCallbacks} * @return The newly created stream * @throws ProducerException */ @@ -76,7 +76,7 @@ KinesisVideoProducerStream createStream(final @Nonnull StreamInfo streamInfo, * Creates Kinesis Video stream synchronously * * @param streamInfo Stream information {@link StreamInfo} object - * @param streamCallbacks Optional stream callnbacks {@link StreamCallbacks} + * @param streamCallbacks Optional stream callbacks {@link StreamCallbacks} * @return The newly created stream * @throws ProducerException */ diff --git a/src/main/java/com/amazonaws/kinesisvideo/internal/producer/jni/NativeKinesisVideoProducerJni.java b/src/main/java/com/amazonaws/kinesisvideo/internal/producer/jni/NativeKinesisVideoProducerJni.java index 98fa4de5a..bd1bc4bfe 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/internal/producer/jni/NativeKinesisVideoProducerJni.java +++ b/src/main/java/com/amazonaws/kinesisvideo/internal/producer/jni/NativeKinesisVideoProducerJni.java @@ -57,7 +57,7 @@ public class NativeKinesisVideoProducerJni implements KinesisVideoProducer { /** * The expected library version. */ - public static final String EXPECTED_LIBRARY_VERSION = "2.0"; + public static final String EXPECTED_LIBRARY_VERSION = "2.1"; /** * The manifest handle will be set after call to parse() diff --git a/src/main/java/com/amazonaws/kinesisvideo/producer/AutomaticStreamingFlags.java b/src/main/java/com/amazonaws/kinesisvideo/producer/AutomaticStreamingFlags.java new file mode 100644 index 000000000..a99dffda7 --- /dev/null +++ b/src/main/java/com/amazonaws/kinesisvideo/producer/AutomaticStreamingFlags.java @@ -0,0 +1,37 @@ +package com.amazonaws.kinesisvideo.producer; + +/** + * Java model for native code in PIC. + *

+ * In some streaming scenarios video is not constantly being produced, + * in this case special handling must take place to handle various streaming + * scenarios. + * + * @see PIC + */ +public enum AutomaticStreamingFlags { + /** + * With this option we'll create a timer (burns a thread) and periodically check + * if there are any streams which haven't had any PutFrame calls + * over fixed period of time, in which case we'll close out the fragment + * to prevent back-end from timing out and closing the session + */ + AUTOMATIC_STREAMING_INTERMITTENT_PRODUCER(0), + + /** + * This option indicates a desire to do continuous recording with no gaps + * this doesn't mean we can't have dropped packets, this mode should NOT + * be used if for example only motion or event based video is to be recorded + */ + AUTOMATIC_STREAMING_ALWAYS_CONTINUOUS((1 << 8)); + + private final int streamingFlagValue; + + AutomaticStreamingFlags(final int streamingFlagValue) { + this.streamingFlagValue = streamingFlagValue; + } + + public int getStreamingFlagValue() { + return streamingFlagValue; + } +} diff --git a/src/main/java/com/amazonaws/kinesisvideo/producer/ClientInfo.java b/src/main/java/com/amazonaws/kinesisvideo/producer/ClientInfo.java index ed6920789..14b97376a 100644 --- a/src/main/java/com/amazonaws/kinesisvideo/producer/ClientInfo.java +++ b/src/main/java/com/amazonaws/kinesisvideo/producer/ClientInfo.java @@ -11,45 +11,49 @@ public class ClientInfo { /** * Current version for the structure as defined in the native code */ + public static final int CLIENT_INFO_CURRENT_VERSION = 3; 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; private final long mStopStreamTimeout; private final long mOfflineBufferAvailabilityTimeout; - private final int mLogLevel; + + private final int mLoggerLogLevel; private final boolean mLogMetric; private final AutomaticStreamingFlags mAutomaticStreamingFlags; + private final long mServiceCallCompletionTimeout; private final long mServiceCallConnectionTimeout; + /** + * NOTE: The below members are not supported for setting/getting in Java. These will be set to + * default values in the JNI and C layers. + */ + private final long mMetricLoggingPeriod; + private final long mReservedCallbackPeriod; + private final KvsRetryStrategy mKvsRetryStrategy; + private final KvsRetryStrategyCallbacks mKvsRetryStrategyCallbacks; + + public ClientInfo() { mVersion = CLIENT_INFO_CURRENT_VERSION; mCreateClientTimeout = 0L; mCreateStreamTimeout = 0L; mStopStreamTimeout = 0L; mOfflineBufferAvailabilityTimeout = 0L; - mLogLevel = DEFAULT_LOG_LEVEL; + mLoggerLogLevel = DEFAULT_LOG_LEVEL; mLogMetric = true; mAutomaticStreamingFlags = AutomaticStreamingFlags.AUTOMATIC_STREAMING_INTERMITTENT_PRODUCER; mServiceCallCompletionTimeout = 0L; mServiceCallConnectionTimeout = 0L; + mMetricLoggingPeriod = 0; + mReservedCallbackPeriod = 0; + mKvsRetryStrategyCallbacks = new DefaultKvsRetryStrategyCallbacks(); + mKvsRetryStrategy = new KvsRetryStrategy(); } public ClientInfo(final long createClientTimeout, final long createStreamTimeout, final long stopStreamTimeout, @@ -68,11 +72,34 @@ public ClientInfo(final long createClientTimeout, final long createStreamTimeout mCreateStreamTimeout = createStreamTimeout; mStopStreamTimeout = stopStreamTimeout; mOfflineBufferAvailabilityTimeout = offlineBufferAvailabilityTimeout; - mLogLevel = logLevel; + mLoggerLogLevel = logLevel; + mLogMetric = logMetric; + mAutomaticStreamingFlags = flag; + mServiceCallCompletionTimeout = 0L; + mServiceCallConnectionTimeout = 0L; + mMetricLoggingPeriod = 0; + mReservedCallbackPeriod = 0; + mKvsRetryStrategyCallbacks = new DefaultKvsRetryStrategyCallbacks(); + mKvsRetryStrategy = new KvsRetryStrategy(); } + + public ClientInfo(final long createClientTimeout, final long createStreamTimeout, final long stopStreamTimeout, + final long offlineBufferAvailabilityTimeout, final long serviceCallConnectionTimeou, + final long serviceCallCompletionTimeout, final int logLevel, + final boolean logMetric, final AutomaticStreamingFlags flag) { + mVersion = CLIENT_INFO_CURRENT_VERSION; + mCreateClientTimeout = createClientTimeout; + mCreateStreamTimeout = createStreamTimeout; + mStopStreamTimeout = stopStreamTimeout; + mOfflineBufferAvailabilityTimeout = offlineBufferAvailabilityTimeout; + mLoggerLogLevel = logLevel; mLogMetric = logMetric; mAutomaticStreamingFlags = flag; mServiceCallCompletionTimeout = serviceCallCompletionTimeout; - mServiceCallConnectionTimeout = serviceCallConnectionTimeout; + mServiceCallConnectionTimeout = serviceCallConnectionTimeou; + mMetricLoggingPeriod = 0; + mReservedCallbackPeriod = 0; + mKvsRetryStrategyCallbacks = new DefaultKvsRetryStrategyCallbacks(); + mKvsRetryStrategy = new KvsRetryStrategy(); } public int getVersion() { @@ -95,8 +122,16 @@ public long getOfflineBufferAvailabilityTimeout() { return mOfflineBufferAvailabilityTimeout; } + public long getServiceCallCompletionTimeout() { + return mServiceCallCompletionTimeout; + } + + public long getServiceCallConnectionTimeout() { + return mServiceCallConnectionTimeout; + } + public int getLoggerLogLevel() { - return mLogLevel; + return mLoggerLogLevel; } public boolean getLogMetric() { @@ -107,11 +142,23 @@ public int getAutomaticStreamingFlags() { return mAutomaticStreamingFlags.getStreamingFlagValue(); } - public long getServiceCompletionTimeout() { - return mServiceCallCompletionTimeout; + public long getMetricLoggingPeriod() { + return mMetricLoggingPeriod; } - public long getServiceConnectionTimeout() { - return mServiceCallConnectionTimeout; + public long getReservedCallbackPeriod() { + return mReservedCallbackPeriod; + } + + public KvsRetryStrategy getKvsRetryStrategy() { + return mKvsRetryStrategy; + } + + /** + * NOTE: The below getters are not supported for setting/getting in Java. These will return + * null to be initialized to default/null values in the JNI and C layers. + */ + public KvsRetryStrategyCallbacks getKvsRetryStrategyCallbacks() { + return null; } } diff --git a/src/main/java/com/amazonaws/kinesisvideo/producer/DefaultKvsRetryStrategyCallbacks.java b/src/main/java/com/amazonaws/kinesisvideo/producer/DefaultKvsRetryStrategyCallbacks.java new file mode 100644 index 000000000..94a87cfaf --- /dev/null +++ b/src/main/java/com/amazonaws/kinesisvideo/producer/DefaultKvsRetryStrategyCallbacks.java @@ -0,0 +1,28 @@ +package com.amazonaws.kinesisvideo.producer; + +/** + * No-op implementation. + */ +public class DefaultKvsRetryStrategyCallbacks implements KvsRetryStrategyCallbacks { + + @Override + public void createRetryStrategyFn(KvsRetryStrategy kvsRetryStrategy) throws ProducerException { + // no-op + } + + @Override + public void getCurrentRetryAttemptNumberFn(KvsRetryStrategy kvsRetryStrategy, int retryCount) throws ProducerException { + // no-op + } + + @Override + public void freeRetryStrategyFn(KvsRetryStrategy kvsRetryStrategy) throws ProducerException { + // no-op + } + + @Override + public void executeRetryStrategyFn(KvsRetryStrategy kvsRetryStrategy, long retryWaitTime) throws ProducerException { + // no-op + } + +} diff --git a/src/main/java/com/amazonaws/kinesisvideo/producer/KvsRetryStrategy.java b/src/main/java/com/amazonaws/kinesisvideo/producer/KvsRetryStrategy.java new file mode 100644 index 000000000..2de840218 --- /dev/null +++ b/src/main/java/com/amazonaws/kinesisvideo/producer/KvsRetryStrategy.java @@ -0,0 +1,49 @@ +package com.amazonaws.kinesisvideo.producer; + +/** + * Java model for native code in PIC. + *

+ * A generic retry strategy + * + * @see PIC + */ +public class KvsRetryStrategy { + + // Pointer to metadata/state/details for the retry strategy. + // The actual data type is abstracted and will be inferred by + // the RetryHandlerFn + private final long mRetryStrategy; + + // Optional configuration used to build the retry strategy. Once the retry strategy is created, + // any changes to the config will be useless. + private final long mRetryStrategyConfig; + + // Retry strategy type + private final KvsRetryStrategyType mKvsRetryStrategyType; + + public KvsRetryStrategy() { + mRetryStrategy = 0; + mRetryStrategyConfig = 0; + mKvsRetryStrategyType = KvsRetryStrategyType.EXPONENTIAL_BACKOFF_WAIT; + } + + /** + * NOTE: The below getters are not supported for setting/getting in Java. These will return + * null to be initialized to default/null values in the JNI and C layers. + *

+ * Check {@code setupDefaultKvsRetryStrategyParameters} in PIC for the default initialization. + * + * @see PIC + */ + public long getRetryStrategy() { + return 0; + } + + public long getRetryStrategyConfig() { + return 0; + } + + public int getRetryStrategyType() { + return mKvsRetryStrategyType.getKvsRetryStrategyType(); + } +} diff --git a/src/main/java/com/amazonaws/kinesisvideo/producer/KvsRetryStrategyCallbacks.java b/src/main/java/com/amazonaws/kinesisvideo/producer/KvsRetryStrategyCallbacks.java new file mode 100644 index 000000000..b3714070a --- /dev/null +++ b/src/main/java/com/amazonaws/kinesisvideo/producer/KvsRetryStrategyCallbacks.java @@ -0,0 +1,24 @@ +package com.amazonaws.kinesisvideo.producer; + +/** + * This interface holds the retry strategy callback functions. + *

+ * NOTE: This should follow the structure defined in PIC's /kvspic-src/src/utils/include/com/amazonaws/kinesis/video/utils/Include.h + * + * @see PIC + */ +public interface KvsRetryStrategyCallbacks { + + // Create new retry strategy + void createRetryStrategyFn(KvsRetryStrategy kvsRetryStrategy) throws ProducerException; + + // Get retry count + void getCurrentRetryAttemptNumberFn(KvsRetryStrategy kvsRetryStrategy, int retryCount) throws ProducerException; + + // Release allocated resources associated with the retry strategy + void freeRetryStrategyFn(KvsRetryStrategy kvsRetryStrategy) throws ProducerException; + + // Actual handler for the given retry strategy + void executeRetryStrategyFn(KvsRetryStrategy kvsRetryStrategy, long retryWaitTime) throws ProducerException; + +} diff --git a/src/main/java/com/amazonaws/kinesisvideo/producer/KvsRetryStrategyType.java b/src/main/java/com/amazonaws/kinesisvideo/producer/KvsRetryStrategyType.java new file mode 100644 index 000000000..ef9c72fbc --- /dev/null +++ b/src/main/java/com/amazonaws/kinesisvideo/producer/KvsRetryStrategyType.java @@ -0,0 +1,23 @@ +package com.amazonaws.kinesisvideo.producer; + +/** + * Java model for native code in PIC. + *

+ * Retry configuration type for {@link KvsRetryStrategy} in {@link KvsRetryStrategyCallbacks}. + * + * @see PIC + */ +public enum KvsRetryStrategyType { + DISABLED(0), + EXPONENTIAL_BACKOFF_WAIT(1); + + private final int kvsRetryStrategyTypeValue; + + KvsRetryStrategyType(final int kvsRetryStrategyTypeValue) { + this.kvsRetryStrategyTypeValue = kvsRetryStrategyTypeValue; + } + + public int getKvsRetryStrategyType() { + return kvsRetryStrategyTypeValue; + } +}