diff --git a/RootEncoder/.swiftpm/xcode/xcshareddata/xcschemes/RootEncoderTests.xcscheme b/RootEncoder/.swiftpm/xcode/xcshareddata/xcschemes/RootEncoderTests.xcscheme new file mode 100644 index 0000000..a65441f --- /dev/null +++ b/RootEncoder/.swiftpm/xcode/xcshareddata/xcschemes/RootEncoderTests.xcscheme @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RootEncoder/Sources/RootEncoder/encoder/audio/AudioEncoder.swift b/RootEncoder/Sources/RootEncoder/encoder/audio/AudioEncoder.swift index 2384eb4..8d1f7c6 100644 --- a/RootEncoder/Sources/RootEncoder/encoder/audio/AudioEncoder.swift +++ b/RootEncoder/Sources/RootEncoder/encoder/audio/AudioEncoder.swift @@ -17,14 +17,29 @@ public class AudioEncoder { private var initTs: Int64 = 0 private let thread = DispatchQueue(label: "AudioEncoder") private let syncQueue = SynchronizedQueue(label: "AudioEncodeQueue", size: 60) - public var codec = AudioCodec.AAC + private var codec = AudioCodec.AAC public init(callback: GetAacData) { self.callback = callback } + public func setCodec(codec: AudioCodec) { + self.codec = codec + } + public func prepareAudio(inputFormat: AVAudioFormat, sampleRate: Double, channels: UInt32, bitrate: Int) -> Bool { - guard let outputFormat = getAACFormat(sampleRate: sampleRate, channels: channels) else { + if (codec == AudioCodec.G711 && (sampleRate != 8000 || channels != 1)) { + print("G711 only support samplerate 8000 and mono channel") + return false + } + let format: AVAudioFormat? = if codec == AudioCodec.AAC { + getAACFormat(sampleRate: sampleRate, channels: channels) + } else if codec == AudioCodec.G711 { + getG711AFormat(sampleRate: sampleRate, channels: channels) + } else { + nil + } + guard let outputFormat = format else { return false } guard let converter = AVAudioConverter(from: inputFormat, to: outputFormat) else { @@ -52,30 +67,51 @@ public class AudioEncoder { let b = self.syncQueue.dequeue() if let b = b { var error: NSError? = nil - guard let aacBuffer = self.convertToAAC(buffer: b, error: &error) else { - continue - } - if error != nil { - print("Encode error: \(error.debugDescription)") - } else { - let data = Array(UnsafeBufferPointer(start: aacBuffer.data.assumingMemoryBound(to: UInt8.self), count: Int(aacBuffer.byteLength))) - guard let packetDescriptions = aacBuffer.packetDescriptions else { + if self.codec == AudioCodec.AAC { + guard let aacBuffer = self.convertToAAC(buffer: b, error: &error) else { + continue + } + if error != nil { + print("Encode error: \(error.debugDescription)") + } else { + let data = Array(UnsafeBufferPointer(start: aacBuffer.data.assumingMemoryBound(to: UInt8.self), count: Int(aacBuffer.byteLength))) + guard let packetDescriptions = aacBuffer.packetDescriptions else { + continue + } + for i in 0..(repeating: 0, count: Int(info.mDataByteSize)) + mBuffer[0...mBuffer.count - 1] = data[Int(info.mStartOffset)...Int(info.mStartOffset) + Int(info.mDataByteSize - 1)] + let end = Date().millisecondsSince1970 + let elapsedNanoSeconds = (end - self.initTs) * 1000 + + var frame = Frame() + frame.buffer = mBuffer + frame.length = UInt32(mBuffer.count) + frame.timeStamp = UInt64(elapsedNanoSeconds) + self.callback?.getAacData(frame: frame) + } + } + } else if self.codec == AudioCodec.G711 { + guard let g711Buffer = self.convertToG711(buffer: b, error: &error) else { continue } - for i in 0..(repeating: 0, count: Int(info.mDataByteSize)) - mBuffer[0...mBuffer.count - 1] = data[Int(info.mStartOffset)...Int(info.mStartOffset) + Int(info.mDataByteSize - 1)] + if error != nil { + print("Encode error: \(error.debugDescription)") + } else { + let data = g711Buffer.audioBufferToBytes() let end = Date().millisecondsSince1970 let elapsedNanoSeconds = (end - self.initTs) * 1000 var frame = Frame() - frame.buffer = mBuffer - frame.length = UInt32(mBuffer.count) + frame.buffer = data + frame.length = UInt32(data.count) frame.timeStamp = UInt64(elapsedNanoSeconds) self.callback?.getAacData(frame: frame) + } } + } } } @@ -97,6 +133,16 @@ public class AudioEncoder { return outBuffer } + private func convertToG711(buffer: AVAudioPCMBuffer, error: inout NSError?) -> AVAudioPCMBuffer? { + guard let outputFormat = outputFormat else { + return nil + } + let outBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat, frameCapacity: AVAudioFrameCount(outputFormat.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate))! + outBuffer.frameLength = outBuffer.frameCapacity + self.convert(sourceBuffer: buffer, destinationBuffer: outBuffer, error: &error) + return outBuffer + } + private func convert(sourceBuffer: AVAudioPCMBuffer, destinationBuffer: AVAudioBuffer, error: NSErrorPointer) { if (running) { sourceBuffer.frameLength = sourceBuffer.frameCapacity @@ -118,7 +164,28 @@ public class AudioEncoder { } private func getAACFormat(sampleRate: Double, channels: UInt32) -> AVAudioFormat? { - var description = AudioStreamBasicDescription(mSampleRate: sampleRate, mFormatID: kAudioFormatMPEG4AAC, mFormatFlags: 0, mBytesPerPacket: 0, mFramesPerPacket: 0, mBytesPerFrame: 0, mChannelsPerFrame: channels, mBitsPerChannel: 0, mReserved: 0) + var description = AudioStreamBasicDescription(mSampleRate: sampleRate, + mFormatID: kAudioFormatMPEG4AAC, + mFormatFlags: 0, + mBytesPerPacket: 0, + mFramesPerPacket: 0, + mBytesPerFrame: 0, + mChannelsPerFrame: channels, + mBitsPerChannel: 0, + mReserved: 0) + return AVAudioFormat(streamDescription: &description) + } + + private func getG711AFormat(sampleRate: Double, channels: UInt32) -> AVAudioFormat? { + var description = AudioStreamBasicDescription(mSampleRate: sampleRate, + mFormatID: kAudioFormatALaw, + mFormatFlags: AudioFormatFlags(kAudioFormatALaw), + mBytesPerPacket: 1, + mFramesPerPacket: 1, + mBytesPerFrame: 1, + mChannelsPerFrame: channels, + mBitsPerChannel: 8, + mReserved: 0) return AVAudioFormat(streamDescription: &description) } } diff --git a/RootEncoder/Sources/RootEncoder/encoder/input/audio/MicrophoneManager.swift b/RootEncoder/Sources/RootEncoder/encoder/input/audio/MicrophoneManager.swift index 4576671..8feb688 100644 --- a/RootEncoder/Sources/RootEncoder/encoder/input/audio/MicrophoneManager.swift +++ b/RootEncoder/Sources/RootEncoder/encoder/input/audio/MicrophoneManager.swift @@ -11,7 +11,7 @@ import AVFoundation public class MicrophoneManager { - private let thread = DispatchQueue.global() + private let thread = DispatchQueue(label: "MicrophoneManager") private let audioEngine = AVAudioEngine() private var inputNode: AVAudioInputNode? private var inputFormat: AVAudioFormat? diff --git a/RootEncoder/Sources/RootEncoder/encoder/utils/EncoderUtils.swift b/RootEncoder/Sources/RootEncoder/encoder/utils/EncoderUtils.swift index b20d6ab..35227ce 100644 --- a/RootEncoder/Sources/RootEncoder/encoder/utils/EncoderUtils.swift +++ b/RootEncoder/Sources/RootEncoder/encoder/utils/EncoderUtils.swift @@ -34,6 +34,19 @@ public extension AVAudioPCMBuffer { ) return sampleBuffer } + + func audioBufferToBytes() -> [UInt8] { + let srcLeft = self.audioBufferList.pointee.mBuffers.mData! + let bytesPerFrame = self.format.streamDescription.pointee.mBytesPerFrame + let numBytes = Int(bytesPerFrame * self.frameLength) + var audioByteArray = [UInt8](repeating: 0, count: numBytes) + srcLeft.withMemoryRebound(to: UInt8.self, capacity: numBytes) { srcByteData in + audioByteArray.withUnsafeMutableBufferPointer { + $0.baseAddress!.initialize(from: srcByteData, count: numBytes) + } + } + return audioByteArray + } } extension AVAudioTime { diff --git a/RootEncoder/Sources/RootEncoder/encoder/video/VideoEncoder.swift b/RootEncoder/Sources/RootEncoder/encoder/video/VideoEncoder.swift index 42a44fd..360a085 100644 --- a/RootEncoder/Sources/RootEncoder/encoder/video/VideoEncoder.swift +++ b/RootEncoder/Sources/RootEncoder/encoder/video/VideoEncoder.swift @@ -52,7 +52,6 @@ public class VideoEncoder { codecType: codec.value, encoderSpecification: nil, imageBufferAttributes: nil, compressedDataAllocator: nil, outputCallback: videoCallback, refcon: Unmanaged.passUnretained(self).toOpaque(), compressionSessionOut: &session) - print("using codec \(codec)") self.resolution = resolution self.fps = fps self.bitrate = bitrate @@ -100,8 +99,13 @@ public class VideoEncoder { } } - public func setCodec(codec: CodecUtil) { - self.codec = codec + public func setCodec(codec: VideoCodec) { + switch codec { + case .H264: + self.codec = CodecUtil.H264 + case .H265: + self.codec = CodecUtil.H265 + } } public func forceKeyFrame() { diff --git a/RootEncoder/Sources/RootEncoder/library/base/CameraBase.swift b/RootEncoder/Sources/RootEncoder/library/base/CameraBase.swift index 31ef1ba..8144331 100644 --- a/RootEncoder/Sources/RootEncoder/library/base/CameraBase.swift +++ b/RootEncoder/Sources/RootEncoder/library/base/CameraBase.swift @@ -164,21 +164,13 @@ public class CameraBase: GetMicrophoneData, GetCameraData, GetAacData, GetH264Da public func setVideoCodec(codec: VideoCodec) { setVideoCodecImp(codec: codec) recordController.setVideoCodec(codec: codec) - let type = switch codec { - case .H264: - CodecUtil.H264 - case .H265: - CodecUtil.H265 - @unknown default: - CodecUtil.H264 - } - videoEncoder.setCodec(codec: type) + videoEncoder.setCodec(codec: codec) } public func setAudioCodec(codec: AudioCodec) { setAudioCodecImp(codec: codec) recordController.setAudioCodec(codec: codec) - audioEncoder.codec = codec + audioEncoder.setCodec(codec: codec) } public func setVideoCodecImp(codec: VideoCodec) {} diff --git a/RootEncoder/Sources/RootEncoder/library/base/DisplayBase.swift b/RootEncoder/Sources/RootEncoder/library/base/DisplayBase.swift index a230ddf..ce6f68b 100644 --- a/RootEncoder/Sources/RootEncoder/library/base/DisplayBase.swift +++ b/RootEncoder/Sources/RootEncoder/library/base/DisplayBase.swift @@ -148,21 +148,13 @@ public class DisplayBase: GetMicrophoneData, GetCameraData, GetAacData, GetH264D public func setVideoCodec(codec: VideoCodec) { setVideoCodecImp(codec: codec) recordController.setVideoCodec(codec: codec) - let type = switch codec { - case .H264: - CodecUtil.H264 - case .H265: - CodecUtil.H265 - @unknown default: - CodecUtil.H264 - } - videoEncoder.setCodec(codec: type) + videoEncoder.setCodec(codec: codec) } public func setAudioCodec(codec: AudioCodec) { setAudioCodecImp(codec: codec) recordController.setAudioCodec(codec: codec) - audioEncoder.codec = codec + audioEncoder.setCodec(codec: codec) } public func setVideoCodecImp(codec: VideoCodec) {} diff --git a/RootEncoder/Sources/RootEncoder/library/rtmp/DisplayRtmp.swift b/RootEncoder/Sources/RootEncoder/library/rtmp/DisplayRtmp.swift index 5c368ca..568030c 100644 --- a/RootEncoder/Sources/RootEncoder/library/rtmp/DisplayRtmp.swift +++ b/RootEncoder/Sources/RootEncoder/library/rtmp/DisplayRtmp.swift @@ -18,11 +18,7 @@ public class DisplayRtmp: DisplayBase { } public func setAuth(user: String, password: String) { - //client.setAuth(user: user, password: password) - } - - public func setCodec(codec: CodecUtil) { - videoEncoder.setCodec(codec: codec) + client.setAuth(user: user, password: password) } public func reTry(delay: Int, reason: String, backUrl: String? = nil) -> Bool { diff --git a/RootEncoder/Sources/RootEncoder/library/rtsp/DisplayRtsp.swift b/RootEncoder/Sources/RootEncoder/library/rtsp/DisplayRtsp.swift index 97993ba..2b782b5 100644 --- a/RootEncoder/Sources/RootEncoder/library/rtsp/DisplayRtsp.swift +++ b/RootEncoder/Sources/RootEncoder/library/rtsp/DisplayRtsp.swift @@ -22,10 +22,6 @@ public class DisplayRtsp: DisplayBase { client.setAuth(user: user, password: password) } - public func setCodec(codec: CodecUtil) { - videoEncoder.setCodec(codec: codec) - } - public func reTry(delay: Int, reason: String, backUrl: String? = nil) -> Bool { let result = client.shouldRetry(reason: reason) if (result) { diff --git a/RootEncoder/Sources/RootEncoder/library/rtsp/RtspCamera.swift b/RootEncoder/Sources/RootEncoder/library/rtsp/RtspCamera.swift index 25832df..2302416 100644 --- a/RootEncoder/Sources/RootEncoder/library/rtsp/RtspCamera.swift +++ b/RootEncoder/Sources/RootEncoder/library/rtsp/RtspCamera.swift @@ -25,10 +25,6 @@ public class RtspCamera: CameraBase { client.setAuth(user: user, password: password) } - public func setCodec(codec: CodecUtil) { - videoEncoder.setCodec(codec: codec) - } - public func reTry(delay: Int, reason: String, backUrl: String? = nil) -> Bool { let result = client.shouldRetry(reason: reason) if (result) { diff --git a/RootEncoder/Sources/RootEncoder/library/utils/RecordController.swift b/RootEncoder/Sources/RootEncoder/library/utils/RecordController.swift index 093271d..719e4fe 100644 --- a/RootEncoder/Sources/RootEncoder/library/utils/RecordController.swift +++ b/RootEncoder/Sources/RootEncoder/library/utils/RecordController.swift @@ -146,8 +146,6 @@ public class RecordController { AVVideoCodecType.h264 case VideoCodec.H265: AVVideoCodecType.hevc - default: - AVVideoCodecType.h264 //TODO throw error } } @@ -157,8 +155,6 @@ public class RecordController { kAudioFormatMPEG4AAC case AudioCodec.G711: kAudioFormatALaw - default: - kAudioFormatLinearPCM // TODO throw error } } diff --git a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpClient.swift b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpClient.swift index 05b52a1..e8b50db 100644 --- a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpClient.swift +++ b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpClient.swift @@ -67,7 +67,7 @@ public class RtmpClient { } if (!self.isStreaming || isRetry) { self.isStreaming = true - thread = Task { + thread = Task(priority: .high) { guard let url = url else { self.connectChecker.onConnectionFailed(reason: "Endpoint malformed, should be: rtmp://ip:port/appname/streamname") return @@ -292,7 +292,7 @@ public class RtmpClient { connectChecker.onAuthError() } default: - connectChecker.onConnectionFailed(reason: description) + connectChecker.onConnectionFailed(reason: description) } case "onStatus": let code = ((command.data[3] as! AmfObject).getProperty(name: "code") as! AmfString).value diff --git a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpCommandManager.swift b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpCommandManager.swift index 3cb2817..0a08df6 100644 --- a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpCommandManager.swift +++ b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpCommandManager.swift @@ -160,8 +160,6 @@ public class RtmpCommandManager { VideoFormat.AVC.rawValue case .H265: VideoFormat.HEVC.rawValue - @unknown default: - VideoFormat.AVC.rawValue } print("codec: \(codecValue)") amfEcmaArray.setProperty(name: "width", data: Double(width)) @@ -176,8 +174,6 @@ public class RtmpCommandManager { AudioFormat.AAC.rawValue case .G711: AudioFormat.G711_A.rawValue - @unknown default: - AudioFormat.AAC.rawValue } amfEcmaArray.setProperty(name: "audiocodecid", data: Double(codecValue)) amfEcmaArray.setProperty(name: "audiosamplerate", data: Double(sampleRate)) diff --git a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpSender.swift b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpSender.swift index c93ee2d..a0320f3 100644 --- a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpSender.swift +++ b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpSender.swift @@ -40,10 +40,6 @@ public class RtmpSender { let packet = RtmpH265Packet() packet.setVideoInfo(sps: sps, pps: pps, vps: vps!) videoPacket = packet - @unknown default: - let packet = RtmpH264Packet() - packet.setVideoInfo(sps: sps, pps: pps) - videoPacket = packet } } @@ -56,10 +52,6 @@ public class RtmpSender { case .G711: let packet = RtmpG711Packet() audioPacket = packet - @unknown default: - let packet = RtmpAacPacket() - packet.sendAudioInfo(sampleRate: sampleRate, isStereo: isStereo) - audioPacket = packet } } @@ -94,7 +86,7 @@ public class RtmpSender { public func start() { queue.clear() running = true - thread = Task { + thread = Task(priority: .high) { while (self.running) { let flvPacket = self.queue.dequeue() if let flvPacket = flvPacket { diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspAacPacket.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspAacPacket.swift index f93ee4f..5fa890e 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspAacPacket.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspAacPacket.swift @@ -9,19 +9,20 @@ public class RtspAacPacket: RtspBasePacket { } public override func createAndSendPacket(buffer: Array, ts: UInt64, callback: (RtpFrame) -> Void) { - let length = buffer.count + var buffer = buffer + let naluLength = buffer.count let dts = ts * 1000 let maxPayload = maxPacketSize - RtpConstants.rtpHeaderLength var sum = 0 - while (sum < length) { - let size = if (length - sum < maxPayload) { - length - sum + while (sum < naluLength) { + let length = if (naluLength - sum < maxPayload) { + naluLength - sum } else { maxPayload } - var rtpBuffer = getBuffer(size: size + RtpConstants.rtpHeaderLength + 4) - rtpBuffer[RtpConstants.rtpHeaderLength + 4...rtpBuffer.count - 1] = buffer[0...buffer.count - 1] + var rtpBuffer = getBuffer(size: length + RtpConstants.rtpHeaderLength + 4) + buffer = buffer.get(destiny: &rtpBuffer, index: RtpConstants.rtpHeaderLength + 4, length: length) markPacket(buffer: &rtpBuffer) let rtpTs = updateTimeStamp(buffer: &rtpBuffer, timeStamp: dts) @@ -31,8 +32,8 @@ public class RtspAacPacket: RtspBasePacket { rtpBuffer[RtpConstants.rtpHeaderLength] = 0x00 rtpBuffer[RtpConstants.rtpHeaderLength + 1] = 0x10 // AU-size - rtpBuffer[RtpConstants.rtpHeaderLength + 2] = intToBytes(from: size >> 5)[0] - rtpBuffer[RtpConstants.rtpHeaderLength + 3] = intToBytes(from: size << 3)[0] + rtpBuffer[RtpConstants.rtpHeaderLength + 2] = intToBytes(from: length >> 5)[0] + rtpBuffer[RtpConstants.rtpHeaderLength + 3] = intToBytes(from: length << 3)[0] // AU-Index rtpBuffer[RtpConstants.rtpHeaderLength + 3] &= 0xF8 rtpBuffer[RtpConstants.rtpHeaderLength + 3] |= 0x00 @@ -44,7 +45,7 @@ public class RtspAacPacket: RtspBasePacket { frame.buffer = rtpBuffer frame.channelIdentifier = channelIdentifier - sum += size + sum += length callback(frame) } } diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspG711Packet.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspG711Packet.swift index 08e8e98..25253c9 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspG711Packet.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspG711Packet.swift @@ -18,18 +18,19 @@ public class RtspG711Packet: RtspBasePacket { } public override func createAndSendPacket(buffer: Array, ts: UInt64, callback: (RtpFrame) -> Void) { - let length = buffer.count + var buffer = buffer + let naluLength = buffer.count let maxPayload = maxPacketSize - RtpConstants.rtpHeaderLength var sum = 0 - while (sum < length) { - let size = if (length - sum < maxPayload) { - length - sum + while (sum < naluLength) { + let length = if (naluLength - sum < maxPayload) { + naluLength - sum } else { maxPayload } - var rtpBuffer = getBuffer(size: size + RtpConstants.rtpHeaderLength) - rtpBuffer[RtpConstants.rtpHeaderLength...rtpBuffer.count - 1] = buffer[0...buffer.count - 1] + var rtpBuffer = getBuffer(size: length + RtpConstants.rtpHeaderLength) + buffer = buffer.get(destiny: &rtpBuffer, index: RtpConstants.rtpHeaderLength, length: length) let dts = ts * 1000 markPacket(buffer: &rtpBuffer) let rtpTs = updateTimeStamp(buffer: &rtpBuffer, timeStamp: dts) @@ -41,7 +42,7 @@ public class RtspG711Packet: RtspBasePacket { frame.buffer = rtpBuffer frame.channelIdentifier = channelIdentifier - sum += size + sum += length callback(frame) } } diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH264Packet.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH264Packet.swift index 0a3ab31..297aa96 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH264Packet.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH264Packet.swift @@ -64,11 +64,10 @@ public class RtspH264Packet: RtspBasePacket { var sum = 0 while sum < naluLength { - var length = 0 - if (naluLength - sum > maxPacketSize - RtpConstants.rtpHeaderLength - 2) { - length = maxPacketSize - RtpConstants.rtpHeaderLength - 2 + let length = if (naluLength - sum > maxPacketSize - RtpConstants.rtpHeaderLength - 2) { + maxPacketSize - RtpConstants.rtpHeaderLength - 2 } else { - length = buffer.count + buffer.count } var rtpBuffer = getBuffer(size: length + RtpConstants.rtpHeaderLength + 2) rtpBuffer[RtpConstants.rtpHeaderLength] = header[0] diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH265Packet.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH265Packet.swift index cbdf549..8c6df11 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH265Packet.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH265Packet.swift @@ -58,11 +58,10 @@ public class RtspH265Packet: RtspBasePacket { var sum = 0 while sum < naluLength { - var length = 0 - if (naluLength - sum > maxPacketSize - RtpConstants.rtpHeaderLength - 3) { - length = maxPacketSize - RtpConstants.rtpHeaderLength - 3 + let length = if (naluLength - sum > maxPacketSize - RtpConstants.rtpHeaderLength - 3) { + maxPacketSize - RtpConstants.rtpHeaderLength - 3 } else { - length = buffer.count + buffer.count } var rtpBuffer = getBuffer(size: length + RtpConstants.rtpHeaderLength + 3) rtpBuffer[RtpConstants.rtpHeaderLength] = header[0] diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspClient.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspClient.swift index d50b7f4..d4aac63 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspClient.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspClient.swift @@ -69,7 +69,7 @@ public class RtspClient { } if (!self.streaming || isRetry) { self.streaming = true - thread = Task { + thread = Task(priority: .background) { guard let url = url else { self.connectChecker.onConnectionFailed(reason: "Endpoint malformed, should be: rtsp://ip:port/appname/streamname") return diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspSender.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspSender.swift index 8cef780..a9b7d56 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspSender.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspSender.swift @@ -50,8 +50,6 @@ public class RtspSender { RtspH264Packet(sps: sps, pps: pps) case VideoCodec.H265: RtspH265Packet() - default: - RtspH264Packet(sps: sps, pps: pps) } } @@ -61,10 +59,7 @@ public class RtspSender { RtspAacPacket(sampleRate: sampleRate) case AudioCodec.G711: RtspG711Packet(sampleRate: sampleRate) - default: - RtspAacPacket(sampleRate: sampleRate) } - } public func sendVideo(buffer: Array, ts: UInt64) { @@ -103,7 +98,7 @@ public class RtspSender { tcpReport?.setSSRC(ssrcVideo: ssrcVideo, ssrcAudio: ssrcAudio) queue.clear() running = true - thread = Task { + thread = Task(priority: .background) { let isTcp = self.tcpSocket is RtpSocketTcp while (self.running) { let frame = self.queue.dequeue() diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/RtspCommandManager.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/RtspCommandManager.swift index 060847c..d514846 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/RtspCommandManager.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/RtspCommandManager.swift @@ -41,8 +41,6 @@ public class RtspCommandManager { return sps != nil && pps != nil case VideoCodec.H265: return sps != nil && pps != nil && vps != nil - default: - return false } } @@ -51,8 +49,8 @@ public class RtspCommandManager { } private func addHeader() -> String { - let session = sessionId != nil ? "Session: \(sessionId!)\r\n" : "" - let auth = authorization != nil ? "Authorization: \(authorization!)\r\n" : "" + let session = sessionId?.isEmpty ?? true != true ? "Session: \(sessionId!)\r\n" : "" + let auth = authorization?.isEmpty ?? true != true ? "Authorization: \(authorization!)\r\n" : "" let result = "CSeq: \(cSeq)\r\n\(session)\(auth)" cSeq += 1 return result @@ -78,8 +76,8 @@ public class RtspCommandManager { public func createSetup(track: Int) -> String { let ports = track == RtpConstants.trackVideo ? videoClientPorts : audioClientPorts - let params = mProtocol == .TCP ? "TCP;interleaved=\(2 * track)-\(2 * track + 1)" : "UDP;unicast;client_port=\(ports[0])-\(ports[1])" - let setup = "SETUP rtsp://\(host!):\(port!)\(path!)/trackID=\(track) RTSP/1.0\r\nTransport: RTP/AVP/\(params);mode=record\r\n\(addHeader())\r\n" + let params = mProtocol == .TCP ? "TCP;unicast;interleaved=\(2 * track)-\(2 * track + 1)" : "UDP;unicast;client_port=\(ports[0])-\(ports[1])" + let setup = "SETUP rtsp://\(host!):\(port!)\(path!)/streamid=\(track) RTSP/1.0\r\nTransport: RTP/AVP/\(params);mode=record\r\n\(addHeader())\r\n" print(setup) return setup } @@ -146,8 +144,6 @@ public class RtspCommandManager { body.createAACBody(trackAudio: RtpConstants.trackAudio, sampleRate: sampleRate, isStereo: isStereo) case .G711: body.createG711Body(trackAudio: RtpConstants.trackAudio, sampleRate: sampleRate, isStereo: isStereo) - default: - "" } } @@ -160,8 +156,6 @@ public class RtspCommandManager { body.createH264Body(trackVideo: RtpConstants.trackVideo, sps: spsString, pps: ppsString) case .H265: body.createH265Body(trackVideo: RtpConstants.trackVideo, sps: spsString, pps: ppsString, vps: vpsString!) - default: - "" } } diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/SdpBody.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/SdpBody.swift index 000f9d1..9c948eb 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/SdpBody.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/SdpBody.swift @@ -27,24 +27,24 @@ public class SdpBody { let config = (2 & 0x1F) << 11 | (sampleNum! & 0x0F) << 7 | (channel & 0x0F) << 3 let hexStringConfig = String(format:"%02X", config) let payload = RtpConstants.payloadType + trackAudio - return "m=audio 0 RTP/AVP \(payload)\r\na=rtpmap:\(payload) MPEG4-GENERIC/\(sampleRate)/\(channel)\r\na=fmtp:\(payload) streamtype=5; profile-level-id=15; mode=AAC-hbr; config=\(hexStringConfig); SizeLength=13; IndexLength=3; IndexDeltaLength=3;\r\na=control:trackID=\(trackAudio)\r\n" + return "m=audio 0 RTP/AVP \(payload)\r\na=rtpmap:\(payload) MPEG4-GENERIC/\(sampleRate)/\(channel)\r\na=fmtp:\(payload) streamtype=5; profile-level-id=15; mode=AAC-hbr; config=\(hexStringConfig); SizeLength=13; IndexLength=3; IndexDeltaLength=3;\r\na=control:streamid=\(trackAudio)\r\n" } public func createG711Body(trackAudio: Int, sampleRate: Int, isStereo: Bool) -> String { let channel = isStereo ? 2 : 1 let payload = RtpConstants.payloadTypeG711 return "m=audio 0 RTP/AVP \(payload)\r\n" + - "a=rtpmap:\(payload) PCMA/\(sampleRate)/\(channel)\r\n" + + "a=rtpmap:\(payload) PCMA/8000/1\r\n" + "a=control:streamid=\(trackAudio)\r\n" } public func createH264Body(trackVideo: Int, sps: String, pps: String) -> String { let payload = RtpConstants.payloadType + trackVideo - return "m=video 0 RTP/AVP \(payload)\r\na=rtpmap:\(payload) H264/\(RtpConstants.clockVideoFrequency)\r\na=fmtp:\(payload) packetization-mode=1;sprop-parameter-sets=\(sps),\(pps);\r\na=control:trackID=\(trackVideo)\r\n" + return "m=video 0 RTP/AVP \(payload)\r\na=rtpmap:\(payload) H264/\(RtpConstants.clockVideoFrequency)\r\na=fmtp:\(payload) packetization-mode=1;sprop-parameter-sets=\(sps),\(pps);\r\na=control:streamid=\(trackVideo)\r\n" } public func createH265Body(trackVideo: Int, sps: String, pps: String, vps: String) -> String { let payload = RtpConstants.payloadType + trackVideo - return "m=video 0 RTP/AVP \(payload)\r\na=rtpmap:\(payload) H265/\(RtpConstants.clockVideoFrequency)\r\na=fmtp:\(payload) sprop-sps=\(sps); sprop-pps=\(pps); sprop-vps=\(vps);\r\na=control:trackID=\(trackVideo)\r\n" + return "m=video 0 RTP/AVP \(payload)\r\na=rtpmap:\(payload) H265/\(RtpConstants.clockVideoFrequency)\r\na=fmtp:\(payload) sprop-sps=\(sps); sprop-pps=\(pps); sprop-vps=\(vps);\r\na=control:streamid=\(trackVideo)\r\n" } } diff --git a/app.xcodeproj/project.pbxproj b/app.xcodeproj/project.pbxproj index c2c8479..28d1247 100644 --- a/app.xcodeproj/project.pbxproj +++ b/app.xcodeproj/project.pbxproj @@ -407,7 +407,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.6; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -464,7 +464,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.6; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; diff --git a/appTests/appTests.swift b/appTests/appTests.swift index 2695446..5c49724 100644 --- a/appTests/appTests.swift +++ b/appTests/appTests.swift @@ -31,39 +31,4 @@ class appTests: XCTestCase { // Put the code you want to measure the time of here. } } - - func testStapAH265() { - let expectedStapA: [UInt8] = [128, 224, 0, 1, 0, 169, 138, 199, 7, 91, 205, 21, 96, 1, 0, 7, 0, 0, 0, 1, 2, 3, 4, 0, 7, 0, 0, 0, 1, 10, 11, 12] - let fakeSps: [UInt8] = [0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04] - let fakePps: [UInt8] = [0x00, 0x00, 0x00, 0x01, 0x0A, 0x0B, 0x0C] - let fakeVps: [UInt8] = [0x00, 0x00, 0x00, 0x01, 0x0D, 0x0E, 0x0F] - - let header: [UInt8] = [0x00, 0x00, 0x00, 0x01, 0x05, 0x00] - let fakeH265 = header + [UInt8](repeating: 0x00, count: 2500) - - let packet1Size = RtpConstants.MTU - 28 - RtpConstants.rtpHeaderLength - 3 - let chunk1 = fakeH265[header.count..