Compare commits

..

1 Commits

Author SHA1 Message Date
tanhakabir 7d65841f1c fix recursive polling logic 2021-04-16 10:04:33 -07:00
8 changed files with 30 additions and 69 deletions
-4
View File
@@ -17,7 +17,6 @@
A40DBE292391D9CA00F86146 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = A40DBE282391D9C900F86146 /* Data.swift */; };
A411CE4625F9609D0039E1CD /* SAPlayerFeatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = A411CE4525F9609D0039E1CD /* SAPlayerFeatures.swift */; };
A41AA0D2238BB9B600A467E1 /* SAPlayingStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = A41AA0D1238BB9B600A467E1 /* SAPlayingStatus.swift */; };
A42157B22609BF8900253D01 /* SAPlayerNetwork.swift in Sources */ = {isa = PBXBuildFile; fileRef = A42157B12609BF8900253D01 /* SAPlayerNetwork.swift */; };
A4681FC6220113880018AB51 /* SAPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4681F8D2200E00E0018AB51 /* SAPlayer.swift */; };
A4681FC72201138B0018AB51 /* SAPlayerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4681F912200E1950018AB51 /* SAPlayerDelegate.swift */; };
A4681FC82201138E0018AB51 /* SAPlayerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = A4681F8F2200E1450018AB51 /* SAPlayerPresenter.swift */; };
@@ -104,7 +103,6 @@
A40DBE282391D9C900F86146 /* Data.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = "<group>"; };
A411CE4525F9609D0039E1CD /* SAPlayerFeatures.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SAPlayerFeatures.swift; sourceTree = "<group>"; };
A41AA0D1238BB9B600A467E1 /* SAPlayingStatus.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SAPlayingStatus.swift; sourceTree = "<group>"; };
A42157B12609BF8900253D01 /* SAPlayerNetwork.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SAPlayerNetwork.swift; sourceTree = "<group>"; };
A4523BC8220A0B3C0079C4BC /* Credited_LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = Credited_LICENSE; sourceTree = "<group>"; };
A4681F802200D0500018AB51 /* Log.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = "<group>"; };
A4681F822200D9150018AB51 /* AudioEngine.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioEngine.swift; sourceTree = "<group>"; };
@@ -363,7 +361,6 @@
A411CE4525F9609D0039E1CD /* SAPlayerFeatures.swift */,
A4FBA6B6221BAC3D00D5A353 /* SAPlayerUpdateSubscription.swift */,
A4B4CC112223ED2A0045554B /* SAPlayerDownloader.swift */,
A42157B12609BF8900253D01 /* SAPlayerNetwork.swift */,
A4681F912200E1950018AB51 /* SAPlayerDelegate.swift */,
A4681F8F2200E1450018AB51 /* SAPlayerPresenter.swift */,
A4681FBE22010ECF0018AB51 /* LockScreenViewProtocol.swift */,
@@ -551,7 +548,6 @@
A4681FE1220113E70018AB51 /* Constants.swift in Sources */,
A40DBE292391D9CA00F86146 /* Data.swift in Sources */,
A4FBA6B5221B74C900D5A353 /* SALockScreenInfo.swift in Sources */,
A42157B22609BF8900253D01 /* SAPlayerNetwork.swift in Sources */,
A4681FC6220113880018AB51 /* SAPlayer.swift in Sources */,
A4FBA6B7221BAC3D00D5A353 /* SAPlayerUpdateSubscription.swift in Sources */,
A4681FC72201138B0018AB51 /* SAPlayerDelegate.swift in Sources */,
@@ -68,7 +68,7 @@ class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
SAPlayer.Network.CellularData.allowUsage = true
SAPlayer.Downloader.allowUsingCellularData = true
// SAPlayer.shared.DEBUG_MODE = true
+1
View File
@@ -173,6 +173,7 @@ class AudioEngine: AudioEngineProtocol {
Timer.scheduledTimer(withTimeInterval: timeInterval, repeats: false) { [weak self] (timer: Timer) in
guard let self = self else { return }
guard self.playingStatus != .ended else {
// Log.test("END TIMER")
self.delegate = nil
return
}
+14 -3
View File
@@ -71,6 +71,7 @@ class AudioStreamEngine: AudioEngine {
private var numberOfBuffersScheduledInTotal = 0 {
didSet {
// Log.test(numberOfBuffersScheduledInTotal)
Log.debug("number of buffers scheduled in total: \(numberOfBuffersScheduledInTotal)")
if numberOfBuffersScheduledInTotal == 0 {
pause()
@@ -86,6 +87,7 @@ class AudioStreamEngine: AudioEngine {
private var numberOfBuffersScheduledFromPoll = 0 {
didSet {
if numberOfBuffersScheduledFromPoll > MAX_POLL_BUFFER_COUNT {
// Log.test("🛑 🛑 STOP POLLING")
shouldPollForNextBuffer = false
}
@@ -149,7 +151,7 @@ class AudioStreamEngine: AudioEngine {
guard let self = self else { return }
guard self.playingStatus != .ended else { return }
self.pollForNextBufferRecursive()
self.pollForNextBuffer()
self.updateNetworkBufferRange()
self.updateNeedle()
self.updateIsPlaying()
@@ -162,9 +164,16 @@ class AudioStreamEngine: AudioEngine {
//Called when
//1. First time audio is finally parsed
//2. When we run to the end of the network buffer and we're waiting again
private func pollForNextBufferRecursive() {
private func pollForNextBuffer() {
guard shouldPollForNextBuffer else { return }
// Log.test("POLL INIT")
pollForNextBufferRecursive()
}
private func pollForNextBufferRecursive() {
// Log.test("POLL")
do {
var nextScheduledBuffer: AVAudioPCMBuffer! = try converter.pullBuffer()
numberOfBuffersScheduledFromPoll += 1
@@ -174,15 +183,17 @@ class AudioStreamEngine: AudioEngine {
queue.async { [weak self] in
if #available(iOS 11.0, *) {
// to make sure the pcm buffers are properly free'd from memory we need to nil them after the player has used them
self?.playerNode.scheduleBuffer(nextScheduledBuffer, completionCallbackType: .dataRendered, completionHandler: { (_) in
self?.playerNode.scheduleBuffer(nextScheduledBuffer, completionCallbackType: .dataConsumed, completionHandler: { (_) in
nextScheduledBuffer = nil
self?.numberOfBuffersScheduledInTotal -= 1
// Log.test("POLL DATA RENDERED")
self?.pollForNextBufferRecursive()
})
} else {
self?.playerNode.scheduleBuffer(nextScheduledBuffer) {
nextScheduledBuffer = nil
self?.numberOfBuffersScheduledInTotal -= 1
// Log.test("POLL OLD")
self?.pollForNextBufferRecursive()
}
}
+3 -6
View File
@@ -29,6 +29,8 @@ protocol AudioDataManagable {
var numberOfQueued: Int { get }
var numberOfActive: Int { get }
var allowCellular: Bool { get set }
func setBackgroundCompletionHandler(_ completionHandler: @escaping () -> ())
func setAllowCellularDownloadPreference(_ preference: Bool)
@@ -51,7 +53,6 @@ protocol AudioDataManagable {
class AudioDataManager: AudioDataManagable {
var allowCellular: Bool = true
var userAgent: String?
static let shared: AudioDataManagable = AudioDataManager()
@@ -103,10 +104,6 @@ class AudioDataManager: AudioDataManagable {
allowCellular = preference
}
func setUserAgent(_ userAgent: String) {
self.userAgent = userAgent
}
func attach(callback: @escaping (_ id: ID, _ progress: Double)->()) {
globalDownloadProgressCallback = callback
}
@@ -131,7 +128,7 @@ extension AudioDataManager {
downloadWorker.stop(withID: url.key) { [weak self] (fetchedData: Data?, totalBytesExpected: Int64?) in
self?.downloadWorker.pauseAllActive()
self?.streamWorker.start(withID: url.key, withRemoteURL: url, withInitialData: fetchedData, andTotalBytesExpectedPreviously: totalBytesExpected, withUserAgent: userAgent)
self?.streamWorker.start(withID: url.key, withRemoteURL: url, withInitialData: fetchedData, andTotalBytesExpectedPreviously: totalBytesExpected)
}
}
@@ -44,7 +44,7 @@ import Foundation
protocol AudioDataStreamable {
//if user taps download then starts to stream
init(progressCallback: @escaping (_ id: ID, _ dto: StreamProgressDTO) -> (), doneCallback: @escaping (_ id: ID, _ error: Error?)->Bool) //Bool is should save or not
func start(withID id: ID, withRemoteURL url: URL, withInitialData data: Data?, andTotalBytesExpectedPreviously previousTotalBytesExpected: Int64?, withUserAgent userAgent: String?)
func start(withID id: ID, withRemoteURL url: URL, withInitialData data: Data?, andTotalBytesExpectedPreviously previousTotalBytesExpected: Int64?)
func pause(withId id: ID)
func resume(withId id: ID)
func stop(withId id: ID)//FIXME: with persistent play we should return a Data so that download can resume
@@ -95,7 +95,7 @@ class AudioStreamWorker:NSObject, AudioDataStreamable {
self.session = URLSession(configuration: config, delegate: self, delegateQueue: nil) //TODO: should we use ephemeral
}
func start(withID id: ID, withRemoteURL url: URL, withInitialData data: Data? = nil, andTotalBytesExpectedPreviously previousTotalBytesExpected: Int64? = nil, withUserAgent userAgent: String?) {
func start(withID id: ID, withRemoteURL url: URL, withInitialData data: Data? = nil, andTotalBytesExpectedPreviously previousTotalBytesExpected: Int64? = nil) {
Log.info("selfID: \(self.id ?? "none"), paramID: \(id) initialData: \(data?.count ?? 0)")
killPreviousTaskIfNeeded()
+9
View File
@@ -100,5 +100,14 @@ extension SAPlayer {
public static func setBackgroundCompletionHandler(_ completionHandler: @escaping () -> ()) {
AudioDataManager.shared.setBackgroundCompletionHandler(completionHandler)
}
/**
Whether downloading audio on cellular data is allowed. By default this is set to `true`.
*/
public static var allowUsingCellularData = true {
didSet {
AudioDataManager.shared.setAllowCellularDownloadPreference(allowUsingCellularData)
}
}
}
}
-53
View File
@@ -1,53 +0,0 @@
//
// SAPlayerNetwork.swift
// SwiftAudioPlayer
//
// Created by Tanha Kabir on 3/22/21.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import Foundation
extension SAPlayer {
/**
Actions relating to remote requests being made to download or stream audio data.
*/
public struct Network {
/**
Handle permissions for downloading and/or streaming on cellular data.
*/
public struct CellularData {
/**
Whether downloading audio on cellular data is allowed. By default this is set to `true`.
*/
public static var allowUsage = true {
didSet {
AudioDataManager.shared.setAllowCellularDownloadPreference(allowUsage)
}
}
}
}
public struct Request {
public func setUserAgent(with userAgent: String) {
}
}
}