From 405cd21c32a4ea9c70b03dd2628fdd59f376506d Mon Sep 17 00:00:00 2001 From: advplyr Date: Mon, 6 Feb 2023 17:20:39 -0600 Subject: [PATCH] Emit playback speed change event when Android Auto changes speed --- .../java/com/audiobookshelf/app/media/MediaManager.kt | 11 ++++++----- .../audiobookshelf/app/player/MediaSessionCallback.kt | 7 ++++--- .../app/player/PlayerNotificationService.kt | 3 +++ .../com/audiobookshelf/app/plugins/AbsAudioPlayer.kt | 4 ++++ components/app/AudioPlayer.vue | 8 ++++++++ 5 files changed, 25 insertions(+), 8 deletions(-) diff --git a/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt b/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt index c5715ebe..a986a4e6 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/media/MediaManager.kt @@ -70,21 +70,22 @@ class MediaManager(private var apiHandler: ApiHandler, var ctx: Context) { if (userSettingsPref != null) { try { val userSettings = JSObject(userSettingsPref) - userSettings.put("playbackRate", newRate.toDouble()) + userSettings.put("playbackRate", newRate.toDouble()) // TODO: Handle storing exact values? This actually comes out to something like 2.00000004432 sharedPrefEditor.putString("userSettings", userSettings.toString()) - sharedPrefEditor.commit() + sharedPrefEditor.apply() userSettingsPlaybackRate = newRate - Log.d(tag, "Saved userSettings JSON from Android Auto") + Log.d(tag, "Saved userSettings JSON from Android Auto with playbackRate=$newRate") } catch(je:JSONException) { Log.e(tag, "Failed to save userSettings JSON ${je.localizedMessage}") } } else { // Not sure if this is the best place for this, but if a user has not changed any user settings in the app // the object will not exist yet, could be moved to a centralized place or created on first app load - var userSettings = JSONObject() + val userSettings = JSONObject() userSettings.put("playbackRate", newRate.toDouble()) sharedPrefEditor.putString("userSettings", userSettings.toString()) - Log.d(tag, "Created and saved userSettings JSON from Android Auto") + userSettingsPlaybackRate = newRate + Log.d(tag, "Created and saved userSettings JSON from Android Auto with playbackRate=$newRate") } } } diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt b/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt index bdddcae8..6406288c 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/MediaSessionCallback.kt @@ -90,9 +90,9 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi private fun onChangeSpeed() { // cycle to next speed, only contains preset android app options, as each increment needs it's own icon - var mediaManager = playerNotificationService.mediaManager - var currentSpeed = mediaManager.getSavedPlaybackRate() - var newSpeed = when (currentSpeed) { + val mediaManager = playerNotificationService.mediaManager + val currentSpeed = mediaManager.getSavedPlaybackRate() + val newSpeed = when (currentSpeed) { 0.5f -> 1.0f 1.0f -> 1.2f 1.2f -> 1.5f @@ -104,6 +104,7 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi } mediaManager.setSavedPlaybackRate(newSpeed) playerNotificationService.setPlaybackSpeed(newSpeed) + playerNotificationService.clientEventEmitter?.onPlaybackSpeedChanged(newSpeed) } override fun onPlayFromMediaId(mediaId: String?, extras: Bundle?) { diff --git a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt index 910e71e8..8e678e4a 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/player/PlayerNotificationService.kt @@ -80,6 +80,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { fun onProgressSyncSuccess() fun onNetworkMeteredChanged(isUnmetered:Boolean) fun onMediaItemHistoryUpdated(mediaItemHistory:MediaItemHistory) + fun onPlaybackSpeedChanged(playbackSpeed:Float) } private val binder = LocalBinder() @@ -1187,6 +1188,8 @@ class PlayerNotificationService : MediaBrowserServiceCompat() { override fun getCustomAction(player: Player): PlaybackStateCompat.CustomAction? { val playbackRate = mediaManager.getSavedPlaybackRate() + + // TODO: Handle custom playback rates like 0.7, 1.3, 1.4, etc val drawable: Int = when (playbackRate) { 0.5f -> R.drawable.ic_play_speed_0_5x 1.0f -> R.drawable.ic_play_speed_1_0x diff --git a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt index ededb470..3272598f 100644 --- a/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt +++ b/android/app/src/main/java/com/audiobookshelf/app/plugins/AbsAudioPlayer.kt @@ -97,6 +97,10 @@ class AbsAudioPlayer : Plugin() { override fun onMediaItemHistoryUpdated(mediaItemHistory:MediaItemHistory) { notifyListeners("onMediaItemHistoryUpdated", JSObject(jacksonMapper.writeValueAsString(mediaItemHistory))) } + + override fun onPlaybackSpeedChanged(playbackSpeed:Float) { + emit("onPlaybackSpeedChanged", playbackSpeed) + } }) MediaEventManager.clientEventEmitter = playerNotificationService.clientEventEmitter diff --git a/components/app/AudioPlayer.vue b/components/app/AudioPlayer.vue index 00f82f90..76a1f1a4 100644 --- a/components/app/AudioPlayer.vue +++ b/components/app/AudioPlayer.vue @@ -143,6 +143,7 @@ export default { onMetadataListener: null, onProgressSyncFailing: null, onProgressSyncSuccess: null, + onPlaybackSpeedChangedListener: null, touchStartY: 0, touchStartTime: 0, touchEndY: 0, @@ -814,6 +815,11 @@ export default { this.$toast.error(`Playback Failed: ${errorMessage}`) this.endPlayback() }, + onPlaybackSpeedChanged(data) { + if (!data.value || isNaN(data.value)) return + this.currentPlaybackRate = Number(data.value) + this.updateTimestamp() + }, async init() { this.useChapterTrack = await this.$localStore.getUseChapterTrack() this.lockUi = await this.$localStore.getPlayerLock() @@ -825,6 +831,7 @@ export default { this.onMetadataListener = AbsAudioPlayer.addListener('onMetadata', this.onMetadata) this.onProgressSyncFailing = AbsAudioPlayer.addListener('onProgressSyncFailing', this.showProgressSyncIsFailing) this.onProgressSyncSuccess = AbsAudioPlayer.addListener('onProgressSyncSuccess', this.showProgressSyncSuccess) + this.onPlaybackSpeedChangedListener = AbsAudioPlayer.addListener('onPlaybackSpeedChanged', this.onPlaybackSpeedChanged) }, screenOrientationChange() { setTimeout(() => { @@ -900,6 +907,7 @@ export default { if (this.onPlaybackFailedListener) this.onPlaybackFailedListener.remove() if (this.onProgressSyncFailing) this.onProgressSyncFailing.remove() if (this.onProgressSyncSuccess) this.onProgressSyncSuccess.remove() + if (this.onPlaybackSpeedChangedListener) this.onPlaybackSpeedChangedListener.remove() clearInterval(this.playInterval) } }