mirror of
https://github.com/clangen/musikcube.git
synced 2024-10-02 04:52:32 +00:00
Addded a new setting to musikdroid that allows automatic playback
transfer from client to server when a headset is disconnected.
This commit is contained in:
parent
c87ea056dd
commit
a1cc7c5422
@ -0,0 +1,47 @@
|
||||
package io.casey.musikcube.remote.service.playback
|
||||
|
||||
import android.content.Context
|
||||
import io.casey.musikcube.remote.service.playback.impl.streaming.StreamingPlaybackService
|
||||
import io.casey.musikcube.remote.ui.shared.mixin.PlaybackMixin
|
||||
|
||||
sealed class Playback {
|
||||
enum class SwitchMode { Transfer, Copy, Swap }
|
||||
|
||||
companion object {
|
||||
fun transferPlayback(context: Context, mode: SwitchMode) {
|
||||
transferPlayback(context, PlaybackMixin(), mode)
|
||||
}
|
||||
|
||||
fun transferPlayback(context: Context, playback: PlaybackMixin, mode: SwitchMode) {
|
||||
val isStreaming = playback.service is StreamingPlaybackService
|
||||
|
||||
if (mode == SwitchMode.Swap) {
|
||||
if (isStreaming) {
|
||||
playback.service.pause()
|
||||
}
|
||||
}
|
||||
else {
|
||||
playback.connectAll()
|
||||
|
||||
val streaming = PlaybackServiceFactory.streaming(context)
|
||||
val remote = PlaybackServiceFactory.remote(context)
|
||||
|
||||
if (!isStreaming) {
|
||||
streaming.playFrom(remote)
|
||||
if (mode == SwitchMode.Transfer) {
|
||||
remote.pause()
|
||||
}
|
||||
}
|
||||
else {
|
||||
remote.playFrom(streaming)
|
||||
if (mode == SwitchMode.Transfer) {
|
||||
streaming.pause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
playback.reload()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,11 +16,11 @@ enum class PlaybackState constructor(private val rawValue: String) {
|
||||
else if (Playing.rawValue == rawValue) {
|
||||
return Playing
|
||||
}
|
||||
else if (Paused.rawValue == rawValue) {
|
||||
else if (Paused.rawValue == rawValue || "prepared" == rawValue) {
|
||||
return Paused
|
||||
}
|
||||
|
||||
throw IllegalArgumentException("rawValue matches invalid")
|
||||
throw IllegalArgumentException("rawValue '$rawValue' is unknown")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -24,6 +24,7 @@ import io.casey.musikcube.remote.Application
|
||||
import io.casey.musikcube.remote.R
|
||||
import io.casey.musikcube.remote.injection.GlideApp
|
||||
import io.casey.musikcube.remote.injection.GlideRequest
|
||||
import io.casey.musikcube.remote.service.playback.Playback
|
||||
import io.casey.musikcube.remote.service.playback.PlaybackServiceFactory
|
||||
import io.casey.musikcube.remote.service.playback.PlaybackState
|
||||
import io.casey.musikcube.remote.service.playback.impl.streaming.StreamingPlaybackService
|
||||
@ -475,7 +476,21 @@ class SystemService : Service() {
|
||||
private val headsetUnpluggedReceiver = object : BroadcastReceiver() {
|
||||
override fun onReceive(context: Context, intent: Intent) {
|
||||
if (intent.action == AudioManager.ACTION_AUDIO_BECOMING_NOISY) {
|
||||
playback?.pause()
|
||||
playback?.let { pb ->
|
||||
val switchOnDisconnect = prefs.getBoolean(
|
||||
Prefs.Key.TRANSFER_TO_SERVER_ON_HEADSET_DISCONNECT,
|
||||
Prefs.Default.TRANSFER_TO_SERVER_ON_HEADSET_DISCONNECT)
|
||||
|
||||
val isPlaying =
|
||||
(pb.state == PlaybackState.Playing) ||
|
||||
(pb.state == PlaybackState.Buffering)
|
||||
|
||||
pb.pause()
|
||||
|
||||
if (switchOnDisconnect && isPlaying) {
|
||||
Playback.transferPlayback(this@SystemService, Playback.SwitchMode.Transfer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -605,7 +605,7 @@ class WebSocketService constructor(private val context: Context) {
|
||||
private val AUTO_DISCONNECT_DELAY_MILLIS = 10000L
|
||||
private val FLAG_AUTHENTICATION_FAILED = 0xbeef
|
||||
private val WEBSOCKET_FLAG_POLICY_VIOLATION = 1008
|
||||
private val MINIMUM_SUPPORTED_API_VERSION = 14
|
||||
private val MINIMUM_SUPPORTED_API_VERSION = 15
|
||||
|
||||
private val MESSAGE_BASE = 0xcafedead.toInt()
|
||||
private val MESSAGE_CONNECT_THREAD_FINISHED = MESSAGE_BASE + 0
|
||||
|
@ -14,6 +14,7 @@ import android.view.*
|
||||
import android.widget.*
|
||||
import com.wooplr.spotlight.SpotlightView
|
||||
import io.casey.musikcube.remote.R
|
||||
import io.casey.musikcube.remote.service.playback.Playback
|
||||
import io.casey.musikcube.remote.service.playback.PlaybackServiceFactory
|
||||
import io.casey.musikcube.remote.service.playback.PlaybackState
|
||||
import io.casey.musikcube.remote.service.playback.RepeatMode
|
||||
@ -42,8 +43,6 @@ import io.casey.musikcube.remote.ui.shared.util.UpdateCheck
|
||||
import io.casey.musikcube.remote.ui.tracks.activity.TrackListActivity
|
||||
|
||||
class MainActivity : BaseActivity() {
|
||||
private enum class SwitchMode { Transfer, Copy, Swap }
|
||||
|
||||
private val handler = Handler()
|
||||
private var updateCheck: UpdateCheck = UpdateCheck()
|
||||
private var seekbarValue = -1
|
||||
@ -148,8 +147,8 @@ class MainActivity : BaseActivity() {
|
||||
|
||||
popup.setOnMenuItemClickListener { it ->
|
||||
when(it.itemId) {
|
||||
R.id.menu_switch_seamless -> togglePlaybackService(SwitchMode.Transfer)
|
||||
R.id.menu_switch_copy -> togglePlaybackService(SwitchMode.Copy)
|
||||
R.id.menu_switch_seamless -> togglePlaybackService(Playback.SwitchMode.Transfer)
|
||||
R.id.menu_switch_copy -> togglePlaybackService(Playback.SwitchMode.Copy)
|
||||
else -> { }
|
||||
}
|
||||
true
|
||||
@ -244,7 +243,7 @@ class MainActivity : BaseActivity() {
|
||||
Prefs.Key.STREAMING_PLAYBACK,
|
||||
Prefs.Default.STREAMING_PLAYBACK)
|
||||
|
||||
private fun togglePlaybackService(mode: SwitchMode = SwitchMode.Swap) {
|
||||
private fun togglePlaybackService(mode: Playback.SwitchMode = Playback.SwitchMode.Swap) {
|
||||
val isStreaming = isStreamingSelected
|
||||
prefs.edit().putBoolean(Prefs.Key.STREAMING_PLAYBACK, !isStreaming)?.apply()
|
||||
|
||||
@ -255,32 +254,7 @@ class MainActivity : BaseActivity() {
|
||||
|
||||
showSnackbar(mainLayout, messageId)
|
||||
|
||||
if (mode == SwitchMode.Swap) {
|
||||
if (isStreaming) {
|
||||
playback.service.pause()
|
||||
}
|
||||
}
|
||||
else {
|
||||
playback.connectAll()
|
||||
|
||||
val streaming = PlaybackServiceFactory.streaming(this)
|
||||
val remote = PlaybackServiceFactory.remote(this)
|
||||
|
||||
if (!isStreaming) {
|
||||
streaming.playFrom(remote)
|
||||
if (mode == SwitchMode.Transfer) {
|
||||
remote.pause()
|
||||
}
|
||||
}
|
||||
else {
|
||||
remote.playFrom(streaming)
|
||||
if (mode == SwitchMode.Transfer) {
|
||||
streaming.pause()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
playback.reload()
|
||||
Playback.transferPlayback(this, playback, mode)
|
||||
|
||||
invalidateOptionsMenu()
|
||||
rebindUi()
|
||||
|
@ -43,6 +43,7 @@ class SettingsActivity : BaseActivity() {
|
||||
private lateinit var softwareVolume: CheckBox
|
||||
private lateinit var sslCheckbox: CheckBox
|
||||
private lateinit var certCheckbox: CheckBox
|
||||
private lateinit var transferCheckbox: CheckBox
|
||||
private lateinit var bitrateSpinner: Spinner
|
||||
private lateinit var cacheSpinner: Spinner
|
||||
private lateinit var prefs: SharedPreferences
|
||||
@ -140,6 +141,10 @@ class SettingsActivity : BaseActivity() {
|
||||
Keys.DISK_CACHE_SIZE_INDEX, Defaults.DISK_CACHE_SIZE_INDEX))
|
||||
|
||||
/* advanced */
|
||||
transferCheckbox.isChecked = prefs.getBoolean(
|
||||
Keys.TRANSFER_TO_SERVER_ON_HEADSET_DISCONNECT,
|
||||
Defaults.TRANSFER_TO_SERVER_ON_HEADSET_DISCONNECT)
|
||||
|
||||
albumArtCheckbox.isChecked = prefs.getBoolean(
|
||||
Keys.LASTFM_ENABLED, Defaults.LASTFM_ENABLED)
|
||||
|
||||
@ -196,6 +201,7 @@ class SettingsActivity : BaseActivity() {
|
||||
this.cacheSpinner = findViewById(R.id.streaming_disk_cache_spinner)
|
||||
this.sslCheckbox = findViewById(R.id.ssl_checkbox)
|
||||
this.certCheckbox = findViewById(R.id.cert_validation)
|
||||
this.transferCheckbox = findViewById(R.id.transfer_on_disconnect_checkbox)
|
||||
}
|
||||
|
||||
private fun bindListeners() {
|
||||
@ -262,6 +268,7 @@ class SettingsActivity : BaseActivity() {
|
||||
.putBoolean(Keys.SOFTWARE_VOLUME, softwareVolume.isChecked)
|
||||
.putBoolean(Keys.SSL_ENABLED, sslCheckbox.isChecked)
|
||||
.putBoolean(Keys.CERT_VALIDATION_DISABLED, certCheckbox.isChecked)
|
||||
.putBoolean(Keys.TRANSFER_TO_SERVER_ON_HEADSET_DISCONNECT, transferCheckbox.isChecked)
|
||||
.putInt(Keys.TRANSCODER_BITRATE_INDEX, bitrateSpinner.selectedItemPosition)
|
||||
.putInt(Keys.DISK_CACHE_SIZE_INDEX, cacheSpinner.selectedItemPosition)
|
||||
.apply()
|
||||
|
@ -16,6 +16,7 @@ class Prefs {
|
||||
const val TRANSCODER_BITRATE_INDEX = "transcoder_bitrate_index"
|
||||
const val DISK_CACHE_SIZE_INDEX = "disk_cache_size_index"
|
||||
const val UPDATE_DIALOG_SUPPRESSED_VERSION = "update_dialog_suppressed_version"
|
||||
const val TRANSFER_TO_SERVER_ON_HEADSET_DISCONNECT = "transfer_to_server_on_headset_disconnect"
|
||||
const val DEVICE_ID = "device_id"
|
||||
}
|
||||
}
|
||||
@ -33,6 +34,7 @@ class Prefs {
|
||||
const val SSL_ENABLED = false
|
||||
const val CERT_VALIDATION_DISABLED = false
|
||||
const val TRANSCODER_BITRATE_INDEX = 0
|
||||
const val TRANSFER_TO_SERVER_ON_HEADSET_DISCONNECT = false
|
||||
const val DISK_CACHE_SIZE_INDEX = 2
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@ import io.casey.musikcube.remote.service.playback.IPlaybackService
|
||||
import io.casey.musikcube.remote.service.playback.PlaybackServiceFactory
|
||||
import io.casey.musikcube.remote.ui.settings.constants.Prefs
|
||||
|
||||
class PlaybackMixin(var listener: (() -> Unit)? = null): MixinBase() {
|
||||
class PlaybackMixin(var listener: (() -> Unit)? = { }): MixinBase() {
|
||||
private lateinit var prefs: SharedPreferences
|
||||
private val context = Application.instance!!
|
||||
|
||||
|
@ -176,6 +176,14 @@
|
||||
android:layout_marginBottom="8dp"
|
||||
android:text="@string/settings_advanced"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/transfer_on_disconnect_checkbox"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:textColor="@color/theme_foreground"
|
||||
android:layout_marginLeft="24dp"
|
||||
android:text="@string/settings_transfer_to_server_on_disconnect"/>
|
||||
|
||||
<CheckBox
|
||||
android:id="@+id/album_art_checkbox"
|
||||
android:layout_width="match_parent"
|
||||
|
@ -120,6 +120,7 @@
|
||||
<string name="settings_playback_engine_exo">ExoPlayer (stable)</string>
|
||||
<string name="settings_playback_engine_exo_gapless">ExoPlayer Gapless (default)</string>
|
||||
<string name="settings_playback_engine_mp">MediaPlayer (legacy)</string>
|
||||
<string name="settings_transfer_to_server_on_disconnect">transfer playback to server on headset disconnect</string>
|
||||
<string name="remote_settings_title">remote management</string>
|
||||
<string name="remote_settings_output_driver">output driver</string>
|
||||
<string name="remote_settings_output_device">output device</string>
|
||||
|
@ -1,5 +1,5 @@
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.2.10'
|
||||
ext.kotlin_version = '1.2.21'
|
||||
|
||||
repositories {
|
||||
jcenter()
|
||||
|
@ -216,7 +216,7 @@ namespace broadcast {
|
||||
static auto PLAYBACK_STATE_TO_STRING = makeBimap<musik::core::sdk::PlaybackState, std::string>({
|
||||
{ musik::core::sdk::PlaybackStopped, "stopped" },
|
||||
{ musik::core::sdk::PlaybackPlaying, "playing" },
|
||||
{ musik::core::sdk::PlaybackPrepared, "paused" },
|
||||
{ musik::core::sdk::PlaybackPrepared, "prepared" },
|
||||
{ musik::core::sdk::PlaybackPaused, "paused" }
|
||||
});
|
||||
|
||||
@ -237,4 +237,4 @@ static auto TRANSPORT_TYPE_TO_STRING = makeBimap<musik::core::sdk::TransportType
|
||||
{ musik::core::sdk::TransportType::Crossfade, "crossfade" },
|
||||
});
|
||||
|
||||
static const int ApiVersion = 14;
|
||||
static const int ApiVersion = 15;
|
||||
|
Loading…
Reference in New Issue
Block a user