Skip to content
This repository has been archived by the owner on Jul 25, 2023. It is now read-only.

Commit

Permalink
Merge pull request #16 from SRGSSR/feature/akamai_qos_integration
Browse files Browse the repository at this point in the history
Feature/akamai qos integration
  • Loading branch information
StaehliJ authored Jun 12, 2018
2 parents 47961d7 + 72cae13 commit 167ff65
Show file tree
Hide file tree
Showing 32 changed files with 502 additions and 2 deletions.
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1 +1 @@
include ':srgmediaplayer', ':srgmediaplayertestutils'
include ':srgmediaplayer', ':srgmediaplayertestutils',':srgmediaplayerdemo'
5 changes: 5 additions & 0 deletions srgmediaplayer/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ dependencies {
androidTestImplementation "com.android.support.test:runner:$rootProject.androidSupportTest"
androidTestImplementation "com.android.support.test:rules:$rootProject.androidSupportTest"

implementation files('libs/libAndroidMediaAnalytics.jar')
implementation files('libs/libAkamaiExoPlayerLoader.jar')

implementation "com.android.support:appcompat-v7:$rootProject.supportLibraryVersion"
implementation "com.android.support:support-annotations:$rootProject.supportLibraryVersion"
implementation "com.android.support:mediarouter-v7:$rootProject.supportLibraryVersion"
Expand All @@ -34,6 +37,8 @@ dependencies {
implementation "com.google.android.exoplayer:exoplayer-dash:r$rootProject.exoPlayerVersion"
implementation "com.google.android.exoplayer:exoplayer-ui:r$rootProject.exoPlayerVersion"
implementation "com.google.android.exoplayer:extension-mediasession:r$rootProject.exoPlayerVersion"


}

apply from: '../utilities.gradle'
Binary file added srgmediaplayer/libs/libAkamaiExoPlayerLoader.jar
Binary file not shown.
Binary file added srgmediaplayer/libs/libAndroidMediaAnalytics.jar
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package ch.srg.mediaplayer;

import android.util.Pair;

/**
* Copyright (c) SRG SSR. All rights reserved.
* <p>
* License information is available from the LICENSE file.
*/
public interface AkamaiMediaAnalyticsConfiguration {
String getAkamaiMediaAnalyticsConfigUrl();

String getAkamaiMediaAnalyticsViewerId();

Iterable<? extends Pair<String, String>> getAkamaiMediaAnalyticsDataSet();
}
26 changes: 26 additions & 0 deletions srgmediaplayer/src/main/java/ch/srg/mediaplayer/EventLogger.java
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -338,31 +345,46 @@ 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
public void onLoadCanceled(DataSpec dataSpec, int dataType, int trackType, Format trackFormat,
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
public void onLoadCompleted(DataSpec dataSpec, int dataType, int trackType, Format trackFormat,
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
Expand Down Expand Up @@ -471,4 +493,8 @@ private static String getTrackStatusString(boolean enabled) {
return enabled ? "[X]" : "[ ]";
}

@Nullable
public void setChainedListener(AdaptiveMediaSourceEventListener chainedListener) {
this.chainedListener = chainedListener;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import android.view.TextureView;
import android.view.View;

import com.akamai.android.exoplayer2loader.AkamaiExoPlayerLoader;
import com.google.android.exoplayer2.C;
import com.google.android.exoplayer2.DefaultLoadControl;
import com.google.android.exoplayer2.DefaultRenderersFactory;
Expand Down Expand Up @@ -443,6 +444,12 @@ public interface Listener {

private static Set<Listener> globalEventListeners = Collections.newSetFromMap(new WeakHashMap<Listener, Boolean>());

@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
Expand Down Expand Up @@ -849,8 +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 + ")");
setupAkamaiQos(videoUri);
try {
if (this.currentMediaUri != null && this.currentMediaUri.equals(videoUri)) {
return;
Expand All @@ -871,6 +879,8 @@ private void prepareInternal(Uri videoUri, int streamType) throws SRGMediaPlayer

MediaSource mediaSource;

eventLogger.setChainedListener(akamaiExoPlayerLoader);

switch (streamType) {
case STREAM_DASH:
mediaSource = new DashMediaSource(videoUri, dataSourceFactory,
Expand Down Expand Up @@ -899,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<String, String> 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);
}
Expand Down Expand Up @@ -1096,7 +1118,11 @@ private void releaseDelegateInternal() {
if (debugMode) {
assertCommandHandlerThread();
}

postEventInternal(Event.Type.MEDIA_STOPPED);
if (akamaiExoPlayerLoader != null) {
akamaiExoPlayerLoader.releaseLoader();
}
exoPlayer.stop();
exoPlayer.release();
currentMediaUri = null;
Expand Down Expand Up @@ -1992,4 +2018,13 @@ public void onCues(List<Cue> 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;
}
}
1 change: 1 addition & 0 deletions srgmediaplayerdemo/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
36 changes: 36 additions & 0 deletions srgmediaplayerdemo/build.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
apply plugin: 'com.android.application'

android {
compileSdkVersion 27



defaultConfig {
applicationId "ch.srg.mediaplayer.demo"
minSdkVersion 16
targetSdkVersion 27
versionCode 1
versionName "1.0"

testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"

}

buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}

}

dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support.constraint:constraint-layout:1.1.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation project(':srgmediaplayer')
}
21 changes: 21 additions & 0 deletions srgmediaplayerdemo/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package ch.srg.mediaplayer.demo;

import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;

import org.junit.Test;
import org.junit.runner.RunWith;

import static org.junit.Assert.*;

/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();

assertEquals("ch.srg.mediaplayer.demo", appContext.getPackageName());
}
}
21 changes: 21 additions & 0 deletions srgmediaplayerdemo/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ch.srg.mediaplayer.demo">

<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>

</manifest>
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package ch.srg.mediaplayer.demo;

import android.net.Uri;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

import ch.srg.mediaplayer.SRGMediaPlayerController;
import ch.srg.mediaplayer.SRGMediaPlayerException;
import ch.srg.mediaplayer.SRGMediaPlayerView;

public class MainActivity extends AppCompatActivity {

private SRGMediaPlayerView mediaPlayerView;
private SRGMediaPlayerController mediaPlayerController;
private static final String URL = "https://srgplayerswivod-vh.akamaihd.net/i/44089658/,video,.mp4.csmil/master.m3u8?start=0.0&end=113.0";
private static final @SRGMediaPlayerController.SRGStreamType
int streamType = SRGMediaPlayerController.STREAM_HLS;

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mediaPlayerView = findViewById(R.id.media_player_view);

mediaPlayerController = new SRGMediaPlayerController(this, "demo_player");
}

@Override
protected void onResume() {
super.onResume();
mediaPlayerController.bindToMediaPlayerView(mediaPlayerView);
try {
mediaPlayerController.play(Uri.parse(URL), streamType);
} catch (SRGMediaPlayerException e) {
e.printStackTrace();
}
}

@Override
protected void onPause() {
super.onPause();
mediaPlayerController.unbindFromMediaPlayerView(mediaPlayerView);
mediaPlayerController.release();
}

}
Loading

0 comments on commit 167ff65

Please sign in to comment.