Add android graceful fallback to transcode & onPlaybackFailed event

This commit is contained in:
advplyr 2022-04-16 13:36:30 -05:00
parent 6cea0ba03d
commit 760d05cf1b
7 changed files with 51 additions and 13 deletions

View file

@ -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()

View file

@ -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) {

View file

@ -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)

View file

@ -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

View file

@ -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)

View file

@ -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)
}
}

View file

@ -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