diff --git a/AudioStreaming/Streaming/Audio Source/AudioStreamSource.swift b/AudioStreaming/Streaming/Audio Source/AudioStreamSource.swift index 9f797e7..7c91c69 100644 --- a/AudioStreaming/Streaming/Audio Source/AudioStreamSource.swift +++ b/AudioStreaming/Streaming/Audio Source/AudioStreamSource.swift @@ -6,7 +6,7 @@ import AudioToolbox import Foundation -protocol AudioStreamSourceDelegate: AnyObject { +public protocol AudioStreamSourceDelegate: AnyObject { /// Indicates that there's data available func dataAvailable(source: CoreAudioStreamSource, data: Data) /// Indicates an error occurred @@ -17,7 +17,7 @@ protocol AudioStreamSourceDelegate: AnyObject { func metadataReceived(data: [String: String]) } -protocol CoreAudioStreamSource: AnyObject { +public protocol CoreAudioStreamSource: AnyObject { /// An `Int` that represents the position of the audio var position: Int { get } /// The length of the audio in bytes diff --git a/AudioStreaming/Streaming/Audio Source/RemoteAudioSource.swift b/AudioStreaming/Streaming/Audio Source/RemoteAudioSource.swift index 370fb67..10bbba0 100644 --- a/AudioStreaming/Streaming/Audio Source/RemoteAudioSource.swift +++ b/AudioStreaming/Streaming/Audio Source/RemoteAudioSource.swift @@ -13,13 +13,13 @@ enum RemoteAudioSourceError: Error { } public class RemoteAudioSource: AudioStreamSource { - weak var delegate: AudioStreamSourceDelegate? + public weak var delegate: AudioStreamSourceDelegate? - var position: Int { + public var position: Int { return seekOffset + relativePosition } - var length: Int { + public var length: Int { guard let parsedHeader = parsedHeaderOutput else { return 0 } return parsedHeader.fileLength } @@ -40,7 +40,7 @@ public class RemoteAudioSource: AudioStreamSource { private var shouldTryParsingIcycastHeaders: Bool = false private let icycastHeadersProcessor: IcycastHeadersProcessor - var audioFileHint: AudioFileTypeID { + public var audioFileHint: AudioFileTypeID { guard let output = parsedHeaderOutput, output.typeId != 0 else { return audioFileType(fileExtension: url.pathExtension) } @@ -49,7 +49,7 @@ public class RemoteAudioSource: AudioStreamSource { private let mp4Restructure: RemoteMp4Restructure - let underlyingQueue: DispatchQueue + public let underlyingQueue: DispatchQueue let streamOperationQueue: OperationQueue let netStatusService: NetStatusProvider var waitingForNetwork = false @@ -114,7 +114,7 @@ public class RemoteAudioSource: AudioStreamSource { httpHeaders: [:]) } - func close() { + public func close() { retrierTimeout.cancel() streamOperationQueue.isSuspended = false streamOperationQueue.cancelAllOperations() @@ -125,7 +125,7 @@ public class RemoteAudioSource: AudioStreamSource { streamRequest = nil } - func seek(at offset: Int) { + public func seek(at offset: Int) { close() relativePosition = 0 @@ -144,11 +144,11 @@ public class RemoteAudioSource: AudioStreamSource { performOpen(seek: offset) } - func suspend() { + public func suspend() { streamOperationQueue.isSuspended = true } - func resume() { + public func resume() { streamOperationQueue.isSuspended = false } diff --git a/AudioStreaming/Streaming/AudioPlayer/AudioPlayer.swift b/AudioStreaming/Streaming/AudioPlayer/AudioPlayer.swift index 0471cf0..5a29251 100644 --- a/AudioStreaming/Streaming/AudioPlayer/AudioPlayer.swift +++ b/AudioStreaming/Streaming/AudioPlayer/AudioPlayer.swift @@ -124,7 +124,7 @@ open class AudioPlayer { private let frameFilterProcessor: FrameFilterProcessor private let serializationQueue: DispatchQueue - private let sourceQueue: DispatchQueue + public let sourceQueue: DispatchQueue private let entryProvider: AudioEntryProviding @@ -190,6 +190,20 @@ open class AudioPlayer { /// - parameter headers: A `Dictionary` specifying any additional headers to be pass to the network request. public func play(url: URL, headers: [String: String]) { let audioEntry = entryProvider.provideAudioEntry(url: url, headers: headers) + play(audioEntry: audioEntry) + } + + /// Starts the audio playback for the supplied stream + /// + /// - parameter source: A `CoreAudioStreamSource` that will providing streaming data + /// - parameter entryId: A `String` that provides a unique id for this item + /// - parameter format: An `AVAudioFormat` the format of this audio source + public func play(source: CoreAudioStreamSource, entryId: String, format: AVAudioFormat) { + let audioEntry = AudioEntry(source: source, entryId: AudioEntryId(id: entryId), outputAudioFormat: format) + play(audioEntry: audioEntry) + } + + private func play(audioEntry: AudioEntry) { audioEntry.delegate = self checkRenderWaitingAndNotifyIfNeeded() @@ -805,7 +819,7 @@ open class AudioPlayer { } extension AudioPlayer: AudioStreamSourceDelegate { - func dataAvailable(source: CoreAudioStreamSource, data: Data) { + public func dataAvailable(source: CoreAudioStreamSource, data: Data) { guard let readingEntry = playerContext.audioReadingEntry, readingEntry.has(same: source) else { return } @@ -835,12 +849,12 @@ extension AudioPlayer: AudioStreamSourceDelegate { } } - func errorOccurred(source: CoreAudioStreamSource, error: Error) { + public func errorOccurred(source: CoreAudioStreamSource, error: Error) { guard let entry = playerContext.audioReadingEntry, entry.has(same: source) else { return } raiseUnexpected(error: .networkError(.failure(error))) } - func endOfFileOccurred(source: CoreAudioStreamSource) { + public func endOfFileOccurred(source: CoreAudioStreamSource) { let hasSameSource = playerContext.audioReadingEntry?.has(same: source) ?? false guard playerContext.audioReadingEntry == nil || hasSameSource else { source.delegate = nil @@ -877,7 +891,7 @@ extension AudioPlayer: AudioStreamSourceDelegate { } } - func metadataReceived(data: [String: String]) { + public func metadataReceived(data: [String: String]) { asyncOnMain { [weak self] in guard let self = self else { return } self.delegate?.audioPlayerDidReadMetadata(player: self, metadata: data)