diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 00000000..1f06fa96
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "orchestrator/android/ExoPlayer-Yospace-Java/ssp"]
+ path = orchestrator/android/ExoPlayer-Yospace-Java/ssp
+ url = git@github.com:streamroot/streamroot-samples-private.git
diff --git a/orchestrator/android/AllSamples/settings.gradle b/orchestrator/android/AllSamples/settings.gradle
index 01fccca3..f110c7f0 100644
--- a/orchestrator/android/AllSamples/settings.gradle
+++ b/orchestrator/android/AllSamples/settings.gradle
@@ -2,7 +2,8 @@
def samples = [
'ExoPlayer',
'ExoPlayer-Java',
- 'PRESTOplay-Java'
+ 'PRESTOplay-Java',
+ 'ExoPlayer-Yospace-Java'
]
samples.each {
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/.gitignore b/orchestrator/android/ExoPlayer-Yospace-Java/.gitignore
new file mode 100644
index 00000000..5edb4eeb
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/.gitignore
@@ -0,0 +1,10 @@
+*.iml
+.gradle
+/local.properties
+/.idea/libraries
+/.idea/modules.xml
+/.idea/workspace.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/README.md b/orchestrator/android/ExoPlayer-Yospace-Java/README.md
new file mode 100644
index 00000000..d3ad9eb2
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/README.md
@@ -0,0 +1,34 @@
+# Streamroot Android Orchestrator ExoPlayer Yospace Java
+
+## Common integration
+
+Make sure you start with the [common Java integration](https://github.com/streamroot/streamroot-samples/blob/master/orchestrator/android/README.md)
+
+## Specific integration override
+
+### 3. Bridge between your Player and the delivery client.
+
+In order to work perfectly, the SDK instances need to interact with the player and listen to its events.
+Please add the following class to your project :
+
+- [PlayerInteractor](https://github.com/streamroot/streamroot-samples/blob/master/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/ExoPlayerInteractor.java)
+
+## Additional steps
+
+-> ExoPlayer requires targetCompatibility java 8.
+-> URLs are hardcoded in the YospaceModule and mode is hardcoded in PlayerActivity
+
+```java
+private static final Session.PlaybackMode YOSPACE_MODE = Session.PlaybackMode.LIVE;
+```
+
+-> Some files are private and thus symlinked. You can find the missing files (AARs, adapters, policy impl, etc), inside the Yospace SDK sample application.
+
+## Integrate with PRESTOplay
+
+- [PRESTOplay-Java project](https://github.com/streamroot/streamroot-samples/tree/master/orchestrator/android/PRESTOplay-Java)
+
+In particular, make sure you replace the player interactor by PRESTO's :
+
+- [PlayerInteractor](https://github.com/streamroot/streamroot-samples/blob/master/orchestrator/android/PRESTOplay-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/prestoplay/PRESTOPlayerInteractor.java)
+
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/.gitignore b/orchestrator/android/ExoPlayer-Yospace-Java/app/.gitignore
new file mode 100644
index 00000000..796b96d1
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/build.gradle b/orchestrator/android/ExoPlayer-Yospace-Java/app/build.gradle
new file mode 100644
index 00000000..eb3f1578
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/build.gradle
@@ -0,0 +1,46 @@
+//noinspection GradleCompatible
+apply plugin: 'com.android.application'
+
+android {
+ compileSdkVersion 29
+ defaultConfig {
+ applicationId "io.streamroot.lumen.delivery.client.samples.orchestrator.exoplayer"
+ minSdkVersion 19
+ targetSdkVersion 29
+ versionCode 1
+ versionName "1.0"
+ multiDexEnabled true
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+ }
+ buildTypes {
+ release {
+ minifyEnabled false
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
+ }
+ }
+
+ compileOptions {
+ targetCompatibility JavaVersion.VERSION_1_8
+ }
+}
+
+repositories {
+ flatDir {
+ dirs 'libs'
+ }
+}
+
+dependencies {
+ implementation 'com.google.android.exoplayer:exoplayer:2.11.7'
+
+ def dc_version = '1.1.1'
+ implementation 'io.streamroot.lumen.delivery.client:orchestrator-sdk:' + dc_version
+ implementation 'io.streamroot.lumen.delivery.client:orchestrator-sdk-utils:' + dc_version
+
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ implementation 'com.google.android.material:material:1.2.1'
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
+
+ implementation(name: 'yoAdManagement-debug', ext: 'aar')
+ implementation(name: 'yoUtil-debug', ext: 'aar')
+}
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/libs/yoAdManagement-debug.aar b/orchestrator/android/ExoPlayer-Yospace-Java/app/libs/yoAdManagement-debug.aar
new file mode 120000
index 00000000..307f96ea
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/libs/yoAdManagement-debug.aar
@@ -0,0 +1 @@
+../../ssp/exoplayer-yospace/lib/yoAdManagement-debug.aar
\ No newline at end of file
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/libs/yoUtil-debug.aar b/orchestrator/android/ExoPlayer-Yospace-Java/app/libs/yoUtil-debug.aar
new file mode 120000
index 00000000..a28feafd
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/libs/yoUtil-debug.aar
@@ -0,0 +1 @@
+../../ssp/exoplayer-yospace/lib/yoUtil-debug.aar
\ No newline at end of file
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/proguard-rules.pro b/orchestrator/android/ExoPlayer-Yospace-Java/app/proguard-rules.pro
new file mode 100644
index 00000000..f1b42451
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/proguard-rules.pro
@@ -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
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/AndroidManifest.xml b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..9bfd57ff
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/AndroidManifest.xml
@@ -0,0 +1,31 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/Callback1.java b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/Callback1.java
new file mode 100644
index 00000000..36b4123b
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/Callback1.java
@@ -0,0 +1,5 @@
+package io.streamroot.lumen.delivery.client.samples.orchestrator.exoplayer;
+
+public interface Callback1 {
+ void call(T t);
+}
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/ExoPlayerInteractor.java b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/ExoPlayerInteractor.java
new file mode 100644
index 00000000..c58a3e26
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/ExoPlayerInteractor.java
@@ -0,0 +1,62 @@
+package io.streamroot.lumen.delivery.client.samples.orchestrator.exoplayer;
+
+import androidx.annotation.NonNull;
+
+import com.google.android.exoplayer2.ExoPlaybackException;
+import com.google.android.exoplayer2.ExoPlayer;
+import com.google.android.exoplayer2.Player;
+import com.google.android.exoplayer2.Player.EventListener;
+import com.google.android.exoplayer2.source.TrackGroupArray;
+import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import io.streamroot.lumen.delivery.client.core.LumenPlayerInteractorBase;
+import io.streamroot.lumen.delivery.client.core.LumenVideoPlaybackState;
+
+public final class ExoPlayerInteractor extends LumenPlayerInteractorBase implements EventListener {
+
+ private AtomicBoolean listening = new AtomicBoolean(false);
+
+ public ExoPlayerInteractor() {}
+ public ExoPlayerInteractor(@NonNull ExoPlayer exoPlayer) { setPlayer(exoPlayer); }
+
+ public void setPlayer(@NonNull ExoPlayer exoPlayer) {
+ if (listening.compareAndSet(false, true)) {
+ exoPlayer.addListener(this);
+ }
+ }
+
+ @Override
+ public void onSeekProcessed() {
+ super.playerStateChange(LumenVideoPlaybackState.SEEKING);
+ }
+
+ @Override
+ public void onTracksChanged(TrackGroupArray trackGroups, TrackSelectionArray trackSelections) {
+ super.playerTrackSwitch();
+ }
+
+ @Override
+ public void onPlayerError(ExoPlaybackException error) {
+ super.playerError();
+ }
+
+ @Override
+ public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
+ switch(playbackState) {
+ case Player.STATE_IDLE:
+ super.playerStateChange(LumenVideoPlaybackState.IDLE);
+ break;
+ case Player.STATE_BUFFERING:
+ super.playerStateChange(LumenVideoPlaybackState.REBUFFERING);
+ break;
+ case Player.STATE_READY:
+ super.playerStateChange(playWhenReady ? LumenVideoPlaybackState.PLAYING : LumenVideoPlaybackState.PAUSED);
+ break;
+ case Player.STATE_ENDED:
+ super.playerStateChange(LumenVideoPlaybackState.ENDED);
+ break;
+ }
+ }
+}
\ No newline at end of file
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/MainActivity.java b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/MainActivity.java
new file mode 100644
index 00000000..6fe5719a
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/MainActivity.java
@@ -0,0 +1,36 @@
+package io.streamroot.lumen.delivery.client.samples.orchestrator.exoplayer;
+
+import android.content.Intent;
+import android.os.Bundle;
+import android.text.TextUtils;
+import android.view.View;
+import android.widget.TextView;
+
+import androidx.annotation.Nullable;
+import androidx.appcompat.app.AppCompatActivity;
+
+public class MainActivity extends AppCompatActivity {
+
+ @Override
+ protected void onCreate(@Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_main);
+
+ findViewById(R.id.launchButton).setOnClickListener(new View.OnClickListener() {
+ @Override
+ public void onClick(View v) {
+ final String stream = ((TextView)findViewById(R.id.streamEditText)).getText().toString();
+ if (TextUtils.isEmpty(stream.trim())) return;
+
+ final Intent i = PlayerActivity.makeIntent(MainActivity.this,
+ new PlayerActivity.PlayerActivityArgs(
+ ((TextView)findViewById(R.id.dcKeyET)).getText().toString(),
+ stream,
+ ((TextView)findViewById(R.id.orchPropET)).getText().toString()
+ )
+ ).addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ startActivity(i);
+ }
+ });
+ }
+}
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/PlayerActivity.java b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/PlayerActivity.java
new file mode 100644
index 00000000..a9c6ace4
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/PlayerActivity.java
@@ -0,0 +1,363 @@
+package io.streamroot.lumen.delivery.client.samples.orchestrator.exoplayer;
+
+import android.annotation.SuppressLint;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.os.Bundle;
+import android.os.Handler;
+import android.util.Log;
+import android.view.View;
+import android.widget.Toast;
+
+import androidx.annotation.NonNull;
+import androidx.appcompat.app.AppCompatActivity;
+
+import com.google.android.exoplayer2.C;
+import com.google.android.exoplayer2.ExoPlaybackException;
+import com.google.android.exoplayer2.ExoPlayer;
+import com.google.android.exoplayer2.Player;
+import com.google.android.exoplayer2.SimpleExoPlayer;
+import com.google.android.exoplayer2.mediacodec.MediaCodecInfo;
+import com.google.android.exoplayer2.mediacodec.MediaCodecRenderer;
+import com.google.android.exoplayer2.mediacodec.MediaCodecUtil;
+import com.google.android.exoplayer2.source.LoopingMediaSource;
+import com.google.android.exoplayer2.source.MediaSource;
+import com.google.android.exoplayer2.source.dash.DashMediaSource;
+import com.google.android.exoplayer2.source.dash.DefaultDashChunkSource;
+import com.google.android.exoplayer2.source.hls.HlsMediaSource;
+import com.google.android.exoplayer2.ui.PlayerView;
+import com.google.android.exoplayer2.upstream.DefaultHttpDataSource;
+import com.google.android.exoplayer2.upstream.DefaultHttpDataSourceFactory;
+import com.google.android.exoplayer2.util.Util;
+import com.yospace.android.hls.analytic.AnalyticEventListener;
+import com.yospace.android.hls.analytic.Session;
+import com.yospace.android.hls.analytic.advert.AdBreak;
+import com.yospace.android.hls.analytic.advert.Advert;
+import com.yospace.android.xml.VastPayload;
+import com.yospace.android.xml.VmapPayload;
+
+import org.jetbrains.annotations.Nullable;
+
+import io.streamroot.lumen.delivery.client.core.LumenDeliveryClient;
+import io.streamroot.lumen.delivery.client.core.LumenLogLevel;
+import io.streamroot.lumen.delivery.client.core.LumenOptionalOrchestratorBuilder;
+import io.streamroot.lumen.delivery.client.core.LumenPlayerInteractorBase;
+import io.streamroot.lumen.delivery.client.samples.orchestrator.exoplayer.common.PlayerAdapter;
+import io.streamroot.lumen.delivery.client.samples.orchestrator.exoplayer.common.PlayerAdapterLive;
+import io.streamroot.lumen.delivery.client.utils.LumenStatsView;
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
+
+public class PlayerActivity extends AppCompatActivity implements Player.EventListener, AnalyticEventListener {
+
+ private static final Session.PlaybackMode YOSPACE_MODE = Session.PlaybackMode.LIVE;
+
+ public static final class PlayerActivityArgs {
+ @Nullable final String dcKey;
+ @Nullable final String url;
+ @Nullable final String orchProperty;
+ public PlayerActivityArgs(@Nullable String dcKey, @Nullable String url, @Nullable String orchProperty) {
+ this.dcKey = dcKey;
+ this.url = url;
+ this.orchProperty = orchProperty;
+ }
+ }
+
+ private static final String ARG_DC_KEY = "dcKey";
+ private static final String ARG_STREAM_URL = "streamUrl";
+ private static final String ARG_ORCH_PROP = "orchestratorProperty";
+
+ public static Intent makeIntent(Context ctx, PlayerActivityArgs args) {
+ return new Intent(ctx, PlayerActivity.class)
+ .putExtra(ARG_DC_KEY, args.dcKey)
+ .putExtra(ARG_STREAM_URL, args.url)
+ .putExtra(ARG_ORCH_PROP, args.orchProperty);
+ }
+
+ public static PlayerActivityArgs extractArgs(Intent i) {
+ return new PlayerActivityArgs(
+ i.getStringExtra(ARG_DC_KEY),
+ i.getStringExtra(ARG_STREAM_URL),
+ i.getStringExtra(ARG_ORCH_PROP));
+ }
+
+ @Nullable private PlayerView exoPlayerView = null;
+ @Nullable private LumenStatsView dcStatsView = null;
+
+ @Nullable private String mDCKey = null;
+ // @Nullable private String mStreamUrl = null;
+ @Nullable private String mOrchProperty = null;
+
+ @Nullable private ExoPlayer player = null;
+
+ @Nullable private LumenDeliveryClient deliveryClient = null;
+
+ @NonNull private YospaceModule.YospaceBridgeStruct yoBridge = new YospaceModule.YospaceBridgeStruct();
+ @Nullable private Handler mMainHandler = null;
+
+ @Override
+ protected void onCreate(@androidx.annotation.Nullable Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.activity_player);
+
+ mMainHandler = new Handler(); // created with main looper
+ final PlayerActivityArgs args = extractArgs(getIntent());
+ // mStreamUrl = args.url;
+ {
+ final String tmpOP = args.orchProperty;
+ mOrchProperty = (tmpOP != null && !tmpOP.trim().isEmpty()) ? tmpOP : null;
+ }
+ {
+ final String tmp = args.dcKey;
+ mDCKey = (tmp != null && !tmp.trim().isEmpty()) ? tmp : null;
+ }
+
+ exoPlayerView = findViewById(R.id.exoplayerView);
+ dcStatsView = findViewById(R.id.dcStatsView);
+ }
+
+ @Override
+ protected void onStart() {
+ super.onStart();
+
+ if (Util.SDK_INT > 23) {
+ initPlayer();
+ }
+ }
+
+ @Override
+ protected void onPause() {
+ super.onPause();
+
+ if (Util.SDK_INT <= 23) {
+ releasePlayer();
+ }
+ }
+
+ @Override
+ protected void onResume() {
+ super.onResume();
+
+ if (Util.SDK_INT <= 23 || player == null) {
+ initPlayer();
+ }
+ }
+
+ @Override
+ protected void onStop() {
+ if (Util.SDK_INT > 23) {
+ releasePlayer();
+ }
+
+ super.onStop();
+ }
+
+ private void initPlayer() {
+ if (player == null) {
+ YospaceModule.createAdapterAndSession(this, this, YOSPACE_MODE, new YospaceModule.YospaceModuleCallback() {
+ @Override
+ public void onSessionAvailable(Session session) {
+ yoBridge.mSession = session;
+ }
+
+ @Override
+ public void onFinalUrlReady(PlayerAdapter adapter, String finalYospaceUrl) {
+ Log.v("PlayerActivity", "finalYospace url => " + finalYospaceUrl);
+ yoBridge.mAdapter = adapter;
+ yoBridge.mFinalYospaceUrl = finalYospaceUrl;
+
+ // Build the player
+ final SimpleExoPlayer newPlayer = new SimpleExoPlayer.Builder(getApplicationContext()).build();
+
+ newPlayer.setPlayWhenReady(true);
+
+ newPlayer.addListener(PlayerActivity.this);
+ newPlayer.addListener(adapter);
+ adapter.setVideoPlayer(newPlayer);
+
+ if (adapter instanceof PlayerAdapterLive) {
+ newPlayer.addMetadataOutput((PlayerAdapterLive) adapter);
+ }
+
+ // Include streamroot in the middle
+ final ExoPlayerInteractor interactor = new ExoPlayerInteractor(newPlayer);
+
+ final LumenDeliveryClient dc = initDeliveryClient(interactor, finalYospaceUrl);
+ deliveryClient = dc;
+ dc.addStateStatsListener(dcStatsView);
+ dcStatsView.showStats();
+ dc.start();
+
+ final Uri uri = Uri.parse(dc.localUrl());
+ final MediaSource ms = buildMediaSource(uri, YOSPACE_MODE == Session.PlaybackMode.NONLINEARSTARTOVER ? true : null);
+ ms.addEventListener(mMainHandler, adapter);
+
+ newPlayer.prepare(new LoopingMediaSource(ms), true, false);
+
+ player = newPlayer;
+ exoPlayerView.setPlayer(newPlayer);
+ }
+ });
+ }
+ }
+
+ private void releasePlayer() {
+ if (player != null) {
+ player.release();
+ player = null;
+ }
+ stopDeliveryClient();
+
+ if (yoBridge.mSession != null)
+ {
+ yoBridge.mSession.shutdown();
+ yoBridge.mSession = null;
+ }
+ }
+
+ @SuppressLint("SwitchIntDef")
+ /**
+ * Quick solution but isHls should be replaced with an enum
+ */
+ private MediaSource buildMediaSource(Uri uri, Boolean isHls) {
+ final DefaultHttpDataSourceFactory defaultDataSourceFactory = new DefaultHttpDataSourceFactory(
+ Util.getUserAgent(getApplicationContext(), "StreamrootQA"),
+ DefaultHttpDataSource.DEFAULT_CONNECT_TIMEOUT_MILLIS,
+ DefaultHttpDataSource.DEFAULT_READ_TIMEOUT_MILLIS,
+ true
+ );
+
+ int type = Util.inferContentType(uri);
+ if ((isHls != null && isHls) || type == C.TYPE_HLS) {
+ return new HlsMediaSource.Factory(defaultDataSourceFactory)
+ //.setDrmSessionManager()
+ .createMediaSource(uri);
+ } else if (type == C.TYPE_DASH) {
+ return new DashMediaSource.Factory(
+ new DefaultDashChunkSource.Factory(
+ defaultDataSourceFactory
+ ), defaultDataSourceFactory
+ )
+ //.setDrmSessionManager()
+ .createMediaSource(uri);
+ } else {
+ throw new IllegalStateException("Unsupported type for url: $uri");
+ }
+ }
+
+ private LumenDeliveryClient initDeliveryClient(
+ final LumenPlayerInteractorBase playerInteractor,
+ final String playerUrl
+ ) {
+ return LumenDeliveryClient.orchestratorBuilder(getApplicationContext())
+ .playerInteractor(playerInteractor)
+ .options(new Function1() {
+ @Override
+ public Unit invoke(LumenOptionalOrchestratorBuilder o) {
+ o.logLevel(LumenLogLevel.TRACE);
+ if (mDCKey != null) o.deliveryClientKey(mDCKey);
+ if (mOrchProperty != null) o.orchestratorProperty(mOrchProperty);
+
+ return null;
+ }
+ }).build(playerUrl);
+ }
+
+ private void stopDeliveryClient() {
+ if (deliveryClient != null) {
+ deliveryClient.terminate();
+ deliveryClient = null;
+ }
+ }
+
+ /**
+ * Utils
+ */
+
+ private void showToast(String message) {
+ Toast.makeText(getApplicationContext(), message, Toast.LENGTH_LONG).show();
+ }
+
+ /**
+ * Player EventListener
+ */
+
+ @Override
+ public void onPlayerError(ExoPlaybackException error) {
+ @Nullable String errorString = null;
+ if (error.type == ExoPlaybackException.TYPE_RENDERER) {
+ final Exception cause = error.getRendererException();
+ if (cause instanceof MediaCodecRenderer.DecoderInitializationException) {
+ final MediaCodecRenderer.DecoderInitializationException castedCause =
+ (MediaCodecRenderer.DecoderInitializationException) cause;
+ // Special case for decoder initialization failures.
+ final MediaCodecInfo codecInfo = castedCause.codecInfo;
+
+ if (codecInfo != null) {
+ errorString = getString(
+ R.string.error_instantiating_decoder,
+ codecInfo.name
+ );
+ } else if (castedCause.getCause() instanceof MediaCodecUtil.DecoderQueryException) {
+ errorString = getString(R.string.error_querying_decoders);
+ } else if (castedCause.secureDecoderRequired) {
+ errorString = getString(
+ R.string.error_no_secure_decoder,
+ castedCause.mimeType);
+ } else {
+ errorString = getString(R.string.error_no_decoder, castedCause.mimeType);
+ }
+ }
+ }
+
+ if (errorString != null) {
+ showToast(errorString);
+ }
+ }
+
+ ///////////////////////////////////////
+ // AnalyticEventListener implementation
+
+ @Override
+ public void onAdvertBreakEnd(AdBreak adBreak) {
+ showToast("Adbreak end");
+ }
+
+ @Override
+ public void onAdvertBreakStart(AdBreak adBreak) {
+ showToast("Adbreak start");
+ }
+
+ @Override
+ public void onAdvertEnd(final Advert advert)
+ {
+ showToast("Adbreak end");
+ }
+
+ @Override
+ public void onAdvertStart(final Advert advert)
+ {
+ showToast(advert.getId() + ":0");
+ }
+
+ @Override
+ public void onTimelineUpdateReceived(VmapPayload vmap) { /* do nothing */ }
+
+ @Override
+ public void onVastReceived(VastPayload vast) {
+ showToast("VAST received");
+ }
+
+ @Override
+ public void onTrackingUrlCalled(final Advert advert, final String type, String url)
+ {
+ String quartile = type.equals("firstQuartile") ? ":1" : null;
+ quartile = type.equals("midpoint") ? ":2" : quartile;
+ quartile = type.equals("thirdQuartile") ? ":3" : quartile;
+
+ if (quartile != null) {
+ showToast(advert.getId() + quartile);
+ }
+ }
+}
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/SRApplication.java b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/SRApplication.java
new file mode 100644
index 00000000..e934d815
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/SRApplication.java
@@ -0,0 +1,13 @@
+package io.streamroot.lumen.delivery.client.samples.orchestrator.exoplayer;
+
+import androidx.multidex.MultiDexApplication;
+
+import io.streamroot.lumen.delivery.client.core.LumenDeliveryClient;
+
+public final class SRApplication extends MultiDexApplication {
+ @Override
+ public void onCreate() {
+ super.onCreate();
+ LumenDeliveryClient.initializeApp(this);
+ }
+}
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/YospaceModule.java b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/YospaceModule.java
new file mode 100644
index 00000000..a8ff9df1
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/YospaceModule.java
@@ -0,0 +1,341 @@
+package io.streamroot.lumen.delivery.client.samples.orchestrator.exoplayer;
+
+import android.app.Activity;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
+
+import io.streamroot.lumen.delivery.client.samples.orchestrator.exoplayer.common.Constant;
+import io.streamroot.lumen.delivery.client.samples.orchestrator.exoplayer.common.PlayerAdapter;
+import io.streamroot.lumen.delivery.client.samples.orchestrator.exoplayer.common.PlayerAdapterLive;
+import io.streamroot.lumen.delivery.client.samples.orchestrator.exoplayer.common.PlayerPolicyImpl;
+
+import com.yospace.android.hls.analytic.AnalyticEventListener;
+import com.yospace.android.hls.analytic.Session;
+import com.yospace.android.hls.analytic.SessionFactory;
+import com.yospace.android.hls.analytic.SessionLive;
+import com.yospace.android.hls.analytic.SessionLivePause;
+import com.yospace.android.hls.analytic.SessionNonLinear;
+import com.yospace.android.hls.analytic.SessionNonLinearStartOver;
+import com.yospace.util.YoLog;
+import com.yospace.util.event.Event;
+import com.yospace.util.event.EventListener;
+
+import static com.yospace.android.hls.analytic.Constant.NO_LIVEPAUSE;
+
+public class YospaceModule {
+
+ public interface YospaceModuleCallback {
+ void onSessionAvailable(Session session);
+ void onFinalUrlReady(PlayerAdapter adapter, String finalYospaceUrl);
+ }
+
+ public static class YospaceBridgeStruct {
+ public @Nullable Session mSession = null;
+ public @Nullable String mFinalYospaceUrl = null;
+ public @Nullable PlayerAdapter mAdapter = null;
+ }
+
+ public static void createAdapterAndSession(@NonNull final Activity a,
+ @NonNull final AnalyticEventListener analyticsObserver,
+ @NonNull final Session.PlaybackMode mode,
+ @NonNull final YospaceModuleCallback cb)
+ {
+ switch (mode) {
+ case LIVE:
+ PlayerAdapterLive adapterLive = new PlayerAdapterLive(a, null);
+ createLive(a, analyticsObserver, Constant.VIDEO_URL_LIVE, adapterLive, cb);
+ break;
+ case LIVEPAUSE:
+ adapterLive = new PlayerAdapterLive(a, null);
+ createLivePause(a, analyticsObserver, Constant.VIDEO_URL_LIVE_PAUSE, adapterLive, cb);
+ break;
+ case NONLINEAR:
+ PlayerAdapter adapter = new PlayerAdapter(a, null);
+ createNonLinear(a, analyticsObserver, Constant.VIDEO_URL_VOD, adapter, cb);
+ break;
+ case NONLINEARSTARTOVER:
+ adapter = new PlayerAdapter(a, null);
+ createNonLinearStartOver(a, analyticsObserver, Constant.VIDEO_URL_NLSO, adapter, cb);
+ break;
+ }
+ }
+
+ // Session url can be returned
+ private static void createLive(final Activity a,
+ final AnalyticEventListener analyticsObserver,
+ final String url,
+ final PlayerAdapterLive adapter,
+ @NonNull final YospaceModuleCallback cb) {
+ Log.i(Constant.getLogTag(), "PlayerLive.initialiseYospace - Initialise Yospace analytics");
+
+ Session.SessionProperties properties = new Session.SessionProperties(url).userAgent(Constant.USER_AGENT);
+
+ properties.addDebugFlags(YoLog.DEBUG_ALL);
+
+ final SessionFactory sf = SessionFactory.create(new EventListener() {
+
+ /**
+ * Callback made by SessionLive once it has initialised a session on the Yospace CSM
+ */
+ @Override
+ public void handle(Event event) {
+
+ // Retrieve the initialised session
+ final SessionLive mSession = (SessionLive) event.getPayload();
+
+ switch (mSession.getState()) {
+
+ case INITIALISED:
+ Log.i(Constant.getLogTag(), "PlayerLive.initialiseYospace - Yospace analytics session initialised");
+
+ adapter.setSession(mSession);
+
+ // Instantiate a LogAnalyticEventListener to make Analytic events visible in the log
+ mSession.addAnalyticListener(analyticsObserver);
+ mSession.setPlayerPolicy(new PlayerPolicyImpl());
+
+ a.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ cb.onSessionAvailable(mSession);
+ }
+ });
+
+ break;
+
+ case NO_ANALYTICS:
+ Log.i(Constant.getLogTag(),
+ "PlayerLive.initialiseYospace - No analytics session created, result code: "
+ + mSession.getResultCode());
+ break;
+
+ case NOT_INITIALISED:
+ Log.e(Constant.getLogTag(), "PlayerLive.initialiseYospace - Failed to initialise analytics session, result code: "
+ + mSession.getResultCode());
+ break;
+
+ default:
+ break;
+ }
+ }
+ }, properties, Session.PlaybackMode.LIVE);
+
+ a.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ cb.onFinalUrlReady(adapter, sf.getPlayerUrl());
+ }
+ });
+ }
+
+ // Session url can be returned
+ private static void createLivePause(final Activity a,
+ final AnalyticEventListener analyticsObserver,
+ final String url,
+ final PlayerAdapterLive adapter,
+ @NonNull final YospaceModuleCallback cb) {
+ Log.i(Constant.getLogTag(), "PlayerLivePause.initialiseYospace - Initialise Yospace analytics");
+
+ Session.SessionProperties properties = new Session.SessionProperties(url).userAgent(Constant.USER_AGENT);
+
+ properties.addDebugFlags(YoLog.DEBUG_PARSING | YoLog.DEBUG_POLLING | YoLog.DEBUG_HEARTBEAT_STATE);
+
+ final SessionFactory sf = SessionFactory.create(new EventListener() {
+
+ /**
+ * Callback made by SessionLivePause once it has initialised a session on the Yospace VoD-e service
+ */
+ @Override
+ public void handle(Event event) {
+
+ // Retrieve the session
+ final Session session = event.getPayload();
+
+ switch (session.getState()) {
+
+ case INITIALISED:
+ if (session.getResultCode() == NO_LIVEPAUSE)
+ {
+ Log.i(Constant.getLogTag(),
+ "PlayerLivePause.initialiseYospace - Video URL is not configured as a LivePause stream");
+
+ // In this case playback reverts to DAI Live and the session object is of type SessionLive.
+ // A customer application would handle this case in the same manner as shown in the
+ // PlayerLive.java sample file.
+ // Note that since the stream is Live, a timeline is unavailable in this case.
+
+ a.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ cb.onSessionAvailable(session);
+ }
+ });
+ }
+ else
+ {
+ Log.i(Constant.getLogTag(), "PlayerLivePause.initialiseYospace - Yospace analytics session initialised");
+
+ final SessionLivePause mSession = (SessionLivePause) event.getPayload();
+ adapter.setSession(mSession);
+
+ // Instantiate a UIAnalyticListener to make Analytic events visible in the log and to update the UI
+ mSession.addAnalyticListener(analyticsObserver);
+ mSession.setPlayerPolicy(new PlayerPolicyImpl());
+
+ a.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ cb.onSessionAvailable(mSession);
+ }
+ });
+ }
+ break;
+
+ case NO_ANALYTICS:
+ Log.i(Constant.getLogTag(),
+ "PlayerLivePause.initialiseYospace - Video URL does not refer to a Yospace stream, no analytics session created");
+ break;
+
+ case NOT_INITIALISED:
+ Log.e(Constant.getLogTag(), "PlayerLivePause.initialiseYospace - Failed to initialise analytics session");
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ }, properties, Session.PlaybackMode.LIVEPAUSE);
+
+ a.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ cb.onFinalUrlReady(adapter, sf.getPlayerUrl());
+ }
+ });
+ }
+
+ private static void createNonLinear(final Activity a,
+ final AnalyticEventListener analyticsObserver,
+ final String url,
+ final PlayerAdapter adapter,
+ @NonNull final YospaceModuleCallback cb) {
+ Log.i(Constant.getLogTag(), "PlayerNonLinear.initialiseYospace - Initialise Yospace analytics");
+
+ Session.SessionProperties properties = new Session.SessionProperties(url).userAgent(Constant.USER_AGENT);
+
+ properties.addDebugFlags(YoLog.DEBUG_PARSING | YoLog.DEBUG_POLLING | YoLog.DEBUG_HEARTBEAT_STATE);
+
+ SessionNonLinear.create(new EventListener() {
+
+ /**
+ * Callback made by SessionNonLinear once it has initialised a session on the Yospace VoD-e service
+ */
+ @Override
+ public void handle(Event event) {
+
+ // Retrieve the initialised session
+ final SessionNonLinear mSession = (SessionNonLinear) event.getPayload();
+
+ switch (mSession.getState()) {
+
+ case INITIALISED:
+ Log.i(Constant.getLogTag(), "PlayerNonLinear.initialiseYospace - Yospace analytics session initialised");
+
+ adapter.setSession(mSession);
+
+ // Instantiate a LogAnalyticEventListener to make Analytic events visible in the log
+ mSession.addAnalyticListener(analyticsObserver);
+ mSession.setPlayerPolicy(new PlayerPolicyImpl());
+
+ a.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ cb.onSessionAvailable(mSession);
+ cb.onFinalUrlReady(adapter, mSession.getPlayerUrl());
+ }
+ });
+ break;
+
+ case NO_ANALYTICS:
+ Log.i(Constant.getLogTag(),
+ "PlayerNonLinear.initialiseYospace - Video URL does not refer to a Yospace stream, no analytics session created");
+ break;
+
+ case NOT_INITIALISED:
+ Log.e(Constant.getLogTag(), "PlayerNonLinear.initialiseYospace - Failed to initialise analytics session");
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ }, properties);
+ }
+
+ private static void createNonLinearStartOver(final Activity a,
+ final AnalyticEventListener analyticsObserver,
+ final String url,
+ final PlayerAdapter adapter,
+ @NonNull final YospaceModuleCallback cb) {
+ Log.i(Constant.getLogTag(), "PlayerNonLinearStartOver.initialiseYospace - Initialise Yospace analytics");
+
+ Session.SessionProperties properties = new Session.SessionProperties(url).userAgent(Constant.USER_AGENT);
+
+ properties.addDebugFlags(YoLog.DEBUG_PARSING | YoLog.DEBUG_POLLING | YoLog.DEBUG_HEARTBEAT_STATE);
+
+ SessionNonLinearStartOver.create(new EventListener() {
+
+ /**
+ * Callback made by SessionNonLinear once it has initialised a session on the Yospace VoD-e service
+ */
+ @Override
+ public void handle(Event event) {
+
+ // Retrieve the initialised session
+ final SessionNonLinearStartOver mSession = (SessionNonLinearStartOver) event.getPayload();
+
+ switch (mSession.getState()) {
+
+ case INITIALISED:
+ Log.i(Constant.getLogTag(), "PlayerNonLinearStartOver.initYo - Yospace analytics session initialised");
+
+ adapter.setSession(mSession);
+
+ // Instantiate a LogAnalyticEventListener to make Analytic events visible in the log
+ mSession.addAnalyticListener(analyticsObserver);
+ mSession.setPlayerPolicy(new PlayerPolicyImpl());
+
+ a.runOnUiThread(new Runnable() {
+ @Override
+ public void run() {
+ cb.onSessionAvailable(mSession);
+ cb.onFinalUrlReady(adapter, mSession.getPlayerUrl());
+ }
+ });
+
+ break;
+
+ case NO_ANALYTICS:
+ Log.i(Constant.getLogTag(),
+ "PlayerNonLinearStartOver.initYo - Video URL does not refer to a Yospace stream, no analytics session created");
+ break;
+
+ case NOT_INITIALISED:
+ Log.e(Constant.getLogTag(), "PlayerNonLinearStartOver.initYo - Failed to initialise analytics session");
+ break;
+
+ default:
+ break;
+ }
+
+ }
+
+ }, properties);
+ }
+}
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/common b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/common
new file mode 120000
index 00000000..54225569
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/java/io/streamroot/lumen/delivery/client/samples/orchestrator/exoplayer/common
@@ -0,0 +1 @@
+../../../../../../../../../../../../ssp/exoplayer-yospace/common
\ No newline at end of file
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
new file mode 100644
index 00000000..c7bd21db
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/drawable-v24/ic_launcher_foreground.xml
@@ -0,0 +1,34 @@
+
+
+
+
+
+
+
+
+
+
+
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/drawable/ic_launcher_background.xml b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/drawable/ic_launcher_background.xml
new file mode 100644
index 00000000..d5fccc53
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/drawable/ic_launcher_background.xml
@@ -0,0 +1,170 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/drawable/streamroot_logo.png b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/drawable/streamroot_logo.png
new file mode 100644
index 00000000..33cc7499
Binary files /dev/null and b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/drawable/streamroot_logo.png differ
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/layout/activity_main.xml b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 00000000..a2164e27
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,122 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/layout/activity_player.xml b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/layout/activity_player.xml
new file mode 100644
index 00000000..c7c5f730
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/layout/activity_player.xml
@@ -0,0 +1,11 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/layout/content_player.xml b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/layout/content_player.xml
new file mode 100644
index 00000000..8e94768a
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/layout/content_player.xml
@@ -0,0 +1,35 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
new file mode 100644
index 00000000..eca70cfe
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
new file mode 100644
index 00000000..eca70cfe
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml
@@ -0,0 +1,5 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-hdpi/ic_launcher.png b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-hdpi/ic_launcher.png
new file mode 100644
index 00000000..a2f59082
Binary files /dev/null and b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-hdpi/ic_launcher.png differ
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-hdpi/ic_launcher_round.png
new file mode 100644
index 00000000..1b523998
Binary files /dev/null and b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-mdpi/ic_launcher.png b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-mdpi/ic_launcher.png
new file mode 100644
index 00000000..ff10afd6
Binary files /dev/null and b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-mdpi/ic_launcher.png differ
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-mdpi/ic_launcher_round.png
new file mode 100644
index 00000000..115a4c76
Binary files /dev/null and b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xhdpi/ic_launcher.png
new file mode 100644
index 00000000..dcd3cd80
Binary files /dev/null and b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..459ca609
Binary files /dev/null and b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xxhdpi/ic_launcher.png
new file mode 100644
index 00000000..8ca12fe0
Binary files /dev/null and b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..8e19b410
Binary files /dev/null and b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png
new file mode 100644
index 00000000..b824ebdd
Binary files /dev/null and b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png
new file mode 100644
index 00000000..4c19a13c
Binary files /dev/null and b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/values/colors.xml b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/values/colors.xml
new file mode 100644
index 00000000..3ab3e9cb
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@
+
+
+ #3F51B5
+ #303F9F
+ #FF4081
+
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/values/dimens.xml b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/values/dimens.xml
new file mode 100644
index 00000000..59a0b0c4
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/values/dimens.xml
@@ -0,0 +1,3 @@
+
+ 16dp
+
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/values/strings.xml b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/values/strings.xml
new file mode 100644
index 00000000..373e64f5
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/values/strings.xml
@@ -0,0 +1,36 @@
+
+ Orchestrator ExoPlayer Sample Java
+ PlayerActivity
+ Logo
+ Delivery client Key / Streamroot key
+ Enter your Delivery Client Key
+ Stream URL
+ Enter your stream URL
+ Orchestrator property
+ Enter orchestrator property
+ Enable Youbora ?
+ Enter your Youbora account
+ Launch demo
+
+ Media includes video tracks, but none are playable by
+ this device
+
+ Media includes audio tracks, but none are playable by
+ this device
+
+ Unable to instantiate decoder
+ %1$s
+
+ This device does not provide a decoder for
+ %1$s
+
+ This device does not provide a secure decoder for
+ %1$s
+
+ Unable to query device decoders
+
+ demoswebsiteandpartners
+ classic
+ http://wowza-test.streamroot.io/liveOrigin/BBB-bl-1500/playlist.m3u8
+
+
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/values/styles.xml b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/values/styles.xml
new file mode 100644
index 00000000..545b9c6d
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/xml/network_security_config.xml b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/xml/network_security_config.xml
new file mode 100644
index 00000000..bb6ab93d
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/app/src/main/res/xml/network_security_config.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/build.gradle b/orchestrator/android/ExoPlayer-Yospace-Java/build.gradle
new file mode 100644
index 00000000..fd36d22f
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/build.gradle
@@ -0,0 +1,26 @@
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
+
+buildscript {
+ repositories {
+ google()
+ jcenter()
+ }
+ dependencies {
+ classpath 'com.android.tools.build:gradle:3.4.1'
+
+ // NOTE: Do not place your application dependencies here; they belong
+ // in the individual module build.gradle files
+ }
+}
+
+allprojects {
+ repositories {
+ google()
+ jcenter()
+ maven { url 'https://sdk.streamroot.io/android' }
+ }
+}
+
+task clean(type: Delete) {
+ delete rootProject.buildDir
+}
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/gradle.properties b/orchestrator/android/ExoPlayer-Yospace-Java/gradle.properties
new file mode 100644
index 00000000..8de50581
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/gradle.properties
@@ -0,0 +1,15 @@
+# Project-wide Gradle settings.
+# IDE (e.g. Android Studio) users:
+# Gradle settings configured through the IDE *will override*
+# any settings specified in this file.
+# For more details on how to configure your build environment visit
+# http://www.gradle.org/docs/current/userguide/build_environment.html
+# Specifies the JVM arguments used for the daemon process.
+# The setting is particularly useful for tweaking memory settings.
+android.enableJetifier=true
+android.useAndroidX=true
+org.gradle.jvmargs=-Xmx1536m
+# When configured, Gradle will run in incubating parallel mode.
+# This option should only be used with decoupled projects. More details, visit
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
+# org.gradle.parallel=true
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/gradle/wrapper/gradle-wrapper.jar b/orchestrator/android/ExoPlayer-Yospace-Java/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 00000000..7a3265ee
Binary files /dev/null and b/orchestrator/android/ExoPlayer-Yospace-Java/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/gradle/wrapper/gradle-wrapper.properties b/orchestrator/android/ExoPlayer-Yospace-Java/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 00000000..9c843a4f
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@
+#Tue May 14 17:46:09 CEST 2019
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.5-all.zip
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/gradlew b/orchestrator/android/ExoPlayer-Yospace-Java/gradlew
new file mode 100755
index 00000000..cccdd3d5
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/gradlew
@@ -0,0 +1,172 @@
+#!/usr/bin/env sh
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS=""
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin, switch paths to Windows format before running java
+if $cygwin ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=$((i+1))
+ done
+ case $i in
+ (0) set -- ;;
+ (1) set -- "$args0" ;;
+ (2) set -- "$args0" "$args1" ;;
+ (3) set -- "$args0" "$args1" "$args2" ;;
+ (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=$(save "$@")
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
+if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
+ cd "$(dirname "$0")"
+fi
+
+exec "$JAVACMD" "$@"
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/gradlew.bat b/orchestrator/android/ExoPlayer-Yospace-Java/gradlew.bat
new file mode 100644
index 00000000..e95643d6
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/gradlew.bat
@@ -0,0 +1,84 @@
+@if "%DEBUG%" == "" @echo off
+@rem ##########################################################################
+@rem
+@rem Gradle startup script for Windows
+@rem
+@rem ##########################################################################
+
+@rem Set local scope for the variables with windows NT shell
+if "%OS%"=="Windows_NT" setlocal
+
+set DIRNAME=%~dp0
+if "%DIRNAME%" == "" set DIRNAME=.
+set APP_BASE_NAME=%~n0
+set APP_HOME=%DIRNAME%
+
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+set DEFAULT_JVM_OPTS=
+
+@rem Find java.exe
+if defined JAVA_HOME goto findJavaFromJavaHome
+
+set JAVA_EXE=java.exe
+%JAVA_EXE% -version >NUL 2>&1
+if "%ERRORLEVEL%" == "0" goto init
+
+echo.
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:findJavaFromJavaHome
+set JAVA_HOME=%JAVA_HOME:"=%
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
+
+if exist "%JAVA_EXE%" goto init
+
+echo.
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
+echo.
+echo Please set the JAVA_HOME variable in your environment to match the
+echo location of your Java installation.
+
+goto fail
+
+:init
+@rem Get command-line arguments, handling Windows variants
+
+if not "%OS%" == "Windows_NT" goto win9xME_args
+
+:win9xME_args
+@rem Slurp the command line arguments.
+set CMD_LINE_ARGS=
+set _SKIP=2
+
+:win9xME_args_slurp
+if "x%~1" == "x" goto execute
+
+set CMD_LINE_ARGS=%*
+
+:execute
+@rem Setup the command line
+
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
+
+@rem Execute Gradle
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
+
+:end
+@rem End local scope for the variables with windows NT shell
+if "%ERRORLEVEL%"=="0" goto mainEnd
+
+:fail
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
+rem the _cmd.exe /c_ return code!
+if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
+exit /b 1
+
+:mainEnd
+if "%OS%"=="Windows_NT" endlocal
+
+:omega
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/settings.gradle b/orchestrator/android/ExoPlayer-Yospace-Java/settings.gradle
new file mode 100644
index 00000000..e7b4def4
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/settings.gradle
@@ -0,0 +1 @@
+include ':app'
diff --git a/orchestrator/android/ExoPlayer-Yospace-Java/ssp b/orchestrator/android/ExoPlayer-Yospace-Java/ssp
new file mode 160000
index 00000000..66fda7db
--- /dev/null
+++ b/orchestrator/android/ExoPlayer-Yospace-Java/ssp
@@ -0,0 +1 @@
+Subproject commit 66fda7db0f54d5253728544d3dd7cfb465d23f06