Keep notification players strongly owned throughout playback
This commit is contained in:
1 parent
b318627022
commit
776345997f
2 files changed
+11
-10
No files matched your search
@@ -47,7 +47,7 @@ object CallRingback {
|
||||
if (active && resourceId == resId) return
|
||||
release("phase changed")
|
||||
if (player != null) {
|
||||
LogManager.addLog("WARN", "Ringback", "start skipped phase=$tag resource=$resId: cleanup pending " +
|
||||
LogManager.addLog("WARN", "Ringback", "start skipped phase=$tag requested_resource=$resId: cleanup pending " +
|
||||
"resource=$resourceId player=${System.identityHashCode(player)}")
|
||||
return
|
||||
}
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.utun.chat.R
|
||||
/**
|
||||
* Однократный msg_incoming.mp3 через профиль уведомлений. play вызывается на main.
|
||||
* enabled и mutedChannels — снимки настроек; их меняет main. Независимые звуки могут перекрываться.
|
||||
* Владелец хранит сильную ссылку на каждый плеер до успешного release, включая время проигрывания.
|
||||
* Каждый плеер получает release по completion/error или при ошибке настройки/запуска.
|
||||
* Ошибка сохраняет владельца для следующего callback/play; успешная очистка повторно не вызывается.
|
||||
* Play сначала повторяет отложенную очистку, даже при mute/disabled или отказе создания нового звука.
|
||||
@@ -19,9 +20,9 @@ object NotificationSound {
|
||||
@Volatile var enabled: Boolean = true
|
||||
@Volatile var mutedChannels: Set<String> = emptySet()
|
||||
|
||||
/** Владелец отдельного звука; released общий для callbacks и повторной очистки перед новым play. */
|
||||
private class Playback(val player: MediaPlayer, val channelId: String) { var released = false }
|
||||
private val pending = mutableSetOf<Playback>() // Только плееры с неподтверждённым release; доступ на main.
|
||||
/** Один звук; cleanupPending отличает неудачный release от ещё играющего плеера. */
|
||||
private class Playback(val player: MediaPlayer, val channelId: String) { var cleanupPending = false }
|
||||
private val playbacks = mutableSetOf<Playback>() // Сильные ссылки до успешного release; доступ только на main.
|
||||
|
||||
/** Прочитать снимок настройки mute канала/личной беседы (DM использует ID с префиксом dm:). */
|
||||
fun isMuted(channelId: String): Boolean = channelId in mutedChannels
|
||||
@@ -37,7 +38,7 @@ object NotificationSound {
|
||||
LogManager.addLog("ERROR", "Sound", "play requires main thread")
|
||||
"NotificationSound requires main thread"
|
||||
}
|
||||
for (playback in pending.toList()) release(playback, "retry before play")
|
||||
for (playback in playbacks.filter { it.cleanupPending }) release(playback, "retry before play")
|
||||
if (!enabled || isMuted(channelId)) return
|
||||
val mp = try {
|
||||
val attrs = AudioAttributes.Builder().setUsage(AudioAttributes.USAGE_NOTIFICATION)
|
||||
@@ -52,10 +53,11 @@ object NotificationSound {
|
||||
return
|
||||
}
|
||||
val playback = Playback(mp, channelId)
|
||||
playbacks.add(playback)
|
||||
try {
|
||||
mp.setOnCompletionListener { release(playback, "completed") }
|
||||
mp.setOnErrorListener { _, what, extra ->
|
||||
if (!playback.released) LogManager.addLog("WARN", "Sound", "playback error ch=$channelId what=$what extra=$extra")
|
||||
if (playback in playbacks) LogManager.addLog("WARN", "Sound", "playback error ch=$channelId what=$what extra=$extra")
|
||||
release(playback, "error")
|
||||
true
|
||||
}
|
||||
@@ -69,16 +71,15 @@ object NotificationSound {
|
||||
|
||||
/** Один release независимо от остальных звуков; исключение сохраняет владельца для следующего callback/play. */
|
||||
private fun release(playback: Playback, reason: String) {
|
||||
if (playback.released) return
|
||||
if (playback !in playbacks) return
|
||||
val mp = playback.player
|
||||
try { mp.release() } catch (e: Exception) {
|
||||
pending.add(playback)
|
||||
playback.cleanupPending = true
|
||||
LogManager.addLog("WARN", "Sound", "release failed ch=${playback.channelId} reason=$reason " +
|
||||
"player=${System.identityHashCode(mp)}; retained for retry: $e")
|
||||
return
|
||||
}
|
||||
playback.released = true
|
||||
pending.remove(playback)
|
||||
playbacks.remove(playback)
|
||||
LogManager.addLog("DEBUG", "Sound", "notification released ch=${playback.channelId} reason=$reason " +
|
||||
"player=${System.identityHashCode(mp)}")
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user