Skip to content

Commit f19bffc

Browse files
committed
debounce formats in UI, not service
1 parent 6efa4e0 commit f19bffc

File tree

2 files changed

+127
-91
lines changed

2 files changed

+127
-91
lines changed

app/src/main/kotlin/org/akanework/gramophone/logic/GramophonePlaybackService.kt

+121-89
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ import android.media.audiofx.AudioEffect
3434
import android.net.Uri
3535
import android.os.Build
3636
import android.os.Bundle
37+
import android.os.Bundle.EMPTY
3738
import android.os.Handler
3839
import android.os.HandlerThread
3940
import android.os.Looper
@@ -176,14 +177,8 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
176177
private var audioTrackReleaseCounter = 0
177178
private val lyricsFetcher = CoroutineScope(Dispatchers.IO.limitedParallelism(1))
178179
private val bitrateFetcher = CoroutineScope(Dispatchers.IO.limitedParallelism(1))
179-
private val formatChangeRunnable = Runnable {
180-
mediaSession?.broadcastCustomCommand(
181-
SessionCommand(SERVICE_GET_AUDIO_FORMAT, Bundle.EMPTY),
182-
Bundle.EMPTY
183-
)
184-
}
185180

186-
private fun getRepeatCommand() =
181+
private fun getRepeatCommand() =
187182
when (controller!!.repeatMode) {
188183
Player.REPEAT_MODE_OFF -> customCommands[2]
189184
Player.REPEAT_MODE_ALL -> customCommands[3]
@@ -234,13 +229,16 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
234229
}
235230

