Android persist playback rate #138

This commit is contained in:
advplyr
2022-04-23 15:06:51 -05:00
parent c5a9677ac6
commit 0b4c999018
5 changed files with 90 additions and 83 deletions
@@ -30,7 +30,7 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
playerNotificationService.mediaManager.play(li, playerNotificationService.getMediaPlayer()) { playerNotificationService.mediaManager.play(li, playerNotificationService.getMediaPlayer()) {
Log.d(tag, "About to prepare player with ${it.displayTitle}") Log.d(tag, "About to prepare player with ${it.displayTitle}")
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
playerNotificationService.preparePlayer(it,true) playerNotificationService.preparePlayer(it,true,null)
} }
} }
} }
@@ -52,7 +52,7 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
playerNotificationService.mediaManager.play(li, playerNotificationService.getMediaPlayer()) { playerNotificationService.mediaManager.play(li, playerNotificationService.getMediaPlayer()) {
Log.d(tag, "About to prepare player with ${it.displayTitle}") Log.d(tag, "About to prepare player with ${it.displayTitle}")
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
playerNotificationService.preparePlayer(it,true) playerNotificationService.preparePlayer(it,true,null)
} }
} }
} }
@@ -100,7 +100,7 @@ class MediaSessionCallback(var playerNotificationService:PlayerNotificationServi
playerNotificationService.mediaManager.play(li, playerNotificationService.getMediaPlayer()) { playerNotificationService.mediaManager.play(li, playerNotificationService.getMediaPlayer()) {
Log.d(tag, "About to prepare player with ${it.displayTitle}") Log.d(tag, "About to prepare player with ${it.displayTitle}")
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
playerNotificationService.preparePlayer(it,true) playerNotificationService.preparePlayer(it,true,null)
} }
} }
} }
@@ -32,7 +32,7 @@ class MediaSessionPlaybackPreparer(var playerNotificationService:PlayerNotificat
playerNotificationService.mediaManager.getFirstItem()?.let { li -> playerNotificationService.mediaManager.getFirstItem()?.let { li ->
playerNotificationService.mediaManager.play(li, playerNotificationService.getMediaPlayer()) { playerNotificationService.mediaManager.play(li, playerNotificationService.getMediaPlayer()) {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
playerNotificationService.preparePlayer(it,playWhenReady) playerNotificationService.preparePlayer(it,playWhenReady,null)
} }
} }
} }
@@ -46,7 +46,7 @@ class MediaSessionPlaybackPreparer(var playerNotificationService:PlayerNotificat
playerNotificationService.mediaManager.play(li, playerNotificationService.getMediaPlayer()) { playerNotificationService.mediaManager.play(li, playerNotificationService.getMediaPlayer()) {
Log.d(tag, "About to prepare player with ${it.displayTitle}") Log.d(tag, "About to prepare player with ${it.displayTitle}")
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
playerNotificationService.preparePlayer(it,playWhenReady) playerNotificationService.preparePlayer(it,playWhenReady,null)
} }
} }
} }
@@ -58,7 +58,7 @@ class MediaSessionPlaybackPreparer(var playerNotificationService:PlayerNotificat
playerNotificationService.mediaManager.play(li, playerNotificationService.getMediaPlayer()) { playerNotificationService.mediaManager.play(li, playerNotificationService.getMediaPlayer()) {
Log.d(tag, "About to prepare player with ${it.displayTitle}") Log.d(tag, "About to prepare player with ${it.displayTitle}")
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
playerNotificationService.preparePlayer(it,playWhenReady) playerNotificationService.preparePlayer(it,playWhenReady,null)
} }
} }
} }
@@ -9,7 +9,6 @@ import android.hardware.SensorManager
import android.os.* import android.os.*
import android.support.v4.media.MediaBrowserCompat import android.support.v4.media.MediaBrowserCompat
import android.support.v4.media.MediaDescriptionCompat import android.support.v4.media.MediaDescriptionCompat
import android.support.v4.media.MediaMetadataCompat
import android.support.v4.media.session.MediaControllerCompat import android.support.v4.media.session.MediaControllerCompat
import android.support.v4.media.session.MediaSessionCompat import android.support.v4.media.session.MediaSessionCompat
import android.support.v4.media.session.PlaybackStateCompat import android.support.v4.media.session.PlaybackStateCompat
@@ -31,7 +30,6 @@ import com.google.android.exoplayer2.source.ProgressiveMediaSource
import com.google.android.exoplayer2.source.hls.HlsMediaSource import com.google.android.exoplayer2.source.hls.HlsMediaSource
import com.google.android.exoplayer2.ui.PlayerNotificationManager import com.google.android.exoplayer2.ui.PlayerNotificationManager
import com.google.android.exoplayer2.upstream.* import com.google.android.exoplayer2.upstream.*
import io.paperdb.Paper
import java.util.* import java.util.*
import kotlin.concurrent.schedule import kotlin.concurrent.schedule
@@ -82,8 +80,9 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
private var channelName = "Audiobookshelf Channel" private var channelName = "Audiobookshelf Channel"
private var currentPlaybackSession:PlaybackSession? = null private var currentPlaybackSession:PlaybackSession? = null
private var initialPlaybackRate:Float? = null
var isAndroidAuto = false private var isAndroidAuto = false
// The following are used for the shake detection // The following are used for the shake detection
private var isShakeSensorRegistered:Boolean = false private var isShakeSensorRegistered:Boolean = false
@@ -164,7 +163,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
ctx = this ctx = this
// Initialize player // Initialize player
var customLoadControl:LoadControl = DefaultLoadControl.Builder().setBufferDurationsMs( val customLoadControl:LoadControl = DefaultLoadControl.Builder().setBufferDurationsMs(
1000 * 20, // 20s min buffer 1000 * 20, // 20s min buffer
1000 * 45, // 45s max buffer 1000 * 45, // 45s max buffer
1000 * 5, // 5s playback start 1000 * 5, // 5s playback start
@@ -178,7 +177,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
.build() .build()
mPlayer.setHandleAudioBecomingNoisy(true) mPlayer.setHandleAudioBecomingNoisy(true)
mPlayer.addListener(PlayerListener(this)) mPlayer.addListener(PlayerListener(this))
var audioAttributes:AudioAttributes = AudioAttributes.Builder().setUsage(C.USAGE_MEDIA).setContentType(C.CONTENT_TYPE_SPEECH).build() val audioAttributes:AudioAttributes = AudioAttributes.Builder().setUsage(C.USAGE_MEDIA).setContentType(C.CONTENT_TYPE_SPEECH).build()
mPlayer.setAudioAttributes(audioAttributes, true) mPlayer.setAudioAttributes(audioAttributes, true)
currentPlayer = mPlayer currentPlayer = mPlayer
@@ -205,7 +204,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
val sessionActivityPendingIntent = val sessionActivityPendingIntent =
packageManager?.getLaunchIntentForPackage(packageName)?.let { sessionIntent -> packageManager?.getLaunchIntentForPackage(packageName)?.let { sessionIntent ->
PendingIntent.getActivity(this, 0, sessionIntent, 0) PendingIntent.getActivity(this, 0, sessionIntent, PendingIntent.FLAG_IMMUTABLE)
} }
mediaSession = MediaSessionCompat(this, tag) mediaSession = MediaSessionCompat(this, tag)
@@ -275,7 +274,10 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
/* /*
User callable methods User callable methods
*/ */
fun preparePlayer(playbackSession: PlaybackSession, playWhenReady:Boolean) { fun preparePlayer(playbackSession: PlaybackSession, playWhenReady:Boolean, playbackRate:Float?) {
val playbackRateToUse = playbackRate ?: initialPlaybackRate ?: 1f
initialPlaybackRate = playbackRate
playbackSession.mediaPlayer = getMediaPlayer() playbackSession.mediaPlayer = getMediaPlayer()
if (playbackSession.mediaPlayer == "cast-player" && playbackSession.isLocal) { if (playbackSession.mediaPlayer == "cast-player" && playbackSession.isLocal) {
@@ -296,9 +298,9 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
clientEventEmitter?.onPlaybackSession(playbackSession) clientEventEmitter?.onPlaybackSession(playbackSession)
var metadata = playbackSession.getMediaMetadataCompat() val metadata = playbackSession.getMediaMetadataCompat()
mediaSession.setMetadata(metadata) mediaSession.setMetadata(metadata)
var mediaItems = playbackSession.getMediaItems() val mediaItems = playbackSession.getMediaItems()
if (mediaItems.isEmpty()) { if (mediaItems.isEmpty()) {
Log.e(tag, "Invalid playback session no media items to play") Log.e(tag, "Invalid playback session no media items to play")
@@ -307,20 +309,20 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
} }
if (mPlayer == currentPlayer) { if (mPlayer == currentPlayer) {
var mediaSource:MediaSource val mediaSource:MediaSource
if (playbackSession.isLocal) { if (playbackSession.isLocal) {
Log.d(tag, "Playing Local Item") Log.d(tag, "Playing Local Item")
var dataSourceFactory = DefaultDataSource.Factory(ctx) val dataSourceFactory = DefaultDataSource.Factory(ctx)
mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItems[0]) mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItems[0])
} else if (!playbackSession.isHLS) { } else if (!playbackSession.isHLS) {
Log.d(tag, "Direct Playing Item") Log.d(tag, "Direct Playing Item")
var dataSourceFactory = DefaultHttpDataSource.Factory() val dataSourceFactory = DefaultHttpDataSource.Factory()
dataSourceFactory.setUserAgent(channelId) dataSourceFactory.setUserAgent(channelId)
mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItems[0]) mediaSource = ProgressiveMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItems[0])
} else { } else {
Log.d(tag, "Playing HLS Item") Log.d(tag, "Playing HLS Item")
var dataSourceFactory = DefaultHttpDataSource.Factory() val dataSourceFactory = DefaultHttpDataSource.Factory()
dataSourceFactory.setUserAgent(channelId) dataSourceFactory.setUserAgent(channelId)
dataSourceFactory.setDefaultRequestProperties(hashMapOf("Authorization" to "Bearer ${DeviceManager.token}")) dataSourceFactory.setDefaultRequestProperties(hashMapOf("Authorization" to "Bearer ${DeviceManager.token}"))
mediaSource = HlsMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItems[0]) mediaSource = HlsMediaSource.Factory(dataSourceFactory).createMediaSource(mediaItems[0])
@@ -333,8 +335,8 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
currentPlayer.addMediaItems(mediaItems.subList(1, mediaItems.size)) currentPlayer.addMediaItems(mediaItems.subList(1, mediaItems.size))
Log.d(tag, "currentPlayer total media items ${currentPlayer.mediaItemCount}") Log.d(tag, "currentPlayer total media items ${currentPlayer.mediaItemCount}")
var currentTrackIndex = playbackSession.getCurrentTrackIndex() val currentTrackIndex = playbackSession.getCurrentTrackIndex()
var currentTrackTime = playbackSession.getCurrentTrackTimeMs() val currentTrackTime = playbackSession.getCurrentTrackTimeMs()
Log.d(tag, "currentPlayer current track index $currentTrackIndex & current track time $currentTrackTime") Log.d(tag, "currentPlayer current track index $currentTrackIndex & current track time $currentTrackTime")
currentPlayer.seekTo(currentTrackIndex, currentTrackTime) currentPlayer.seekTo(currentTrackIndex, currentTrackTime)
} else { } else {
@@ -343,16 +345,15 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
Log.d(tag, "Prepare complete for session ${currentPlaybackSession?.displayTitle} | ${currentPlayer.mediaItemCount}") Log.d(tag, "Prepare complete for session ${currentPlaybackSession?.displayTitle} | ${currentPlayer.mediaItemCount}")
currentPlayer.playWhenReady = playWhenReady currentPlayer.playWhenReady = playWhenReady
currentPlayer.setPlaybackSpeed(1f) // TODO: Playback speed should come from settings currentPlayer.setPlaybackSpeed(playbackRateToUse)
currentPlayer.prepare() currentPlayer.prepare()
} else if (castPlayer != null) { } else if (castPlayer != null) {
var currentTrackIndex = playbackSession.getCurrentTrackIndex() val currentTrackIndex = playbackSession.getCurrentTrackIndex()
var currentTrackTime = playbackSession.getCurrentTrackTimeMs() val currentTrackTime = playbackSession.getCurrentTrackTimeMs()
var mediaType = playbackSession.mediaType val mediaType = playbackSession.mediaType
Log.d(tag, "Loading cast player $currentTrackIndex $currentTrackTime $mediaType") Log.d(tag, "Loading cast player $currentTrackIndex $currentTrackTime $mediaType")
castPlayer?.load(mediaItems, currentTrackIndex, currentTrackTime, playWhenReady, 1f, mediaType) castPlayer?.load(mediaItems, currentTrackIndex, currentTrackTime, playWhenReady, playbackRateToUse, mediaType)
} }
} }
@@ -360,14 +361,14 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
// On error and was attempting to direct play - fallback to transcode // On error and was attempting to direct play - fallback to transcode
currentPlaybackSession?.let { playbackSession -> currentPlaybackSession?.let { playbackSession ->
if (playbackSession.isDirectPlay) { if (playbackSession.isDirectPlay) {
var mediaPlayer = getMediaPlayer() val mediaPlayer = getMediaPlayer()
Log.d(tag, "Fallback to transcode $mediaPlayer") Log.d(tag, "Fallback to transcode $mediaPlayer")
var libraryItemId = playbackSession.libraryItemId ?: "" // Must be true since direct play val libraryItemId = playbackSession.libraryItemId ?: "" // Must be true since direct play
var episodeId = playbackSession.episodeId val episodeId = playbackSession.episodeId
apiHandler.playLibraryItem(libraryItemId, episodeId, true, mediaPlayer) { apiHandler.playLibraryItem(libraryItemId, episodeId, true, mediaPlayer) {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post() {
preparePlayer(it, true) preparePlayer(it, true, null)
} }
} }
} else { } else {
@@ -378,7 +379,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
} }
fun switchToPlayer(useCastPlayer: Boolean) { fun switchToPlayer(useCastPlayer: Boolean) {
var wasPlaying = currentPlayer.isPlaying val wasPlaying = currentPlayer.isPlaying
if (useCastPlayer) { if (useCastPlayer) {
if (currentPlayer == castPlayer) { if (currentPlayer == castPlayer) {
Log.d(tag, "switchToPlayer: Already using Cast Player " + castPlayer?.deviceInfo) Log.d(tag, "switchToPlayer: Already using Cast Player " + castPlayer?.deviceInfo)
@@ -420,7 +421,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
if (wasPlaying) { // media is paused when switching players if (wasPlaying) { // media is paused when switching players
clientEventEmitter?.onPlayingUpdate(false) clientEventEmitter?.onPlayingUpdate(false)
} }
preparePlayer(it, false) preparePlayer(it, false, null)
} }
} }
@@ -499,8 +500,8 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
Log.d(tag, "seekPlayer mediaCount = ${currentPlayer.mediaItemCount} | $time") Log.d(tag, "seekPlayer mediaCount = ${currentPlayer.mediaItemCount} | $time")
if (currentPlayer.mediaItemCount > 1) { if (currentPlayer.mediaItemCount > 1) {
currentPlaybackSession?.currentTime = time / 1000.0 currentPlaybackSession?.currentTime = time / 1000.0
var newWindowIndex = currentPlaybackSession?.getCurrentTrackIndex() ?: 0 val newWindowIndex = currentPlaybackSession?.getCurrentTrackIndex() ?: 0
var newTimeOffset = currentPlaybackSession?.getCurrentTrackTimeMs() ?: 0 val newTimeOffset = currentPlaybackSession?.getCurrentTrackTimeMs() ?: 0
currentPlayer.seekTo(newWindowIndex, newTimeOffset) currentPlayer.seekTo(newWindowIndex, newTimeOffset)
} else { } else {
currentPlayer.seekTo(time) currentPlayer.seekTo(time)
@@ -528,7 +529,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
} }
fun sendClientMetadata(playerState: PlayerState) { fun sendClientMetadata(playerState: PlayerState) {
var duration = currentPlaybackSession?.getTotalDuration() ?: 0.0 val duration = currentPlaybackSession?.getTotalDuration() ?: 0.0
clientEventEmitter?.onMetadata(PlaybackMetadata(duration, getCurrentTimeSeconds(), playerState)) clientEventEmitter?.onMetadata(PlaybackMetadata(duration, getCurrentTimeSeconds(), playerState))
} }
@@ -593,7 +594,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
override fun onLoadChildren(parentMediaId: String, result: Result<MutableList<MediaBrowserCompat.MediaItem>>) { override fun onLoadChildren(parentMediaId: String, result: Result<MutableList<MediaBrowserCompat.MediaItem>>) {
Log.d(tag, "ON LOAD CHILDREN $parentMediaId") Log.d(tag, "ON LOAD CHILDREN $parentMediaId")
var flag = if (parentMediaId == AUTO_MEDIA_ROOT) MediaBrowserCompat.MediaItem.FLAG_BROWSABLE else MediaBrowserCompat.MediaItem.FLAG_PLAYABLE val flag = if (parentMediaId == AUTO_MEDIA_ROOT) MediaBrowserCompat.MediaItem.FLAG_BROWSABLE else MediaBrowserCompat.MediaItem.FLAG_PLAYABLE
result.detach() result.detach()
@@ -652,7 +653,7 @@ class PlayerNotificationService : MediaBrowserServiceCompat() {
shakeSensorUnregisterTask?.cancel() shakeSensorUnregisterTask?.cancel()
Log.d(tag, "Registering shake SENSOR ${mAccelerometer?.isWakeUpSensor}") Log.d(tag, "Registering shake SENSOR ${mAccelerometer?.isWakeUpSensor}")
var success = mSensorManager!!.registerListener( val success = mSensorManager!!.registerListener(
mShakeDetector, mShakeDetector,
mAccelerometer, mAccelerometer,
SensorManager.SENSOR_DELAY_UI SensorManager.SENSOR_DELAY_UI
@@ -23,8 +23,8 @@ class AbsAudioPlayer : Plugin() {
private val tag = "AbsAudioPlayer" private val tag = "AbsAudioPlayer"
var jacksonMapper = jacksonObjectMapper().enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature()) var jacksonMapper = jacksonObjectMapper().enable(JsonReadFeature.ALLOW_UNESCAPED_CONTROL_CHARS.mappedFeature())
lateinit var mainActivity: MainActivity private lateinit var mainActivity: MainActivity
lateinit var apiHandler:ApiHandler private lateinit var apiHandler:ApiHandler
lateinit var castManager:CastManager lateinit var castManager:CastManager
lateinit var playerNotificationService: PlayerNotificationService lateinit var playerNotificationService: PlayerNotificationService
@@ -37,7 +37,7 @@ class AbsAudioPlayer : Plugin() {
initCastManager() initCastManager()
var foregroundServiceReady : () -> Unit = { val foregroundServiceReady : () -> Unit = {
playerNotificationService = mainActivity.foregroundService playerNotificationService = mainActivity.foregroundService
playerNotificationService.clientEventEmitter = (object : PlayerNotificationService.ClientEventEmitter { playerNotificationService.clientEventEmitter = (object : PlayerNotificationService.ClientEventEmitter {
@@ -58,7 +58,7 @@ class AbsAudioPlayer : Plugin() {
} }
override fun onPrepare(audiobookId: String, playWhenReady: Boolean) { override fun onPrepare(audiobookId: String, playWhenReady: Boolean) {
var jsobj = JSObject() val jsobj = JSObject()
jsobj.put("audiobookId", audiobookId) jsobj.put("audiobookId", audiobookId)
jsobj.put("playWhenReady", playWhenReady) jsobj.put("playWhenReady", playWhenReady)
notifyListeners("onPrepareMedia", jsobj) notifyListeners("onPrepareMedia", jsobj)
@@ -89,13 +89,13 @@ class AbsAudioPlayer : Plugin() {
} }
fun emit(evtName: String, value: Any) { fun emit(evtName: String, value: Any) {
var ret = JSObject() val ret = JSObject()
ret.put("value", value) ret.put("value", value)
notifyListeners(evtName, ret) notifyListeners(evtName, ret)
} }
fun initCastManager() { private fun initCastManager() {
var connListener = object: CastManager.ChromecastListener() { val connListener = object: CastManager.ChromecastListener() {
override fun onReceiverAvailableUpdate(available: Boolean) { override fun onReceiverAvailableUpdate(available: Boolean) {
Log.d(tag, "ChromecastListener: CAST Receiver Update Available $available") Log.d(tag, "ChromecastListener: CAST Receiver Update Available $available")
isCastAvailable = available isCastAvailable = available
@@ -141,9 +141,10 @@ class AbsAudioPlayer : Plugin() {
} }
} }
var libraryItemId = call.getString("libraryItemId", "").toString() val libraryItemId = call.getString("libraryItemId", "").toString()
var episodeId = call.getString("episodeId", "").toString() val episodeId = call.getString("episodeId", "").toString()
var playWhenReady = call.getBoolean("playWhenReady") == true val playWhenReady = call.getBoolean("playWhenReady") == true
var playbackRate = call.getFloat("playbackRate",1f) ?: 1f
if (libraryItemId.isEmpty()) { if (libraryItemId.isEmpty()) {
Log.e(tag, "Invalid call to play library item no library item id") Log.e(tag, "Invalid call to play library item no library item id")
@@ -153,8 +154,8 @@ class AbsAudioPlayer : Plugin() {
if (libraryItemId.startsWith("local")) { // Play local media item if (libraryItemId.startsWith("local")) { // Play local media item
DeviceManager.dbManager.getLocalLibraryItem(libraryItemId)?.let { DeviceManager.dbManager.getLocalLibraryItem(libraryItemId)?.let {
var episode: PodcastEpisode? = null var episode: PodcastEpisode? = null
if (!episodeId.isNullOrEmpty()) { if (episodeId.isNotEmpty()) {
var podcastMedia = it.media as Podcast val podcastMedia = it.media as Podcast
episode = podcastMedia.episodes?.find { ep -> ep.id == episodeId } episode = podcastMedia.episodes?.find { ep -> ep.id == episodeId }
if (episode == null) { if (episode == null) {
Log.e(tag, "prepareLibraryItem: Podcast episode not found $episodeId") Log.e(tag, "prepareLibraryItem: Podcast episode not found $episodeId")
@@ -162,21 +163,21 @@ class AbsAudioPlayer : Plugin() {
} }
} }
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
Log.d(tag, "prepareLibraryItem: Preparing Local Media item ${jacksonMapper.writeValueAsString(it)}") Log.d(tag, "prepareLibraryItem: Preparing Local Media item ${jacksonMapper.writeValueAsString(it)}")
var playbackSession = it.getPlaybackSession(episode) val playbackSession = it.getPlaybackSession(episode)
playerNotificationService.preparePlayer(playbackSession, playWhenReady) playerNotificationService.preparePlayer(playbackSession, playWhenReady, playbackRate)
} }
return call.resolve(JSObject()) return call.resolve(JSObject())
} }
} else { // Play library item from server } else { // Play library item from server
var mediaPlayer = playerNotificationService.getMediaPlayer() val mediaPlayer = playerNotificationService.getMediaPlayer()
apiHandler.playLibraryItem(libraryItemId, episodeId, false, mediaPlayer) { apiHandler.playLibraryItem(libraryItemId, episodeId, false, mediaPlayer) {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
Log.d(tag, "Preparing Player TEST ${jacksonMapper.writeValueAsString(it)}") Log.d(tag, "Preparing Player TEST ${jacksonMapper.writeValueAsString(it)}")
playerNotificationService.preparePlayer(it, playWhenReady) playerNotificationService.preparePlayer(it, playWhenReady, playbackRate)
} }
call.resolve(JSObject(jacksonMapper.writeValueAsString(it))) call.resolve(JSObject(jacksonMapper.writeValueAsString(it)))
@@ -186,9 +187,9 @@ class AbsAudioPlayer : Plugin() {
@PluginMethod @PluginMethod
fun getCurrentTime(call: PluginCall) { fun getCurrentTime(call: PluginCall) {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
var currentTime = playerNotificationService.getCurrentTimeSeconds() val currentTime = playerNotificationService.getCurrentTimeSeconds()
var bufferedTime = playerNotificationService.getBufferedTimeSeconds() val bufferedTime = playerNotificationService.getBufferedTimeSeconds()
val ret = JSObject() val ret = JSObject()
ret.put("value", currentTime) ret.put("value", currentTime)
ret.put("bufferedTime", bufferedTime) ret.put("bufferedTime", bufferedTime)
@@ -198,7 +199,7 @@ class AbsAudioPlayer : Plugin() {
@PluginMethod @PluginMethod
fun pausePlayer(call: PluginCall) { fun pausePlayer(call: PluginCall) {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
playerNotificationService.pause() playerNotificationService.pause()
call.resolve() call.resolve()
} }
@@ -206,7 +207,7 @@ class AbsAudioPlayer : Plugin() {
@PluginMethod @PluginMethod
fun playPlayer(call: PluginCall) { fun playPlayer(call: PluginCall) {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
playerNotificationService.play() playerNotificationService.play()
call.resolve() call.resolve()
} }
@@ -214,16 +215,16 @@ class AbsAudioPlayer : Plugin() {
@PluginMethod @PluginMethod
fun playPause(call: PluginCall) { fun playPause(call: PluginCall) {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
var playing = playerNotificationService.playPause() val playing = playerNotificationService.playPause()
call.resolve(JSObject("{\"playing\":$playing}")) call.resolve(JSObject("{\"playing\":$playing}"))
} }
} }
@PluginMethod @PluginMethod
fun seek(call: PluginCall) { fun seek(call: PluginCall) {
var time:Int = call.getInt("value", 0) ?: 0 // Value in seconds val time:Int = call.getInt("value", 0) ?: 0 // Value in seconds
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
playerNotificationService.seekPlayer(time * 1000L) // convert to ms playerNotificationService.seekPlayer(time * 1000L) // convert to ms
call.resolve() call.resolve()
} }
@@ -231,8 +232,8 @@ class AbsAudioPlayer : Plugin() {
@PluginMethod @PluginMethod
fun seekForward(call: PluginCall) { fun seekForward(call: PluginCall) {
var amount:Int = call.getInt("value", 0) ?: 0 val amount:Int = call.getInt("value", 0) ?: 0
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
playerNotificationService.seekForward(amount * 1000L) // convert to ms playerNotificationService.seekForward(amount * 1000L) // convert to ms
call.resolve() call.resolve()
} }
@@ -240,8 +241,8 @@ class AbsAudioPlayer : Plugin() {
@PluginMethod @PluginMethod
fun seekBackward(call: PluginCall) { fun seekBackward(call: PluginCall) {
var amount:Int = call.getInt("value", 0) ?: 0 // Value in seconds val amount:Int = call.getInt("value", 0) ?: 0 // Value in seconds
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
playerNotificationService.seekBackward(amount * 1000L) // convert to ms playerNotificationService.seekBackward(amount * 1000L) // convert to ms
call.resolve() call.resolve()
} }
@@ -249,9 +250,9 @@ class AbsAudioPlayer : Plugin() {
@PluginMethod @PluginMethod
fun setPlaybackSpeed(call: PluginCall) { fun setPlaybackSpeed(call: PluginCall) {
var playbackSpeed:Float = call.getFloat("value", 1.0f) ?: 1.0f val playbackSpeed:Float = call.getFloat("value", 1.0f) ?: 1.0f
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
playerNotificationService.setPlaybackSpeed(playbackSpeed) playerNotificationService.setPlaybackSpeed(playbackSpeed)
call.resolve() call.resolve()
} }
@@ -259,7 +260,7 @@ class AbsAudioPlayer : Plugin() {
@PluginMethod @PluginMethod
fun closePlayback(call: PluginCall) { fun closePlayback(call: PluginCall) {
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
playerNotificationService.closePlayback() playerNotificationService.closePlayback()
call.resolve() call.resolve()
} }
@@ -267,11 +268,11 @@ class AbsAudioPlayer : Plugin() {
@PluginMethod @PluginMethod
fun setSleepTimer(call: PluginCall) { fun setSleepTimer(call: PluginCall) {
var time:Long = call.getString("time", "360000")!!.toLong() val time:Long = call.getString("time", "360000")!!.toLong()
var isChapterTime:Boolean = call.getBoolean("isChapterTime", false) == true val isChapterTime:Boolean = call.getBoolean("isChapterTime", false) == true
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
var success:Boolean = playerNotificationService.sleepTimerManager.setSleepTimer(time, isChapterTime) val success:Boolean = playerNotificationService.sleepTimerManager.setSleepTimer(time, isChapterTime)
val ret = JSObject() val ret = JSObject()
ret.put("success", success) ret.put("success", success)
call.resolve(ret) call.resolve(ret)
@@ -280,7 +281,7 @@ class AbsAudioPlayer : Plugin() {
@PluginMethod @PluginMethod
fun getSleepTimerTime(call: PluginCall) { fun getSleepTimerTime(call: PluginCall) {
var time = playerNotificationService.sleepTimerManager.getSleepTimerTime() val time = playerNotificationService.sleepTimerManager.getSleepTimerTime()
val ret = JSObject() val ret = JSObject()
ret.put("value", time) ret.put("value", time)
call.resolve(ret) call.resolve(ret)
@@ -288,9 +289,9 @@ class AbsAudioPlayer : Plugin() {
@PluginMethod @PluginMethod
fun increaseSleepTime(call: PluginCall) { fun increaseSleepTime(call: PluginCall) {
var time:Long = call.getString("time", "300000")!!.toLong() val time:Long = call.getString("time", "300000")!!.toLong()
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
playerNotificationService.sleepTimerManager.increaseSleepTime(time) playerNotificationService.sleepTimerManager.increaseSleepTime(time)
val ret = JSObject() val ret = JSObject()
ret.put("success", true) ret.put("success", true)
@@ -300,9 +301,9 @@ class AbsAudioPlayer : Plugin() {
@PluginMethod @PluginMethod
fun decreaseSleepTime(call: PluginCall) { fun decreaseSleepTime(call: PluginCall) {
var time:Long = call.getString("time", "300000")!!.toLong() val time:Long = call.getString("time", "300000")!!.toLong()
Handler(Looper.getMainLooper()).post() { Handler(Looper.getMainLooper()).post {
playerNotificationService.sleepTimerManager.decreaseSleepTime(time) playerNotificationService.sleepTimerManager.decreaseSleepTime(time)
val ret = JSObject() val ret = JSObject()
ret.put("success", true) ret.put("success", true)
@@ -338,7 +339,7 @@ class AbsAudioPlayer : Plugin() {
@PluginMethod @PluginMethod
fun getIsCastAvailable(call: PluginCall) { fun getIsCastAvailable(call: PluginCall) {
var jsobj = JSObject() val jsobj = JSObject()
jsobj.put("value", isCastAvailable) jsobj.put("value", isCastAvailable)
call.resolve(jsobj) call.resolve(jsobj)
} }
+6 -1
View File
@@ -184,8 +184,13 @@ export default {
this.serverLibraryItemId = null this.serverLibraryItemId = null
var playbackRate = 1
if (this.$refs.audioPlayer) {
playbackRate = this.$refs.audioPlayer.currentPlaybackRate || 1
}
console.log('Called playLibraryItem', libraryItemId) console.log('Called playLibraryItem', libraryItemId)
AbsAudioPlayer.prepareLibraryItem({ libraryItemId, episodeId, playWhenReady: true }) AbsAudioPlayer.prepareLibraryItem({ libraryItemId, episodeId, playWhenReady: true, playbackRate })
.then((data) => { .then((data) => {
console.log('Library item play response', JSON.stringify(data)) console.log('Library item play response', JSON.stringify(data))
if (!libraryItemId.startsWith('local')) { if (!libraryItemId.startsWith('local')) {