Added the ability to select playback engine (ExoPlayer, ExoPlayer

Gapless, or MediaPlayer).
This commit is contained in:
casey langen 2017-11-21 14:31:07 -08:00
parent b065751b0a
commit 0a6851544e
7 changed files with 94 additions and 13 deletions

View File

@ -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) {

View File

@ -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!!)
}

View File

@ -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<View>(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()

View File

@ -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
}
}

View File

@ -168,6 +168,23 @@
android:layout_width="0dp"
android:layout_height="16dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginRight="8dp"
android:text="@string/settings_playback_engine"/>
<Spinner
android:id="@+id/streaming_playback_engine"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="24dp"/>
<android.support.v4.widget.Space
android:layout_width="0dp"
android:layout_height="16dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"

View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string-array name="playback_engine_array">
<item>@string/settings_playback_engine_exo</item>
<item>@string/settings_playback_engine_exo_gapless</item>
<item>@string/settings_playback_engine_mp</item>
</string-array>
</resources>

View File

@ -106,6 +106,10 @@
<string name="settings_invalid_connection_no_name_message">one or more connection fields are invalid.\n\nensure you\'ve entered a hostname and port numbers.</string>
<string name="settings_confirm_delete_title">confirm delete</string>
<string name="settings_confirm_delete_message">are you sure you want to delete \'%s\'?</string>
<string name="settings_playback_engine">playback engine</string>
<string name="settings_playback_engine_exo">ExoPlayer (stable)</string>
<string name="settings_playback_engine_exo_gapless">ExoPlayer Gapless (experimental)</string>
<string name="settings_playback_engine_mp">MediaPlayer (deprecated)</string>
<string name="connections_no_presets">no saved connection presets.</string>
<string name="empty_show_offline_tracks_button">show offline songs</string>
<string name="empty_no_offline_tracks_message">oops, you don\'t seem to have any songs available offline.\n\nnext time you\'re connected, stream some music!</string>
@ -135,5 +139,4 @@
<string name="playlist_not_created">could not create playlist \'%s\'</string>
<string name="playlist_deleted">playlist \'%s\' deleted</string>
<string name="playlist_not_deleted">could not delete playlist \'%s\'</string>
</resources>