@@ -34,6 +34,7 @@ import android.media.audiofx.AudioEffect
34
34
import android.net.Uri
35
35
import android.os.Build
36
36
import android.os.Bundle
37
+ import android.os.Bundle.EMPTY
37
38
import android.os.Handler
38
39
import android.os.HandlerThread
39
40
import android.os.Looper
@@ -176,14 +177,8 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
176
177
private var audioTrackReleaseCounter = 0
177
178
private val lyricsFetcher = CoroutineScope (Dispatchers .IO .limitedParallelism(1 ))
178
179
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
- }
185
180
186
- private fun getRepeatCommand () =
181
+ private fun getRepeatCommand () =
187
182
when (controller!! .repeatMode) {
188
183
Player .REPEAT_MODE_OFF -> customCommands[2 ]
189
184
Player .REPEAT_MODE_ALL -> customCommands[3 ]
@@ -234,13 +229,16 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
234
229
}
235
230
236
231
private val btReceiver = object : BroadcastReceiver () {
237
- // TODO verify if stable
232
+ // TODO verify if stable
238
233
override fun onReceive (context : Context , intent : Intent ) {
239
234
if (intent.action.equals(" android.bluetooth.a2dp.profile.action.CODEC_CONFIG_CHANGED" ) &&
240
235
Build .VERSION .SDK_INT >= Build .VERSION_CODES .O /* before 8, only sbc was supported */
241
236
) {
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
+ )
244
242
Log .d(TAG , " new bluetooth codec config $btInfo " )
245
243
}
246
244
}
@@ -318,14 +316,19 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
318
316
)
319
317
afFormatTracker = AfFormatTracker (this , playbackHandler, handler)
320
318
afFormatTracker.formatChangedCallback = {
321
- sendDebouncedFormatChange()
319
+ mediaSession?.broadcastCustomCommand(
320
+ SessionCommand (SERVICE_GET_AUDIO_FORMAT , EMPTY ),
321
+ EMPTY
322
+ )
322
323
}
323
324
val player = EndedWorkaroundPlayer (
324
325
ExoPlayer .Builder (
325
326
this ,
326
- GramophoneRenderFactory (this , this ::onAudioSinkInputFormatChanged,
327
- afFormatTracker::setAudioSink)
328
- .setEnableAudioFloatOutput(
327
+ GramophoneRenderFactory (
328
+ this , this ::onAudioSinkInputFormatChanged,
329
+ afFormatTracker::setAudioSink
330
+ )
331
+ .setEnableAudioFloatOutput(
329
332
prefs.getBooleanStrict(" floatoutput" , false )
330
333
)
331
334
.setEnableDecoderFallback(true )
@@ -447,7 +450,10 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
447
450
proxy = BtCodecInfo .getCodec(this ) {
448
451
Log .d(TAG , " first bluetooth codec config $btInfo " )
449
452
btInfo = it
450
- sendDebouncedFormatChange()
453
+ mediaSession?.broadcastCustomCommand(
454
+ SessionCommand (SERVICE_GET_AUDIO_FORMAT , EMPTY ),
455
+ EMPTY
456
+ )
451
457
}
452
458
}
453
459
lastPlayedManager.restore { items, factory ->
@@ -462,8 +468,10 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
462
468
)
463
469
} catch (e: IllegalSeekPositionException ) {
464
470
// 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
+ )
467
475
try {
468
476
mediaSession?.player?.setMediaItems(
469
477
items.mediaItems, items.startIndex, C .TIME_UNSET
@@ -543,7 +551,10 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
543
551
SessionCommand (SERVICE_GET_LYRICS , Bundle .EMPTY ),
544
552
Bundle .EMPTY
545
553
)
546
- sendDebouncedFormatChange()
554
+ mediaSession?.broadcastCustomCommand(
555
+ SessionCommand (SERVICE_GET_AUDIO_FORMAT , EMPTY ),
556
+ EMPTY
557
+ )
547
558
}
548
559
549
560
return MediaSession .ConnectionResult .AcceptedResultBuilder (session)
@@ -568,7 +579,12 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
568
579
} else {
569
580
Log .e(TAG , " session id is 0? why????? THIS MIGHT BREAK EQUALIZER" )
570
581
}
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
+ )
572
588
Toast .makeText(this , " direct: ${s.directOrOffload} " , Toast .LENGTH_LONG ).show()
573
589
val track = NativeTrack (this )
574
590
track.set()
@@ -590,83 +606,84 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
590
606
customCommand : SessionCommand ,
591
607
args : Bundle
592
608
): 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
+ }
598
615
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
+ }
603
620
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 )
608
627
}
609
- SessionResult (SessionResult .RESULT_SUCCESS )
610
- }
611
628
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
+ }
616
634
}
617
635
}
618
- }
619
636
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
+ }
629
647
}
630
648
}
631
- }
632
649
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
+ }
636
654
}
637
- }
638
655
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
+ }
642
660
}
643
- }
644
661
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
+ }
648
666
}
649
- }
650
667
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
+ }
655
672
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
+ }
660
677
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
+ }
665
682
666
- else -> {
667
- SessionResult (SessionError .ERROR_BAD_VALUE )
668
- }
669
- })
683
+ else -> {
684
+ SessionResult (SessionError .ERROR_BAD_VALUE )
685
+ }
686
+ })
670
687
}
671
688
672
689
override fun onPlaybackResumption (
@@ -765,18 +782,16 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
765
782
}
766
783
}
767
784
768
- private fun sendDebouncedFormatChange () {
769
- handler.removeCallbacks(formatChangeRunnable)
770
- handler.postDelayed(formatChangeRunnable, 500 )
771
- }
772
-
773
785
override fun onAudioTrackInitialized (
774
786
eventTime : AnalyticsListener .EventTime ,
775
787
audioTrackConfig : AudioSink .AudioTrackConfig
776
788
) {
777
789
audioTrackInfoCounter++
778
790
audioTrackInfo = AudioTrackInfo .fromMedia3AudioTrackConfig(audioTrackConfig)
779
- sendDebouncedFormatChange()
791
+ mediaSession?.broadcastCustomCommand(
792
+ SessionCommand (SERVICE_GET_AUDIO_FORMAT , EMPTY ),
793
+ EMPTY
794
+ )
780
795
}
781
796
782
797
override fun onAudioTrackReleased (
@@ -787,7 +802,10 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
787
802
// without replacement, we want to instantly know that instead of keeping stale data.
788
803
if (++ audioTrackReleaseCounter == audioTrackInfoCounter) {
789
804
audioTrackInfo = null
790
- sendDebouncedFormatChange()
805
+ mediaSession?.broadcastCustomCommand(
806
+ SessionCommand (SERVICE_GET_AUDIO_FORMAT , EMPTY ),
807
+ EMPTY
808
+ )
791
809
}
792
810
}
793
811
@@ -796,18 +814,27 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
796
814
mediaLoadData : MediaLoadData
797
815
) {
798
816
downstreamFormat = mediaLoadData.trackFormat
799
- sendDebouncedFormatChange()
817
+ mediaSession?.broadcastCustomCommand(
818
+ SessionCommand (SERVICE_GET_AUDIO_FORMAT , EMPTY ),
819
+ EMPTY
820
+ )
800
821
}
801
822
802
823
private fun onAudioSinkInputFormatChanged (inputFormat : Format ? ) {
803
824
audioSinkInputFormat = inputFormat
804
- sendDebouncedFormatChange()
825
+ mediaSession?.broadcastCustomCommand(
826
+ SessionCommand (SERVICE_GET_AUDIO_FORMAT , EMPTY ),
827
+ EMPTY
828
+ )
805
829
}
806
830
807
831
override fun onPlaybackStateChanged (eventTime : AnalyticsListener .EventTime , state : Int ) {
808
832
if (state == Player .STATE_IDLE ) {
809
833
downstreamFormat = null
810
- sendDebouncedFormatChange()
834
+ mediaSession?.broadcastCustomCommand(
835
+ SessionCommand (SERVICE_GET_AUDIO_FORMAT , EMPTY ),
836
+ EMPTY
837
+ )
811
838
}
812
839
}
813
840
@@ -819,7 +846,10 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
819
846
bitrate = null
820
847
bitrateFetcher.launch {
821
848
bitrate = mediaItem?.getBitrate() // TODO subtract cover size
822
- sendDebouncedFormatChange()
849
+ this @GramophonePlaybackService.mediaSession?.broadcastCustomCommand(
850
+ SessionCommand (SERVICE_GET_AUDIO_FORMAT , EMPTY ),
851
+ EMPTY
852
+ )
823
853
}
824
854
lyrics = null
825
855
lyricsLegacy = null
@@ -837,7 +867,8 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
837
867
// if timeline changed, shuffle order is handled elsewhere instead (cloneAndInsert called by
838
868
// ExoPlayer for common case and nextShuffleOrder for resumption case)
839
869
if (events.contains(EVENT_SHUFFLE_MODE_ENABLED_CHANGED )
840
- && ! events.contains(Player .EVENT_TIMELINE_CHANGED )) {
870
+ && ! events.contains(Player .EVENT_TIMELINE_CHANGED )
871
+ ) {
841
872
// when enabling shuffle, re-shuffle lists so that the first index is up to date
842
873
Log .i(TAG , " re-shuffling playlist" )
843
874
endedWorkaroundPlayer?.setShuffleOrder {
@@ -914,6 +945,7 @@ class GramophonePlaybackService : MediaLibraryService(), MediaSessionService.Lis
914
945
doUpdateNotification(mediaSession!! )
915
946
}
916
947
}
948
+
917
949
fun getCurrentLyricIndex (withTranslation : Boolean ) =
918
950
if (syncedLyrics != null ) {
919
951
syncedLyrics?.text?.mapIndexed { i, it -> i to it }?.filter {
0 commit comments