mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2026-07-24 13:38:37 +02:00
Merge pull request #1738 from eagleeyetom/chromecast-volume-fix-updated
Android cast: stabilize MediaSession volume handling; simplify Google…
This commit is contained in:
@@ -3,6 +3,7 @@ package com.audiobookshelf.app.player
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Looper
|
||||
import android.util.Log
|
||||
import kotlin.math.roundToInt
|
||||
import android.view.Surface
|
||||
import android.view.SurfaceHolder
|
||||
import android.view.SurfaceView
|
||||
@@ -53,6 +54,10 @@ class CastPlayer(var castContext: CastContext) : BasePlayer() {
|
||||
private var myCurrentTrackGroups: TrackGroupArray
|
||||
private var myCurrentTrackSelections: TrackSelectionArray
|
||||
|
||||
// Cache for pending volume to handle async setVolume
|
||||
private var pendingVolume: Int? = null
|
||||
private var pendingVolumeSetAt: Long = 0L
|
||||
|
||||
var currentMediaItems:List<MediaItem> = mutableListOf()
|
||||
var remoteMediaClient:RemoteMediaClient? = null
|
||||
var sessionAvailabilityListener:SessionAvailabilityListener? = null
|
||||
@@ -864,12 +869,24 @@ class CastPlayer(var castContext: CastContext) : BasePlayer() {
|
||||
}
|
||||
|
||||
override fun getDeviceVolume(): Int {
|
||||
// Short-lived cache without even-value quantization
|
||||
val now = System.currentTimeMillis()
|
||||
if (pendingVolume != null && (now - pendingVolumeSetAt) < 100) {
|
||||
return pendingVolume!!
|
||||
}
|
||||
|
||||
val session = castContext.sessionManager.currentCastSession
|
||||
return if (session != null && !session.isMute) {
|
||||
(session.volume * 100).toInt()
|
||||
val vol = if (session != null && !session.isMute) {
|
||||
(session.volume * 100).roundToInt().coerceIn(0, 100)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
|
||||
if (pendingVolume != null && vol == pendingVolume) {
|
||||
pendingVolume = null
|
||||
}
|
||||
|
||||
return vol
|
||||
}
|
||||
|
||||
override fun isDeviceMuted(): Boolean {
|
||||
@@ -881,22 +898,28 @@ class CastPlayer(var castContext: CastContext) : BasePlayer() {
|
||||
val session = castContext.sessionManager.currentCastSession
|
||||
try {
|
||||
val clamped = volume.coerceIn(0, 100)
|
||||
session?.volume = clamped / 100.0
|
||||
val target = (clamped / 100.0).let { kotlin.math.round(it * 100.0) / 100.0 }
|
||||
|
||||
// Cache for 100ms to return in getDeviceVolume during async period
|
||||
pendingVolume = clamped
|
||||
pendingVolumeSetAt = System.currentTimeMillis()
|
||||
|
||||
session?.setVolume(target)
|
||||
} catch (e: Exception) {
|
||||
Log.e(tag, "Failed to set cast device volume", e)
|
||||
}
|
||||
}
|
||||
|
||||
override fun increaseDeviceVolume() {
|
||||
val currentVolume = getDeviceVolume()
|
||||
val newVolume = (currentVolume + 1).coerceAtMost(100)
|
||||
setDeviceVolume(newVolume)
|
||||
val current = getDeviceVolume()
|
||||
val next = current + 1
|
||||
setDeviceVolume(next.coerceAtMost(100))
|
||||
}
|
||||
|
||||
override fun decreaseDeviceVolume() {
|
||||
val currentVolume = getDeviceVolume()
|
||||
val newVolume = (currentVolume - 1).coerceAtLeast(0)
|
||||
setDeviceVolume(newVolume)
|
||||
val current = getDeviceVolume()
|
||||
val next = current - 1
|
||||
setDeviceVolume(next.coerceAtLeast(0))
|
||||
}
|
||||
|
||||
override fun setDeviceMuted(muted: Boolean) {
|
||||
|
||||
+10
-21
@@ -736,32 +736,21 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
||||
}
|
||||
|
||||
private fun setMediaSessionToCastVolume() {
|
||||
val currentVol = try { castPlayer?.getDeviceVolume() ?: 0 } catch (e: Exception) { 0 }
|
||||
val currentVol = try { castPlayer?.getDeviceVolume() ?: 0 } catch (_: Exception) { 0 }
|
||||
val provider = object : VolumeProviderCompat(VolumeProviderCompat.VOLUME_CONTROL_ABSOLUTE, 100, currentVol) {
|
||||
override fun onSetVolumeTo(volume: Int) {
|
||||
// Clamp, update UI immediately, then send to device
|
||||
val clamped = volume.coerceIn(0, 100)
|
||||
try {
|
||||
castPlayer?.setDeviceVolume(clamped)
|
||||
val actual = castPlayer?.getDeviceVolume() ?: clamped
|
||||
setCurrentVolume(actual)
|
||||
} catch (_: Exception) {}
|
||||
setCurrentVolume(clamped)
|
||||
try { castPlayer?.setDeviceVolume(clamped) } catch (_: Exception) {}
|
||||
}
|
||||
|
||||
override fun onAdjustVolume(direction: Int) {
|
||||
val current = try { castPlayer?.getDeviceVolume() ?: currentVolume } catch (_: Exception) { currentVolume }
|
||||
val step = if (direction > 0) 1 else if (direction < 0) -1 else 0
|
||||
if (step == 0) return
|
||||
var target = (current + step).coerceIn(0, 100)
|
||||
try {
|
||||
castPlayer?.setDeviceVolume(target)
|
||||
var actual = castPlayer?.getDeviceVolume() ?: current
|
||||
// If device ignored tiny step, try nudging up to 3 steps total.
|
||||
if (actual == current) {
|
||||
target = (current + step * 3).coerceIn(0, 100)
|
||||
castPlayer?.setDeviceVolume(target)
|
||||
actual = castPlayer?.getDeviceVolume() ?: current
|
||||
}
|
||||
setCurrentVolume(actual)
|
||||
} catch (_: Exception) {}
|
||||
// Use Android-provided step (−1, 0, +1). Clamp, update UI immediately, then send.
|
||||
val current = currentVolume
|
||||
val target = (current + direction).coerceIn(0, 100)
|
||||
setCurrentVolume(target)
|
||||
try { castPlayer?.setDeviceVolume(target) } catch (_: Exception) {}
|
||||
}
|
||||
}
|
||||
remoteVolumeProvider = provider
|
||||
|
||||
Reference in New Issue
Block a user