236231
private val btReceiver = object : BroadcastReceiver() {
237-
// TODO verify if stable
232+
// TODO verify if stable
238233
override fun onReceive(context: Context, intent: Intent) {
239234
if (intent.action.equals("android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED") &&
240235
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O /* before 8, only sbc was supported */
241236
) {
242-
btInfo = BtCodecInfo.fromCodecConfig(@SuppressLint("NewApi") IntentCompat.getParcelableExtra(
243-
intent, "android.bluetooth.extra.CODEC_STATUS", BluetoothCodecStatus::class.java)?.codecConfig)
237+
btInfo = BtCodecInfo.fromCodecConfig(
238+
@SuppressLint("NewApi") IntentCompat.getParcelableExtra(
239+
intent, "android.bluetooth.extra.CODEC_STATUS", BluetoothCodecStatus::class.java
240+
)?.codecConfig
241+
)
244242
Log.d(TAG, "new bluetooth codec config $btInfo")
245243
}
246244
}
@@ -318,14 +316,19 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
318316
)
319317
afFormatTracker = AfFormatTracker(this, playbackHandler, handler)
320318
afFormatTracker.formatChangedCallback = {
321-
sendDebouncedFormatChange()
319+
mediaSession?.broadcastCustomCommand(
320+
SessionCommand(SERVICE_GET_AUDIO_FORMAT, EMPTY),
321+
EMPTY
322+
)
322323
}
323324
val player = EndedWorkaroundPlayer(
324325
ExoPlayer.Builder(
325326
this,
326-
GramophoneRenderFactory(this, this::onAudioSinkInputFormatChanged,
327-
afFormatTracker::setAudioSink)
328-
.setEnableAudioFloatOutput(
327+
GramophoneRenderFactory(
328+
this, this::onAudioSinkInputFormatChanged,
329+
afFormatTracker::setAudioSink
330+
)
331+
.setEnableAudioFloatOutput(
329332
prefs.getBooleanStrict("floatoutput", false)
330333
)
331334
.setEnableDecoderFallback(true)
@@ -447,7 +450,10 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
447450
proxy = BtCodecInfo.getCodec(this) {
448451
Log.d(TAG, "first bluetooth codec config $btInfo")
449452
btInfo = it
450-
sendDebouncedFormatChange()
453+
mediaSession?.broadcastCustomCommand(
454+
SessionCommand(SERVICE_GET_AUDIO_FORMAT, EMPTY),
455+
EMPTY
456+
)
451457
}
452458
}
453459
lastPlayedManager.restore { items, factory ->
@@ -462,8 +468,10 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
462468
)
463469
} catch (e: IllegalSeekPositionException) {
464470
// song was edited to be shorter and playback position doesn't exist anymore
465-
Log.e(TAG, "failed to restore with startPositionMs, trying without... "
466-
+ Log.getStackTraceString(e))
471+
Log.e(
472+
TAG, "failed to restore with startPositionMs, trying without... "
473+
+ Log.getStackTraceString(e)
474+
)
467475
try {
468476
mediaSession?.player?.setMediaItems(
469477
items.mediaItems, items.startIndex, C.TIME_UNSET
@@ -543,7 +551,10 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
543551
SessionCommand(SERVICE_GET_LYRICS, Bundle.EMPTY),
544552
Bundle.EMPTY
545553
)
546-
sendDebouncedFormatChange()
554+
mediaSession?.broadcastCustomCommand(
555+
SessionCommand(SERVICE_GET_AUDIO_FORMAT, EMPTY),
556+
EMPTY
557+
)
547558
}
548559

549560
return MediaSession.ConnectionResult.AcceptedResultBuilder(session)
@@ -568,7 +579,12 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
568579
} else {
569580
Log.e(TAG, "session id is 0? why????? THIS MIGHT BREAK EQUALIZER")
570581
}
571-
val s = NativeTrack.getDirectPlaybackSupport(this, 192000, AudioFormat.ENCODING_PCM_16BIT, AudioFormat.CHANNEL_OUT_STEREO)
582+
val s = NativeTrack.getDirectPlaybackSupport(
583+
this,
584+
192000,
585+
AudioFormat.ENCODING_PCM_16BIT,
586+
AudioFormat.CHANNEL_OUT_STEREO
587+
)
572588
Toast.makeText(this, "direct: ${s.directOrOffload}", Toast.LENGTH_LONG).show()
573589
val track = NativeTrack(this)
574590
track.set()
@@ -590,83 +606,84 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
590606
customCommand: SessionCommand,
591607
args: Bundle
592608
): ListenableFuture<SessionResult> {
593-
return Futures.immediateFuture(when (customCommand.customAction) {
594-
PLAYBACK_SHUFFLE_ACTION_ON -> {
595-
this.controller!!.shuffleModeEnabled = true
596-
SessionResult(SessionResult.RESULT_SUCCESS)
597-
}
609+
return Futures.immediateFuture(
610+
when (customCommand.customAction) {
611+
PLAYBACK_SHUFFLE_ACTION_ON -> {
612+
this.controller!!.shuffleModeEnabled = true
613+
SessionResult(SessionResult.RESULT_SUCCESS)
614+
}
598615

599-
PLAYBACK_SHUFFLE_ACTION_OFF -> {
600-
this.controller!!.shuffleModeEnabled = false
601-
SessionResult(SessionResult.RESULT_SUCCESS)
602-
}
616+
PLAYBACK_SHUFFLE_ACTION_OFF -> {
617+
this.controller!!.shuffleModeEnabled = false
618+
SessionResult(SessionResult.RESULT_SUCCESS)
619+
}
603620

604-
SERVICE_SET_TIMER -> {
605-
// 0 = clear timer
606-
customCommand.customExtras.getInt("duration").let {
607-
timerDuration = if (it > 0) System.currentTimeMillis() + it else null
621+
SERVICE_SET_TIMER -> {
622+
// 0 = clear timer
623+
customCommand.customExtras.getInt("duration").let {
624+
timerDuration = if (it > 0) System.currentTimeMillis() + it else null
625+
}
626+
SessionResult(SessionResult.RESULT_SUCCESS)
608627
}
609-
SessionResult(SessionResult.RESULT_SUCCESS)
610-
}
611628

612-
SERVICE_QUERY_TIMER -> {
613-
SessionResult(SessionResult.RESULT_SUCCESS).also {
614-
timerDuration?.let { td ->
615-
it.extras.putInt("duration", (td - System.currentTimeMillis()).toInt())
629+
SERVICE_QUERY_TIMER -> {
630+
SessionResult(SessionResult.RESULT_SUCCESS).also {
631+
timerDuration?.let { td ->
632+
it.extras.putInt("duration", (td - System.currentTimeMillis()).toInt())
633+
}
616634
}
617635
}
618-
}
619636

620-
SERVICE_GET_AUDIO_FORMAT -> {
621-
SessionResult(SessionResult.RESULT_SUCCESS).also {
622-
it.extras.putBundle("file_format", downstreamFormat?.toBundle())
623-
it.extras.putBundle("sink_format", audioSinkInputFormat?.toBundle())
624-
it.extras.putParcelable("track_format", audioTrackInfo)
625-
it.extras.putParcelable("hal_format", afFormatTracker.format)
626-
bitrate?.let { value -> it.extras.putLong("bitrate", value) }
627-
if (afFormatTracker.format?.routedDeviceType == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP) {
628-
it.extras.putParcelable("bt", btInfo)
637+
SERVICE_GET_AUDIO_FORMAT -> {
638+
SessionResult(SessionResult.RESULT_SUCCESS).also {
639+
it.extras.putBundle("file_format", downstreamFormat?.toBundle())
640+
it.extras.putBundle("sink_format", audioSinkInputFormat?.toBundle())
641+
it.extras.putParcelable("track_format", audioTrackInfo)
642+
it.extras.putParcelable("hal_format", afFormatTracker.format)
643+
bitrate?.let { value -> it.extras.putLong("bitrate", value) }
644+
if (afFormatTracker.format?.routedDeviceType == AudioDeviceInfo.TYPE_BLUETOOTH_A2DP) {
645+
it.extras.putParcelable("bt", btInfo)
646+
}
629647
}
630648
}
631-
}
632649

633-
SERVICE_GET_LYRICS -> {
634-
SessionResult(SessionResult.RESULT_SUCCESS).also {
635-
it.extras.putParcelable("lyrics", lyrics)
650+
SERVICE_GET_LYRICS -> {
651+
SessionResult(SessionResult.RESULT_SUCCESS).also {
652+
it.extras.putParcelable("lyrics", lyrics)
653+
}
636654
}
637-
}
638655

639-
SERVICE_GET_LYRICS_LEGACY -> {
640-
SessionResult(SessionResult.RESULT_SUCCESS).also {
641-
it.extras.putParcelableArray("lyrics", lyricsLegacy?.toTypedArray())
656+
SERVICE_GET_LYRICS_LEGACY -> {
657+
SessionResult(SessionResult.RESULT_SUCCESS).also {
658+
it.extras.putParcelableArray("lyrics", lyricsLegacy?.toTypedArray())
659+
}
642660
}
643-
}
644661

645-
SERVICE_GET_SESSION -> {
646-
SessionResult(SessionResult.RESULT_SUCCESS).also {
647-
it.extras.putInt("session", lastSessionId)
662+
SERVICE_GET_SESSION -> {
663+
SessionResult(SessionResult.RESULT_SUCCESS).also {
664+
it.extras.putInt("session", lastSessionId)
665+
}
648666
}
649-
}
650667

651-
PLAYBACK_REPEAT_OFF -> {
652-
this.controller!!.repeatMode = Player.REPEAT_MODE_OFF
653-
SessionResult(SessionResult.RESULT_SUCCESS)
654-
}
668+
PLAYBACK_REPEAT_OFF -> {
669+
this.controller!!.repeatMode = Player.REPEAT_MODE_OFF
670+
SessionResult(SessionResult.RESULT_SUCCESS)
671+
}
655672

656-
PLAYBACK_REPEAT_ONE -> {
657-
this.controller!!.repeatMode = Player.REPEAT_MODE_ONE
658-
SessionResult(SessionResult.RESULT_SUCCESS)
659-
}
673+
PLAYBACK_REPEAT_ONE -> {
674+
this.controller!!.repeatMode = Player.REPEAT_MODE_ONE
675+
SessionResult(SessionResult.RESULT_SUCCESS)
676+
}
660677

661-
PLAYBACK_REPEAT_ALL -> {
662-
this.controller!!.repeatMode = Player.REPEAT_MODE_ALL
663-
SessionResult(SessionResult.RESULT_SUCCESS)
664-
}
678+
PLAYBACK_REPEAT_ALL -> {
679+
this.controller!!.repeatMode = Player.REPEAT_MODE_ALL
680+
SessionResult(SessionResult.RESULT_SUCCESS)
681+
}
665682

666-
else -> {
667-
SessionResult(SessionError.ERROR_BAD_VALUE)
668-
}
669-
})
683+
else -> {
684+
SessionResult(SessionError.ERROR_BAD_VALUE)
685+
}
686+
})
670687
}
671688

672689
override fun onPlaybackResumption(
@@ -765,18 +782,16 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
765782
}
766783
}
767784

768-
private fun sendDebouncedFormatChange() {
769-
handler.removeCallbacks(formatChangeRunnable)
770-
handler.postDelayed(formatChangeRunnable, 500)
771-
}
772-
773785
override fun onAudioTrackInitialized(
774786
eventTime: AnalyticsListener.EventTime,
775787
audioTrackConfig: AudioSink.AudioTrackConfig
776788
) {
777789
audioTrackInfoCounter++
778790
audioTrackInfo = AudioTrackInfo.fromMedia3AudioTrackConfig(audioTrackConfig)
779-
sendDebouncedFormatChange()
791+
mediaSession?.broadcastCustomCommand(
792+
SessionCommand(SERVICE_GET_AUDIO_FORMAT, EMPTY),
793+
EMPTY
794+
)
780795
}
781796

782797
override fun onAudioTrackReleased(
@@ -787,7 +802,10 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
787802
// without replacement, we want to instantly know that instead of keeping stale data.
788803
if (++audioTrackReleaseCounter == audioTrackInfoCounter) {
789804
audioTrackInfo = null
790-
sendDebouncedFormatChange()
805+
mediaSession?.broadcastCustomCommand(
806+
SessionCommand(SERVICE_GET_AUDIO_FORMAT, EMPTY),
807+
EMPTY
808+
)
791809
}
792810
}
793811

@@ -796,18 +814,27 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
796814
mediaLoadData: MediaLoadData
797815
) {
798816
downstreamFormat = mediaLoadData.trackFormat
799-
sendDebouncedFormatChange()
817+
mediaSession?.broadcastCustomCommand(
818+
SessionCommand(SERVICE_GET_AUDIO_FORMAT, EMPTY),
819+
EMPTY
820+
)
800821
}
801822

802823
private fun onAudioSinkInputFormatChanged(inputFormat: Format?) {
803824
audioSinkInputFormat = inputFormat
804-
sendDebouncedFormatChange()
825+
mediaSession?.broadcastCustomCommand(
826+
SessionCommand(SERVICE_GET_AUDIO_FORMAT, EMPTY),
827+
EMPTY
828+
)
805829
}
806830

807831
override fun onPlaybackStateChanged(eventTime: AnalyticsListener.EventTime, state: Int) {
808832
if (state == Player.STATE_IDLE) {
809833
downstreamFormat = null
810-
sendDebouncedFormatChange()
834+
mediaSession?.broadcastCustomCommand(
835+
SessionCommand(SERVICE_GET_AUDIO_FORMAT, EMPTY),
836+
EMPTY
837+
)
811838
}
812839
}
813840

@@ -819,7 +846,10 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
819846
bitrate = null
820847
bitrateFetcher.launch {
821848
bitrate = mediaItem?.getBitrate() // TODO subtract cover size
822-
sendDebouncedFormatChange()
849+
this@GramophonePlaybackService.mediaSession?.broadcastCustomCommand(
850+
SessionCommand(SERVICE_GET_AUDIO_FORMAT, EMPTY),
851+
EMPTY
852+
)
823853
}
824854
lyrics = null
825855
lyricsLegacy = null
@@ -837,7 +867,8 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
837867
// if timeline changed, shuffle order is handled elsewhere instead (cloneAndInsert called by
838868
// ExoPlayer for common case and nextShuffleOrder for resumption case)
839869
if (events.contains(EVENT_SHUFFLE_MODE_ENABLED_CHANGED)
840-
&& !events.contains(Player.EVENT_TIMELINE_CHANGED)) {
870+
&& !events.contains(Player.EVENT_TIMELINE_CHANGED)
871+
) {
841872
// when enabling shuffle, re-shuffle lists so that the first index is up to date
842873
Log.i(TAG, "re-shuffling playlist")
843874
endedWorkaroundPlayer?.setShuffleOrder {
@@ -914,6 +945,7 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
914945
doUpdateNotification(mediaSession!!)
915946
}
916947
}
948+
917949
fun getCurrentLyricIndex(withTranslation: Boolean) =
918950
if (syncedLyrics != null) {
919951
syncedLyrics?.text?.mapIndexed { i, it -> i to it }?.filter {

app/src/main/kotlin/org/akanework/gramophone/ui/components/FullBottomSheet.kt

+6-2
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,10 @@ class FullBottomSheet
187187
isUserTracking = false
188188
}
189189
}
190+
private val formatUpdateRunnable = Runnable {
191+
updateQualityIndicators(if (enableQualityInfo)
192+
AudioFormatDetector.detectAudioFormat(currentFormat) else null)
193+
}
190194
private val bottomSheetFullCover: ImageView
191195
private val bottomSheetFullTitle: TextView
192196
private val bottomSheetFullSubtitle: TextView
@@ -297,8 +301,8 @@ class FullBottomSheet
297301
GramophonePlaybackService.SERVICE_GET_AUDIO_FORMAT -> {
298302
val format = instance?.getAudioFormat()
299303
this.currentFormat = format
300-
updateQualityIndicators(if (enableQualityInfo)
301-
AudioFormatDetector.detectAudioFormat(format) else null)
304+
handler.removeCallbacks(formatUpdateRunnable)
305+
handler.postDelayed(formatUpdateRunnable, 500)
302306
}
303307

304308
else -> {

0 commit comments

Comments
 (0)