mirror of
https://github.com/advplyr/audiobookshelf-app.git
synced 2025-08-04 01:54:33 +02:00
fix: seek pauses playback
This commit is contained in:
parent
40b2ff5a97
commit
cbd74d08e1
6 changed files with 49 additions and 47 deletions
|
@ -783,8 +783,6 @@ export default {
|
|||
|
||||
console.log('received metadata update', data)
|
||||
|
||||
if (data.currentRate && data.currentRate > 0) this.playbackSpeed = data.currentRate
|
||||
|
||||
this.timeupdate()
|
||||
},
|
||||
// When a playback session is started the native android/ios will send the session
|
||||
|
|
|
@ -159,7 +159,7 @@ public class AbsAudioPlayer: CAPPlugin {
|
|||
|
||||
@objc func sendMetadata() {
|
||||
self.notifyListeners("onPlayingUpdate", data: [ "value": !PlayerHandler.paused ])
|
||||
if let metadata = PlayerHandler.getMetdata() {
|
||||
if let metadata = try? PlayerHandler.getMetdata()?.asDictionary() {
|
||||
self.notifyListeners("onMetadata", data: metadata)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,8 +7,8 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
class PlaybackMetadata: Codable {
|
||||
var duration: Double = 0
|
||||
var currentTime: Double = 0
|
||||
var playerState: PlayerState = PlayerState.IDLE
|
||||
struct PlaybackMetadata: Codable {
|
||||
let duration: Double
|
||||
let currentTime: Double
|
||||
let playerState: PlayerState
|
||||
}
|
||||
|
|
|
@ -7,9 +7,9 @@
|
|||
|
||||
import Foundation
|
||||
|
||||
enum PlayerState: Codable {
|
||||
case IDLE
|
||||
case BUFFERING
|
||||
case READY
|
||||
case ENDED
|
||||
enum PlayerState: String, Codable {
|
||||
case idle = "IDLE"
|
||||
case buffering = "BUFFERING"
|
||||
case ready = "READY"
|
||||
case ended = "ENDED"
|
||||
}
|
||||
|
|
|
@ -10,21 +10,26 @@ import AVFoundation
|
|||
import UIKit
|
||||
import MediaPlayer
|
||||
|
||||
enum PlayMethod:Int {
|
||||
enum PlayMethod: Int {
|
||||
case directplay = 0
|
||||
case directstream = 1
|
||||
case transcode = 2
|
||||
case local = 3
|
||||
}
|
||||
|
||||
enum PlayerStatus: Int {
|
||||
case uninitialized = -1
|
||||
case paused = 0
|
||||
case playing = 1
|
||||
}
|
||||
|
||||
class AudioPlayer: NSObject {
|
||||
internal let queue = DispatchQueue(label: "ABSAudioPlayerQueue")
|
||||
internal let logger = AppLogger(category: "AudioPlayer")
|
||||
|
||||
// enums and @objc are not compatible
|
||||
@objc dynamic var status: Int
|
||||
@objc dynamic var rate: Float
|
||||
|
||||
|
||||
private var status: PlayerStatus
|
||||
internal var rate: Float
|
||||
|
||||
private var tmpRate: Float = 1.0
|
||||
|
||||
private var playerContext = 0
|
||||
|
@ -59,7 +64,7 @@ class AudioPlayer: NSObject {
|
|||
self.audioPlayer = AVQueuePlayer()
|
||||
self.audioPlayer.automaticallyWaitsToMinimizeStalling = false
|
||||
self.sessionId = sessionId
|
||||
self.status = -1
|
||||
self.status = .uninitialized
|
||||
self.rate = 0.0
|
||||
self.tmpRate = playbackRate
|
||||
|
||||
|
@ -141,7 +146,7 @@ class AudioPlayer: NSObject {
|
|||
}
|
||||
|
||||
public func isInitialized() -> Bool {
|
||||
return self.status != -1
|
||||
return self.status != .uninitialized
|
||||
}
|
||||
|
||||
public func getPlaybackSession() -> PlaybackSession? {
|
||||
|
@ -254,7 +259,7 @@ class AudioPlayer: NSObject {
|
|||
logger.log("queueStatusObserver: Current Item Ready to play. PlayWhenReady: \(self.playWhenReady)")
|
||||
|
||||
// Seek the player before initializing, so a currentTime of 0 does not appear in MediaProgress / session
|
||||
let firstReady = self.status < 0
|
||||
let firstReady = self.status == .uninitialized
|
||||
if firstReady && !self.playWhenReady {
|
||||
// Seek is async, and if we call this when also pressing play, we will get weird jumps in the scrub bar depending on timing
|
||||
// Seeking to the correct position happens during play()
|
||||
|
@ -267,7 +272,7 @@ class AudioPlayer: NSObject {
|
|||
self.play(allowSeekBack: false, isInitializing: true)
|
||||
} else {
|
||||
// Mark the player as ready
|
||||
self.status = 0
|
||||
self.status = .paused
|
||||
}
|
||||
} else if (playerItem.status == .failed) {
|
||||
logger.error("queueStatusObserver: FAILED \(playerItem.error?.localizedDescription ?? "")")
|
||||
|
@ -327,8 +332,8 @@ class AudioPlayer: NSObject {
|
|||
self.audioPlayer.play()
|
||||
self.audioPlayer.rate = self.tmpRate
|
||||
}
|
||||
self.status = 1
|
||||
|
||||
self.status = .playing
|
||||
|
||||
// Update the progress
|
||||
self.updateNowPlaying()
|
||||
|
||||
|
@ -351,20 +356,16 @@ class AudioPlayer: NSObject {
|
|||
}
|
||||
}
|
||||
|
||||
self.status = 0
|
||||
|
||||
self.status = .paused
|
||||
updateNowPlaying()
|
||||
|
||||
self.startPausedTimer()
|
||||
}
|
||||
|
||||
public func seek(_ to: Double, from: String) {
|
||||
let continuePlaying = rate > 0.0
|
||||
|
||||
self.pause()
|
||||
|
||||
logger.log("SEEK: Seek to \(to) from \(from) and continuePlaying(\(continuePlaying)")
|
||||
|
||||
logger.log("SEEK: Seek to \(to) from \(from)")
|
||||
|
||||
guard let playbackSession = self.getPlaybackSession() else { return }
|
||||
|
||||
let currentTrack = playbackSession.audioTracks[self.currentTrackIndex]
|
||||
|
@ -383,8 +384,6 @@ class AudioPlayer: NSObject {
|
|||
playbackSession.currentTime = to
|
||||
}
|
||||
|
||||
self.playWhenReady = continuePlaying // Only playWhenReady if already playing
|
||||
self.status = -1
|
||||
let playerItems = self.allPlayerItems[indexOfSeek..<self.allPlayerItems.count]
|
||||
|
||||
DispatchQueue.runOnMainQueue {
|
||||
|
@ -402,17 +401,13 @@ class AudioPlayer: NSObject {
|
|||
|
||||
DispatchQueue.runOnMainQueue {
|
||||
self.audioPlayer.seek(to: CMTime(seconds: seekTime, preferredTimescale: 1000)) { [weak self] completed in
|
||||
self?.logger.log("SEEK: Completion handler called and continuePlaying(\(continuePlaying)")
|
||||
self?.logger.log("SEEK: Completion handler called")
|
||||
guard completed else {
|
||||
self?.logger.log("SEEK: WARNING: seeking not completed (to \(seekTime)")
|
||||
return
|
||||
}
|
||||
guard let self = self else { return }
|
||||
|
||||
if continuePlaying {
|
||||
self.resumePlayback()
|
||||
}
|
||||
|
||||
self.updateNowPlaying()
|
||||
}
|
||||
}
|
||||
|
@ -463,9 +458,19 @@ class AudioPlayer: NSObject {
|
|||
}
|
||||
|
||||
public func isPlaying() -> Bool {
|
||||
return self.status > 0
|
||||
return self.status == .playing
|
||||
}
|
||||
|
||||
public func getPlayerState() -> PlayerState {
|
||||
// Other PlayerStates doesn't translate to player status
|
||||
switch status {
|
||||
case .uninitialized:
|
||||
return PlayerState.buffering
|
||||
default:
|
||||
return PlayerState.ready
|
||||
}
|
||||
}
|
||||
|
||||
// MARK: - Private
|
||||
private func createAsset(itemId:String, track:AudioTrack) -> AVAsset? {
|
||||
guard let playbackSession = self.getPlaybackSession() else { return nil }
|
||||
|
|
|
@ -118,16 +118,15 @@ class PlayerHandler {
|
|||
player.seek(amount, from: "handler")
|
||||
}
|
||||
|
||||
public static func getMetdata() -> [String: Any]? {
|
||||
public static func getMetdata() -> PlaybackMetadata? {
|
||||
guard let player = player else { return nil }
|
||||
guard player.isInitialized() else { return nil }
|
||||
|
||||
return [
|
||||
"duration": player.getDuration(),
|
||||
"currentTime": player.getCurrentTime(),
|
||||
"playerState": !paused,
|
||||
"currentRate": player.rate,
|
||||
]
|
||||
|
||||
return PlaybackMetadata(
|
||||
duration: player.getDuration() ?? 0,
|
||||
currentTime: player.getCurrentTime() ?? 0,
|
||||
playerState: player.getPlayerState()
|
||||
)
|
||||
}
|
||||
|
||||
// MARK: - Helper logic
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue