diff --git a/demo/src/main/AndroidManifest.xml b/demo/src/main/AndroidManifest.xml
index 0c54dadcbf4..d3293adcd5c 100644
--- a/demo/src/main/AndroidManifest.xml
+++ b/demo/src/main/AndroidManifest.xml
@@ -66,6 +66,10 @@
+
+
+
+
diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java b/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java
index dbbd5694ad9..6ca6c0d3ecc 100644
--- a/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java
+++ b/demo/src/main/java/com/google/android/exoplayer/demo/PlayerActivity.java
@@ -25,27 +25,19 @@
import com.google.android.exoplayer.ExoPlayerFactory;
import com.google.android.exoplayer.MediaCodecTrackRenderer.DecoderInitializationException;
import com.google.android.exoplayer.MediaCodecUtil.DecoderQueryException;
-import com.google.android.exoplayer.SampleSource;
import com.google.android.exoplayer.SimpleExoPlayer;
import com.google.android.exoplayer.TrackGroupArray;
-import com.google.android.exoplayer.dash.DashSampleSource;
import com.google.android.exoplayer.drm.DrmSessionManager;
import com.google.android.exoplayer.drm.StreamingDrmSessionManager;
import com.google.android.exoplayer.drm.UnsupportedDrmException;
-import com.google.android.exoplayer.extractor.ExtractorSampleSource;
-import com.google.android.exoplayer.hls.HlsSampleSource;
import com.google.android.exoplayer.metadata.id3.GeobFrame;
import com.google.android.exoplayer.metadata.id3.Id3Frame;
import com.google.android.exoplayer.metadata.id3.PrivFrame;
import com.google.android.exoplayer.metadata.id3.TxxxFrame;
-import com.google.android.exoplayer.smoothstreaming.SmoothStreamingSampleSource;
import com.google.android.exoplayer.text.CaptionStyleCompat;
import com.google.android.exoplayer.text.Cue;
import com.google.android.exoplayer.text.SubtitleLayout;
-import com.google.android.exoplayer.upstream.Allocator;
-import com.google.android.exoplayer.upstream.DataSource;
import com.google.android.exoplayer.upstream.DataSourceFactory;
-import com.google.android.exoplayer.upstream.DefaultAllocator;
import com.google.android.exoplayer.upstream.DefaultDataSourceFactory;
import com.google.android.exoplayer.util.DebugTextViewHelper;
import com.google.android.exoplayer.util.PlayerControl;
@@ -60,7 +52,6 @@
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
-import android.text.TextUtils;
import android.util.Log;
import android.view.KeyEvent;
import android.view.MotionEvent;
@@ -99,7 +90,11 @@ public class PlayerActivity extends Activity implements SurfaceHolder.Callback,
public static final String USE_EXTENSION_DECODERS = "use_extension_decoders";
// For use when launching the demo app using adb.
+ public static final String ACTION_VIEW = "com.google.android.exoplayer.demo.action.VIEW";
+ private static final String ACTION_VIEW_LIST =
+ "com.google.android.exoplayer.demo.action.VIEW_LIST";
private static final String CONTENT_EXT_EXTRA = "type";
+ private static final String URIS_LIST_EXTRA = "uris";
private static final String TAG = "PlayerActivity";
@@ -246,40 +241,10 @@ public void onRequestPermissionsResult(int requestCode, String[] permissions,
}
}
- // Permission management methods
-
- /**
- * Checks whether it is necessary to ask for permission to read storage. If necessary, it also
- * requests permission.
- *
- * @param uri A URI that may require {@link permission#READ_EXTERNAL_STORAGE} to play.
- * @return True if a permission request is made. False if it is not necessary.
- */
- @TargetApi(23)
- private boolean maybeRequestPermission(Uri uri) {
- if (requiresPermission(uri)) {
- requestPermissions(new String[] {permission.READ_EXTERNAL_STORAGE}, 0);
- return true;
- } else {
- return false;
- }
- }
-
- @TargetApi(23)
- private boolean requiresPermission(Uri uri) {
- return Util.SDK_INT >= 23
- && Util.isLocalFileUri(uri)
- && checkSelfPermission(permission.READ_EXTERNAL_STORAGE)
- != PackageManager.PERMISSION_GRANTED;
- }
-
// Internal methods
private void initializePlayer() {
Intent intent = getIntent();
- Uri uri = intent.getData();
- int type = intent.getIntExtra(CONTENT_TYPE_EXTRA,
- inferContentType(uri, intent.getStringExtra(CONTENT_EXT_EXTRA)));
if (player == null) {
boolean useExtensionDecoders = intent.getBooleanExtra(USE_EXTENSION_DECODERS, false);
UUID drmSchemeUuid = (UUID) intent.getSerializableExtra(DRM_SCHEME_UUID_EXTRA);
@@ -318,11 +283,31 @@ private void initializePlayer() {
playerNeedsSource = true;
}
if (playerNeedsSource) {
- if (maybeRequestPermission(uri)) {
+ String action = intent.getAction();
+ Uri[] uris;
+ UriSampleSourceProvider sourceProvider;
+ if (ACTION_VIEW.equals(action)) {
+ uris = new Uri[] {intent.getData()};
+ sourceProvider = new UriSampleSourceProvider(player, dataSourceFactory, intent.getData(),
+ intent.getIntExtra(CONTENT_TYPE_EXTRA, UriSampleSourceProvider.UNKNOWN_TYPE),
+ intent.getStringExtra(CONTENT_EXT_EXTRA), mainHandler, eventLogger);
+ } else if (ACTION_VIEW_LIST.equals(action)) {
+ String[] uriStrings = intent.getStringArrayExtra(URIS_LIST_EXTRA);
+ uris = new Uri[uriStrings.length];
+ for (int i = 0; i < uriStrings.length; i++) {
+ uris[i] = Uri.parse(uriStrings[i]);
+ }
+ sourceProvider = new UriSampleSourceProvider(player, dataSourceFactory, uris, mainHandler,
+ eventLogger);
+ } else {
+ Log.w(TAG, "Unexpected intent action: " + action);
+ return;
+ }
+ if (maybeRequestPermission(uris)) {
// The player will be reinitialized if permission is granted.
return;
}
- player.setSource(buildSource(type, uri));
+ player.setSourceProvider(sourceProvider);
playerNeedsSource = false;
updateButtonVisibilities();
}
@@ -351,25 +336,28 @@ private void onUnsupportedDrmError(UnsupportedDrmException e) {
Toast.makeText(getApplicationContext(), errorString, Toast.LENGTH_LONG).show();
}
- private SampleSource buildSource(int type, Uri uri) {
- switch (type) {
- case Util.TYPE_SS:
- return new SmoothStreamingSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(),
- mainHandler, eventLogger);
- case Util.TYPE_DASH:
- return new DashSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(), mainHandler,
- eventLogger);
- case Util.TYPE_HLS:
- return new HlsSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(), mainHandler,
- eventLogger);
- case Util.TYPE_OTHER:
- Allocator allocator = new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE);
- DataSource dataSource = dataSourceFactory.createDataSource(player.getBandwidthMeter());
- return new ExtractorSampleSource(uri, dataSource, allocator, C.DEFAULT_MUXED_BUFFER_SIZE,
- mainHandler, eventLogger, 0, ExtractorSampleSource.newDefaultExtractors());
- default:
- throw new IllegalStateException("Unsupported type: " + type);
+ /**
+ * Checks whether it is necessary to ask for permission to read storage. If necessary, it also
+ * requests permission.
+ *
+ * @param uris URIs that may require {@link permission#READ_EXTERNAL_STORAGE} to play.
+ * @return True if a permission request is made. False if it is not necessary.
+ */
+ @TargetApi(23)
+ private boolean maybeRequestPermission(Uri... uris) {
+ if (Util.SDK_INT >= 23) {
+ for (Uri uri : uris) {
+ if (Util.isLocalFileUri(uri)) {
+ if (checkSelfPermission(permission.READ_EXTERNAL_STORAGE)
+ != PackageManager.PERMISSION_GRANTED) {
+ requestPermissions(new String[] {permission.READ_EXTERNAL_STORAGE}, 0);
+ return true;
+ }
+ break;
+ }
+ }
}
+ return false;
}
private void releasePlayer() {
@@ -585,20 +573,6 @@ private CaptionStyleCompat getUserCaptionStyleV19() {
return CaptionStyleCompat.createFromCaptionStyle(captioningManager.getUserStyle());
}
- /**
- * Makes a best guess to infer the type from a media {@link Uri} and an optional overriding file
- * extension.
- *
- * @param uri The {@link Uri} of the media.
- * @param fileExtension An overriding file extension.
- * @return The inferred type.
- */
- private static int inferContentType(Uri uri, String fileExtension) {
- String lastPathSegment = !TextUtils.isEmpty(fileExtension) ? "." + fileExtension
- : uri.getLastPathSegment();
- return Util.inferContentType(lastPathSegment);
- }
-
private static final class KeyCompatibleMediaController extends MediaController {
private MediaController.MediaPlayerControl playerControl;
diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/SampleChooserActivity.java b/demo/src/main/java/com/google/android/exoplayer/demo/SampleChooserActivity.java
index 3b747762448..4c4f637e63e 100644
--- a/demo/src/main/java/com/google/android/exoplayer/demo/SampleChooserActivity.java
+++ b/demo/src/main/java/com/google/android/exoplayer/demo/SampleChooserActivity.java
@@ -91,6 +91,7 @@ public boolean onChildClick(ExpandableListView parent, View view, int groupPosit
private void onSampleSelected(Sample sample) {
Intent intent = new Intent(this, PlayerActivity.class)
+ .setAction(PlayerActivity.ACTION_VIEW)
.setData(Uri.parse(sample.uri))
.putExtra(PlayerActivity.CONTENT_TYPE_EXTRA, sample.type)
.putExtra(PlayerActivity.DRM_SCHEME_UUID_EXTRA, sample.drmSchemeUuid)
diff --git a/demo/src/main/java/com/google/android/exoplayer/demo/UriSampleSourceProvider.java b/demo/src/main/java/com/google/android/exoplayer/demo/UriSampleSourceProvider.java
new file mode 100644
index 00000000000..51037917ae4
--- /dev/null
+++ b/demo/src/main/java/com/google/android/exoplayer/demo/UriSampleSourceProvider.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.exoplayer.demo;
+
+import com.google.android.exoplayer.C;
+import com.google.android.exoplayer.SampleSource;
+import com.google.android.exoplayer.SampleSourceProvider;
+import com.google.android.exoplayer.SimpleExoPlayer;
+import com.google.android.exoplayer.dash.DashSampleSource;
+import com.google.android.exoplayer.extractor.ExtractorSampleSource;
+import com.google.android.exoplayer.hls.HlsSampleSource;
+import com.google.android.exoplayer.smoothstreaming.SmoothStreamingSampleSource;
+import com.google.android.exoplayer.upstream.Allocator;
+import com.google.android.exoplayer.upstream.DataSource;
+import com.google.android.exoplayer.upstream.DataSourceFactory;
+import com.google.android.exoplayer.upstream.DefaultAllocator;
+import com.google.android.exoplayer.util.Util;
+
+import android.net.Uri;
+import android.os.Handler;
+import android.text.TextUtils;
+
+/**
+ * Provides {@link SampleSource}s to play back media loaded from one or more URI/URIs.
+ */
+public final class UriSampleSourceProvider implements SampleSourceProvider {
+
+ public static final int UNKNOWN_TYPE = -1;
+
+ private final SimpleExoPlayer player;
+ private final DataSourceFactory dataSourceFactory;
+ private final Uri[] uris;
+ private final String overrideExtension;
+ private final int type;
+ private final Handler handler;
+ private final EventLogger eventLogger;
+
+ /**
+ * Constructs a source provider for {@link SampleSource} to play back media at the specified
+ * URI, using the specified type.
+ *
+ * @param player The demo player, which will listen to source events.
+ * @param dataSourceFactory A data source factory.
+ * @param uri The URI to play back.
+ * @param type A {@code PlayerActivity.TYPE_*} constant specifying the type of the source, or
+ * {@link #UNKNOWN_TYPE}, in which case it is inferred from the URI's extension.
+ * @param overrideExtension An overriding file extension used when inferring the source's type,
+ * or {@code null}.
+ * @param handler A handler to use for logging events.
+ * @param eventLogger An event logger.
+ */
+ public UriSampleSourceProvider(SimpleExoPlayer player, DataSourceFactory dataSourceFactory,
+ Uri uri, int type, String overrideExtension, Handler handler, EventLogger eventLogger) {
+ this.player = player;
+ this.dataSourceFactory = dataSourceFactory;
+ this.overrideExtension = overrideExtension;
+ this.type = type;
+ this.handler = handler;
+ this.eventLogger = eventLogger;
+
+ uris = new Uri[] {uri};
+ }
+
+ /**
+ * Constructs a source provider for {@link SampleSource}s to play back media at one or more
+ * {@link Uri}s. The content type of each URI is inferred based on its last path segment.
+ *
+ * @param player The demo player, which will listen to source events.
+ * @param dataSourceFactory A data source factory.
+ * @param uris The URIs to play back.
+ * @param handler A handler to use for logging events.
+ * @param eventLogger An event logger.
+ */
+ public UriSampleSourceProvider(SimpleExoPlayer player, DataSourceFactory dataSourceFactory,
+ Uri[] uris, Handler handler, EventLogger eventLogger) {
+ this.player = player;
+ this.dataSourceFactory = dataSourceFactory;
+ this.uris = uris;
+ this.handler = handler;
+ this.eventLogger = eventLogger;
+
+ overrideExtension = null;
+ type = UNKNOWN_TYPE;
+ }
+
+ @Override
+ public int getSourceCount() {
+ return uris.length;
+ }
+
+ @Override
+ public SampleSource createSource(int index) {
+ Uri uri = uris[index];
+ int type = this.type == UNKNOWN_TYPE ? inferContentType(uri, overrideExtension) : this.type;
+ switch (type) {
+ case Util.TYPE_SS:
+ return new SmoothStreamingSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(),
+ handler, eventLogger);
+ case Util.TYPE_DASH:
+ return new DashSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(), handler,
+ eventLogger);
+ case Util.TYPE_HLS:
+ return new HlsSampleSource(uri, dataSourceFactory, player.getBandwidthMeter(), handler,
+ eventLogger);
+ case Util.TYPE_OTHER:
+ Allocator allocator = new DefaultAllocator(C.DEFAULT_BUFFER_SEGMENT_SIZE);
+ DataSource dataSource = dataSourceFactory.createDataSource(player.getBandwidthMeter());
+ return new ExtractorSampleSource(uri, dataSource, allocator, C.DEFAULT_MUXED_BUFFER_SIZE,
+ handler, eventLogger, 0, ExtractorSampleSource.newDefaultExtractors());
+ default:
+ throw new IllegalStateException("Unsupported type: " + type);
+ }
+ }
+
+ /**
+ * Makes a best guess to infer the type from a media {@link Uri} and an optional overriding file
+ * extension.
+ *
+ * @param uri The {@link Uri} of the media.
+ * @param fileExtension An overriding file extension.
+ * @return The inferred type.
+ */
+ private static int inferContentType(Uri uri, String fileExtension) {
+ String lastPathSegment = !TextUtils.isEmpty(fileExtension) ? "." + fileExtension
+ : uri.getLastPathSegment();
+ return Util.inferContentType(lastPathSegment);
+ }
+
+}
diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java
index f975a0db399..affb59a7640 100644
--- a/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java
+++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayer.java
@@ -84,7 +84,8 @@
*
*
The possible playback state transitions are shown below. Transitions can be triggered either
* by changes in the state of the {@link TrackRenderer}s being used, or as a result of
- * {@link #setSource(SampleSource)}, {@link #stop()} or {@link #release()} being invoked.
+ * {@link #setSource(SampleSource)}, {@link #setSourceProvider(SampleSourceProvider)},
+ * {@link #stop()} or {@link #release()} being invoked.
* ![ExoPlayer playback state transitions](../../../../../images/exoplayer_playbackstate.png)
@@ -225,6 +226,14 @@ public ExoPlayerMessage(ExoPlayerComponent target, int messageType, Object messa
*/
void setSource(SampleSource sampleSource);
+ /**
+ * Sets the player's source provider. The player will transition to {@link #STATE_BUFFERING} until
+ * it is ready to play the first source.
+ *
+ * @param sourceProvider The provider of {@link SampleSource}s to play.
+ */
+ void setSourceProvider(SampleSourceProvider sourceProvider);
+
/**
* Sets whether playback should proceed when {@link #getPlaybackState()} == {@link #STATE_READY}.
* If the player is already in this state, then this method can be used to pause and resume
diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java
index f8b2e486fe4..d98689d4264 100644
--- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java
+++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImpl.java
@@ -86,8 +86,13 @@ public int getPlaybackState() {
}
@Override
- public void setSource(SampleSource source) {
- internalPlayer.setSource(source);
+ public void setSource(final SampleSource sampleSource) {
+ internalPlayer.setSourceProvider(new SingleSampleSourceProvider(sampleSource));
+ }
+
+ @Override
+ public void setSourceProvider(SampleSourceProvider sourceProvider) {
+ internalPlayer.setSourceProvider(sourceProvider);
}
@Override
@@ -190,4 +195,25 @@ public int getBufferedPercentage() {
}
}
+ private static final class SingleSampleSourceProvider implements SampleSourceProvider {
+
+ private final SampleSource sampleSource;
+
+ public SingleSampleSourceProvider(SampleSource sampleSource) {
+ this.sampleSource = sampleSource;
+ }
+
+ @Override
+ public int getSourceCount() {
+ return 1;
+ }
+
+ @Override
+ public SampleSource createSource(int index) {
+ // The source will only be created once.
+ return sampleSource;
+ }
+
+ }
+
}
diff --git a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java
index 04635ec41f1..f609ad71912 100644
--- a/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java
+++ b/library/src/main/java/com/google/android/exoplayer/ExoPlayerImplInternal.java
@@ -48,7 +48,7 @@
public static final int MSG_ERROR = 3;
// Internal messages
- private static final int MSG_SET_SOURCE = 0;
+ private static final int MSG_SET_SOURCE_PROVIDER = 0;
private static final int MSG_SET_PLAY_WHEN_READY = 1;
private static final int MSG_DO_SOME_WORK = 2;
private static final int MSG_SEEK_TO = 3;
@@ -135,8 +135,8 @@ public long getDuration() {
return durationUs == C.UNSET_TIME_US ? ExoPlayer.UNKNOWN_TIME : durationUs / 1000;
}
- public void setSource(SampleSource sampleSource) {
- handler.obtainMessage(MSG_SET_SOURCE, sampleSource).sendToTarget();
+ public void setSourceProvider(SampleSourceProvider sourceProvider) {
+ handler.obtainMessage(MSG_SET_SOURCE_PROVIDER, sourceProvider).sendToTarget();
}
public void setPlayWhenReady(boolean playWhenReady) {
@@ -203,8 +203,8 @@ public void onTrackSelectionsInvalidated() {
public boolean handleMessage(Message msg) {
try {
switch (msg.what) {
- case MSG_SET_SOURCE: {
- setSourceInternal((SampleSource) msg.obj);
+ case MSG_SET_SOURCE_PROVIDER: {
+ setSourceProviderInternal((SampleSourceProvider) msg.obj);
return true;
}
case MSG_SET_PLAY_WHEN_READY: {
@@ -277,9 +277,10 @@ private boolean haveSufficientBuffer() {
|| (durationUs != C.UNSET_TIME_US && bufferedPositionUs >= durationUs);
}
- private void setSourceInternal(SampleSource source) {
+ private void setSourceProviderInternal(SampleSourceProvider sourceProvider) {
resetInternal();
- this.source = source;
+ // TODO[playlists]: Create and use sources after the first one.
+ this.source = sourceProvider.createSource(0);
setState(ExoPlayer.STATE_BUFFERING);
handler.sendEmptyMessage(MSG_DO_SOME_WORK);
}
diff --git a/library/src/main/java/com/google/android/exoplayer/SampleSourceProvider.java b/library/src/main/java/com/google/android/exoplayer/SampleSourceProvider.java
new file mode 100644
index 00000000000..5e2700fd950
--- /dev/null
+++ b/library/src/main/java/com/google/android/exoplayer/SampleSourceProvider.java
@@ -0,0 +1,46 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.android.exoplayer;
+
+// TODO[playlists]: Rename this and maybe change the interface once we support multi-period DASH.
+/**
+ * Provides a sequence of {@link SampleSource}s to play back.
+ */
+public interface SampleSourceProvider {
+
+ /**
+ * Returned by {@link #getSourceCount()} if the number of sources is not known.
+ */
+ int UNKNOWN_SOURCE_COUNT = -1;
+
+ /**
+ * Returns the number of sources in the sequence, or {@link #UNKNOWN_SOURCE_COUNT} if the number
+ * of sources is not yet known.
+ */
+ int getSourceCount();
+
+ /**
+ * Returns a new {@link SampleSource} providing media at the specified index in the sequence, or
+ * {@code null} if the source at the specified index is not yet available.
+ *
+ * @param index The index of the source to create, which must be less than the count returned by
+ * {@link #getSourceCount()}.
+ * @return A new {@link SampleSource}, or {@code null} if the source at the specified index is not
+ * yet available.
+ */
+ SampleSource createSource(int index);
+
+}
diff --git a/library/src/main/java/com/google/android/exoplayer/SimpleExoPlayer.java b/library/src/main/java/com/google/android/exoplayer/SimpleExoPlayer.java
index f9ab7f38a05..c635f9349ae 100644
--- a/library/src/main/java/com/google/android/exoplayer/SimpleExoPlayer.java
+++ b/library/src/main/java/com/google/android/exoplayer/SimpleExoPlayer.java
@@ -287,8 +287,13 @@ public int getPlaybackState() {
}
@Override
- public void setSource(SampleSource source) {
- player.setSource(source);
+ public void setSource(SampleSource sampleSource) {
+ player.setSource(sampleSource);
+ }
+
+ @Override
+ public void setSourceProvider(SampleSourceProvider sourceProvider) {
+ player.setSourceProvider(sourceProvider);
}
@Override