update exoplayer and implement custom media source factory
This commit is contained in:
parent
12443be2ce
commit
f584cff697
2 changed files with 85 additions and 67 deletions
|
|
@ -13,13 +13,9 @@ import com.dkanada.gramophone.util.PreferenceUtil;
|
||||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||||
import com.google.android.exoplayer2.ExoPlayer;
|
import com.google.android.exoplayer2.ExoPlayer;
|
||||||
import com.google.android.exoplayer2.MediaItem;
|
import com.google.android.exoplayer2.MediaItem;
|
||||||
import com.google.android.exoplayer2.Player;
|
|
||||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||||
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
|
import com.google.android.exoplayer2.database.ExoDatabaseProvider;
|
||||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
import com.google.android.exoplayer2.source.MediaSourceFactory;
|
||||||
import com.google.android.exoplayer2.source.MediaSource;
|
|
||||||
import com.google.android.exoplayer2.source.ProgressiveMediaSource;
|
|
||||||
import com.google.android.exoplayer2.source.hls.HlsMediaSource;
|
|
||||||
import com.google.android.exoplayer2.upstream.DataSource;
|
import com.google.android.exoplayer2.upstream.DataSource;
|
||||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||||
import com.google.android.exoplayer2.upstream.FileDataSource;
|
import com.google.android.exoplayer2.upstream.FileDataSource;
|
||||||
|
|
@ -29,27 +25,13 @@ import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvicto
|
||||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
import okhttp3.Call;
|
|
||||||
import okhttp3.Callback;
|
|
||||||
import okhttp3.Dispatcher;
|
|
||||||
import okhttp3.OkHttpClient;
|
|
||||||
import okhttp3.Request;
|
|
||||||
import okhttp3.Response;
|
|
||||||
import okhttp3.internal.annotations.EverythingIsNonNull;
|
|
||||||
|
|
||||||
public class MultiPlayer implements Playback {
|
public class MultiPlayer implements Playback {
|
||||||
public static final String TAG = MultiPlayer.class.getSimpleName();
|
public static final String TAG = MultiPlayer.class.getSimpleName();
|
||||||
|
|
||||||
private final Context context;
|
private final Context context;
|
||||||
private final OkHttpClient httpClient;
|
private final SimpleExoPlayer exoPlayer;
|
||||||
|
|
||||||
private SimpleExoPlayer exoPlayer;
|
|
||||||
private ConcatenatingMediaSource mediaSource;
|
|
||||||
|
|
||||||
private final SimpleCache simpleCache;
|
private final SimpleCache simpleCache;
|
||||||
private final DataSource.Factory dataSource;
|
|
||||||
|
|
||||||
private PlaybackCallbacks callbacks;
|
private PlaybackCallbacks callbacks;
|
||||||
|
|
||||||
|
|
@ -83,7 +65,7 @@ public class MultiPlayer implements Playback {
|
||||||
int windowIndex = exoPlayer.getCurrentWindowIndex();
|
int windowIndex = exoPlayer.getCurrentWindowIndex();
|
||||||
|
|
||||||
if (windowIndex == 1) {
|
if (windowIndex == 1) {
|
||||||
mediaSource.removeMediaSource(0);
|
exoPlayer.removeMediaItem(0);
|
||||||
if (exoPlayer.isPlaying()) {
|
if (exoPlayer.isPlaying()) {
|
||||||
// there are still songs left in the queue
|
// there are still songs left in the queue
|
||||||
callbacks.onTrackWentToNext();
|
callbacks.onTrackWentToNext();
|
||||||
|
|
@ -103,17 +85,11 @@ public class MultiPlayer implements Playback {
|
||||||
public MultiPlayer(Context context) {
|
public MultiPlayer(Context context) {
|
||||||
this.context = context;
|
this.context = context;
|
||||||
|
|
||||||
Dispatcher dispatcher = new Dispatcher();
|
MediaSourceFactory mediaSourceFactory = new UnknownMediaSourceFactory(buildDataSourceFactory());
|
||||||
dispatcher.setMaxRequests(1);
|
exoPlayer = new SimpleExoPlayer.Builder(context).setMediaSourceFactory(mediaSourceFactory).build();
|
||||||
|
|
||||||
httpClient = new OkHttpClient.Builder().dispatcher(dispatcher).build();
|
|
||||||
|
|
||||||
exoPlayer = new SimpleExoPlayer.Builder(context).build();
|
|
||||||
mediaSource = new ConcatenatingMediaSource();
|
|
||||||
|
|
||||||
exoPlayer.addListener(eventListener);
|
exoPlayer.addListener(eventListener);
|
||||||
exoPlayer.prepare(mediaSource);
|
exoPlayer.prepare();
|
||||||
exoPlayer.setRepeatMode(Player.REPEAT_MODE_OFF);
|
|
||||||
|
|
||||||
long cacheSize = PreferenceUtil.getInstance(context).getMediaCacheSize();
|
long cacheSize = PreferenceUtil.getInstance(context).getMediaCacheSize();
|
||||||
LeastRecentlyUsedCacheEvictor recentlyUsedCache = new LeastRecentlyUsedCacheEvictor(cacheSize);
|
LeastRecentlyUsedCacheEvictor recentlyUsedCache = new LeastRecentlyUsedCacheEvictor(cacheSize);
|
||||||
|
|
@ -121,23 +97,19 @@ public class MultiPlayer implements Playback {
|
||||||
|
|
||||||
File cacheDirectory = new File(context.getCacheDir(), "exoplayer");
|
File cacheDirectory = new File(context.getCacheDir(), "exoplayer");
|
||||||
simpleCache = new SimpleCache(cacheDirectory, recentlyUsedCache, databaseProvider);
|
simpleCache = new SimpleCache(cacheDirectory, recentlyUsedCache, databaseProvider);
|
||||||
dataSource = buildDataSourceFactory();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setDataSource(Song song) {
|
public void setDataSource(Song song) {
|
||||||
mediaSource = new ConcatenatingMediaSource();
|
exoPlayer.clearMediaItems();
|
||||||
|
|
||||||
exoPlayer.addListener(eventListener);
|
|
||||||
exoPlayer.prepare(mediaSource);
|
|
||||||
|
|
||||||
appendDataSource(MusicUtil.getSongFileUri(song));
|
appendDataSource(MusicUtil.getSongFileUri(song));
|
||||||
|
exoPlayer.seekTo(0, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void queueDataSource(Song song) {
|
public void queueDataSource(Song song) {
|
||||||
while (mediaSource.getSize() > 1) {
|
while (exoPlayer.getMediaItemCount() > 1) {
|
||||||
mediaSource.removeMediaSource(1);
|
exoPlayer.removeMediaItem(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
appendDataSource(MusicUtil.getSongFileUri(song));
|
appendDataSource(MusicUtil.getSongFileUri(song));
|
||||||
|
|
@ -145,36 +117,9 @@ public class MultiPlayer implements Playback {
|
||||||
|
|
||||||
private void appendDataSource(String path) {
|
private void appendDataSource(String path) {
|
||||||
Uri uri = Uri.parse(path);
|
Uri uri = Uri.parse(path);
|
||||||
|
MediaItem mediaItem = MediaItem.fromUri(uri);
|
||||||
|
|
||||||
httpClient.newCall(new Request.Builder().url(path).head().build()).enqueue(new Callback() {
|
exoPlayer.addMediaItem(mediaItem);
|
||||||
@Override
|
|
||||||
@EverythingIsNonNull
|
|
||||||
public void onFailure(Call call, IOException e) {
|
|
||||||
Toast.makeText(context, context.getResources().getString(R.string.unplayable_file), Toast.LENGTH_SHORT).show();
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
@EverythingIsNonNull
|
|
||||||
public void onResponse(Call call, Response response) {
|
|
||||||
String type = response.header("Content-Type");
|
|
||||||
if (type == null) return;
|
|
||||||
|
|
||||||
MediaSource source;
|
|
||||||
if (type.equals("application/x-mpegURL")) {
|
|
||||||
source = new HlsMediaSource.Factory(dataSource)
|
|
||||||
.setTag(path)
|
|
||||||
.setAllowChunklessPreparation(true)
|
|
||||||
.createMediaSource(uri);
|
|
||||||
} else {
|
|
||||||
source = new ProgressiveMediaSource.Factory(dataSource)
|
|
||||||
.setTag(path)
|
|
||||||
.createMediaSource(uri);
|
|
||||||
}
|
|
||||||
|
|
||||||
mediaSource.addMediaSource(source);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DataSource.Factory buildDataSourceFactory() {
|
private DataSource.Factory buildDataSourceFactory() {
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,73 @@
|
||||||
|
package com.dkanada.gramophone.service
|
||||||
|
|
||||||
|
import com.google.android.exoplayer2.MediaItem
|
||||||
|
import com.google.android.exoplayer2.drm.DrmSessionManager
|
||||||
|
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory
|
||||||
|
import com.google.android.exoplayer2.source.MediaSource
|
||||||
|
import com.google.android.exoplayer2.source.MediaSourceFactory
|
||||||
|
import com.google.android.exoplayer2.source.ProgressiveMediaSource
|
||||||
|
import com.google.android.exoplayer2.source.hls.HlsMediaSource
|
||||||
|
import com.google.android.exoplayer2.upstream.*
|
||||||
|
|
||||||
|
import kotlinx.coroutines.*
|
||||||
|
|
||||||
|
import java.net.HttpURLConnection
|
||||||
|
import java.net.URL
|
||||||
|
|
||||||
|
class UnknownMediaSourceFactory(dataSourceFactory: DataSource.Factory) : MediaSourceFactory {
|
||||||
|
private val hlsMediaSource : HlsMediaSource.Factory
|
||||||
|
private val progressiveMediaSource : ProgressiveMediaSource.Factory
|
||||||
|
|
||||||
|
private var loadErrorHandlingPolicy: LoadErrorHandlingPolicy
|
||||||
|
|
||||||
|
override fun setDrmSessionManager(drmSessionManager: DrmSessionManager?): MediaSourceFactory {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setDrmHttpDataSourceFactory(drmHttpDataSourceFactory: HttpDataSource.Factory?): MediaSourceFactory {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setDrmUserAgent(drmUserAgent: String?): MediaSourceFactory {
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun setLoadErrorHandlingPolicy(loadErrorHandlingPolicy: LoadErrorHandlingPolicy?): MediaSourceFactory {
|
||||||
|
this.loadErrorHandlingPolicy = loadErrorHandlingPolicy!!
|
||||||
|
return this
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getSupportedTypes(): IntArray {
|
||||||
|
return intArrayOf()
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun createMediaSource(mediaItem: MediaItem): MediaSource {
|
||||||
|
val type: String? = runBlocking {
|
||||||
|
httpGet(mediaItem.playbackProperties!!.uri.toString())
|
||||||
|
}
|
||||||
|
|
||||||
|
val sourceFactory: MediaSourceFactory = if (type == "application/x-mpegURL") {
|
||||||
|
hlsMediaSource
|
||||||
|
} else {
|
||||||
|
progressiveMediaSource
|
||||||
|
}
|
||||||
|
|
||||||
|
return sourceFactory.createMediaSource(mediaItem)
|
||||||
|
}
|
||||||
|
|
||||||
|
private suspend fun httpGet(url: String?): String? {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
val request = URL(url)
|
||||||
|
val conn = request.openConnection() as HttpURLConnection
|
||||||
|
|
||||||
|
return@withContext conn.getHeaderField("Content-Type")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
hlsMediaSource = HlsMediaSource.Factory(dataSourceFactory)
|
||||||
|
progressiveMediaSource = ProgressiveMediaSource.Factory(dataSourceFactory, DefaultExtractorsFactory())
|
||||||
|
|
||||||
|
loadErrorHandlingPolicy = DefaultLoadErrorHandlingPolicy()
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue