diff --git a/android/src/main/java/com/brentvatne/common/API/TimedMetadata.kt b/android/src/main/java/com/brentvatne/common/API/TimedMetadata.kt new file mode 100644 index 00000000..81feb0fd --- /dev/null +++ b/android/src/main/java/com/brentvatne/common/API/TimedMetadata.kt @@ -0,0 +1,8 @@ +package com.brentvatne.common.API + +class TimedMetadata { + @kotlin.jvm.JvmField + var m_Identifier: String? = null + @kotlin.jvm.JvmField + var m_Value: String? = null +} \ No newline at end of file diff --git a/android/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java b/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.java similarity index 86% rename from android/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java rename to android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.java index 24d8eafb..fdbe1fe8 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java +++ b/android/src/main/java/com/brentvatne/common/react/VideoEventEmitter.java @@ -1,8 +1,9 @@ -package com.brentvatne.exoplayer; +package com.brentvatne.common.react; import androidx.annotation.StringDef; import android.view.View; +import com.brentvatne.common.API.TimedMetadata; import com.brentvatne.common.Track; import com.brentvatne.common.VideoTrack; import com.facebook.react.bridge.Arguments; @@ -10,10 +11,6 @@ import com.facebook.react.bridge.ReactContext; import com.facebook.react.bridge.WritableArray; import com.facebook.react.bridge.WritableMap; import com.facebook.react.uimanager.events.RCTEventEmitter; -import com.google.android.exoplayer2.metadata.Metadata; -import com.google.android.exoplayer2.metadata.emsg.EventMessage; -import com.google.android.exoplayer2.metadata.id3.Id3Frame; -import com.google.android.exoplayer2.metadata.id3.TextInformationFrame; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -21,13 +18,13 @@ import java.io.StringWriter; import java.io.PrintWriter; import java.util.ArrayList; -class VideoEventEmitter { +public class VideoEventEmitter { private final RCTEventEmitter eventEmitter; private int viewId = View.NO_ID; - VideoEventEmitter(ReactContext reactContext) { + public VideoEventEmitter(ReactContext reactContext) { this.eventEmitter = reactContext.getJSModule(RCTEventEmitter.class); } @@ -58,7 +55,7 @@ class VideoEventEmitter { private static final String EVENT_VIDEO_TRACKS = "onVideoTracks"; private static final String EVENT_ON_RECEIVE_AD_EVENT = "onReceiveAdEvent"; - static final String[] Events = { + public static final String[] Events = { EVENT_LOAD_START, EVENT_LOAD, EVENT_ERROR, @@ -156,11 +153,11 @@ class VideoEventEmitter { private static final String EVENT_PROP_IS_PLAYING = "isPlaying"; - void setViewId(int viewId) { + public void setViewId(int viewId) { this.viewId = viewId; } - void loadStart() { + public void loadStart() { receiveEvent(EVENT_LOAD_START, null); } @@ -241,7 +238,7 @@ class VideoEventEmitter { } - private void load(double duration, double currentPosition, int videoWidth, int videoHeight, + public void load(double duration, double currentPosition, int videoWidth, int videoHeight, WritableArray audioTracks, WritableArray textTracks, WritableArray videoTracks, String trackId) { WritableMap event = Arguments.createMap(); event.putDouble(EVENT_PROP_DURATION, duration / 1000D); @@ -286,7 +283,7 @@ class VideoEventEmitter { receiveEvent(EVENT_VIDEO_TRACKS, arrayToObject(EVENT_PROP_VIDEO_TRACKS, videoTracksToArray(videoTracks))); } - void progressChanged(double currentPosition, double bufferedDuration, double seekableDuration, double currentPlaybackTime) { + public void progressChanged(double currentPosition, double bufferedDuration, double seekableDuration, double currentPlaybackTime) { WritableMap event = Arguments.createMap(); event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D); event.putDouble(EVENT_PROP_PLAYABLE_DURATION, bufferedDuration / 1000D); @@ -295,67 +292,67 @@ class VideoEventEmitter { receiveEvent(EVENT_PROGRESS, event); } - void bandwidthReport(double bitRateEstimate, int height, int width, String id) { + public void bandwidthReport(double bitRateEstimate, int height, int width, String id) { WritableMap event = Arguments.createMap(); event.putDouble(EVENT_PROP_BITRATE, bitRateEstimate); event.putInt(EVENT_PROP_WIDTH, width); event.putInt(EVENT_PROP_HEIGHT, height); event.putString(EVENT_PROP_TRACK_ID, id); receiveEvent(EVENT_BANDWIDTH, event); - } + } - void seek(long currentPosition, long seekTime) { + public void seek(long currentPosition, long seekTime) { WritableMap event = Arguments.createMap(); event.putDouble(EVENT_PROP_CURRENT_TIME, currentPosition / 1000D); event.putDouble(EVENT_PROP_SEEK_TIME, seekTime / 1000D); receiveEvent(EVENT_SEEK, event); } - void ready() { + public void ready() { receiveEvent(EVENT_READY, null); } - void buffering(boolean isBuffering) { + public void buffering(boolean isBuffering) { WritableMap map = Arguments.createMap(); map.putBoolean(EVENT_PROP_IS_BUFFERING, isBuffering); receiveEvent(EVENT_BUFFER, map); } - void playbackStateChanged(boolean isPlaying) { + public void playbackStateChanged(boolean isPlaying) { WritableMap map = Arguments.createMap(); map.putBoolean(EVENT_PROP_IS_PLAYING, isPlaying); receiveEvent(EVENT_PLAYBACK_STATE_CHANGED, map); } - void idle() { + public void idle() { receiveEvent(EVENT_IDLE, null); } - void end() { + public void end() { receiveEvent(EVENT_END, null); } - void fullscreenWillPresent() { + public void fullscreenWillPresent() { receiveEvent(EVENT_FULLSCREEN_WILL_PRESENT, null); } - void fullscreenDidPresent() { + public void fullscreenDidPresent() { receiveEvent(EVENT_FULLSCREEN_DID_PRESENT, null); } - void fullscreenWillDismiss() { + public void fullscreenWillDismiss() { receiveEvent(EVENT_FULLSCREEN_WILL_DISMISS, null); } - void fullscreenDidDismiss() { + public void fullscreenDidDismiss() { receiveEvent(EVENT_FULLSCREEN_DID_DISMISS, null); } - void error(String errorString, Exception exception) { + public void error(String errorString, Exception exception) { _error(errorString, exception, "0001"); } - void error(String errorString, Exception exception, String errorCode) { + public void error(String errorString, Exception exception, String errorCode) { _error(errorString, exception, errorCode); } @@ -376,48 +373,24 @@ class VideoEventEmitter { receiveEvent(EVENT_ERROR, event); } - void playbackRateChange(float rate) { + public void playbackRateChange(float rate) { WritableMap map = Arguments.createMap(); map.putDouble(EVENT_PROP_PLAYBACK_RATE, (double)rate); receiveEvent(EVENT_PLAYBACK_RATE_CHANGE, map); } - void timedMetadata(Metadata metadata) { + + public void timedMetadata(ArrayList _metadataArrayList) { + if (_metadataArrayList.size() == 0) { + return; + } WritableArray metadataArray = Arguments.createArray(); - for (int i = 0; i < metadata.length(); i++) { - - Metadata.Entry entry = metadata.get(i); - - if (entry instanceof Id3Frame) { - - Id3Frame frame = (Id3Frame) entry; - - String value = ""; - - if (frame instanceof TextInformationFrame) { - TextInformationFrame txxxFrame = (TextInformationFrame) frame; - value = txxxFrame.value; - } - - String identifier = frame.id; - - WritableMap map = Arguments.createMap(); - map.putString("identifier", identifier); - map.putString("value", value); - - metadataArray.pushMap(map); - - } else if (entry instanceof EventMessage) { - - EventMessage eventMessage = (EventMessage) entry; - - WritableMap map = Arguments.createMap(); - map.putString("identifier", eventMessage.schemeIdUri); - map.putString("value", eventMessage.value); - metadataArray.pushMap(map); - - } + for (int i = 0; i < _metadataArrayList.size(); i++) { + WritableMap map = Arguments.createMap(); + map.putString("identifier", _metadataArrayList.get(i).m_Identifier); + map.putString("value", _metadataArrayList.get(i).m_Value); + metadataArray.pushMap(map); } WritableMap event = Arguments.createMap(); @@ -425,17 +398,17 @@ class VideoEventEmitter { receiveEvent(EVENT_TIMED_METADATA, event); } - void audioFocusChanged(boolean hasFocus) { + public void audioFocusChanged(boolean hasFocus) { WritableMap map = Arguments.createMap(); map.putBoolean(EVENT_PROP_HAS_AUDIO_FOCUS, hasFocus); receiveEvent(EVENT_AUDIO_FOCUS_CHANGE, map); } - void audioBecomingNoisy() { + public void audioBecomingNoisy() { receiveEvent(EVENT_AUDIO_BECOMING_NOISY, null); } - void receiveAdEvent(String event) { + public void receiveAdEvent(String event) { WritableMap map = Arguments.createMap(); map.putString("event", event); diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java index 9a55dc4a..71ea7760 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java @@ -26,8 +26,10 @@ import androidx.annotation.NonNull; import androidx.annotation.WorkerThread; import androidx.activity.OnBackPressedCallback; +import com.brentvatne.common.API.TimedMetadata; import com.brentvatne.common.Track; import com.brentvatne.common.VideoTrack; +import com.brentvatne.common.react.VideoEventEmitter; import com.brentvatne.common.toolbox.DebugLog; import com.brentvatne.exoplayer.AudioOutput; import com.brentvatne.react.R; @@ -93,6 +95,10 @@ import com.google.android.exoplayer2.source.dash.manifest.DashManifest; import com.google.android.exoplayer2.source.dash.manifest.Period; import com.google.android.exoplayer2.source.dash.manifest.AdaptationSet; import com.google.android.exoplayer2.source.dash.manifest.Representation; +import com.google.android.exoplayer2.metadata.Metadata; +import com.google.android.exoplayer2.metadata.emsg.EventMessage; +import com.google.android.exoplayer2.metadata.id3.Id3Frame; +import com.google.android.exoplayer2.metadata.id3.TextInformationFrame; import com.google.android.exoplayer2.ext.ima.ImaAdsLoader; import com.google.android.exoplayer2.source.ads.AdsMediaSource; @@ -1475,7 +1481,38 @@ public class ReactExoplayerView extends FrameLayout implements @Override public void onMetadata(@NonNull Metadata metadata) { - eventEmitter.timedMetadata(metadata); + ArrayList metadataArray = new ArrayList<>(); + for (int i = 0; i < metadata.length(); i++) { + Metadata.Entry entry = metadata.get(i); + + if (entry instanceof Id3Frame) { + Id3Frame frame = (Id3Frame) metadata.get(i); + + String value = ""; + + if (frame instanceof TextInformationFrame) { + TextInformationFrame txxxFrame = (TextInformationFrame) frame; + value = txxxFrame.value; + } + + String identifier = frame.id; + + TimedMetadata timedMetadata = new TimedMetadata(); + timedMetadata.m_Identifier = identifier; + timedMetadata.m_Value = value; + + metadataArray.add(timedMetadata); + } else if (entry instanceof EventMessage) { + EventMessage eventMessage = (EventMessage) entry; + TimedMetadata timedMetadata = new TimedMetadata(); + timedMetadata.m_Identifier = eventMessage.schemeIdUri; + timedMetadata.m_Value = eventMessage.value; + metadataArray.add(timedMetadata); + } else { + DebugLog.d(TAG, "unhandled metadata " + entry.toString()); + } + } + eventEmitter.timedMetadata(metadataArray); } // ReactExoplayerViewManager public api diff --git a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java index 6c9e9888..1eb008d5 100644 --- a/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java +++ b/android/src/main/java/com/brentvatne/exoplayer/ReactExoplayerViewManager.java @@ -6,6 +6,7 @@ import android.net.Uri; import android.text.TextUtils; import android.util.Log; +import com.brentvatne.common.react.VideoEventEmitter; import com.brentvatne.common.toolbox.DebugLog; import com.brentvatne.common.toolbox.ReactBridgeUtils; import com.brentvatne.exoplayer.AudioOutput;