Compare commits
12 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 2abba6f0cc | |||
| f081b7549d | |||
| 55fbae7b4a | |||
| 2acbde2efa | |||
| acbdf05d4f | |||
| c325caa914 | |||
| dd54d81573 | |||
| ebc282d5c2 | |||
| 80ce253f92 | |||
| fe2395066f | |||
| 3e66b4b4d4 | |||
| 58bbc97a1b |
@@ -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)",
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -149,6 +151,8 @@ class ViewController: UIViewController {
|
||||
|
||||
if buffer.bufferingProgress >= 0.99 {
|
||||
self.streamButton.isEnabled = false
|
||||
} else {
|
||||
self.streamButton.isEnabled = true
|
||||
}
|
||||
|
||||
self.isPlayable = buffer.isReadyForPlaying
|
||||
@@ -183,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() {
|
||||
@@ -260,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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -276,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])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -136,6 +136,7 @@ class AudioDiskEngine: AudioEngine {
|
||||
}
|
||||
|
||||
override func invalidate() {
|
||||
super.invalidate()
|
||||
//Nothing to invalidate for disk
|
||||
}
|
||||
}
|
||||
|
||||
@@ -154,7 +154,7 @@ class AudioEngine: AudioEngineProtocol {
|
||||
|
||||
func updateIsPlaying() {
|
||||
if !bufferedSeconds.isPlayable {
|
||||
if bufferedSeconds.bufferingProgress == 1.0 {
|
||||
if bufferedSeconds.bufferingProgress > 0.999 {
|
||||
playingStatus = .ended
|
||||
} else {
|
||||
playingStatus = .buffering
|
||||
|
||||
@@ -291,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))
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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)")
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
|
||||
Pod::Spec.new do |s|
|
||||
s.name = 'SwiftAudioPlayer'
|
||||
s.version = '2.8.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.
|
||||
|
||||
Reference in New Issue
Block a user