From dfced03ad791a86c58c4cc2e046280cfc2fac578 Mon Sep 17 00:00:00 2001 From: Dimitris C Date: Thu, 13 Aug 2020 09:02:47 +0300 Subject: [PATCH] Fixes issue on OutputStreamWriter --- .../xcschemes/AudioExample.xcscheme | 5 ++++ .../AudioExample/ViewController.swift | 10 +++++-- AudioStreaming/Core/DispatchReadSource.swift | 3 ++- .../Core/Network/NetworkDataStream.swift | 10 ++++--- .../Core/Network/NetworkSessionDelegate.swift | 4 +-- .../Core/Network/NetworkingClient.swift | 2 ++ .../Core/Network/OutputStreamWriter.swift | 26 ++++++++++++++----- .../Streaming/AudioSource/AudioEntry.swift | 13 +++++----- .../AudioSource/RemoteAudioSource.swift | 1 + 9 files changed, 52 insertions(+), 22 deletions(-) diff --git a/AudioExample/AudioExample.xcodeproj/xcshareddata/xcschemes/AudioExample.xcscheme b/AudioExample/AudioExample.xcodeproj/xcshareddata/xcschemes/AudioExample.xcscheme index 8726906..bc22a65 100644 --- a/AudioExample/AudioExample.xcodeproj/xcshareddata/xcschemes/AudioExample.xcscheme +++ b/AudioExample/AudioExample.xcodeproj/xcshareddata/xcschemes/AudioExample.xcscheme @@ -75,6 +75,11 @@ value = "" isEnabled = "YES"> + + 0 { self.expectedContentLength = .length(value: contentLength) } + streamState.outputStream?.open() } internal func didReceive(data: Data, response: HTTPURLResponse?) { underlyingQueue.async { [weak self] in guard let self = self else { return } self.outputStreamWriter.storeReceived(data: data) - if let outputStream = self.streamState.outputStream, outputStream.hasSpaceAvailable { - let writtenBytes = self.outputStreamWriter.writeData(on: outputStream, bufferSize: self.bufferSize) - self.checkEndOfFile(stream: outputStream, writtenBytes: writtenBytes) + if let outputStream = self.streamState.outputStream, outputStream.streamStatus == .open { + if outputStream.hasSpaceAvailable { + let writtenBytes = self.outputStreamWriter.writeData(on: outputStream, bufferSize: self.bufferSize) + self.checkEndOfFile(stream: outputStream, writtenBytes: writtenBytes) + } } } $streamState.read { state in diff --git a/AudioStreaming/Core/Network/NetworkSessionDelegate.swift b/AudioStreaming/Core/Network/NetworkSessionDelegate.swift index a78f717..55a4ff8 100644 --- a/AudioStreaming/Core/Network/NetworkSessionDelegate.swift +++ b/AudioStreaming/Core/Network/NetworkSessionDelegate.swift @@ -41,9 +41,9 @@ internal final class NetworkSessionDelegate: NSObject, URLSessionDataDelegate { } //extension NetworkSessionDelegate: URLSessionTaskDelegate { -// +// // func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) { // completionHandler(.performDefaultHandling, nil) // } -// +// //} diff --git a/AudioStreaming/Core/Network/NetworkingClient.swift b/AudioStreaming/Core/Network/NetworkingClient.swift index 68f4d53..2bb59ea 100644 --- a/AudioStreaming/Core/Network/NetworkingClient.swift +++ b/AudioStreaming/Core/Network/NetworkingClient.swift @@ -18,7 +18,9 @@ extension URLSessionConfiguration { static var networkingConfiguration: URLSessionConfiguration { let configuration = URLSessionConfiguration.default configuration.networkServiceType = .avStreaming + configuration.requestCachePolicy = .reloadIgnoringCacheData configuration.urlCache = nil + configuration.httpCookieStorage = nil return configuration } } diff --git a/AudioStreaming/Core/Network/OutputStreamWriter.swift b/AudioStreaming/Core/Network/OutputStreamWriter.swift index 98fa61a..dd84eca 100644 --- a/AudioStreaming/Core/Network/OutputStreamWriter.swift +++ b/AudioStreaming/Core/Network/OutputStreamWriter.swift @@ -7,8 +7,10 @@ final class OutputStreamWriter { /// The accumulated data received from the URLSession private var dataReceived = Data() - /// Keeps a track of the written bytes in the output stream - private var bytesWritten: Int = 0 + /// Keeps track of the total written bytes in the output stream + private var totalBytesWritten: Int = 0 + /// Keeps tracks of the index that bytes were written in the output stream + private var byteIndex: Int = 0 /// Write the data on the `OutputStream` /// @@ -20,12 +22,12 @@ final class OutputStreamWriter { guard !dataReceived.isEmpty else { return 0 } var bytes = dataReceived.getBytes { $0 } /// offset the buffer by the number of written bytes - bytes += bytesWritten + bytes += byteIndex let dataCount = dataReceived.count // get the count of bytes to be written, restrict to maximum of `bufferSize` - let count = (dataCount - bytesWritten >= bufferSize) + let count = (dataCount - byteIndex >= bufferSize) ? bufferSize - : dataCount - bytesWritten + : dataCount - byteIndex guard count > 0 else { return 0 } @@ -34,10 +36,20 @@ final class OutputStreamWriter { defer { buffer.deallocate() } memcpy(buffer, bytes, count) - bytesWritten += stream.write(buffer, maxLength: count) - return bytesWritten + let written = stream.write(buffer, maxLength: count) + byteIndex += written + if written > 0 && dataReceived.count > written { + dataReceived.removeFirst(written) + byteIndex -= written + } + + totalBytesWritten += written + return totalBytesWritten } + /// Stores the given data + /// + /// - parameter data: A `Data` object as received from a network request. func storeReceived(data: Data) { self.dataReceived.append(data) } diff --git a/AudioStreaming/Streaming/AudioSource/AudioEntry.swift b/AudioStreaming/Streaming/AudioSource/AudioEntry.swift index 538ebc8..22cd8f5 100644 --- a/AudioStreaming/Streaming/AudioSource/AudioEntry.swift +++ b/AudioStreaming/Streaming/AudioSource/AudioEntry.swift @@ -41,11 +41,11 @@ public class AudioEntry { var packetCount: Double = 0 var packetDuration: Double { - return Double(audioStreamFormat.basicStreamDescription.mFramesPerPacket) / Double(sampleRate) + return Double(audioStreamFormat.mFramesPerPacket) / Double(sampleRate) } /// The sample rate from the `audioStreamFormat` var sampleRate: Float { - Float(audioStreamFormat.basicStreamDescription.mSampleRate) + Float(audioStreamFormat.mSampleRate) } var framesState: EntryFramesState @@ -54,7 +54,7 @@ public class AudioEntry { var audioDataOffset: UInt64 = 0 var audioDataByteCount: UInt64? - var audioStreamFormat = AVAudioFormat() + var audioStreamFormat = AudioStreamBasicDescription() private var avaragePacketByteSize: Double { let packets = processedPacketsState @@ -78,19 +78,20 @@ public class AudioEntry { } func calculatedBitrate() -> Double { + lock.lock(); defer { lock.unlock() } let packets = processedPacketsState if packetDuration > 0 { if packets.count > estimationMinPacketsPreferred || - (audioStreamFormat.basicStreamDescription.mBytesPerFrame == 0 && packets.count > estimationMinPackets) { + (audioStreamFormat.mBytesPerFrame == 0 && packets.count > estimationMinPackets) { return avaragePacketByteSize / packetDuration * 8 } } - return (Double(audioStreamFormat.basicStreamDescription.mBytesPerFrame) * audioStreamFormat.basicStreamDescription.mSampleRate) * 8 + return (Double(audioStreamFormat.mBytesPerFrame) * audioStreamFormat.mSampleRate) * 8 } func progressInFrames() -> Float { lock.lock(); defer { lock.unlock() } - return (seekTime + Float(audioStreamFormat.basicStreamDescription.mSampleRate)) + Float(framesState.played) + return (seekTime + Float(audioStreamFormat.mSampleRate)) + Float(framesState.played) } func duration() -> Double { diff --git a/AudioStreaming/Streaming/AudioSource/RemoteAudioSource.swift b/AudioStreaming/Streaming/AudioSource/RemoteAudioSource.swift index 949d167..dc84f10 100644 --- a/AudioStreaming/Streaming/AudioSource/RemoteAudioSource.swift +++ b/AudioStreaming/Streaming/AudioSource/RemoteAudioSource.swift @@ -208,6 +208,7 @@ public class RemoteAudioSource: NSObject, AudioStreamSource { private func buildUrlRequest(with url: URL, seekIfNeeded seekOffset: Int) -> URLRequest { var urlRequest = URLRequest(url: self.url) urlRequest.networkServiceType = .avStreaming + urlRequest.cachePolicy = .reloadIgnoringLocalCacheData for header in self.additionalRequestHeaders { urlRequest.addValue(header.value, forHTTPHeaderField: header.key)