Compare commits

..

16 Commits

Author SHA1 Message Date
tanhakabir 2abba6f0cc Release 2.11.0 2020-10-22 12:22:20 -07:00
tanhakabir f081b7549d add endpoint to remove default pitch modifier (#51) 2020-10-22 11:59:01 -07:00
tanhakabir 55fbae7b4a Update README to include module name for import (#47) 2020-09-19 16:02:46 -07:00
tanhakabir 2acbde2efa Release 2.10.0 2020-09-19 15:52:25 -07:00
Moises Inzunza acbdf05d4f Fixed bug in swift 5.3 (#46) 2020-09-19 12:19:50 -07:00
Tanha c325caa914 Release 2.9.0 2020-03-06 23:53:42 -08:00
tanhakabir dd54d81573 implement streaming cancellation (#32)
* cancels streaming initally, but player enters weird state trying to stream again

* calling superclass invalidate from engines for good measure

* Fix UI to fix seemingly weird state

* Fix error warning
2020-03-06 23:52:22 -08:00
tanhakabir ebc282d5c2 fix crash on cancel streaming pressed (#30) 2020-03-06 23:28:30 -08:00
Tanha 80ce253f92 Release 2.8.2 2020-01-21 00:29:28 -08:00
tanhakabir fe2395066f Add equalizer example (#28)
* project configure for me

* to see log

* set project

* new UI

* fix ui

* re-fix UI

* add example of equalizer

* Revert "re-fix UI"

This reverts commit 05ed993a52.

* Revert "fix ui"

This reverts commit 0da9f6adea.

* Revert "new UI"

This reverts commit ffd6a95a2d.

* Add verbose debug mode to player

Co-authored-by: cendolinside123 <jnsbstn391@gmail.com>
2020-01-21 00:27:51 -08:00
Tanha 3e66b4b4d4 Release 2.8.1 2020-01-04 13:35:29 -08:00
Tanha 58bbc97a1b Minor fix on end of audio notification 2020-01-04 13:35:03 -08:00
Tanha 8d9e9d92f4 Release 2.8.0 2020-01-04 13:24:47 -08:00
tanhakabir 03392c21e0 fix bug in notification of end of audio in PlayingStatus (#25) 2020-01-04 13:23:50 -08:00
Tanha 924170d159 Release 2.7.0 2020-01-04 02:04:35 -08:00
tanhakabir b355eb4e09 add api for buffer progress in SAAvailabilityRange (#24) 2020-01-04 02:02:56 -08:00
15 changed files with 230 additions and 49 deletions
@@ -212,12 +212,12 @@
TargetAttributes = {
607FACCF1AFB9204008FA782 = {
CreatedOnToolsVersion = 6.3.1;
DevelopmentTeam = R2392A68YQ;
DevelopmentTeam = H9Y26B6GZB;
LastSwiftMigration = 1120;
};
607FACE41AFB9204008FA782 = {
CreatedOnToolsVersion = 6.3.1;
DevelopmentTeam = R2392A68YQ;
DevelopmentTeam = H9Y26B6GZB;
LastSwiftMigration = 1120;
TestTargetID = 607FACCF1AFB9204008FA782;
};
@@ -475,11 +475,11 @@
baseConfigurationReference = 65A66AB4C3016E8BB53FF3E0 /* Pods-SwiftAudioPlayer_Example.debug.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = R2392A68YQ;
DEVELOPMENT_TEAM = H9Y26B6GZB;
INFOPLIST_FILE = SwiftAudioPlayer/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MODULE_NAME = ExampleApp;
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo-test.SwiftAudioPlayer-Example";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
@@ -490,11 +490,11 @@
baseConfigurationReference = 4B5DD2AE0B23A759D18926DC /* Pods-SwiftAudioPlayer_Example.release.xcconfig */;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
DEVELOPMENT_TEAM = R2392A68YQ;
DEVELOPMENT_TEAM = H9Y26B6GZB;
INFOPLIST_FILE = SwiftAudioPlayer/Info.plist;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MODULE_NAME = ExampleApp;
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo.$(PRODUCT_NAME:rfc1034identifier)";
PRODUCT_BUNDLE_IDENTIFIER = "org.cocoapods.demo-test.SwiftAudioPlayer-Example";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
};
@@ -504,7 +504,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = BBD877782CC67FBCC7BF7532 /* Pods-SwiftAudioPlayer_Tests.debug.xcconfig */;
buildSettings = {
DEVELOPMENT_TEAM = R2392A68YQ;
DEVELOPMENT_TEAM = H9Y26B6GZB;
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
@@ -526,7 +526,7 @@
isa = XCBuildConfiguration;
baseConfigurationReference = 0B7D1E6C00E83B4AF8AA1781 /* Pods-SwiftAudioPlayer_Tests.release.xcconfig */;
buildSettings = {
DEVELOPMENT_TEAM = R2392A68YQ;
DEVELOPMENT_TEAM = H9Y26B6GZB;
FRAMEWORK_SEARCH_PATHS = (
"$(SDKROOT)/Developer/Library/Frameworks",
"$(inherited)",
+35 -6
View File
@@ -59,7 +59,7 @@ class ViewController: UIViewController {
self.currentUrlLocationLabel.text = "remote url: \(selectedAudio.url.absoluteString)"
}
}
var freq:[Int] = [0,0,0,0,0,0,0,0,0,0]
@IBOutlet weak var currentUrlLocationLabel: UILabel!
@IBOutlet weak var bufferProgress: UIProgressView!
@IBOutlet weak var scrubberSlider: UISlider!
@@ -103,6 +103,8 @@ class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
SAPlayer.shared.DEBUG_MODE = true
isPlayable = false
selectedAudio = AudioInfo(index: 0)
@@ -145,12 +147,12 @@ class ViewController: UIViewController {
if self.duration == 0.0 { return }
let progress = Float((buffer.totalDurationBuffered + buffer.startingBufferTimePositon) / self.duration)
self.bufferProgress.progress = Float(buffer.bufferingProgress)
self.bufferProgress.progress = progress
if progress >= 0.99 {
if buffer.bufferingProgress >= 0.99 {
self.streamButton.isEnabled = false
} else {
self.streamButton.isEnabled = true
}
self.isPlayable = buffer.isReadyForPlaying
@@ -185,6 +187,16 @@ class ViewController: UIViewController {
let node = AVAudioUnitReverb()
SAPlayer.shared.audioModifiers.append(node)
node.wetDryMix = 300
let frequency:[Int] = [60,170,310,600,1000,3000,6000,12000,14000,16000]
let node2 = AVAudioUnitEQ(numberOfBands:frequency.count)
node2.globalGain = 1
for i in 0...(node2.bands.count-1) {
node2.bands[i].frequency = Float(frequency[i])
node2.bands[i].gain = 0
node2.bands[i].bypass = false
node2.bands[i].filterType = .parametric
}
SAPlayer.shared.audioModifiers.append(node2)
}
override func didReceiveMemoryWarning() {
@@ -262,8 +274,12 @@ class ViewController: UIViewController {
SAPlayer.shared.startRemoteAudio(withRemoteUrl: selectedAudio.url)
streamButton.setTitle("Cancel streaming", for: .normal)
downloadButton.isEnabled = false
isStreaming = true
} else {
// TODO
SAPlayer.shared.stopStreamingRemoteAudio()
streamButton.setTitle("Stream", for: .normal)
downloadButton.isEnabled = true
isStreaming = false
}
}
@@ -278,6 +294,19 @@ class ViewController: UIViewController {
@IBAction func skipForwardTouched(_ sender: Any) {
SAPlayer.shared.skipForward()
}
@IBAction func setEqualizerValue(_ sender: Any) {
if let slider = sender as? UISlider{
print("slider of index:", slider.tag, "is changed to", slider.value)
freq[slider.tag] = Int(slider.value)
print("current frequency : ",freq)
if let node = SAPlayer.shared.audioModifiers[2] as? AVAudioUnitEQ{
for i in 0...(node.bands.count - 1){
node.bands[i].gain = Float(freq[i])
}
}
}
}
}
+5
View File
@@ -34,6 +34,11 @@ pod 'SwiftAudioPlayer'
### Usage
Import the player at the top:
```swift
import SwiftAudioPlayer
```
**Important:** For app in background downloading please refer to [note](#important-step-for-background-downloads).
To play remote audio:
+2 -1
View File
@@ -64,7 +64,7 @@ class AudioDiskEngine: AudioEngine {
audioSampleRate = Float(audioFormat?.sampleRate ?? 44100)
audioLengthSeconds = Float(audioLengthSamples) / audioSampleRate
duration = Duration(audioLengthSeconds)
bufferedSeconds = SAAudioAvailabilityRange(startingNeedle: 0, durationLoadedByNetwork: duration, isPlayable: true)
bufferedSeconds = SAAudioAvailabilityRange(startingNeedle: 0, durationLoadedByNetwork: duration, predictedDurationToLoad: duration, isPlayable: true)
} else {
Log.monitor("Could not load downloaded file with url: \(url)")
}
@@ -136,6 +136,7 @@ class AudioDiskEngine: AudioEngine {
}
override func invalidate() {
super.invalidate()
//Nothing to invalidate for disk
}
}
+7 -3
View File
@@ -86,8 +86,8 @@ class AudioEngine: AudioEngineProtocol {
}
}
var bufferedSecondsDebouncer: SAAudioAvailabilityRange = SAAudioAvailabilityRange(startingNeedle: 0.0, durationLoadedByNetwork: 0.0, isPlayable: false)
var bufferedSeconds: SAAudioAvailabilityRange = SAAudioAvailabilityRange(startingNeedle: 0.0, durationLoadedByNetwork: 0.0, isPlayable: false) {
var bufferedSecondsDebouncer: SAAudioAvailabilityRange = SAAudioAvailabilityRange(startingNeedle: 0.0, durationLoadedByNetwork: 0.0, predictedDurationToLoad: Double.greatestFiniteMagnitude, isPlayable: false)
var bufferedSeconds: SAAudioAvailabilityRange = SAAudioAvailabilityRange(startingNeedle: 0.0, durationLoadedByNetwork: 0.0, predictedDurationToLoad: Double.greatestFiniteMagnitude, isPlayable: false) {
didSet {
if bufferedSeconds.startingNeedle == 0.0 && bufferedSeconds.durationLoadedByNetwork == 0.0 {
bufferedSecondsDebouncer = bufferedSeconds
@@ -154,7 +154,11 @@ class AudioEngine: AudioEngineProtocol {
func updateIsPlaying() {
if !bufferedSeconds.isPlayable {
playingStatus = .buffering
if bufferedSeconds.bufferingProgress > 0.999 {
playingStatus = .ended
} else {
playingStatus = .buffering
}
return
}
+2 -7
View File
@@ -218,7 +218,7 @@ class AudioStreamEngine: AudioEngine {
let range = converter.pollNetworkAudioAvailabilityRange()
isPlayable = (numberOfBuffersScheduledInTotal >= MIN_BUFFERS_TO_BE_PLAYABLE && range.1 > 0) && predictedStreamDuration > 0
Log.debug("loaded \(range), numberOfBuffersScheduledInTotal: \(numberOfBuffersScheduledInTotal), isPlayable: \(isPlayable)")
bufferedSeconds = SAAudioAvailabilityRange(startingNeedle: range.0, durationLoadedByNetwork: range.1, isPlayable: isPlayable)
bufferedSeconds = SAAudioAvailabilityRange(startingNeedle: range.0, durationLoadedByNetwork: range.1, predictedDurationToLoad: predictedStreamDuration, isPlayable: isPlayable)
}
private func updateNeedle() {
@@ -236,12 +236,6 @@ class AudioStreamEngine: AudioEngine {
var currentTime = TimeInterval(playerTime.sampleTime) / playerTime.sampleRate
currentTime = currentTime > 0 ? currentTime : 0
if currentTime > predictedStreamDuration {
Log.info("reached end of audio")
seek(toNeedle: 0)
pause()
playingStatus = .ended
}
needle = (currentTime + currentTimeOffset)
}
@@ -297,6 +291,7 @@ class AudioStreamEngine: AudioEngine {
}
override func invalidate() {
super.invalidate()
converter.invalidate()
}
}
@@ -57,28 +57,39 @@ public enum ConverterError: LocalizedError {
public var errorDescription: String? {
switch self {
case .cannotLockQueue:
Log.warn("Failed to lock queue")
return "Failed to lock queue"
case .converterFailed(let status):
Log.warn(localizedDescriptionFromConverterError(status))
return localizedDescriptionFromConverterError(status)
case .failedToCreateDestinationFormat:
Log.warn("Failed to create a destination (processing) format")
return "Failed to create a destination (processing) format"
case .failedToCreatePCMBuffer:
Log.warn("Failed to create PCM buffer for reading data")
return "Failed to create PCM buffer for reading data"
case .notEnoughData:
Log.warn("Not enough data for read-conversion operation")
return "Not enough data for read-conversion operation"
case .parserMissingDataFormat:
Log.warn("Parser is missing a valid data format")
return "Parser is missing a valid data format"
case .reachedEndOfFile:
Log.warn("Reached the end of the file")
return "Reached the end of the file"
case .unableToCreateConverter(let status):
return localizedDescriptionFromConverterError(status)
case .superConcerningShouldNeverHappen:
Log.warn("Weird unexpected reader error. Should not have happened")
return "Weird unexpected reader error. Should not have happened"
case .cannotCreatePCMBufferWithoutConverter:
Log.warn("Could not create a PCM Buffer because reader does not have a converter yet")
return "Could not create a PCM Buffer because reader does not have a converter yet"
case .throttleParsingBuffersForEngine:
Log.warn("Preventing the reader from creating more PCM buffers since the player has more than 60 seconds of audio already to play")
return "Preventing the reader from creating more PCM buffers since the player has more than 60 seconds of audio already to play"
case .failedToCreateParser:
Log.warn("Could not create a parser")
return "Could not create a parser"
}
}
@@ -3,7 +3,7 @@
// SwiftAudioPlayer
//
// Created by Tanha Kabir on 2019-01-29.
// Copyright © 2019 Tanha Kabir, Jon Mercer
// Copyright © 2019 Tanha Kabir, Jon Mercer, Moy Inzunza
//
// This file was modified and adapted from https://github.com/syedhali/AudioStreamer
// which was released under Apache License 2.0. Apache License 2.0 requires explicit
@@ -32,7 +32,19 @@
import Foundation
import AVFoundation
func ParserPacketListener(_ context: UnsafeMutableRawPointer, _ byteCount: UInt32, _ packetCount: UInt32, _ streamData: UnsafeRawPointer, _ packetDescriptions: UnsafeMutablePointer<AudioStreamPacketDescription>) {
#if swift(>=5.3)
func ParserPacketListener (_ context: UnsafeMutableRawPointer, _ byteCount: UInt32, _ packetCount: UInt32, _ streamData: UnsafeRawPointer, _ packetDescriptions: UnsafeMutablePointer<AudioStreamPacketDescription>?) {
parserPacket(context, byteCount, packetCount, streamData, packetDescriptions!)
}
#else
func ParserPacketListener (_ context: UnsafeMutableRawPointer, _ byteCount: UInt32, _ packetCount: UInt32, _ streamData: UnsafeRawPointer, _ packetDescriptions: UnsafeMutablePointer<AudioStreamPacketDescription>) {
parserPacket(context, byteCount, packetCount, streamData, packetDescriptions)
}
#endif
func parserPacket(_ context: UnsafeMutableRawPointer, _ byteCount: UInt32, _ packetCount: UInt32, _ streamData: UnsafeRawPointer, _ packetDescriptions: UnsafeMutablePointer<AudioStreamPacketDescription>){
let selfAudioParser = Unmanaged<AudioParser>.fromOpaque(context).takeUnretainedValue()
//bug in core audio where this could be nil
@@ -68,4 +80,5 @@ func ParserPacketListener(_ context: UnsafeMutableRawPointer, _ byteCount: UInt3
selfAudioParser.audioPackets.append((nil, audioPacketData))
}
}
}
@@ -29,8 +29,15 @@ import Foundation
public struct SAAudioAvailabilityRange {
let startingNeedle: Needle
let durationLoadedByNetwork: Duration
let predictedDurationToLoad: Duration
let isPlayable: Bool
public var bufferingProgress: Double {
get {
return (startingNeedle + durationLoadedByNetwork) / predictedDurationToLoad
}
}
public var startingBufferTimePositon: Double {
get {
return startingNeedle
@@ -52,4 +59,8 @@ public struct SAAudioAvailabilityRange {
public func contains(_ needle: Double) -> Bool {
return needle >= startingNeedle && (needle - startingNeedle) < durationLoadedByNetwork
}
public func isCompletelyBuffered() -> Bool {
return startingNeedle + durationLoadedByNetwork >= predictedDurationToLoad
}
}
@@ -243,7 +243,7 @@ extension AudioStreamWorker: URLSessionDataDelegate {
}
guard self.task == dataTask else {
Log.error("stream_error not the same task") //Probably because of seek
Log.error("stream_error not the same task 638283") //Probably because of seek
return
}
@@ -271,7 +271,7 @@ extension AudioStreamWorker: URLSessionDataDelegate {
}
guard self.task == dataTask else {
Log.error("stream_error not the same task")
Log.error("stream_error not the same task 517253")
return
}
@@ -293,8 +293,8 @@ extension AudioStreamWorker: URLSessionDataDelegate {
return
}
guard self.task == task else {
Log.error("stream_error not the same task")
if self.task != task && self.task != nil {
Log.error("stream_error not the same task 3901833")
return
}
+91
View File
@@ -27,6 +27,16 @@ import Foundation
import AVFoundation
public class SAPlayer {
public var DEBUG_MODE: Bool = false {
didSet {
if(DEBUG_MODE) {
logLevel = LogLevel.EXTERNAL_DEBUG
} else {
logLevel = LogLevel.MONITOR
}
}
}
/**
Access to the player.
*/
@@ -99,6 +109,10 @@ public class SAPlayer {
}
````
Please look at [forums.developer.apple.com/thread/5874](https://forums.developer.apple.com/thread/5874) and [forums.developer.apple.com/thread/6050](https://forums.developer.apple.com/thread/6050) for more details.
For more details on pitch modifiers for playback rate changes please look at [developer.apple.com/forums/thread/6050](https://developer.apple.com/forums/thread/6050).
To remove this default pitch modifier for playback rate changes, remove the node by calling `SAPlayer.shared.clearAudioModifiers()`.
*/
public var audioModifiers: [AVAudioUnit] = []
@@ -171,6 +185,22 @@ public class SAPlayer {
audioModifiers.append(AVAudioUnitTimePitch(audioComponentDescription: componentDescription))
}
/**
Clears all [AVAudioUnit](https://developer.apple.com/documentation/avfoundation/audio_track_engineering/audio_engine_building_blocks/audio_enhancements) modifiers intended to be used for realtime audio manipulation.
*/
public func clearAudioModifiers() {
audioModifiers.removeAll()
}
/**
Append an [AVAudioUnit](https://developer.apple.com/documentation/avfoundation/audio_track_engineering/audio_engine_building_blocks/audio_enhancements) modifier to the list of modifiers used for realtime audio manipulation. The modifier will be added to the end of the list.
- Parameter modifier: The modifier to append.
*/
public func addAudioModifier(_ modifer: AVAudioUnit) {
audioModifiers.append(modifer)
}
/**
Formats a textual representation of a given timestamp for display in hh:MM:SS format, that is hours:minutes:seconds.
@@ -256,6 +286,23 @@ extension SAPlayer {
/**
If using an AVAudioUnitTimePitch, it's important to notify the player that the rate at which the audio playing has changed to keep the media player in the lockscreen up to date. This is only important for playback rate changes.
- Note: By default this engine has added a pitch modifier node to change the pitch so that on playback rate changes of spoken word the pitch isn't shifted.
The component description of this node is:
````
var componentDescription: AudioComponentDescription {
get {
var ret = AudioComponentDescription()
ret.componentType = kAudioUnitType_FormatConverter
ret.componentSubType = kAudioUnitSubType_AUiPodTimeOther
return ret
}
}
````
Please look at [forums.developer.apple.com/thread/5874](https://forums.developer.apple.com/thread/5874) and [forums.developer.apple.com/thread/6050](https://forums.developer.apple.com/thread/6050) for more details.
For more details on pitch modifiers for playback rate changes please look at [developer.apple.com/forums/thread/6050](https://developer.apple.com/forums/thread/6050).
- Parameter rate: The current rate at which the audio is playing.
*/
public func playbackRateOfAudioChanged(rate: Float) {
@@ -267,6 +314,23 @@ extension SAPlayer {
- Important: If intending to use [AVAudioUnit](https://developer.apple.com/documentation/avfoundation/audio_track_engineering/audio_engine_building_blocks/audio_enhancements) audio modifiers during playback, the list of audio modifiers under `SAPlayer.shared.audioModifiers` must be finalized before calling this function. After all realtime audio manipulations within the this will be effective.
- Note: The default list already has an AVAudioUnitTimePitch node first in the list. This node is specifically set to change the rate of audio without changing the pitch of the audio (intended for changing the rate of spoken word).
The component description of this node is:
````
var componentDescription: AudioComponentDescription {
get {
var ret = AudioComponentDescription()
ret.componentType = kAudioUnitType_FormatConverter
ret.componentSubType = kAudioUnitSubType_AUiPodTimeOther
return ret
}
}
````
Please look at [forums.developer.apple.com/thread/5874](https://forums.developer.apple.com/thread/5874) and [forums.developer.apple.com/thread/6050](https://forums.developer.apple.com/thread/6050) for more details.
To remove this default pitch modifier for playback rate changes, remove the node by calling `SAPlayer.shared.clearAudioModifiers()`.
- Parameter withSavedUrl: The URL of the audio saved on the device.
- Parameter mediaInfo: The media information of the audio to show on the lockscreen media player (optional).
*/
@@ -286,6 +350,23 @@ extension SAPlayer {
- Important: If intending to use [AVAudioUnit](https://developer.apple.com/documentation/avfoundation/audio_track_engineering/audio_engine_building_blocks/audio_enhancements) audio modifiers during playback, the list of audio modifiers under `SAPlayer.shared.audioModifiers` must be finalized before calling this function. After all realtime audio manipulations within the this will be effective.
- Note: The default list already has an AVAudioUnitTimePitch node first in the list. This node is specifically set to change the rate of audio without changing the pitch of the audio (intended for changing the rate of spoken word).
The component description of this node is:
````
var componentDescription: AudioComponentDescription {
get {
var ret = AudioComponentDescription()
ret.componentType = kAudioUnitType_FormatConverter
ret.componentSubType = kAudioUnitSubType_AUiPodTimeOther
return ret
}
}
````
Please look at [forums.developer.apple.com/thread/5874](https://forums.developer.apple.com/thread/5874) and [forums.developer.apple.com/thread/6050](https://forums.developer.apple.com/thread/6050) for more details.
To remove this default pitch modifier for playback rate changes, remove the node by calling `SAPlayer.shared.clearAudioModifiers()`.
- Note: Subscribe to `SAPlayer.Updates.StreamingBuffer` to see updates in streaming progress.
- Parameter withRemoteUrl: The URL of the remote audio.
@@ -302,6 +383,10 @@ extension SAPlayer {
presenter.handlePlayStreamedAudio(withRemoteUrl: url)
}
public func stopStreamingRemoteAudio() {
presenter.handleStopStreamingAudio()
}
/**
Resets the player to the state before initializing audio and setting media info.
*/
@@ -326,6 +411,12 @@ extension SAPlayer: SAPlayerDelegate {
player = AudioStreamEngine(withRemoteUrl: url, delegate: presenter)
}
func clearEngine() {
player?.pause()
player?.invalidate()
player = nil
}
func playEngine() {
becomeDeviceAudioPlayer()
player?.play()
+1
View File
@@ -32,6 +32,7 @@ protocol SAPlayerDelegate: AnyObject, LockScreenViewProtocol {
func startAudioDownloaded(withSavedUrl url: AudioURL)
func startAudioStreamed(withRemoteUrl url: AudioURL)
func clearEngine()
func playEngine()
func pauseEngine()
func seekEngine(toNeedle needle: Needle) //TODO ensure that engine cleans up out of bounds
+12 -3
View File
@@ -83,9 +83,7 @@ class SAPlayerPresenter {
}
private func attachForUpdates(url: URL) {
AudioClockDirector.shared.detachFromChangesInDuration(withID: durationRef)
AudioClockDirector.shared.detachFromChangesInNeedle(withID: needleRef)
AudioClockDirector.shared.detachFromChangesInPlayingStatus(withID: playingStatusRef)
detachFromUpdates()
self.key = url.key
urlKeyMap[url.key] = url
@@ -125,6 +123,17 @@ class SAPlayerPresenter {
})
}
private func detachFromUpdates() {
AudioClockDirector.shared.detachFromChangesInDuration(withID: durationRef)
AudioClockDirector.shared.detachFromChangesInNeedle(withID: needleRef)
AudioClockDirector.shared.detachFromChangesInPlayingStatus(withID: playingStatusRef)
}
func handleStopStreamingAudio() {
delegate?.clearEngine()
detachFromUpdates()
}
@available(iOS 10.0, *)
func handleLockscreenInfo(info: SALockScreenInfo?) {
self.mediaInfo = info
+25 -14
View File
@@ -9,22 +9,23 @@
import Foundation
import os.log
// Possible levels of log messages to log
enum LogLevel: Int {
case DEBUG = 1
case INFO = 2
case WARN = 3
case ERROR = 4
case EXTERNAL_DEBUG = 5
case MONITOR = 6
case TEST = 7
}
// Specify which types of log messages to display. Default level is set to WARN, which means Log will print any log messages of type only WARN, ERROR, MONITOR, and TEST. To print DEBUG and INFO logs, set the level to a lower value.
var logLevel: LogLevel = LogLevel.MONITOR
class Log {
private init() {}
// Possible levels of log messages to log
public enum LogLevel: Int {
case DEBUG = 1
case INFO = 2
case WARN = 3
case ERROR = 4
case MONITOR = 5
case TEST = 6
}
// Specify which types of log messages to display. Default level is set to WARN, which means Log will print any log messages of type only WARN, ERROR, MONITOR, and TEST. To print DEBUG and INFO logs, set the level to a lower value.
public static var logLevel: LogLevel = LogLevel.MONITOR
// Used for OSLog
private static let SUBSYSTEM: String = "com.SwiftAudioPlayer"
@@ -68,6 +69,11 @@ class Log {
let log = OSLog(subsystem: SUBSYSTEM, category: "ERROR 🛑🛑🛑🛑")
os_log("%@:%@:%d:: %@", log: log, fileName, functionName, lineNumber, "\(logMessage)")
}
if logLevel.rawValue <= LogLevel.EXTERNAL_DEBUG.rawValue {
let log = OSLog(subsystem: SUBSYSTEM, category: "WARNING")
os_log("%@:%@:%d:: %@", log: log, fileName, functionName, lineNumber, "\(logMessage)")
}
}
/**
@@ -86,7 +92,7 @@ class Log {
public static func monitor(_ logMessage: Any, classPath: String = #file, functionName: String = #function, lineNumber: Int = #line) {
let fileName = URLUtil.getNameFromStringPath(classPath)
if logLevel.rawValue <= LogLevel.ERROR.rawValue {
let log = OSLog(subsystem: SUBSYSTEM, category: "MONITOR 🔥🔥🔥🔥")
let log = OSLog(subsystem: SUBSYSTEM, category: "ERROR 🔥🔥🔥🔥")
os_log("%@:%@:%d:: %@", log: log, fileName, functionName, lineNumber, "\(logMessage)")
}
}
@@ -110,6 +116,11 @@ class Log {
let log = OSLog(subsystem: SUBSYSTEM, category: "WARN ⚠️⚠️⚠️⚠️")
os_log("%@:%@:%d:: %@", log: log, fileName, functionName, lineNumber, "\(logMessage)")
}
if logLevel.rawValue <= LogLevel.EXTERNAL_DEBUG.rawValue {
let log = OSLog(subsystem: SUBSYSTEM, category: "DEBUG")
os_log("%@:%@:%d:: %@", log: log, fileName, functionName, lineNumber, "\(logMessage)")
}
}
/**
+1 -1
View File
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = 'SwiftAudioPlayer'
s.version = '2.6.0'
s.version = '2.11.0'
s.summary = 'SwiftAudioPlayer is a Swift based audio player that can handle streaming from a remote location and audio manipulation.'
# This description is used to generate tags and improve search results.