Initialize some vals onCreate, thus making them explicitely non-null

Also modify setNextPlaying to accept only non-null files.
This commit is contained in:
tzugen 2021-03-24 13:28:54 +01:00
parent a467abf10b
commit d017ca9fb2
No known key found for this signature in database
GPG Key ID: 61E9C34BC10EC930
2 changed files with 65 additions and 62 deletions

View File

@ -305,7 +305,7 @@ public class MediaPlayerService extends Service
if (!gaplessPlayback) if (!gaplessPlayback)
{ {
localMediaPlayer.setNextPlaying(null); localMediaPlayer.clearNextPlaying(true);
return; return;
} }
@ -327,7 +327,7 @@ public class MediaPlayerService extends Service
} }
} }
localMediaPlayer.clearNextPlaying(); localMediaPlayer.clearNextPlaying(false);
if (index < downloader.downloadList.size() && index != -1) if (index < downloader.downloadList.size() && index != -1)
{ {
@ -335,7 +335,7 @@ public class MediaPlayerService extends Service
} }
else else
{ {
localMediaPlayer.setNextPlaying(null); localMediaPlayer.clearNextPlaying(true);
} }
} }

View File

@ -52,36 +52,32 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
private var nextPlayerState = PlayerState.IDLE private var nextPlayerState = PlayerState.IDLE
private var nextSetup = false private var nextSetup = false
private var nextPlayingTask: CancellableTask? = null private var nextPlayingTask: CancellableTask? = null
private val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager private var mediaPlayer: MediaPlayer = MediaPlayer()
private val wakeLock: WakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.javaClass.name)
private var mediaPlayer: MediaPlayer? = null
private var nextMediaPlayer: MediaPlayer? = null private var nextMediaPlayer: MediaPlayer? = null
private var mediaPlayerLooper: Looper? = null private var mediaPlayerLooper: Looper? = null
private var mediaPlayerHandler: Handler? = null private var mediaPlayerHandler: Handler? = null
private var cachedPosition = 0 private var cachedPosition = 0
private var proxy: StreamProxy? = null private var proxy: StreamProxy? = null
private var audioManager: AudioManager? = null private var audioManager: AudioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
private var remoteControlClient: RemoteControlClient? = null private var remoteControlClient: RemoteControlClient? = null
private var bufferTask: CancellableTask? = null private var bufferTask: CancellableTask? = null
private var positionCache: PositionCache? = null private var positionCache: PositionCache? = null
private var secondaryProgress = -1 private var secondaryProgress = -1
private val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager
private val wakeLock: WakeLock = pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, this.javaClass.name)
fun onCreate() { fun onCreate() {
if (mediaPlayer != null) {
mediaPlayer!!.release()
}
mediaPlayer = MediaPlayer()
Thread { Thread {
Thread.currentThread().name = "MediaPlayerThread" Thread.currentThread().name = "MediaPlayerThread"
Looper.prepare() Looper.prepare()
mediaPlayer!!.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK) mediaPlayer.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK)
mediaPlayer!!.setOnErrorListener { mediaPlayer, what, more -> mediaPlayer.setOnErrorListener { mediaPlayer, what, more ->
handleError(Exception(String.format(Locale.getDefault(), "MediaPlayer error: %d (%d)", what, more))) handleError(Exception(String.format(Locale.getDefault(), "MediaPlayer error: %d (%d)", what, more)))
false false
} }
try { try {
val i = Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION) val i = Intent(AudioEffect.ACTION_OPEN_AUDIO_EFFECT_CONTROL_SESSION)
i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mediaPlayer!!.audioSessionId) i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mediaPlayer.audioSessionId)
i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName) i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName)
context.sendBroadcast(i) context.sendBroadcast(i)
} catch (e: Throwable) { } catch (e: Throwable) {
@ -99,7 +95,6 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
}.start() }.start()
wakeLock.setReferenceCounted(false) wakeLock.setReferenceCounted(false)
audioManager = context.getSystemService(Context.AUDIO_SERVICE) as AudioManager
Util.registerMediaButtonEventReceiver(context, true) Util.registerMediaButtonEventReceiver(context, true)
setUpRemoteControlClient() setUpRemoteControlClient()
Timber.i("LocalMediaPlayer created") Timber.i("LocalMediaPlayer created")
@ -109,12 +104,12 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
reset() reset()
try { try {
val i = Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION) val i = Intent(AudioEffect.ACTION_CLOSE_AUDIO_EFFECT_CONTROL_SESSION)
i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mediaPlayer!!.audioSessionId) i.putExtra(AudioEffect.EXTRA_AUDIO_SESSION, mediaPlayer.audioSessionId)
i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName) i.putExtra(AudioEffect.EXTRA_PACKAGE_NAME, context.packageName)
context.sendBroadcast(i) context.sendBroadcast(i)
EqualizerController.release() EqualizerController.release()
VisualizerController.release() VisualizerController.release()
mediaPlayer!!.release() mediaPlayer.release()
if (nextMediaPlayer != null) { if (nextMediaPlayer != null) {
nextMediaPlayer!!.release() nextMediaPlayer!!.release()
} }
@ -125,7 +120,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
if (nextPlayingTask != null) { if (nextPlayingTask != null) {
nextPlayingTask!!.cancel() nextPlayingTask!!.cancel()
} }
audioManager!!.unregisterRemoteControlClient(remoteControlClient) audioManager.unregisterRemoteControlClient(remoteControlClient)
clearRemoteControl() clearRemoteControl()
Util.unregisterMediaButtonEventReceiver(context, true) Util.unregisterMediaButtonEventReceiver(context, true)
wakeLock.release() wakeLock.release()
@ -160,11 +155,15 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
} }
} }
/*
* Set the current playing file. It's called with null to reset the player.
*/
@Synchronized @Synchronized
fun setCurrentPlaying(currentPlaying: DownloadFile?) { fun setCurrentPlaying(currentPlaying: DownloadFile?) {
Timber.v("setCurrentPlaying %s", currentPlaying) Timber.v("setCurrentPlaying %s", currentPlaying)
this.currentPlaying = currentPlaying this.currentPlaying = currentPlaying
updateRemoteControl() updateRemoteControl()
if (onCurrentPlayingChanged != null) { if (onCurrentPlayingChanged != null) {
val mainHandler = Handler(context.mainLooper) val mainHandler = Handler(context.mainLooper)
val myRunnable = Runnable { onCurrentPlayingChanged!!.accept(currentPlaying) } val myRunnable = Runnable { onCurrentPlayingChanged!!.accept(currentPlaying) }
@ -172,26 +171,28 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
} }
} }
/*
* Set the next playing file.
*/
@Synchronized @Synchronized
fun setNextPlaying(nextToPlay: DownloadFile?) { fun setNextPlaying(nextToPlay: DownloadFile) {
if (nextToPlay == null) {
nextPlaying = null
setNextPlayerState(PlayerState.IDLE)
return
}
nextPlaying = nextToPlay nextPlaying = nextToPlay
nextPlayingTask = CheckCompletionTask(nextPlaying) nextPlayingTask = CheckCompletionTask(nextPlaying)
nextPlayingTask?.start() nextPlayingTask?.start()
} }
@Synchronized @Synchronized
fun clearNextPlaying() { fun clearNextPlaying(setIdle: Boolean) {
nextSetup = false nextSetup = false
nextPlaying = null nextPlaying = null
if (nextPlayingTask != null) { if (nextPlayingTask != null) {
nextPlayingTask!!.cancel() nextPlayingTask!!.cancel()
nextPlayingTask = null nextPlayingTask = null
} }
if (setIdle) {
setNextPlayerState(PlayerState.IDLE)
}
} }
@Synchronized @Synchronized
@ -223,12 +224,14 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
@Synchronized @Synchronized
fun playNext() { fun playNext() {
if (nextMediaPlayer == null || currentPlaying == null) return
val tmp = mediaPlayer val tmp = mediaPlayer
mediaPlayer = nextMediaPlayer mediaPlayer = nextMediaPlayer!!
nextMediaPlayer = tmp nextMediaPlayer = tmp
setCurrentPlaying(nextPlaying) setCurrentPlaying(nextPlaying)
setPlayerState(PlayerState.STARTED) setPlayerState(PlayerState.STARTED)
setupHandlers(currentPlaying, false) attachHandlersToPlayer(mediaPlayer, currentPlaying!!, false)
if (onNextSongRequested != null) { if (onNextSongRequested != null) {
val mainHandler = Handler(context.mainLooper) val mainHandler = Handler(context.mainLooper)
val myRunnable = Runnable { onNextSongRequested!!.run() } val myRunnable = Runnable { onNextSongRequested!!.run() }
@ -236,16 +239,14 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
} }
// Proxy should not be being used here since the next player was already setup to play // Proxy should not be being used here since the next player was already setup to play
if (proxy != null) { proxy?.stop()
proxy!!.stop() proxy = null
proxy = null
}
} }
@Synchronized @Synchronized
fun pause() { fun pause() {
try { try {
mediaPlayer!!.pause() mediaPlayer.pause()
} catch (x: Exception) { } catch (x: Exception) {
handleError(x) handleError(x)
} }
@ -254,7 +255,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
@Synchronized @Synchronized
fun start() { fun start() {
try { try {
mediaPlayer!!.start() mediaPlayer.start()
} catch (x: Exception) { } catch (x: Exception) {
handleError(x) handleError(x)
} }
@ -266,8 +267,8 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
return return
} }
if (remoteControlClient != null) { if (remoteControlClient != null) {
audioManager!!.unregisterRemoteControlClient(remoteControlClient) audioManager.unregisterRemoteControlClient(remoteControlClient)
audioManager!!.registerRemoteControlClient(remoteControlClient) audioManager.registerRemoteControlClient(remoteControlClient)
} else { } else {
setUpRemoteControlClient() setUpRemoteControlClient()
} }
@ -308,7 +309,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
fun clearRemoteControl() { fun clearRemoteControl() {
if (remoteControlClient != null) { if (remoteControlClient != null) {
remoteControlClient!!.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED) remoteControlClient!!.setPlaybackState(RemoteControlClient.PLAYSTATE_STOPPED)
audioManager!!.unregisterRemoteControlClient(remoteControlClient) audioManager.unregisterRemoteControlClient(remoteControlClient)
remoteControlClient = null remoteControlClient = null
} }
} }
@ -321,7 +322,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
mediaButtonIntent.component = componentName mediaButtonIntent.component = componentName
val broadcast = PendingIntent.getBroadcast(context, 0, mediaButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT) val broadcast = PendingIntent.getBroadcast(context, 0, mediaButtonIntent, PendingIntent.FLAG_UPDATE_CURRENT)
remoteControlClient = RemoteControlClient(broadcast) remoteControlClient = RemoteControlClient(broadcast)
audioManager!!.registerRemoteControlClient(remoteControlClient) audioManager.registerRemoteControlClient(remoteControlClient)
// Flags for the media transport control that this client supports. // Flags for the media transport control that this client supports.
var flags = RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS or var flags = RemoteControlClient.FLAG_KEY_MEDIA_PREVIOUS or
@ -332,7 +333,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
RemoteControlClient.FLAG_KEY_MEDIA_STOP RemoteControlClient.FLAG_KEY_MEDIA_STOP
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2) {
flags = flags or RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE flags = flags or RemoteControlClient.FLAG_KEY_MEDIA_POSITION_UPDATE
remoteControlClient!!.setOnGetPlaybackPositionListener { mediaPlayer!!.currentPosition.toLong() } remoteControlClient!!.setOnGetPlaybackPositionListener { mediaPlayer.currentPosition.toLong() }
remoteControlClient!!.setPlaybackPositionUpdateListener { newPositionMs -> seekTo(newPositionMs.toInt()) } remoteControlClient!!.setPlaybackPositionUpdateListener { newPositionMs -> seekTo(newPositionMs.toInt()) }
} }
remoteControlClient!!.setTransportControlFlags(flags) remoteControlClient!!.setTransportControlFlags(flags)
@ -342,7 +343,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
@Synchronized @Synchronized
fun seekTo(position: Int) { fun seekTo(position: Int) {
try { try {
mediaPlayer!!.seekTo(position) mediaPlayer.seekTo(position)
cachedPosition = position cachedPosition = position
updateRemoteControl() updateRemoteControl()
} catch (x: Exception) { } catch (x: Exception) {
@ -372,7 +373,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
} }
if (playerState !== PlayerState.IDLE && playerState !== PlayerState.DOWNLOADING && playerState !== PlayerState.PREPARING) { if (playerState !== PlayerState.IDLE && playerState !== PlayerState.DOWNLOADING && playerState !== PlayerState.PREPARING) {
try { try {
return mediaPlayer!!.duration return mediaPlayer.duration
} catch (x: Exception) { } catch (x: Exception) {
handleError(x) handleError(x)
} }
@ -382,7 +383,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
fun setVolume(volume: Float) { fun setVolume(volume: Float) {
if (mediaPlayer != null) { if (mediaPlayer != null) {
mediaPlayer!!.setVolume(volume, volume) mediaPlayer.setVolume(volume, volume)
} }
} }
@ -394,11 +395,11 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
val file = if (downloadFile.isCompleteFileAvailable) downloadFile.completeFile else downloadFile.partialFile val file = if (downloadFile.isCompleteFileAvailable) downloadFile.completeFile else downloadFile.partialFile
val partial = file == downloadFile.partialFile val partial = file == downloadFile.partialFile
downloadFile.updateModificationDate() downloadFile.updateModificationDate()
mediaPlayer!!.setOnCompletionListener(null) mediaPlayer.setOnCompletionListener(null)
secondaryProgress = -1 // Ensure seeking in non StreamProxy playback works secondaryProgress = -1 // Ensure seeking in non StreamProxy playback works
mediaPlayer!!.reset() mediaPlayer.reset()
setPlayerState(PlayerState.IDLE) setPlayerState(PlayerState.IDLE)
mediaPlayer!!.setAudioStreamType(AudioManager.STREAM_MUSIC) mediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC)
var dataSource = file.path var dataSource = file.path
if (partial) { if (partial) {
if (proxy == null) { if (proxy == null) {
@ -417,9 +418,9 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
proxy = null proxy = null
} }
Timber.i("Preparing media player") Timber.i("Preparing media player")
mediaPlayer!!.setDataSource(dataSource) mediaPlayer.setDataSource(dataSource)
setPlayerState(PlayerState.PREPARING) setPlayerState(PlayerState.PREPARING)
mediaPlayer!!.setOnBufferingUpdateListener { mp, percent -> mediaPlayer.setOnBufferingUpdateListener { mp, percent ->
val progressBar = PlayerFragment.getProgressBar() val progressBar = PlayerFragment.getProgressBar()
val song = downloadFile.song val song = downloadFile.song
if (percent == 100) { if (percent == 100) {
@ -432,7 +433,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
progressBar.secondaryProgress = secondaryProgress progressBar.secondaryProgress = secondaryProgress
} }
} }
mediaPlayer!!.setOnPreparedListener { mediaPlayer.setOnPreparedListener {
Timber.i("Media player prepared") Timber.i("Media player prepared")
setPlayerState(PlayerState.PREPARED) setPlayerState(PlayerState.PREPARED)
val progressBar = PlayerFragment.getProgressBar() val progressBar = PlayerFragment.getProgressBar()
@ -447,7 +448,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
} }
cachedPosition = position cachedPosition = position
if (start) { if (start) {
mediaPlayer!!.start() mediaPlayer.start()
setPlayerState(PlayerState.STARTED) setPlayerState(PlayerState.STARTED)
} else { } else {
setPlayerState(PlayerState.PAUSED) setPlayerState(PlayerState.PAUSED)
@ -459,8 +460,8 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
mainHandler.post(myRunnable) mainHandler.post(myRunnable)
} }
} }
setupHandlers(downloadFile, partial) attachHandlersToPlayer(mediaPlayer, downloadFile, partial)
mediaPlayer!!.prepareAsync() mediaPlayer.prepareAsync()
} catch (x: Exception) { } catch (x: Exception) {
handleError(x) handleError(x)
} }
@ -478,7 +479,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
nextMediaPlayer = MediaPlayer() nextMediaPlayer = MediaPlayer()
nextMediaPlayer!!.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK) nextMediaPlayer!!.setWakeMode(context, PowerManager.PARTIAL_WAKE_LOCK)
try { try {
nextMediaPlayer!!.audioSessionId = mediaPlayer!!.audioSessionId nextMediaPlayer!!.audioSessionId = mediaPlayer.audioSessionId
} catch (e: Throwable) { } catch (e: Throwable) {
nextMediaPlayer!!.setAudioStreamType(AudioManager.STREAM_MUSIC) nextMediaPlayer!!.setAudioStreamType(AudioManager.STREAM_MUSIC)
} }
@ -488,7 +489,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
try { try {
setNextPlayerState(PlayerState.PREPARED) setNextPlayerState(PlayerState.PREPARED)
if (Util.getGaplessPlaybackPreference(context) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && (playerState === PlayerState.STARTED || playerState === PlayerState.PAUSED)) { if (Util.getGaplessPlaybackPreference(context) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN && (playerState === PlayerState.STARTED || playerState === PlayerState.PAUSED)) {
mediaPlayer!!.setNextMediaPlayer(nextMediaPlayer) mediaPlayer.setNextMediaPlayer(nextMediaPlayer)
nextSetup = true nextSetup = true
} }
} catch (x: Exception) { } catch (x: Exception) {
@ -505,18 +506,20 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
} }
} }
private fun setupHandlers(downloadFile: DownloadFile?, isPartial: Boolean) { private fun attachHandlersToPlayer(mediaPlayer: MediaPlayer, downloadFile: DownloadFile, isPartial: Boolean) {
mediaPlayer!!.setOnErrorListener { mediaPlayer, what, extra -> mediaPlayer.setOnErrorListener { _, what, extra ->
Timber.w("Error on playing file (%d, %d): %s", what, extra, downloadFile) Timber.w("Error on playing file (%d, %d): %s", what, extra, downloadFile)
val pos = cachedPosition val pos = cachedPosition
reset() reset()
downloadFile!!.setPlaying(false) downloadFile.setPlaying(false)
doPlay(downloadFile, pos, true) doPlay(downloadFile, pos, true)
downloadFile.setPlaying(true) downloadFile.setPlaying(true)
true true
} }
val duration = if (downloadFile!!.song.duration == null) 0 else downloadFile.song.duration!! * 1000
mediaPlayer!!.setOnCompletionListener(object : OnCompletionListener { val duration = if (downloadFile.song.duration == null) 0 else downloadFile.song.duration!! * 1000
mediaPlayer.setOnCompletionListener(object : OnCompletionListener {
override fun onCompletion(mediaPlayer: MediaPlayer) { override fun onCompletion(mediaPlayer: MediaPlayer) {
// Acquire a temporary wakelock, since when we return from // Acquire a temporary wakelock, since when we return from
// this callback the MediaPlayer will release its wakelock // this callback the MediaPlayer will release its wakelock
@ -566,9 +569,9 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
} }
try { try {
setPlayerState(PlayerState.IDLE) setPlayerState(PlayerState.IDLE)
mediaPlayer!!.setOnErrorListener(null) mediaPlayer.setOnErrorListener(null)
mediaPlayer!!.setOnCompletionListener(null) mediaPlayer.setOnCompletionListener(null)
mediaPlayer!!.reset() mediaPlayer.reset()
} catch (x: Exception) { } catch (x: Exception) {
handleError(x) handleError(x)
} }
@ -669,7 +672,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
while (isRunning) { while (isRunning) {
try { try {
if (mediaPlayer != null && playerState === PlayerState.STARTED) { if (mediaPlayer != null && playerState === PlayerState.STARTED) {
cachedPosition = mediaPlayer!!.currentPosition cachedPosition = mediaPlayer.currentPosition
} }
Util.sleepQuietly(50L) Util.sleepQuietly(50L)
} catch (e: Exception) { } catch (e: Exception) {
@ -684,7 +687,7 @@ class LocalMediaPlayer(private val audioFocusHandler: AudioFocusHandler, private
private fun handleError(x: Exception) { private fun handleError(x: Exception) {
Timber.w(x, "Media player error") Timber.w(x, "Media player error")
try { try {
mediaPlayer!!.reset() mediaPlayer.reset()
} catch (ex: Exception) { } catch (ex: Exception) {
Timber.w(ex, "Exception encountered when resetting media player") Timber.w(ex, "Exception encountered when resetting media player")
} }