Compare commits

..

11 Commits

Author SHA1 Message Date
tanhakabir 930509d6be fix maintaining rate changes while skip silences is enabled 2021-05-09 17:15:18 -07:00
tanhakabir c513c723ed Release 5.0.4 2021-05-08 18:57:11 -07:00
tanhakabir b34a264aec Fix bug introduced by queuing for lockscreen info (#108)
* add extra data for queuing and change order of clearing mediaInfo

* make SAPlayer the only source for mediaInfo

Co-authored-by: @dylancom
Co-authored-by: @dezinezync
2021-05-08 18:55:08 -07:00
tanhakabir a83c2f702f pass lockscreen info to player in example app (#107)
related to #106
2021-05-07 13:16:24 -07:00
tanhakabir 8644bf24fb Merge pull request #105 from Husseinhj/patch-1
Anchor link in SAPlayer.Updates fixed
2021-05-03 20:42:19 -07:00
tanhakabir 69a979cb98 Add twitter handle to podspec 2021-05-03 20:40:57 -07:00
Hussein Habibi Juybari 6ba43e70ea Rollback Contact header changes 2021-05-03 11:34:30 +04:30
Hussein Habibi Juybari 6f19009000 Anchor link in SAPlayer.Updates fixed 2021-05-03 11:32:30 +04:30
tanhakabir 64677ad6ce Release 5.0.3 2021-04-28 15:33:46 -07:00
tanhakabir 3894309706 Merge pull request #102 from niczyja/session-fix
Fix for audio session setup on iOS 11 and up
2021-04-26 09:41:07 -07:00
Maciej Sienkiewicz e44f16258f Fix for audio session setup on iOS 11 and up 2021-04-26 14:43:13 +02:00
19 changed files with 86 additions and 989 deletions
+7
View File
@@ -7,6 +7,7 @@
//
import Foundation
import SwiftAudioPlayer
struct AudioInfo: Hashable {
var index: Int = 0
@@ -44,6 +45,12 @@ struct AudioInfo: Hashable {
let artist: String = "SwiftAudioPlayer Sample App"
let releaseDate: Int = 1550790640
var lockscreenInfo: SALockScreenInfo {
get {
return SALockScreenInfo(title: self.title, artist: self.artist, artwork: nil, releaseDate: self.releaseDate)
}
}
var savedUrl: URL? {
get {
return savedUrls[index]
@@ -259,7 +259,12 @@ class ViewController: UIViewController {
@IBAction func rateChanged(_ sender: Any) {
let speed = rateSlider.value
rateLabel.text = "rate: \(speed)x"
SAPlayer.shared.rate = speed
if skipSilencesSwitch.isOn {
SAPlayer.Features.SkipSilences.setRateSafely(speed) // if using Skip Silences, we need use this version of setting rate to safely change the rate with the feature enabled.
} else {
SAPlayer.shared.rate = speed
}
}
@IBAction func reverbChanged(_ sender: Any) {
let reverb = reverbSlider.value
@@ -295,7 +300,7 @@ class ViewController: UIViewController {
self.currentUrlLocationLabel.text = "saved to: \(url.lastPathComponent)"
self.selectedAudio.addSavedUrl(url)
SAPlayer.shared.startSavedAudio(withSavedUrl: url)
SAPlayer.shared.startSavedAudio(withSavedUrl: url, mediaInfo: self.selectedAudio.lockscreenInfo)
self.lastPlayedAudioIndex = self.selectedAudio.index
}
})
@@ -312,9 +317,9 @@ class ViewController: UIViewController {
@IBAction func streamTouched(_ sender: Any) {
if !isStreaming {
if selectedAudio.index == 2 { // radio
SAPlayer.shared.startRemoteAudio(withRemoteUrl: selectedAudio.url, bitrate: .low)
SAPlayer.shared.startRemoteAudio(withRemoteUrl: selectedAudio.url, bitrate: .low, mediaInfo: selectedAudio.lockscreenInfo)
} else {
SAPlayer.shared.startRemoteAudio(withRemoteUrl: selectedAudio.url)
SAPlayer.shared.startRemoteAudio(withRemoteUrl: selectedAudio.url, mediaInfo: selectedAudio.lockscreenInfo)
}
lastPlayedAudioIndex = selectedAudio.index
@@ -1,574 +0,0 @@
// !$*UTF8*$!
{
archiveVersion = 1;
classes = {
};
objectVersion = 50;
objects = {
/* Begin PBXBuildFile section */
25911CD42631355C0099DE52 /* SwiftAudioPlayer_SwiftUIApp.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CD32631355C0099DE52 /* SwiftAudioPlayer_SwiftUIApp.swift */; };
25911CD62631355C0099DE52 /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CD52631355C0099DE52 /* ContentView.swift */; };
25911CD82631355E0099DE52 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 25911CD72631355E0099DE52 /* Assets.xcassets */; };
25911CDB2631355E0099DE52 /* Preview Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 25911CDA2631355E0099DE52 /* Preview Assets.xcassets */; };
25911D182631392C0099DE52 /* SAPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CE92631392C0099DE52 /* SAPlayer.swift */; };
25911D192631392C0099DE52 /* Constants.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CEB2631392C0099DE52 /* Constants.swift */; };
25911D1A2631392C0099DE52 /* Date.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CEC2631392C0099DE52 /* Date.swift */; };
25911D1B2631392C0099DE52 /* Log.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CED2631392C0099DE52 /* Log.swift */; };
25911D1C2631392C0099DE52 /* Data.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CEE2631392C0099DE52 /* Data.swift */; };
25911D1D2631392C0099DE52 /* DirectorThreadSafeClosures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CEF2631392C0099DE52 /* DirectorThreadSafeClosures.swift */; };
25911D1E2631392C0099DE52 /* URL.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CF02631392C0099DE52 /* URL.swift */; };
25911D1F2631392C0099DE52 /* SALockScreenInfo.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CF12631392C0099DE52 /* SALockScreenInfo.swift */; };
25911D202631392C0099DE52 /* SAPlayerFeatures.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CF22631392C0099DE52 /* SAPlayerFeatures.swift */; };
25911D212631392C0099DE52 /* SAPlayerUpdateSubscription.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CF32631392C0099DE52 /* SAPlayerUpdateSubscription.swift */; };
25911D222631392C0099DE52 /* SAPlayerDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CF42631392C0099DE52 /* SAPlayerDownloader.swift */; };
25911D232631392C0099DE52 /* SAPlayerDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CF52631392C0099DE52 /* SAPlayerDelegate.swift */; };
25911D242631392C0099DE52 /* LockScreenViewProtocol.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CF62631392C0099DE52 /* LockScreenViewProtocol.swift */; };
25911D252631392C0099DE52 /* AudioQueue.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CF82631392C0099DE52 /* AudioQueue.swift */; };
25911D262631392C0099DE52 /* AudioDataManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CF92631392C0099DE52 /* AudioDataManager.swift */; };
25911D272631392C0099DE52 /* AudioStreamWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CFB2631392C0099DE52 /* AudioStreamWorker.swift */; };
25911D282631392C0099DE52 /* StreamProgressDTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CFC2631392C0099DE52 /* StreamProgressDTO.swift */; };
25911D292631392C0099DE52 /* FileStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CFE2631392C0099DE52 /* FileStorage.swift */; };
25911D2A2631392C0099DE52 /* AudioDownloadWorker.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911CFF2631392C0099DE52 /* AudioDownloadWorker.swift */; };
25911D2B2631392C0099DE52 /* StreamProgressPTO.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D002631392C0099DE52 /* StreamProgressPTO.swift */; };
25911D2C2631392C0099DE52 /* AudioDiskEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D022631392C0099DE52 /* AudioDiskEngine.swift */; };
25911D2D2631392C0099DE52 /* AudioStreamEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D032631392C0099DE52 /* AudioStreamEngine.swift */; };
25911D2E2631392C0099DE52 /* AudioConverterListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D052631392C0099DE52 /* AudioConverterListener.swift */; };
25911D2F2631392C0099DE52 /* AudioConverterErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D062631392C0099DE52 /* AudioConverterErrors.swift */; };
25911D302631392C0099DE52 /* AudioConverter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D072631392C0099DE52 /* AudioConverter.swift */; };
25911D312631392C0099DE52 /* SAAudioAvailabilityRange.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D082631392C0099DE52 /* SAAudioAvailabilityRange.swift */; };
25911D322631392C0099DE52 /* SAPlayingStatus.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D092631392C0099DE52 /* SAPlayingStatus.swift */; };
25911D332631392C0099DE52 /* AudioParser.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D0B2631392C0099DE52 /* AudioParser.swift */; };
25911D342631392C0099DE52 /* AudioParsable.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D0C2631392C0099DE52 /* AudioParsable.swift */; };
25911D352631392C0099DE52 /* AudioParserPropertyListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D0D2631392C0099DE52 /* AudioParserPropertyListener.swift */; };
25911D362631392C0099DE52 /* AudioParserPacketListener.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D0E2631392C0099DE52 /* AudioParserPacketListener.swift */; };
25911D372631392C0099DE52 /* AudioParserErrors.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D0F2631392C0099DE52 /* AudioParserErrors.swift */; };
25911D382631392C0099DE52 /* AudioThrottler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D102631392C0099DE52 /* AudioThrottler.swift */; };
25911D392631392C0099DE52 /* AudioEngine.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D112631392C0099DE52 /* AudioEngine.swift */; };
25911D3A2631392C0099DE52 /* SAPlayerPresenter.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D122631392C0099DE52 /* SAPlayerPresenter.swift */; };
25911D3B2631392C0099DE52 /* AudioClockDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D142631392C0099DE52 /* AudioClockDirector.swift */; };
25911D3C2631392C0099DE52 /* DownloadProgressDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D152631392C0099DE52 /* DownloadProgressDirector.swift */; };
25911D3D2631392D0099DE52 /* AudioQueueDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D162631392C0099DE52 /* AudioQueueDirector.swift */; };
25911D3E2631392D0099DE52 /* StreamingDownloadDirector.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D172631392C0099DE52 /* StreamingDownloadDirector.swift */; };
25911D4126313AF90099DE52 /* SAPlayerCombineUpdates.swift in Sources */ = {isa = PBXBuildFile; fileRef = 25911D4026313AF90099DE52 /* SAPlayerCombineUpdates.swift */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
25911CD02631355C0099DE52 /* SwiftAudioPlayer-SwiftUI.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "SwiftAudioPlayer-SwiftUI.app"; sourceTree = BUILT_PRODUCTS_DIR; };
25911CD32631355C0099DE52 /* SwiftAudioPlayer_SwiftUIApp.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SwiftAudioPlayer_SwiftUIApp.swift; sourceTree = "<group>"; };
25911CD52631355C0099DE52 /* ContentView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContentView.swift; sourceTree = "<group>"; };
25911CD72631355E0099DE52 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
25911CDA2631355E0099DE52 /* Preview Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = "Preview Assets.xcassets"; sourceTree = "<group>"; };
25911CDC2631355E0099DE52 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = "<group>"; };
25911CE92631392C0099DE52 /* SAPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAPlayer.swift; sourceTree = "<group>"; };
25911CEB2631392C0099DE52 /* Constants.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Constants.swift; sourceTree = "<group>"; };
25911CEC2631392C0099DE52 /* Date.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Date.swift; sourceTree = "<group>"; };
25911CED2631392C0099DE52 /* Log.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Log.swift; sourceTree = "<group>"; };
25911CEE2631392C0099DE52 /* Data.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Data.swift; sourceTree = "<group>"; };
25911CEF2631392C0099DE52 /* DirectorThreadSafeClosures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DirectorThreadSafeClosures.swift; sourceTree = "<group>"; };
25911CF02631392C0099DE52 /* URL.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = URL.swift; sourceTree = "<group>"; };
25911CF12631392C0099DE52 /* SALockScreenInfo.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SALockScreenInfo.swift; sourceTree = "<group>"; };
25911CF22631392C0099DE52 /* SAPlayerFeatures.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAPlayerFeatures.swift; sourceTree = "<group>"; };
25911CF32631392C0099DE52 /* SAPlayerUpdateSubscription.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAPlayerUpdateSubscription.swift; sourceTree = "<group>"; };
25911CF42631392C0099DE52 /* SAPlayerDownloader.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAPlayerDownloader.swift; sourceTree = "<group>"; };
25911CF52631392C0099DE52 /* SAPlayerDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAPlayerDelegate.swift; sourceTree = "<group>"; };
25911CF62631392C0099DE52 /* LockScreenViewProtocol.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = LockScreenViewProtocol.swift; sourceTree = "<group>"; };
25911CF82631392C0099DE52 /* AudioQueue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioQueue.swift; sourceTree = "<group>"; };
25911CF92631392C0099DE52 /* AudioDataManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioDataManager.swift; sourceTree = "<group>"; };
25911CFB2631392C0099DE52 /* AudioStreamWorker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioStreamWorker.swift; sourceTree = "<group>"; };
25911CFC2631392C0099DE52 /* StreamProgressDTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StreamProgressDTO.swift; sourceTree = "<group>"; };
25911CFE2631392C0099DE52 /* FileStorage.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = FileStorage.swift; sourceTree = "<group>"; };
25911CFF2631392C0099DE52 /* AudioDownloadWorker.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioDownloadWorker.swift; sourceTree = "<group>"; };
25911D002631392C0099DE52 /* StreamProgressPTO.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StreamProgressPTO.swift; sourceTree = "<group>"; };
25911D022631392C0099DE52 /* AudioDiskEngine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioDiskEngine.swift; sourceTree = "<group>"; };
25911D032631392C0099DE52 /* AudioStreamEngine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioStreamEngine.swift; sourceTree = "<group>"; };
25911D052631392C0099DE52 /* AudioConverterListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioConverterListener.swift; sourceTree = "<group>"; };
25911D062631392C0099DE52 /* AudioConverterErrors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioConverterErrors.swift; sourceTree = "<group>"; };
25911D072631392C0099DE52 /* AudioConverter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioConverter.swift; sourceTree = "<group>"; };
25911D082631392C0099DE52 /* SAAudioAvailabilityRange.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAAudioAvailabilityRange.swift; sourceTree = "<group>"; };
25911D092631392C0099DE52 /* SAPlayingStatus.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAPlayingStatus.swift; sourceTree = "<group>"; };
25911D0B2631392C0099DE52 /* AudioParser.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioParser.swift; sourceTree = "<group>"; };
25911D0C2631392C0099DE52 /* AudioParsable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioParsable.swift; sourceTree = "<group>"; };
25911D0D2631392C0099DE52 /* AudioParserPropertyListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioParserPropertyListener.swift; sourceTree = "<group>"; };
25911D0E2631392C0099DE52 /* AudioParserPacketListener.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioParserPacketListener.swift; sourceTree = "<group>"; };
25911D0F2631392C0099DE52 /* AudioParserErrors.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioParserErrors.swift; sourceTree = "<group>"; };
25911D102631392C0099DE52 /* AudioThrottler.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioThrottler.swift; sourceTree = "<group>"; };
25911D112631392C0099DE52 /* AudioEngine.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioEngine.swift; sourceTree = "<group>"; };
25911D122631392C0099DE52 /* SAPlayerPresenter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SAPlayerPresenter.swift; sourceTree = "<group>"; };
25911D142631392C0099DE52 /* AudioClockDirector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioClockDirector.swift; sourceTree = "<group>"; };
25911D152631392C0099DE52 /* DownloadProgressDirector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = DownloadProgressDirector.swift; sourceTree = "<group>"; };
25911D162631392C0099DE52 /* AudioQueueDirector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioQueueDirector.swift; sourceTree = "<group>"; };
25911D172631392C0099DE52 /* StreamingDownloadDirector.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StreamingDownloadDirector.swift; sourceTree = "<group>"; };
25911D4026313AF90099DE52 /* SAPlayerCombineUpdates.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SAPlayerCombineUpdates.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
25911CCD2631355C0099DE52 /* Frameworks */ = {
isa = PBXFrameworksBuildPhase;
buildActionMask = 2147483647;
files = (
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXFrameworksBuildPhase section */
/* Begin PBXGroup section */
25911CC72631355C0099DE52 = {
isa = PBXGroup;
children = (
25911CD22631355C0099DE52 /* SwiftAudioPlayer-SwiftUI */,
25911CD12631355C0099DE52 /* Products */,
);
sourceTree = "<group>";
};
25911CD12631355C0099DE52 /* Products */ = {
isa = PBXGroup;
children = (
25911CD02631355C0099DE52 /* SwiftAudioPlayer-SwiftUI.app */,
);
name = Products;
sourceTree = "<group>";
};
25911CD22631355C0099DE52 /* SwiftAudioPlayer-SwiftUI */ = {
isa = PBXGroup;
children = (
25911CE32631371C0099DE52 /* SAPlayer */,
25911CD32631355C0099DE52 /* SwiftAudioPlayer_SwiftUIApp.swift */,
25911CD52631355C0099DE52 /* ContentView.swift */,
25911CD72631355E0099DE52 /* Assets.xcassets */,
25911CDC2631355E0099DE52 /* Info.plist */,
25911CD92631355E0099DE52 /* Preview Content */,
);
path = "SwiftAudioPlayer-SwiftUI";
sourceTree = "<group>";
};
25911CD92631355E0099DE52 /* Preview Content */ = {
isa = PBXGroup;
children = (
25911CDA2631355E0099DE52 /* Preview Assets.xcassets */,
);
path = "Preview Content";
sourceTree = "<group>";
};
25911CE32631371C0099DE52 /* SAPlayer */ = {
isa = PBXGroup;
children = (
25911CE82631392C0099DE52 /* Source */,
);
path = SAPlayer;
sourceTree = "<group>";
};
25911CE82631392C0099DE52 /* Source */ = {
isa = PBXGroup;
children = (
25911CE92631392C0099DE52 /* SAPlayer.swift */,
25911CEA2631392C0099DE52 /* Util */,
25911CF12631392C0099DE52 /* SALockScreenInfo.swift */,
25911CF22631392C0099DE52 /* SAPlayerFeatures.swift */,
25911CF32631392C0099DE52 /* SAPlayerUpdateSubscription.swift */,
25911D4026313AF90099DE52 /* SAPlayerCombineUpdates.swift */,
25911CF42631392C0099DE52 /* SAPlayerDownloader.swift */,
25911CF52631392C0099DE52 /* SAPlayerDelegate.swift */,
25911CF62631392C0099DE52 /* LockScreenViewProtocol.swift */,
25911CF72631392C0099DE52 /* Model */,
25911D012631392C0099DE52 /* Engine */,
25911D122631392C0099DE52 /* SAPlayerPresenter.swift */,
25911D132631392C0099DE52 /* Directors */,
);
name = Source;
path = ../../../../Source;
sourceTree = "<group>";
};
25911CEA2631392C0099DE52 /* Util */ = {
isa = PBXGroup;
children = (
25911CEB2631392C0099DE52 /* Constants.swift */,
25911CEC2631392C0099DE52 /* Date.swift */,
25911CED2631392C0099DE52 /* Log.swift */,
25911CEE2631392C0099DE52 /* Data.swift */,
25911CEF2631392C0099DE52 /* DirectorThreadSafeClosures.swift */,
25911CF02631392C0099DE52 /* URL.swift */,
);
path = Util;
sourceTree = "<group>";
};
25911CF72631392C0099DE52 /* Model */ = {
isa = PBXGroup;
children = (
25911CF82631392C0099DE52 /* AudioQueue.swift */,
25911CF92631392C0099DE52 /* AudioDataManager.swift */,
25911CFA2631392C0099DE52 /* Streaming */,
25911CFD2631392C0099DE52 /* Downloading */,
25911D002631392C0099DE52 /* StreamProgressPTO.swift */,
);
path = Model;
sourceTree = "<group>";
};
25911CFA2631392C0099DE52 /* Streaming */ = {
isa = PBXGroup;
children = (
25911CFB2631392C0099DE52 /* AudioStreamWorker.swift */,
25911CFC2631392C0099DE52 /* StreamProgressDTO.swift */,
);
path = Streaming;
sourceTree = "<group>";
};
25911CFD2631392C0099DE52 /* Downloading */ = {
isa = PBXGroup;
children = (
25911CFE2631392C0099DE52 /* FileStorage.swift */,
25911CFF2631392C0099DE52 /* AudioDownloadWorker.swift */,
);
path = Downloading;
sourceTree = "<group>";
};
25911D012631392C0099DE52 /* Engine */ = {
isa = PBXGroup;
children = (
25911D022631392C0099DE52 /* AudioDiskEngine.swift */,
25911D032631392C0099DE52 /* AudioStreamEngine.swift */,
25911D042631392C0099DE52 /* Converter */,
25911D082631392C0099DE52 /* SAAudioAvailabilityRange.swift */,
25911D092631392C0099DE52 /* SAPlayingStatus.swift */,
25911D0A2631392C0099DE52 /* Parser */,
25911D102631392C0099DE52 /* AudioThrottler.swift */,
25911D112631392C0099DE52 /* AudioEngine.swift */,
);
path = Engine;
sourceTree = "<group>";
};
25911D042631392C0099DE52 /* Converter */ = {
isa = PBXGroup;
children = (
25911D052631392C0099DE52 /* AudioConverterListener.swift */,
25911D062631392C0099DE52 /* AudioConverterErrors.swift */,
25911D072631392C0099DE52 /* AudioConverter.swift */,
);
path = Converter;
sourceTree = "<group>";
};
25911D0A2631392C0099DE52 /* Parser */ = {
isa = PBXGroup;
children = (
25911D0B2631392C0099DE52 /* AudioParser.swift */,
25911D0C2631392C0099DE52 /* AudioParsable.swift */,
25911D0D2631392C0099DE52 /* AudioParserPropertyListener.swift */,
25911D0E2631392C0099DE52 /* AudioParserPacketListener.swift */,
25911D0F2631392C0099DE52 /* AudioParserErrors.swift */,
);
path = Parser;
sourceTree = "<group>";
};
25911D132631392C0099DE52 /* Directors */ = {
isa = PBXGroup;
children = (
25911D142631392C0099DE52 /* AudioClockDirector.swift */,
25911D152631392C0099DE52 /* DownloadProgressDirector.swift */,
25911D162631392C0099DE52 /* AudioQueueDirector.swift */,
25911D172631392C0099DE52 /* StreamingDownloadDirector.swift */,
);
path = Directors;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
25911CCF2631355C0099DE52 /* SwiftAudioPlayer-SwiftUI */ = {
isa = PBXNativeTarget;
buildConfigurationList = 25911CDF2631355E0099DE52 /* Build configuration list for PBXNativeTarget "SwiftAudioPlayer-SwiftUI" */;
buildPhases = (
25911CCC2631355C0099DE52 /* Sources */,
25911CCD2631355C0099DE52 /* Frameworks */,
25911CCE2631355C0099DE52 /* Resources */,
);
buildRules = (
);
dependencies = (
);
name = "SwiftAudioPlayer-SwiftUI";
productName = "SwiftAudioPlayer-SwiftUI";
productReference = 25911CD02631355C0099DE52 /* SwiftAudioPlayer-SwiftUI.app */;
productType = "com.apple.product-type.application";
};
/* End PBXNativeTarget section */
/* Begin PBXProject section */
25911CC82631355C0099DE52 /* Project object */ = {
isa = PBXProject;
attributes = {
LastSwiftUpdateCheck = 1240;
LastUpgradeCheck = 1240;
TargetAttributes = {
25911CCF2631355C0099DE52 = {
CreatedOnToolsVersion = 12.4;
};
};
};
buildConfigurationList = 25911CCB2631355C0099DE52 /* Build configuration list for PBXProject "SwiftAudioPlayer-SwiftUI" */;
compatibilityVersion = "Xcode 9.3";
developmentRegion = en;
hasScannedForEncodings = 0;
knownRegions = (
en,
Base,
);
mainGroup = 25911CC72631355C0099DE52;
productRefGroup = 25911CD12631355C0099DE52 /* Products */;
projectDirPath = "";
projectRoot = "";
targets = (
25911CCF2631355C0099DE52 /* SwiftAudioPlayer-SwiftUI */,
);
};
/* End PBXProject section */
/* Begin PBXResourcesBuildPhase section */
25911CCE2631355C0099DE52 /* Resources */ = {
isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647;
files = (
25911CDB2631355E0099DE52 /* Preview Assets.xcassets in Resources */,
25911CD82631355E0099DE52 /* Assets.xcassets in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXResourcesBuildPhase section */
/* Begin PBXSourcesBuildPhase section */
25911CCC2631355C0099DE52 /* Sources */ = {
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
25911D392631392C0099DE52 /* AudioEngine.swift in Sources */,
25911D2A2631392C0099DE52 /* AudioDownloadWorker.swift in Sources */,
25911D212631392C0099DE52 /* SAPlayerUpdateSubscription.swift in Sources */,
25911D342631392C0099DE52 /* AudioParsable.swift in Sources */,
25911D292631392C0099DE52 /* FileStorage.swift in Sources */,
25911D282631392C0099DE52 /* StreamProgressDTO.swift in Sources */,
25911D262631392C0099DE52 /* AudioDataManager.swift in Sources */,
25911D1C2631392C0099DE52 /* Data.swift in Sources */,
25911D2B2631392C0099DE52 /* StreamProgressPTO.swift in Sources */,
25911D3A2631392C0099DE52 /* SAPlayerPresenter.swift in Sources */,
25911D252631392C0099DE52 /* AudioQueue.swift in Sources */,
25911D242631392C0099DE52 /* LockScreenViewProtocol.swift in Sources */,
25911D182631392C0099DE52 /* SAPlayer.swift in Sources */,
25911D382631392C0099DE52 /* AudioThrottler.swift in Sources */,
25911D362631392C0099DE52 /* AudioParserPacketListener.swift in Sources */,
25911D2C2631392C0099DE52 /* AudioDiskEngine.swift in Sources */,
25911D232631392C0099DE52 /* SAPlayerDelegate.swift in Sources */,
25911D1E2631392C0099DE52 /* URL.swift in Sources */,
25911D1A2631392C0099DE52 /* Date.swift in Sources */,
25911D2F2631392C0099DE52 /* AudioConverterErrors.swift in Sources */,
25911D1F2631392C0099DE52 /* SALockScreenInfo.swift in Sources */,
25911D1B2631392C0099DE52 /* Log.swift in Sources */,
25911D3E2631392D0099DE52 /* StreamingDownloadDirector.swift in Sources */,
25911D3D2631392D0099DE52 /* AudioQueueDirector.swift in Sources */,
25911D352631392C0099DE52 /* AudioParserPropertyListener.swift in Sources */,
25911D222631392C0099DE52 /* SAPlayerDownloader.swift in Sources */,
25911D2E2631392C0099DE52 /* AudioConverterListener.swift in Sources */,
25911D3B2631392C0099DE52 /* AudioClockDirector.swift in Sources */,
25911D372631392C0099DE52 /* AudioParserErrors.swift in Sources */,
25911D202631392C0099DE52 /* SAPlayerFeatures.swift in Sources */,
25911D3C2631392C0099DE52 /* DownloadProgressDirector.swift in Sources */,
25911D1D2631392C0099DE52 /* DirectorThreadSafeClosures.swift in Sources */,
25911D302631392C0099DE52 /* AudioConverter.swift in Sources */,
25911CD62631355C0099DE52 /* ContentView.swift in Sources */,
25911CD42631355C0099DE52 /* SwiftAudioPlayer_SwiftUIApp.swift in Sources */,
25911D4126313AF90099DE52 /* SAPlayerCombineUpdates.swift in Sources */,
25911D322631392C0099DE52 /* SAPlayingStatus.swift in Sources */,
25911D272631392C0099DE52 /* AudioStreamWorker.swift in Sources */,
25911D2D2631392C0099DE52 /* AudioStreamEngine.swift in Sources */,
25911D332631392C0099DE52 /* AudioParser.swift in Sources */,
25911D192631392C0099DE52 /* Constants.swift in Sources */,
25911D312631392C0099DE52 /* SAAudioAvailabilityRange.swift in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
/* End PBXSourcesBuildPhase section */
/* Begin XCBuildConfiguration section */
25911CDD2631355E0099DE52 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_DYNAMIC_NO_PIC = NO;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
"$(inherited)",
);
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.4;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
SWIFT_OPTIMIZATION_LEVEL = "-Onone";
};
name = Debug;
};
25911CDE2631355E0099DE52 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ANALYZER_NONNULL = YES;
CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE;
CLANG_CXX_LANGUAGE_STANDARD = "gnu++14";
CLANG_CXX_LIBRARY = "libc++";
CLANG_ENABLE_MODULES = YES;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu11;
GCC_NO_COMMON_BLOCKS = YES;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 14.4;
MTL_ENABLE_DEBUG_INFO = NO;
MTL_FAST_MATH = YES;
SDKROOT = iphoneos;
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES;
};
name = Release;
};
25911CE02631355E0099DE52 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"SwiftAudioPlayer-SwiftUI/Preview Content\"";
DEVELOPMENT_TEAM = TN363JJW64;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = "SwiftAudioPlayer-SwiftUI/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "jonmercer.SwiftAudioPlayer-SwiftUI";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Debug;
};
25911CE12631355E0099DE52 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
ASSETCATALOG_COMPILER_GLOBAL_ACCENT_COLOR_NAME = AccentColor;
CODE_SIGN_STYLE = Automatic;
DEVELOPMENT_ASSET_PATHS = "\"SwiftAudioPlayer-SwiftUI/Preview Content\"";
DEVELOPMENT_TEAM = TN363JJW64;
ENABLE_PREVIEWS = YES;
INFOPLIST_FILE = "SwiftAudioPlayer-SwiftUI/Info.plist";
IPHONEOS_DEPLOYMENT_TARGET = 14.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
);
PRODUCT_BUNDLE_IDENTIFIER = "jonmercer.SwiftAudioPlayer-SwiftUI";
PRODUCT_NAME = "$(TARGET_NAME)";
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
};
name = Release;
};
/* End XCBuildConfiguration section */
/* Begin XCConfigurationList section */
25911CCB2631355C0099DE52 /* Build configuration list for PBXProject "SwiftAudioPlayer-SwiftUI" */ = {
isa = XCConfigurationList;
buildConfigurations = (
25911CDD2631355E0099DE52 /* Debug */,
25911CDE2631355E0099DE52 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
25911CDF2631355E0099DE52 /* Build configuration list for PBXNativeTarget "SwiftAudioPlayer-SwiftUI" */ = {
isa = XCConfigurationList;
buildConfigurations = (
25911CE02631355E0099DE52 /* Debug */,
25911CE12631355E0099DE52 /* Release */,
);
defaultConfigurationIsVisible = 0;
defaultConfigurationName = Release;
};
/* End XCConfigurationList section */
};
rootObject = 25911CC82631355C0099DE52 /* Project object */;
}
@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<Workspace
version = "1.0">
<FileRef
location = "self:">
</FileRef>
</Workspace>
@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>IDEDidComputeMac32BitWarning</key>
<true/>
</dict>
</plist>
@@ -1,11 +0,0 @@
{
"colors" : [
{
"idiom" : "universal"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -1,98 +0,0 @@
{
"images" : [
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "20x20"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "29x29"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "40x40"
},
{
"idiom" : "ipad",
"scale" : "1x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "76x76"
},
{
"idiom" : "ipad",
"scale" : "2x",
"size" : "83.5x83.5"
},
{
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -1,6 +0,0 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -1,51 +0,0 @@
//
// ContentView.swift
// SwiftAudioPlayer-SwiftUI
//
// Created by Ran on 4/21/21.
//
import SwiftUI
struct ContentView: View {
//If you're going to use saUpdates in multiple views, consider moving this to your App file and inject it into each view. For each view save it as @ObservedObject instead of @StateObject
@StateObject var saUpdates = SAPlayer.SAPlayerCombine.shared
var body: some View {
VStack {
Text(saUpdates.update.elapsedTime == nil ? "Hit the play button" : "playing audio at: \(saUpdates.update.elapsedTime!)")
.padding()
Button(action: {
guard let status = saUpdates.update.playingStatus else {
//Consider moving this stuff out of the view layer to be more scalable
let url = URL(string: "https://chtbl.com/track/18338/traffic.libsyn.com/secure/acquired/Acquired_-_Rec_Room_-_Final.mp3")!
SAPlayer.shared.startRemoteAudio(withRemoteUrl: url)
SAPlayer.shared.play()
return
}
if status == .playing {
SAPlayer.shared.pause()
} else if status == .paused {
SAPlayer.shared.play()
} else {
print("you're probably still buffering, chill...")
}
}, label: {
Image(systemName: saUpdates.update.playingStatus == nil ? "play.circle.fill" : saUpdates.update.playingStatus! == .playing ? "pause.circle.fill" : "play.circle.fill")
.resizable()
.frame(width: 100, height: 100, alignment: .center)
})
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
@@ -1,50 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleDevelopmentRegion</key>
<string>$(DEVELOPMENT_LANGUAGE)</string>
<key>CFBundleExecutable</key>
<string>$(EXECUTABLE_NAME)</string>
<key>CFBundleIdentifier</key>
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
<key>CFBundleInfoDictionaryVersion</key>
<string>6.0</string>
<key>CFBundleName</key>
<string>$(PRODUCT_NAME)</string>
<key>CFBundlePackageType</key>
<string>$(PRODUCT_BUNDLE_PACKAGE_TYPE)</string>
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleVersion</key>
<string>1</string>
<key>LSRequiresIPhoneOS</key>
<true/>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<true/>
</dict>
<key>UIApplicationSupportsIndirectInputEvents</key>
<true/>
<key>UILaunchScreen</key>
<dict/>
<key>UIRequiredDeviceCapabilities</key>
<array>
<string>armv7</string>
</array>
<key>UISupportedInterfaceOrientations</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
</dict>
</plist>
@@ -1,6 +0,0 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}
@@ -1,17 +0,0 @@
//
// SwiftAudioPlayer_SwiftUIApp.swift
// SwiftAudioPlayer-SwiftUI
//
// Created by Ran on 4/21/21.
//
import SwiftUI
@main
struct SwiftAudioPlayer_SwiftUIApp: App {
var body: some Scene {
WindowGroup {
ContentView()
}
}
}
+3 -1
View File
@@ -14,6 +14,7 @@ Thus, using [AudioToolbox](https://developer.apple.com/documentation/audiotoolbo
1. Realtime audio manipulation that includes going up to 10x speed, using [equalizers and other manipulations](https://developer.apple.com/documentation/avfaudio/avaudiouniteq)
1. Stream online audio using AVAudioEngine
1. Stream radio
1. Play locally saved audio with the same API
1. Download audio
1. Queue up downloaded and streamed audio for autoplay
@@ -88,7 +89,7 @@ override func viewDidLoad() {
}
}
```
Look at the [Updates](#SAPlayer.Updates) section to see usage details and other updates to follow.
Look at the [Updates](#saplayerupdates) section to see usage details and other updates to follow.
For realtime audio manipulations, [AVAudioUnit](https://developer.apple.com/documentation/avfoundation/avaudiounit) nodes are used. For example to adjust the reverb through a slider in the UI:
@@ -113,6 +114,7 @@ For a more detailed explanation on usage, look at the [Realtime Audio Manipulati
For more details and specifics look at the [API documentation](#api-in-detail) below.
## Contact
### Issues
+23 -33
View File
@@ -123,13 +123,6 @@ public class SAPlayer {
node.rate = value
playbackRateOfAudioChanged(rate: value)
// if skip silences was on, reset it to have the new rate
// TODO fix this to rate being broadcasted and handled in only Features.SkipSilences https://github.com/tanhakabir/SwiftAudioPlayer/issues/77
// if Features.SkipSilences.enabled && !(value == rate ?? 1.0 - 0.5 || value == rate ?? 1.0 + 0.5) {
// _ = Features.SkipSilences.disable()
// _ = Features.SkipSilences.enable()
// }
}
}
@@ -183,7 +176,7 @@ public class SAPlayer {
public var audioQueued: [URL] {
get {
return presenter.audioQueue.map { (queued) -> URL in
return queued.1
return queued.url
}
}
}
@@ -233,11 +226,7 @@ public class SAPlayer {
- Note: Setting this to nil clears the information displayed on the lockscreen media player.
*/
public var mediaInfo: SALockScreenInfo? = nil {
didSet {
presenter.handleLockscreenInfo(info: mediaInfo)
}
}
public var mediaInfo: SALockScreenInfo? = nil
private init() {
presenter = SAPlayerPresenter(delegate: self)
@@ -414,14 +403,14 @@ extension SAPlayer {
- Parameter mediaInfo: The media information of the audio to show on the lockscreen media player (optional).
*/
public func startSavedAudio(withSavedUrl url: URL, mediaInfo: SALockScreenInfo? = nil) {
self.mediaInfo = mediaInfo
// Because we support queueing, we want to clear off any existing players.
// Therefore, instantiate new player every time, destroy any existing ones.
// This prevents a crash where an owning engine already exists.
presenter.handleClear()
presenter.handlePlaySavedAudio(withSavedUrl: url)
}
@available(*, deprecated, renamed: "startSavedAudio")
public func initializeSavedAudio(withSavedUrl url: URL, mediaInfo: SALockScreenInfo? = nil) {
self.mediaInfo = mediaInfo
presenter.handlePlaySavedAudio(withSavedUrl: url)
}
/**
@@ -453,14 +442,14 @@ extension SAPlayer {
- Parameter mediaInfo: The media information of the audio to show on the lockscreen media player (optional).
*/
public func startRemoteAudio(withRemoteUrl url: URL, bitrate: SAPlayerBitrate = .high, mediaInfo: SALockScreenInfo? = nil) {
self.mediaInfo = mediaInfo
// Because we support queueing, we want to clear off any existing players.
// Therefore, instantiate new player every time, destroy any existing ones.
// This prevents a crash where an owning engine already exists.
presenter.handleClear()
presenter.handlePlayStreamedAudio(withRemoteUrl: url, bitrate: bitrate)
}
@available(*, deprecated, renamed: "startRemoteAudio")
public func initializeRemoteAudio(withRemoteUrl url: URL, mediaInfo: SALockScreenInfo? = nil) {
self.mediaInfo = mediaInfo
presenter.handlePlayStreamedAudio(withRemoteUrl: url, bitrate: .high)
}
/**
@@ -474,18 +463,21 @@ extension SAPlayer {
Queues remote audio to be played next. The URLs in the queue can be both remote or on disk but once the queued audio starts playing it will start buffering and loading then. This means no guarantee for a 'gapless' playback where there might be several moments in between one audio ending and another starting due to buffering remote audio.
- Parameter withRemoteUrl: The URL of the remote audio.
- Parameter bitrate: The bitrate of the streamed audio. By default the bitrate is set to high for streaming saved audio files. If you want to stream radios then you should use the `low` bitrate option.
- Parameter mediaInfo: The media information of the audio to show on the lockscreen media player (optional).
*/
public func queueRemoteAudio(withRemoteUrl url: URL) {
presenter.handleQueueStreamedAudio(withRemoteUrl: url)
public func queueRemoteAudio(withRemoteUrl url: URL, bitrate: SAPlayerBitrate = .high, mediaInfo: SALockScreenInfo? = nil) {
presenter.handleQueueStreamedAudio(withRemoteUrl: url, mediaInfo: mediaInfo, bitrate: bitrate)
}
/**
Queues saved audio to be played next. The URLs in the queuecan be both remote or on disk but once the queued audio starts playing it will start buffering and loading then. This means no guarantee for a 'gapless' playback where there might be several moments in between one audio ending and another starting due to buffering remote audio.
- 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).
*/
public func queueSavedAudio(withSavedUrl url: URL) {
presenter.handleQueueSavedAudio(withSavedUrl: url)
public func queueSavedAudio(withSavedUrl url: URL, mediaInfo: SALockScreenInfo? = nil) {
presenter.handleQueueSavedAudio(withSavedUrl: url, mediaInfo: mediaInfo)
}
/**
@@ -523,12 +515,10 @@ extension SAPlayer: SAPlayerDelegate {
private func becomeDeviceAudioPlayer() {
do {
if #available(iOS 11.0, *) {
// try AVAudioSession.sharedInstance().setCategory(.playback, mode: .spokenAudio, policy: .longForm, options: [])
try AVAudioSession.sharedInstance().setCategory(.playback, mode: .spokenAudio, policy: .longFormAudio, options: [])
} else {
// Fallback on earlier versions
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode(rawValue: convertFromAVAudioSessionMode(AVAudioSession.Mode.default)), options: .allowAirPlay)
}
try AVAudioSession.sharedInstance().setCategory(AVAudioSession.Category.playback, mode: AVAudioSession.Mode(rawValue: convertFromAVAudioSessionMode(AVAudioSession.Mode.default)), options: .allowAirPlay)
try AVAudioSession.sharedInstance().setActive(true, options: .notifyOthersOnDeactivation)
} catch {
Log.monitor("Problem setting up AVAudioSession to play in:: \(error.localizedDescription)")
-93
View File
@@ -1,93 +0,0 @@
//
// SAPlayerCombineUpdates.swift
// SwiftAudioPlayer-SwiftUI
//
// Created by Jon Mercer on 4/21/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
import Combine
extension SAPlayer {
class SAPlayerCombine: ObservableObject {
static let shared = SAPlayerCombine()
// Ideally this won't be a nil because we should be using a PassthroughSubject. However, most new users are used to `@Published` so I went with that.
// If you're going to heavily use this player with SwiftUI consider making a PR using PassthroughSubject, or at least let me know and I'll implement that.
@Published var update = CombineUpdate()
struct CombineUpdate {
var url: URL?
var elapsedTime: Double?
var duration: Double?
var playingStatus: SAPlayingStatus?
var streamingBuffer: SAAudioAvailabilityRange?
var downloadProgress: Double?
//TODO: add queue here if people use this
}
private var elapsedTimeId:UInt?
private var durationId:UInt?
private var playingStatusId:UInt?
private var streamingBufferId:UInt?
private var audioDownloadingId:UInt?
private var audioQueueId:UInt? //TODO: add this later becuase it's more complicated
deinit {
if let id = elapsedTimeId { SAPlayer.Updates.ElapsedTime.unsubscribe(id) }
if let id = durationId { SAPlayer.Updates.Duration.unsubscribe(id) }
if let id = playingStatusId { SAPlayer.Updates.PlayingStatus.unsubscribe(id) }
if let id = streamingBufferId { SAPlayer.Updates.StreamingBuffer.unsubscribe(id) }
if let id = audioDownloadingId { SAPlayer.Updates.AudioDownloading.unsubscribe(id) }
}
init() {
elapsedTimeId = SAPlayer.Updates.ElapsedTime.subscribe { [weak self] (url:URL, timePosition:Double) in
guard let self = self else { return }
self.update.url = url
self.update.elapsedTime = timePosition
}
durationId = SAPlayer.Updates.Duration.subscribe { [weak self] (url:URL, duration:Double) in
guard let self = self else { return }
self.update.url = url
self.update.duration = duration
}
playingStatusId = SAPlayer.Updates.PlayingStatus.subscribe { [weak self] (url:URL, status:SAPlayingStatus) in
guard let self = self else { return }
self.update.url = url
self.update.playingStatus = status
}
streamingBufferId = SAPlayer.Updates.StreamingBuffer.subscribe { [weak self] (url:URL, buffer:SAAudioAvailabilityRange) in
guard let self = self else { return }
self.update.url = url
self.update.streamingBuffer = buffer
}
audioDownloadingId = SAPlayer.Updates.AudioDownloading.subscribe { [weak self] (url:URL, progress:Double) in
guard let self = self else { return }
self.update.url = url
self.update.downloadProgress = progress
}
}
}
}
+1
View File
@@ -27,6 +27,7 @@ import Foundation
import CoreMedia
protocol SAPlayerDelegate: AnyObject, LockScreenViewProtocol {
var mediaInfo: SALockScreenInfo? { get set }
var skipForwardSeconds: Double { get set }
var skipBackwardSeconds: Double { get set }
+13 -2
View File
@@ -29,7 +29,8 @@ extension SAPlayer {
/**
Enable feature to skip silences in spoken word audio. The player will speed up the rate of audio playback when silence is detected. This can be called at any point of audio playback.
- Important: The first audio modifier must be the default `AVAudioUnitTimePitch` that comes with the SAPlayer for this feature to work.
- Precondition: The first audio modifier must be the default `AVAudioUnitTimePitch` that comes with the SAPlayer for this feature to work.
- Important: If you want to change the rate of the overall player while having skip silences on, please use `SAPlayer.Features.SkipSilences.setRateSafely()` to properly set the rate of the player. Any rate changes to the player will be ignored while using Skip Silences otherwise.
*/
public static func enable() -> Bool {
guard let engine = SAPlayer.shared.engine else { return false }
@@ -72,7 +73,7 @@ extension SAPlayer {
/**
Disable feature to skip silences in spoken word audio. The player will speed up the rate of audio playback when silence is detected. This can be called at any point of audio playback.
- Important: The first audio modifier must be the default `AVAudioUnitTimePitch` that comes with the SAPlayer for this feature to work.
- Precondition: The first audio modifier must be the default `AVAudioUnitTimePitch` that comes with the SAPlayer for this feature to work.
*/
public static func disable() -> Bool {
guard let engine = SAPlayer.shared.engine else { return false }
@@ -83,6 +84,16 @@ extension SAPlayer {
return true
}
/**
Use this function to set the overall rate of the player for when skip silences is on. This ensures that the overall rate will be what is set through this function even as skip silences is on; if this function is not used then any changes asked of from the overall player while skip silences is on won't be recorded!
- Important: The first audio modifier must be the default `AVAudioUnitTimePitch` that comes with the SAPlayer for this feature to work.
*/
public static func setRateSafely(_ rate: Float) {
originalRate = rate
SAPlayer.shared.rate = rate
}
private static func scaledPower(power: Float) -> Float {
guard power.isFinite else { return 0.0 }
let minDb: Float = -80.0
+28 -26
View File
@@ -28,6 +28,20 @@ import AVFoundation
import MediaPlayer
class SAPlayerPresenter {
struct QueueItem {
var loc: Location
var url: URL
var mediaInfo: SALockScreenInfo?
var bitrate: SAPlayerBitrate
init(loc: Location, url: URL, mediaInfo: SALockScreenInfo?, bitrate: SAPlayerBitrate = .high) {
self.loc = loc
self.url = url
self.mediaInfo = mediaInfo
self.bitrate = bitrate
}
}
enum Location {
case remote
case disk
@@ -41,14 +55,13 @@ class SAPlayerPresenter {
private var key: String?
private var isPlaying: SAPlayingStatus = .buffering
private var mediaInfo: SALockScreenInfo?
private var urlKeyMap: [Key: URL] = [:]
var durationRef:UInt = 0
var needleRef:UInt = 0
var playingStatusRef:UInt = 0
var audioQueue: [(Location, URL)] = []
var audioQueue: [QueueItem] = []
init(delegate: SAPlayerDelegate?) {
self.delegate = delegate
@@ -70,7 +83,7 @@ class SAPlayerPresenter {
needle = nil
duration = nil
key = nil
mediaInfo = nil
delegate?.mediaInfo = nil
delegate?.clearLockScreenInfo()
AudioClockDirector.shared.detachFromChangesInDuration(withID: durationRef)
@@ -79,29 +92,21 @@ class SAPlayerPresenter {
}
func handlePlaySavedAudio(withSavedUrl url: URL) {
// Because we support queueing, we want to clear off any existing players.
// Therefore, instantiate new player every time, destroy any existing ones.
// This prevents a crash where an owning engine already exists.
handleClear()
attachForUpdates(url: url)
delegate?.startAudioDownloaded(withSavedUrl: url)
}
func handlePlayStreamedAudio(withRemoteUrl url: URL, bitrate: SAPlayerBitrate) {
// Because we support queueing, we want to clear off any existing players.
// Therefore, instantiate new player every time, destroy any existing ones.
// This prevents a crash where an owning engine already exists.
handleClear()
attachForUpdates(url: url)
delegate?.startAudioStreamed(withRemoteUrl: url, bitrate: bitrate)
}
func handleQueueStreamedAudio(withRemoteUrl url: URL) {
audioQueue.append((.remote, url))
func handleQueueStreamedAudio(withRemoteUrl url: URL, mediaInfo: SALockScreenInfo?, bitrate: SAPlayerBitrate) {
audioQueue.append(QueueItem(loc: .remote, url: url, mediaInfo: mediaInfo, bitrate: bitrate))
}
func handleQueueSavedAudio(withSavedUrl url: URL) {
audioQueue.append((.disk, url))
func handleQueueSavedAudio(withSavedUrl url: URL, mediaInfo: SALockScreenInfo?) {
audioQueue.append(QueueItem(loc: .disk, url: url, mediaInfo: mediaInfo))
}
private func attachForUpdates(url: URL) {
@@ -120,7 +125,7 @@ class SAPlayerPresenter {
self.delegate?.updateLockscreenPlaybackDuration(duration: duration)
self.duration = duration
self.delegate?.setLockScreenInfo(withMediaInfo: self.mediaInfo, duration: duration)
self.delegate?.setLockScreenInfo(withMediaInfo: self.delegate?.mediaInfo, duration: duration)
})
needleRef = AudioClockDirector.shared.attachToChangesInNeedle(closure: { [weak self] (key, needle) in
@@ -164,11 +169,6 @@ class SAPlayerPresenter {
delegate?.clearEngine()
detachFromUpdates()
}
@available(iOS 10.0, *)
func handleLockscreenInfo(info: SALockScreenInfo?) {
self.mediaInfo = info
}
}
//MARK:- Used by outside world including:
@@ -238,24 +238,26 @@ extension SAPlayerPresenter {
return
}
let nextAudioURL = audioQueue.removeFirst()
let key = nextAudioURL.1.key
let key = nextAudioURL.url.key
Log.info("getting ready to play \(nextAudioURL)")
AudioQueueDirector.shared.changeInQueue(key, url: nextAudioURL.1)
AudioQueueDirector.shared.changeInQueue(key, url: nextAudioURL.url)
handleClear()
delegate?.mediaInfo = nextAudioURL.mediaInfo
// We need to give a second to clean up the previous engine properly. Deinit takes some time.
Timer.scheduledTimer(withTimeInterval: 1.0, repeats: false) { [weak self] (_) in
guard let self = self else { return }
switch nextAudioURL.0 {
switch nextAudioURL.loc {
case .remote:
self.handlePlayStreamedAudio(withRemoteUrl: nextAudioURL.1, bitrate: .high) // TODO fix to add option for low birate
self.handlePlayStreamedAudio(withRemoteUrl: nextAudioURL.url, bitrate: nextAudioURL.bitrate)
break
case .disk:
self.handlePlaySavedAudio(withSavedUrl: nextAudioURL.1)
self.handlePlaySavedAudio(withSavedUrl: nextAudioURL.url)
}
self.shouldPlayImmediately = true
+2 -2
View File
@@ -8,7 +8,7 @@
Pod::Spec.new do |s|
s.name = 'SwiftAudioPlayer'
s.version = '5.0.2'
s.version = '5.0.4'
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.
@@ -26,7 +26,7 @@ SwiftAudioPlayer is a Swift based audio player that can handle streaming from a
s.license = { :type => 'MIT', :file => 'LICENSE' }
s.author = { 'tanhakabir' => 'tanhakabir.ca@gmail.com', 'JonMercer' => 'mercer.jon@gmail.com' }
s.source = { :git => 'https://github.com/tanhakabir/SwiftAudioPlayer.git', :tag => s.version.to_s }
# s.social_media_url = 'https://twitter.com/<TWITTER_USERNAME>'
s.social_media_url = 'https://twitter.com/_tanhakabir'
s.ios.deployment_target = '10.0'