Commit d792427c authored by Andrea Cresta's avatar Andrea Cresta Committed by Matt Apperson
Browse files

Added onTimedMetadata callback for iOS player and Exoplayer (#487)

* added listener for timedMetadata event.

* added callback in RCTVideo for the timed metadata

* exposing onTimedMetadata to JS

* added forgotten method declaration

* returning array of string values

* added metadata type to the array

* added onMetadata method

* overridden onMetadata method on exoplayer2

* added format of return value from onMetadata

* added function reference in README file
parent 07ac819a
Loading
Loading
Loading
Loading
+1 −0
Changes for README.md: 1 added line, 0 removed lines.
Original line number Diff line number Diff line
@@ -151,6 +151,7 @@ using System.Collections.Generic;
       onEnd={this.onEnd}                      // Callback when playback finishes
       onError={this.videoError}               // Callback when video cannot be loaded
       onBuffer={this.onBuffer}                // Callback when remote video is buffering
       onTimedMetadata={this.onTimedMetadata}  // Callback when the stream receive some metadata
       style={styles.backgroundVideo} />

// Later to trigger fullscreen
+8 −0
Changes for Video.js: 8 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -79,6 +79,12 @@ export default class Video extends Component {
    }
  };

  _onTimedMetadata = (event) => {
    if (this.props.onTimedMetadata) {
      this.props.onTimedMetadata(event.nativeEvent);
    }
  };

  _onFullscreenPlayerWillPresent = (event) => {
    if (this.props.onFullscreenPlayerWillPresent) {
      this.props.onFullscreenPlayerWillPresent(event.nativeEvent);
@@ -191,6 +197,7 @@ export default class Video extends Component {
      onVideoSeek: this._onSeek,
      onVideoEnd: this._onEnd,
      onVideoBuffer: this._onBuffer,
      onTimedMetadata: this._onTimedMetadata,
      onVideoFullscreenPlayerWillPresent: this._onFullscreenPlayerWillPresent,
      onVideoFullscreenPlayerDidPresent: this._onFullscreenPlayerDidPresent,
      onVideoFullscreenPlayerWillDismiss: this._onFullscreenPlayerWillDismiss,
@@ -248,6 +255,7 @@ Video.propTypes = {
  onVideoProgress: PropTypes.func,
  onVideoSeek: PropTypes.func,
  onVideoEnd: PropTypes.func,
  onTimedMetadata: PropTypes.func,
  onVideoFullscreenPlayerWillPresent: PropTypes.func,
  onVideoFullscreenPlayerDidPresent: PropTypes.func,
  onVideoFullscreenPlayerWillDismiss: PropTypes.func,
+10 −1
Changes for android-exoplayer/src/main/java/com/brentvatne/exoplayer/ExoPlayerView.java: 10 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -4,6 +4,7 @@ import android.annotation.TargetApi;
import android.content.Context;
import android.support.v4.content.ContextCompat;
import android.util.AttributeSet;
import android.util.Log;
import android.view.Gravity;
import android.view.SurfaceView;
import android.view.TextureView;
@@ -16,6 +17,8 @@ import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.MetadataRenderer;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.text.Cue;
import com.google.android.exoplayer2.text.TextRenderer;
@@ -96,6 +99,7 @@ public final class ExoPlayerView extends FrameLayout {
            this.player.setVideoListener(null);
            this.player.removeListener(componentListener);
            this.player.setVideoSurface(null);
            this.player.setMetadataOutput(componentListener);
        }
        this.player = player;
        shutterView.setVisibility(VISIBLE);
@@ -108,6 +112,7 @@ public final class ExoPlayerView extends FrameLayout {
            player.setVideoListener(componentListener);
            player.addListener(componentListener);
            player.setTextOutput(componentListener);
            player.setMetadataOutput(componentListener);
        }
    }

@@ -161,7 +166,7 @@ public final class ExoPlayerView extends FrameLayout {
    }

    private final class ComponentListener implements SimpleExoPlayer.VideoListener,
            TextRenderer.Output, ExoPlayer.EventListener {
            TextRenderer.Output, ExoPlayer.EventListener, MetadataRenderer.Output {

        // TextRenderer.Output implementation

@@ -220,6 +225,10 @@ public final class ExoPlayerView extends FrameLayout {
            updateForCurrentTrackSelections();
        }

        @Override
        public void onMetadata(Metadata metadata) {
            Log.d("onMetadata", "onMetadata");
        }
    }

}
+13 −1
Changes for android-exoplayer/src/main/java/com/brentvatne/exoplayer/ReactExoplayerView.java: 13 added lines, 1 removed line.
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import com.google.android.exoplayer2.Timeline;
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer;
import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
import com.google.android.exoplayer2.metadata.Metadata;
import com.google.android.exoplayer2.metadata.MetadataRenderer;
import com.google.android.exoplayer2.source.ExtractorMediaSource;
import com.google.android.exoplayer2.source.LoopingMediaSource;
import com.google.android.exoplayer2.source.MediaSource;
@@ -49,11 +51,14 @@ import java.net.CookieManager;
import java.net.CookiePolicy;

@SuppressLint("ViewConstructor")

class ReactExoplayerView extends FrameLayout implements
        LifecycleEventListener,
        ExoPlayer.EventListener,
        BecomingNoisyListener,
        AudioManager.OnAudioFocusChangeListener {
        AudioManager.OnAudioFocusChangeListener,
        MetadataRenderer.Output
    {

    private static final String TAG = "ReactExoplayerView";

@@ -192,6 +197,7 @@ class ReactExoplayerView extends FrameLayout implements
            trackSelector = new DefaultTrackSelector(videoTrackSelectionFactory);
            player = ExoPlayerFactory.newSimpleInstance(getContext(), trackSelector, new DefaultLoadControl());
            player.addListener(this);
            player.setMetadataOutput(this);
            exoPlayerView.setPlayer(player);
            if (isTimelineStatic) {
                if (playerPosition == C.TIME_UNSET) {
@@ -247,6 +253,7 @@ class ReactExoplayerView extends FrameLayout implements
                playerPosition = player.getCurrentPosition();
            }
            player.release();
            player.setMetadataOutput(null);
            player = null;
            trackSelector = null;
        }
@@ -480,6 +487,11 @@ class ReactExoplayerView extends FrameLayout implements
        playerNeedsSource = true;
    }

    @Override
    public void onMetadata(Metadata metadata) {
        eventEmitter.timedMetadata(metadata);
    }

    // ReactExoplayerViewManager public api

    public void setSrc(final Uri uri, final String extension) {
+43 −0
Changes for android-exoplayer/src/main/java/com/brentvatne/exoplayer/VideoEventEmitter.java: 43 added lines, 0 removed lines.
Original line number Diff line number Diff line
@@ -5,11 +5,18 @@ import android.view.View;

import com.facebook.react.bridge.Arguments;
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.id3.BinaryFrame;
import com.google.android.exoplayer2.metadata.id3.Id3Frame;
import com.google.android.exoplayer2.metadata.id3.TxxxFrame;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.HashMap;
import java.util.Map;

class VideoEventEmitter {

@@ -32,6 +39,7 @@ class VideoEventEmitter {
    private static final String EVENT_READY = "onReadyForDisplay";
    private static final String EVENT_BUFFER = "onVideoBuffer";
    private static final String EVENT_IDLE = "onVideoIdle";
    private static final String EVENT_TIMED_METADATA = "onTimedMetadata";
    private static final String EVENT_AUDIO_BECOMING_NOISY = "onAudioBecomingNoisy";
    private static final String EVENT_AUDIO_FOCUS_CHANGE = "onAudioFocusChanged";

@@ -47,6 +55,7 @@ class VideoEventEmitter {
            EVENT_READY,
            EVENT_BUFFER,
            EVENT_IDLE,
            EVENT_TIMED_METADATA,
            EVENT_AUDIO_BECOMING_NOISY,
            EVENT_AUDIO_FOCUS_CHANGE,
    };
@@ -64,6 +73,7 @@ class VideoEventEmitter {
            EVENT_READY,
            EVENT_BUFFER,
            EVENT_IDLE,
            EVENT_TIMED_METADATA,
            EVENT_AUDIO_BECOMING_NOISY,
            EVENT_AUDIO_FOCUS_CHANGE,
    })
@@ -92,6 +102,9 @@ class VideoEventEmitter {
    private static final String EVENT_PROP_ERROR_STRING = "errorString";
    private static final String EVENT_PROP_ERROR_EXCEPTION = "";

    private static final String EVENT_PROP_TIMED_METADATA = "metadata";


    void setViewId(int viewId) {
        this.viewId = viewId;
    }
@@ -168,6 +181,36 @@ class VideoEventEmitter {
        receiveEvent(EVENT_ERROR, event);
    }

    void timedMetadata(Metadata metadata) {
        WritableArray metadataArray = Arguments.createArray();

        for (int i = 0; i < metadata.length(); i++) {


            Id3Frame frame = (Id3Frame) metadata.get(i);

            String value = "";

            if (frame instanceof TxxxFrame) {
                TxxxFrame txxxFrame = (TxxxFrame) frame;
                value = txxxFrame.value;
            }

            String identifier = frame.id;

            WritableMap map = Arguments.createMap();
            map.putString("identifier", identifier);
            map.putString("value", value);

            metadataArray.pushMap(map);

        }

        WritableMap event = Arguments.createMap();
        event.putArray(EVENT_PROP_TIMED_METADATA, metadataArray);
        receiveEvent(EVENT_TIMED_METADATA, event);
    }

    void audioFocusChanged(boolean hasFocus) {
        WritableMap map = Arguments.createMap();
        map.putBoolean(EVENT_PROP_HAS_AUDIO_FOCUS, hasFocus);
Loading