Skip to content

Commit 0519505

Browse files
YPandasstefankieszYuqi Huang
authored
Add PutEventMetadata support to Java and JNI (#283)
* Add PutEventMetadata support to Java and JNI (#193) * Adding in Java end * Make StreamEventMetadata nullable, start tests. * Test works * Fix native putEventMetadata to not pass null metadata * Test using illegal "AWS" metadata case * Fix a StreamEventMetadata to be Nullable * Cleanup, add StreamEventType enum * Add back a Nonnull * Fixup some comments * Add non-optional mNumberOfPairs comment * Cleanup DemoSample eventMetadata putting * Fix a Nonnull->Nullable, initialize eventMetadata cleanly * Address more comments * Make NumberOfPairs member an int datatype * Add PutEventMetadata support to Java and JNI (#193) * Adding in Java end * Make StreamEventMetadata nullable, start tests. * Test works * Fix native putEventMetadata to not pass null metadata * Test using illegal "AWS" metadata case * Fix a StreamEventMetadata to be Nullable * Cleanup, add StreamEventType enum * Add back a Nonnull * Fixup some comments * Add non-optional mNumberOfPairs comment * Cleanup DemoSample eventMetadata putting * Fix a Nonnull->Nullable, initialize eventMetadata cleanly * Address more comments * Make NumberOfPairs member an int datatype * feat: Add putEventMetadata support to JNI layer - Add putKinesisVideoEventMetadata method to KinesisVideoClientWrapper - Implement setStreamEventMetadata parameter conversion in Parameters.cpp - Add JNI native method declaration in NativeProducerInterface.cpp * feat: Add wrapper for StreamEventMetadata and unit tests for putKinesisVideoEventMetadata - Add safer HashMap constructor wrapper for StreamEventMetadata with validation - Add comprehensive test suite covering edge cases and validation scenarios - Update ImageFrameSource to use new event metadata callback method --------- Co-authored-by: Stefan Kieszkowski <[email protected]> Co-authored-by: Yuqi Huang <[email protected]>
1 parent c709dd0 commit 0519505

23 files changed

+986
-31
lines changed

.github/workflows/code-coverage.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
-Daws.secretKey=${AWS_SECRET_ACCESS_KEY} \
5555
-Daws.sessionToken=${AWS_SESSION_TOKEN} \
5656
-Djava.library.path=${JAVA_LIBRARY_PATH} \
57-
-Dlog4j.configurationFile=log4j2.xml"
57+
-Dlog4j.configurationFile=.github/log4j2.xml"
5858
shell: bash
5959

6060
- name: Upload coverage reports to Codecov

jni/com/amazonaws/kinesis/video/producer/jni/KinesisVideoClientWrapper.cpp

Lines changed: 81 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -503,11 +503,90 @@ void KinesisVideoClientWrapper::putKinesisVideoFragmentMetadata(jlong streamHand
503503

504504
if (STATUS_FAILED(retStatus))
505505
{
506-
DLOGE("Failed to put a metadata with status code 0x%08x", retStatus);
507-
throwNativeException(env, EXCEPTION_NAME, "Failed to put a metadata into the stream.", retStatus);
506+
DLOGE("Failed to put a fragment metadata with status code 0x%08x", retStatus);
507+
throwNativeException(env, EXCEPTION_NAME, "Failed to put a fragment metadata into the stream.", retStatus);
508508
return;
509509
}
510+
}
510511

512+
void KinesisVideoClientWrapper::putKinesisVideoEventMetadata(jlong streamHandle, jint event, jobject kinesisStreamEventMetadata)
513+
{
514+
STATUS retStatus = STATUS_SUCCESS;
515+
JNIEnv *env;
516+
this->getJVM()->GetEnv((PVOID*) &env, JNI_VERSION_1_6);
517+
518+
if (!IS_VALID_CLIENT_HANDLE(mClientHandle))
519+
{
520+
DLOGE("Invalid client object");
521+
throwNativeException(env, EXCEPTION_NAME, "Invalid call after the client is freed.", STATUS_INVALID_OPERATION);
522+
return;
523+
}
524+
525+
if (!IS_VALID_STREAM_HANDLE(streamHandle))
526+
{
527+
DLOGE("Invalid stream handle 0x%016" PRIx64, (UINT64) streamHandle);
528+
throwNativeException(env, EXCEPTION_NAME, "Invalid stream handle.", STATUS_INVALID_OPERATION);
529+
return;
530+
}
531+
532+
// Check for a negative STREAM_EVENT_TYPE coming from Java.
533+
if (event < STREAM_EVENT_TYPE_NONE) {
534+
DLOGE("STREAM_EVENT_TYPE cannot be negative.");
535+
throwNativeException(env, EXCEPTION_NAME, "STREAM_EVENT_TYPE cannot be negative.", STATUS_INVALID_OPERATION);
536+
return;
537+
}
538+
539+
StreamEventMetadata streamEventMetadata;
540+
PStreamEventMetadata pStreamEventMetadata = NULL;
541+
542+
if (kinesisStreamEventMetadata != NULL) {
543+
MEMSET(&streamEventMetadata, 0, SIZEOF(streamEventMetadata)); // Null-init the struct.
544+
545+
if (!setStreamEventMetadata(env, kinesisStreamEventMetadata, &streamEventMetadata))
546+
{
547+
DLOGE("Failed converting streamEventMetadata object.");
548+
throwNativeException(env, EXCEPTION_NAME, "Failed converting streamEventMetadata object.", STATUS_INVALID_OPERATION);
549+
return;
550+
}
551+
552+
pStreamEventMetadata = &streamEventMetadata;
553+
}
554+
555+
556+
// Call the API
557+
retStatus = ::putKinesisVideoEventMetadata(streamHandle, event, pStreamEventMetadata);
558+
if (STATUS_SUCCEEDED(retStatus)) {
559+
int metadataLength = (pStreamEventMetadata != NULL) ? pStreamEventMetadata->numberOfPairs : 0;
560+
DLOGD("Successfully added event metadata 0x%016" PRIx64 " with %d pairs", (UINT64) streamHandle, metadataLength);
561+
}
562+
563+
564+
CleanUp:
565+
566+
// Deallocate the memory allocated for the StreamEventMetadata members.
567+
568+
if (pStreamEventMetadata != NULL) {
569+
if (pStreamEventMetadata->imagePrefix != NULL) {
570+
MEMFREE(pStreamEventMetadata->imagePrefix);
571+
}
572+
573+
for (jsize i = 0; i < MAX_EVENT_CUSTOM_PAIRS; i++) {
574+
if (pStreamEventMetadata->names[i] != NULL) {
575+
MEMFREE(pStreamEventMetadata->names[i]);
576+
}
577+
if (pStreamEventMetadata->values[i] != NULL) {
578+
MEMFREE(pStreamEventMetadata->values[i]);
579+
}
580+
}
581+
}
582+
583+
584+
if (STATUS_FAILED(retStatus))
585+
{
586+
DLOGE("Failed to put an event metadata with status code 0x%08x", retStatus);
587+
throwNativeException(env, EXCEPTION_NAME, "Failed to put an event metadata into the stream.", retStatus);
588+
return;
589+
}
511590
}
512591

513592
void KinesisVideoClientWrapper::getKinesisVideoStreamData(jlong streamHandle, jlong uploadHandle, jobject dataBuffer, jint offset, jint length, jobject readResult)

jni/com/amazonaws/kinesis/video/producer/jni/NativeProducerInterface.cpp

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ extern "C" {
232232
{
233233
ENTERS();
234234

235-
DLOGS("Putting Kinesis Video metadata for stream 0x%016" PRIx64 ".", streamHandle);
235+
DLOGS("Putting Kinesis Video fragment metadata for stream 0x%016" PRIx64 ".", streamHandle);
236236
CHECK(env != NULL && thiz != NULL);
237237

238238
KinesisVideoClientWrapper* pWrapper = FROM_WRAPPER_HANDLE(handle);
@@ -244,6 +244,26 @@ extern "C" {
244244
LEAVES();
245245
}
246246

247+
/**
248+
* Puts an event metadata in to the frame buffer
249+
*/
250+
PUBLIC_API void JNICALL Java_com_amazonaws_kinesisvideo_internal_producer_jni_NativeKinesisVideoProducerJni_putKinesisVideoEventMetadata(JNIEnv* env, jobject thiz, jlong handle, jlong streamHandle, jint event, jobject streamEventMetadata)
251+
{
252+
ENTERS();
253+
254+
DLOGS("Putting Kinesis Video event metadata for stream 0x%016" PRIx64 ".", streamHandle);
255+
CHECK(env != NULL && thiz != NULL);
256+
257+
KinesisVideoClientWrapper* pWrapper = FROM_WRAPPER_HANDLE(handle);
258+
if (pWrapper != NULL) {
259+
SyncMutex::Autolock l(pWrapper->getSyncLock(), __FUNCTION__);
260+
pWrapper->putKinesisVideoEventMetadata(streamHandle, event, streamEventMetadata);
261+
}
262+
263+
LEAVES();
264+
}
265+
266+
247267
PUBLIC_API void JNICALL Java_com_amazonaws_kinesisvideo_internal_producer_jni_NativeKinesisVideoProducerJni_kinesisVideoStreamFragmentAck(JNIEnv* env, jobject thiz, jlong handle, jlong streamHandle, jlong uploadHandle, jobject fragmentAck)
248268
{
249269
ENTERS();

jni/com/amazonaws/kinesis/video/producer/jni/Parameters.cpp

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1354,3 +1354,146 @@ BOOL releaseStreamDataBuffer(JNIEnv* env, jobject dataBuffer, UINT32 offset, PBY
13541354

13551355
return TRUE;
13561356
}
1357+
1358+
BOOL setStreamEventMetadata(JNIEnv* env, jobject streamEventMetadata, PStreamEventMetadata pStreamEventMetadata)
1359+
{
1360+
STATUS retStatus = STATUS_SUCCESS;
1361+
jmethodID methodId = NULL;
1362+
CHECK(env != NULL && streamEventMetadata != NULL && pStreamEventMetadata != NULL);
1363+
const char *retChars;
1364+
1365+
// Load KinesisVideoFrame
1366+
jclass cls = env->GetObjectClass(streamEventMetadata);
1367+
if (cls == NULL) {
1368+
DLOGE("Failed to create StreamEventMetadata class.");
1369+
CHK(FALSE, STATUS_INVALID_OPERATION);
1370+
}
1371+
1372+
// Retrieve the methods and call them
1373+
1374+
methodId = env->GetMethodID(cls, "getVersion", "()I");
1375+
if (methodId == NULL) {
1376+
DLOGW("Couldn't find method id getVersion");
1377+
} else {
1378+
pStreamEventMetadata->version = env->CallIntMethod(streamEventMetadata, methodId);
1379+
CHK_JVM_EXCEPTION(env);
1380+
}
1381+
1382+
methodId = env->GetMethodID(cls, "getImagePrefix", "()Ljava/lang/String;");
1383+
if (methodId == NULL) {
1384+
DLOGW("Couldn't find method id getImagePrefix");
1385+
} else {
1386+
jstring retString = (jstring) env->CallObjectMethod(streamEventMetadata, methodId);
1387+
CHK_JVM_EXCEPTION(env);
1388+
1389+
if (retString != NULL) {
1390+
jsize javaStringLength = env->GetStringUTFLength(retString);
1391+
pStreamEventMetadata->imagePrefix = (PCHAR)MEMCALLOC(javaStringLength + 1, SIZEOF(CHAR));
1392+
retChars = env->GetStringUTFChars(retString, NULL);
1393+
STRNCPY(pStreamEventMetadata->imagePrefix, retChars, javaStringLength);
1394+
env->ReleaseStringUTFChars(retString, retChars);
1395+
}
1396+
}
1397+
1398+
methodId = env->GetMethodID(cls, "getNumberOfPairs", "()I");
1399+
if (methodId == NULL) {
1400+
DLOGW("Couldn't find method id getNumberOfPairs");
1401+
} else {
1402+
pStreamEventMetadata->numberOfPairs = env->CallByteMethod(streamEventMetadata, methodId);
1403+
CHK_JVM_EXCEPTION(env);
1404+
}
1405+
1406+
methodId = env->GetMethodID(cls, "getNames", "()[Ljava/lang/String;");
1407+
if (methodId == NULL) {
1408+
DLOGW("Couldn't find method id getNames");
1409+
} else {
1410+
// Check if names array is null before processing
1411+
jobjectArray namesArray = (jobjectArray) env->CallObjectMethod(streamEventMetadata, methodId);
1412+
CHK_JVM_EXCEPTION(env);
1413+
if (namesArray != NULL) {
1414+
if(!allocStreamEventMetadataArray(env, streamEventMetadata, pStreamEventMetadata->names, methodId)) {
1415+
DLOGW("Failed in allocStreamEventMetadataArray step for metadata names.");
1416+
}
1417+
} else {
1418+
DLOGW("Names array is null, skipping allocation");
1419+
}
1420+
}
1421+
1422+
methodId = env->GetMethodID(cls, "getValues", "()[Ljava/lang/String;");
1423+
if (methodId == NULL) {
1424+
DLOGW("Couldn't find method id getValues");
1425+
} else {
1426+
// Check if values array is null before processing
1427+
jobjectArray valuesArray = (jobjectArray) env->CallObjectMethod(streamEventMetadata, methodId);
1428+
CHK_JVM_EXCEPTION(env);
1429+
if (valuesArray != NULL) {
1430+
if(!allocStreamEventMetadataArray(env, streamEventMetadata, pStreamEventMetadata->values, methodId)) {
1431+
DLOGW("Failed in allocStreamEventMetadataArray step for metadata values.");
1432+
}
1433+
} else {
1434+
DLOGW("Values array is null, skipping allocation");
1435+
}
1436+
}
1437+
1438+
CleanUp:
1439+
return STATUS_FAILED(retStatus) ? FALSE : TRUE;
1440+
}
1441+
1442+
BOOL allocStreamEventMetadataArray(JNIEnv* env, jobject streamEventMetadata, PCHAR* metaDataArray, jmethodID methodId) {
1443+
STATUS retStatus = STATUS_SUCCESS;
1444+
jobjectArray retArray = NULL;
1445+
jsize arrayLength = 0;
1446+
jstring stringElement;
1447+
const char *retChars;
1448+
1449+
CHK(methodId != NULL, STATUS_NULL_ARG);
1450+
retArray = (jobjectArray) env->CallObjectMethod(streamEventMetadata, methodId);
1451+
CHK_JVM_EXCEPTION(env);
1452+
CHK(retArray != NULL, STATUS_NULL_ARG);
1453+
1454+
arrayLength = env->GetArrayLength(retArray);
1455+
1456+
// Verify array returned from Java is not too long.
1457+
// NOTE: This check will already be done in PIC, but can do it here to safely alloc/delloc memory here in JNI.
1458+
CHK(arrayLength <= MAX_EVENT_CUSTOM_PAIRS, STATUS_MAX_FRAGMENT_METADATA_COUNT);
1459+
1460+
// Null all elements for safety.
1461+
MEMSET(metaDataArray, NULL, sizeof(PCHAR) * MAX_EVENT_CUSTOM_PAIRS);
1462+
1463+
// Iterate through the char pointers, allocating memory for the Java string that will be copied to the char pointers.
1464+
for (jsize i = 0; i < arrayLength; i++) {
1465+
stringElement = (jstring) env->GetObjectArrayElement(retArray, i);
1466+
// Add null check for string element
1467+
CHK(stringElement != NULL, STATUS_NULL_ARG);
1468+
jsize javaStringLength = env->GetStringUTFLength(stringElement);
1469+
CHK(javaStringLength >= 0, STATUS_INVALID_ARG); // (jsize is signed, but will be used as an unsigned SIZE_T)
1470+
retChars = env->GetStringUTFChars(stringElement, NULL);
1471+
1472+
// Verify GetStringUTFChars success.
1473+
CHK(retChars != NULL, STATUS_NULL_ARG);
1474+
1475+
metaDataArray[i] = (PCHAR)MEMALLOC(javaStringLength + 1); // No need for calloc as we are filling it completely with the strncpy, minus the last char which is then set to null terminator
1476+
STRNCPY(metaDataArray[i], retChars, javaStringLength);
1477+
1478+
// Set last char to be a null terminator.
1479+
metaDataArray[i][(SIZE_T)javaStringLength] = '\0';
1480+
1481+
env->ReleaseStringUTFChars(stringElement, retChars);
1482+
retChars = NULL;
1483+
env->DeleteLocalRef(stringElement);
1484+
stringElement = NULL;
1485+
}
1486+
1487+
1488+
CleanUp:
1489+
1490+
if (retChars != NULL) {
1491+
env->ReleaseStringUTFChars(stringElement, retChars);
1492+
}
1493+
1494+
if (stringElement != NULL) {
1495+
env->DeleteLocalRef(stringElement);
1496+
}
1497+
1498+
return STATUS_FAILED(retStatus) ? FALSE : TRUE;
1499+
}

jni/include/com/amazonaws/kinesis/video/producer/jni/KinesisVideoClientWrapper.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,7 @@ class KinesisVideoClientWrapper
187187
void getKinesisVideoStreamMetrics(jlong streamHandle, jobject kinesisVideoStreamMetrics);
188188
void stopKinesisVideoStream(jlong streamHandle);
189189
void freeKinesisVideoStream(jlong streamHandle);
190+
void putKinesisVideoEventMetadata(jlong streamHandle, jint event, jobject pStreamEventMetadata);
190191
void putKinesisVideoFrame(jlong streamHandle, jobject kinesisVideoFrame);
191192
void putKinesisVideoFragmentMetadata(jlong streamHandle, jstring metadataName, jstring metadataValue, jboolean persistent);
192193
void describeStreamResult(jlong streamHandle, jint httpStatusCode, jobject streamDescription);

jni/include/com/amazonaws/kinesis/video/producer/jni/Parameters.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ BOOL setStreamingEndpoint(JNIEnv* env, jstring streamingEndpoint, PCHAR pEndpoin
1616
BOOL setStreamDataBuffer(JNIEnv* env, jobject dataBuffer, UINT32 offset, PBYTE* ppBuffer);
1717
BOOL releaseStreamDataBuffer(JNIEnv* env, jobject dataBuffer, UINT32 offset, PBYTE pBuffer);
1818
BOOL setTags(JNIEnv *env, jobjectArray tagArray, PTag* ppTags, PUINT32 pTagCount);
19+
BOOL setStreamEventMetadata(JNIEnv* env, jobject streamEventMetadata, PStreamEventMetadata pStreamEventMetadata);
20+
BOOL allocStreamEventMetadataArray(JNIEnv* env, jobject streamEventMetadata, PCHAR* metaDataArray, jmethodID methodId);
1921
VOID releaseTags(PTag tags);
2022
BOOL setKvsRetryStrategy(JNIEnv *env, jobject kvsRetryStrategyCallbacks, PKvsRetryStrategy pKvsRetryStrategy, PKvsRetryStrategyCallbacks pCallbacks);
2123

jni/include/com/amazonaws/kinesis/video/producer/jni/com_amazonaws_kinesisvideo_internal_producer_jni_NativeKinesisVideoProducerJni.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ JNIEXPORT void JNICALL Java_com_amazonaws_kinesisvideo_internal_producer_jni_Nat
104104
* Signature: (JJLjava/lang/String;Ljava/lang/String;Z)V
105105
*/
106106
JNIEXPORT void JNICALL Java_com_amazonaws_kinesisvideo_internal_producer_jni_NativeKinesisVideoProducerJni_putKinesisVideoFragmentMetadata
107-
(JNIEnv*, jobject, jlong, jlong, jstring, jstring, jboolean);
107+
(JNIEnv *, jobject, jlong, jlong, jstring, jstring, jboolean);
108108

109109
/*
110110
* Class: com_amazonaws_kinesisvideo_internal_producer_jni_NativeKinesisVideoProducerJni
@@ -226,6 +226,13 @@ JNIEXPORT void JNICALL Java_com_amazonaws_kinesisvideo_internal_producer_jni_Nat
226226
JNIEXPORT jlong JNICALL Java_com_amazonaws_kinesisvideo_internal_producer_jni_NativeKinesisVideoProducerJni_getCurrentAllocationBytes
227227
(JNIEnv *, jobject);
228228

229+
/*
230+
* Class: com_amazonaws_kinesisvideo_internal_producer_jni_NativeKinesisVideoProducerJni
231+
* Method: putKinesisVideoEventMetadata
232+
* Signature: (JILcom/amazonaws/kinesisvideo/internal/producer/StreamEventMetadata)V
233+
*/
234+
JNIEXPORT void JNICALL Java_com_amazonaws_kinesisvideo_internal_producer_jni_NativeKinesisVideoProducerJni_putKinesisVideoEventMetadata
235+
(JNIEnv *, jobject, jlong, jlong, jint, jobject);
229236
#ifdef __cplusplus
230237
}
231238
#endif

src/main/java/com/amazonaws/kinesisvideo/internal/client/mediasource/MediaSourceSink.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import com.amazonaws.kinesisvideo.common.exception.KinesisVideoException;
44
import com.amazonaws.kinesisvideo.internal.producer.KinesisVideoProducerStream;
55
import com.amazonaws.kinesisvideo.producer.KinesisVideoFrame;
6+
import com.amazonaws.kinesisvideo.internal.producer.StreamEventMetadata;
67

78
import javax.annotation.Nonnull;
89
import javax.annotation.Nullable;
@@ -144,6 +145,9 @@ public interface MediaSourceSink {
144145
*/
145146
void onFragmentMetadata(final @Nonnull String metadataName, final @Nonnull String metadataValue, final boolean persistent)
146147
throws KinesisVideoException;
148+
149+
void onEventMetadata(final int event, @Nullable final StreamEventMetadata streamEventMetadata)
150+
throws KinesisVideoException;
147151

148152
/**
149153
* Returns the underlying Kinesis Video Producer stream that receives the media data.

src/main/java/com/amazonaws/kinesisvideo/internal/mediasource/DefaultOnStreamDataAvailable.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
11
package com.amazonaws.kinesisvideo.internal.mediasource;
22

3+
import javax.annotation.Nullable;
4+
35
import com.amazonaws.kinesisvideo.common.exception.KinesisVideoException;
46
import com.amazonaws.kinesisvideo.common.preconditions.Preconditions;
57
import com.amazonaws.kinesisvideo.internal.client.mediasource.MediaSourceSink;
8+
import com.amazonaws.kinesisvideo.internal.producer.StreamEventMetadata;
69
import com.amazonaws.kinesisvideo.producer.KinesisVideoFrame;
710

811
import javax.annotation.Nonnull;
@@ -40,4 +43,10 @@ public void onFragmentMetadataAvailable(@Nonnull final String metadataName, @Non
4043
Preconditions.checkArgument(metadataValue != null, "Metadata value cannot be null");
4144
this.mediaSourceSink.onFragmentMetadata(metadataName, metadataValue, persistent);
4245
}
46+
47+
@Override
48+
public void onEventMetadataAvailable(final int event, @Nullable final StreamEventMetadata streamEventMetadata)
49+
throws KinesisVideoException {
50+
mediaSourceSink.onEventMetadata(event, streamEventMetadata);
51+
}
4352
}

src/main/java/com/amazonaws/kinesisvideo/internal/mediasource/OnStreamDataAvailable.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.amazonaws.kinesisvideo.internal.mediasource;
22

33
import com.amazonaws.kinesisvideo.common.exception.KinesisVideoException;
4+
import com.amazonaws.kinesisvideo.internal.producer.StreamEventMetadata;
45
import com.amazonaws.kinesisvideo.producer.KinesisVideoFrame;
56

67
import javax.annotation.Nonnull;
@@ -28,4 +29,7 @@ default void onFragmentMetadataAvailable(@Nonnull final String metadataName, @No
2829
final boolean persistent) throws KinesisVideoException {
2930
// no-op
3031
}
32+
default void onEventMetadataAvailable(final int event, final StreamEventMetadata streamEventMetadata) throws KinesisVideoException {
33+
// no-op
34+
}
3135
}

0 commit comments

Comments
 (0)