mirror of
https://github.com/sudoxnym/audiobookshelf-atv.git
synced 2026-04-14 19:46:30 +00:00
Add android graceful fallback to transcode & onPlaybackFailed event
This commit is contained in:
parent
6cea0ba03d
commit
760d05cf1b
7 changed files with 51 additions and 13 deletions
|
|
@ -48,6 +48,8 @@ class PlaybackSession(
|
|||
@get:JsonIgnore
|
||||
val isHLS get() = playMethod == PLAYMETHOD_TRANSCODE
|
||||
@get:JsonIgnore
|
||||
val isDirectPlay get() = playMethod == PLAYMETHOD_DIRECTPLAY
|
||||
@get:JsonIgnore
|
||||
val isLocal get() = playMethod == PLAYMETHOD_LOCAL
|
||||
@get:JsonIgnore
|
||||
val currentTimeMs get() = (currentTime * 1000L).toLong()
|
||||
|
|
|
|||
|
|
@ -15,8 +15,9 @@ class PlayerListener(var playerNotificationService:PlayerNotificationService) :
|
|||
private var onSeekBack: Boolean = false
|
||||
|
||||
override fun onPlayerError(error: PlaybackException) {
|
||||
error.message?.let { Log.e(tag, it) }
|
||||
error.localizedMessage?.let { Log.e(tag, it) }
|
||||
var errorMessage = error.message ?: "Unknown Error"
|
||||
Log.e(tag, "onPlayerError $errorMessage")
|
||||
playerNotificationService.handlePlayerPlaybackError(errorMessage) // If was direct playing session, fallback to transcode
|
||||
}
|
||||
|
||||
override fun onEvents(player: Player, events: Player.Events) {
|
||||
|
|
|
|||
|
|
@ -55,6 +55,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
|||
fun onSleepTimerEnded(currentPosition: Long)
|
||||
fun onSleepTimerSet(sleepTimeRemaining: Int)
|
||||
fun onLocalMediaProgressUpdate(localMediaProgress: LocalMediaProgress)
|
||||
fun onPlaybackFailed(errorMessage:String)
|
||||
}
|
||||
|
||||
private val tag = "PlayerService"
|
||||
|
|
@ -289,7 +290,6 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
|||
mediaSession.setMetadata(metadata)
|
||||
var mediaItems = playbackSession.getMediaItems()
|
||||
if (mPlayer == currentPlayer) {
|
||||
|
||||
var mediaSource:MediaSource
|
||||
|
||||
if (playbackSession.isLocal) {
|
||||
|
|
@ -333,6 +333,26 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
|
|||
currentPlayer.prepare()
|
||||
}
|
||||
|
||||
fun handlePlayerPlaybackError(errorMessage:String) {
|
||||
// On error and was attempting to direct play - fallback to transcode
|
||||
currentPlaybackSession?.let { playbackSession ->
|
||||
if (playbackSession.isDirectPlay) {
|
||||
Log.d(tag, "Fallback to transcode")
|
||||
|
||||
var libraryItemId = playbackSession.libraryItemId ?: "" // Must be true since direct play
|
||||
var episodeId = playbackSession.episodeId
|
||||
apiHandler.playLibraryItem(libraryItemId, episodeId, true) {
|
||||
Handler(Looper.getMainLooper()).post() {
|
||||
preparePlayer(it, true)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
clientEventEmitter?.onPlaybackFailed(errorMessage)
|
||||
closePlayback()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun switchToPlayer(useCastPlayer: Boolean) {
|
||||
currentPlayer = if (useCastPlayer) {
|
||||
Log.d(tag, "switchToPlayer: Using Cast Player " + castPlayer?.deviceInfo)
|
||||
|
|
|
|||
|
|
@ -68,6 +68,10 @@ class AbsAudioPlayer : Plugin() {
|
|||
override fun onLocalMediaProgressUpdate(localMediaProgress: LocalMediaProgress) {
|
||||
notifyListeners("onLocalMediaProgressUpdate", JSObject(jacksonMapper.writeValueAsString(localMediaProgress)))
|
||||
}
|
||||
|
||||
override fun onPlaybackFailed(errorMessage: String) {
|
||||
emit("onPlaybackFailed", errorMessage)
|
||||
}
|
||||
})
|
||||
}
|
||||
mainActivity.pluginCallback = foregroundServiceReady
|
||||
|
|
|
|||
|
|
@ -151,12 +151,11 @@ class ApiHandler {
|
|||
}
|
||||
}
|
||||
|
||||
fun playLibraryItem(libraryItemId:String, episodeId:String, forceTranscode:Boolean, cb: (PlaybackSession) -> Unit) {
|
||||
fun playLibraryItem(libraryItemId:String, episodeId:String?, forceTranscode:Boolean, cb: (PlaybackSession) -> Unit) {
|
||||
var payload = JSObject()
|
||||
payload.put("mediaPlayer", "exo-player")
|
||||
|
||||
// Only if direct play fails do we force transcode
|
||||
// TODO: Fallback to transcode
|
||||
if (!forceTranscode) payload.put("forceDirectPlay", true)
|
||||
else payload.put("forceTranscode", true)
|
||||
|
||||
|
|
|
|||
|
|
@ -535,6 +535,12 @@ export default {
|
|||
this.$refs.dropdownMenu.closeMenu()
|
||||
}
|
||||
},
|
||||
closePlayback() {
|
||||
this.$store.commit('setPlayerItem', null)
|
||||
this.showFullscreen = false
|
||||
this.isEnded = false
|
||||
this.playbackSession = null
|
||||
},
|
||||
//
|
||||
// Listeners from audio AbsAudioPlayer
|
||||
//
|
||||
|
|
@ -586,16 +592,20 @@ export default {
|
|||
},
|
||||
onPlaybackClosed() {
|
||||
console.log('Received onPlaybackClosed evt')
|
||||
this.$store.commit('setPlayerItem', null)
|
||||
this.showFullscreen = false
|
||||
this.isEnded = false
|
||||
this.playbackSession = null
|
||||
this.closePlayback()
|
||||
},
|
||||
onPlaybackFailed(data) {
|
||||
console.log('Received onPlaybackFailed evt')
|
||||
var errorMessage = data.value || 'Unknown Error'
|
||||
this.$toast.error(`Playback Failed: ${errorMessage}`)
|
||||
this.closePlayback()
|
||||
},
|
||||
async init() {
|
||||
this.useChapterTrack = await this.$localStore.getUseChapterTrack()
|
||||
|
||||
this.onPlaybackSessionListener = AbsAudioPlayer.addListener('onPlaybackSession', this.onPlaybackSession)
|
||||
this.onPlaybackClosedListener = AbsAudioPlayer.addListener('onPlaybackClosed', this.onPlaybackClosed)
|
||||
this.onPlaybackFailedListener = AbsAudioPlayer.addListener('onPlaybackFailed', this.onPlaybackFailed)
|
||||
this.onPlayingUpdateListener = AbsAudioPlayer.addListener('onPlayingUpdate', this.onPlayingUpdate)
|
||||
this.onMetadataListener = AbsAudioPlayer.addListener('onMetadata', this.onMetadata)
|
||||
}
|
||||
|
|
@ -615,6 +625,7 @@ export default {
|
|||
if (this.onMetadataListener) this.onMetadataListener.remove()
|
||||
if (this.onPlaybackSessionListener) this.onPlaybackSessionListener.remove()
|
||||
if (this.onPlaybackClosedListener) this.onPlaybackClosedListener.remove()
|
||||
if (this.onPlaybackFailedListener) this.onPlaybackFailedListener.remove()
|
||||
clearInterval(this.playInterval)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,11 +23,11 @@
|
|||
|
||||
<div v-if="!hasCover" class="absolute top-0 left-0 right-0 bottom-0 w-full h-full flex items-center justify-center z-10" :style="{ padding: placeholderCoverPadding + 'rem' }">
|
||||
<div>
|
||||
<p class="text-center font-book" style="color: rgb(247 223 187)" :style="{ fontSize: titleFontSize + 'rem' }">{{ titleCleaned }}</p>
|
||||
<p class="text-center font-book truncate leading-none origin-center" style="color: rgb(247 223 187); font-size: 0.8rem" :style="{ transform: `scale(${sizeMultiplier})` }">{{ titleCleaned }}</p>
|
||||
</div>
|
||||
</div>
|
||||
<div v-if="!hasCover" class="absolute left-0 right-0 w-full flex items-center justify-center z-10" :style="{ padding: placeholderCoverPadding + 'rem', bottom: authorBottom + 'rem' }">
|
||||
<p class="text-center font-book" style="color: rgb(247 223 187); opacity: 0.75" :style="{ fontSize: authorFontSize + 'rem' }">{{ authorCleaned }}</p>
|
||||
<p class="text-center font-book truncate leading-none origin-center" style="color: rgb(247 223 187); opacity: 0.75; font-size: 0.6rem" :style="{ transform: `scale(${sizeMultiplier})` }">{{ authorCleaned }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
|
@ -123,7 +123,7 @@ export default {
|
|||
return !!this.media.coverPath || this.localCover || this.downloadCover
|
||||
},
|
||||
sizeMultiplier() {
|
||||
var baseSize = this.squareAspectRatio ? 192 : 120
|
||||
var baseSize = this.squareAspectRatio ? 128 : 96
|
||||
return this.width / baseSize
|
||||
},
|
||||
titleFontSize() {
|
||||
|
|
@ -133,7 +133,8 @@ export default {
|
|||
return 0.6 * this.sizeMultiplier
|
||||
},
|
||||
placeholderCoverPadding() {
|
||||
return 0.8 * this.sizeMultiplier
|
||||
if (this.sizeMultiplier < 0.5) return 0
|
||||
return this.sizeMultiplier
|
||||
},
|
||||
authorBottom() {
|
||||
return 0.75 * this.sizeMultiplier
|
||||
|
|
|
|||
Loading…
Reference in a new issue