diff --git a/srgmediaplayer/src/main/java/ch/srg/mediaplayer/AkamaiMediaAnalyticsConfiguration.java b/srgmediaplayer/src/main/java/ch/srg/mediaplayer/AkamaiMediaAnalyticsConfiguration.java
new file mode 100644
index 0000000..1bd94a8
--- /dev/null
+++ b/srgmediaplayer/src/main/java/ch/srg/mediaplayer/AkamaiMediaAnalyticsConfiguration.java
@@ -0,0 +1,16 @@
+package ch.srg.mediaplayer;
+
+import android.util.Pair;
+
+/**
+ * Copyright (c) SRG SSR. All rights reserved.
+ *
+ * License information is available from the LICENSE file.
+ */
+public interface AkamaiMediaAnalyticsConfiguration {
+ String getAkamaiMediaAnalyticsConfigUrl();
+
+ String getAkamaiMediaAnalyticsViewerId();
+
+ Iterable extends Pair> getAkamaiMediaAnalyticsDataSet();
+}
diff --git a/srgmediaplayer/src/main/java/ch/srg/mediaplayer/EventLogger.java b/srgmediaplayer/src/main/java/ch/srg/mediaplayer/EventLogger.java
index 17242cc..3a8638e 100644
--- a/srgmediaplayer/src/main/java/ch/srg/mediaplayer/EventLogger.java
+++ b/srgmediaplayer/src/main/java/ch/srg/mediaplayer/EventLogger.java
@@ -16,9 +16,11 @@
package ch.srg.mediaplayer;
import android.os.SystemClock;
+import android.support.annotation.Nullable;
import android.util.Log;
import android.view.Surface;
+import com.akamai.android.exoplayer2loader.AkamaiExoPlayerLoader;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.ExoPlaybackException;
import com.google.android.exoplayer2.ExoPlayer;
@@ -77,6 +79,8 @@
private final Timeline.Window window;
private final Timeline.Period period;
private final long startTimeMs;
+ @Nullable
+ private AdaptiveMediaSourceEventListener chainedListener;
public EventLogger(MappingTrackSelector trackSelector) {
this.trackSelector = trackSelector;
@@ -330,6 +334,9 @@ public void onLoadStarted(DataSpec dataSpec, int dataType, int trackType, Format
int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs,
long mediaEndTimeMs, long elapsedRealtimeMs) {
// Do nothing.
+ if (chainedListener != null) {
+ chainedListener.onLoadStarted(dataSpec, dataType, trackType, trackFormat, trackSelectionReason, trackSelectionData, mediaStartTimeMs, mediaEndTimeMs, elapsedRealtimeMs);
+ }
}
@Override
@@ -338,6 +345,9 @@ public void onLoadError(DataSpec dataSpec, int dataType, int trackType, Format t
long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded,
IOException error, boolean wasCanceled) {
printInternalError("loadError", error);
+ if (chainedListener != null) {
+ chainedListener.onLoadError(dataSpec, dataType, trackType, trackFormat, trackSelectionReason, trackSelectionData, mediaStartTimeMs, mediaEndTimeMs, elapsedRealtimeMs, loadDurationMs, bytesLoaded, error, wasCanceled);
+ }
}
@Override
@@ -345,6 +355,9 @@ public void onLoadCanceled(DataSpec dataSpec, int dataType, int trackType, Forma
int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs,
long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded) {
// Do nothing.
+ if (chainedListener != null) {
+ chainedListener.onLoadCanceled(dataSpec, dataType, trackType, trackFormat, trackSelectionReason, trackSelectionData, mediaStartTimeMs, mediaEndTimeMs, elapsedRealtimeMs, loadDurationMs, bytesLoaded);
+ }
}
@Override
@@ -352,17 +365,26 @@ public void onLoadCompleted(DataSpec dataSpec, int dataType, int trackType, Form
int trackSelectionReason, Object trackSelectionData, long mediaStartTimeMs,
long mediaEndTimeMs, long elapsedRealtimeMs, long loadDurationMs, long bytesLoaded) {
Log.d(TAG, "onLoadCompleted: mediaStartTimeMs:" + mediaStartTimeMs + " mediaEndTimeMs:" + mediaEndTimeMs + " elapsedRealtimeMs:" + elapsedRealtimeMs);
+ if (chainedListener != null) {
+ chainedListener.onLoadCompleted(dataSpec, dataType, trackType, trackFormat, trackSelectionReason, trackSelectionData, mediaStartTimeMs, mediaEndTimeMs, elapsedRealtimeMs, loadDurationMs, bytesLoaded);
+ }
}
@Override
public void onUpstreamDiscarded(int trackType, long mediaStartTimeMs, long mediaEndTimeMs) {
// Do nothing.
+ if (chainedListener != null) {
+ chainedListener.onUpstreamDiscarded(trackType, mediaStartTimeMs, mediaEndTimeMs);
+ }
}
@Override
public void onDownstreamFormatChanged(int trackType, Format trackFormat, int trackSelectionReason,
Object trackSelectionData, long mediaTimeMs) {
// Do nothing.
+ if (chainedListener != null) {
+ chainedListener.onDownstreamFormatChanged(trackType, trackFormat, trackSelectionReason, trackSelectionData, mediaTimeMs);
+ }
}
// Internal methods
@@ -471,4 +493,8 @@ private static String getTrackStatusString(boolean enabled) {
return enabled ? "[X]" : "[ ]";
}
+ @Nullable
+ public void setChainedListener(AdaptiveMediaSourceEventListener chainedListener) {
+ this.chainedListener = chainedListener;
+ }
}
diff --git a/srgmediaplayer/src/main/java/ch/srg/mediaplayer/SRGMediaPlayerController.java b/srgmediaplayer/src/main/java/ch/srg/mediaplayer/SRGMediaPlayerController.java
index b3de357..bb781d6 100644
--- a/srgmediaplayer/src/main/java/ch/srg/mediaplayer/SRGMediaPlayerController.java
+++ b/srgmediaplayer/src/main/java/ch/srg/mediaplayer/SRGMediaPlayerController.java
@@ -65,7 +65,6 @@
import java.util.HashSet;
import java.util.List;
import java.util.Set;
-import java.util.UUID;
import java.util.WeakHashMap;
import ch.srg.mediaplayer.segment.model.Segment;
@@ -445,8 +444,12 @@ public interface Listener {
private static Set globalEventListeners = Collections.newSetFromMap(new WeakHashMap());
+ @Nullable
private AkamaiExoPlayerLoader akamaiExoPlayerLoader;
+ @Nullable
+ private AkamaiMediaAnalyticsConfiguration akamaiMediaAnalyticsConfiguration;
+
/**
* Create a new SRGMediaPlayerController with the current context, a mediaPlayerDataProvider, and a TAG
* if you need to retrieve a controller
@@ -484,14 +487,6 @@ public SRGMediaPlayerController(Context context, String tag) {
audioFocusChangeListener = new OnAudioFocusChangeListener(new WeakReference<>(this));
audioFocusGranted = false;
-
- String AKAMAI_QOS_VIEWER_ID = UUID.randomUUID().toString(); //FIXME Generate for each exoplayer session or shared between all exoplayer for a device?
- String AKAMAI_QOS_CONFIG_URL = "https://ma252-r.analytics.edgekey.net/config/beacon-17838.xml";
- akamaiExoPlayerLoader = new AkamaiExoPlayerLoader(getContext(), "AKAMAI_QOS_CONFIG_URL", true);
- akamaiExoPlayerLoader.setViewerId(AKAMAI_QOS_VIEWER_ID);
- akamaiExoPlayerLoader.setViewerDiagnosticsId(AKAMAI_QOS_VIEWER_ID);
-
- exoPlayer.setVideoDebugListener(akamaiExoPlayerLoader);
}
private synchronized void startBackgroundThreadIfNecessary() {
@@ -861,9 +856,9 @@ public void run() {
}
}
- private void prepareInternal(Uri videoUri, int streamType) throws SRGMediaPlayerException {
+ private void prepareInternal(@NonNull Uri videoUri, int streamType) throws SRGMediaPlayerException {
Log.v(TAG, "Preparing " + videoUri + " (" + streamType + ")");
- akamaiExoPlayerLoader.initializeLoader(exoPlayer, videoUri.toString());
+ setupAkamaiQos(videoUri);
try {
if (this.currentMediaUri != null && this.currentMediaUri.equals(videoUri)) {
return;
@@ -884,13 +879,15 @@ private void prepareInternal(Uri videoUri, int streamType) throws SRGMediaPlayer
MediaSource mediaSource;
+ eventLogger.setChainedListener(akamaiExoPlayerLoader);
+
switch (streamType) {
case STREAM_DASH:
mediaSource = new DashMediaSource(videoUri, dataSourceFactory,
- new DefaultDashChunkSource.Factory(dataSourceFactory), mainHandler, akamaiExoPlayerLoader);
+ new DefaultDashChunkSource.Factory(dataSourceFactory), mainHandler, eventLogger);
break;
case STREAM_HLS:
- mediaSource = new HlsMediaSource(videoUri, dataSourceFactory, mainHandler, akamaiExoPlayerLoader);
+ mediaSource = new HlsMediaSource(videoUri, dataSourceFactory, mainHandler, eventLogger);
break;
case STREAM_HTTP_PROGRESSIVE:
mediaSource = new ExtractorMediaSource(videoUri, dataSourceFactory, new DefaultExtractorsFactory(),
@@ -912,6 +909,18 @@ private void prepareInternal(Uri videoUri, int streamType) throws SRGMediaPlayer
}
}
+ private void setupAkamaiQos(@NonNull Uri videoUri) {
+ if (akamaiMediaAnalyticsConfiguration != null) {
+ akamaiExoPlayerLoader = new AkamaiExoPlayerLoader(getContext(), akamaiMediaAnalyticsConfiguration.getAkamaiMediaAnalyticsConfigUrl(), isDebugMode());
+ akamaiExoPlayerLoader.setViewerId(akamaiMediaAnalyticsConfiguration.getAkamaiMediaAnalyticsViewerId());
+ for (Pair keyValue : akamaiMediaAnalyticsConfiguration.getAkamaiMediaAnalyticsDataSet()) {
+ akamaiExoPlayerLoader.setData(keyValue.first, keyValue.second);
+ }
+ akamaiExoPlayerLoader.initializeLoader(exoPlayer, videoUri.toString());
+ exoPlayer.setVideoDebugListener(akamaiExoPlayerLoader);
+ }
+ }
+
private void muteInternal(boolean muted) {
exoPlayer.setVolume(muted ? 0f : 1f);
}
@@ -1111,7 +1120,9 @@ private void releaseDelegateInternal() {
}
postEventInternal(Event.Type.MEDIA_STOPPED);
- akamaiExoPlayerLoader.releaseLoader();
+ if (akamaiExoPlayerLoader != null) {
+ akamaiExoPlayerLoader.releaseLoader();
+ }
exoPlayer.stop();
exoPlayer.release();
currentMediaUri = null;
@@ -2007,4 +2018,13 @@ public void onCues(List cues) {
sendMessage(MSG_PLAYER_SUBTITLE_CUES, cues);
}
+ /**
+ * Provide Akamai QOS Configuration.
+ *
+ * @param akamaiMediaAnalyticsConfiguration akamai qos configuration to enable QOS monitoring. null to disable
+ * akamai qos.
+ */
+ public void setAkamaiMediaAnalyticsConfiguration(@Nullable AkamaiMediaAnalyticsConfiguration akamaiMediaAnalyticsConfiguration) {
+ this.akamaiMediaAnalyticsConfiguration = akamaiMediaAnalyticsConfiguration;
+ }
}
\ No newline at end of file