From 0a6851544ecf190fe1e9dc8e6122f1686071f52c Mon Sep 17 00:00:00 2001 From: casey langen Date: Tue, 21 Nov 2017 14:31:07 -0800 Subject: [PATCH] Added the ability to select playback engine (ExoPlayer, ExoPlayer Gapless, or MediaPlayer). --- .../remote/service/playback/PlayerWrapper.kt | 28 +++++++++--- .../streaming/StreamingPlaybackService.kt | 4 +- .../ui/settings/activity/SettingsActivity.kt | 43 ++++++++++++++++--- .../remote/ui/settings/constants/Prefs.kt | 2 + .../src/main/res/layout/activity_settings.xml | 17 ++++++++ .../src/main/res/values/playback_engines.xml | 8 ++++ .../app/src/main/res/values/strings.xml | 5 ++- 7 files changed, 94 insertions(+), 13 deletions(-) create mode 100644 src/musikdroid/app/src/main/res/values/playback_engines.xml diff --git a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/service/playback/PlayerWrapper.kt b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/service/playback/PlayerWrapper.kt index 4a0a10cac..0cc847180 100644 --- a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/service/playback/PlayerWrapper.kt +++ b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/service/playback/PlayerWrapper.kt @@ -1,11 +1,13 @@ package io.casey.musikcube.remote.service.playback +import android.content.SharedPreferences import io.casey.musikcube.remote.Application import io.casey.musikcube.remote.service.playback.impl.player.ExoPlayerWrapper import io.casey.musikcube.remote.service.playback.impl.player.GaplessExoPlayerWrapper import io.casey.musikcube.remote.service.playback.impl.player.MediaPlayerWrapper import io.casey.musikcube.remote.service.playback.impl.streaming.offline.OfflineTrack import io.casey.musikcube.remote.service.websocket.model.ITrack +import io.casey.musikcube.remote.ui.settings.constants.Prefs import io.casey.musikcube.remote.util.Preconditions import io.reactivex.Single import io.reactivex.android.schedulers.AndroidSchedulers @@ -13,8 +15,17 @@ import io.reactivex.schedulers.Schedulers import java.util.* abstract class PlayerWrapper { - private enum class Type { - MediaPlayer, ExoPlayer + private enum class Type(prefIndex: Int) { + ExoPlayer(0), ExoPlayerGapless(1), MediaPlayer(2); + + companion object { + fun fromPrefIndex(index: Int): Type = + when(index) { + 2 -> MediaPlayer + 1 -> ExoPlayerGapless + else -> ExoPlayer + } + } } enum class State { @@ -140,9 +151,16 @@ abstract class PlayerWrapper { } } - fun newInstance(): PlayerWrapper { - return if (TYPE == Type.ExoPlayer) - GaplessExoPlayerWrapper() else MediaPlayerWrapper() + fun newInstance(prefs: SharedPreferences): PlayerWrapper { + val type = prefs.getInt( + Prefs.Key.PLAYBACK_ENGINE_INDEX, + Prefs.Default.PLAYBACK_ENGINE_INDEX) + + return when (Type.fromPrefIndex(type)) { + Type.ExoPlayer -> ExoPlayerWrapper() + Type.ExoPlayerGapless -> GaplessExoPlayerWrapper() + Type.MediaPlayer -> MediaPlayerWrapper() + } } fun addActivePlayer(player: PlayerWrapper) { diff --git a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/service/playback/impl/streaming/StreamingPlaybackService.kt b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/service/playback/impl/streaming/StreamingPlaybackService.kt index 71fbddd0f..b190a3d30 100644 --- a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/service/playback/impl/streaming/StreamingPlaybackService.kt +++ b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/service/playback/impl/streaming/StreamingPlaybackService.kt @@ -621,7 +621,7 @@ class StreamingPlaybackService(context: Context) : IPlaybackService { if (uri != null && uri != playContext.nextPlayer?.uri) { playContext.reset(playContext.nextPlayer) - playContext.nextPlayer = PlayerWrapper.newInstance() + playContext.nextPlayer = PlayerWrapper.newInstance(prefs) playContext.nextPlayer?.setOnStateChangedListener(onNextPlayerStateChanged) playContext.nextPlayer?.prefetch(uri, playContext.nextMetadata!!) } @@ -720,7 +720,7 @@ class StreamingPlaybackService(context: Context) : IPlaybackService { val uri = getUri(playContext.currentMetadata) if (uri != null) { - playContext.currentPlayer = PlayerWrapper.newInstance() + playContext.currentPlayer = PlayerWrapper.newInstance(prefs) playContext.currentPlayer?.setOnStateChangedListener(onCurrentPlayerStateChanged) playContext.currentPlayer?.play(uri, playContext.currentMetadata!!) } diff --git a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/settings/activity/SettingsActivity.kt b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/settings/activity/SettingsActivity.kt index fe4604c0d..e2ee80128 100644 --- a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/settings/activity/SettingsActivity.kt +++ b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/settings/activity/SettingsActivity.kt @@ -24,6 +24,7 @@ import io.casey.musikcube.remote.ui.settings.model.Connection import io.casey.musikcube.remote.ui.shared.activity.BaseActivity import io.casey.musikcube.remote.ui.shared.extension.* import io.casey.musikcube.remote.ui.shared.mixin.DataProviderMixin +import io.casey.musikcube.remote.ui.shared.mixin.PlaybackMixin import java.util.* import io.casey.musikcube.remote.ui.settings.constants.Prefs.Default as Defaults import io.casey.musikcube.remote.ui.settings.constants.Prefs.Key as Keys @@ -40,11 +41,16 @@ class SettingsActivity : BaseActivity() { private lateinit var certCheckbox: CheckBox private lateinit var bitrateSpinner: Spinner private lateinit var cacheSpinner: Spinner + private lateinit var playbackEngineSpinner: Spinner private lateinit var prefs: SharedPreferences + private lateinit var playback: PlaybackMixin private lateinit var data: DataProviderMixin + private var engineType = -1 + override fun onCreate(savedInstanceState: Bundle?) { data = mixin(DataProviderMixin()) + playback = mixin(PlaybackMixin()) component.inject(this) super.onCreate(savedInstanceState) prefs = this.getSharedPreferences(Prefs.NAME, Context.MODE_PRIVATE) @@ -116,16 +122,31 @@ class SettingsActivity : BaseActivity() { bitrateSpinner.setSelection(prefs.getInt( Keys.TRANSCODER_BITRATE_INDEX, Defaults.TRANSCODER_BITRATE_INDEX)) + /* disk cache */ val cacheSizes = ArrayAdapter.createFromResource( this, R.array.disk_cache_array, android.R.layout.simple_spinner_item) - /* disk cache */ cacheSizes.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) cacheSpinner.adapter = cacheSizes cacheSpinner.setSelection(prefs.getInt( Keys.DISK_CACHE_SIZE_INDEX, Defaults.DISK_CACHE_SIZE_INDEX)) + /* playback engine */ + val engines = ArrayAdapter.createFromResource( + this, R.array.playback_engine_array, android.R.layout.simple_spinner_item) + + engines.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item) + + val engineType = prefs.getInt(Keys.PLAYBACK_ENGINE_INDEX, Defaults.PLAYBACK_ENGINE_INDEX) + + if (this.engineType == -1) { + this.engineType = engineType + } + + playbackEngineSpinner.adapter = engines + playbackEngineSpinner.setSelection(engineType) + /* advanced */ albumArtCheckbox.isChecked = prefs.getBoolean( Keys.LASTFM_ENABLED, Defaults.LASTFM_ENABLED) @@ -165,8 +186,8 @@ class SettingsActivity : BaseActivity() { if (value) { if (!dialogVisible(DisableCertValidationAlertDialog.TAG)) { showDialog( - DisableCertValidationAlertDialog.newInstance(), - DisableCertValidationAlertDialog.TAG) + DisableCertValidationAlertDialog.newInstance(), + DisableCertValidationAlertDialog.TAG) } } } @@ -181,6 +202,7 @@ class SettingsActivity : BaseActivity() { this.softwareVolume = findViewById(R.id.software_volume) this.bitrateSpinner = findViewById(R.id.transcoder_bitrate_spinner) this.cacheSpinner = findViewById(R.id.streaming_disk_cache_spinner) + this.playbackEngineSpinner = findViewById(R.id.streaming_playback_engine) this.sslCheckbox = findViewById(R.id.ssl_checkbox) this.certCheckbox = findViewById(R.id.cert_validation) } @@ -192,8 +214,8 @@ class SettingsActivity : BaseActivity() { findViewById(R.id.button_load).setOnClickListener{_ -> startActivityForResult( - ConnectionsActivity.getStartIntent(this), - CONNECTIONS_REQUEST_CODE) + ConnectionsActivity.getStartIntent(this), + CONNECTIONS_REQUEST_CODE) } } @@ -239,6 +261,12 @@ class SettingsActivity : BaseActivity() { val password = passwordText.text.toString() try { + val engineType = playbackEngineSpinner.selectedItemPosition + + val streaming = prefs.getBoolean( + Prefs.Key.STREAMING_PLAYBACK, + Prefs.Default.STREAMING_PLAYBACK) + prefs.edit() .putString(Keys.ADDRESS, addr) .putInt(Keys.MAIN_PORT, if (port.isNotEmpty()) port.toInt() else 0) @@ -251,12 +279,17 @@ class SettingsActivity : BaseActivity() { .putBoolean(Keys.CERT_VALIDATION_DISABLED, certCheckbox.isChecked) .putInt(Keys.TRANSCODER_BITRATE_INDEX, bitrateSpinner.selectedItemPosition) .putInt(Keys.DISK_CACHE_SIZE_INDEX, cacheSpinner.selectedItemPosition) + .putInt(Keys.PLAYBACK_ENGINE_INDEX, engineType) .apply() if (!softwareVolume.isChecked) { PlayerWrapper.setVolume(1.0f) } + if (streaming && engineType != this.engineType) { + playback.service.stop() + } + StreamProxy.reload() data.wss.disconnect() diff --git a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/settings/constants/Prefs.kt b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/settings/constants/Prefs.kt index 61554cd1c..572a15250 100644 --- a/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/settings/constants/Prefs.kt +++ b/src/musikdroid/app/src/main/java/io/casey/musikcube/remote/ui/settings/constants/Prefs.kt @@ -16,6 +16,7 @@ class Prefs { val TRANSCODER_BITRATE_INDEX = "transcoder_bitrate_index" val DISK_CACHE_SIZE_INDEX = "disk_cache_size_index" val UPDATE_DIALOG_SUPPRESSED_VERSION = "update_dialog_suppressed_version" + val PLAYBACK_ENGINE_INDEX = "playback_engine_index" } } @@ -33,6 +34,7 @@ class Prefs { val CERT_VALIDATION_DISABLED = false val TRANSCODER_BITRATE_INDEX = 0 val DISK_CACHE_SIZE_INDEX = 2 + val PLAYBACK_ENGINE_INDEX = 0 } } diff --git a/src/musikdroid/app/src/main/res/layout/activity_settings.xml b/src/musikdroid/app/src/main/res/layout/activity_settings.xml index 17f41b6e8..6fd405001 100644 --- a/src/musikdroid/app/src/main/res/layout/activity_settings.xml +++ b/src/musikdroid/app/src/main/res/layout/activity_settings.xml @@ -168,6 +168,23 @@ android:layout_width="0dp" android:layout_height="16dp"/> + + + + + + + + + @string/settings_playback_engine_exo + @string/settings_playback_engine_exo_gapless + @string/settings_playback_engine_mp + + \ No newline at end of file diff --git a/src/musikdroid/app/src/main/res/values/strings.xml b/src/musikdroid/app/src/main/res/values/strings.xml index 0dc0dd41d..916aa8fc3 100644 --- a/src/musikdroid/app/src/main/res/values/strings.xml +++ b/src/musikdroid/app/src/main/res/values/strings.xml @@ -106,6 +106,10 @@ one or more connection fields are invalid.\n\nensure you\'ve entered a hostname and port numbers. confirm delete are you sure you want to delete \'%s\'? + playback engine + ExoPlayer (stable) + ExoPlayer Gapless (experimental) + MediaPlayer (deprecated) no saved connection presets. show offline songs oops, you don\'t seem to have any songs available offline.\n\nnext time you\'re connected, stream some music! @@ -135,5 +139,4 @@ could not create playlist \'%s\' playlist \'%s\' deleted could not delete playlist \'%s\' -