From 026a7a47adaedf95912496ddda4204b1426cdd9f Mon Sep 17 00:00:00 2001 From: Huiping Guo Date: Thu, 22 Jun 2023 01:42:17 +0900 Subject: [PATCH 1/5] bring swiftlint and fix lint error --- .../HPRTMPExample/Shared/ContentView.swift | 5 +- .../HPRTMPExample/Shared/RTMPService.swift | 8 +- Package.resolved | 86 ++++ Package.swift | 11 +- Sources/HPRTMP/AMF/AFM3Decode.swift | 83 ++-- Sources/HPRTMP/AMF/AMF0+data.swift | 28 +- Sources/HPRTMP/AMF/AMF0+decode.swift | 57 ++- Sources/HPRTMP/AMF/AMF0Object.swift | 27 +- Sources/HPRTMP/AMF/AMF3+data.swift | 28 +- Sources/HPRTMP/AMF/AMF3Object.swift | 39 +- Sources/HPRTMP/AMF/AMFProtocol.swift | 1 - Sources/HPRTMP/Chunk/Chunk.swift | 24 +- Sources/HPRTMP/Chunk/ChunkDecoder.swift | 163 ++++--- Sources/HPRTMP/Chunk/ChunkEncoder.swift | 19 +- Sources/HPRTMP/Chunk/MessageHeader.swift | 8 +- Sources/HPRTMP/Chunk/RTMPMessageDefine.swift | 82 ++-- Sources/HPRTMP/Help.swift | 6 +- Sources/HPRTMP/Message/CommandMessage.swift | 63 ++- Sources/HPRTMP/Message/ControlMessage.swift | 24 +- Sources/HPRTMP/Message/DataMessage.swift | 21 +- Sources/HPRTMP/Message/RTMPResponse.swift | 76 ++-- .../HPRTMP/Message/UserControlMessage.swift | 11 +- Sources/HPRTMP/PublishConfigure.swift | 4 +- Sources/HPRTMP/RTMPHandshake.swift | 48 +-- Sources/HPRTMP/RTMPPublishSession.swift | 70 ++- Sources/HPRTMP/RTMPSocket.swift | 84 ++-- Sources/HPRTMP/RTMPURLParser.swift | 12 +- Sources/HPRTMP/Util/ArrayExtensions.swift | 4 +- Sources/HPRTMP/Util/DataExtensions.swift | 28 +- .../HPRTMP/Util/NWConnectionExtensions.swift | 12 +- Sources/HPRTMP/WindowControl.swift | 19 +- Tests/HPRTMPTests/AFM0DecodeTests.swift | 25 +- Tests/HPRTMPTests/AMF0EncodeTests.swift | 16 +- Tests/HPRTMPTests/BasicHeaderTests.swift | 18 +- Tests/HPRTMPTests/ChunkDecoderTests.swift | 399 +++++++++--------- Tests/HPRTMPTests/ChunkEncoderTests.swift | 22 +- Tests/HPRTMPTests/ChunkHeaderTests.swift | 2 +- Tests/HPRTMPTests/MessageHeaderTests.swift | 11 +- Tests/HPRTMPTests/RTMPHandshakeTests.swift | 26 +- Tests/HPRTMPTests/RTMPURLParserTests.swift | 18 +- Tests/HPRTMPTests/WindowControlTests.swift | 17 +- Tests/HPRTMPTests/util/DataTests.swift | 44 +- 42 files changed, 884 insertions(+), 865 deletions(-) create mode 100644 Package.resolved diff --git a/Example/HPRTMPExample/Shared/ContentView.swift b/Example/HPRTMPExample/Shared/ContentView.swift index 45dd359..1cd1065 100644 --- a/Example/HPRTMPExample/Shared/ContentView.swift +++ b/Example/HPRTMPExample/Shared/ContentView.swift @@ -8,10 +8,9 @@ import SwiftUI struct ContentView: View { - + let rtmpService = RTMPService() - - + var body: some View { Text("Hello, world!") .padding().onAppear(perform: { diff --git a/Example/HPRTMPExample/Shared/RTMPService.swift b/Example/HPRTMPExample/Shared/RTMPService.swift index 52f7057..2f149b6 100644 --- a/Example/HPRTMPExample/Shared/RTMPService.swift +++ b/Example/HPRTMPExample/Shared/RTMPService.swift @@ -9,16 +9,16 @@ import Foundation import HPRTMP class RTMPService { - + private var session = RTMPPublishSession() - + init() { // let url = URL(string: "rtmp://192.168.11.23/live")! // let streamKey = "hello" // let port = 1935 // socket.connect(streamURL: url, streamKey: streamKey, port: port) } - + func run() { let publishConfig = PublishConfigure( width: 640, @@ -30,7 +30,7 @@ class RTMPService { framerate: 30, videoframerate: 30 ) - + session.publish(url: "rtmp://192.168.11.48/live/haha", configure: publishConfig) } } diff --git a/Package.resolved b/Package.resolved new file mode 100644 index 0000000..de87034 --- /dev/null +++ b/Package.resolved @@ -0,0 +1,86 @@ +{ + "pins" : [ + { + "identity" : "collectionconcurrencykit", + "kind" : "remoteSourceControl", + "location" : "https://github.com/JohnSundell/CollectionConcurrencyKit.git", + "state" : { + "revision" : "b4f23e24b5a1bff301efc5e70871083ca029ff95", + "version" : "0.2.0" + } + }, + { + "identity" : "cryptoswift", + "kind" : "remoteSourceControl", + "location" : "https://github.com/krzyzanowskim/CryptoSwift.git", + "state" : { + "revision" : "32f641cf24fc7abc1c591a2025e9f2f572648b0f", + "version" : "1.7.2" + } + }, + { + "identity" : "sourcekitten", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jpsim/SourceKitten.git", + "state" : { + "revision" : "b6dc09ee51dfb0c66e042d2328c017483a1a5d56", + "version" : "0.34.1" + } + }, + { + "identity" : "swift-argument-parser", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-argument-parser.git", + "state" : { + "revision" : "fee6933f37fde9a5e12a1e4aeaa93fe60116ff2a", + "version" : "1.2.2" + } + }, + { + "identity" : "swift-syntax", + "kind" : "remoteSourceControl", + "location" : "https://github.com/apple/swift-syntax.git", + "state" : { + "revision" : "27cd6190ce0628847a3f8050794d6e627ad79c08", + "version" : "509.0.0-swift-DEVELOPMENT-SNAPSHOT-2023-05-02-a" + } + }, + { + "identity" : "swiftlint", + "kind" : "remoteSourceControl", + "location" : "https://github.com/realm/SwiftLint", + "state" : { + "revision" : "34f5ffa7f706ed2dfe11bd300e5197e8878e3856", + "version" : "0.52.2" + } + }, + { + "identity" : "swiftytexttable", + "kind" : "remoteSourceControl", + "location" : "https://github.com/scottrhoyt/SwiftyTextTable.git", + "state" : { + "revision" : "c6df6cf533d120716bff38f8ff9885e1ce2a4ac3", + "version" : "0.9.0" + } + }, + { + "identity" : "swxmlhash", + "kind" : "remoteSourceControl", + "location" : "https://github.com/drmohundro/SWXMLHash.git", + "state" : { + "revision" : "a853604c9e9a83ad9954c7e3d2a565273982471f", + "version" : "7.0.2" + } + }, + { + "identity" : "yams", + "kind" : "remoteSourceControl", + "location" : "https://github.com/jpsim/Yams.git", + "state" : { + "revision" : "f47ba4838c30dbd59998a4e4c87ab620ff959e8a", + "version" : "5.0.5" + } + } + ], + "version" : 2 +} diff --git a/Package.swift b/Package.swift index 422fc15..f3a4001 100644 --- a/Package.swift +++ b/Package.swift @@ -5,25 +5,26 @@ import PackageDescription let package = Package( name: "HPRTMP", - platforms: [.iOS(.v14),.macOS(.v11)], + platforms: [.iOS(.v14), .macOS(.v11)], products: [ .library( name: "HPRTMP", targets: ["HPRTMP"] - ), + ) ], dependencies: [ // Dependencies declare other packages that this package depends on. - // .package(url: /* package url */, from: "1.0.0"), + .package(url: "https://github.com/realm/SwiftLint", from: "0.52.2") ], targets: [ // Targets are the basic building blocks of a package. A target can define a module or a test suite. // Targets can depend on other targets in this package, and on products in packages this package depends on. .target( name: "HPRTMP", - dependencies: []), + dependencies: [], + plugins: [.plugin(name: "SwiftLintPlugin", package: "SwiftLint")]), .testTarget( name: "HPRTMPTests", - dependencies: ["HPRTMP"]), + dependencies: ["HPRTMP"]) ] ) diff --git a/Sources/HPRTMP/AMF/AFM3Decode.swift b/Sources/HPRTMP/AMF/AFM3Decode.swift index 10fa87f..475dca7 100644 --- a/Sources/HPRTMP/AMF/AFM3Decode.swift +++ b/Sources/HPRTMP/AMF/AFM3Decode.swift @@ -1,7 +1,7 @@ import Foundation import os -//Note that 3 separate reference tables are used for Strings, Complex Objects and Object Traits respectively. +// Note that 3 separate reference tables are used for Strings, Complex Objects and Object Traits respectively. public class AMF3ReferenceTable { private(set) lazy var string = { return [String]() @@ -15,7 +15,7 @@ extension AMF3ReferenceTable { func append(_ value: String) { self.string.append(value) } - + func string(index: Int) -> String { return self.string[index] } @@ -26,21 +26,20 @@ extension AMF3ReferenceTable { self.objects.append([Any]()) return self.objects.count-1 } - + func replace(_ value: Any, idx: Int) { self.objects[idx] = value } - + func append(_ value: Any) { self.objects.append(value) } - + func object(_ index: Int) -> T? { return self.objects[index] as? T } } - public enum AMF3DecodeError: Error { case rangeError case parseError @@ -50,9 +49,9 @@ public enum AMF3DecodeError: Error { extension Data { public func decodeAMF3() -> [Any]? { - var b = self + var bytes = self var reference = AMF3ReferenceTable() - return b.decode(reference: &reference) + return bytes.decode(reference: &reference) } } @@ -60,7 +59,6 @@ private let nullString = "Null" private let logger = Logger(subsystem: "HPRTMP", category: "AMF3Decoder") - private extension Data { mutating func decode(reference: inout AMF3ReferenceTable) -> [Any]? { var decodeData = [Any]() @@ -76,14 +74,14 @@ private extension Data { logger.error("Decode Error \(error.localizedDescription)") return nil } - + } return decodeData } - + mutating func parseValue(type: RTMPAMF3Type, reference: inout AMF3ReferenceTable) throws -> Any { switch type { - case .undefined ,.null: + case .undefined, .null: return nullString case .boolTrue: return true @@ -124,7 +122,7 @@ private extension Data { } return 0 } - + mutating func decodeDouble() throws -> Double { let range = 0..<8 guard let value = self[safe: range] else { @@ -133,9 +131,9 @@ private extension Data { self.removeSubrange(range) return Data(value.reversed()).double } - + mutating func decodeString(_ reference: inout AMF3ReferenceTable) throws -> String { - + let (length, type) = try self.decodeLengthWithType() switch type { case .value: @@ -153,10 +151,10 @@ private extension Data { return reference.string(index: length) } } - + mutating func decodeDate(_ reference: inout AMF3ReferenceTable) throws -> Date { let (length, type) = try self.decodeLengthWithType() - + switch type { case .reference: guard let date: Date = reference.object(length) else { @@ -174,7 +172,7 @@ private extension Data { return value } } - + mutating func decodeArray(_ reference: inout AMF3ReferenceTable) throws -> [Any] { let (length, type) = try self.decodeLengthWithType() switch type { @@ -189,7 +187,7 @@ private extension Data { return value } } - + private mutating func decodeArray(length: Int, reference: inout AMF3ReferenceTable) throws -> [Any] { self.remove(at: 0) var decodeData = [Any]() @@ -207,7 +205,7 @@ private extension Data { } return decodeData } - + mutating func decodeXML(_ reference: inout AMF3ReferenceTable) throws -> String { let (length, type) = try self.decodeLengthWithType() switch type { @@ -227,7 +225,7 @@ private extension Data { return xml } } - + mutating func decodeObjectInfo(_ reference: inout AMF3ReferenceTable) throws -> [String: Any] { var map = [String: Any]() if let className = try? self.decodeString(&reference), className.count > 0 { @@ -236,7 +234,7 @@ private extension Data { var key = "" while let first = self.first { var type: RTMPAMF3Type? = RTMPAMF3Type(rawValue: first) - + if key.isEmpty { type = .string let value = try self.decodeString(&reference) @@ -244,12 +242,12 @@ private extension Data { if key.count == 0 { break } continue } - guard let t = type else { + guard let type = type else { throw AMF3DecodeError.rangeError } - + self.remove(at: 0) - switch t { + switch type { case .string: let value = try self.decodeString(&reference) map[key] = value @@ -261,7 +259,7 @@ private extension Data { reference.replace(value, idx: idx) key = "" default: - let value = try self.parseValue(type: t, reference: &reference) + let value = try self.parseValue(type: type, reference: &reference) map[key] = value key = "" } @@ -284,7 +282,7 @@ private extension Data { } else if value & 0x0f == 0x07, let className = try? self.decodeString(&reference), className.count > 0 { map["className"] = className } else if value & 0x0f == 0x0b { - + let idx = reference.createReserved() let info = try self.decodeObjectInfo(&reference) reference.replace(info, idx: idx) @@ -292,7 +290,7 @@ private extension Data { } return map } - + mutating func decodeByteArray(_ reference: inout AMF3ReferenceTable) throws -> Data { let (length, type) = try self.decodeLengthWithType() switch type { @@ -311,11 +309,11 @@ private extension Data { return byte } } - + mutating func decodeVectorNumber(_ reference: inout AMF3ReferenceTable) throws -> [T] { var decodeData = [T]() let (length, type) = try self.decodeLengthWithType() - + guard let first = self.first, let _ = AMF3EncodeType.Vector(rawValue: first) else { throw AMF3DecodeError.rangeError @@ -331,12 +329,12 @@ private extension Data { guard let rangeBytes = self[safe: range] else { throw AMF3DecodeError.rangeError } - if T.self == UInt32.self { - decodeData.append(Data(rangeBytes.reversed()).uint32 as! T) - } else if T.self == Int32.self { - decodeData.append(Data(rangeBytes.reversed()).int32 as! T) - } else if T.self == Double.self { - decodeData.append(Data(rangeBytes.reversed()).double as! T) + if let data = Data(rangeBytes.reversed()).uint32 as? T, T.self == UInt32.self { + decodeData.append(data) + } else if let data = Data(rangeBytes.reversed()).int32 as? T, T.self == Int32.self { + decodeData.append(data) + } else if let data = Data(rangeBytes.reversed()).double as? T, T.self == Double.self { + decodeData.append(data) } self.removeSubrange(range) } @@ -349,7 +347,7 @@ private extension Data { reference.append(decodeData) return decodeData } - + mutating func decodeVectorObject(_ reference: inout AMF3ReferenceTable) throws -> [Any] { let (count, objType) = try self.decodeLengthWithType() self.remove(at: 0) @@ -369,20 +367,19 @@ private extension Data { } return [Any]() } - - + mutating func decodeLengthWithType() throws -> (length: Int, type: AMF3EncodeType.U29) { let value = self.convertLength() - + let length = value >> 1 let u29Raw = UInt8(value & 0x01) - + guard let type = AMF3EncodeType.U29(rawValue: u29Raw) else { throw AMF3DecodeError.rangeError } return (length, type) } - + mutating func convertLength() -> Int { var lastIdx = 0 var numberArr = [UInt8]() @@ -401,7 +398,7 @@ private extension Data { } return rc + Int(current.element) << shift } - + return value } } diff --git a/Sources/HPRTMP/AMF/AMF0+data.swift b/Sources/HPRTMP/AMF/AMF0+data.swift index 40b8191..268a4fc 100644 --- a/Sources/HPRTMP/AMF/AMF0+data.swift +++ b/Sources/HPRTMP/AMF/AMF0+data.swift @@ -106,31 +106,30 @@ extension String: AMF0Encode { let isLongString = self.count > UInt16.max return isLongString ? amf0LongStringValue : amf0StringValue } - - + private var amf0StringValue: Data { var data = Data() - + data.write(RTMPAMF0Type.string.rawValue) data.append(UInt16(Data(self.utf8).count).bigEndian.data) data.append(Data(self.utf8)) - + return data } - + private var amf0LongStringValue: Data { var data = Data() - + data.write(RTMPAMF0Type.longString.rawValue) data.append(UInt32(Data(self.utf8).count).bigEndian.data) data.append(Data(self.utf8)) - + return data } - + var amf0KeyEncode: Data { let isLong = UInt32(UInt16.max) < UInt32(self.count) - + var data = Data() let convert = Data(self.utf8) if isLong { @@ -150,12 +149,11 @@ extension Date: AMF0Encode { var data = Data() data.write(RTMPAMF0Type.date.rawValue) data.append(Data(mileSecondSince1970.bitPattern.data)) - data.write([UInt8]([0x0,0x0])) + data.write([UInt8]([0x0, 0x0])) return data } } - // Object - 0x03 (Set of key/value pairs) // Object End - 0x09 (preceded by an empty 16-bit string length) extension Dictionary where Key == String { @@ -163,10 +161,10 @@ extension Dictionary where Key == String { var data = Data() data.write(RTMPAMF0Type.object.rawValue) data.append(keyValueEncode()) - data.write([0x00,0x00,RTMPAMF0Type.objectEnd.rawValue]) + data.write([0x00, 0x00, RTMPAMF0Type.objectEnd.rawValue]) return data } - + // ECMA Array var amf0EcmaArray: Data { var data = Data() @@ -175,7 +173,7 @@ extension Dictionary where Key == String { data.append(self.keyValueEncode()) return data } - + fileprivate func keyValueEncode() -> Data { var data = Data() self.forEach { (key, value) in @@ -221,5 +219,3 @@ extension Array { return group } } - - diff --git a/Sources/HPRTMP/AMF/AMF0+decode.swift b/Sources/HPRTMP/AMF/AMF0+decode.swift index f4cbede..871ee89 100644 --- a/Sources/HPRTMP/AMF/AMF0+decode.swift +++ b/Sources/HPRTMP/AMF/AMF0+decode.swift @@ -13,7 +13,6 @@ enum AMF0DecodeError: Error { case parseError } - extension Data { func subdata(safe range: Range) -> Data? { if range.lowerBound < 0 || range.upperBound > count { @@ -30,43 +29,43 @@ extension Data { return ptr.load(as: Int.self) } } - + var uint8: UInt8 { return withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in return ptr.load(as: UInt8.self) } } - + var uint16: UInt16 { return withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in return ptr.load(as: UInt16.self) } } - + var int32: Int32 { return withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in return ptr.load(as: Int32.self) } } - + var uint32: UInt32 { return withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in return ptr.load(as: UInt32.self) } } - + var float: Float { return withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in return ptr.load(as: Float.self) } } - + var double: Double { return withUnsafeBytes { (ptr: UnsafeRawBufferPointer) in return ptr.load(as: Double.self) } } - + var string: String { return String(data: self, encoding: .utf8) ?? "" } @@ -89,7 +88,7 @@ class AMF0Decoder { guard let realType = RTMPAMF0Type(rawValue: first) else { return decodeData } - + self.data.removeSubrange(0..<1) do { try decodeData.append(self.parseValue(type: realType)) @@ -100,8 +99,7 @@ class AMF0Decoder { } return decodeData } - - + func parseValue(type: RTMPAMF0Type) throws -> Any { switch type { case .number: @@ -132,7 +130,7 @@ class AMF0Decoder { return AMF0DecodeError.parseError } } - + func decodeNumber() throws -> Double { let range = 0..<8 guard let result = data.subdata(safe: range) else { @@ -141,7 +139,7 @@ class AMF0Decoder { data.removeSubrange(range) return Data(result.reversed()).double } - + func decodeBool() throws -> Bool { guard let result = data.first else { throw AMF0DecodeError.rangeError @@ -160,7 +158,7 @@ class AMF0Decoder { data.removeSubrange(0.. String { let range = 0..<4 guard let rangeBytes = data.subdata(safe: range) else { @@ -172,7 +170,7 @@ class AMF0Decoder { data.removeSubrange(0.. String { let range = 0..<4 guard let rangeBytes = data.subdata(safe: range) else { @@ -180,7 +178,7 @@ class AMF0Decoder { } let length = Data(rangeBytes.reversed()).uint32 data.removeSubrange(range) - + guard let stringBytes = data.subdata(safe: 0.. Date { guard let value = data.subdata(safe: 0..<8) else { throw AMF0DecodeError.rangeError @@ -198,7 +196,7 @@ class AMF0Decoder { data.removeSubrange(0..<10) return result } - + func decodeObj() throws -> [String: Any] { var map = [String: Any]() var key = "" @@ -210,13 +208,13 @@ class AMF0Decoder { key = value continue } - - guard let t = type else { + + guard let type = type else { throw AMF0DecodeError.rangeError } data.removeSubrange(0..<1) - - switch t { + + switch type { case .string: let value = try decodeString() map[key] = value @@ -226,37 +224,37 @@ class AMF0Decoder { map[key] = value key = "" default: - - let value = try self.parseValue(type: t) + + let value = try self.parseValue(type: type) map[key] = value key = "" } } data.removeSubrange(0..<1) - + return map } - + func decodeTypeObject() throws -> [String: Any] { let range = 0..<4 data.removeSubrange(range) return try self.decodeObj() } - + func deocdeArray() throws -> [String: Any] { let entryPoint = 0..<4 data.removeSubrange(entryPoint) let value = try self.decodeObj() return value } - + func decodeStrictArray() throws -> [Any] { let entryPoint = 0..<4 guard let rangeBytes = data.subdata(safe: entryPoint) else { throw AMF0DecodeError.rangeError } var decodeData = [Any]() - + var count = Int(Data(rangeBytes.reversed()).uint32) data.removeSubrange(entryPoint) while let first = data.first, count != 0 { @@ -270,4 +268,3 @@ class AMF0Decoder { return decodeData } } - diff --git a/Sources/HPRTMP/AMF/AMF0Object.swift b/Sources/HPRTMP/AMF/AMF0Object.swift index 1168ecb..b9f8758 100644 --- a/Sources/HPRTMP/AMF/AMF0Object.swift +++ b/Sources/HPRTMP/AMF/AMF0Object.swift @@ -7,55 +7,54 @@ import Foundation - protocol AMF0Encode { var amf0Value: Data { get } } struct AMF0Object: AMF0Protocol { var data = Data() - - mutating func appendEcma(_ value: [String : Any?]) { + + mutating func appendEcma(_ value: [String: Any?]) { data.append(value.amf0EcmaArray) } - + mutating func append(_ value: Double) { data.append(value.amf0Value) } - + mutating func append(_ value: String) { data.append(value.amf0Value) } - + mutating func appned(_ value: Bool) { data.append(value.amf0Value) } - - mutating func append(_ value: [String : Any?]?) { + + mutating func append(_ value: [String: Any?]?) { guard let value else { return } data.append(value.amf0Encode) } - + mutating func append(_ value: Date) { data.append(value.amf0Value) } - + mutating func appendNil() { data.write(RTMPAMF0Type.null.rawValue) } - + mutating func append(_ value: [Any]) { data.append(value.amf0Value) } - + mutating func appendXML(_ value: String) { // todo } - + mutating func decode() -> [Any]? { data.decodeAMF0() } - + static func decode(_ data: Data) -> [Any]? { data.decodeAMF0() } diff --git a/Sources/HPRTMP/AMF/AMF3+data.swift b/Sources/HPRTMP/AMF/AMF3+data.swift index f8ef850..459d7c1 100644 --- a/Sources/HPRTMP/AMF/AMF3+data.swift +++ b/Sources/HPRTMP/AMF/AMF3+data.swift @@ -27,14 +27,12 @@ protocol AMF3VectorUnitEncode { var vectorData: Data { get } } - extension Bool: AMF3Encode { var amf3Encode: Data { return Data([self == false ? 0x02 : 0x03]) } } - extension Int: AMF3Encode { var amf3Encode: Data { var data = Data() @@ -65,7 +63,7 @@ extension Int: AMF3Encode { return Double(self).amf3Encode } } - + var vectorData: Data { return self.bigEndian.data } @@ -87,7 +85,7 @@ extension String: AMF3Encode, AMF3KeyEncode { data.append(Data(self.utf8)) return data } - + var amf3Encode: Data { var data = Data() data.write(RTMPAMF3Type.string.rawValue) @@ -110,18 +108,18 @@ extension Date: AMF3Encode { extension Dictionary: AMF3Encode where Key: AMF3KeyEncode, Value: AMF3Encode { var amf3Encode: Data { var data = Data([0x03]) // Object marker - + // Write object traits data.append(Data([0x0b])) // Trait type (object) data.append(Data([0x01])) // Trait count (1) data.append(self.keys.count.amf3Encode) // Write number of keys data.append(Data([0x01])) // Trait property name (always an empty string) - + for key in self.keys { data.append(key.amf3KeyEncode) // Write the key as a string data.append(self[key]!.amf3Encode) // Write the value } - + return data } } @@ -129,7 +127,7 @@ extension Dictionary: AMF3Encode where Key: AMF3KeyEncode, Value: AMF3Encode { extension Dictionary where Key == String { var amf3Encode: Data { var data = Data() - data.write([RTMPAMF3Type.object.rawValue,0x0b,RTMPAMF3Type.null.rawValue]) + data.write([RTMPAMF3Type.object.rawValue, 0x0b, RTMPAMF3Type.null.rawValue]) self.forEach { (key, value) in let keyEncode = key.amf3KeyEncode data.append(keyEncode) @@ -150,7 +148,7 @@ extension Array: AMF3Encode { var data = Data() data.write(RTMPAMF3Type.array.rawValue) data.append(encodeLength) - + self.forEach { if let valueEncode = ($0 as? AMF3Encode)?.amf3Encode { data.append(valueEncode) @@ -172,17 +170,17 @@ extension Array: AMF3VectorEncode { } else { type = .vectorObject } - - guard let t = type else { + + guard let type = type else { return Data() } - + let encodeLength = (self.count << 1 | 0x01).amf3LengthConvert var data = Data() - data.write(t.rawValue) + data.write(type.rawValue) data.append(encodeLength) data.write(AMF3EncodeType.Vector.dynamic.rawValue) - + if type == .vectorObject { let objectType = "*".amf3Encode let encodeLength = (objectType.count << 1 | 0x01).amf3LengthConvert @@ -200,7 +198,7 @@ extension Array: AMF3VectorEncode { } } } - + return data } } diff --git a/Sources/HPRTMP/AMF/AMF3Object.swift b/Sources/HPRTMP/AMF/AMF3Object.swift index a191e7d..3e3370d 100644 --- a/Sources/HPRTMP/AMF/AMF3Object.swift +++ b/Sources/HPRTMP/AMF/AMF3Object.swift @@ -75,72 +75,69 @@ enum RTMPAMF3Type: UInt8 { struct AMF3Object: AMF3Protocol { var data = Data() - + mutating func appendUndefined() { data.append(RTMPAMF3Type.undefined.rawValue) } - + mutating func appendNil() { data.append(RTMPAMF3Type.null.rawValue) } - + mutating func appned(_ value: Bool) { data.append(value.amf3Encode) } - + mutating func append(_ value: Int) { data.append(value.amf3Encode) } - + mutating func append(_ value: Double) { data.append(value.amf3Encode) } - + mutating func append(_ value: String) { data.append(value.amf3Encode) } - + mutating func appendXML(_ value: String) { data.append(value.amf3Encode) } - + mutating func append(_ value: Date) { data.append(value.amf3Encode) } - + mutating func append(_ value: [Any]) { data.append(value.amf3Encode) } - + mutating func append(_ value: [String: Any?]?) { - if let v = value { - data.append(v.amf3Encode) - } + guard let value = value else { return } + data.append(value.amf3Encode) } - + mutating func appendVector(_ value: [Int32]) { data.append(value.amf3VectorEncode) } - + mutating func appendVector(_ value: [UInt32]) { data.append(value.amf3VectorEncode) } - + mutating func appendVector(_ value: [Double]) { data.append(value.amf3VectorEncode) } - + mutating func appendByteArray(_ value: Data) { data.append(value.byteEncode) } - + public func decode() -> [Any]? { data.decodeAMF3() } - + public static func decode(_ data: Data) -> [Any]? { data.decodeAMF3() } } - - diff --git a/Sources/HPRTMP/AMF/AMFProtocol.swift b/Sources/HPRTMP/AMF/AMFProtocol.swift index e3450bf..5aea59c 100644 --- a/Sources/HPRTMP/AMF/AMFProtocol.swift +++ b/Sources/HPRTMP/AMF/AMFProtocol.swift @@ -21,7 +21,6 @@ protocol AMFProtocol { static func decode(_ data: Data) -> [Any]? } - protocol AMF0Protocol: AMFProtocol { mutating func appendEcma(_ value: [String: Any?]) } diff --git a/Sources/HPRTMP/Chunk/Chunk.swift b/Sources/HPRTMP/Chunk/Chunk.swift index 6fc378c..e83c168 100644 --- a/Sources/HPRTMP/Chunk/Chunk.swift +++ b/Sources/HPRTMP/Chunk/Chunk.swift @@ -7,11 +7,11 @@ protocol Encodable { struct Chunk: Encodable, Equatable { let chunkHeader: ChunkHeader var chunkData: Data - + func encode() -> Data { return chunkHeader.encode() + chunkData } - + static func == (lhs: Chunk, rhs: Chunk) -> Bool { return lhs.chunkHeader == rhs.chunkHeader && lhs.chunkData == rhs.chunkData } @@ -20,16 +20,16 @@ struct Chunk: Encodable, Equatable { struct ChunkHeader: Encodable { let basicHeader: BasicHeader let messageHeader: MessageHeader - + init(basicHeader: BasicHeader, messageHeader: MessageHeader) { self.basicHeader = basicHeader self.messageHeader = messageHeader } - + // Initialize the ChunkHeader struct with a stream ID, message header, and chunk payload - init(streamId: Int,messageHeader: MessageHeader) { + init(streamId: Int, messageHeader: MessageHeader) { self.messageHeader = messageHeader - + // Determine the basic header type based on the type of the message header let basicHeaderType: MessageHeaderType switch messageHeader { @@ -45,11 +45,11 @@ struct ChunkHeader: Encodable { // If the message header is not one of the four defined types, set the basic header type to type0 basicHeaderType = .type0 } - + // Initialize the basic header with the stream ID and type self.basicHeader = BasicHeader(streamId: UInt16(streamId), type: basicHeaderType) } - + // Encode the chunk header into a data object func encode() -> Data { // Concatenate the encoded basic header, message header, and chunk payload @@ -73,24 +73,24 @@ enum MessageHeaderType: Int { struct BasicHeader: Equatable { let streamId: UInt16 let type: MessageHeaderType - + func encode() -> Data { // Calculates the format field (fmt) by left shifting the MessageHeaderType's raw value 6 bits to the left let fmt = UInt8(type.rawValue << 6) - + // Checks if streamId is less than or equal to 63, in which case the Basic Header will only consist of one byte if streamId <= 63 { // Returns a single-byte Data object that contains the value of `fmt` ORed with the value of streamId casted to UInt8 return Data([UInt8(fmt | UInt8(streamId))]) } - + // Checks if streamId is less than or equal to 319, in which case the Basic Header will consist of two bytes if streamId <= 319 { // Returns a two-byte Data object where the first byte is the value of `fmt` ORed with 0b00000000 (0 in binary), // and the second byte is the value of streamId minus 64 casted to UInt8 return Data([UInt8(fmt | 0b00000000), UInt8(streamId - 64)]) } - + // If streamId is greater than 319, the Basic Header will consist of three bytes. // In this case, the first byte is the value of `fmt` ORed with 0b00000001 (1 in binary), // and the next two bytes are the value of `streamId` minus 64 in big endian byte order. diff --git a/Sources/HPRTMP/Chunk/ChunkDecoder.swift b/Sources/HPRTMP/Chunk/ChunkDecoder.swift index cba2081..cf7711c 100644 --- a/Sources/HPRTMP/Chunk/ChunkDecoder.swift +++ b/Sources/HPRTMP/Chunk/ChunkDecoder.swift @@ -3,33 +3,33 @@ import os actor MessageDecoder { private var data = Data() - + private let chunkDecoder = ChunkDecoder() - + private var maxChunkSize: Int = Int(128) - + private(set) var isDecoding = false - + private let logger = Logger(subsystem: "HPRTMP", category: "MessageDecoder") - + func setMaxChunkSize(maxChunkSize: Int) async { self.maxChunkSize = maxChunkSize await chunkDecoder.setMaxChunkSize(maxChunkSize: maxChunkSize) } - + func append(_ newData: Data) { self.data.append(newData) } - + var remainDataCount: Int { data.count } - + func decode() async -> RTMPMessage? { guard !isDecoding else { return nil } logger.debug("decode message start") isDecoding = true - let (message,size) = await decodeMessage(data: data) + let (message, size) = await decodeMessage(data: data) guard let message else { return nil } data.removeFirst(size) isDecoding = false @@ -37,11 +37,11 @@ actor MessageDecoder { logger.debug("MessageDecoder remain data count: \(self.data.count)") return message } - + func reset() { data = Data() } - + func createMessage(chunkStreamId: UInt16, msgStreamId: Int, messageType: MessageType, timestamp: UInt32, chunkPayload: Data) -> RTMPMessage? { switch messageType { case .chunkSize: @@ -57,19 +57,19 @@ actor MessageDecoder { return PeerBandwidthMessage(windowSize: peer, limit: .dynamic) case .command(type: let type): let data = type == .amf0 ? chunkPayload.decodeAMF0() : chunkPayload.decodeAMF3() - + // first is command name guard let commandName = data?.first as? String else { return nil } - + // second is Transaction ID, number let transactionId = data?[safe: 1] as? Double - + // third is command object let objcet = data?[safe: 2] as? [String: Any] - + // fourth is info, maybe object([String: Any?]) or Number(connect messsage) let info = data?[safe: 3] - + return CommandMessage(encodeType: type, commandName: commandName, msgStreamId: msgStreamId, transactionId: Int(transactionId ?? 0), commandObject: objcet, info: info) case .data(type: let type): return DataMessage(encodeType: type, msgStreamId: msgStreamId) @@ -98,26 +98,26 @@ actor MessageDecoder { return nil } } - - func decodeMessage(data: Data) async -> (RTMPMessage?,Int) { + + func decodeMessage(data: Data) async -> (RTMPMessage?, Int) { let (firstChunk, chunkSize) = await chunkDecoder.decodeChunk(data: data) - guard let firstChunk = firstChunk else { return (nil,0) } - + guard let firstChunk = firstChunk else { return (nil, 0) } + if let messageHeaderType0 = firstChunk.chunkHeader.messageHeader as? MessageHeaderType0 { previousChunkMessageId = messageHeaderType0.messageStreamId return await handleMessageHeaderType0(firstChunk: firstChunk, chunkSize: chunkSize, messageHeaderType0: messageHeaderType0, data: data) } - + if let messageHeaderType1 = firstChunk.chunkHeader.messageHeader as? MessageHeaderType1 { - let (message,size) = await handleMessageHeaderType1(firstChunk: firstChunk, chunkSize: chunkSize, messageHeaderType1: messageHeaderType1) + let (message, size) = await handleMessageHeaderType1(firstChunk: firstChunk, chunkSize: chunkSize, messageHeaderType1: messageHeaderType1) previousChunkMessageId = message?.msgStreamId - return (message,size) + return (message, size) } - - return (nil,0) + + return (nil, 0) } - - private func handleMessageHeaderType0(firstChunk: Chunk, chunkSize: Int, messageHeaderType0: MessageHeaderType0, data: Data) async -> (RTMPMessage?,Int) { + + private func handleMessageHeaderType0(firstChunk: Chunk, chunkSize: Int, messageHeaderType0: MessageHeaderType0, data: Data) async -> (RTMPMessage?, Int) { let messageLength = messageHeaderType0.messageLength // one chunk = one message if messageLength <= maxChunkSize { @@ -126,15 +126,15 @@ actor MessageDecoder { messageType: messageHeaderType0.type, timestamp: messageHeaderType0.timestamp, chunkPayload: firstChunk.chunkData) - return (message,chunkSize) + return (message, chunkSize) } else { var remainPayloadSize = messageLength - maxChunkSize var totalPayload = firstChunk.chunkData var allChunkSize = chunkSize while remainPayloadSize > 0 { let (chunk, chunkSize) = await chunkDecoder.decodeChunk(data: data.advanced(by: chunkSize)) - guard let chunk else { return (nil,0) } - + guard let chunk else { return (nil, 0) } + // same stream id chunk guard chunk.chunkHeader.basicHeader.streamId == firstChunk.chunkHeader.basicHeader.streamId else { continue @@ -151,11 +151,11 @@ actor MessageDecoder { return (message, allChunkSize) } } - + private var previousChunkMessageId: Int? - - private func handleMessageHeaderType1(firstChunk: Chunk, chunkSize: Int, messageHeaderType1: MessageHeaderType1) async -> (RTMPMessage?,Int) { - guard let previousChunkMessageId = previousChunkMessageId else { return (nil,0) } + + private func handleMessageHeaderType1(firstChunk: Chunk, chunkSize: Int, messageHeaderType1: MessageHeaderType1) async -> (RTMPMessage?, Int) { + guard let previousChunkMessageId = previousChunkMessageId else { return (nil, 0) } let messageLength = messageHeaderType1.messageLength @@ -166,15 +166,15 @@ actor MessageDecoder { messageType: messageHeaderType1.type, timestamp: messageHeaderType1.timestampDelta, chunkPayload: firstChunk.chunkData) - return (message,chunkSize) + return (message, chunkSize) } else { var remainPayloadSize = messageLength - maxChunkSize var totalPayload = firstChunk.chunkData var allChunkSize = chunkSize while remainPayloadSize > 0 { let (chunk, chunkSize) = await chunkDecoder.decodeChunk(data: data.advanced(by: chunkSize)) - guard let chunk else { return (nil,0) } - + guard let chunk else { return (nil, 0) } + // same stream id chunk guard chunk.chunkHeader.basicHeader.streamId == firstChunk.chunkHeader.basicHeader.streamId else { continue @@ -193,32 +193,31 @@ actor MessageDecoder { } } - actor ChunkDecoder { - + private var chunks: [Chunk] = [] - + private(set) var messageDataLengthMap: [UInt16: Int] = [:] private(set) var remainDataLengthMap: [UInt16: Int] = [:] - + var maxChunkSize: Int = Int(128) - + func setMaxChunkSize(maxChunkSize: Int) { self.maxChunkSize = maxChunkSize } - + func reset() { chunks = [] messageDataLengthMap = [:] remainDataLengthMap = [:] } - + private func getChunkDataLength(streamId: UInt16) -> Int? { // every chunk is same data size - if let messageDataLength = messageDataLengthMap[streamId] { + if let messageDataLength = messageDataLengthMap[streamId] { return messageDataLength } - + // big data size guard let remainDataLength = remainDataLengthMap[streamId] else { return nil } if remainDataLength > maxChunkSize { @@ -228,27 +227,25 @@ actor ChunkDecoder { remainDataLengthMap.removeValue(forKey: streamId) return remainDataLength } - - - + func decodeChunk(data: Data) -> (Chunk?, Int) { // Decode basic header let (basicHeader, basicHeaderSize) = decodeBasicHeader(data: data) guard let basicHeader = basicHeader else { return (nil, 0) } - + // Decode message header let (messageHeader, messageHeaderSize) = decodeMessageHeader(data: data.advanced(by: basicHeaderSize), type: basicHeader.type) guard let messageHeader = messageHeader else { return (nil, 0) } - + // Check if message header is of type 0 or type 1, then process it if let messageHeaderType0 = messageHeader as? MessageHeaderType0 { return processMessageHeader(data: data, basicHeader: basicHeader, messageHeader: messageHeaderType0, basicHeaderSize: basicHeaderSize, messageHeaderSize: messageHeaderSize) } - + if let messageHeaderType1 = messageHeader as? MessageHeaderType1 { return processMessageHeader(data: data, basicHeader: basicHeader, messageHeader: messageHeaderType1, basicHeaderSize: basicHeaderSize, messageHeaderSize: messageHeaderSize) } - + // If message header is of type 2 or type 3, process it if messageHeader is MessageHeaderType2 || messageHeader is MessageHeaderType3 { guard let payloadLength = getChunkDataLength(streamId: basicHeader.streamId) else { return (nil, 0) } @@ -259,10 +256,10 @@ actor ChunkDecoder { let chunkSize = basicHeaderSize + messageHeaderSize + chunkDataSize return (Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader, messageHeader: messageHeader), chunkData: chunkData), chunkSize) } - + return (nil, 0) } - + func processMessageHeader(data: Data, basicHeader: BasicHeader, messageHeader: MessageHeader, basicHeaderSize: Int, messageHeaderSize: Int) -> (Chunk?, Int) { let messageLength: Int if let headerType0 = messageHeader as? MessageHeaderType0 { @@ -272,48 +269,48 @@ actor ChunkDecoder { } else { return (nil, 0) } - + let currentMessageLength = messageLength <= maxChunkSize ? messageLength : maxChunkSize - + // Decode chunk data let (chunkData, chunkDataSize) = decodeChunkData(data: data.advanced(by: basicHeaderSize + messageHeaderSize), messageLength: currentMessageLength) guard let chunkData = chunkData else { return (nil, 0) } - + // Update message data length and remaining data length maps if messageLength <= maxChunkSize { messageDataLengthMap[basicHeader.streamId] = messageLength } else { remainDataLengthMap[basicHeader.streamId] = messageLength - maxChunkSize } - + let chunkSize = basicHeaderSize + messageHeaderSize + chunkDataSize return (Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader, messageHeader: messageHeader), chunkData: chunkData), chunkSize) } - - func decodeBasicHeader(data: Data) -> (BasicHeader?,Int) { + + func decodeBasicHeader(data: Data) -> (BasicHeader?, Int) { guard let byte = data.first else { - return (nil,0) + return (nil, 0) } // first 2 bit is type let fmt = byte >> 6 - + guard let headerType = MessageHeaderType(rawValue: Int(fmt)) else { - return (nil,0) + return (nil, 0) } - + let compare: UInt8 = 0b00111111 let streamId: UInt16 let basicHeaderLength: Int switch compare & byte { case 0: - guard data.count >= 2 else { return (nil,0) } + guard data.count >= 2 else { return (nil, 0) } // 2bytes. fmt| 0 |csid-64 basicHeaderLength = 2 streamId = UInt16(data[1] + 64) case 1: - guard data.count >= 3 else { return (nil,0) } + guard data.count >= 3 else { return (nil, 0) } // 3bytes. fmt|1| csid-64 basicHeaderLength = 3 streamId = UInt16(Data(data[1...2].reversed()).uint16) + 64 @@ -322,15 +319,15 @@ actor ChunkDecoder { basicHeaderLength = 1 streamId = UInt16(compare & byte) } - + return (BasicHeader(streamId: streamId, type: headerType), basicHeaderLength) } - + func decodeMessageHeader(data: Data, type: MessageHeaderType) -> ((any MessageHeader)?, Int) { switch type { case .type0: // 11bytes - guard data.count >= 11 else { return (nil,0) } + guard data.count >= 11 else { return (nil, 0) } // timestamp 3bytes let timestamp = Data(data[0...2].reversed() + [0x00]).uint32 // message length 3 byte @@ -339,38 +336,38 @@ actor ChunkDecoder { let messageType = MessageType(rawValue: data[6]) // msg stream id 4bytes, little-endian let messageStreamId = Data(data[7...10]).uint32 - + if timestamp == maxTimestamp { let extendTimestamp = Data(data[11...14].reversed()).uint32 return (MessageHeaderType0(timestamp: extendTimestamp, messageLength: Int(messageLength), type: messageType, messageStreamId: Int(messageStreamId)), 15) } - + return (MessageHeaderType0(timestamp: timestamp, messageLength: Int(messageLength), type: messageType, messageStreamId: Int(messageStreamId)), 11) - + case .type1: // 7bytes - guard data.count >= 7 else { return (nil,0) } + guard data.count >= 7 else { return (nil, 0) } let timestampDelta = Data(data[0...2].reversed() + [0x00]).uint32 let messageLength = Data(data[3...5].reversed() + [0x00]).uint32 let messageType = MessageType(rawValue: data[6]) - - return (MessageHeaderType1(timestampDelta: timestampDelta, messageLength: Int(messageLength), type: messageType),7) - + + return (MessageHeaderType1(timestampDelta: timestampDelta, messageLength: Int(messageLength), type: messageType), 7) + case .type2: // 3bytes - guard data.count >= 3 else { return (nil,0) } + guard data.count >= 3 else { return (nil, 0) } let timestampDelta = Data(data[0...2].reversed() + [0x00]).uint32 return (MessageHeaderType2(timestampDelta: timestampDelta), 3) - + case .type3: - return (MessageHeaderType3(),0) + return (MessageHeaderType3(), 0) } } - + func decodeChunkData(data: Data, messageLength: Int) -> (Data?, Int) { - guard data.count >= messageLength else { return (nil,0) } + guard data.count >= messageLength else { return (nil, 0) } let chunkData = data[0.. [Chunk] { let payload = message.encode() - + return payload.split(size: Int(chunkSize)) .enumerated() .map({ @@ -19,17 +19,17 @@ class ChunkEncoder { if isFirstType0 { messageHeader = MessageHeaderType0(timestamp: message.timestamp, messageLength: payload.count, - type: message.messageType , + type: message.messageType, messageStreamId: message.msgStreamId) } else { messageHeader = MessageHeaderType1(timestampDelta: message.timestamp, messageLength: payload.count, type: message.messageType) } - + let header = ChunkHeader(streamId: message.streamId, messageHeader: messageHeader) - + return Chunk(chunkHeader: header, chunkData: Data($0.element)) } let header = ChunkHeader(streamId: message.streamId, @@ -37,9 +37,9 @@ class ChunkEncoder { return Chunk(chunkHeader: header, chunkData: Data($0.element)) }) } - + func reset() { - + } } @@ -52,4 +52,3 @@ public extension Data { }) } } - diff --git a/Sources/HPRTMP/Chunk/MessageHeader.swift b/Sources/HPRTMP/Chunk/MessageHeader.swift index 56682d9..f55d031 100644 --- a/Sources/HPRTMP/Chunk/MessageHeader.swift +++ b/Sources/HPRTMP/Chunk/MessageHeader.swift @@ -12,12 +12,12 @@ extension MessageHeader where Self: Equatable { struct MessageHeaderType0: MessageHeader { // max timestamp 0xFFFFFF let maxTimestamp: UInt32 = 16777215 - + let timestamp: UInt32 let messageLength: Int let type: MessageType let messageStreamId: Int - + func encode() -> Data { var data = Data() let isExtendTime = timestamp > maxTimestamp @@ -38,7 +38,7 @@ struct MessageHeaderType1: MessageHeader { let timestampDelta: UInt32 let messageLength: Int let type: MessageType - + func encode() -> Data { var data = Data() data.writeU24(UInt32(timestampDelta), bigEndian: true) @@ -50,7 +50,7 @@ struct MessageHeaderType1: MessageHeader { struct MessageHeaderType2: MessageHeader { let timestampDelta: UInt32 - + func encode() -> Data { var data = Data() data.writeU24(UInt32(timestampDelta), bigEndian: true) diff --git a/Sources/HPRTMP/Chunk/RTMPMessageDefine.swift b/Sources/HPRTMP/Chunk/RTMPMessageDefine.swift index 7830e60..5e99715 100644 --- a/Sources/HPRTMP/Chunk/RTMPMessageDefine.swift +++ b/Sources/HPRTMP/Chunk/RTMPMessageDefine.swift @@ -13,7 +13,7 @@ enum RTMPAudioCodecsType: UInt16 { case none = 0x0001 case adpcm = 0x0002 case mp3 = 0x0004 - case intel = 0x0008 //not use + case intel = 0x0008 // not use case unused = 0x0010 // not use case nelly = 0x0040 case g711a = 0x0080 @@ -25,9 +25,9 @@ enum RTMPAudioCodecsType: UInt16 { } enum RTMPVideoCodecsType: UInt16 { - case unused = 0x0001 //Obsolete value - case jpeg = 0x0002 //Obsolete value - case sorenson = 0x0004 //Sorenson Flash Video + case unused = 0x0001 // Obsolete value + case jpeg = 0x0002 // Obsolete value + case sorenson = 0x0004 // Sorenson Flash Video case homebrew = 0x0008 // V1 screen sharning case vp6 = 0x0010 // on2 video(Flash 8+) case vp6Alpha = 0x0020 @@ -37,7 +37,7 @@ enum RTMPVideoCodecsType: UInt16 { } enum MessageType: Equatable { - + // controll case chunkSize case abort @@ -52,7 +52,7 @@ enum MessageType: Equatable { case video case aggreate case none - + init(rawValue: UInt8) { switch rawValue { case 1: self = .chunkSize @@ -61,8 +61,7 @@ enum MessageType: Equatable { case 4: self = .control case 5: self = .windowAcknowledgement case 6: self = .peerBandwidth - - + case 20: self = .command(type: .amf0) case 17: self = .command(type: .amf3) case 18: self = .data(type: .amf0) @@ -75,7 +74,7 @@ enum MessageType: Equatable { default: self = .none } } - + var rawValue: UInt8 { switch self { case .chunkSize: @@ -106,11 +105,11 @@ enum MessageType: Equatable { return 0xff } } - + static func == (lhs: MessageType, rhs: MessageType) -> Bool { lhs.rawValue == rhs.rawValue } - + } public enum VideoData { @@ -121,7 +120,7 @@ public enum VideoData { case generated = 4 case command = 5 } - + public enum CodecId: Int { case jpeg = 1 case h263 = 2 @@ -131,7 +130,7 @@ public enum VideoData { case screen2 = 6 case avc = 7 } - + public enum AVCPacketType: UInt8 { case header = 0 case nalu = 1 @@ -162,9 +161,9 @@ public enum AudioData { case reserved = 9 case aac = 10 case speex = 11 - case mp3_8KHZ = 14 + case mp3SmapleRate8KHZ = 14 case device = 15 - + var headerSize: Int { switch self { case .aac: @@ -174,13 +173,13 @@ public enum AudioData { } } } - + public enum SoundRate: Int { - case kHz5_5 = 0 + case kHz5Point5 = 0 case kHz11 = 1 case kHz22 = 2 case kHz44 = 3 - + public init(value: Float64) { switch value { case 44100: @@ -190,15 +189,15 @@ public enum AudioData { case 22050: self = .kHz22 case 5500: - self = .kHz5_5 + self = .kHz5Point5 default: self = .kHz44 } } - + public var value: Float64 { switch self { - case .kHz5_5: + case .kHz5Point5: return 5500 case .kHz11: return 11025 @@ -209,17 +208,17 @@ public enum AudioData { } } } - + public enum SoundSize: Int { case snd8Bit = 0 case snd16Bit = 1 } - + public enum SoundType: Int { case sndMono = 0 case sndStereo = 1 } - + public enum AACPacketType: UInt8 { case header = 0 case raw = 1 @@ -232,25 +231,25 @@ public enum ChannelConfigType: UInt8 { // R = Right // LFE = LFE-channel case aot = 0 - case front_C = 1 - case front_LR = 2 - case front_CLR = 3 - case front_CLR_back_C = 4 - case front_CLR_back_LR = 5 - case front_CLR_back_LR_LFE = 6 - case front_CLR_side_LR_back_LR_LFE = 7 + case frontC = 1 + case frontLR = 2 + case frontCLR = 3 + case frontCLRBackC = 4 + case frontCLRBackLR = 5 + case frontCLRBackLRLFE = 6 + case frontCLRSideLRBackLRLFE = 7 case reserved = 8 case unknown = 0xff public init(rawValue: UInt8) { switch rawValue { case 0: self = .aot - case 1: self = .front_C - case 2: self = .front_LR - case 3: self = .front_CLR - case 4: self = .front_CLR_back_C - case 5: self = .front_CLR_back_LR - case 6: self = .front_CLR_back_LR_LFE - case 7: self = .front_CLR_side_LR_back_LR_LFE + case 1: self = .frontC + case 2: self = .frontLR + case 3: self = .frontCLR + case 4: self = .frontCLRBackC + case 5: self = .frontCLRBackLR + case 6: self = .frontCLRBackLRLFE + case 7: self = .frontCLRSideLRBackLRLFE case 8: self = .reserved default: self = .unknown } @@ -296,7 +295,7 @@ public enum SampleFrequencyType: UInt8 { default: self = .unknown } } - + public init(value: Double) { switch value { case 96000: self = .kHz96000 @@ -314,8 +313,7 @@ public enum SampleFrequencyType: UInt8 { case 7350: self = .kHz7350 default: self = .unknown } - - + } public var value: Int { switch self { @@ -332,7 +330,7 @@ public enum SampleFrequencyType: UInt8 { case .kHz11025: return 11025 case .kHz8000: return 8000 case .kHz7350: return 7350 - case .unknown, .reserved0, .reserved1 , .writenExplictly: return 0xff + case .unknown, .reserved0, .reserved1, .writenExplictly: return 0xff } } } diff --git a/Sources/HPRTMP/Help.swift b/Sources/HPRTMP/Help.swift index 860b923..13861fb 100644 --- a/Sources/HPRTMP/Help.swift +++ b/Sources/HPRTMP/Help.swift @@ -2,11 +2,11 @@ import os actor MessageHolder { var raw = [Int: RTMPBaseMessage]() - + func register(transactionId: Int, message: RTMPBaseMessage) { raw[transactionId] = message } - + func removeMessage(transactionId: Int) -> RTMPBaseMessage? { let value = raw[transactionId] raw[transactionId] = nil @@ -16,7 +16,7 @@ actor MessageHolder { actor TransactionIdGenerator { private var currentId: Int = 1 - + func nextId() -> Int { currentId += 1 return currentId diff --git a/Sources/HPRTMP/Message/CommandMessage.swift b/Sources/HPRTMP/Message/CommandMessage.swift index 9b141b4..2223539 100644 --- a/Sources/HPRTMP/Message/CommandMessage.swift +++ b/Sources/HPRTMP/Message/CommandMessage.swift @@ -14,7 +14,7 @@ enum CodeType { case badVersion = "NetConnection.Call.BadVersion" case failed = "NetConnection.Call.Failed" } - + enum Connect: String, Decodable { case failed = "NetConnection.Connect.Failed" case timeout = "NetConnection.Connect.IdleTimeOut" @@ -26,7 +26,7 @@ enum CodeType { } enum CommandNameType: String { - //检测带宽成功 + // 检测带宽成功 case onBWDone = "onBWDone" case onStatus = "onStatus" case onMetaData = "onMetaData" @@ -43,7 +43,7 @@ class CommandMessage: RTMPBaseMessage, CustomStringConvertible { } let transactionId: Int let commandObject: [String: Any?]? - + let info: Any? init(encodeType: ObjectEncodingType, @@ -57,9 +57,9 @@ class CommandMessage: RTMPBaseMessage, CustomStringConvertible { self.commandObject = commandObject self.info = info self.encodeType = encodeType - super.init(type: .command(type: encodeType),msgStreamId: msgStreamId, streamId: RTMPStreamId.command.rawValue) + super.init(type: .command(type: encodeType), msgStreamId: msgStreamId, streamId: RTMPStreamId.command.rawValue) } - + var description: String { var result = "" result += "Command Name: \(commandName)\n" @@ -74,7 +74,6 @@ class CommandMessage: RTMPBaseMessage, CustomStringConvertible { } } - class ConnectMessage: CommandMessage, Encodable { let argument: [String: Any?]? init(encodeType: ObjectEncodingType = .amf0, @@ -88,20 +87,20 @@ class ConnectMessage: CommandMessage, Encodable { pageURL: URL? = nil, argument: [String: Any?]? = nil) { self.argument = argument - let obj:[String: Any?] = ["app": appName, + let obj: [String: Any?] = ["app": appName, "flashver": flashVer, - "swfUrl":swfURL?.absoluteString, - "tcUrl":tcUrl, - "fpad":fpad, + "swfUrl": swfURL?.absoluteString, + "tcUrl": tcUrl, + "fpad": fpad, "audioCodecs": audio.rawValue, - "videoCodecs":video.rawValue, - "videoFunction":RTMPVideoFunction.seek.rawValue, - "pageUrl":pageURL?.absoluteString, - "objectEncoding":encodeType.rawValue] - + "videoCodecs": video.rawValue, + "videoFunction": RTMPVideoFunction.seek.rawValue, + "pageUrl": pageURL?.absoluteString, + "objectEncoding": encodeType.rawValue] + super.init(encodeType: encodeType, commandName: "connect", transactionId: commonTransactionId.connect, commandObject: obj) } - + func encode() -> Data { var amf: AMFProtocol = encodeType == .amf0 ? AMF0Object() : AMF3Object() amf.append(commandName) @@ -109,7 +108,7 @@ class ConnectMessage: CommandMessage, Encodable { amf.append(commandObject) return amf.data } - + override var description: String { var desc = "ConnectMessage(" desc += "commandName: \(commandName), " @@ -121,12 +120,11 @@ class ConnectMessage: CommandMessage, Encodable { } } - class CreateStreamMessage: CommandMessage, Encodable { init(encodeType: ObjectEncodingType = .amf0, transactionId: Int, commonObject: [String: Any?]? = nil) { - super.init(encodeType: encodeType,commandName: "createStream", transactionId: transactionId, commandObject: commonObject) + super.init(encodeType: encodeType, commandName: "createStream", transactionId: transactionId, commandObject: commonObject) } - + func encode() -> Data { var amf: AMFProtocol = encodeType == .amf0 ? AMF0Object() : AMF3Object() amf.append(commandName) @@ -134,7 +132,7 @@ class CreateStreamMessage: CommandMessage, Encodable { amf.append(commandObject) return amf.data } - + override var description: String { let objDesc = commandObject != nil ? "\(commandObject!)" : "nil" let infoDesc = info != nil ? "\(info!)" : "nil" @@ -144,9 +142,9 @@ class CreateStreamMessage: CommandMessage, Encodable { class CloseStreamMessage: CommandMessage, Encodable { init(encodeType: ObjectEncodingType = .amf0, msgStreamId: Int) { - super.init(encodeType: encodeType,commandName: "closeStream", msgStreamId: msgStreamId, transactionId: 0, commandObject: nil) + super.init(encodeType: encodeType, commandName: "closeStream", msgStreamId: msgStreamId, transactionId: 0, commandObject: nil) } - + func encode() -> Data { var amf: AMFProtocol = encodeType == .amf0 ? AMF0Object() : AMF3Object() amf.append(commandName) @@ -154,7 +152,7 @@ class CloseStreamMessage: CommandMessage, Encodable { amf.append(commandObject) return amf.data } - + override var description: String { let objDesc = commandObject != nil ? "\(commandObject!)" : "nil" let infoDesc = info != nil ? "\(info!)" : "nil" @@ -164,9 +162,9 @@ class CloseStreamMessage: CommandMessage, Encodable { class DeleteStreamMessage: CommandMessage, Encodable { init(encodeType: ObjectEncodingType = .amf0, msgStreamId: Int) { - super.init(encodeType: encodeType,commandName: "deleteStream", msgStreamId: msgStreamId, transactionId: 0, commandObject: nil) + super.init(encodeType: encodeType, commandName: "deleteStream", msgStreamId: msgStreamId, transactionId: 0, commandObject: nil) } - + func encode() -> Data { var amf: AMFProtocol = encodeType == .amf0 ? AMF0Object() : AMF3Object() amf.append(commandName) @@ -174,7 +172,7 @@ class DeleteStreamMessage: CommandMessage, Encodable { amf.append(commandObject) return amf.data } - + override var description: String { let objDesc = commandObject != nil ? "\(commandObject!)" : "nil" let infoDesc = info != nil ? "\(info!)" : "nil" @@ -196,7 +194,7 @@ class PublishMessage: CommandMessage, Encodable { self.type = type super.init(encodeType: encodeType, commandName: "publish", transactionId: commonTransactionId.stream) } - + func encode() -> Data { var amf: AMFProtocol = encodeType == .amf0 ? AMF0Object() : AMF3Object() amf.append(commandName) @@ -208,14 +206,13 @@ class PublishMessage: CommandMessage, Encodable { } } - class SeekMessage: CommandMessage, Encodable { let millSecond: Double init(encodeType: ObjectEncodingType = .amf0, msgStreamId: Int, millSecond: Double) { self.millSecond = millSecond super.init(encodeType: encodeType, commandName: "seek", msgStreamId: msgStreamId, transactionId: commonTransactionId.stream) } - + func encode() -> Data { var amf: AMFProtocol = encodeType == .amf0 ? AMF0Object() : AMF3Object() amf.append(commandName) @@ -226,16 +223,15 @@ class SeekMessage: CommandMessage, Encodable { } } - class PauseMessage: CommandMessage, Encodable { let isPause: Bool let millSecond: Double - init(encodeType: ObjectEncodingType = .amf0, msgStreamId:Int, isPause: Bool, millSecond: Double) { + init(encodeType: ObjectEncodingType = .amf0, msgStreamId: Int, isPause: Bool, millSecond: Double) { self.isPause = isPause self.millSecond = millSecond super.init(encodeType: encodeType, commandName: "pause", msgStreamId: msgStreamId, transactionId: commonTransactionId.stream) } - + func encode() -> Data { var amf: AMFProtocol = encodeType == .amf0 ? AMF0Object() : AMF3Object() amf.append(commandName) @@ -246,4 +242,3 @@ class PauseMessage: CommandMessage, Encodable { return amf.data } } - diff --git a/Sources/HPRTMP/Message/ControlMessage.swift b/Sources/HPRTMP/Message/ControlMessage.swift index be5c9e1..2d682d8 100644 --- a/Sources/HPRTMP/Message/ControlMessage.swift +++ b/Sources/HPRTMP/Message/ControlMessage.swift @@ -20,7 +20,7 @@ class ChunkSizeMessage: ControlMessage, Encodable { self.size = size super.init(type: .chunkSize) } - + func encode() -> Data { var data = Data() data.write(size & 0x7FFFFFFF) @@ -28,15 +28,14 @@ class ChunkSizeMessage: ControlMessage, Encodable { } } - // Abort message (2) class AbortMessage: ControlMessage, Encodable { let chunkStreamId: UInt16 - init(chunkStreamId : UInt16) { + init(chunkStreamId: UInt16) { self.chunkStreamId = chunkStreamId super.init(type: .abort) } - + func encode() -> Data { var data = Data() data.write(UInt32(chunkStreamId)) @@ -44,7 +43,6 @@ class AbortMessage: ControlMessage, Encodable { } } - // Acknowledgement (3) class AcknowledgementMessage: ControlMessage, Encodable { let sequence: UInt32 @@ -52,7 +50,7 @@ class AcknowledgementMessage: ControlMessage, Encodable { self.sequence = sequence super.init(type: .acknowledgement) } - + func encode() -> Data { var data = Data() data.write(sequence) @@ -60,15 +58,14 @@ class AcknowledgementMessage: ControlMessage, Encodable { } } - -//Window Acknowledgement Size (5) +// Window Acknowledgement Size (5) class WindowAckMessage: ControlMessage, Encodable { let size: UInt32 init(size: UInt32) { self.size = size super.init(type: .windowAcknowledgement) } - + func encode() -> Data { var data = Data() data.write(size) @@ -76,16 +73,15 @@ class WindowAckMessage: ControlMessage, Encodable { } } - -//Set Peer Bandwidth (6) +// Set Peer Bandwidth (6) class PeerBandwidthMessage: ControlMessage, Encodable { - + enum LimitType: UInt8 { case hard = 0 case soft = 1 case dynamic = 2 } - + let windowSize: UInt32 let limit: LimitType init(windowSize: UInt32, limit: LimitType) { @@ -93,7 +89,7 @@ class PeerBandwidthMessage: ControlMessage, Encodable { self.limit = limit super.init(type: .peerBandwidth) } - + func encode() -> Data { var data = Data() data.write(windowSize) diff --git a/Sources/HPRTMP/Message/DataMessage.swift b/Sources/HPRTMP/Message/DataMessage.swift index 6e6d96f..c213c01 100644 --- a/Sources/HPRTMP/Message/DataMessage.swift +++ b/Sources/HPRTMP/Message/DataMessage.swift @@ -5,13 +5,11 @@ // Created by Huiping Guo on 2022/11/03. // - import Foundation // max timestamp 0xFFFFFF let maxTimestamp: UInt32 = 16777215 - enum RTMPStreamId: Int { case control = 2 case command = 3 @@ -20,17 +18,17 @@ enum RTMPStreamId: Int { } protocol RTMPMessage { - var timestamp: UInt32 { set get } + var timestamp: UInt32 { get set } var messageType: MessageType { get } - var msgStreamId: Int { get set } - var streamId: Int { get } + var msgStreamId: Int { get set } + var streamId: Int { get } } public class RTMPBaseMessage: RTMPMessage { let messageType: MessageType var msgStreamId: Int let streamId: Int - + init(type: MessageType, msgStreamId: Int = 0, streamId: Int) { self.messageType = type self.msgStreamId = msgStreamId @@ -38,7 +36,7 @@ public class RTMPBaseMessage: RTMPMessage { } private var _timeInterval: UInt32 = 0 - public var timestamp:UInt32 { + public var timestamp: UInt32 { set { _timeInterval = newValue >= maxTimestamp ? maxTimestamp : newValue } get { @@ -57,7 +55,6 @@ class DataMessage: RTMPBaseMessage { } } - class MetaMessage: DataMessage, Encodable { let meta: [String: Any] init(encodeType: ObjectEncodingType, msgStreamId: Int, meta: [String: Any]) { @@ -65,7 +62,7 @@ class MetaMessage: DataMessage, Encodable { super.init(encodeType: encodeType, msgStreamId: msgStreamId) } - + func encode() -> Data { var amf: AMFProtocol = encodeType == .amf0 ? AMF0Object() : AMF3Object() amf.append("onMetaData") @@ -74,7 +71,6 @@ class MetaMessage: DataMessage, Encodable { } } - class VideoMessage: RTMPBaseMessage, Encodable { let data: Data init(msgStreamId: Int, data: Data, timestamp: UInt32) { @@ -89,7 +85,6 @@ class VideoMessage: RTMPBaseMessage, Encodable { } } - class AudioMessage: RTMPBaseMessage, Encodable { let data: Data @@ -108,13 +103,13 @@ class AudioMessage: RTMPBaseMessage, Encodable { class SharedObjectMessage: DataMessage, Encodable { let sharedObjectName: String? let sharedObject: [String: Any]? - + init(encodeType: ObjectEncodingType, msgStreamId: Int, sharedObjectName: String?, sharedObject: [String: Any]?) { self.sharedObjectName = sharedObjectName self.sharedObject = sharedObject super.init(encodeType: encodeType, msgStreamId: msgStreamId) } - + func encode() -> Data { var amf: AMFProtocol = encodeType == .amf0 ? AMF0Object() : AMF3Object() amf.append("onSharedObject") diff --git a/Sources/HPRTMP/Message/RTMPResponse.swift b/Sources/HPRTMP/Message/RTMPResponse.swift index 1dada02..f241822 100644 --- a/Sources/HPRTMP/Message/RTMPResponse.swift +++ b/Sources/HPRTMP/Message/RTMPResponse.swift @@ -4,19 +4,19 @@ struct ConnectResponse { var description: String var level: String var code: CodeType.Connect - + var objectEncoding: ObjectEncodingType - + init?(info: Any?) { guard let info = info as? [String: Any?] else { return nil } guard let code = info["code"] as? String else { return nil } self.code = CodeType.Connect(rawValue: code) ?? .failed - + guard let level = info["level"] as? String else { return nil } self.level = level guard let description = info["description"] as? String else { return nil } self.description = description - + guard let objectEncoding = info["objectEncoding"] as? Double else { return nil } self.objectEncoding = ObjectEncodingType(rawValue: UInt8(objectEncoding)) ?? .amf0 } @@ -28,23 +28,23 @@ struct StatusResponse: Decodable { case status = "status" case error = "error" } - + enum StreamStatus: String, Decodable { case bufferEmpty = "NetStream.Buffer.Empty" case bufferFlush = "NetStream.Buffer.Flush" case bufferFull = "NetStream.Buffer.Full" - + case connectClosed = "NetStream.Connect.Closed" case connectFailed = "NetStream.Connect.Failed" case connectRejected = "NetStream.Connect.Rejected" case connectSuccess = "NetStream.Connect.Success" - + case drmUpdateNeeded = "NetStream.DRM.UpdateNeeded" case failed = "NetStream.Failed" case multicastStreamReset = "NetStream.MulticastStream.Reset" - + case pauseNotify = "NetStream.Pause.Notify" - + case playFailed = "NetStream.Play.Failed" case playFileStructureInvalid = "NetStream.Play.FileStructureInvalid" case playInsufficientBW = "NetStream.Play.InsufficientBW" @@ -55,7 +55,7 @@ struct StatusResponse: Decodable { case playStreamNotFound = "NetStream.Play.StreamNotFound" case playTransition = "NetStream.Play.Transition" case playUnpublishNotify = "NetStream.Play.UnpublishNotify" - + case publishBadName = "NetStream.Publish.BadName" case publishIdle = "NetStream.Publish.Idle" case publishStart = "NetStream.Publish.Start" @@ -78,17 +78,17 @@ struct StatusResponse: Decodable { let code: StreamStatus? let level: Level? let description: String? - + init?(info: Any?) { guard let info = info as? [String: Any?] else { return nil } guard let code = info["code"] as? String else { return nil } self.code = StreamStatus(rawValue: code) ?? .failed - + guard let level = info["level"] as? String else { return nil } self.level = Level(rawValue: level) self.description = info["description"] as? String } - + } public struct SampleDescription { @@ -96,32 +96,32 @@ public struct SampleDescription { } public struct Trackinfo { - public let sampledescription : [SampleDescription] - public let language : String - public let timescale : Double - public let length : Double + public let sampledescription: [SampleDescription] + public let language: String + public let timescale: Double + public let length: Double } public struct MetaDataResponse { - public var duration : Double = 0 - public var height : Int = 0 - public var frameWidth : Int = 0 - public var moovposition : Int = 0 - public var framerate : Int = 0 - public var avcprofile : Int = 0 - public var videocodecid : String = "" - public var frameHeight : Int = 0 - public var videoframerate : Int = 0 - public var audiochannels : Int = 0 - public var displayWidth : Int = 0 - public var displayHeight : Int = 0 + public var duration: Double = 0 + public var height: Int = 0 + public var frameWidth: Int = 0 + public var moovposition: Int = 0 + public var framerate: Int = 0 + public var avcprofile: Int = 0 + public var videocodecid: String = "" + public var frameHeight: Int = 0 + public var videoframerate: Int = 0 + public var audiochannels: Int = 0 + public var displayWidth: Int = 0 + public var displayHeight: Int = 0 public var trackinfo = [Trackinfo]() - public var width : Int = 0 - public var avclevel : Int = 0 - public var audiosamplerate : Int = 0 - public var aacaot : Int = 0 - public var audiocodecid : String = "" - + public var width: Int = 0 + public var avclevel: Int = 0 + public var audiosamplerate: Int = 0 + public var aacaot: Int = 0 + public var audiocodecid: String = "" + enum CodingKeys: String, CodingKey { case duration = "duration" case height = "height" @@ -142,10 +142,10 @@ public struct MetaDataResponse { case aacaot = "aacaot" case audiocodecid = "audiocodecid" } - - init?(commandObject: [String: Any?]?) { + + init?(commandObject: [String: Any?]?) { // swiftlint:disable:this cyclomatic_complexity guard let commandObject = commandObject else { return nil } - + if let duration = commandObject["duration"] as? Double { self.duration = duration } diff --git a/Sources/HPRTMP/Message/UserControlMessage.swift b/Sources/HPRTMP/Message/UserControlMessage.swift index ccea0e5..c10461c 100644 --- a/Sources/HPRTMP/Message/UserControlMessage.swift +++ b/Sources/HPRTMP/Message/UserControlMessage.swift @@ -21,14 +21,14 @@ enum UserControlEventType: Int { class UserControlMessage: RTMPBaseMessage, Encodable { let type: UserControlEventType let data: Data - + init(type: UserControlEventType, data: Data, streamId: Int) { self.type = type self.data = data - + super.init(type: .control, streamId: streamId) } - + convenience init(streamBufferLength: Int, streamId: Int) { var data = Data() let id = UInt32(streamId).bigEndian.data @@ -38,13 +38,12 @@ class UserControlMessage: RTMPBaseMessage, Encodable { self.init(type: .streamBufferLength, data: data, streamId: streamId) } - + func encode() -> Data { var data = Data() data.write(UInt16(type.rawValue)) data.append(data) return data } - - + } diff --git a/Sources/HPRTMP/PublishConfigure.swift b/Sources/HPRTMP/PublishConfigure.swift index 55333e5..7ef71ad 100644 --- a/Sources/HPRTMP/PublishConfigure.swift +++ b/Sources/HPRTMP/PublishConfigure.swift @@ -1,5 +1,3 @@ - - public struct PublishConfigure { let width: Int let height: Int @@ -22,7 +20,7 @@ public struct PublishConfigure { self.audioDatarate = audioDatarate self.audioSamplerate = audioSamplerate } - + var meta: [String: Any] { var dic: [String: Any] = [ "width": Int32(width), diff --git a/Sources/HPRTMP/RTMPHandshake.swift b/Sources/HPRTMP/RTMPHandshake.swift index e6e0060..b23322b 100644 --- a/Sources/HPRTMP/RTMPHandshake.swift +++ b/Sources/HPRTMP/RTMPHandshake.swift @@ -20,44 +20,44 @@ actor RTMPHandshake { case handshakeDone case none } - + // const 1536 byte static let packetSize = 1536 private static let rtmpVersion: UInt8 = 3 - + private let dataSender: (Data) async throws -> Void private let dataReceiver: () async throws -> Data - + weak var delegate: RTMPHandshakeDelegate? - + private let logger = Logger(subsystem: "HPRTMP", category: "Handshake") - + public func setDelegate(delegate: RTMPHandshakeDelegate?) { self.delegate = delegate } - + public init(dataSender: @escaping (Data) async throws -> Void, dataReceiver: @escaping () async throws -> Data) { self.dataSender = dataSender self.dataReceiver = dataReceiver } - + private(set) var status = Status.none { didSet { logger.info("handshake status changed to \(self.status.rawValue) ") delegate?.rtmpHandshakeDidChange(status: status) } } - + var c0c1Packet: Data { var data = Data() - + // rtmp version data.write(RTMPHandshake.rtmpVersion) // time stamp data.write(UInt32(0).toUInt8Array()) // const 0,0,0,0 - data.write([0x00,0x00,0x00,0x00]) - + data.write([0x00, 0x00, 0x00, 0x00]) + // random let randomSize = RTMPHandshake.packetSize - data.count (0...randomSize).forEach { _ in @@ -65,7 +65,7 @@ actor RTMPHandshake { } return data } - + func c2Packet(s0s1Packet: Data) -> Data { var data = Data() // s1 timestamp @@ -76,26 +76,26 @@ actor RTMPHandshake { data.append(s0s1Packet.subdata(in: 8..= firstHandlingDataSize { @@ -106,28 +106,26 @@ actor RTMPHandshake { break } } - + // send c2 packet try await dataSender(c2Packet(s0s1Packet: s0s1Packet)) - + // ackSent status status = .ackSent - + while true { if handshakeData.count >= Self.packetSize { // remove s2 packet handshakeData.removeSubrange(0.. Bool { switch (lhs, rhs) { case (.unknown, .unknown), @@ -30,30 +30,29 @@ public class RTMPPublishSession { } } } - + public weak var delegate: RTMPPublishSessionDelegate? - + public var publishStatus: Status = .unknown { didSet { delegate?.sessionStatusChange(self, status: publishStatus) } } - + public let encodeType: ObjectEncodingType = .amf0 - + private var socket: RTMPSocket! - + private let transactionIdGenerator = TransactionIdGenerator() - + private var configure: PublishConfigure? - + private var connectId: Int = 0 - + private let logger = Logger(subsystem: "HPRTMP", category: "Publish") - public init() {} - + public func publish(url: String, configure: PublishConfigure) async { self.configure = configure if socket != nil { @@ -62,10 +61,10 @@ public class RTMPPublishSession { socket = await RTMPSocket() await socket.setDelegate(delegate: self) await socket.connect(url: url) - + publishStatus = .handShakeStart } - + private var videoHeaderSended = false private var audioHeaderSended = false @@ -74,34 +73,34 @@ public class RTMPPublishSession { await socket.send(message: message, firstType: true) videoHeaderSended = true } - + public func publishVideo(data: Data, delta: UInt32) async { guard videoHeaderSended else { return } let message = VideoMessage(msgStreamId: connectId, data: data, timestamp: delta) await socket.send(message: message, firstType: false) } - + public func publishAudioHeader(data: Data) async { let message = AudioMessage(msgStreamId: connectId, data: data, timestamp: 0) await socket.send(message: message, firstType: true) audioHeaderSended = true } - + public func publishAudio(data: Data, delta: UInt32) async { guard audioHeaderSended else { return } let message = AudioMessage(msgStreamId: connectId, data: data, timestamp: delta) await socket.send(message: message, firstType: false) } - + public func invalidate() async { // send closeStream let closeStreamMessage = CloseStreamMessage(msgStreamId: connectId) await socket.send(message: closeStreamMessage, firstType: true) - + // send deleteStream let deleteStreamMessage = DeleteStreamMessage(msgStreamId: connectId) await socket.send(message: deleteStreamMessage, firstType: true) - + await self.socket.invalidate() self.publishStatus = .disconnected } @@ -111,7 +110,7 @@ extension RTMPPublishSession: RTMPSocketDelegate { func socketGetMeta(_ socket: RTMPSocket, meta: MetaDataResponse) {} func socketStreamOutputAudio(_ socket: RTMPSocket, data: Data, timeStamp: Int64) {} func socketStreamOutputVideo(_ socket: RTMPSocket, data: Data, timeStamp: Int64) {} - + func socketStreamPublishStart(_ socket: RTMPSocket) { logger.debug("socketStreamPublishStart") publishStatus = .publishStart @@ -121,36 +120,36 @@ extension RTMPPublishSession: RTMPSocketDelegate { await socket.send(message: metaMessage, firstType: true) } } - + func socketStreamRecord(_ socket: RTMPSocket) { // publisher dont need implement } - + func socketStreamPlayStart(_ socket: RTMPSocket) { // publisher dont need implement } - + func socketStreamPause(_ socket: RTMPSocket, pause: Bool) { // publisher dont need implement } - + func socketConnectDone(_ socket: RTMPSocket) { publishStatus = .connect Task { let message = CreateStreamMessage(encodeType: encodeType, transactionId: await transactionIdGenerator.nextId()) await self.socket.messageHolder.register(transactionId: message.transactionId, message: message) await socket.send(message: message, firstType: true) - + // make chunk size more bigger let chunkSize: UInt32 = 1024*10 let size = ChunkSizeMessage(size: chunkSize) await socket.send(message: size, firstType: true) } } - + func socketHandShakeDone(_ socket: RTMPSocket) { publishStatus = .handShakeDone - + Task { guard let urlInfo = await socket.urlInfo else { return } let connect = ConnectMessage(encodeType: encodeType, @@ -164,39 +163,38 @@ extension RTMPPublishSession: RTMPSocketDelegate { await self.socket.send(message: connect, firstType: true) } } - + func socketCreateStreamDone(_ socket: RTMPSocket, msgStreamId: Int) { publishStatus = .connect Task { let message = await PublishMessage(encodeType: encodeType, streamName: socket.urlInfo?.key ?? "", type: .live) - + message.msgStreamId = msgStreamId self.connectId = msgStreamId await socket.send(message: message, firstType: true) } } - + func socketPinRequest(_ socket: RTMPSocket, data: Data) { Task { let message = UserControlMessage(type: .pingResponse, data: data, streamId: connectId) await socket.send(message: message, firstType: true) } } - + func socketError(_ socket: RTMPSocket, err: RTMPError) { delegate?.sessionError(self, error: err) } - + func socketPeerBandWidth(_ socket: RTMPSocket, size: UInt32) { Task { // send window ack message to server await socket.send(message: WindowAckMessage(size: size), firstType: true) } } - + func socketDisconnected(_ socket: RTMPSocket) { publishStatus = .disconnected } } - diff --git a/Sources/HPRTMP/RTMPSocket.swift b/Sources/HPRTMP/RTMPSocket.swift index 550cf59..ef6d55e 100644 --- a/Sources/HPRTMP/RTMPSocket.swift +++ b/Sources/HPRTMP/RTMPSocket.swift @@ -46,8 +46,7 @@ protocol RTMPSocketDelegate: AnyObject { func socketGetMeta(_ socket: RTMPSocket, meta: MetaDataResponse) func socketPeerBandWidth(_ socket: RTMPSocket, size: UInt32) func socketDisconnected(_ socket: RTMPSocket) - - + func socketStreamOutputAudio(_ socket: RTMPSocket, data: Data, timeStamp: Int64) func socketStreamOutputVideo(_ socket: RTMPSocket, data: Data, timeStamp: Int64) func socketStreamPublishStart(_ socket: RTMPSocket) @@ -57,50 +56,49 @@ protocol RTMPSocketDelegate: AnyObject { } public actor RTMPSocket { - + private var connection: NWConnection? - + private var status: RTMPStatus = .none - + weak var delegate: RTMPSocketDelegate? - + func setDelegate(delegate: RTMPSocketDelegate) { self.delegate = delegate } - + private(set) var urlInfo: RTMPURLInfo? - + let messageHolder = MessageHolder() - + private let encoder = ChunkEncoder() private let decoder = MessageDecoder() - + private var handshake: RTMPHandshake? - + private let windowControl = WindowControl() - + private let logger = Logger(subsystem: "HPRTMP", category: "RTMPSocket") - + public init() async { await windowControl.setInBytesWindowEvent { [weak self]inbytesCount in await self?.sendAcknowledgementMessage(sequence: inbytesCount) } } - + private func sendAcknowledgementMessage(sequence: UInt32) async { guard status == .connected else { return } await self.send(message: AcknowledgementMessage(sequence: UInt32(sequence)), firstType: true) } - - + public func connect(url: String) async { let urlParser = RTMPURLParser() guard let urlInfo = try? urlParser.parse(url: url) else { return } self.urlInfo = urlInfo - + await resume() } - + public func connect(streamURL: URL, streamKey: String, port: Int = 1935) { let urlInfo = RTMPURLInfo(url: streamURL, appName: "", key: streamKey, port: port) self.urlInfo = urlInfo @@ -135,11 +133,11 @@ extension RTMPSocket { } } NWConnection.maxReadSize = Int((await windowControl.windowSize)) - + status = .open connection.start(queue: DispatchQueue.global(qos: .default)) } - + private func startShakeHands() async { guard let connection = self.connection else { return } self.handshake = RTMPHandshake(dataSender: connection.sendData, dataReceiver: connection.receiveData) @@ -150,7 +148,7 @@ extension RTMPSocket { self.delegate?.socketError(self, err: .handShake(desc: error.localizedDescription)) } } - + public func invalidate() async { guard status != .closed && status != .none else { return } await handshake?.reset() @@ -162,7 +160,7 @@ extension RTMPSocket { status = .closed delegate?.socketDisconnected(self) } - + private func startReceiveData() async throws { guard let connection else { return } while true { @@ -176,7 +174,7 @@ extension RTMPSocket { extension RTMPSocket { func send(message: RTMPMessage & Encodable, firstType: Bool) async { logger.debug("send message start: \(type(of: message))") - + if let message = message as? ChunkSizeMessage { encoder.chunkSize = message.size } @@ -212,7 +210,7 @@ extension RTMPSocket { guard !data.isEmpty else { return } await windowControl.addInBytesCount(UInt32(data.count)) await decoder.append(data) - + if await decoder.isDecoding { return } @@ -222,42 +220,42 @@ extension RTMPSocket { await decode(data: data) } } - + private func decode(data: Data) async { guard let message = await decoder.decode() else { logger.info("[HPRTMP] decode message need more data.") return } - + if let windowAckMessage = message as? WindowAckMessage { logger.info("WindowAckMessage, size \(windowAckMessage.size)") await windowControl.setWindowSize(windowAckMessage.size) return } - + if let acknowledgementMessage = message as? AcknowledgementMessage { logger.info("AcknowledgementMessage, size \(acknowledgementMessage.sequence)") return } - + if let peerBandwidthMessage = message as? PeerBandwidthMessage { logger.info("PeerBandwidthMessage, size \(peerBandwidthMessage.windowSize)") delegate?.socketPeerBandWidth(self, size: peerBandwidthMessage.windowSize) return } - + if let chunkSizeMessage = message as? ChunkSizeMessage { logger.info("chunkSizeMessage, size \(chunkSizeMessage.size)") await decoder.setMaxChunkSize(maxChunkSize: Int(chunkSizeMessage.size)) return } - + if let commandMessage = message as? CommandMessage { logger.info("CommandMessage, \(commandMessage.description)") await handleCommandMessage(commandMessage) return } - + if let userControlMessage = message as? UserControlMessage { logger.info("UserControlMessage, message Type: \(userControlMessage.type.rawValue)") switch userControlMessage.type { @@ -269,42 +267,42 @@ extension RTMPSocket { break } } - + if let controlMessage = message as? ControlMessage { logger.info("ControlMessage, message Type: \(controlMessage.messageType.rawValue)") - + return } - + if let dataMessage = message as? DataMessage { logger.info("DataMessage, message Type: \(dataMessage.messageType.rawValue)") - + return } - + if let videoMessage = message as? VideoMessage { logger.info("VideoMessage, message Type: \(videoMessage.messageType.rawValue)") self.delegate?.socketStreamOutputVideo(self, data: videoMessage.data, timeStamp: Int64(videoMessage.timestamp)) return } - + if let audioMessage = message as? AudioMessage { logger.info("AudioMessage, message Type: \(audioMessage.messageType.rawValue)") self.delegate?.socketStreamOutputAudio(self, data: audioMessage.data, timeStamp: Int64(audioMessage.timestamp)) return } - + if let sharedObjectMessage = message as? SharedObjectMessage { logger.info("ShareMessage, message Type: \(sharedObjectMessage.messageType.rawValue)") return } - + if let abortMessage = message as? AbortMessage { logger.info("AbortMessage, message Type: \(abortMessage.chunkStreamId)") return } } - + private func handleCommandMessage(_ commandMessage: CommandMessage) async { if commandMessage.commandNameType == .onStatus { guard let statusResponse = StatusResponse(info: commandMessage.info) else { return } @@ -326,14 +324,14 @@ extension RTMPSocket { } return } - + // meta data if commandMessage.commandNameType == .onMetaData { guard let meta = MetaDataResponse(commandObject: commandMessage.commandObject) else { return } self.delegate?.socketGetMeta(self, meta: meta) return } - + // back from server let message = await messageHolder.removeMessage(transactionId: commandMessage.transactionId) switch message { @@ -352,7 +350,7 @@ extension RTMPSocket { if commandMessage.commandNameType == .result { logger.info("Create Stream Success") self.status = .connected - + let msgStreamId = commandMessage.info as? Double ?? 0 self.delegate?.socketCreateStreamDone(self, msgStreamId: Int(msgStreamId)) } else { diff --git a/Sources/HPRTMP/RTMPURLParser.swift b/Sources/HPRTMP/RTMPURLParser.swift index 47b4b9d..66a8dec 100644 --- a/Sources/HPRTMP/RTMPURLParser.swift +++ b/Sources/HPRTMP/RTMPURLParser.swift @@ -7,7 +7,7 @@ struct RTMPURLInfo { let appName: String let key: String let port: Int - + var host: String { return url.host! } @@ -21,25 +21,25 @@ enum RTMPURLParsingError: Error { struct RTMPURLParser { init() {} - + func parse(url: String) throws -> RTMPURLInfo? { guard let parsedURL = URL(string: url) else { throw RTMPURLParsingError.invalidURL } - + guard let scheme = parsedURL.scheme, scheme == "rtmp" else { throw RTMPURLParsingError.invalidScheme } - + let pathComponents = parsedURL.pathComponents guard pathComponents.count >= 3 else { throw RTMPURLParsingError.missingAppNameOrKey } - + let appName = pathComponents[1] let key = pathComponents[2] let port = parsedURL.port ?? 1935 - + return RTMPURLInfo(url: parsedURL, appName: appName, key: key, port: port) } } diff --git a/Sources/HPRTMP/Util/ArrayExtensions.swift b/Sources/HPRTMP/Util/ArrayExtensions.swift index 202db93..185a57a 100644 --- a/Sources/HPRTMP/Util/ArrayExtensions.swift +++ b/Sources/HPRTMP/Util/ArrayExtensions.swift @@ -9,13 +9,13 @@ import Foundation public extension Array { subscript (safe range: CountableRange) -> ArraySlice? { - + if range.lowerBound < 0 || range.count > self.count { return nil } return self[range] } - + subscript (safe index: Index) -> Element? { return indices.contains(index) ? self[index] : nil } diff --git a/Sources/HPRTMP/Util/DataExtensions.swift b/Sources/HPRTMP/Util/DataExtensions.swift index d0996ef..8830231 100644 --- a/Sources/HPRTMP/Util/DataExtensions.swift +++ b/Sources/HPRTMP/Util/DataExtensions.swift @@ -11,19 +11,19 @@ public extension Data { mutating func write(_ value: UInt8) { write([value]) } - + mutating func write(_ value: [UInt8]) { self.append(contentsOf: value) } - + mutating func write(_ value: UInt16) { self.append(value.bigEndian.data) } - + mutating func write(_ value: UInt32) { self.append(value.bigEndian.data) } - + mutating func write24(_ value: Int32, bigEndian: Bool) { if bigEndian { let convert = value.bigEndian.data @@ -33,7 +33,7 @@ public extension Data { append(convert[0..) -> Data { - let range = Range(uncheckedBounds: (lower: Swift.max(0, r.lowerBound), - upper: Swift.min(count, r.upperBound))) + subscript (range: Range) -> Data { + let range = Range(uncheckedBounds: (lower: Swift.max(0, range.lowerBound), + upper: Swift.min(count, range.upperBound))) return self.subdata(in: range) } - + subscript (safe range: CountableRange) -> Data? { if range.lowerBound < 0 || range.upperBound > self.count { return nil } - + return self[range] } - + subscript (safe range: CountableClosedRange) -> Data? { if range.lowerBound < 0 || range.upperBound >= self.count { return nil } - + return self[range] } - + subscript (safe index: Int) -> UInt8? { if index > 0 && index < self.count { return self[index] @@ -87,5 +87,5 @@ extension UInt32 { } return Array(bytePtr) } - + } diff --git a/Sources/HPRTMP/Util/NWConnectionExtensions.swift b/Sources/HPRTMP/Util/NWConnectionExtensions.swift index e6c9e4e..cb7e61d 100644 --- a/Sources/HPRTMP/Util/NWConnectionExtensions.swift +++ b/Sources/HPRTMP/Util/NWConnectionExtensions.swift @@ -3,14 +3,14 @@ import Network extension NWConnection { static var maxReadSize = Int(UInt16.max) - - func sendData(_ datas: [Data]) async throws -> Void { + + func sendData(_ datas: [Data]) async throws { for data in datas { try await sendData(data) } } - func sendData(_ data: Data) async throws -> Void { + func sendData(_ data: Data) async throws { try await withCheckedThrowingContinuation { (continuation: CheckedContinuation) in self.send(content: data, completion: .contentProcessed({error in if let error = error { @@ -21,19 +21,19 @@ extension NWConnection { })) } } - + func receiveData() async throws -> Data { try await withCheckedThrowingContinuation { [weak self]continuation in guard let self else { continuation.resume(returning: Data()) return } - self.receive(minimumIncompleteLength: 0, maximumLength: NWConnection.maxReadSize) { data, context, isComplete, error in + self.receive(minimumIncompleteLength: 0, maximumLength: NWConnection.maxReadSize) { data, _, _, error in if let error { continuation.resume(throwing: error) return } - + guard let data else { continuation.resume(returning: Data()) return diff --git a/Sources/HPRTMP/WindowControl.swift b/Sources/HPRTMP/WindowControl.swift index adc8284..ee73d59 100644 --- a/Sources/HPRTMP/WindowControl.swift +++ b/Sources/HPRTMP/WindowControl.swift @@ -1,32 +1,31 @@ import Foundation - actor WindowControl { - + let defaultWindowSize: UInt32 = 250000 - + var windowSize: UInt32 - + var totalInBytesCount: UInt32 = 0 var totalInBytesSeq: UInt32 = 1 var totalOutBytesCount: UInt32 = 0 var totalOutBytesSeq: UInt32 = 1 - var inBytesWindowEvent: ((UInt32) async -> Void)? = nil + var inBytesWindowEvent: ((UInt32) async -> Void)? - func setInBytesWindowEvent(_ inBytesWindowEvent:((UInt32) async -> Void)?) { + func setInBytesWindowEvent(_ inBytesWindowEvent: ((UInt32) async -> Void)?) { self.inBytesWindowEvent = inBytesWindowEvent } - + func setWindowSize(_ size: UInt32) { self.windowSize = size } - + init() { self.windowSize = defaultWindowSize } - + func addInBytesCount(_ count: UInt32) async { totalInBytesCount += count if totalInBytesCount >= windowSize * totalInBytesSeq { @@ -34,7 +33,7 @@ actor WindowControl { totalInBytesSeq += 1 } } - + func addOutBytesCount(_ count: UInt32) { totalOutBytesCount += count if totalOutBytesCount >= windowSize * totalOutBytesSeq { diff --git a/Tests/HPRTMPTests/AFM0DecodeTests.swift b/Tests/HPRTMPTests/AFM0DecodeTests.swift index 831ba79..8832a7f 100644 --- a/Tests/HPRTMPTests/AFM0DecodeTests.swift +++ b/Tests/HPRTMPTests/AFM0DecodeTests.swift @@ -9,7 +9,7 @@ import XCTest @testable import HPRTMP class AMF0DecoderTests: XCTestCase { - + func testDecodeNumber() { let data = 123.amf0Value let decoder = AMF0Decoder() @@ -23,7 +23,7 @@ class AMF0DecoderTests: XCTestCase { let result = decoder.decodeAMF0(data) XCTAssertEqual(result?.first as? Double, number) } - + func testEncodeDecodeString() { let string = "Hello, world!" let data = string.amf0Value @@ -31,7 +31,7 @@ class AMF0DecoderTests: XCTestCase { let result = decoder.decodeAMF0(data) XCTAssertEqual(result?.first as? String, string) } - + func testEncodeDecodeLongString() { let longString = "This is a long string that exceeds the maximum size of a regular string in AMF0, which is 65535 bytes." let data = longString.amf0Value @@ -39,7 +39,7 @@ class AMF0DecoderTests: XCTestCase { let result = decoder.decodeAMF0(data) XCTAssertEqual(result?.first as? String, longString) } - + func testEncodeDecodeBoolean() { let boolean = true let data = boolean.amf0Value @@ -47,26 +47,25 @@ class AMF0DecoderTests: XCTestCase { let result = decoder.decodeAMF0(data) XCTAssertEqual(result?.first as? Bool, boolean) } - + func testEncodeDecodeNull() { let data = Data([0x05]) let decoder = AMF0Decoder() let result = decoder.decodeAMF0(data) XCTAssertEqual(result?.first as? String, "null") } - - + func testEncodeDecodeObject() { - let object: [String : Any] = ["foo": "bar", "baz": 123] + let object: [String: Any] = ["foo": "bar", "baz": 123] let data = object.amf0Encode let decoder = AMF0Decoder() let result = decoder.decodeAMF0(data) - + let dic = result?.first as? [String: Any] XCTAssertEqual(dic?["foo"] as! String, "bar") XCTAssertEqual(dic?["baz"] as! Double, 123) } - + func testEncodeDecodeArray() { let array = ["foo", "bar", 123] as [Any] let data = array.amf0Value @@ -77,7 +76,7 @@ class AMF0DecoderTests: XCTestCase { XCTAssertEqual(resultArray?[1] as? String, "bar") XCTAssertEqual(resultArray?[2] as? Double, 123) } - + func testEncodeDecodeDate() { let date = Date(timeIntervalSince1970: 1234567890) let data = date.amf0Value @@ -85,7 +84,7 @@ class AMF0DecoderTests: XCTestCase { let result = decoder.decodeAMF0(data) XCTAssertEqual(result?.first as? Date, date) } - + func testEncodeDecodeXML() { let xml = "bar" let data = xml.amf0Value @@ -93,5 +92,5 @@ class AMF0DecoderTests: XCTestCase { let result = decoder.decodeAMF0(data) XCTAssertEqual(result?.first as? String, xml) } - + } diff --git a/Tests/HPRTMPTests/AMF0EncodeTests.swift b/Tests/HPRTMPTests/AMF0EncodeTests.swift index 20f4d64..0db452a 100644 --- a/Tests/HPRTMPTests/AMF0EncodeTests.swift +++ b/Tests/HPRTMPTests/AMF0EncodeTests.swift @@ -18,15 +18,15 @@ extension Data { } final class AMF0EncodeTests: XCTestCase { - + override func setUpWithError() throws { // Put setup code here. This method is called before the invocation of each test method in the class. } - + override func tearDownWithError() throws { // Put teardown code here. This method is called after the invocation of each test method in the class. } - + func testEncoding() { // Number XCTAssertEqual(123.amf0Value, Data([0x00, 0x40, 0x5E, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00])) @@ -35,14 +35,14 @@ final class AMF0EncodeTests: XCTestCase { // Boolean XCTAssertEqual(true.amf0Value, Data([0x01, 0x01])) XCTAssertEqual(false.amf0Value, Data([0x01, 0x00])) - + // String XCTAssertEqual("hello".amf0Value, Data([0x02, 0x00, 0x05, 0x68, 0x65, 0x6C, 0x6C, 0x6F])) - + // Long String let longString = String(repeating: "a", count: Int(UInt16.max) + 1) XCTAssertEqual(longString.amf0Value, Data([0x0c, 0x00, 0x01, 0x00, 0x00] + Array(repeating: 0x61, count: Int(UInt16.max) + 1))) - + // Date let date = Date(timeIntervalSince1970: 10.12) XCTAssertEqual(date.amf0Value, Data([0x0b, 0x0, 0x0, 0x0, 0x0, 0x0, 0xc4, 0xc3, 0x40, 0x0, 0x0])) @@ -51,13 +51,13 @@ final class AMF0EncodeTests: XCTestCase { let object = ["name": "John", "age": 30] as [String: Any] let expectedObjectData1 = Data([0x03, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x02, 0x00, 0x04, 0x4A, 0x6F, 0x68, 0x6E, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, 0x40, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09]) let expectedObjectData2 = Data([0x03, 0x00, 0x03, 0x61, 0x67, 0x65, 0x00, 0x40, 0x3E, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x6E, 0x61, 0x6D, 0x65, 0x02, 0x00, 0x04, 0x4A, 0x6F, 0x68, 0x6E, 0x00, 0x00, 0x09]) - + XCTAssert(object.amf0Encode == expectedObjectData1 || object.amf0Encode == expectedObjectData2) // Simple array with Int, String, and Double values let array: [Any] = [1, "two", 3.0] XCTAssertEqual(array.amf0Value, Data([0x0A, 0x00, 0x00, 0x00, 0x03, 0x00, 0x3F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x03, 0x74, 0x77, 0x6F, 0x00, 0x40, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])) - + // Array of dictionaries let dict1: [String: Any] = ["name": "John"] let dict2: [String: Any] = ["name": "Jane"] diff --git a/Tests/HPRTMPTests/BasicHeaderTests.swift b/Tests/HPRTMPTests/BasicHeaderTests.swift index 9ec5fbf..2a241f4 100644 --- a/Tests/HPRTMPTests/BasicHeaderTests.swift +++ b/Tests/HPRTMPTests/BasicHeaderTests.swift @@ -12,34 +12,34 @@ class BasicHeaderTests: XCTestCase { func testEncodeForStreamIdLessThanOrEqualTo63() { let header = BasicHeader(streamId: 63, type: .type0) let encodedData = header.encode() - + XCTAssertEqual(encodedData, Data([0 << 6 | 63])) } - + func testEncodeForStreamIdLessThanOrEqualTo319() { let header = BasicHeader(streamId: 319, type: .type1) let encodedData = header.encode() - + XCTAssertEqual(encodedData, Data([(1 << 6) | 0, 255])) } - + func testEncodeForStreamIdGreaterThan319() { let header = BasicHeader(streamId: 320, type: .type2) let encodedData = header.encode() - + let expectedData = Data([(2 << 6) | 0b00000001] + (UInt16(320 - 64)).bigEndian.data) XCTAssertEqual(encodedData, expectedData) } - + func testEncodeForDifferentTypes() { let header1 = BasicHeader(streamId: 319, type: .type0) let encodedData1 = header1.encode() - + XCTAssertEqual(encodedData1, Data([(0 << 6) | 0, 255])) - + let header2 = BasicHeader(streamId: 63, type: .type3) let encodedData2 = header2.encode() - + XCTAssertEqual(encodedData2, Data([(3 << 6) | 0b00111111])) } } diff --git a/Tests/HPRTMPTests/ChunkDecoderTests.swift b/Tests/HPRTMPTests/ChunkDecoderTests.swift index e50e419..5a6b76b 100644 --- a/Tests/HPRTMPTests/ChunkDecoderTests.swift +++ b/Tests/HPRTMPTests/ChunkDecoderTests.swift @@ -11,44 +11,44 @@ import XCTest class MessageDecoderTests: XCTestCase { func testDecodeMessage_SingleChunk() async { let decoder = MessageDecoder() - + // Prepare your test data here, which should be a Data object containing a single RTMP chunk. let basicHeader = BasicHeader(streamId: 10, type: .type0) let targetMessageHeader = MessageHeaderType0(timestamp: 100, messageLength: 9, type: .audio, messageStreamId: 15) - + var payload = Data() payload.writeU24(1, bigEndian: true) payload.writeU24(1, bigEndian: true) payload.writeU24(1, bigEndian: true) - + let targetChunk = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader, messageHeader: targetMessageHeader), chunkData: payload) let data = targetChunk.encode() - + let (message, chunkSize) = await decoder.decodeMessage(data: data) - + XCTAssertNotNil(message) XCTAssertTrue(message is AudioMessage) let audioMessage = message as? AudioMessage XCTAssertEqual(audioMessage?.data, payload) XCTAssertEqual(audioMessage?.timestamp, 100) XCTAssertEqual(audioMessage?.msgStreamId, 15) - + XCTAssertEqual(chunkSize, data.count) } func testDecodeMessage_MultipleChunks() async { let decoder = MessageDecoder() - + // Prepare your test data here, which should be a Data object containing multiple RTMP chunks. let basicHeader = BasicHeader(streamId: 10, type: .type0) let targetMessageHeader = MessageHeaderType0(timestamp: 100, messageLength: 307, type: .audio, messageStreamId: 15) - + var payload = Data() (0..<128).forEach { _ in payload.write(UInt8(1)) } - + let targetChunk = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader, messageHeader: targetMessageHeader), chunkData: payload) - + let basicHeader2 = BasicHeader(streamId: 10, type: .type3) let messageHeader2 = MessageHeaderType3() var payload2 = Data() @@ -56,7 +56,7 @@ class MessageDecoderTests: XCTestCase { payload2.write(UInt8(1)) } let secondChunk = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader2, messageHeader: messageHeader2), chunkData: payload2) - + let basicHeader3 = BasicHeader(streamId: 10, type: .type3) let messageHeader3 = MessageHeaderType3() var payload3 = Data() @@ -64,189 +64,185 @@ class MessageDecoderTests: XCTestCase { payload3.write(UInt8(1)) } let chunk3 = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader3, messageHeader: messageHeader3), chunkData: payload3) - - + // Encode the target chunk multiple times to simulate multiple chunks in the data. let data = targetChunk.encode() + secondChunk.encode() + chunk3.encode() - + let (message, chunkSize) = await decoder.decodeMessage(data: data) - + XCTAssertNotNil(message) XCTAssertTrue(message is AudioMessage) let audioMessage = message as? AudioMessage XCTAssertEqual(audioMessage?.data.count, 307) XCTAssertEqual(audioMessage?.timestamp, 100) XCTAssertEqual(audioMessage?.msgStreamId, 15) - + // Adjust the expected chunk size based on the number of chunks in the test data. XCTAssertEqual(chunkSize, data.count) } - + func testDecodeMessage_InvalidData() async { let decoder = MessageDecoder() let basicHeader = BasicHeader(streamId: 10, type: .type0) let targetMessageHeader = MessageHeaderType0(timestamp: 100, messageLength: 307, type: .audio, messageStreamId: 15) - + var payload = Data() (0..<128).forEach { _ in payload.write(UInt8(1)) } - + let targetChunk = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader, messageHeader: targetMessageHeader), chunkData: payload) - + let data = targetChunk.chunkData - + let (message, chunkSize) = await decoder.decodeMessage(data: data) - + XCTAssertNil(message) XCTAssertEqual(chunkSize, 0) } - - + func testCreateMessage() async { let decoder = MessageDecoder() - + let chunkStreamId: UInt16 = 1 let msgStreamId = 1 let timestamp: UInt32 = 100 let chunkPayload = Data([0, 1, 2, 3]) - + let chunkSizeMessage = await decoder.createMessage(chunkStreamId: chunkStreamId, msgStreamId: msgStreamId, messageType: .chunkSize, timestamp: timestamp, chunkPayload: chunkPayload) XCTAssertTrue(chunkSizeMessage is ChunkSizeMessage) - + let controlMessage = await decoder.createMessage(chunkStreamId: chunkStreamId, msgStreamId: msgStreamId, messageType: .control, timestamp: timestamp, chunkPayload: chunkPayload) XCTAssertTrue(controlMessage is ControlMessage) - + let peerBandwidthMessage = await decoder.createMessage(chunkStreamId: chunkStreamId, msgStreamId: msgStreamId, messageType: .peerBandwidth, timestamp: timestamp, chunkPayload: chunkPayload) XCTAssertTrue(peerBandwidthMessage is PeerBandwidthMessage) - - let commandMessagePayload: Data = "connect".amf0Value + 5.amf0Value + ["object":"haha"].amf0Encode + ["info": "test"].amf0Encode + + let commandMessagePayload: Data = "connect".amf0Value + 5.amf0Value + ["object": "haha"].amf0Encode + ["info": "test"].amf0Encode let commandMessage = await decoder.createMessage(chunkStreamId: chunkStreamId, msgStreamId: msgStreamId, messageType: .command(type: .amf0), timestamp: timestamp, chunkPayload: commandMessagePayload) XCTAssertTrue(commandMessage is CommandMessage) - + let dataMessage = await decoder.createMessage(chunkStreamId: chunkStreamId, msgStreamId: msgStreamId, messageType: .data(type: .amf0), timestamp: timestamp, chunkPayload: chunkPayload) XCTAssertTrue(dataMessage is DataMessage) - + let audioMessage = await decoder.createMessage(chunkStreamId: chunkStreamId, msgStreamId: msgStreamId, messageType: .audio, timestamp: timestamp, chunkPayload: chunkPayload) XCTAssertTrue(audioMessage is AudioMessage) - + let videoMessage = await decoder.createMessage(chunkStreamId: chunkStreamId, msgStreamId: msgStreamId, messageType: .video, timestamp: timestamp, chunkPayload: chunkPayload) XCTAssertTrue(videoMessage is VideoMessage) - + let abortMessage = await decoder.createMessage(chunkStreamId: chunkStreamId, msgStreamId: msgStreamId, messageType: .abort, timestamp: timestamp, chunkPayload: chunkPayload) XCTAssertTrue(abortMessage is AbortMessage) - + let acknowledgementMessage = await decoder.createMessage(chunkStreamId: chunkStreamId, msgStreamId: msgStreamId, messageType: .acknowledgement, timestamp: timestamp, chunkPayload: chunkPayload) XCTAssertTrue(acknowledgementMessage is AcknowledgementMessage) - + let windowAckMessage = await decoder.createMessage(chunkStreamId: chunkStreamId, msgStreamId: msgStreamId, messageType: .windowAcknowledgement, timestamp: timestamp, chunkPayload: chunkPayload) XCTAssertTrue(windowAckMessage is WindowAckMessage) } - -} +} class ChunkDecoderTests: XCTestCase { - + // test decode chunk data - + func testDecodeChunkWithEmptyData() async { let data = Data() let decoder = ChunkDecoder() - + let (chunk, size) = await decoder.decodeChunk(data: data) XCTAssertNil(chunk) XCTAssertEqual(size, 0) } - + // Add more test cases with valid data inputs representing different scenarios. // For example, you can create Data objects with various message header types, chunk sizes, // and message lengths, then test if the decodeChunk function returns the correct output. - + func testDecodeChunkWithValidMessageHeaderType0() async { // Prepare Data object with valid MessageHeaderType0 let basicHeader = BasicHeader(streamId: 10, type: .type0) let targetMessageHeader = MessageHeaderType0(timestamp: 100, messageLength: 9, type: .audio, messageStreamId: 15) - + var payload = Data() payload.writeU24(1, bigEndian: true) payload.writeU24(1, bigEndian: true) payload.writeU24(1, bigEndian: true) - + let targetChunk = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader, messageHeader: targetMessageHeader), chunkData: payload) let data = targetChunk.encode() - + let decoder = ChunkDecoder() - + let (chunk, size) = await decoder.decodeChunk(data: data) XCTAssertNotNil(chunk) XCTAssertEqual(size, data.count) - - + // Test specific properties of the chunk and headers XCTAssertEqual(chunk?.chunkHeader.basicHeader.type, .type0) XCTAssertEqual(chunk?.chunkHeader.basicHeader.streamId, 10) - + XCTAssertTrue(chunk?.chunkHeader.messageHeader is MessageHeaderType0) - + let messageHeader = chunk?.chunkHeader.messageHeader as? MessageHeaderType0 XCTAssertEqual(messageHeader?.timestamp, 100) XCTAssertEqual(messageHeader?.messageLength, 9) XCTAssertEqual(messageHeader?.messageStreamId, 15) XCTAssertEqual(messageHeader?.type, .audio) - + // Test other properties and conditions depending on your specific scenario XCTAssertEqual(chunk?.chunkData, payload) } - + func testDecodeChunkWithValidMessageHeaderType1() async { // Prepare Data object with valid MessageHeaderType1 let basicHeader = BasicHeader(streamId: 10, type: .type1) let targetMessageHeader = MessageHeaderType1(timestampDelta: 50, messageLength: 9, type: .video) - + var payload = Data() payload.writeU24(1, bigEndian: true) payload.writeU24(1, bigEndian: true) payload.writeU24(1, bigEndian: true) - + let targetChunk = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader, messageHeader: targetMessageHeader), chunkData: payload) let data = targetChunk.encode() - + let decoder = ChunkDecoder() - + let (chunk, size) = await decoder.decodeChunk(data: data) XCTAssertNotNil(chunk) XCTAssertEqual(size, data.count) - + // Test specific properties of the chunk and headers XCTAssertEqual(chunk?.chunkHeader.basicHeader.type, .type1) XCTAssertEqual(chunk?.chunkHeader.basicHeader.streamId, 10) - + XCTAssertTrue(chunk?.chunkHeader.messageHeader is MessageHeaderType1) - + let messageHeader = chunk?.chunkHeader.messageHeader as? MessageHeaderType1 XCTAssertEqual(messageHeader?.timestampDelta, 50) XCTAssertEqual(messageHeader?.messageLength, 9) XCTAssertEqual(messageHeader?.type, .video) XCTAssertEqual(chunk?.chunkData, payload) } - + func testDecodeChunkWithValidMessageHeaderType2() async { let decoder = ChunkDecoder() - + let basicHeader0 = BasicHeader(streamId: 10, type: .type0) let targetMessageHeader0 = MessageHeaderType0(timestamp: 100, messageLength: 9, type: .audio, messageStreamId: 15) - + var payload0 = Data() payload0.writeU24(1, bigEndian: true) payload0.writeU24(1, bigEndian: true) payload0.writeU24(1, bigEndian: true) - + let chunk0 = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader0, messageHeader: targetMessageHeader0), chunkData: payload0) let chunkData0 = chunk0.encode() - - let _ = await decoder.decodeChunk(data: chunkData0) - + + _ = await decoder.decodeChunk(data: chunkData0) + // Prepare Data object with valid MessageHeaderType2 let basicHeader = BasicHeader(streamId: 10, type: .type2) let targetMessageHeader = MessageHeaderType2(timestampDelta: 50) @@ -254,322 +250,316 @@ class ChunkDecoderTests: XCTestCase { payload.writeU24(1, bigEndian: true) payload.writeU24(1, bigEndian: true) payload.writeU24(1, bigEndian: true) - + let targetChunk = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader, messageHeader: targetMessageHeader), chunkData: payload) let data = targetChunk.encode() - - + // Assume a previous chunk with same streamId and messageLength exists let messageLength = await decoder.messageDataLengthMap[10] XCTAssertEqual(messageLength, 9) - + let (chunk, size) = await decoder.decodeChunk(data: data) XCTAssertNotNil(chunk) XCTAssertEqual(size, data.count) - + // Test specific properties of the chunk and headers XCTAssertEqual(chunk?.chunkHeader.basicHeader.type, .type2) XCTAssertEqual(chunk?.chunkHeader.basicHeader.streamId, 10) - + XCTAssertTrue(chunk?.chunkHeader.messageHeader is MessageHeaderType2) - + let messageHeader = chunk?.chunkHeader.messageHeader as? MessageHeaderType2 XCTAssertEqual(messageHeader?.timestampDelta, 50) XCTAssertEqual(chunk?.chunkData, payload) } - + func testDecodeChunkWithValidMessageHeaderType3() async { let decoder = ChunkDecoder() - + let basicHeader0 = BasicHeader(streamId: 10, type: .type0) let targetMessageHeader0 = MessageHeaderType0(timestamp: 100, messageLength: 9, type: .audio, messageStreamId: 15) - + var payload0 = Data() payload0.writeU24(1, bigEndian: true) payload0.writeU24(1, bigEndian: true) payload0.writeU24(1, bigEndian: true) - + let chunk0 = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader0, messageHeader: targetMessageHeader0), chunkData: payload0) let chunkData0 = chunk0.encode() - - let _ = await decoder.decodeChunk(data: chunkData0) - + + _ = await decoder.decodeChunk(data: chunkData0) + // Prepare Data object with valid MessageHeaderType3 let basicHeader = BasicHeader(streamId: 10, type: .type3) var payload = Data() payload.writeU24(1, bigEndian: true) payload.writeU24(1, bigEndian: true) payload.writeU24(1, bigEndian: true) - + let targetMessageHeader = MessageHeaderType3() let targetChunk = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader, messageHeader: targetMessageHeader), chunkData: payload) let data = targetChunk.encode() - + // Assume a previous chunk with same streamId and messageLength exists let messageLength = await decoder.messageDataLengthMap[10] XCTAssertEqual(messageLength, 9) - + let (chunk, size) = await decoder.decodeChunk(data: data) XCTAssertNotNil(chunk) XCTAssertEqual(size, data.count) - + // Test specific properties of the chunk and headers XCTAssertEqual(chunk?.chunkHeader.basicHeader.type, MessageHeaderType.type3) XCTAssertEqual(chunk?.chunkHeader.basicHeader.streamId, 10) - + XCTAssertTrue(chunk?.chunkHeader.messageHeader is MessageHeaderType3) - + // Test other properties and conditions depending on your specific scenario XCTAssertEqual(chunk?.chunkData, payload) } - + func testDecodeChunkWithValidMessageHeaderType3WithLongPayload() async { let decoder = ChunkDecoder() - + let basicHeader0 = BasicHeader(streamId: 10, type: .type0) let targetMessageHeader0 = MessageHeaderType0(timestamp: 100, messageLength: 300, type: .audio, messageStreamId: 15) - + var payload0 = Data() (0..<128).forEach { _ in payload0.write(UInt8(1)) } - + let chunk0 = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader0, messageHeader: targetMessageHeader0), chunkData: payload0) let chunkData0 = chunk0.encode() - - let _ = await decoder.decodeChunk(data: chunkData0) - + + _ = await decoder.decodeChunk(data: chunkData0) + var remainMessageLength = await decoder.remainDataLengthMap[10] XCTAssertEqual(remainMessageLength, 300 - 128) - + // Prepare Data object with valid MessageHeaderType3 let basicHeader = BasicHeader(streamId: 10, type: .type3) var payload = Data() (0..<128).forEach { _ in payload.write(UInt8(1)) } - + let targetMessageHeader = MessageHeaderType3() let targetChunk = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader, messageHeader: targetMessageHeader), chunkData: payload) let data = targetChunk.encode() - + let (chunk, size) = await decoder.decodeChunk(data: data) - + remainMessageLength = await decoder.remainDataLengthMap[10] XCTAssertEqual(remainMessageLength, 300 - 128 - 128) - + XCTAssertNotNil(chunk) XCTAssertEqual(size, data.count) - + // Test specific properties of the chunk and headers XCTAssertEqual(chunk?.chunkHeader.basicHeader.type, MessageHeaderType.type3) XCTAssertEqual(chunk?.chunkHeader.basicHeader.streamId, 10) - + XCTAssertTrue(chunk?.chunkHeader.messageHeader is MessageHeaderType3) - + // Test other properties and conditions depending on your specific scenario XCTAssertEqual(chunk?.chunkData, payload) - - - + let basicHeader2 = BasicHeader(streamId: 10, type: .type3) var payload2 = Data() (0..<44).forEach { _ in payload2.write(UInt8(1)) } - + let targetMessageHeader2 = MessageHeaderType3() let targetChunk2 = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader2, messageHeader: targetMessageHeader2), chunkData: payload2) let data2 = targetChunk2.encode() - + let (chunk2, size2) = await decoder.decodeChunk(data: data2) - + remainMessageLength = await decoder.remainDataLengthMap[10] XCTAssertEqual(remainMessageLength, nil) - + XCTAssertNotNil(chunk2) XCTAssertEqual(size2, data2.count) - + // Test specific properties of the chunk and headers XCTAssertEqual(chunk2?.chunkHeader.basicHeader.type, MessageHeaderType.type3) XCTAssertEqual(chunk2?.chunkHeader.basicHeader.streamId, 10) - + XCTAssertTrue(chunk2?.chunkHeader.messageHeader is MessageHeaderType3) - + // Test other properties and conditions depending on your specific scenario XCTAssertEqual(chunk2?.chunkData, payload2) } - + func testDecodeChunkWithValidMessageHeaderType2WithLongPayload() async { let decoder = ChunkDecoder() - + let basicHeader1 = BasicHeader(streamId: 10, type: .type0) let targetMessageHeader1 = MessageHeaderType0(timestamp: 100, messageLength: 300, type: .audio, messageStreamId: 15) - + var payload1 = Data() (0..<128).forEach { _ in payload1.write(UInt8(1)) } - + let chunk1 = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader1, messageHeader: targetMessageHeader1), chunkData: payload1) let chunkData1 = chunk1.encode() - - let _ = await decoder.decodeChunk(data: chunkData1) - + + _ = await decoder.decodeChunk(data: chunkData1) + var remainMessageLength = await decoder.remainDataLengthMap[10] XCTAssertEqual(remainMessageLength, 300 - 128) - + // Prepare Data object with valid MessageHeaderType3 let basicHeader = BasicHeader(streamId: 10, type: .type2) var payload = Data() (0..<128).forEach { _ in payload.write(UInt8(1)) } - + let targetMessageHeader = MessageHeaderType2(timestampDelta: 100) let targetChunk = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader, messageHeader: targetMessageHeader), chunkData: payload) let data = targetChunk.encode() - + let (chunk, size) = await decoder.decodeChunk(data: data) - + remainMessageLength = await decoder.remainDataLengthMap[10] XCTAssertEqual(remainMessageLength, 300 - 128 - 128) - + XCTAssertNotNil(chunk) XCTAssertEqual(size, data.count) - + // Test specific properties of the chunk and headers XCTAssertEqual(chunk?.chunkHeader.basicHeader.type, .type2) XCTAssertEqual(chunk?.chunkHeader.basicHeader.streamId, 10) - + XCTAssertTrue(chunk?.chunkHeader.messageHeader is MessageHeaderType2) - + let messageHeader = chunk?.chunkHeader.messageHeader as? MessageHeaderType2 XCTAssertEqual(messageHeader?.timestampDelta, 100) XCTAssertEqual(chunk?.chunkData, payload) - - + let basicHeader2 = BasicHeader(streamId: 10, type: .type2) var payload2 = Data() (0..<44).forEach { _ in payload2.write(UInt8(1)) } - + let targetMessageHeader2 = MessageHeaderType2(timestampDelta: 100) let targetChunk2 = Chunk(chunkHeader: ChunkHeader(basicHeader: basicHeader2, messageHeader: targetMessageHeader2), chunkData: payload2) let data2 = targetChunk2.encode() - + let (chunk2, size2) = await decoder.decodeChunk(data: data) - + remainMessageLength = await decoder.remainDataLengthMap[10] XCTAssertEqual(remainMessageLength, nil) - + XCTAssertNotNil(chunk2) XCTAssertEqual(size2, data2.count) - + // Test specific properties of the chunk and headers XCTAssertEqual(chunk2?.chunkHeader.basicHeader.type, .type2) XCTAssertEqual(chunk2?.chunkHeader.basicHeader.streamId, 10) - + XCTAssertTrue(chunk2?.chunkHeader.messageHeader is MessageHeaderType2) - + let messageHeader2 = chunk?.chunkHeader.messageHeader as? MessageHeaderType2 XCTAssertEqual(messageHeader2?.timestampDelta, 100) XCTAssertEqual(chunk2?.chunkData, payload2) } - - + func testBasicHeaderEmptyData() async throws { // Given let data = Data() let decoder = ChunkDecoder() - + // When let (header, length) = await decoder.decodeBasicHeader(data: data) - + // Then XCTAssertNil(header) XCTAssertEqual(length, 0) } - + func testBasicHeaderFormat0() async throws { // Given let data = Data([0x00]) let decoder = ChunkDecoder() - + // When let (header, length) = await decoder.decodeBasicHeader(data: data) - + // Then XCTAssertNil(header) XCTAssertEqual(length, 0) } - + func testBasicHeaderFormat0WithEncoder() async throws { let basicHeader = BasicHeader(streamId: 63, type: .type0) let data = basicHeader.encode() let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeBasicHeader(data: data) - + XCTAssertNotNil(header) XCTAssertEqual(length, 1) XCTAssertEqual(header?.streamId, 63) XCTAssertEqual(header?.type, .type0) } - + func testBasicHeaderFormat1() async throws { // Given let data = Data([0b01000000, 0b00000001]) let decoder = ChunkDecoder() - + // When let (header, length) = await decoder.decodeBasicHeader(data: data) - + // Then XCTAssertNotNil(header) XCTAssertEqual(length, 2) XCTAssertEqual(header?.streamId, 65) XCTAssertEqual(header?.type, .type1) } - + func testBasicHeaderFormatWithEncoder() async throws { // Given let basicHeader = BasicHeader(streamId: 65, type: .type1) let data = basicHeader.encode() let decoder = ChunkDecoder() - + // When let (header, length) = await decoder.decodeBasicHeader(data: data) - + // Then XCTAssertNotNil(header) XCTAssertEqual(length, 2) XCTAssertEqual(header?.streamId, 65) XCTAssertEqual(header?.type, .type1) } - + func testBasicHeaderFormat2() async throws { let basicHeader = BasicHeader(streamId: 320, type: .type1) let data = basicHeader.encode() let decoder = ChunkDecoder() - + // When let (header, length) = await decoder.decodeBasicHeader(data: data) - + // Then XCTAssertNotNil(header) XCTAssertEqual(length, 3) XCTAssertEqual(header?.streamId, 320) XCTAssertEqual(header?.type, .type1) } - - + func testMessageHeaderType0() async { let data: [UInt8] = [0x00, 0x01, 0x02, 0x00, 0x00, 0x04, 0x12, 0x00, 0x00, 0x00, 0x01] - + let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeMessageHeader(data: Data(data), type: .type0) XCTAssertEqual(length, 11) XCTAssertTrue(header is MessageHeaderType0) @@ -580,13 +570,13 @@ class ChunkDecoderTests: XCTestCase { let streamId = Data([0x00, 0x00, 0x00, 0x01]).uint32 XCTAssertEqual(headerType0.messageStreamId, Int(streamId)) } - + func testMessageHeaderType0WithEncode() async { let messageHeaderType0 = MessageHeaderType0(timestamp: 32, messageLength: 100, type: .audio, messageStreamId: 5) let data = messageHeaderType0.encode() - + let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeMessageHeader(data: data, type: .type0) XCTAssertEqual(length, 11) XCTAssertTrue(header is MessageHeaderType0) @@ -596,26 +586,26 @@ class ChunkDecoderTests: XCTestCase { XCTAssertEqual(headerType0.type, .audio) XCTAssertEqual(headerType0.messageStreamId, 5) } - + func testMessageHeaderType0ExtendTimestamp() async { let data: [UInt8] = [0xff, 0xff, 0xff, 0xff, 0x01, 0x00, 0x04, 0x12, 0x34, 0x56, 0x78, 0xff, 0xff, 0xff, 0xff] - + let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeMessageHeader(data: Data(data), type: .type0) XCTAssertEqual(length, 15) XCTAssertTrue(header is MessageHeaderType0) - + let headerType0 = header as! MessageHeaderType0 XCTAssertEqual(headerType0.timestamp, 4294967295) } - + func testMessageHeaderType0ExtendTimestampWithEncode() async { let messageHeaderType0 = MessageHeaderType0(timestamp: 32 + maxTimestamp, messageLength: 100, type: .audio, messageStreamId: 5) let data = messageHeaderType0.encode() - + let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeMessageHeader(data: data, type: .type0) XCTAssertEqual(length, 15) XCTAssertTrue(header is MessageHeaderType0) @@ -625,12 +615,12 @@ class ChunkDecoderTests: XCTestCase { XCTAssertEqual(headerType0.type, .audio) XCTAssertEqual(headerType0.messageStreamId, 5) } - + func testMessageHeaderType1() async { let data: [UInt8] = [0x00, 0x01, 0x02, 0x00, 0x00, 0x04, 0x02] - + let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeMessageHeader(data: Data(data), type: .type1) XCTAssertEqual(length, 7) XCTAssertTrue(header is MessageHeaderType1) @@ -639,13 +629,13 @@ class ChunkDecoderTests: XCTestCase { XCTAssertEqual(headerType1.messageLength, 0x000004) XCTAssertEqual(headerType1.type, .abort) } - + func testMessageHeaderType1WithEncode() async { let messageHeaderType1 = MessageHeaderType1(timestampDelta: 1234, messageLength: 456, type: .video) let data = messageHeaderType1.encode() - + let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeMessageHeader(data: data, type: .type1) XCTAssertEqual(length, 7) XCTAssertTrue(header is MessageHeaderType1) @@ -654,104 +644,103 @@ class ChunkDecoderTests: XCTestCase { XCTAssertEqual(headerType1.messageLength, 456) XCTAssertEqual(headerType1.type, .video) } - + func testMessageHeaderType2() async { let data: [UInt8] = [0x00, 0x01, 0x02] - + let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeMessageHeader(data: Data(data), type: .type2) XCTAssertEqual(length, 3) XCTAssertTrue(header is MessageHeaderType2) let headerType2 = header as! MessageHeaderType2 XCTAssertEqual(headerType2.timestampDelta, Data([0x02, 0x01, 0x00, 0x00]).uint32) } - + func testMessageHeaderType2WithEncode() async { let messageHeaderType2 = MessageHeaderType2(timestampDelta: 1234) let data = messageHeaderType2.encode() - + let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeMessageHeader(data: data, type: .type2) XCTAssertEqual(length, 3) XCTAssertTrue(header is MessageHeaderType2) let headerType2 = header as! MessageHeaderType2 XCTAssertEqual(headerType2.timestampDelta, 1234) } - - + func testMessageHeaderType3() async { let data: [UInt8] = [] - + let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeMessageHeader(data: Data(data), type: .type3) XCTAssertEqual(length, 0) XCTAssertTrue(header is MessageHeaderType3) } - + func testMessageHeaderType3WithEncode() async { let messageHeaderType3 = MessageHeaderType3() let data = messageHeaderType3.encode() - + let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeMessageHeader(data: data, type: .type3) XCTAssertEqual(length, 0) XCTAssertTrue(header is MessageHeaderType3) } - + func testMessageHeaderType0InvalidData() async { let data: [UInt8] = [0x00, 0x01, 0x02, 0x00, 0x00, 0x04, 0x12, 0x34, 0x56] - + let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeMessageHeader(data: Data(data), type: .type0) XCTAssertNil(header) XCTAssertEqual(length, 0) } - + func testMessageHeaderType1InvalidData() async { let data: [UInt8] = [0x00, 0x01, 0x02, 0x00, 0x00, 0x04] - + let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeMessageHeader(data: Data(data), type: .type1) XCTAssertNil(header) XCTAssertEqual(length, 0) } - + func testMessageHeaderType2InvalidData() async { let data: [UInt8] = [0x00, 0x01] - + let decoder = ChunkDecoder() - + let (header, length) = await decoder.decodeMessageHeader(data: Data(data), type: .type2) XCTAssertNil(header) XCTAssertEqual(length, 0) } - + func testDecodeChunkDataNoEnoughData() async { let messageLength = 32 let data = Data(repeating: 0xff, count: 25) - + let decoder = ChunkDecoder() - + let (chunkData, chunkSize) = await decoder.decodeChunkData(data: data, messageLength: messageLength) - + XCTAssertNil(chunkData) XCTAssertEqual(chunkSize, 0) } - + func testDecodeChunkDataLessThan256() async { let messageLength = 32 let data = Data(repeating: 0xff, count: 256) - + let decoder = ChunkDecoder() - + let (chunkData, chunkSize) = await decoder.decodeChunkData(data: data, messageLength: messageLength) - + XCTAssertEqual(chunkData?.count, 32) XCTAssertEqual(chunkSize, 32) } diff --git a/Tests/HPRTMPTests/ChunkEncoderTests.swift b/Tests/HPRTMPTests/ChunkEncoderTests.swift index 055a6f8..3656917 100644 --- a/Tests/HPRTMPTests/ChunkEncoderTests.swift +++ b/Tests/HPRTMPTests/ChunkEncoderTests.swift @@ -9,14 +9,14 @@ import XCTest @testable import HPRTMP final class ChunkEncoderTests: XCTestCase { - + func testSingleChunkFirst() throws { let message = AudioMessage(msgStreamId: 10, data: Data([0x01, 0x02, 0x03, 0x04]), timestamp: 1234) let encoder = ChunkEncoder() - + // When let chunks = encoder.chunk(message: message, isFirstType0: true) - + // Then XCTAssertEqual(chunks.count, 1) let firstChunk = chunks[0] @@ -30,14 +30,14 @@ final class ChunkEncoderTests: XCTestCase { XCTAssertEqual(messageHeader.type, .audio) XCTAssertEqual(firstChunk.chunkData, Data([0x01, 0x02, 0x03, 0x04])) } - + func testSingleChunkNotFirst() throws { let message = AudioMessage(msgStreamId: 10, data: Data([0x01, 0x02, 0x03, 0x04]), timestamp: 1234) let encoder = ChunkEncoder() - + // When let chunks = encoder.chunk(message: message, isFirstType0: false) - + // Then XCTAssertEqual(chunks.count, 1) let firstChunk = chunks[0] @@ -50,18 +50,18 @@ final class ChunkEncoderTests: XCTestCase { XCTAssertEqual(messageHeader.type, .audio) XCTAssertEqual(firstChunk.chunkData, Data([0x01, 0x02, 0x03, 0x04])) } - + func testChunk_multipleChunks() throws { let message = AudioMessage(msgStreamId: 10, data: Data([0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08]), timestamp: 1234) let encoder = ChunkEncoder() encoder.chunkSize = 4 - + // When let chunks = encoder.chunk(message: message) - + // Then XCTAssertEqual(chunks.count, 2) - + let chunk0 = chunks[0] let header0 = chunk0.chunkHeader XCTAssertTrue(header0.messageHeader is MessageHeaderType0) @@ -72,7 +72,7 @@ final class ChunkEncoderTests: XCTestCase { XCTAssertEqual(messageHeader0.type, .audio) XCTAssertEqual(messageHeader0.messageStreamId, 10) XCTAssertEqual(chunk0.chunkData, Data([0x01, 0x02, 0x03, 0x04])) - + let chunk1 = chunks[1] let header1 = chunk1.chunkHeader XCTAssertTrue(header1.messageHeader is MessageHeaderType3) diff --git a/Tests/HPRTMPTests/ChunkHeaderTests.swift b/Tests/HPRTMPTests/ChunkHeaderTests.swift index da1a099..ddea318 100644 --- a/Tests/HPRTMPTests/ChunkHeaderTests.swift +++ b/Tests/HPRTMPTests/ChunkHeaderTests.swift @@ -34,7 +34,7 @@ final class ChunkTests: XCTestCase { let chunkHeader2 = ChunkHeader(streamId: streamId, messageHeader: messageHeaderType2) XCTAssertEqual(chunkHeader2.basicHeader.type, .type2) - + let messageHeaderType3 = MessageHeaderType3() let chunkHeader3 = ChunkHeader(streamId: streamId, messageHeader: messageHeaderType3) diff --git a/Tests/HPRTMPTests/MessageHeaderTests.swift b/Tests/HPRTMPTests/MessageHeaderTests.swift index 880b74d..0abbfbc 100644 --- a/Tests/HPRTMPTests/MessageHeaderTests.swift +++ b/Tests/HPRTMPTests/MessageHeaderTests.swift @@ -9,7 +9,7 @@ import XCTest @testable import HPRTMP class MessageHeaderType0Tests: XCTestCase { - + func testEncodeWithMaxTimestamp() { let header = MessageHeaderType0(timestamp: 16777215, messageLength: 5, @@ -18,7 +18,7 @@ class MessageHeaderType0Tests: XCTestCase { let expected = Data([0xff, 0xff, 0xff, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x00]) XCTAssertEqual(header.encode(), expected) } - + func testEncodeWithExtendedTimestamp() { let header = MessageHeaderType0(timestamp: 16777216, messageLength: 5, @@ -27,17 +27,14 @@ class MessageHeaderType0Tests: XCTestCase { let expected = Data([0xff, 0xff, 0xff, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00]) XCTAssertEqual(header.encode(), expected) } - + func testEncodeWithSmallTimestamp() { let header = MessageHeaderType0(timestamp: 1, messageLength: 5, type: .video, messageStreamId: 1) let expected = Data([0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x09, 0x01, 0x00, 0x00, 0x00]) - - - - + XCTAssertEqual(header.encode(), expected) } } diff --git a/Tests/HPRTMPTests/RTMPHandshakeTests.swift b/Tests/HPRTMPTests/RTMPHandshakeTests.swift index 4baaae4..756ed60 100644 --- a/Tests/HPRTMPTests/RTMPHandshakeTests.swift +++ b/Tests/HPRTMPTests/RTMPHandshakeTests.swift @@ -9,50 +9,50 @@ import XCTest @testable import HPRTMP final class RTMPHandshakeTests: XCTestCase { - + override func setUpWithError() throws { // Put setup code here. This method is called before the invocation of each test method in the class. } - + override func tearDownWithError() throws { // Put teardown code here. This method is called after the invocation of each test method in the class. } - + func testC0C1PacketLength() async { let handshake = RTMPHandshake(dataSender: {_ in }, dataReceiver: { Data()}) - + let c0c1Packet = await handshake.c0c1Packet let expectedLength = 1537 // C0 chunk size (1 byte) + C1 chunk size (1536 bytes) - + XCTAssertEqual(c0c1Packet.count, expectedLength, "C0/C1 packet length is incorrect") } - + private func generateS1Packet() -> Data { var data = Data() - + // s1 timestamp let timestamp = UInt32(Date().timeIntervalSince1970).bigEndian data.write(timestamp) - + // s1 random data let randomSize = RTMPHandshake.packetSize - 4 // S1 timestamp is 4 bytes (0.. Date: Thu, 22 Jun 2023 02:04:18 +0900 Subject: [PATCH 2/5] fix swiftlint warning --- .swiftlint.yml | 10 ++++ HPRTMP.podspec | 2 +- Package.swift | 2 +- Sources/HPRTMP/AMF/AFM3Decode.swift | 12 ++--- Sources/HPRTMP/Message/CommandMessage.swift | 6 +-- Sources/HPRTMP/Message/DataMessage.swift | 15 +++--- Sources/HPRTMP/Message/RTMPResponse.swift | 51 +++++++++++---------- Sources/HPRTMP/RTMPHandshake.swift | 2 +- Sources/HPRTMP/RTMPPublishSession.swift | 2 +- Sources/HPRTMP/RTMPSocket.swift | 25 +++++----- 10 files changed, 66 insertions(+), 61 deletions(-) create mode 100644 .swiftlint.yml diff --git a/.swiftlint.yml b/.swiftlint.yml new file mode 100644 index 0000000..0cd8afc --- /dev/null +++ b/.swiftlint.yml @@ -0,0 +1,10 @@ +disabled_rules: + - cyclomatic_complexity +included: + - Sources + - Tests +#excluded: +# - "the place where i committed many coding sins" +line_length: 200 +#reporter: "json" +#allow_zero_lintable_files: true diff --git a/HPRTMP.podspec b/HPRTMP.podspec index 38714b1..8ceb934 100644 --- a/HPRTMP.podspec +++ b/HPRTMP.podspec @@ -5,7 +5,7 @@ Pod::Spec.new do |s| s.homepage = 'https://github.com/huiping192/HPRTMP' s.license = 'MIT' s.author = { 'huiping192' => 'huiping192@163.com' } - s.platforms = { :ios => '14.0', :osx => '11' } + s.platforms = { :ios => '14.0', :osx => '12' } s.source = { :git => 'https://github.com/huiping192/HPRTMP.git', :tag => s.version.to_s } s.swift_version = '5.5' diff --git a/Package.swift b/Package.swift index f3a4001..6768671 100644 --- a/Package.swift +++ b/Package.swift @@ -5,7 +5,7 @@ import PackageDescription let package = Package( name: "HPRTMP", - platforms: [.iOS(.v14), .macOS(.v11)], + platforms: [.iOS(.v14), .macOS(.v12)], products: [ .library( name: "HPRTMP", diff --git a/Sources/HPRTMP/AMF/AFM3Decode.swift b/Sources/HPRTMP/AMF/AFM3Decode.swift index 475dca7..30fba14 100644 --- a/Sources/HPRTMP/AMF/AFM3Decode.swift +++ b/Sources/HPRTMP/AMF/AFM3Decode.swift @@ -313,9 +313,7 @@ private extension Data { mutating func decodeVectorNumber(_ reference: inout AMF3ReferenceTable) throws -> [T] { var decodeData = [T]() let (length, type) = try self.decodeLengthWithType() - - guard let first = self.first, - let _ = AMF3EncodeType.Vector(rawValue: first) else { + guard let first = self.first, AMF3EncodeType.Vector(rawValue: first) != nil else { throw AMF3DecodeError.rangeError } self.remove(at: 0) @@ -355,7 +353,7 @@ private extension Data { switch objType { case .value: let range = 0.. (length: Int, type: AMF3EncodeType.U29) { let value = self.convertLength() - let length = value >> 1 let u29Raw = UInt8(value & 0x01) - guard let type = AMF3EncodeType.U29(rawValue: u29Raw) else { throw AMF3DecodeError.rangeError } @@ -391,12 +387,12 @@ private extension Data { if isEnd { break } lastIdx += 1 } - let value = numberArr.enumerated().reduce(0) { (rc, current) -> Int in + let value = numberArr.enumerated().reduce(0) { (rcValue, current) -> Int in var shift = (lastIdx-current.offset)*7 if lastIdx == 3 && current.offset != 3 { shift += 1 } - return rc + Int(current.element) << shift + return rcValue + Int(current.element) << shift } return value diff --git a/Sources/HPRTMP/Message/CommandMessage.swift b/Sources/HPRTMP/Message/CommandMessage.swift index 2223539..69d1a93 100644 --- a/Sources/HPRTMP/Message/CommandMessage.swift +++ b/Sources/HPRTMP/Message/CommandMessage.swift @@ -181,9 +181,9 @@ class DeleteStreamMessage: CommandMessage, Encodable { } public enum PubishType: String { - case live = "live" - case record = "record" - case append = "append" + case live + case record + case append } class PublishMessage: CommandMessage, Encodable { diff --git a/Sources/HPRTMP/Message/DataMessage.swift b/Sources/HPRTMP/Message/DataMessage.swift index c213c01..7a29771 100644 --- a/Sources/HPRTMP/Message/DataMessage.swift +++ b/Sources/HPRTMP/Message/DataMessage.swift @@ -35,14 +35,15 @@ public class RTMPBaseMessage: RTMPMessage { self.streamId = streamId } - private var _timeInterval: UInt32 = 0 - public var timestamp: UInt32 { - set { - _timeInterval = newValue >= maxTimestamp ? maxTimestamp : newValue - } get { - return _timeInterval - } + private var _timeInterval: UInt32 = 0 + public var timestamp: UInt32 { + get { + return _timeInterval } + set { + _timeInterval = newValue >= maxTimestamp ? maxTimestamp : newValue + } + } } class DataMessage: RTMPBaseMessage { diff --git a/Sources/HPRTMP/Message/RTMPResponse.swift b/Sources/HPRTMP/Message/RTMPResponse.swift index f241822..65325dd 100644 --- a/Sources/HPRTMP/Message/RTMPResponse.swift +++ b/Sources/HPRTMP/Message/RTMPResponse.swift @@ -24,9 +24,9 @@ struct ConnectResponse { struct StatusResponse: Decodable { enum Level: String, Decodable { - case warning = "warning" - case status = "status" - case error = "error" + case warning + case status + case error } enum StreamStatus: String, Decodable { @@ -123,27 +123,27 @@ public struct MetaDataResponse { public var audiocodecid: String = "" enum CodingKeys: String, CodingKey { - case duration = "duration" - case height = "height" - case frameWidth = "frameWidth" - case moovposition = "moovposition" - case framerate = "framerate" - case avcprofile = "avcprofile" - case videocodecid = "videocodecid" - case frameHeight = "frameHeight" - case videoframerate = "videoframerate" - case audiochannels = "audiochannels" - case displayWidth = "displayWidth" - case displayHeight = "displayHeight" - case trackinfo = "trackinfo" - case width = "width" - case avclevel = "avclevel" - case audiosamplerate = "audiosamplerate" - case aacaot = "aacaot" - case audiocodecid = "audiocodecid" + case duration + case height + case frameWidth + case moovposition + case framerate + case avcprofile + case videocodecid + case frameHeight + case videoframerate + case audiochannels + case displayWidth + case displayHeight + case trackinfo + case width + case avclevel + case audiosamplerate + case aacaot + case audiocodecid } - init?(commandObject: [String: Any?]?) { // swiftlint:disable:this cyclomatic_complexity + init?(commandObject: [String: Any?]?) { // swiftlint:disable:this function_body_length guard let commandObject = commandObject else { return nil } if let duration = commandObject["duration"] as? Double { @@ -198,7 +198,7 @@ public struct MetaDataResponse { self.audiocodecid = audiocodecid } if let trackinfoArray = commandObject["trackinfo"] as? [[String: Any?]] { - var trackinfo = [Trackinfo]() + var trackinfos = [Trackinfo]() for trackinfoDict in trackinfoArray { if let timescale = trackinfoDict["timescale"] as? Double, let length = trackinfoDict["length"] as? Double, @@ -210,10 +210,11 @@ public struct MetaDataResponse { sampledescription.append(SampleDescription(sampletype: sampletype)) } } - trackinfo.append(Trackinfo(sampledescription: sampledescription, language: language, timescale: timescale, length: length)) + let trackinfo = Trackinfo(sampledescription: sampledescription, language: language, timescale: timescale, length: length) + trackinfos.append(trackinfo) } } - self.trackinfo = trackinfo + self.trackinfo = trackinfos } } } diff --git a/Sources/HPRTMP/RTMPHandshake.swift b/Sources/HPRTMP/RTMPHandshake.swift index b23322b..d43b8c0 100644 --- a/Sources/HPRTMP/RTMPHandshake.swift +++ b/Sources/HPRTMP/RTMPHandshake.swift @@ -61,7 +61,7 @@ actor RTMPHandshake { // random let randomSize = RTMPHandshake.packetSize - data.count (0...randomSize).forEach { _ in - data.write(UInt8(arc4random_uniform(0xff))) + data.write(UInt8.random(in: 0...0xff)) } return data } diff --git a/Sources/HPRTMP/RTMPPublishSession.swift b/Sources/HPRTMP/RTMPPublishSession.swift index ac6ec7e..50df711 100644 --- a/Sources/HPRTMP/RTMPPublishSession.swift +++ b/Sources/HPRTMP/RTMPPublishSession.swift @@ -16,7 +16,7 @@ public class RTMPPublishSession { case failed(err: RTMPError) case disconnected - public static func ==(lhs: Status, rhs: Status) -> Bool { + public static func == (lhs: Status, rhs: Status) -> Bool { switch (lhs, rhs) { case (.unknown, .unknown), (.connect, .connect), diff --git a/Sources/HPRTMP/RTMPSocket.swift b/Sources/HPRTMP/RTMPSocket.swift index ef6d55e..44e268f 100644 --- a/Sources/HPRTMP/RTMPSocket.swift +++ b/Sources/HPRTMP/RTMPSocket.swift @@ -22,17 +22,15 @@ public enum RTMPError: Error { case command(desc: String) case uknown(desc: String) var localizedDescription: String { - get { - switch self { - case .handShake(let desc): - return desc - case .stream(let desc): - return desc - case .command(let desc): - return desc - case .uknown(let desc): - return desc - } + switch self { + case .handShake(let desc): + return desc + case .stream(let desc): + return desc + case .command(let desc): + return desc + case .uknown(let desc): + return desc } } } @@ -128,7 +126,6 @@ extension RTMPSocket { await self.invalidate() default: self.logger.info("connection state: other") - break } } } @@ -221,7 +218,7 @@ extension RTMPSocket { } } - private func decode(data: Data) async { + private func decode(data: Data) async { // swiftlint:disable:this function_body_length guard let message = await decoder.decode() else { logger.info("[HPRTMP] decode message need more data.") return @@ -303,7 +300,7 @@ extension RTMPSocket { } } - private func handleCommandMessage(_ commandMessage: CommandMessage) async { + private func handleCommandMessage(_ commandMessage: CommandMessage) async { // swiftlint:disable:this function_body_length if commandMessage.commandNameType == .onStatus { guard let statusResponse = StatusResponse(info: commandMessage.info) else { return } if statusResponse.level == .error { From d4fd7e3203c754e2c54226dacdb0e18df4fbf65e Mon Sep 17 00:00:00 2001 From: Huiping Guo Date: Thu, 22 Jun 2023 02:43:30 +0900 Subject: [PATCH 3/5] test --- .github/workflows/swift.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 759e4de..60702a4 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -9,17 +9,17 @@ on: - main env: - DEVELOPER_DIR: /Applications/Xcode.app + DEVELOPER_DIR: /Applications/Xcode_14.3.app jobs: build: - runs-on: self-hosted + runs-on: macOS-latest steps: - uses: actions/checkout@v2 - name: Build run: swift build -v test: - runs-on: self-hosted + runs-on: macOS-latest steps: - uses: actions/checkout@v2 - name: Test From e5b06fd6f941a08276d09fca2ddaa27cced0aa13 Mon Sep 17 00:00:00 2001 From: Huiping Guo Date: Thu, 22 Jun 2023 02:44:47 +0900 Subject: [PATCH 4/5] version --- .github/workflows/swift.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index 60702a4..ae59166 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -9,7 +9,7 @@ on: - main env: - DEVELOPER_DIR: /Applications/Xcode_14.3.app + DEVELOPER_DIR: /Applications/Xcode_14.3.1.app jobs: build: From 5de23f85a9f23c57d33ef90de6eb60aface5cbee Mon Sep 17 00:00:00 2001 From: Huiping Guo Date: Thu, 22 Jun 2023 02:46:26 +0900 Subject: [PATCH 5/5] xcode --- .github/workflows/swift.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/swift.yml b/.github/workflows/swift.yml index ae59166..13ac53c 100644 --- a/.github/workflows/swift.yml +++ b/.github/workflows/swift.yml @@ -9,7 +9,7 @@ on: - main env: - DEVELOPER_DIR: /Applications/Xcode_14.3.1.app + DEVELOPER_DIR: /Applications/Xcode.app jobs: build: