diff --git a/.DS_Store b/.DS_Store new file mode 100644 index 0000000..968fd82 Binary files /dev/null and b/.DS_Store differ diff --git a/AudioExample/.DS_Store b/AudioExample/.DS_Store new file mode 100644 index 0000000..8c5c358 Binary files /dev/null and b/AudioExample/.DS_Store differ diff --git a/AudioExample/AudioExample.xcodeproj/project.pbxproj b/AudioExample/AudioExample.xcodeproj/project.pbxproj index 967ae48..06e2232 100644 --- a/AudioExample/AudioExample.xcodeproj/project.pbxproj +++ b/AudioExample/AudioExample.xcodeproj/project.pbxproj @@ -7,6 +7,7 @@ objects = { /* Begin PBXBuildFile section */ + 984808A028C0F549001160E6 /* hipjazz.wav in Resources */ = {isa = PBXBuildFile; fileRef = 9848089F28C0F549001160E6 /* hipjazz.wav */; }; B5220836256051830086FB3A /* AudioPlayerService.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220835256051830086FB3A /* AudioPlayerService.swift */; }; B5220948256074910086FB3A /* MulticastDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = B5220947256074910086FB3A /* MulticastDelegate.swift */; }; B52209502561883E0086FB3A /* EqualizerViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = B522094F2561883E0086FB3A /* EqualizerViewController.swift */; }; @@ -42,6 +43,7 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 9848089F28C0F549001160E6 /* hipjazz.wav */ = {isa = PBXFileReference; lastKnownFileType = audio.wav; path = hipjazz.wav; sourceTree = ""; }; B5220835256051830086FB3A /* AudioPlayerService.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioPlayerService.swift; sourceTree = ""; }; B5220947256074910086FB3A /* MulticastDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MulticastDelegate.swift; sourceTree = ""; }; B522094F2561883E0086FB3A /* EqualizerViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EqualizerViewController.swift; sourceTree = ""; }; @@ -78,6 +80,7 @@ B524D59D2560177C00F5A88F /* Resources */ = { isa = PBXGroup; children = ( + 9848089F28C0F549001160E6 /* hipjazz.wav */, B524D59B2560176C00F5A88F /* bensound-jazzyfrenchy.mp3 */, B5AEDBDD2475274D007D8101 /* Assets.xcassets */, B5AEDBDF2475274D007D8101 /* LaunchScreen.storyboard */, @@ -211,6 +214,7 @@ B524D59C2560176C00F5A88F /* bensound-jazzyfrenchy.mp3 in Resources */, B5AEDBE12475274D007D8101 /* LaunchScreen.storyboard in Resources */, B5AEDBDE2475274D007D8101 /* Assets.xcassets in Resources */, + 984808A028C0F549001160E6 /* hipjazz.wav in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/AudioExample/AudioExample/.DS_Store b/AudioExample/AudioExample/.DS_Store new file mode 100644 index 0000000..d2a02ff Binary files /dev/null and b/AudioExample/AudioExample/.DS_Store differ diff --git a/AudioExample/AudioExample/Controllers/PlayerViewController.swift b/AudioExample/AudioExample/Controllers/PlayerViewController.swift index ff41733..dcba25d 100644 --- a/AudioExample/AudioExample/Controllers/PlayerViewController.swift +++ b/AudioExample/AudioExample/Controllers/PlayerViewController.swift @@ -121,7 +121,8 @@ extension PlayerViewController: UITableViewDataSource { return cell } cell.textLabel?.text = item.name - cell.detailTextLabel?.text = item.queues ? "Queue item" : nil + let queuedItem = item.queues ? "Queue item" : nil + cell.detailTextLabel?.text = queuedItem ?? item.subtitle update(status: item.status, of: cell) return cell } diff --git a/AudioExample/AudioExample/Controllers/PlayerViewModel.swift b/AudioExample/AudioExample/Controllers/PlayerViewModel.swift index 4f6a80b..88f8825 100644 --- a/AudioExample/AudioExample/Controllers/PlayerViewModel.swift +++ b/AudioExample/AudioExample/Controllers/PlayerViewModel.swift @@ -48,7 +48,7 @@ final class PlayerViewModel { print("malformed url error") return } - playlistItemsService.add(item: PlaylistItem(url: url, name: urlString, status: .stopped, queues: false)) + playlistItemsService.add(item: PlaylistItem(url: url, name: urlString, subtitle: nil, status: .stopped, queues: false)) reloadContent?(.all) } diff --git a/AudioExample/AudioExample/Resources/hipjazz.wav b/AudioExample/AudioExample/Resources/hipjazz.wav new file mode 100644 index 0000000..20807ed Binary files /dev/null and b/AudioExample/AudioExample/Resources/hipjazz.wav differ diff --git a/AudioExample/AudioExample/Services/AudioContent.swift b/AudioExample/AudioExample/Services/AudioContent.swift index d4857ed..3f0b392 100644 --- a/AudioExample/AudioExample/Services/AudioContent.swift +++ b/AudioExample/AudioExample/Services/AudioContent.swift @@ -16,7 +16,9 @@ enum AudioContent: Int, CaseIterable { case radiox case khruangbin case piano + case remoteWave case local + case localWave var title: String { switch self { @@ -34,8 +36,37 @@ enum AudioContent: Int, CaseIterable { return "Khruangbin (mp3 preview)" case .piano: return "Piano (mp3)" + case .remoteWave: + return "Sample remote (wave)" case .local: - return "Local file (mp3)" + return "Jazzy Frenchy (local mp3)" + case .localWave: + return "Local file (local wave)" + } + } + + var subtitle: String? { + switch self { + case .offradio: + return nil + case .enlefko: + return nil + case .pepper966: + return nil + case .kosmos: + return nil + case .radiox: + return nil + case .khruangbin: + return nil + case .piano: + return nil + case .remoteWave: + return nil + case .local: + return "Music by: bensound.com" + case .localWave: + return "Music by: bensound.com" } } @@ -46,7 +77,7 @@ enum AudioContent: Int, CaseIterable { case .offradio: return URL(string: "https://s3.yesstreaming.net:17062/stream")! case .pepper966: - return URL(string: "https://ample-09.radiojar.com/pepper.m4a?1593699983=&rj-tok=AAABcw_1KyMAIViq2XpI098ZSQ&rj-ttl=5")! + return URL(string: "https://n04.radiojar.com/pepper.m4a?1662039818=&rj-tok=AAABgvlUaioALhdOXDt0mgajoA&rj-ttl=5")! case .kosmos: return URL(string: "https://radiostreaming.ert.gr/ert-kosmos")! case .radiox: @@ -58,6 +89,11 @@ enum AudioContent: Int, CaseIterable { case .local: let path = Bundle.main.path(forResource: "bensound-jazzyfrenchy", ofType: "mp3")! return URL(fileURLWithPath: path) + case .localWave: + let path = Bundle.main.path(forResource: "hipjazz", ofType: "wav")! + return URL(fileURLWithPath: path) + case .remoteWave: + return URL(string: "https://file-examples.com/storage/fe183d9197630fb5c969255/2017/11/file_example_WAV_5MG.wav")! } } } diff --git a/AudioExample/AudioExample/Services/PlaylistItemsService.swift b/AudioExample/AudioExample/Services/PlaylistItemsService.swift index 30e0c35..51f867e 100644 --- a/AudioExample/AudioExample/Services/PlaylistItemsService.swift +++ b/AudioExample/AudioExample/Services/PlaylistItemsService.swift @@ -18,19 +18,22 @@ struct PlaylistItem: Equatable { let url: URL let name: String + let subtitle: String? let status: Status let queues: Bool init(content: AudioContent, queues: Bool) { name = content.title + subtitle = content.subtitle url = content.streamUrl status = .stopped self.queues = queues } - init(url: URL, name: String, status: Status, queues: Bool) { + init(url: URL, name: String, subtitle: String?, status: Status, queues: Bool) { self.url = url self.name = name + self.subtitle = subtitle self.status = status self.queues = queues } @@ -73,7 +76,13 @@ final class PlaylistItemsService { guard let item = item(at: index) else { return } - items[index] = PlaylistItem(url: item.url, name: item.name, status: status, queues: item.queues) + items[index] = PlaylistItem( + url: item.url, + name: item.name, + subtitle: item.subtitle, + status: status, + queues: item.queues + ) } } diff --git a/AudioStreaming/Streaming/Audio Entry/AudioEntry.swift b/AudioStreaming/Streaming/Audio Entry/AudioEntry.swift index fb32d55..9569ec7 100644 --- a/AudioStreaming/Streaming/Audio Entry/AudioEntry.swift +++ b/AudioStreaming/Streaming/Audio Entry/AudioEntry.swift @@ -22,9 +22,7 @@ internal class AudioEntry { let id: AudioEntryId /// The sample rate from the `audioStreamFormat` - var sampleRate: Float { - Float(audioStreamFormat.mSampleRate) - } + var sampleRate: Float var audioFileHint: AudioFileTypeID { source.audioFileHint @@ -49,9 +47,7 @@ internal class AudioEntry { private(set) var framesState: EntryFramesState private(set) var processedPacketsState: ProcessedPacketsState - var packetDuration: Double { - return Double(audioStreamFormat.mFramesPerPacket) / Double(sampleRate) - } + var packetDuration: Double private var averagePacketByteSize: Double { let packets = processedPacketsState @@ -72,6 +68,8 @@ internal class AudioEntry { processedPacketsState = ProcessedPacketsState() framesState = EntryFramesState() audioStreamState = AudioStreamState() + sampleRate = 0 + packetDuration = 0 } func close() { diff --git a/AudioStreaming/Streaming/AudioPlayer/AudioPlayer.swift b/AudioStreaming/Streaming/AudioPlayer/AudioPlayer.swift index 64eb948..ecb0322 100644 --- a/AudioStreaming/Streaming/AudioPlayer/AudioPlayer.swift +++ b/AudioStreaming/Streaming/AudioPlayer/AudioPlayer.swift @@ -140,7 +140,7 @@ open class AudioPlayer { entriesQueue = PlayerQueueEntries() serializationQueue = DispatchQueue(label: "streaming.core.queue", qos: .userInitiated) - sourceQueue = DispatchQueue(label: "source.queue", qos: .userInitiated) + sourceQueue = DispatchQueue(label: "source.queue", qos: .default) entryProvider = AudioEntryProvider(networkingClient: NetworkingClient(), underlyingQueue: sourceQueue, diff --git a/AudioStreaming/Streaming/AudioPlayer/Processors/AudioFileStreamProcessor.swift b/AudioStreaming/Streaming/AudioPlayer/Processors/AudioFileStreamProcessor.swift index 64e21ae..c256074 100644 --- a/AudioStreaming/Streaming/AudioPlayer/Processors/AudioFileStreamProcessor.swift +++ b/AudioStreaming/Streaming/AudioPlayer/Processors/AudioFileStreamProcessor.swift @@ -116,7 +116,7 @@ final class AudioFileStreamProcessor { readingEntry.lock.unlock() let bitrate = readingEntry.calculatedBitrate() - if readingEntry.processedPacketsState.count > 0, bitrate > 0 { + if readingEntry.packetDuration > 0, bitrate > 0 { var ioFlags = AudioFileStreamSeekFlags(rawValue: 0) var packetsAlignedByteOffset: Int64 = 0 let seekPacket = Int64(floor(readingEntry.seekRequest.time / readingEntry.packetDuration)) @@ -279,6 +279,9 @@ final class AudioFileStreamProcessor { entry.audioStreamFormat = audioStreamFormat } + entry.sampleRate = Float(audioStreamFormat.mSampleRate) + entry.packetDuration = Double(audioStreamFormat.mFramesPerPacket) / Double(entry.sampleRate) + var packetBufferSize: UInt32 = 0 var status = fileStreamGetProperty(value: &packetBufferSize, fileStream: fileStream, diff --git a/AudioStreaming/Streaming/AudioPlayer/Processors/AudioPlayerRenderProcessor.swift b/AudioStreaming/Streaming/AudioPlayer/Processors/AudioPlayerRenderProcessor.swift index 0c270dc..41d4170 100644 --- a/AudioStreaming/Streaming/AudioPlayer/Processors/AudioPlayerRenderProcessor.swift +++ b/AudioStreaming/Streaming/AudioPlayer/Processors/AudioPlayerRenderProcessor.swift @@ -198,7 +198,6 @@ final class AudioPlayerRenderProcessor: NSObject { state.contains(.running) && state != .playing } } - rendererContext.waitingForDataAfterSeekFrameCount.write { $0 = 0 } } } else { rendererContext.waitingForDataAfterSeekFrameCount.write { $0 = 0 }