Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(ios): Conflicts issue fix #61

Open
wants to merge 50 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
bd9ff2b
Fixed airplay fullscreen icon
Aug 6, 2019
9035126
Integrate the example app with Charles
Aug 22, 2019
ff016ab
Integrate Akamai ExoplayerLoader
Aug 22, 2019
2771131
Added akamai library
Aug 27, 2019
0bf9d62
Code refactor
Aug 27, 2019
9ee3701
Merge pull request #43 from pankaj-pp/akamai-exoplayer-loader
Aug 28, 2019
8fe6ed3
Merge pull request #44 from pankaj-pp/akamai_integration
emanueluayza Aug 28, 2019
a391372
Merge branch 'development' into DRT-80
Aug 28, 2019
c005a89
Merge pull request #39 from pankaj-pp/DRT-80
emanueluayza Aug 28, 2019
3f76b46
Removed akamai framework from react library
Aug 29, 2019
64a399d
Fixed akamai framework for simulator
Aug 29, 2019
def4c16
Fixed akamai for device
Aug 29, 2019
41d1218
Changed react-native-player settings
Aug 29, 2019
1d9e6df
Removed fake identifier
Aug 29, 2019
a646ff6
Merge pull request #45 from pankaj-pp/akamai_fixes
emanueluayza Aug 30, 2019
fe8eb69
DRT-103: Remove the call to on Event Ready
Sep 10, 2019
70bf330
DRT-130-132: Added rewind event + live button event
Sep 16, 2019
98acef1
DRT-109: Implement eventSource property for PAUSE event
Sep 17, 2019
aaefd5d
DRT-113: Add an event when the user clicks on the live button
Sep 17, 2019
630b4f4
DRT-114: Add heart-beat for watched time
Sep 18, 2019
79d1100
DRT-119: Add an event when the rewind button is triggered
Sep 18, 2019
4f46962
Rename the event live button
Sep 18, 2019
dff0e2e
Rename events mapping values to match the React part
Sep 18, 2019
86fb3ec
Only call loadVideo when all the needed metadata is ready
Sep 18, 2019
befcd83
DTR-111 Add user friendly message when error code is 3
miguelvps Sep 23, 2019
2430d62
DRT-122 DRT-104 Add mediaType metadata to the events
miguelvps Sep 23, 2019
527023a
DRT-123 DRT-102 Rename event property name to contentName
miguelvps Sep 23, 2019
6ef4fa4
DRT-124 DRT-103 Remove READY event
miguelvps Sep 23, 2019
36279da
DRT-130 DRT-113 Handle live selection native event
miguelvps Sep 23, 2019
d52309f
DRT-131 DRT-114 Handle watched time native event
miguelvps Sep 23, 2019
7f97d30
DRT-132 DRT-119 Handle rewind native event
miguelvps Sep 23, 2019
75017d1
Merge pull request #48 from pankaj-pp/DRT-130-132
emanueluayza Sep 23, 2019
3c6899f
Cleaned code + added enter foreground notification (#51)
emanueluayza Sep 23, 2019
c69cb83
Merge pull request #49 from pankaj-pp/d11-analytics
Sep 24, 2019
c7a6622
Merge pull request #50 from pankaj-pp/multiple-video-load
Sep 24, 2019
7de33f6
Merge pull request #46 from pankaj-pp/DRT-103
Sep 24, 2019
1fd0d87
Merge pull request #52 from pankaj-pp/analytics
miguelvps Sep 26, 2019
1b5b48e
DTR-111 Fix syntax error
miguelvps Sep 26, 2019
3a346f6
Replaced akamai library + handle events manually
Sep 26, 2019
5e74373
Added akamai v2
Sep 26, 2019
c937bb4
Fixed rewind and live buttons events
Sep 26, 2019
2d45973
Merge branch 'development' into akamai_v2
Sep 26, 2019
42446b8
Merge pull request #54 from pankaj-pp/akamai_v2
miguelvps Sep 27, 2019
beb139b
Update Akamai QOS xml config url
miguelvps Oct 11, 2019
e7ac9ef
Merge pull request #57 from pankaj-pp/akamai-config
miguelvps Oct 13, 2019
acc045f
Added buffer event, added bitrate event, added completed event when t…
Oct 17, 2019
bf21415
Merge pull request #58 from pankaj-pp/Akamai_improvements
miguelvps Oct 17, 2019
0048c87
Merge branch 'master' into development
pankaj-pp Nov 5, 2019
b9e847f
Merge pull request #55 from pankaj-pp/development
pankaj-pp Nov 5, 2019
ea077fb
fix(ios): Conflicts issue fix
pankaj-pp Nov 6, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions android/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -46,4 +46,6 @@ android {
dependencies {
implementation 'com.facebook.react:react-native:+'
implementation 'com.brightcove.player:exoplayer2:6.8.1'
implementation files('lib/libAkamaiExoPlayerLoader.jar')
implementation files('lib/libAndroidMediaAnalytics.jar')
}
Binary file added android/lib/libAkamaiExoPlayerLoader.jar
Binary file not shown.
Binary file added android/lib/libAndroidMediaAnalytics.jar
Binary file not shown.
10 changes: 10 additions & 0 deletions android/src/main/java/jp/manse/BrightcovePlayerManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,13 @@ public class BrightcovePlayerManager extends SimpleViewManager<BrightcovePlayerV
public static final String EVENT_ENTER_FULLSCREEN = "event_enter_fullscreen";
public static final String EVENT_EXIT_FULLSCREEN = "event_exit_fullscreen";
public static final String EVENT_NETWORK_CONNECTIVITY_CHANGED = "event_network_connectivity_changed";
public static final String EVENT_LIVE_BUTTON_CLICKED = "event_live_button_clicked";
public static final String PROPERTY_EVENT_SOURCE = "eventSource";
public static final String PROPERTY_EVENT_SOURCE_CLICKED = "clicked";
public static final String PROPERTY_EVENT_SOURCE_AUTO = "auto";
public static final String EVENT_WATCHED_TIME = "event_watched_time";
public static final String PROPERTY_WATCHED_TIME_DURATION = "duration";
public static final String EVENT_REWIND_BUTTON_CLICKED = "event_rewind_button_clicked";

private ReactApplicationContext applicationContext;

Expand Down Expand Up @@ -187,6 +194,9 @@ public void receiveCommand(BrightcovePlayerView view, int commandType, @Nullable
map.put(EVENT_EXIT_FULLSCREEN, (Object) MapBuilder.of("registrationName", "onExitFullscreen"));
map.put(EVENT_ERROR, (Object) MapBuilder.of("registrationName", "onError"));
map.put(EVENT_NETWORK_CONNECTIVITY_CHANGED, (Object) MapBuilder.of("registrationName", "onNetworkConnectivityChange"));
map.put(EVENT_LIVE_BUTTON_CLICKED, (Object) MapBuilder.of("registrationName", "onLiveSelection"));
map.put(EVENT_WATCHED_TIME, (Object) MapBuilder.of("registrationName", "onWatchedTime"));
map.put(EVENT_REWIND_BUTTON_CLICKED, (Object) MapBuilder.of("registrationName", "onRewind"));
return map;
}
}
160 changes: 157 additions & 3 deletions android/src/main/java/jp/manse/BrightcovePlayerView.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,18 @@
import android.content.IntentFilter;
import android.content.res.Configuration;
import android.graphics.Color;
import android.os.Handler;
import android.support.v4.view.ViewCompat;
import android.util.Log;
import android.view.Choreographer;
import android.view.MotionEvent;
import android.view.SurfaceView;
import android.view.View;
import android.widget.RelativeLayout;

import com.akamai.android.exoplayer2loader.AkamaiExoPlayerLoader;
import com.brightcove.player.controller.ExoPlayerSourceSelector;
import com.brightcove.player.controller.NoSourceFoundException;
import com.brightcove.player.display.ExoPlayerVideoDisplayComponent;
import com.brightcove.player.edge.Catalog;
import com.brightcove.player.edge.OfflineCatalog;
Expand All @@ -23,6 +28,7 @@
import com.brightcove.player.mediacontroller.buttons.SeekButtonController;
import com.brightcove.player.model.Video;
import com.brightcove.player.analytics.Analytics;
import com.brightcove.player.util.StringUtil;
import com.brightcove.player.view.BrightcoveExoPlayerVideoView;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.LifecycleEventListener;
Expand All @@ -36,19 +42,24 @@
import com.google.android.exoplayer2.Format;
import com.google.android.exoplayer2.PlaybackParameters;
import com.google.android.exoplayer2.RendererCapabilities;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.source.TrackGroup;
import com.google.android.exoplayer2.source.TrackGroupArray;
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
import com.google.android.exoplayer2.trackselection.FixedTrackSelection;
import com.google.android.exoplayer2.trackselection.MappingTrackSelector;
import com.google.android.exoplayer2.trackselection.TrackSelection;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;
import java.util.UUID;

import jp.manse.util.AudioFocusManager;
import jp.manse.util.NetworkChangeReceiver;
import jp.manse.util.NetworkUtil;
import jp.manse.util.PlayTimer;

public class BrightcovePlayerView extends RelativeLayout implements LifecycleEventListener,
AudioFocusManager.AudioFocusChangedListener, NetworkChangeReceiver.NetworkChangeListener {
Expand All @@ -68,6 +79,7 @@ public class BrightcovePlayerView extends RelativeLayout implements LifecycleEve
private Map<String, Object> mediaInfo;
private boolean autoPlay = true;
private boolean playing = false;
private boolean pauseButtonClicked = false;
private int bitRate = 0;
private float playbackRate = 1;
private static final int SEEK_AMOUNT = 10000; // In milliseconds
Expand All @@ -76,6 +88,37 @@ public class BrightcovePlayerView extends RelativeLayout implements LifecycleEve
private NetworkChangeReceiver networkChangeReceiver;
private boolean isNetworkForcedPause = false;
private boolean isRegisteredConnectivityChanged = false;
private AkamaiExoPlayerLoader akamaiExoPlayerLoader;
private String akamaiConfigURL = "https://ma1442-r.analytics.edgekey.net/config/beacon-25672.xml";
private String currentStreamURL;
private String uuid;
private PlayTimer playTimer;
final long heartBeatInterval = 30000;
final Handler handler = new Handler();
Runnable heartBeatRunnable = new Runnable() {

@Override
public void run() {
int watchTime;
if (playerVideoView.isPlaying()) {
playTimer.pause();
watchTime = playTimer.elapsedTime;
playTimer.stop();
playTimer.start();
} else {
watchTime = playTimer.elapsedTime;
playTimer.stop();
}

WritableMap event = Arguments.createMap();
event.putInt(BrightcovePlayerManager.PROPERTY_WATCHED_TIME_DURATION, watchTime);
ReactContext reactContext = (ReactContext) BrightcovePlayerView.this.getContext();
reactContext
.getJSModule(RCTEventEmitter.class)
.receiveEvent(BrightcovePlayerView.this.getId(), BrightcovePlayerManager.EVENT_WATCHED_TIME, event);
handler.postDelayed(this, heartBeatInterval);
}
};

public BrightcovePlayerView(ThemedReactContext context, ReactApplicationContext applicationContext) {
super(context);
Expand All @@ -102,6 +145,10 @@ public BrightcovePlayerView(ThemedReactContext context, ReactApplicationContext
// Implement the analytics to the Brightcove player
this.analytics = this.playerVideoView.getAnalytics();

// Create Akamai ExoPlayerLoader
akamaiExoPlayerLoader = new AkamaiExoPlayerLoader(this.context.getCurrentActivity(), akamaiConfigURL, true);
uuid = UUID.randomUUID().toString();

// Create AudioFocusManager instance and register BrightcovePlayerView as a listener
this.audioFocusManager = new AudioFocusManager(this.context);
this.audioFocusManager.registerListener(this);
Expand Down Expand Up @@ -131,6 +178,12 @@ public void processEvent(Event e) {
eventEmitter.on(EventType.DID_SET_VIDEO, new EventListener() {
@Override
public void processEvent(Event e) {
setCurrentStreamURL(BrightcovePlayerView.this.playerVideoView.getCurrentVideo());
// Initialization of the ExoplayerLoader should happen after a video is set, otherwise ExoPlayer
// instance will be null
initializeAkamaiExoplayerLoader();
setAkamaiExoPlayerLoaderData();

WritableMap mediaInfo = Arguments.createMap();
mediaInfo.putString("title", BrightcovePlayerView.this.mediaInfo.get("name").toString());

Expand All @@ -145,6 +198,13 @@ public void processEvent(Event e) {
eventEmitter.on(EventType.DID_PLAY, new EventListener() {
@Override
public void processEvent(Event e) {
if (playTimer == null) {
// This is the first time the player is playing a video
playTimer = new PlayTimer();
handler.postDelayed(heartBeatRunnable, heartBeatInterval);
}

playTimer.start();
BrightcovePlayerView.this.playing = true;
WritableMap event = Arguments.createMap();
ReactContext reactContext = (ReactContext) BrightcovePlayerView.this.getContext();
Expand All @@ -156,8 +216,15 @@ public void processEvent(Event e) {
eventEmitter.on(EventType.DID_PAUSE, new EventListener() {
@Override
public void processEvent(Event e) {
playTimer.pause();
BrightcovePlayerView.this.playing = false;
WritableMap event = Arguments.createMap();
if (pauseButtonClicked) {
event.putString(BrightcovePlayerManager.PROPERTY_EVENT_SOURCE, BrightcovePlayerManager.PROPERTY_EVENT_SOURCE_CLICKED);
pauseButtonClicked = false;
} else {
event.putString(BrightcovePlayerManager.PROPERTY_EVENT_SOURCE, BrightcovePlayerManager.PROPERTY_EVENT_SOURCE_AUTO);
}
ReactContext reactContext = (ReactContext) BrightcovePlayerView.this.getContext();
reactContext.getJSModule(RCTEventEmitter.class).receiveEvent(BrightcovePlayerView.this.getId(), BrightcovePlayerManager.EVENT_PAUSE, event);
// When the playback stops, release the audio focus
Expand Down Expand Up @@ -249,6 +316,46 @@ public void processEvent(Event e) {
.receiveEvent(BrightcovePlayerView.this.getId(), BrightcovePlayerManager.EVENT_BUFFERING_COMPLETED, event);
}
});

eventEmitter.on(EventType.REWIND, new EventListener() {
@Override
public void processEvent(Event e) {
WritableMap event = Arguments.createMap();
ReactContext reactContext = (ReactContext) BrightcovePlayerView.this.getContext();
reactContext
.getJSModule(RCTEventEmitter.class)
.receiveEvent(BrightcovePlayerView.this.getId(), BrightcovePlayerManager.EVENT_REWIND_BUTTON_CLICKED, event);
}
});

this.playerVideoView.getBrightcoveMediaController().getBrightcoveControlBar().findViewById(R.id.play).setOnTouchListener(new OnTouchListener(){

@Override
public boolean onTouch(View v, MotionEvent event) {
if (event.getAction() == MotionEvent.ACTION_DOWN) {
if(playerVideoView.isPlaying()) {
pauseButtonClicked = true;
}
}
return false;
}
});

this.playerVideoView.getBrightcoveMediaController().getBrightcoveControlBar().findViewById(R.id.live).setOnTouchListener(new OnTouchListener(){

@Override
public boolean onTouch(View v, MotionEvent motionEvent) {
if (motionEvent.getAction() == MotionEvent.ACTION_DOWN) {
WritableMap event = Arguments.createMap();
ReactContext reactContext = (ReactContext) BrightcovePlayerView.this.getContext();
reactContext
.getJSModule(RCTEventEmitter.class)
.receiveEvent(BrightcovePlayerView.this.getId(), BrightcovePlayerManager.EVENT_LIVE_BUTTON_CLICKED, event);
}
return false;
}
});

// Emits all the errors back to the React Native
eventEmitter.on(EventType.ERROR, new EventListener() {
@Override
Expand Down Expand Up @@ -315,7 +422,6 @@ public void setAccountId(String accountId) {
public void setPlayerId(String playerId) {
this.playerId = playerId;
this.analytics.setDestination("bcsdk://" + playerId);
this.loadVideo();
}

public void setVideoId(String videoId) {
Expand All @@ -332,7 +438,9 @@ public void setReferenceId(String referenceId) {

public void setVideoToken(String videoToken) {
this.videoToken = videoToken;
this.loadVideo();
if (videoToken == null || videoToken.isEmpty()) {
this.loadVideo();
}
}

public void setAutoPlay(boolean autoPlay) {
Expand Down Expand Up @@ -472,7 +580,7 @@ public void onError(String s) {

this.catalog = new Catalog(this.playerVideoView.getEventEmitter(), this.accountId, this.policyKey);

if (this.accountId != null) {
if (this.accountId != null && this.policyKey != null) {
if (this.videoId != null) {
this.catalog.findVideoByID(this.videoId, listener);
} else if (this.referenceId != null) {
Expand Down Expand Up @@ -531,13 +639,20 @@ public void onHostResume() {
// Register to audio focus changes when the screen resumes
audioFocusManager.registerListener(this);
registerConnectivityChange();
if (!StringUtil.isEmpty(currentStreamURL)) {
// Re-initialize ExoplayerLoader when the host resumes
initializeAkamaiExoplayerLoader();
setAkamaiExoPlayerLoaderData();
}
}

@Override
public void onHostPause() {
// Unregister from audio focus changes when the screen goes in the background
audioFocusManager.unregisterListener();
unregisterConnectivityChange();
// release the loader when the host is paused
releaseAkamaiExoplayerLoader();
}

@Override
Expand All @@ -548,12 +663,15 @@ protected void onDetachedFromWindow() {
// Unregister from audio focus changes when the screen goes in the background
audioFocusManager.unregisterListener();
unregisterConnectivityChange();
// release the loader when the view is detached
releaseAkamaiExoplayerLoader();
}

@Override
public void onHostDestroy() {
this.playerVideoView.destroyDrawingCache();
this.playerVideoView.clear();
this.currentStreamURL = "";
this.removeAllViews();
this.applicationContext.removeLifecycleEventListener(this);
}
Expand Down Expand Up @@ -646,4 +764,40 @@ private void onNetworkConnectivityChange(String networkStatus) {
event
);
}

private void setCurrentStreamURL(Video video) {
try {
String videoCloudURL = (new ExoPlayerSourceSelector()).selectSource(video).getUrl();
URL url = new URL(videoCloudURL);
// We just need the base url and the path to be passed to initializeLoader
currentStreamURL = url.getProtocol() + "://" + url.getHost() + url.getPath();
} catch (NoSourceFoundException | MalformedURLException e) {
e.printStackTrace();
}
}

private void initializeAkamaiExoplayerLoader() {
ExoPlayer exoPlayer =
((ExoPlayerVideoDisplayComponent)this.playerVideoView.getVideoDisplay()).getExoPlayer();
akamaiExoPlayerLoader.initializeLoader(exoPlayer, currentStreamURL);
if (exoPlayer != null) {
((SimpleExoPlayer) exoPlayer).addAnalyticsListener(akamaiExoPlayerLoader);
}
}

private void setAkamaiExoPlayerLoaderData() {
BrightcovePlayerView.this.akamaiExoPlayerLoader.setData("title", BrightcovePlayerView.this.mediaInfo.get("name").toString());
BrightcovePlayerView.this.akamaiExoPlayerLoader.setData("contentLength", BrightcovePlayerView.this.mediaInfo.get("duration").toString());
BrightcovePlayerView.this.akamaiExoPlayerLoader.setData("device", android.os.Build.DEVICE);
BrightcovePlayerView.this.akamaiExoPlayerLoader.setData("playerId", BrightcovePlayerView.this.playerId);
BrightcovePlayerView.this.akamaiExoPlayerLoader.setData("eventName", "ExoPlayerLoaderReactPlayer");
BrightcovePlayerView.this.akamaiExoPlayerLoader.setViewerId(uuid);
BrightcovePlayerView.this.akamaiExoPlayerLoader.setViewerDiagnosticsId(uuid);
}

private void releaseAkamaiExoplayerLoader() {
if (akamaiExoPlayerLoader != null){
akamaiExoPlayerLoader.releaseLoader();
}
}
}
27 changes: 27 additions & 0 deletions android/src/main/java/jp/manse/util/PlayTimer.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
package jp.manse.util;

public class PlayTimer {
public int elapsedTime = 0;
private long startTime;

public void start() {
startTime = System.currentTimeMillis();
}

public void pause() {
long currentTime = System.currentTimeMillis();
if (startTime > 0) {
elapsedTime += (currentTime - startTime) / 1000.0;
}
startTime = 0;
}

public int getElapsedTime() {
return elapsedTime;
}

public void stop() {
elapsedTime = 0;
startTime = 0;
}
}
4 changes: 3 additions & 1 deletion example/android/app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
android:icon="@mipmap/ic_launcher"
android:roundIcon="@mipmap/ic_launcher_round"
android:allowBackup="false"
android:theme="@style/AppTheme">
android:theme="@style/AppTheme"
android:networkSecurityConfig="@xml/network_security_config"
>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
<debug-overrides>
<trust-anchors>
<!-- Trust user added CAs while debuggable only -->
<certificates src="user"/>
</trust-anchors>
</debug-overrides>
</network-security-config>
Loading