mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2026-04-19 13:21:22 +00:00
-Added wake and wifi lock to popup video player.
-Added seek time display to player binding activity. -Added button effect for all image buttons on player binding activity. -Added click to scroll to current selected on metadata layout for player binding activity. -Refactored player utilities and preference getters into PlayerHelper. -Refactored player caching into CacheFactory. -Refactored player audio related methods into AudioReactor. -Refactored player locks into LockManager. -Refactored player loading and buffering mechanics into LoadController. -Fixed outdated names for background player.
This commit is contained in:
@@ -26,10 +26,8 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.graphics.Bitmap;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.Build;
|
||||
import android.os.IBinder;
|
||||
import android.os.PowerManager;
|
||||
import android.support.annotation.IntRange;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.annotation.Nullable;
|
||||
@@ -48,10 +46,13 @@ import org.schabi.newpipe.extractor.MediaFormat;
|
||||
import org.schabi.newpipe.extractor.stream.AudioStream;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.player.event.PlayerEventListener;
|
||||
import org.schabi.newpipe.player.refactor.LockManager;
|
||||
import org.schabi.newpipe.playlist.PlayQueueItem;
|
||||
import org.schabi.newpipe.util.ListHelper;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
import static org.schabi.newpipe.player.refactor.PlayerHelper.getTimeString;
|
||||
|
||||
|
||||
/**
|
||||
* Base players joining the common properties
|
||||
@@ -64,18 +65,13 @@ public final class BackgroundPlayer extends Service {
|
||||
|
||||
public static final String ACTION_CLOSE = "org.schabi.newpipe.player.BackgroundPlayer.CLOSE";
|
||||
public static final String ACTION_PLAY_PAUSE = "org.schabi.newpipe.player.BackgroundPlayer.PLAY_PAUSE";
|
||||
public static final String ACTION_OPEN_DETAIL = "org.schabi.newpipe.player.BackgroundPlayer.OPEN_DETAIL";
|
||||
public static final String ACTION_OPEN_CONTROLS = "org.schabi.newpipe.player.BackgroundPlayer.OPEN_CONTROLS";
|
||||
public static final String ACTION_REPEAT = "org.schabi.newpipe.player.BackgroundPlayer.REPEAT";
|
||||
public static final String ACTION_FAST_REWIND = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_FAST_REWIND";
|
||||
public static final String ACTION_FAST_FORWARD = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_FAST_FORWARD";
|
||||
public static final String ACTION_PLAY_NEXT = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_PLAY_NEXT";
|
||||
public static final String ACTION_PLAY_PREVIOUS = "org.schabi.newpipe.player.BackgroundPlayer.ACTION_PLAY_PREVIOUS";
|
||||
|
||||
private BasePlayerImpl basePlayerImpl;
|
||||
private PowerManager powerManager;
|
||||
private WifiManager wifiManager;
|
||||
|
||||
private PowerManager.WakeLock wakeLock;
|
||||
private WifiManager.WifiLock wifiLock;
|
||||
|
||||
private LockManager lockManager;
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Service-Activity Binder
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
@@ -93,7 +89,6 @@ public final class BackgroundPlayer extends Service {
|
||||
private RemoteViews notRemoteView;
|
||||
private RemoteViews bigNotRemoteView;
|
||||
private final String setAlphaMethodName = (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) ? "setImageAlpha" : "setAlpha";
|
||||
private final String setImageResourceMethodName = "setImageResource";
|
||||
|
||||
private boolean shouldUpdateOnProgress;
|
||||
|
||||
@@ -105,11 +100,10 @@ public final class BackgroundPlayer extends Service {
|
||||
public void onCreate() {
|
||||
if (DEBUG) Log.d(TAG, "onCreate() called");
|
||||
notificationManager = ((NotificationManager) getSystemService(NOTIFICATION_SERVICE));
|
||||
powerManager = ((PowerManager) getSystemService(POWER_SERVICE));
|
||||
wifiManager = ((WifiManager) getApplicationContext().getSystemService(WIFI_SERVICE));
|
||||
lockManager = new LockManager(this);
|
||||
|
||||
ThemeHelper.setTheme(this);
|
||||
basePlayerImpl = new BasePlayerImpl(getApplicationContext());
|
||||
basePlayerImpl = new BasePlayerImpl(this);
|
||||
basePlayerImpl.setup();
|
||||
|
||||
mBinder = new PlayerServiceBinder(basePlayerImpl);
|
||||
@@ -150,8 +144,9 @@ public final class BackgroundPlayer extends Service {
|
||||
private void onClose() {
|
||||
if (DEBUG) Log.d(TAG, "onClose() called");
|
||||
|
||||
releaseWifiAndCpu();
|
||||
|
||||
if (lockManager != null) {
|
||||
lockManager.releaseWifiAndCpu();
|
||||
}
|
||||
if (basePlayerImpl != null) {
|
||||
basePlayerImpl.stopActivityBinding();
|
||||
basePlayerImpl.destroy();
|
||||
@@ -159,6 +154,7 @@ public final class BackgroundPlayer extends Service {
|
||||
if (notificationManager != null) notificationManager.cancel(NOTIFICATION_ID);
|
||||
mBinder = null;
|
||||
basePlayerImpl = null;
|
||||
lockManager = null;
|
||||
|
||||
stopForeground(true);
|
||||
stopSelf();
|
||||
@@ -198,19 +194,22 @@ public final class BackgroundPlayer extends Service {
|
||||
}
|
||||
|
||||
private void setupNotification(RemoteViews remoteViews) {
|
||||
bigNotRemoteView.setTextViewText(R.id.notificationSongName, basePlayerImpl.getVideoTitle());
|
||||
bigNotRemoteView.setTextViewText(R.id.notificationArtist, basePlayerImpl.getVideoTitle());
|
||||
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationPlayPause,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PAUSE), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationStop,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationContent,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_OPEN_DETAIL), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_OPEN_CONTROLS), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationRepeat,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationFRewind,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_FAST_REWIND), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_NEXT), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
remoteViews.setOnClickPendingIntent(R.id.notificationFForward,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_FAST_FORWARD), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_PLAY_PREVIOUS), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
|
||||
setRepeatModeIcon(remoteViews, basePlayerImpl.getRepeatMode());
|
||||
}
|
||||
@@ -244,36 +243,18 @@ public final class BackgroundPlayer extends Service {
|
||||
// Utils
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private void lockWifiAndCpu() {
|
||||
if (DEBUG) Log.d(TAG, "lockWifiAndCpu() called");
|
||||
if (wakeLock != null && wakeLock.isHeld() && wifiLock != null && wifiLock.isHeld()) return;
|
||||
|
||||
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
|
||||
wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
|
||||
|
||||
if (wakeLock != null) wakeLock.acquire();
|
||||
if (wifiLock != null) wifiLock.acquire();
|
||||
}
|
||||
|
||||
private void releaseWifiAndCpu() {
|
||||
if (DEBUG) Log.d(TAG, "releaseWifiAndCpu() called");
|
||||
if (wakeLock != null && wakeLock.isHeld()) wakeLock.release();
|
||||
if (wifiLock != null && wifiLock.isHeld()) wifiLock.release();
|
||||
|
||||
wakeLock = null;
|
||||
wifiLock = null;
|
||||
}
|
||||
|
||||
private void setRepeatModeIcon(final RemoteViews remoteViews, final int repeatMode) {
|
||||
final String methodName = "setImageResource";
|
||||
|
||||
switch (repeatMode) {
|
||||
case Player.REPEAT_MODE_OFF:
|
||||
remoteViews.setInt(R.id.notificationRepeat, setImageResourceMethodName, R.drawable.exo_controls_repeat_off);
|
||||
remoteViews.setInt(R.id.notificationRepeat, methodName, R.drawable.exo_controls_repeat_off);
|
||||
break;
|
||||
case Player.REPEAT_MODE_ONE:
|
||||
remoteViews.setInt(R.id.notificationRepeat, setImageResourceMethodName, R.drawable.exo_controls_repeat_one);
|
||||
remoteViews.setInt(R.id.notificationRepeat, methodName, R.drawable.exo_controls_repeat_one);
|
||||
break;
|
||||
case Player.REPEAT_MODE_ALL:
|
||||
remoteViews.setInt(R.id.notificationRepeat, setImageResourceMethodName, R.drawable.exo_controls_repeat_all);
|
||||
remoteViews.setInt(R.id.notificationRepeat, methodName, R.drawable.exo_controls_repeat_all);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -336,23 +317,12 @@ public final class BackgroundPlayer extends Service {
|
||||
@Override
|
||||
public void onUpdateProgress(int currentProgress, int duration, int bufferPercent) {
|
||||
updateProgress(currentProgress, duration, bufferPercent);
|
||||
|
||||
if (!shouldUpdateOnProgress) return;
|
||||
|
||||
resetNotification();
|
||||
if (bigNotRemoteView != null) {
|
||||
if (currentItem != null) {
|
||||
bigNotRemoteView.setTextViewText(R.id.notificationSongName, getVideoTitle());
|
||||
bigNotRemoteView.setTextViewText(R.id.notificationArtist, getUploaderName());
|
||||
}
|
||||
bigNotRemoteView.setProgressBar(R.id.notificationProgressBar, duration, currentProgress, false);
|
||||
bigNotRemoteView.setTextViewText(R.id.notificationTime, getTimeString(currentProgress) + " / " + getTimeString(duration));
|
||||
}
|
||||
if (notRemoteView != null) {
|
||||
if (currentItem != null) {
|
||||
notRemoteView.setTextViewText(R.id.notificationSongName, getVideoTitle());
|
||||
notRemoteView.setTextViewText(R.id.notificationArtist, getUploaderName());
|
||||
}
|
||||
notRemoteView.setProgressBar(R.id.notificationProgressBar, duration, currentProgress, false);
|
||||
}
|
||||
|
||||
@@ -360,18 +330,14 @@ public final class BackgroundPlayer extends Service {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFastRewind() {
|
||||
if (!isPlayerReady()) return;
|
||||
|
||||
onPlayPrevious();
|
||||
public void onPlayPrevious() {
|
||||
super.onPlayPrevious();
|
||||
triggerProgressUpdate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFastForward() {
|
||||
if (!isPlayerReady()) return;
|
||||
|
||||
onPlayNext();
|
||||
public void onPlayNext() {
|
||||
super.onPlayNext();
|
||||
triggerProgressUpdate();
|
||||
}
|
||||
|
||||
@@ -464,14 +430,14 @@ public final class BackgroundPlayer extends Service {
|
||||
// Activity Event Listener
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
public void setActivityListener(PlayerEventListener listener) {
|
||||
/*package-private*/ void setActivityListener(PlayerEventListener listener) {
|
||||
activityListener = listener;
|
||||
updateMetadata();
|
||||
updatePlayback();
|
||||
triggerProgressUpdate();
|
||||
}
|
||||
|
||||
public void removeActivityListener(PlayerEventListener listener) {
|
||||
/*package-private*/ void removeActivityListener(PlayerEventListener listener) {
|
||||
if (activityListener == listener) {
|
||||
activityListener = null;
|
||||
}
|
||||
@@ -511,10 +477,10 @@ public final class BackgroundPlayer extends Service {
|
||||
super.setupBroadcastReceiver(intentFilter);
|
||||
intentFilter.addAction(ACTION_CLOSE);
|
||||
intentFilter.addAction(ACTION_PLAY_PAUSE);
|
||||
intentFilter.addAction(ACTION_OPEN_DETAIL);
|
||||
intentFilter.addAction(ACTION_OPEN_CONTROLS);
|
||||
intentFilter.addAction(ACTION_REPEAT);
|
||||
intentFilter.addAction(ACTION_FAST_FORWARD);
|
||||
intentFilter.addAction(ACTION_FAST_REWIND);
|
||||
intentFilter.addAction(ACTION_PLAY_PREVIOUS);
|
||||
intentFilter.addAction(ACTION_PLAY_NEXT);
|
||||
|
||||
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
|
||||
intentFilter.addAction(Intent.ACTION_SCREEN_OFF);
|
||||
@@ -525,6 +491,7 @@ public final class BackgroundPlayer extends Service {
|
||||
@Override
|
||||
public void onBroadcastReceived(Intent intent) {
|
||||
super.onBroadcastReceived(intent);
|
||||
if (intent == null || intent.getAction() == null) return;
|
||||
if (DEBUG) Log.d(TAG, "onBroadcastReceived() called with: intent = [" + intent + "]");
|
||||
switch (intent.getAction()) {
|
||||
case ACTION_CLOSE:
|
||||
@@ -533,17 +500,17 @@ public final class BackgroundPlayer extends Service {
|
||||
case ACTION_PLAY_PAUSE:
|
||||
onVideoPlayPause();
|
||||
break;
|
||||
case ACTION_OPEN_DETAIL:
|
||||
case ACTION_OPEN_CONTROLS:
|
||||
openControl(getApplicationContext());
|
||||
break;
|
||||
case ACTION_REPEAT:
|
||||
onRepeatClicked();
|
||||
break;
|
||||
case ACTION_FAST_REWIND:
|
||||
onFastRewind();
|
||||
case ACTION_PLAY_NEXT:
|
||||
onPlayNext();
|
||||
break;
|
||||
case ACTION_FAST_FORWARD:
|
||||
onFastForward();
|
||||
case ACTION_PLAY_PREVIOUS:
|
||||
onPlayPrevious();
|
||||
break;
|
||||
case Intent.ACTION_SCREEN_ON:
|
||||
onScreenOnOff(true);
|
||||
@@ -579,7 +546,7 @@ public final class BackgroundPlayer extends Service {
|
||||
setControlsOpacity(255);
|
||||
updateNotification(R.drawable.ic_pause_white);
|
||||
|
||||
lockWifiAndCpu();
|
||||
lockManager.acquireWifiAndCpu();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -589,7 +556,7 @@ public final class BackgroundPlayer extends Service {
|
||||
updateNotification(R.drawable.ic_play_arrow_white);
|
||||
if (isProgressLoopRunning()) stopProgressLoop();
|
||||
|
||||
releaseWifiAndCpu();
|
||||
lockManager.releaseWifiAndCpu();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -601,7 +568,7 @@ public final class BackgroundPlayer extends Service {
|
||||
if (notRemoteView != null) notRemoteView.setProgressBar(R.id.notificationProgressBar, 100, 100, false);
|
||||
updateNotification(R.drawable.ic_replay_white);
|
||||
|
||||
releaseWifiAndCpu();
|
||||
lockManager.releaseWifiAndCpu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,7 +29,6 @@ import android.content.IntentFilter;
|
||||
import android.content.SharedPreferences;
|
||||
import android.graphics.Bitmap;
|
||||
import android.media.AudioManager;
|
||||
import android.media.audiofx.AudioEffect;
|
||||
import android.net.Uri;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.Nullable;
|
||||
@@ -39,18 +38,15 @@ import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.DefaultLoadControl;
|
||||
import com.google.android.exoplayer2.DefaultRenderersFactory;
|
||||
import com.google.android.exoplayer2.ExoPlaybackException;
|
||||
import com.google.android.exoplayer2.ExoPlayerFactory;
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.LoadControl;
|
||||
import com.google.android.exoplayer2.PlaybackParameters;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.RenderersFactory;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.Timeline;
|
||||
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
|
||||
import com.google.android.exoplayer2.decoder.DecoderCounters;
|
||||
import com.google.android.exoplayer2.extractor.DefaultExtractorsFactory;
|
||||
import com.google.android.exoplayer2.source.ExtractorMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
@@ -63,31 +59,23 @@ import com.google.android.exoplayer2.source.smoothstreaming.SsMediaSource;
|
||||
import com.google.android.exoplayer2.trackselection.AdaptiveTrackSelection;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor;
|
||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
||||
import com.google.android.exoplayer2.util.Util;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
import com.nostra13.universalimageloader.core.listener.SimpleImageLoadingListener;
|
||||
|
||||
import org.schabi.newpipe.Downloader;
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.player.playback.MediaSourceManager;
|
||||
import org.schabi.newpipe.player.playback.PlaybackListener;
|
||||
import org.schabi.newpipe.player.refactor.AudioReactor;
|
||||
import org.schabi.newpipe.player.refactor.CacheFactory;
|
||||
import org.schabi.newpipe.player.refactor.LoadController;
|
||||
import org.schabi.newpipe.playlist.PlayQueue;
|
||||
import org.schabi.newpipe.playlist.PlayQueueAdapter;
|
||||
import org.schabi.newpipe.playlist.PlayQueueItem;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.Serializable;
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import io.reactivex.Observable;
|
||||
@@ -97,22 +85,21 @@ import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.functions.Predicate;
|
||||
|
||||
import static org.schabi.newpipe.player.refactor.PlayerHelper.getTimeString;
|
||||
|
||||
/**
|
||||
* Base for the players, joining the common properties
|
||||
*
|
||||
* @author mauriciocolli
|
||||
*/
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
public abstract class BasePlayer implements Player.EventListener,
|
||||
AudioManager.OnAudioFocusChangeListener, PlaybackListener, AudioRendererEventListener {
|
||||
// TODO: Check api version for deprecated audio manager methods
|
||||
public abstract class BasePlayer implements Player.EventListener, PlaybackListener {
|
||||
|
||||
public static final boolean DEBUG = true;
|
||||
public static final String TAG = "BasePlayer";
|
||||
|
||||
protected Context context;
|
||||
protected SharedPreferences sharedPreferences;
|
||||
protected AudioManager audioManager;
|
||||
|
||||
protected BroadcastReceiver broadcastReceiver;
|
||||
protected IntentFilter intentFilter;
|
||||
@@ -144,6 +131,7 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||
protected PlayQueueItem currentItem;
|
||||
|
||||
protected Toast errorToast;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Player
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
@@ -151,15 +139,15 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||
protected final static int FAST_FORWARD_REWIND_AMOUNT = 10000; // 10 Seconds
|
||||
protected final static int PLAY_PREV_ACTIVATION_LIMIT = 5000; // 5 seconds
|
||||
protected final static int PROGRESS_LOOP_INTERVAL = 500;
|
||||
protected final static String CACHE_FOLDER_NAME = "exoplayer";
|
||||
|
||||
protected SimpleExoPlayer simpleExoPlayer;
|
||||
protected AudioReactor audioReactor;
|
||||
|
||||
protected boolean isPrepared = false;
|
||||
|
||||
protected DefaultTrackSelector trackSelector;
|
||||
protected CacheDataSourceFactory cacheDataSourceFactory;
|
||||
protected final DefaultExtractorsFactory extractorsFactory = new DefaultExtractorsFactory();
|
||||
protected final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
||||
protected DataSource.Factory cacheDataSourceFactory;
|
||||
protected DefaultExtractorsFactory extractorsFactory;
|
||||
|
||||
protected Disposable progressUpdateReactor;
|
||||
|
||||
@@ -185,37 +173,21 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||
initListeners();
|
||||
}
|
||||
|
||||
private void initExoPlayerCache() {
|
||||
if (cacheDataSourceFactory == null) {
|
||||
DefaultDataSourceFactory dataSourceFactory = new DefaultDataSourceFactory(context, Downloader.USER_AGENT, bandwidthMeter);
|
||||
File cacheDir = new File(context.getExternalCacheDir(), CACHE_FOLDER_NAME);
|
||||
if (!cacheDir.exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
cacheDir.mkdir();
|
||||
}
|
||||
|
||||
if (DEBUG) Log.d(TAG, "initExoPlayerCache: cacheDir = " + cacheDir.getAbsolutePath());
|
||||
SimpleCache simpleCache = new SimpleCache(cacheDir, new LeastRecentlyUsedCacheEvictor(64 * 1024 * 1024L));
|
||||
cacheDataSourceFactory = new CacheDataSourceFactory(simpleCache, dataSourceFactory, CacheDataSource.FLAG_BLOCK_ON_CACHE, 512 * 1024);
|
||||
}
|
||||
}
|
||||
|
||||
public void initPlayer() {
|
||||
if (DEBUG) Log.d(TAG, "initPlayer() called with: context = [" + context + "]");
|
||||
initExoPlayerCache();
|
||||
|
||||
if (audioManager == null) {
|
||||
this.audioManager = ((AudioManager) context.getSystemService(Context.AUDIO_SERVICE));
|
||||
}
|
||||
|
||||
AdaptiveTrackSelection.Factory trackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
|
||||
trackSelector = new DefaultTrackSelector(trackSelectionFactory);
|
||||
|
||||
DefaultLoadControl loadControl = new DefaultLoadControl();
|
||||
|
||||
final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
||||
final AdaptiveTrackSelection.Factory trackSelectionFactory = new AdaptiveTrackSelection.Factory(bandwidthMeter);
|
||||
final LoadControl loadControl = new LoadController(context);
|
||||
final RenderersFactory renderFactory = new DefaultRenderersFactory(context);
|
||||
|
||||
trackSelector = new DefaultTrackSelector(trackSelectionFactory);
|
||||
extractorsFactory = new DefaultExtractorsFactory();
|
||||
cacheDataSourceFactory = new CacheFactory(context);
|
||||
|
||||
simpleExoPlayer = ExoPlayerFactory.newSimpleInstance(renderFactory, trackSelector, loadControl);
|
||||
simpleExoPlayer.setAudioDebugListener(this);
|
||||
audioReactor = new AudioReactor(context, simpleExoPlayer);
|
||||
|
||||
simpleExoPlayer.addListener(this);
|
||||
simpleExoPlayer.setPlayWhenReady(true);
|
||||
}
|
||||
@@ -306,10 +278,7 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||
simpleExoPlayer.release();
|
||||
}
|
||||
if (isProgressLoopRunning()) stopProgressLoop();
|
||||
if (audioManager != null) {
|
||||
audioManager.abandonAudioFocus(this);
|
||||
audioManager = null;
|
||||
}
|
||||
if (audioReactor != null) audioReactor.abandonAudioFocus();
|
||||
}
|
||||
|
||||
public void destroy() {
|
||||
@@ -318,14 +287,8 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||
clearThumbnailCache();
|
||||
unregisterBroadcastReceiver();
|
||||
|
||||
if (playQueue != null) {
|
||||
playQueue.dispose();
|
||||
playQueue = null;
|
||||
}
|
||||
if (playbackManager != null) {
|
||||
playbackManager.dispose();
|
||||
playbackManager = null;
|
||||
}
|
||||
if (playQueue != null) playQueue.dispose();
|
||||
if (playbackManager != null) playbackManager.dispose();
|
||||
|
||||
trackSelector = null;
|
||||
simpleExoPlayer = null;
|
||||
@@ -372,6 +335,7 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||
}
|
||||
|
||||
public void onBroadcastReceived(Intent intent) {
|
||||
if (intent == null || intent.getAction() == null) return;
|
||||
switch (intent.getAction()) {
|
||||
case AudioManager.ACTION_AUDIO_BECOMING_NOISY:
|
||||
if (isPlaying()) simpleExoPlayer.setPlayWhenReady(false);
|
||||
@@ -386,84 +350,6 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// AudioFocus
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private static final int DUCK_DURATION = 1500;
|
||||
private static final float DUCK_AUDIO_TO = .2f;
|
||||
|
||||
@Override
|
||||
public void onAudioFocusChange(int focusChange) {
|
||||
if (DEBUG) Log.d(TAG, "onAudioFocusChange() called with: focusChange = [" + focusChange + "]");
|
||||
if (simpleExoPlayer == null) return;
|
||||
switch (focusChange) {
|
||||
case AudioManager.AUDIOFOCUS_GAIN:
|
||||
onAudioFocusGain();
|
||||
break;
|
||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
|
||||
onAudioFocusLossCanDuck();
|
||||
break;
|
||||
case AudioManager.AUDIOFOCUS_LOSS:
|
||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
||||
onAudioFocusLoss();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean isResumeAfterAudioFocusGain() {
|
||||
return sharedPreferences != null && context != null
|
||||
&& sharedPreferences.getBoolean(context.getString(R.string.resume_on_audio_focus_gain_key), false);
|
||||
}
|
||||
|
||||
protected void onAudioFocusGain() {
|
||||
if (DEBUG) Log.d(TAG, "onAudioFocusGain() called");
|
||||
if (simpleExoPlayer != null) simpleExoPlayer.setVolume(DUCK_AUDIO_TO);
|
||||
animateAudio(DUCK_AUDIO_TO, 1f, DUCK_DURATION);
|
||||
|
||||
if (isResumeAfterAudioFocusGain()) {
|
||||
simpleExoPlayer.setPlayWhenReady(true);
|
||||
}
|
||||
}
|
||||
|
||||
protected void onAudioFocusLoss() {
|
||||
if (DEBUG) Log.d(TAG, "onAudioFocusLoss() called");
|
||||
simpleExoPlayer.setPlayWhenReady(false);
|
||||
}
|
||||
|
||||
protected void onAudioFocusLossCanDuck() {
|
||||
if (DEBUG) Log.d(TAG, "onAudioFocusLossCanDuck() called");
|
||||
// Set the volume to 1/10 on ducking
|
||||
animateAudio(simpleExoPlayer.getVolume(), DUCK_AUDIO_TO, DUCK_DURATION);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Audio Processing
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void onAudioEnabled(DecoderCounters decoderCounters) {}
|
||||
|
||||
@Override
|
||||
public void onAudioSessionId(int i) {
|
||||
final Intent intent = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
|
||||
intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, i);
|
||||
intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName());
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioDecoderInitialized(String s, long l, long l1) {}
|
||||
|
||||
@Override
|
||||
public void onAudioInputFormatChanged(Format format) {}
|
||||
|
||||
@Override
|
||||
public void onAudioTrackUnderrun(int i, long l, long l1) {}
|
||||
|
||||
@Override
|
||||
public void onAudioDisabled(DecoderCounters decoderCounters) {}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// States Implementation
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
@@ -790,7 +676,7 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||
|
||||
public void onPrepared(boolean playWhenReady) {
|
||||
if (DEBUG) Log.d(TAG, "onPrepared() called with: playWhenReady = [" + playWhenReady + "]");
|
||||
if (playWhenReady) audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||
if (playWhenReady) audioReactor.requestAudioFocus();
|
||||
changeState(playWhenReady ? STATE_PLAYING : STATE_PAUSED);
|
||||
}
|
||||
|
||||
@@ -799,8 +685,11 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||
public void onVideoPlayPause() {
|
||||
if (DEBUG) Log.d(TAG, "onVideoPlayPause() called");
|
||||
|
||||
if (!isPlaying()) audioManager.requestAudioFocus(this, AudioManager.STREAM_MUSIC, AudioManager.AUDIOFOCUS_GAIN);
|
||||
else audioManager.abandonAudioFocus(this);
|
||||
if (!isPlaying()) {
|
||||
audioReactor.requestAudioFocus();
|
||||
} else {
|
||||
audioReactor.abandonAudioFocus();
|
||||
}
|
||||
|
||||
if (getCurrentState() == STATE_COMPLETED) {
|
||||
playQueue.setIndex(0);
|
||||
@@ -869,32 +758,6 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||
// Utils
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
private final StringBuilder stringBuilder = new StringBuilder();
|
||||
private final Formatter formatter = new Formatter(stringBuilder, Locale.getDefault());
|
||||
private final NumberFormat speedFormatter = new DecimalFormat("0.##x");
|
||||
private final NumberFormat pitchFormatter = new DecimalFormat("##%");
|
||||
|
||||
// todo: merge this into Localization
|
||||
public String getTimeString(int milliSeconds) {
|
||||
long seconds = (milliSeconds % 60000L) / 1000L;
|
||||
long minutes = (milliSeconds % 3600000L) / 60000L;
|
||||
long hours = (milliSeconds % 86400000L) / 3600000L;
|
||||
long days = (milliSeconds % (86400000L * 7L)) / 86400000L;
|
||||
|
||||
stringBuilder.setLength(0);
|
||||
return days > 0 ? formatter.format("%d:%02d:%02d:%02d", days, hours, minutes, seconds).toString()
|
||||
: hours > 0 ? formatter.format("%d:%02d:%02d", hours, minutes, seconds).toString()
|
||||
: formatter.format("%02d:%02d", minutes, seconds).toString();
|
||||
}
|
||||
|
||||
protected String formatSpeed(float speed) {
|
||||
return speedFormatter.format(speed);
|
||||
}
|
||||
|
||||
protected String formatPitch(float pitch) {
|
||||
return pitchFormatter.format(pitch);
|
||||
}
|
||||
|
||||
protected void reload() {
|
||||
if (playbackManager != null) {
|
||||
playbackManager.reset();
|
||||
@@ -965,6 +828,10 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||
return sharedPreferences;
|
||||
}
|
||||
|
||||
public AudioReactor getAudioReactor() {
|
||||
return audioReactor;
|
||||
}
|
||||
|
||||
public int getCurrentState() {
|
||||
return currentState;
|
||||
}
|
||||
@@ -1026,6 +893,10 @@ public abstract class BasePlayer implements Player.EventListener,
|
||||
return playQueue;
|
||||
}
|
||||
|
||||
public PlayQueueAdapter getPlayQueueAdapter() {
|
||||
return playQueueAdapter;
|
||||
}
|
||||
|
||||
public boolean isPlayerReady() {
|
||||
return currentState == STATE_PLAYING || currentState == STATE_COMPLETED || currentState == STATE_PAUSED;
|
||||
}
|
||||
|
||||
@@ -46,11 +46,11 @@ import android.widget.Toast;
|
||||
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.trackselection.DefaultTrackSelector;
|
||||
import com.nostra13.universalimageloader.core.ImageLoader;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||
import org.schabi.newpipe.player.refactor.PlayerHelper;
|
||||
import org.schabi.newpipe.playlist.PlayQueueItem;
|
||||
import org.schabi.newpipe.playlist.PlayQueueItemBuilder;
|
||||
import org.schabi.newpipe.playlist.PlayQueueItemHolder;
|
||||
@@ -100,7 +100,7 @@ public final class MainVideoPlayer extends Activity {
|
||||
|
||||
showSystemUi();
|
||||
setContentView(R.layout.activity_main_player);
|
||||
playerImpl = new VideoPlayerImpl(getApplicationContext());
|
||||
playerImpl = new VideoPlayerImpl(this);
|
||||
playerImpl.setup(findViewById(android.R.id.content));
|
||||
playerImpl.handleIntent(getIntent());
|
||||
}
|
||||
@@ -723,12 +723,12 @@ public final class MainVideoPlayer extends Activity {
|
||||
return true;
|
||||
}
|
||||
|
||||
private final boolean isGestureControlsEnabled = playerImpl.getSharedPreferences().getBoolean(getString(R.string.player_gesture_controls_key), true);
|
||||
private final boolean isPlayerGestureEnabled = PlayerHelper.isPlayerGestureEnabled(getApplicationContext());
|
||||
|
||||
private final float stepsBrightness = 15, stepBrightness = (1f / stepsBrightness), minBrightness = .01f;
|
||||
private float currentBrightness = .5f;
|
||||
|
||||
private int currentVolume, maxVolume = playerImpl.audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
|
||||
private int currentVolume, maxVolume = playerImpl.getAudioReactor().getMaxVolume();
|
||||
private final float stepsVolume = 15, stepVolume = (float) Math.ceil(maxVolume / stepsVolume), minVolume = 0;
|
||||
|
||||
private final String brightnessUnicode = new String(Character.toChars(0x2600));
|
||||
@@ -742,7 +742,7 @@ public final class MainVideoPlayer extends Activity {
|
||||
// TODO: Improve video gesture controls
|
||||
@Override
|
||||
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
|
||||
if (!isGestureControlsEnabled) return false;
|
||||
if (!isPlayerGestureEnabled) return false;
|
||||
|
||||
//noinspection PointlessBooleanExpression
|
||||
if (DEBUG && false) Log.d(TAG, "MainVideoPlayer.onScroll = " +
|
||||
@@ -763,13 +763,14 @@ public final class MainVideoPlayer extends Activity {
|
||||
|
||||
if (e1.getX() > playerImpl.getRootView().getWidth() / 2) {
|
||||
double floor = Math.floor(up ? stepVolume : -stepVolume);
|
||||
currentVolume = (int) (playerImpl.audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) + floor);
|
||||
currentVolume = (int) (playerImpl.getAudioReactor().getMaxVolume() + floor);
|
||||
if (currentVolume >= maxVolume) currentVolume = maxVolume;
|
||||
if (currentVolume <= minVolume) currentVolume = (int) minVolume;
|
||||
playerImpl.audioManager.setStreamVolume(AudioManager.STREAM_MUSIC, currentVolume, 0);
|
||||
playerImpl.getAudioReactor().setMaxVolume(currentVolume);
|
||||
|
||||
if (DEBUG) Log.d(TAG, "onScroll().volumeControl, currentVolume = " + currentVolume);
|
||||
playerImpl.getVolumeTextView().setText(volumeUnicode + " " + Math.round((((float) currentVolume) / maxVolume) * 100) + "%");
|
||||
final String volumeText = volumeUnicode + " " + Math.round((((float) currentVolume) / maxVolume) * 100) + "%";
|
||||
playerImpl.getVolumeTextView().setText(volumeText);
|
||||
|
||||
if (playerImpl.getVolumeTextView().getVisibility() != View.VISIBLE) animateView(playerImpl.getVolumeTextView(), true, 200);
|
||||
if (playerImpl.getBrightnessTextView().getVisibility() == View.VISIBLE) playerImpl.getBrightnessTextView().setVisibility(View.GONE);
|
||||
@@ -784,7 +785,8 @@ public final class MainVideoPlayer extends Activity {
|
||||
if (DEBUG) Log.d(TAG, "onScroll().brightnessControl, currentBrightness = " + currentBrightness);
|
||||
int brightnessNormalized = Math.round(currentBrightness * 100);
|
||||
|
||||
playerImpl.getBrightnessTextView().setText(brightnessUnicode + " " + (brightnessNormalized == 1 ? 0 : brightnessNormalized) + "%");
|
||||
final String brightnessText = brightnessUnicode + " " + (brightnessNormalized == 1 ? 0 : brightnessNormalized) + "%";
|
||||
playerImpl.getBrightnessTextView().setText(brightnessText);
|
||||
|
||||
if (playerImpl.getBrightnessTextView().getVisibility() != View.VISIBLE) animateView(playerImpl.getBrightnessTextView(), true, 200);
|
||||
if (playerImpl.getVolumeTextView().getVisibility() == View.VISIBLE) playerImpl.getVolumeTextView().setVisibility(View.GONE);
|
||||
|
||||
@@ -66,6 +66,7 @@ import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.extractor.stream.VideoStream;
|
||||
import org.schabi.newpipe.player.event.PlayerEventListener;
|
||||
import org.schabi.newpipe.player.old.PlayVideoActivity;
|
||||
import org.schabi.newpipe.player.refactor.LockManager;
|
||||
import org.schabi.newpipe.playlist.PlayQueueItem;
|
||||
import org.schabi.newpipe.playlist.SinglePlayQueue;
|
||||
import org.schabi.newpipe.report.ErrorActivity;
|
||||
@@ -84,6 +85,7 @@ import io.reactivex.disposables.Disposable;
|
||||
import io.reactivex.functions.Consumer;
|
||||
import io.reactivex.schedulers.Schedulers;
|
||||
|
||||
import static org.schabi.newpipe.player.refactor.PlayerHelper.isUsingOldPlayer;
|
||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||
|
||||
/**
|
||||
@@ -99,7 +101,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
private static final int NOTIFICATION_ID = 40028922;
|
||||
public static final String ACTION_CLOSE = "org.schabi.newpipe.player.PopupVideoPlayer.CLOSE";
|
||||
public static final String ACTION_PLAY_PAUSE = "org.schabi.newpipe.player.PopupVideoPlayer.PLAY_PAUSE";
|
||||
public static final String ACTION_OPEN_DETAIL = "org.schabi.newpipe.player.PopupVideoPlayer.OPEN_DETAIL";
|
||||
public static final String ACTION_OPEN_CONTROLS = "org.schabi.newpipe.player.PopupVideoPlayer.OPEN_CONTROLS";
|
||||
public static final String ACTION_REPEAT = "org.schabi.newpipe.player.PopupVideoPlayer.REPEAT";
|
||||
|
||||
private static final String POPUP_SAVED_WIDTH = "popup_saved_width";
|
||||
@@ -116,15 +118,13 @@ public final class PopupVideoPlayer extends Service {
|
||||
private float minimumWidth, minimumHeight;
|
||||
private float maximumWidth, maximumHeight;
|
||||
|
||||
private final String setImageResourceMethodName = "setImageResource";
|
||||
|
||||
private NotificationManager notificationManager;
|
||||
private NotificationCompat.Builder notBuilder;
|
||||
private RemoteViews notRemoteView;
|
||||
|
||||
private VideoPlayerImpl playerImpl;
|
||||
private Disposable currentWorker;
|
||||
|
||||
private LockManager lockManager;
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Service-Activity Binder
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
@@ -141,7 +141,8 @@ public final class PopupVideoPlayer extends Service {
|
||||
windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
|
||||
notificationManager = ((NotificationManager) getSystemService(NOTIFICATION_SERVICE));
|
||||
|
||||
playerImpl = new VideoPlayerImpl(getApplicationContext());
|
||||
lockManager = new LockManager(this);
|
||||
playerImpl = new VideoPlayerImpl(this);
|
||||
ThemeHelper.setTheme(this);
|
||||
|
||||
mBinder = new PlayerServiceBinder(playerImpl);
|
||||
@@ -261,7 +262,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
notRemoteView.setOnClickPendingIntent(R.id.notificationStop,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_CLOSE), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
notRemoteView.setOnClickPendingIntent(R.id.notificationContent,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_OPEN_DETAIL), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_OPEN_CONTROLS), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
notRemoteView.setOnClickPendingIntent(R.id.notificationRepeat,
|
||||
PendingIntent.getBroadcast(this, NOTIFICATION_ID, new Intent(ACTION_REPEAT), PendingIntent.FLAG_UPDATE_CURRENT));
|
||||
|
||||
@@ -302,6 +303,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
playerImpl.stopActivityBinding();
|
||||
playerImpl.destroy();
|
||||
}
|
||||
if (lockManager != null) lockManager.releaseWifiAndCpu();
|
||||
if (notificationManager != null) notificationManager.cancel(NOTIFICATION_ID);
|
||||
if (currentWorker != null) currentWorker.dispose();
|
||||
mBinder = null;
|
||||
@@ -381,17 +383,19 @@ public final class PopupVideoPlayer extends Service {
|
||||
}
|
||||
|
||||
protected void setRepeatModeRemote(final RemoteViews remoteViews, final int repeatMode) {
|
||||
final String methodName = "setImageResource";
|
||||
|
||||
if (remoteViews == null) return;
|
||||
|
||||
switch (repeatMode) {
|
||||
case Player.REPEAT_MODE_OFF:
|
||||
remoteViews.setInt(R.id.notificationRepeat, setImageResourceMethodName, R.drawable.exo_controls_repeat_off);
|
||||
remoteViews.setInt(R.id.notificationRepeat, methodName, R.drawable.exo_controls_repeat_off);
|
||||
break;
|
||||
case Player.REPEAT_MODE_ONE:
|
||||
remoteViews.setInt(R.id.notificationRepeat, setImageResourceMethodName, R.drawable.exo_controls_repeat_one);
|
||||
remoteViews.setInt(R.id.notificationRepeat, methodName, R.drawable.exo_controls_repeat_one);
|
||||
break;
|
||||
case Player.REPEAT_MODE_ALL:
|
||||
remoteViews.setInt(R.id.notificationRepeat, setImageResourceMethodName, R.drawable.exo_controls_repeat_all);
|
||||
remoteViews.setInt(R.id.notificationRepeat, methodName, R.drawable.exo_controls_repeat_all);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -447,7 +451,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
|
||||
setRecovery();
|
||||
Intent intent;
|
||||
if (!getSharedPreferences().getBoolean(getResources().getString(R.string.use_old_player_key), false)) {
|
||||
if (!isUsingOldPlayer(getApplicationContext())) {
|
||||
intent = NavigationHelper.getPlayerIntent(
|
||||
context,
|
||||
MainVideoPlayer.class,
|
||||
@@ -516,8 +520,8 @@ public final class PopupVideoPlayer extends Service {
|
||||
|
||||
@Override
|
||||
public void onUpdateProgress(int currentProgress, int duration, int bufferPercent) {
|
||||
super.onUpdateProgress(currentProgress, duration, bufferPercent);
|
||||
updateProgress(currentProgress, duration, bufferPercent);
|
||||
super.onUpdateProgress(currentProgress, duration, bufferPercent);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -535,14 +539,14 @@ public final class PopupVideoPlayer extends Service {
|
||||
// Activity Event Listener
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
public void setActivityListener(PlayerEventListener listener) {
|
||||
/*package-private*/ void setActivityListener(PlayerEventListener listener) {
|
||||
activityListener = listener;
|
||||
updateMetadata();
|
||||
updatePlayback();
|
||||
triggerProgressUpdate();
|
||||
}
|
||||
|
||||
public void removeActivityListener(PlayerEventListener listener) {
|
||||
/*package-private*/ void removeActivityListener(PlayerEventListener listener) {
|
||||
if (activityListener == listener) {
|
||||
activityListener = null;
|
||||
}
|
||||
@@ -617,7 +621,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
if (DEBUG) Log.d(TAG, "setupBroadcastReceiver() called with: intentFilter = [" + intentFilter + "]");
|
||||
intentFilter.addAction(ACTION_CLOSE);
|
||||
intentFilter.addAction(ACTION_PLAY_PAUSE);
|
||||
intentFilter.addAction(ACTION_OPEN_DETAIL);
|
||||
intentFilter.addAction(ACTION_OPEN_CONTROLS);
|
||||
intentFilter.addAction(ACTION_REPEAT);
|
||||
|
||||
intentFilter.addAction(Intent.ACTION_SCREEN_ON);
|
||||
@@ -636,7 +640,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
case ACTION_PLAY_PAUSE:
|
||||
onVideoPlayPause();
|
||||
break;
|
||||
case ACTION_OPEN_DETAIL:
|
||||
case ACTION_OPEN_CONTROLS:
|
||||
openControl(getApplicationContext());
|
||||
break;
|
||||
case ACTION_REPEAT:
|
||||
@@ -671,6 +675,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
public void onPlaying() {
|
||||
super.onPlaying();
|
||||
updateNotification(R.drawable.ic_pause_white);
|
||||
lockManager.acquireWifiAndCpu();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -684,6 +689,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
super.onPaused();
|
||||
updateNotification(R.drawable.ic_play_arrow_white);
|
||||
showAndAnimateControl(R.drawable.ic_play_arrow_white, false);
|
||||
lockManager.releaseWifiAndCpu();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -697,13 +703,14 @@ public final class PopupVideoPlayer extends Service {
|
||||
super.onCompleted();
|
||||
updateNotification(R.drawable.ic_replay_white);
|
||||
showAndAnimateControl(R.drawable.ic_replay_white, false);
|
||||
lockManager.releaseWifiAndCpu();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Utils
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
public void enableVideoRenderer(final boolean enable) {
|
||||
/*package-private*/ void enableVideoRenderer(final boolean enable) {
|
||||
final int videoRendererIndex = getVideoRendererIndex();
|
||||
if (trackSelector != null && videoRendererIndex != -1) {
|
||||
trackSelector.setRendererDisabled(videoRendererIndex, !enable);
|
||||
@@ -894,7 +901,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
this.serviceId = serviceId;
|
||||
}
|
||||
|
||||
public void onReceive(final StreamInfo info) {
|
||||
/*package-private*/ void onReceive(final StreamInfo info) {
|
||||
mainHandler.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
@@ -929,7 +936,7 @@ public final class PopupVideoPlayer extends Service {
|
||||
stopSelf();
|
||||
}
|
||||
|
||||
public void onReCaptchaException() {
|
||||
/*package-private*/ void onReCaptchaException() {
|
||||
Toast.makeText(context, R.string.recaptcha_request_toast, Toast.LENGTH_LONG).show();
|
||||
// Starting ReCaptcha Challenge Activity
|
||||
Intent intent = new Intent(context, ReCaptchaActivity.class);
|
||||
|
||||
@@ -17,6 +17,7 @@ import android.view.Menu;
|
||||
import android.view.MenuItem;
|
||||
import android.view.View;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.PopupMenu;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.SeekBar;
|
||||
@@ -35,6 +36,9 @@ import org.schabi.newpipe.util.Localization;
|
||||
import org.schabi.newpipe.util.NavigationHelper;
|
||||
import org.schabi.newpipe.util.ThemeHelper;
|
||||
|
||||
import static org.schabi.newpipe.player.refactor.PlayerHelper.formatPitch;
|
||||
import static org.schabi.newpipe.player.refactor.PlayerHelper.formatSpeed;
|
||||
|
||||
public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
implements PlayerEventListener, SeekBar.OnSeekBarChangeListener, View.OnClickListener {
|
||||
|
||||
@@ -58,12 +62,14 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
private RecyclerView itemsList;
|
||||
private ItemTouchHelper itemTouchHelper;
|
||||
|
||||
private LinearLayout metadata;
|
||||
private TextView metadataTitle;
|
||||
private TextView metadataArtist;
|
||||
|
||||
private SeekBar progressSeekBar;
|
||||
private TextView progressCurrentTime;
|
||||
private TextView progressEndTime;
|
||||
private TextView seekDisplay;
|
||||
|
||||
private ImageButton repeatButton;
|
||||
private ImageButton backwardButton;
|
||||
@@ -113,11 +119,6 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
bind();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
getMenuInflater().inflate(R.menu.menu_play_queue, menu);
|
||||
@@ -185,7 +186,8 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
player = ((PlayerServiceBinder) service).getPlayerInstance();
|
||||
}
|
||||
|
||||
if (player == null || player.playQueue == null || player.playQueueAdapter == null || player.simpleExoPlayer == null) {
|
||||
if (player == null || player.getPlayQueue() == null ||
|
||||
player.getPlayQueueAdapter() == null || player.getPlayer() == null) {
|
||||
unbind();
|
||||
finish();
|
||||
} else {
|
||||
@@ -210,25 +212,29 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
private void buildQueue() {
|
||||
itemsList = findViewById(R.id.play_queue);
|
||||
itemsList.setLayoutManager(new LinearLayoutManager(this));
|
||||
itemsList.setAdapter(player.playQueueAdapter);
|
||||
itemsList.setAdapter(player.getPlayQueueAdapter());
|
||||
itemsList.setClickable(true);
|
||||
itemsList.setLongClickable(true);
|
||||
|
||||
itemTouchHelper = new ItemTouchHelper(getItemTouchCallback());
|
||||
itemTouchHelper.attachToRecyclerView(itemsList);
|
||||
|
||||
player.playQueueAdapter.setSelectedListener(getOnSelectedListener());
|
||||
player.getPlayQueueAdapter().setSelectedListener(getOnSelectedListener());
|
||||
}
|
||||
|
||||
private void buildMetadata() {
|
||||
metadata = rootView.findViewById(R.id.metadata);
|
||||
metadataTitle = rootView.findViewById(R.id.song_name);
|
||||
metadataArtist = rootView.findViewById(R.id.artist_name);
|
||||
|
||||
metadata.setOnClickListener(this);
|
||||
}
|
||||
|
||||
private void buildSeekBar() {
|
||||
progressCurrentTime = rootView.findViewById(R.id.current_time);
|
||||
progressSeekBar = rootView.findViewById(R.id.seek_bar);
|
||||
progressEndTime = rootView.findViewById(R.id.end_time);
|
||||
seekDisplay = rootView.findViewById(R.id.seek_display);
|
||||
|
||||
progressSeekBar.setOnSeekBarChangeListener(this);
|
||||
}
|
||||
@@ -263,7 +269,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
playbackSpeedPopupMenu.getMenu().removeGroup(PLAYBACK_SPEED_POPUP_MENU_GROUP_ID);
|
||||
for (int i = 0; i < BasePlayer.PLAYBACK_SPEEDS.length; i++) {
|
||||
final float playbackSpeed = BasePlayer.PLAYBACK_SPEEDS[i];
|
||||
final String formattedSpeed = player.formatSpeed(playbackSpeed);
|
||||
final String formattedSpeed = formatSpeed(playbackSpeed);
|
||||
final MenuItem item = playbackSpeedPopupMenu.getMenu().add(PLAYBACK_SPEED_POPUP_MENU_GROUP_ID, i, Menu.NONE, formattedSpeed);
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
@@ -281,7 +287,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
playbackPitchPopupMenu.getMenu().removeGroup(PLAYBACK_PITCH_POPUP_MENU_GROUP_ID);
|
||||
for (int i = 0; i < BasePlayer.PLAYBACK_PITCHES.length; i++) {
|
||||
final float playbackPitch = BasePlayer.PLAYBACK_PITCHES[i];
|
||||
final String formattedPitch = player.formatPitch(playbackPitch);
|
||||
final String formattedPitch = formatPitch(playbackPitch);
|
||||
final MenuItem item = playbackPitchPopupMenu.getMenu().add(PLAYBACK_PITCH_POPUP_MENU_GROUP_ID, i, Menu.NONE, formattedPitch);
|
||||
item.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
@@ -299,8 +305,8 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
remove.setOnMenuItemClickListener(new MenuItem.OnMenuItemClickListener() {
|
||||
@Override
|
||||
public boolean onMenuItemClick(MenuItem menuItem) {
|
||||
final int index = player.playQueue.indexOf(item);
|
||||
if (index != -1) player.playQueue.remove(index);
|
||||
final int index = player.getPlayQueue().indexOf(item);
|
||||
if (index != -1) player.getPlayQueue().remove(index);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
@@ -331,7 +337,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
|
||||
final int sourceIndex = source.getLayoutPosition();
|
||||
final int targetIndex = target.getLayoutPosition();
|
||||
player.playQueue.move(sourceIndex, targetIndex);
|
||||
player.getPlayQueue().move(sourceIndex, targetIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -359,7 +365,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
|
||||
@Override
|
||||
public void held(PlayQueueItem item, View view) {
|
||||
final int index = player.playQueue.indexOf(item);
|
||||
final int index = player.getPlayQueue().indexOf(item);
|
||||
if (index != -1) buildItemPopupMenu(item, view);
|
||||
}
|
||||
|
||||
@@ -375,7 +381,7 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
}
|
||||
|
||||
private void scrollToSelected() {
|
||||
itemsList.smoothScrollToPosition(player.playQueue.getIndex());
|
||||
itemsList.smoothScrollToPosition(player.getPlayQueue().getIndex());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
@@ -404,6 +410,10 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
|
||||
} else if (view.getId() == playbackPitchButton.getId()) {
|
||||
playbackPitchPopupMenu.show();
|
||||
|
||||
} else if (view.getId() == metadata.getId()) {
|
||||
scrollToSelected();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -413,17 +423,23 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
|
||||
@Override
|
||||
public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
|
||||
if (fromUser) progressCurrentTime.setText(Localization.getDurationString(progress / 1000));
|
||||
if (fromUser) {
|
||||
final String seekTime = Localization.getDurationString(progress / 1000);
|
||||
progressCurrentTime.setText(seekTime);
|
||||
seekDisplay.setText(seekTime);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStartTrackingTouch(SeekBar seekBar) {
|
||||
seeking = true;
|
||||
seekDisplay.setVisibility(View.VISIBLE);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopTrackingTouch(SeekBar seekBar) {
|
||||
player.simpleExoPlayer.seekTo(seekBar.getProgress());
|
||||
seekDisplay.setVisibility(View.GONE);
|
||||
seeking = false;
|
||||
}
|
||||
|
||||
@@ -528,8 +544,8 @@ public abstract class ServicePlayerActivity extends AppCompatActivity
|
||||
|
||||
private void onPlaybackParameterChanged(final PlaybackParameters parameters) {
|
||||
if (parameters != null) {
|
||||
playbackSpeedButton.setText(player.formatSpeed(parameters.speed));
|
||||
playbackPitchButton.setText(player.formatPitch(parameters.pitch));
|
||||
playbackSpeedButton.setText(formatSpeed(parameters.speed));
|
||||
playbackPitchButton.setText(formatPitch(parameters.pitch));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -49,7 +49,6 @@ import android.widget.TextView;
|
||||
import com.google.android.exoplayer2.C;
|
||||
import com.google.android.exoplayer2.Player;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.source.ConcatenatingMediaSource;
|
||||
import com.google.android.exoplayer2.source.MediaSource;
|
||||
import com.google.android.exoplayer2.source.MergingMediaSource;
|
||||
import com.google.android.exoplayer2.ui.AspectRatioFrameLayout;
|
||||
@@ -66,6 +65,8 @@ import org.schabi.newpipe.util.ListHelper;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static org.schabi.newpipe.player.refactor.PlayerHelper.formatSpeed;
|
||||
import static org.schabi.newpipe.player.refactor.PlayerHelper.getTimeString;
|
||||
import static org.schabi.newpipe.util.AnimationUtils.animateView;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
package org.schabi.newpipe.player.mediasource;
|
||||
package org.schabi.newpipe.player.playback;
|
||||
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
@@ -9,7 +9,6 @@ import com.google.android.exoplayer2.source.MediaSource;
|
||||
import org.reactivestreams.Subscriber;
|
||||
import org.reactivestreams.Subscription;
|
||||
import org.schabi.newpipe.extractor.stream.StreamInfo;
|
||||
import org.schabi.newpipe.player.mediasource.DeferredMediaSource;
|
||||
import org.schabi.newpipe.playlist.PlayQueue;
|
||||
import org.schabi.newpipe.playlist.PlayQueueItem;
|
||||
import org.schabi.newpipe.playlist.events.MoveEvent;
|
||||
@@ -29,8 +28,8 @@ public class MediaSourceManager implements DeferredMediaSource.Callback {
|
||||
// One-side rolling window size for default loading
|
||||
// Effectively loads windowSize * 2 + 1 streams, must be greater than 0
|
||||
private final int windowSize;
|
||||
private PlaybackListener playbackListener;
|
||||
private PlayQueue playQueue;
|
||||
private final PlaybackListener playbackListener;
|
||||
private final PlayQueue playQueue;
|
||||
|
||||
private DynamicConcatenatingMediaSource sources;
|
||||
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
package org.schabi.newpipe.player.refactor;
|
||||
|
||||
import android.animation.Animator;
|
||||
import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.media.AudioFocusRequest;
|
||||
import android.media.AudioManager;
|
||||
import android.media.audiofx.AudioEffect;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.exoplayer2.Format;
|
||||
import com.google.android.exoplayer2.SimpleExoPlayer;
|
||||
import com.google.android.exoplayer2.audio.AudioRendererEventListener;
|
||||
import com.google.android.exoplayer2.decoder.DecoderCounters;
|
||||
|
||||
@SuppressWarnings({"WeakerAccess", "unused"})
|
||||
public class AudioReactor implements AudioManager.OnAudioFocusChangeListener, AudioRendererEventListener {
|
||||
|
||||
private static final String TAG = "AudioFocusReactor";
|
||||
|
||||
private static final int DUCK_DURATION = 1500;
|
||||
private static final float DUCK_AUDIO_TO = .2f;
|
||||
|
||||
private static final int FOCUS_GAIN_TYPE = AudioManager.AUDIOFOCUS_GAIN;
|
||||
private static final int STREAM_TYPE = AudioManager.STREAM_MUSIC;
|
||||
|
||||
private final SimpleExoPlayer player;
|
||||
private final Context context;
|
||||
private final AudioManager audioManager;
|
||||
|
||||
private AudioFocusRequest request;
|
||||
|
||||
private final boolean isResumeAfterAudioFocusGain;
|
||||
|
||||
public AudioReactor(@NonNull final Context context, @NonNull final SimpleExoPlayer player) {
|
||||
this.player = player;
|
||||
this.context = context;
|
||||
|
||||
this.audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
|
||||
this.isResumeAfterAudioFocusGain = PlayerHelper.isResumeAfterAudioFocusGain(context);
|
||||
|
||||
player.setAudioDebugListener(this);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
request = new AudioFocusRequest.Builder(FOCUS_GAIN_TYPE)
|
||||
.setAcceptsDelayedFocusGain(true)
|
||||
.setWillPauseWhenDucked(true)
|
||||
.setOnAudioFocusChangeListener(this)
|
||||
.build();
|
||||
}
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Audio Manager
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
public void requestAudioFocus() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
audioManager.requestAudioFocus(request);
|
||||
} else {
|
||||
audioManager.requestAudioFocus(this, STREAM_TYPE, FOCUS_GAIN_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
public void abandonAudioFocus() {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
audioManager.abandonAudioFocusRequest(request);
|
||||
} else {
|
||||
audioManager.abandonAudioFocus(this);
|
||||
}
|
||||
}
|
||||
|
||||
public int getMaxVolume() {
|
||||
return audioManager.getStreamMaxVolume(STREAM_TYPE);
|
||||
}
|
||||
|
||||
public void setMaxVolume(final int volume) {
|
||||
audioManager.setStreamVolume(STREAM_TYPE, volume, 0);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// AudioFocus
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void onAudioFocusChange(int focusChange) {
|
||||
Log.d(TAG, "onAudioFocusChange() called with: focusChange = [" + focusChange + "]");
|
||||
switch (focusChange) {
|
||||
case AudioManager.AUDIOFOCUS_GAIN:
|
||||
onAudioFocusGain();
|
||||
break;
|
||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT_CAN_DUCK:
|
||||
onAudioFocusLossCanDuck();
|
||||
break;
|
||||
case AudioManager.AUDIOFOCUS_LOSS:
|
||||
case AudioManager.AUDIOFOCUS_LOSS_TRANSIENT:
|
||||
onAudioFocusLoss();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void onAudioFocusGain() {
|
||||
Log.d(TAG, "onAudioFocusGain() called");
|
||||
player.setVolume(DUCK_AUDIO_TO);
|
||||
animateAudio(DUCK_AUDIO_TO, 1f, DUCK_DURATION);
|
||||
|
||||
if (isResumeAfterAudioFocusGain) {
|
||||
player.setPlayWhenReady(true);
|
||||
}
|
||||
}
|
||||
|
||||
private void onAudioFocusLoss() {
|
||||
Log.d(TAG, "onAudioFocusLoss() called");
|
||||
player.setPlayWhenReady(false);
|
||||
}
|
||||
|
||||
private void onAudioFocusLossCanDuck() {
|
||||
Log.d(TAG, "onAudioFocusLossCanDuck() called");
|
||||
// Set the volume to 1/10 on ducking
|
||||
animateAudio(player.getVolume(), DUCK_AUDIO_TO, DUCK_DURATION);
|
||||
}
|
||||
|
||||
private void animateAudio(final float from, final float to, int duration) {
|
||||
ValueAnimator valueAnimator = new ValueAnimator();
|
||||
valueAnimator.setFloatValues(from, to);
|
||||
valueAnimator.setDuration(duration);
|
||||
valueAnimator.addListener(new AnimatorListenerAdapter() {
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
player.setVolume(from);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
player.setVolume(to);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
player.setVolume(to);
|
||||
}
|
||||
});
|
||||
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
|
||||
@Override
|
||||
public void onAnimationUpdate(ValueAnimator animation) {
|
||||
player.setVolume(((float) animation.getAnimatedValue()));
|
||||
}
|
||||
});
|
||||
valueAnimator.start();
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Audio Processing
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void onAudioSessionId(int i) {
|
||||
final Intent intent = new Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION);
|
||||
intent.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, i);
|
||||
intent.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.getPackageName());
|
||||
context.sendBroadcast(intent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAudioEnabled(DecoderCounters decoderCounters) {}
|
||||
|
||||
@Override
|
||||
public void onAudioDecoderInitialized(String s, long l, long l1) {}
|
||||
|
||||
@Override
|
||||
public void onAudioInputFormatChanged(Format format) {}
|
||||
|
||||
@Override
|
||||
public void onAudioTrackUnderrun(int i, long l, long l1) {}
|
||||
|
||||
@Override
|
||||
public void onAudioDisabled(DecoderCounters decoderCounters) {}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package org.schabi.newpipe.player.refactor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.exoplayer2.upstream.DataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultBandwidthMeter;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSource;
|
||||
import com.google.android.exoplayer2.upstream.DefaultDataSourceFactory;
|
||||
import com.google.android.exoplayer2.upstream.FileDataSource;
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSink;
|
||||
import com.google.android.exoplayer2.upstream.cache.CacheDataSource;
|
||||
import com.google.android.exoplayer2.upstream.cache.LeastRecentlyUsedCacheEvictor;
|
||||
import com.google.android.exoplayer2.upstream.cache.SimpleCache;
|
||||
|
||||
import org.schabi.newpipe.Downloader;
|
||||
|
||||
import java.io.File;
|
||||
|
||||
public class CacheFactory implements DataSource.Factory {
|
||||
private static final String TAG = "CacheFactory";
|
||||
private static final String CACHE_FOLDER_NAME = "exoplayer";
|
||||
private static final int CACHE_FLAGS = CacheDataSource.FLAG_BLOCK_ON_CACHE | CacheDataSource.FLAG_IGNORE_CACHE_ON_ERROR;
|
||||
|
||||
private final DefaultDataSourceFactory dataSourceFactory;
|
||||
private final File cacheDir;
|
||||
private final long maxFileSize;
|
||||
|
||||
// Creating cache on every instance may cause problems with multiple players when
|
||||
// sources are not ExtractorMediaSource
|
||||
// see: https://stackoverflow.com/questions/28700391/using-cache-in-exoplayer
|
||||
// todo: make this a singleton?
|
||||
private static SimpleCache cache;
|
||||
|
||||
public CacheFactory(@NonNull final Context context) {
|
||||
this(context, PlayerHelper.getPreferredCacheSize(context), PlayerHelper.getPreferredFileSize(context));
|
||||
}
|
||||
|
||||
CacheFactory(@NonNull final Context context, final long maxCacheSize, final long maxFileSize) {
|
||||
super();
|
||||
this.maxFileSize = maxFileSize;
|
||||
|
||||
final String userAgent = Downloader.USER_AGENT;
|
||||
final DefaultBandwidthMeter bandwidthMeter = new DefaultBandwidthMeter();
|
||||
dataSourceFactory = new DefaultDataSourceFactory(context, userAgent, bandwidthMeter);
|
||||
|
||||
cacheDir = new File(context.getExternalCacheDir(), CACHE_FOLDER_NAME);
|
||||
if (!cacheDir.exists()) {
|
||||
//noinspection ResultOfMethodCallIgnored
|
||||
cacheDir.mkdir();
|
||||
}
|
||||
|
||||
if (cache == null) {
|
||||
final LeastRecentlyUsedCacheEvictor evictor = new LeastRecentlyUsedCacheEvictor(maxCacheSize);
|
||||
cache = new SimpleCache(cacheDir, evictor);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSource createDataSource() {
|
||||
Log.d(TAG, "initExoPlayerCache: cacheDir = " + cacheDir.getAbsolutePath());
|
||||
|
||||
final DefaultDataSource dataSource = dataSourceFactory.createDataSource();
|
||||
final FileDataSource fileSource = new FileDataSource();
|
||||
final CacheDataSink dataSink = new CacheDataSink(cache, maxFileSize);
|
||||
|
||||
return new CacheDataSource(cache, dataSource, fileSource, dataSink, CACHE_FLAGS, null);
|
||||
}
|
||||
|
||||
public void tryDeleteCacheFiles() {
|
||||
if (!cacheDir.exists() || !cacheDir.isDirectory()) return;
|
||||
|
||||
try {
|
||||
for (File file : cacheDir.listFiles()) {
|
||||
final String filePath = file.getAbsolutePath();
|
||||
final boolean deleteSuccessful = file.delete();
|
||||
|
||||
Log.d(TAG, "tryDeleteCacheFiles: " + filePath + " deleted = " + deleteSuccessful);
|
||||
}
|
||||
} catch (Exception ignored) {
|
||||
Log.e(TAG, "Failed to delete file.", ignored);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,76 @@
|
||||
package org.schabi.newpipe.player.refactor;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
import com.google.android.exoplayer2.DefaultLoadControl;
|
||||
import com.google.android.exoplayer2.LoadControl;
|
||||
import com.google.android.exoplayer2.Renderer;
|
||||
import com.google.android.exoplayer2.source.TrackGroupArray;
|
||||
import com.google.android.exoplayer2.trackselection.TrackSelectionArray;
|
||||
import com.google.android.exoplayer2.upstream.Allocator;
|
||||
import com.google.android.exoplayer2.upstream.DefaultAllocator;
|
||||
|
||||
public class LoadController implements LoadControl {
|
||||
|
||||
public static final String TAG = "LoadController";
|
||||
|
||||
private final LoadControl internalLoadControl;
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Default Load Control
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
public LoadController(final Context context) {
|
||||
this(PlayerHelper.getMinBufferMs(context),
|
||||
PlayerHelper.getMaxBufferMs(context),
|
||||
PlayerHelper.getBufferForPlaybackMs(context),
|
||||
PlayerHelper.getBufferForPlaybackAfterRebufferMs(context));
|
||||
}
|
||||
|
||||
public LoadController(final int minBufferMs,
|
||||
final int maxBufferMs,
|
||||
final long bufferForPlaybackMs,
|
||||
final long bufferForPlaybackAfterRebufferMs) {
|
||||
final DefaultAllocator allocator = new DefaultAllocator(true, 65536);
|
||||
internalLoadControl = new DefaultLoadControl(allocator, minBufferMs, maxBufferMs, bufferForPlaybackMs, bufferForPlaybackAfterRebufferMs);
|
||||
}
|
||||
|
||||
/*//////////////////////////////////////////////////////////////////////////
|
||||
// Custom behaviours
|
||||
//////////////////////////////////////////////////////////////////////////*/
|
||||
|
||||
@Override
|
||||
public void onPrepared() {
|
||||
internalLoadControl.onPrepared();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTracksSelected(Renderer[] renderers, TrackGroupArray trackGroupArray, TrackSelectionArray trackSelectionArray) {
|
||||
internalLoadControl.onTracksSelected(renderers, trackGroupArray, trackSelectionArray);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStopped() {
|
||||
internalLoadControl.onStopped();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReleased() {
|
||||
internalLoadControl.onReleased();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Allocator getAllocator() {
|
||||
return internalLoadControl.getAllocator();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldStartPlayback(long l, boolean b) {
|
||||
return internalLoadControl.shouldStartPlayback(l, b);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldContinueLoading(long l) {
|
||||
return internalLoadControl.shouldContinueLoading(l);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package org.schabi.newpipe.player.refactor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.os.PowerManager;
|
||||
import android.util.Log;
|
||||
|
||||
import static android.content.Context.POWER_SERVICE;
|
||||
import static android.content.Context.WIFI_SERVICE;
|
||||
|
||||
public class LockManager {
|
||||
private final String TAG = "LockManager@" + hashCode();
|
||||
|
||||
private final PowerManager powerManager;
|
||||
private final WifiManager wifiManager;
|
||||
|
||||
private PowerManager.WakeLock wakeLock;
|
||||
private WifiManager.WifiLock wifiLock;
|
||||
|
||||
public LockManager(final Context context) {
|
||||
powerManager = ((PowerManager) context.getApplicationContext().getSystemService(POWER_SERVICE));
|
||||
wifiManager = ((WifiManager) context.getApplicationContext().getSystemService(WIFI_SERVICE));
|
||||
}
|
||||
|
||||
public void acquireWifiAndCpu() {
|
||||
Log.d(TAG, "acquireWifiAndCpu() called");
|
||||
if (wakeLock != null && wakeLock.isHeld() && wifiLock != null && wifiLock.isHeld()) return;
|
||||
|
||||
wakeLock = powerManager.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, TAG);
|
||||
wifiLock = wifiManager.createWifiLock(WifiManager.WIFI_MODE_FULL, TAG);
|
||||
|
||||
if (wakeLock != null) wakeLock.acquire();
|
||||
if (wifiLock != null) wifiLock.acquire();
|
||||
}
|
||||
|
||||
public void releaseWifiAndCpu() {
|
||||
Log.d(TAG, "releaseWifiAndCpu() called");
|
||||
if (wakeLock != null && wakeLock.isHeld()) wakeLock.release();
|
||||
if (wifiLock != null && wifiLock.isHeld()) wifiLock.release();
|
||||
|
||||
wakeLock = null;
|
||||
wifiLock = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package org.schabi.newpipe.player.refactor;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.annotation.NonNull;
|
||||
|
||||
import org.schabi.newpipe.R;
|
||||
|
||||
import java.text.DecimalFormat;
|
||||
import java.text.NumberFormat;
|
||||
import java.util.Formatter;
|
||||
import java.util.Locale;
|
||||
|
||||
public class PlayerHelper {
|
||||
private PlayerHelper() {}
|
||||
|
||||
private static final StringBuilder stringBuilder = new StringBuilder();
|
||||
private static final Formatter stringFormatter = new Formatter(stringBuilder, Locale.getDefault());
|
||||
private static final NumberFormat speedFormatter = new DecimalFormat("0.##x");
|
||||
private static final NumberFormat pitchFormatter = new DecimalFormat("##%");
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Exposed helpers
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public static String getTimeString(int milliSeconds) {
|
||||
long seconds = (milliSeconds % 60000L) / 1000L;
|
||||
long minutes = (milliSeconds % 3600000L) / 60000L;
|
||||
long hours = (milliSeconds % 86400000L) / 3600000L;
|
||||
long days = (milliSeconds % (86400000L * 7L)) / 86400000L;
|
||||
|
||||
stringBuilder.setLength(0);
|
||||
return days > 0 ? stringFormatter.format("%d:%02d:%02d:%02d", days, hours, minutes, seconds).toString()
|
||||
: hours > 0 ? stringFormatter.format("%d:%02d:%02d", hours, minutes, seconds).toString()
|
||||
: stringFormatter.format("%02d:%02d", minutes, seconds).toString();
|
||||
}
|
||||
|
||||
public static String formatSpeed(float speed) {
|
||||
return speedFormatter.format(speed);
|
||||
}
|
||||
|
||||
public static String formatPitch(float pitch) {
|
||||
return pitchFormatter.format(pitch);
|
||||
}
|
||||
|
||||
public static boolean isResumeAfterAudioFocusGain(@NonNull final Context context) {
|
||||
return isResumeAfterAudioFocusGain(context, false);
|
||||
}
|
||||
|
||||
public static boolean isPlayerGestureEnabled(@NonNull final Context context) {
|
||||
return isPlayerGestureEnabled(context, true);
|
||||
}
|
||||
|
||||
public static boolean isUsingOldPlayer(@NonNull final Context context) {
|
||||
return isUsingOldPlayer(context, false);
|
||||
}
|
||||
|
||||
public static long getPreferredCacheSize(@NonNull final Context context) {
|
||||
return 64 * 1024 * 1024L;
|
||||
}
|
||||
|
||||
public static long getPreferredFileSize(@NonNull final Context context) {
|
||||
return 512 * 1024L;
|
||||
}
|
||||
|
||||
public static int getMinBufferMs(@NonNull final Context context) {
|
||||
return 15000;
|
||||
}
|
||||
|
||||
public static int getMaxBufferMs(@NonNull final Context context) {
|
||||
return 30000;
|
||||
}
|
||||
|
||||
public static long getBufferForPlaybackMs(@NonNull final Context context) {
|
||||
return 2500L;
|
||||
}
|
||||
|
||||
public static long getBufferForPlaybackAfterRebufferMs(@NonNull final Context context) {
|
||||
return 5000L;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
// Private helpers
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@NonNull
|
||||
private static SharedPreferences getPreferences(@NonNull final Context context) {
|
||||
return PreferenceManager.getDefaultSharedPreferences(context);
|
||||
}
|
||||
|
||||
private static boolean isResumeAfterAudioFocusGain(@NonNull final Context context, final boolean b) {
|
||||
return getPreferences(context).getBoolean(context.getString(R.string.resume_on_audio_focus_gain_key), b);
|
||||
}
|
||||
|
||||
private static boolean isPlayerGestureEnabled(@NonNull final Context context, final boolean b) {
|
||||
return getPreferences(context).getBoolean(context.getString(R.string.player_gesture_controls_key), b);
|
||||
}
|
||||
|
||||
private static boolean isUsingOldPlayer(@NonNull final Context context, final boolean b) {
|
||||
return getPreferences(context).getBoolean(context.getString(R.string.use_old_player_key), b);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user