From 959063fc004b0cd2f962d814cdf39c60d905aa50 Mon Sep 17 00:00:00 2001 From: pedroSG94 Date: Fri, 10 May 2024 21:59:17 +0200 Subject: [PATCH 1/5] adding g711 codec --- .../encoder/audio/AudioEncoder.swift | 47 +++++++++-- .../RootEncoder/encoder/audio/G711Codec.swift | 77 +++++++++++++++++++ .../encoder/utils/EncoderUtils.swift | 13 ++++ .../encoder/video/VideoEncoder.swift | 10 ++- .../RootEncoder/library/base/CameraBase.swift | 14 +--- .../library/base/DisplayBase.swift | 12 +-- .../library/rtmp/DisplayRtmp.swift | 6 +- .../library/rtsp/DisplayRtsp.swift | 4 - .../RootEncoder/library/rtsp/RtspCamera.swift | 4 - .../library/utils/RecordController.swift | 4 - .../RootEncoder/rtmp/rtmp/RtmpClient.swift | 2 +- .../rtmp/rtmp/RtmpCommandManager.swift | 4 - .../RootEncoder/rtmp/rtmp/RtmpSender.swift | 8 -- .../RootEncoder/rtsp/rtsp/RtspSender.swift | 5 -- .../rtsp/commands/RtspCommandManager.swift | 6 -- app.xcodeproj/project.pbxproj | 4 +- app/RtspSwiftUIView.swift | 1 + 17 files changed, 146 insertions(+), 75 deletions(-) create mode 100644 RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift diff --git a/RootEncoder/Sources/RootEncoder/encoder/audio/AudioEncoder.swift b/RootEncoder/Sources/RootEncoder/encoder/audio/AudioEncoder.swift index 2384eb4..d130176 100644 --- a/RootEncoder/Sources/RootEncoder/encoder/audio/AudioEncoder.swift +++ b/RootEncoder/Sources/RootEncoder/encoder/audio/AudioEncoder.swift @@ -17,22 +17,41 @@ public class AudioEncoder { private var initTs: Int64 = 0 private let thread = DispatchQueue(label: "AudioEncoder") private let syncQueue = SynchronizedQueue(label: "AudioEncodeQueue", size: 60) - public var codec = AudioCodec.AAC + private let g711Codec = G711Codec() + private var codec = AudioCodec.AAC public init(callback: GetAacData) { self.callback = callback } + public func setCodec(codec: AudioCodec) { + self.codec = codec + } + public func prepareAudio(inputFormat: AVAudioFormat, sampleRate: Double, channels: UInt32, bitrate: Int) -> Bool { - guard let outputFormat = getAACFormat(sampleRate: sampleRate, channels: channels) else { - return false - } - guard let converter = AVAudioConverter(from: inputFormat, to: outputFormat) else { + if codec == AudioCodec.AAC { + guard let outputFormat = getAACFormat(sampleRate: sampleRate, channels: channels) else { + return false + } + guard let converter = AVAudioConverter(from: inputFormat, to: outputFormat) else { + return false + } + converter.bitRate = bitrate + self.outputFormat = outputFormat + self.converter = converter + } else if codec == AudioCodec.G711 { + do { + try g711Codec.configure(sampleRate: sampleRate, channels: channels) + } catch IOException.runtimeError(let error) { + print("Create AudioEncoder failed. \(error)") + return false + } catch { + return false + } + } else { + print("invalid codec") return false } - converter.bitRate = bitrate - self.outputFormat = outputFormat - self.converter = converter print("prepare audio success") return true } @@ -51,6 +70,18 @@ public class AudioEncoder { while (self.running) { let b = self.syncQueue.dequeue() if let b = b { + if self.codec == AudioCodec.G711 { + let data = b.audioBufferToBytes() + let mBuffer = self.g711Codec.encode(buffer: data, offset: 0, size: data.count) + let end = Date().millisecondsSince1970 + let elapsedNanoSeconds = (end - self.initTs) * 1000 + var frame = Frame() + frame.buffer = mBuffer + frame.length = UInt32(mBuffer.count) + frame.timeStamp = UInt64(elapsedNanoSeconds) + self.callback?.getAacData(frame: frame) + continue + } var error: NSError? = nil guard let aacBuffer = self.convertToAAC(buffer: b, error: &error) else { continue diff --git a/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift b/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift new file mode 100644 index 0000000..bfd098d --- /dev/null +++ b/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift @@ -0,0 +1,77 @@ +// +// File.swift +// +// +// Created by Pedro on 10/5/24. +// + +import Foundation +import AVFoundation + +public class G711Codec { + + public init() {} + + public func configure(sampleRate: Double, channels: UInt32) throws { + if sampleRate != 8000 || channels != 1 { + throw IOException.runtimeError("G711 codec only support 8000 sampleRate and mono channel") + } + } + + public func encode(buffer: Array, offset: Int, size: Int) -> Array{ + var j = offset + let count = size / 2 + var out = [UInt8](repeating: 0, count: count) + for i in 0.., offset: Int, len: Int) -> Array{ + var j = 0 + var out = [UInt8](repeating: 0, count: src.count * 2) + for i in 0..> 8) & 0xff) + j += 2 + } + return out + } + + private func linearToALawSample(_ mySample: UInt16) -> UInt8 { + var sample = Int16(bitPattern: mySample) + let sign = ~sample >> 8 & 0x80 + if sign != 0x80 { + sample = -sample + } + if sample > cClip { + sample = cClip + } + var s: Int + if sample >= 256 { + let exponent = Int(aLawCompressTable[Int(sample) >> 8 & 0x7F]) + let mantissa = Int(sample) >> exponent + 3 & 0x0F + s = exponent << 4 | mantissa + } else { + s = Int(sample) >> 4 + } + s = s ^ (Int(sign) ^ 0x55) + print("value: \(s.toUInt8Array()[0])") + return s.toUInt8Array()[0] + } + + private let cClip: Int16 = 32635 + private let aLawDecompressTable: [Int16] = [ + -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, -344, -328, -376, + -360, -280, -264, -312, -296, -472, -456, -504, -488, -408, -392, -440, -424, -88, -72, -120, -104, -24, -8, -56, -40, -216, -200, -248, -232, -152, -136, -184, -168, -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, -688, -656, -752, -720, -560, -528, -624, -592, -944, -912, -1008, -976, -816, -784, -880, -848, 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, 2752, 2624, + 3008, 2880, 2240, 2112, 2496, 2368, 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, 344, 328, 376, 360, 280, 264, 312, 296, 472, 456, 504, 488, 408, 392, 440, 424, 88, 72, 120, 104, 24, 8, 56, 40, 216, 200, 248, 232, 152, 136, 184, 168, 1376, 1312, 1504, 1440, 1120, + 1056, 1248, 1184, 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, 688, 656, 752, 720, 560, 528, 624, 592, 944, 912, 1008, 976, 816, 784, 880, 848 + ] + private let aLawCompressTable: [UInt8] = [ + 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + ] +} diff --git a/RootEncoder/Sources/RootEncoder/encoder/utils/EncoderUtils.swift b/RootEncoder/Sources/RootEncoder/encoder/utils/EncoderUtils.swift index b20d6ab..4a5c392 100644 --- a/RootEncoder/Sources/RootEncoder/encoder/utils/EncoderUtils.swift +++ b/RootEncoder/Sources/RootEncoder/encoder/utils/EncoderUtils.swift @@ -34,6 +34,19 @@ public extension AVAudioPCMBuffer { ) return sampleBuffer } + + func audioBufferToBytes() -> [UInt8] { + let srcLeft = self.floatChannelData![0] + let bytesPerFrame = self.format.streamDescription.pointee.mBytesPerFrame + let numBytes = Int(bytesPerFrame * self.frameLength) + var audioByteArray = [UInt8](repeating: 0, count: numBytes) + srcLeft.withMemoryRebound(to: UInt8.self, capacity: numBytes) { srcByteData in + audioByteArray.withUnsafeMutableBufferPointer { + $0.baseAddress!.initialize(from: srcByteData, count: numBytes) + } + } + return audioByteArray + } } extension AVAudioTime { diff --git a/RootEncoder/Sources/RootEncoder/encoder/video/VideoEncoder.swift b/RootEncoder/Sources/RootEncoder/encoder/video/VideoEncoder.swift index 42a44fd..360a085 100644 --- a/RootEncoder/Sources/RootEncoder/encoder/video/VideoEncoder.swift +++ b/RootEncoder/Sources/RootEncoder/encoder/video/VideoEncoder.swift @@ -52,7 +52,6 @@ public class VideoEncoder { codecType: codec.value, encoderSpecification: nil, imageBufferAttributes: nil, compressedDataAllocator: nil, outputCallback: videoCallback, refcon: Unmanaged.passUnretained(self).toOpaque(), compressionSessionOut: &session) - print("using codec \(codec)") self.resolution = resolution self.fps = fps self.bitrate = bitrate @@ -100,8 +99,13 @@ public class VideoEncoder { } } - public func setCodec(codec: CodecUtil) { - self.codec = codec + public func setCodec(codec: VideoCodec) { + switch codec { + case .H264: + self.codec = CodecUtil.H264 + case .H265: + self.codec = CodecUtil.H265 + } } public func forceKeyFrame() { diff --git a/RootEncoder/Sources/RootEncoder/library/base/CameraBase.swift b/RootEncoder/Sources/RootEncoder/library/base/CameraBase.swift index 31ef1ba..6c336b6 100644 --- a/RootEncoder/Sources/RootEncoder/library/base/CameraBase.swift +++ b/RootEncoder/Sources/RootEncoder/library/base/CameraBase.swift @@ -48,7 +48,7 @@ public class CameraBase: GetMicrophoneData, GetCameraData, GetAacData, GetH264Da } public func prepareAudio() -> Bool { - prepareAudio(bitrate: 64 * 1024, sampleRate: 32000, isStereo: true) + prepareAudio(bitrate: 64 * 1024, sampleRate: 8000, isStereo: false) } public func prepareVideo(resolution: CameraHelper.Resolution, fps: Int, bitrate: Int, iFrameInterval: Int, rotation: Int) -> Bool { @@ -164,21 +164,13 @@ public class CameraBase: GetMicrophoneData, GetCameraData, GetAacData, GetH264Da public func setVideoCodec(codec: VideoCodec) { setVideoCodecImp(codec: codec) recordController.setVideoCodec(codec: codec) - let type = switch codec { - case .H264: - CodecUtil.H264 - case .H265: - CodecUtil.H265 - @unknown default: - CodecUtil.H264 - } - videoEncoder.setCodec(codec: type) + videoEncoder.setCodec(codec: codec) } public func setAudioCodec(codec: AudioCodec) { setAudioCodecImp(codec: codec) recordController.setAudioCodec(codec: codec) - audioEncoder.codec = codec + audioEncoder.setCodec(codec: codec) } public func setVideoCodecImp(codec: VideoCodec) {} diff --git a/RootEncoder/Sources/RootEncoder/library/base/DisplayBase.swift b/RootEncoder/Sources/RootEncoder/library/base/DisplayBase.swift index a230ddf..ce6f68b 100644 --- a/RootEncoder/Sources/RootEncoder/library/base/DisplayBase.swift +++ b/RootEncoder/Sources/RootEncoder/library/base/DisplayBase.swift @@ -148,21 +148,13 @@ public class DisplayBase: GetMicrophoneData, GetCameraData, GetAacData, GetH264D public func setVideoCodec(codec: VideoCodec) { setVideoCodecImp(codec: codec) recordController.setVideoCodec(codec: codec) - let type = switch codec { - case .H264: - CodecUtil.H264 - case .H265: - CodecUtil.H265 - @unknown default: - CodecUtil.H264 - } - videoEncoder.setCodec(codec: type) + videoEncoder.setCodec(codec: codec) } public func setAudioCodec(codec: AudioCodec) { setAudioCodecImp(codec: codec) recordController.setAudioCodec(codec: codec) - audioEncoder.codec = codec + audioEncoder.setCodec(codec: codec) } public func setVideoCodecImp(codec: VideoCodec) {} diff --git a/RootEncoder/Sources/RootEncoder/library/rtmp/DisplayRtmp.swift b/RootEncoder/Sources/RootEncoder/library/rtmp/DisplayRtmp.swift index 5c368ca..568030c 100644 --- a/RootEncoder/Sources/RootEncoder/library/rtmp/DisplayRtmp.swift +++ b/RootEncoder/Sources/RootEncoder/library/rtmp/DisplayRtmp.swift @@ -18,11 +18,7 @@ public class DisplayRtmp: DisplayBase { } public func setAuth(user: String, password: String) { - //client.setAuth(user: user, password: password) - } - - public func setCodec(codec: CodecUtil) { - videoEncoder.setCodec(codec: codec) + client.setAuth(user: user, password: password) } public func reTry(delay: Int, reason: String, backUrl: String? = nil) -> Bool { diff --git a/RootEncoder/Sources/RootEncoder/library/rtsp/DisplayRtsp.swift b/RootEncoder/Sources/RootEncoder/library/rtsp/DisplayRtsp.swift index 97993ba..2b782b5 100644 --- a/RootEncoder/Sources/RootEncoder/library/rtsp/DisplayRtsp.swift +++ b/RootEncoder/Sources/RootEncoder/library/rtsp/DisplayRtsp.swift @@ -22,10 +22,6 @@ public class DisplayRtsp: DisplayBase { client.setAuth(user: user, password: password) } - public func setCodec(codec: CodecUtil) { - videoEncoder.setCodec(codec: codec) - } - public func reTry(delay: Int, reason: String, backUrl: String? = nil) -> Bool { let result = client.shouldRetry(reason: reason) if (result) { diff --git a/RootEncoder/Sources/RootEncoder/library/rtsp/RtspCamera.swift b/RootEncoder/Sources/RootEncoder/library/rtsp/RtspCamera.swift index 25832df..2302416 100644 --- a/RootEncoder/Sources/RootEncoder/library/rtsp/RtspCamera.swift +++ b/RootEncoder/Sources/RootEncoder/library/rtsp/RtspCamera.swift @@ -25,10 +25,6 @@ public class RtspCamera: CameraBase { client.setAuth(user: user, password: password) } - public func setCodec(codec: CodecUtil) { - videoEncoder.setCodec(codec: codec) - } - public func reTry(delay: Int, reason: String, backUrl: String? = nil) -> Bool { let result = client.shouldRetry(reason: reason) if (result) { diff --git a/RootEncoder/Sources/RootEncoder/library/utils/RecordController.swift b/RootEncoder/Sources/RootEncoder/library/utils/RecordController.swift index 093271d..719e4fe 100644 --- a/RootEncoder/Sources/RootEncoder/library/utils/RecordController.swift +++ b/RootEncoder/Sources/RootEncoder/library/utils/RecordController.swift @@ -146,8 +146,6 @@ public class RecordController { AVVideoCodecType.h264 case VideoCodec.H265: AVVideoCodecType.hevc - default: - AVVideoCodecType.h264 //TODO throw error } } @@ -157,8 +155,6 @@ public class RecordController { kAudioFormatMPEG4AAC case AudioCodec.G711: kAudioFormatALaw - default: - kAudioFormatLinearPCM // TODO throw error } } diff --git a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpClient.swift b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpClient.swift index 05b52a1..2b9d1ff 100644 --- a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpClient.swift +++ b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpClient.swift @@ -292,7 +292,7 @@ public class RtmpClient { connectChecker.onAuthError() } default: - connectChecker.onConnectionFailed(reason: description) + connectChecker.onConnectionFailed(reason: description) } case "onStatus": let code = ((command.data[3] as! AmfObject).getProperty(name: "code") as! AmfString).value diff --git a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpCommandManager.swift b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpCommandManager.swift index 3cb2817..0a08df6 100644 --- a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpCommandManager.swift +++ b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpCommandManager.swift @@ -160,8 +160,6 @@ public class RtmpCommandManager { VideoFormat.AVC.rawValue case .H265: VideoFormat.HEVC.rawValue - @unknown default: - VideoFormat.AVC.rawValue } print("codec: \(codecValue)") amfEcmaArray.setProperty(name: "width", data: Double(width)) @@ -176,8 +174,6 @@ public class RtmpCommandManager { AudioFormat.AAC.rawValue case .G711: AudioFormat.G711_A.rawValue - @unknown default: - AudioFormat.AAC.rawValue } amfEcmaArray.setProperty(name: "audiocodecid", data: Double(codecValue)) amfEcmaArray.setProperty(name: "audiosamplerate", data: Double(sampleRate)) diff --git a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpSender.swift b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpSender.swift index c93ee2d..f341400 100644 --- a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpSender.swift +++ b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpSender.swift @@ -40,10 +40,6 @@ public class RtmpSender { let packet = RtmpH265Packet() packet.setVideoInfo(sps: sps, pps: pps, vps: vps!) videoPacket = packet - @unknown default: - let packet = RtmpH264Packet() - packet.setVideoInfo(sps: sps, pps: pps) - videoPacket = packet } } @@ -56,10 +52,6 @@ public class RtmpSender { case .G711: let packet = RtmpG711Packet() audioPacket = packet - @unknown default: - let packet = RtmpAacPacket() - packet.sendAudioInfo(sampleRate: sampleRate, isStereo: isStereo) - audioPacket = packet } } diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspSender.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspSender.swift index 8cef780..5c63075 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspSender.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspSender.swift @@ -50,8 +50,6 @@ public class RtspSender { RtspH264Packet(sps: sps, pps: pps) case VideoCodec.H265: RtspH265Packet() - default: - RtspH264Packet(sps: sps, pps: pps) } } @@ -61,10 +59,7 @@ public class RtspSender { RtspAacPacket(sampleRate: sampleRate) case AudioCodec.G711: RtspG711Packet(sampleRate: sampleRate) - default: - RtspAacPacket(sampleRate: sampleRate) } - } public func sendVideo(buffer: Array, ts: UInt64) { diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/RtspCommandManager.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/RtspCommandManager.swift index 060847c..8c3a350 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/RtspCommandManager.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/RtspCommandManager.swift @@ -41,8 +41,6 @@ public class RtspCommandManager { return sps != nil && pps != nil case VideoCodec.H265: return sps != nil && pps != nil && vps != nil - default: - return false } } @@ -146,8 +144,6 @@ public class RtspCommandManager { body.createAACBody(trackAudio: RtpConstants.trackAudio, sampleRate: sampleRate, isStereo: isStereo) case .G711: body.createG711Body(trackAudio: RtpConstants.trackAudio, sampleRate: sampleRate, isStereo: isStereo) - default: - "" } } @@ -160,8 +156,6 @@ public class RtspCommandManager { body.createH264Body(trackVideo: RtpConstants.trackVideo, sps: spsString, pps: ppsString) case .H265: body.createH265Body(trackVideo: RtpConstants.trackVideo, sps: spsString, pps: ppsString, vps: vpsString!) - default: - "" } } diff --git a/app.xcodeproj/project.pbxproj b/app.xcodeproj/project.pbxproj index c2c8479..28d1247 100644 --- a/app.xcodeproj/project.pbxproj +++ b/app.xcodeproj/project.pbxproj @@ -407,7 +407,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.6; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; MTL_FAST_MATH = YES; ONLY_ACTIVE_ARCH = YES; @@ -464,7 +464,7 @@ GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; GCC_WARN_UNUSED_FUNCTION = YES; GCC_WARN_UNUSED_VARIABLE = YES; - IPHONEOS_DEPLOYMENT_TARGET = 13.6; + IPHONEOS_DEPLOYMENT_TARGET = 14.0; MTL_ENABLE_DEBUG_INFO = NO; MTL_FAST_MATH = YES; SDKROOT = iphoneos; diff --git a/app/RtspSwiftUIView.swift b/app/RtspSwiftUIView.swift index 2f5d41c..816aba7 100644 --- a/app/RtspSwiftUIView.swift +++ b/app/RtspSwiftUIView.swift @@ -91,6 +91,7 @@ struct RtspSwiftUIView: View, ConnectChecker { camera.onAppear { rtspCamera = RtspCamera(view: cameraView, connectChecker: self) + rtspCamera.setAudioCodec(codec: AudioCodec.G711) rtspCamera.setRetries(reTries: 10) rtspCamera.startPreview() } From 80d780daf5e3ccdf0887f4881b97205b311634fd Mon Sep 17 00:00:00 2001 From: pedroSG94 Date: Fri, 17 May 2024 23:48:39 +0200 Subject: [PATCH 2/5] fix rtsp audio packets and use streamid instead of trackID --- .../RootEncoder/encoder/audio/G711Codec.swift | 3 +-- .../input/audio/MicrophoneManager.swift | 2 +- .../RootEncoder/rtmp/rtmp/RtmpClient.swift | 2 +- .../RootEncoder/rtmp/rtmp/RtmpSender.swift | 2 +- .../rtsp/rtp/packets/RtspAacPacket.swift | 19 ++++++++++--------- .../rtsp/rtp/packets/RtspG711Packet.swift | 15 ++++++++------- .../rtsp/rtp/packets/RtspH264Packet.swift | 7 +++---- .../rtsp/rtp/packets/RtspH265Packet.swift | 7 +++---- .../RootEncoder/rtsp/rtsp/RtspClient.swift | 2 +- .../RootEncoder/rtsp/rtsp/RtspSender.swift | 2 +- .../rtsp/commands/RtspCommandManager.swift | 8 ++++---- .../rtsp/rtsp/commands/SdpBody.swift | 8 ++++---- 12 files changed, 38 insertions(+), 39 deletions(-) diff --git a/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift b/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift index bfd098d..116eaad 100644 --- a/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift +++ b/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift @@ -46,7 +46,7 @@ public class G711Codec { var sample = Int16(bitPattern: mySample) let sign = ~sample >> 8 & 0x80 if sign != 0x80 { - sample = -sample + sample = ~sample } if sample > cClip { sample = cClip @@ -60,7 +60,6 @@ public class G711Codec { s = Int(sample) >> 4 } s = s ^ (Int(sign) ^ 0x55) - print("value: \(s.toUInt8Array()[0])") return s.toUInt8Array()[0] } diff --git a/RootEncoder/Sources/RootEncoder/encoder/input/audio/MicrophoneManager.swift b/RootEncoder/Sources/RootEncoder/encoder/input/audio/MicrophoneManager.swift index 4576671..8feb688 100644 --- a/RootEncoder/Sources/RootEncoder/encoder/input/audio/MicrophoneManager.swift +++ b/RootEncoder/Sources/RootEncoder/encoder/input/audio/MicrophoneManager.swift @@ -11,7 +11,7 @@ import AVFoundation public class MicrophoneManager { - private let thread = DispatchQueue.global() + private let thread = DispatchQueue(label: "MicrophoneManager") private let audioEngine = AVAudioEngine() private var inputNode: AVAudioInputNode? private var inputFormat: AVAudioFormat? diff --git a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpClient.swift b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpClient.swift index 2b9d1ff..e8b50db 100644 --- a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpClient.swift +++ b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpClient.swift @@ -67,7 +67,7 @@ public class RtmpClient { } if (!self.isStreaming || isRetry) { self.isStreaming = true - thread = Task { + thread = Task(priority: .high) { guard let url = url else { self.connectChecker.onConnectionFailed(reason: "Endpoint malformed, should be: rtmp://ip:port/appname/streamname") return diff --git a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpSender.swift b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpSender.swift index f341400..a0320f3 100644 --- a/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpSender.swift +++ b/RootEncoder/Sources/RootEncoder/rtmp/rtmp/RtmpSender.swift @@ -86,7 +86,7 @@ public class RtmpSender { public func start() { queue.clear() running = true - thread = Task { + thread = Task(priority: .high) { while (self.running) { let flvPacket = self.queue.dequeue() if let flvPacket = flvPacket { diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspAacPacket.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspAacPacket.swift index f93ee4f..5fa890e 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspAacPacket.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspAacPacket.swift @@ -9,19 +9,20 @@ public class RtspAacPacket: RtspBasePacket { } public override func createAndSendPacket(buffer: Array, ts: UInt64, callback: (RtpFrame) -> Void) { - let length = buffer.count + var buffer = buffer + let naluLength = buffer.count let dts = ts * 1000 let maxPayload = maxPacketSize - RtpConstants.rtpHeaderLength var sum = 0 - while (sum < length) { - let size = if (length - sum < maxPayload) { - length - sum + while (sum < naluLength) { + let length = if (naluLength - sum < maxPayload) { + naluLength - sum } else { maxPayload } - var rtpBuffer = getBuffer(size: size + RtpConstants.rtpHeaderLength + 4) - rtpBuffer[RtpConstants.rtpHeaderLength + 4...rtpBuffer.count - 1] = buffer[0...buffer.count - 1] + var rtpBuffer = getBuffer(size: length + RtpConstants.rtpHeaderLength + 4) + buffer = buffer.get(destiny: &rtpBuffer, index: RtpConstants.rtpHeaderLength + 4, length: length) markPacket(buffer: &rtpBuffer) let rtpTs = updateTimeStamp(buffer: &rtpBuffer, timeStamp: dts) @@ -31,8 +32,8 @@ public class RtspAacPacket: RtspBasePacket { rtpBuffer[RtpConstants.rtpHeaderLength] = 0x00 rtpBuffer[RtpConstants.rtpHeaderLength + 1] = 0x10 // AU-size - rtpBuffer[RtpConstants.rtpHeaderLength + 2] = intToBytes(from: size >> 5)[0] - rtpBuffer[RtpConstants.rtpHeaderLength + 3] = intToBytes(from: size << 3)[0] + rtpBuffer[RtpConstants.rtpHeaderLength + 2] = intToBytes(from: length >> 5)[0] + rtpBuffer[RtpConstants.rtpHeaderLength + 3] = intToBytes(from: length << 3)[0] // AU-Index rtpBuffer[RtpConstants.rtpHeaderLength + 3] &= 0xF8 rtpBuffer[RtpConstants.rtpHeaderLength + 3] |= 0x00 @@ -44,7 +45,7 @@ public class RtspAacPacket: RtspBasePacket { frame.buffer = rtpBuffer frame.channelIdentifier = channelIdentifier - sum += size + sum += length callback(frame) } } diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspG711Packet.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspG711Packet.swift index 08e8e98..25253c9 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspG711Packet.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspG711Packet.swift @@ -18,18 +18,19 @@ public class RtspG711Packet: RtspBasePacket { } public override func createAndSendPacket(buffer: Array, ts: UInt64, callback: (RtpFrame) -> Void) { - let length = buffer.count + var buffer = buffer + let naluLength = buffer.count let maxPayload = maxPacketSize - RtpConstants.rtpHeaderLength var sum = 0 - while (sum < length) { - let size = if (length - sum < maxPayload) { - length - sum + while (sum < naluLength) { + let length = if (naluLength - sum < maxPayload) { + naluLength - sum } else { maxPayload } - var rtpBuffer = getBuffer(size: size + RtpConstants.rtpHeaderLength) - rtpBuffer[RtpConstants.rtpHeaderLength...rtpBuffer.count - 1] = buffer[0...buffer.count - 1] + var rtpBuffer = getBuffer(size: length + RtpConstants.rtpHeaderLength) + buffer = buffer.get(destiny: &rtpBuffer, index: RtpConstants.rtpHeaderLength, length: length) let dts = ts * 1000 markPacket(buffer: &rtpBuffer) let rtpTs = updateTimeStamp(buffer: &rtpBuffer, timeStamp: dts) @@ -41,7 +42,7 @@ public class RtspG711Packet: RtspBasePacket { frame.buffer = rtpBuffer frame.channelIdentifier = channelIdentifier - sum += size + sum += length callback(frame) } } diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH264Packet.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH264Packet.swift index 0a3ab31..297aa96 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH264Packet.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH264Packet.swift @@ -64,11 +64,10 @@ public class RtspH264Packet: RtspBasePacket { var sum = 0 while sum < naluLength { - var length = 0 - if (naluLength - sum > maxPacketSize - RtpConstants.rtpHeaderLength - 2) { - length = maxPacketSize - RtpConstants.rtpHeaderLength - 2 + let length = if (naluLength - sum > maxPacketSize - RtpConstants.rtpHeaderLength - 2) { + maxPacketSize - RtpConstants.rtpHeaderLength - 2 } else { - length = buffer.count + buffer.count } var rtpBuffer = getBuffer(size: length + RtpConstants.rtpHeaderLength + 2) rtpBuffer[RtpConstants.rtpHeaderLength] = header[0] diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH265Packet.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH265Packet.swift index cbdf549..8c6df11 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH265Packet.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtp/packets/RtspH265Packet.swift @@ -58,11 +58,10 @@ public class RtspH265Packet: RtspBasePacket { var sum = 0 while sum < naluLength { - var length = 0 - if (naluLength - sum > maxPacketSize - RtpConstants.rtpHeaderLength - 3) { - length = maxPacketSize - RtpConstants.rtpHeaderLength - 3 + let length = if (naluLength - sum > maxPacketSize - RtpConstants.rtpHeaderLength - 3) { + maxPacketSize - RtpConstants.rtpHeaderLength - 3 } else { - length = buffer.count + buffer.count } var rtpBuffer = getBuffer(size: length + RtpConstants.rtpHeaderLength + 3) rtpBuffer[RtpConstants.rtpHeaderLength] = header[0] diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspClient.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspClient.swift index d50b7f4..d4aac63 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspClient.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspClient.swift @@ -69,7 +69,7 @@ public class RtspClient { } if (!self.streaming || isRetry) { self.streaming = true - thread = Task { + thread = Task(priority: .background) { guard let url = url else { self.connectChecker.onConnectionFailed(reason: "Endpoint malformed, should be: rtsp://ip:port/appname/streamname") return diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspSender.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspSender.swift index 5c63075..a9b7d56 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspSender.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/RtspSender.swift @@ -98,7 +98,7 @@ public class RtspSender { tcpReport?.setSSRC(ssrcVideo: ssrcVideo, ssrcAudio: ssrcAudio) queue.clear() running = true - thread = Task { + thread = Task(priority: .background) { let isTcp = self.tcpSocket is RtpSocketTcp while (self.running) { let frame = self.queue.dequeue() diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/RtspCommandManager.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/RtspCommandManager.swift index 8c3a350..d514846 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/RtspCommandManager.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/RtspCommandManager.swift @@ -49,8 +49,8 @@ public class RtspCommandManager { } private func addHeader() -> String { - let session = sessionId != nil ? "Session: \(sessionId!)\r\n" : "" - let auth = authorization != nil ? "Authorization: \(authorization!)\r\n" : "" + let session = sessionId?.isEmpty ?? true != true ? "Session: \(sessionId!)\r\n" : "" + let auth = authorization?.isEmpty ?? true != true ? "Authorization: \(authorization!)\r\n" : "" let result = "CSeq: \(cSeq)\r\n\(session)\(auth)" cSeq += 1 return result @@ -76,8 +76,8 @@ public class RtspCommandManager { public func createSetup(track: Int) -> String { let ports = track == RtpConstants.trackVideo ? videoClientPorts : audioClientPorts - let params = mProtocol == .TCP ? "TCP;interleaved=\(2 * track)-\(2 * track + 1)" : "UDP;unicast;client_port=\(ports[0])-\(ports[1])" - let setup = "SETUP rtsp://\(host!):\(port!)\(path!)/trackID=\(track) RTSP/1.0\r\nTransport: RTP/AVP/\(params);mode=record\r\n\(addHeader())\r\n" + let params = mProtocol == .TCP ? "TCP;unicast;interleaved=\(2 * track)-\(2 * track + 1)" : "UDP;unicast;client_port=\(ports[0])-\(ports[1])" + let setup = "SETUP rtsp://\(host!):\(port!)\(path!)/streamid=\(track) RTSP/1.0\r\nTransport: RTP/AVP/\(params);mode=record\r\n\(addHeader())\r\n" print(setup) return setup } diff --git a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/SdpBody.swift b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/SdpBody.swift index 000f9d1..9c948eb 100644 --- a/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/SdpBody.swift +++ b/RootEncoder/Sources/RootEncoder/rtsp/rtsp/commands/SdpBody.swift @@ -27,24 +27,24 @@ public class SdpBody { let config = (2 & 0x1F) << 11 | (sampleNum! & 0x0F) << 7 | (channel & 0x0F) << 3 let hexStringConfig = String(format:"%02X", config) let payload = RtpConstants.payloadType + trackAudio - return "m=audio 0 RTP/AVP \(payload)\r\na=rtpmap:\(payload) MPEG4-GENERIC/\(sampleRate)/\(channel)\r\na=fmtp:\(payload) streamtype=5; profile-level-id=15; mode=AAC-hbr; config=\(hexStringConfig); SizeLength=13; IndexLength=3; IndexDeltaLength=3;\r\na=control:trackID=\(trackAudio)\r\n" + return "m=audio 0 RTP/AVP \(payload)\r\na=rtpmap:\(payload) MPEG4-GENERIC/\(sampleRate)/\(channel)\r\na=fmtp:\(payload) streamtype=5; profile-level-id=15; mode=AAC-hbr; config=\(hexStringConfig); SizeLength=13; IndexLength=3; IndexDeltaLength=3;\r\na=control:streamid=\(trackAudio)\r\n" } public func createG711Body(trackAudio: Int, sampleRate: Int, isStereo: Bool) -> String { let channel = isStereo ? 2 : 1 let payload = RtpConstants.payloadTypeG711 return "m=audio 0 RTP/AVP \(payload)\r\n" + - "a=rtpmap:\(payload) PCMA/\(sampleRate)/\(channel)\r\n" + + "a=rtpmap:\(payload) PCMA/8000/1\r\n" + "a=control:streamid=\(trackAudio)\r\n" } public func createH264Body(trackVideo: Int, sps: String, pps: String) -> String { let payload = RtpConstants.payloadType + trackVideo - return "m=video 0 RTP/AVP \(payload)\r\na=rtpmap:\(payload) H264/\(RtpConstants.clockVideoFrequency)\r\na=fmtp:\(payload) packetization-mode=1;sprop-parameter-sets=\(sps),\(pps);\r\na=control:trackID=\(trackVideo)\r\n" + return "m=video 0 RTP/AVP \(payload)\r\na=rtpmap:\(payload) H264/\(RtpConstants.clockVideoFrequency)\r\na=fmtp:\(payload) packetization-mode=1;sprop-parameter-sets=\(sps),\(pps);\r\na=control:streamid=\(trackVideo)\r\n" } public func createH265Body(trackVideo: Int, sps: String, pps: String, vps: String) -> String { let payload = RtpConstants.payloadType + trackVideo - return "m=video 0 RTP/AVP \(payload)\r\na=rtpmap:\(payload) H265/\(RtpConstants.clockVideoFrequency)\r\na=fmtp:\(payload) sprop-sps=\(sps); sprop-pps=\(pps); sprop-vps=\(vps);\r\na=control:trackID=\(trackVideo)\r\n" + return "m=video 0 RTP/AVP \(payload)\r\na=rtpmap:\(payload) H265/\(RtpConstants.clockVideoFrequency)\r\na=fmtp:\(payload) sprop-sps=\(sps); sprop-pps=\(pps); sprop-vps=\(vps);\r\na=control:streamid=\(trackVideo)\r\n" } } From 564c2bccfcdfd15a8bd6fa248b3184c4f842598b Mon Sep 17 00:00:00 2001 From: pedroSG94 Date: Sat, 25 May 2024 20:41:09 +0200 Subject: [PATCH 3/5] fixing g711 encode --- .../xcschemes/RootEncoderTests.xcscheme | 73 +++++++++++++++++++ .../RootEncoder/encoder/audio/G711Codec.swift | 28 ++++--- .../RootEncoderTests/RootEncoderTests.swift | 20 +++++ app/RtspSwiftUIView.swift | 1 - appTests/appTests.swift | 35 --------- 5 files changed, 106 insertions(+), 51 deletions(-) create mode 100644 RootEncoder/.swiftpm/xcode/xcshareddata/xcschemes/RootEncoderTests.xcscheme diff --git a/RootEncoder/.swiftpm/xcode/xcshareddata/xcschemes/RootEncoderTests.xcscheme b/RootEncoder/.swiftpm/xcode/xcshareddata/xcschemes/RootEncoderTests.xcscheme new file mode 100644 index 0000000..a65441f --- /dev/null +++ b/RootEncoder/.swiftpm/xcode/xcshareddata/xcschemes/RootEncoderTests.xcscheme @@ -0,0 +1,73 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift b/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift index 116eaad..d0a22cc 100644 --- a/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift +++ b/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift @@ -30,11 +30,11 @@ public class G711Codec { return out } - public func decode(src: Array, offset: Int, len: Int) -> Array{ + public func decode(buffer: Array, offset: Int, size: Int) -> Array{ var j = 0 - var out = [UInt8](repeating: 0, count: src.count * 2) - for i in 0..> 8) & 0xff) j += 2 @@ -42,8 +42,8 @@ public class G711Codec { return out } - private func linearToALawSample(_ mySample: UInt16) -> UInt8 { - var sample = Int16(bitPattern: mySample) + public func linearToALawSample(_ mySample: UInt16) -> UInt8 { + var sample = mySample let sign = ~sample >> 8 & 0x80 if sign != 0x80 { sample = ~sample @@ -53,8 +53,9 @@ public class G711Codec { } var s: Int if sample >= 256 { - let exponent = Int(aLawCompressTable[Int(sample) >> 8 & 0x7F]) - let mantissa = Int(sample) >> exponent + 3 & 0x0F + let tableValue = Int(sample) >> 8 & 0x7F + let exponent = Int(aLawCompressTable[tableValue]) + let mantissa = Int(sample) >> (exponent + 3) & 0x0F s = exponent << 4 | mantissa } else { s = Int(sample) >> 4 @@ -63,14 +64,11 @@ public class G711Codec { return s.toUInt8Array()[0] } - private let cClip: Int16 = 32635 - private let aLawDecompressTable: [Int16] = [ - -5504, -5248, -6016, -5760, -4480, -4224, -4992, -4736, -7552, -7296, -8064, -7808, -6528, -6272, -7040, -6784, -2752, -2624, -3008, -2880, -2240, -2112, -2496, -2368, -3776, -3648, -4032, -3904, -3264, -3136, -3520, -3392, -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944, -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136, -11008, -10496, -12032, -11520, -8960, -8448, -9984, -9472, -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568, -344, -328, -376, - -360, -280, -264, -312, -296, -472, -456, -504, -488, -408, -392, -440, -424, -88, -72, -120, -104, -24, -8, -56, -40, -216, -200, -248, -232, -152, -136, -184, -168, -1376, -1312, -1504, -1440, -1120, -1056, -1248, -1184, -1888, -1824, -2016, -1952, -1632, -1568, -1760, -1696, -688, -656, -752, -720, -560, -528, -624, -592, -944, -912, -1008, -976, -816, -784, -880, -848, 5504, 5248, 6016, 5760, 4480, 4224, 4992, 4736, 7552, 7296, 8064, 7808, 6528, 6272, 7040, 6784, 2752, 2624, - 3008, 2880, 2240, 2112, 2496, 2368, 3776, 3648, 4032, 3904, 3264, 3136, 3520, 3392, 22016, 20992, 24064, 23040, 17920, 16896, 19968, 18944, 30208, 29184, 32256, 31232, 26112, 25088, 28160, 27136, 11008, 10496, 12032, 11520, 8960, 8448, 9984, 9472, 15104, 14592, 16128, 15616, 13056, 12544, 14080, 13568, 344, 328, 376, 360, 280, 264, 312, 296, 472, 456, 504, 488, 408, 392, 440, 424, 88, 72, 120, 104, 24, 8, 56, 40, 216, 200, 248, 232, 152, 136, 184, 168, 1376, 1312, 1504, 1440, 1120, - 1056, 1248, 1184, 1888, 1824, 2016, 1952, 1632, 1568, 1760, 1696, 688, 656, 752, 720, 560, 528, 624, 592, 944, 912, 1008, 976, 816, 784, 880, 848 + private let cClip: UInt16 = 32635 + private let aLawDecompressTable: [UInt16] = [ + 0xea80, 0xeb80, 0xe880, 0xe980, 0xee80, 0xef80, 0xec80, 0xed80, 0xe280, 0xe380, 0xe080, 0xe180, 0xe680, 0xe780, 0xe480, 0xe580, 0xf540, 0xf5c0, 0xf440, 0xf4c0, 0xf740, 0xf7c0, 0xf640, 0xf6c0, 0xf140, 0xf1c0, 0xf040, 0xf0c0, 0xf340, 0xf3c0, 0xf240, 0xf2c0, 0xaa00, 0xae00, 0xa200, 0xa600, 0xba00, 0xbe00, 0xb200, 0xb600, 0x8a00, 0x8e00, 0x8200, 0x8600, 0x9a00, 0x9e00, 0x9200, 0x9600, 0xd500, 0xd700, 0xd100, 0xd300, 0xdd00, 0xdf00, 0xd900, 0xdb00, 0xc500, 0xc700, 0xc100, 0xc300, 0xcd00, 0xcf00, 0xc900, 0xcb00, 0xfea8, 0xfeb8, 0xfe88, 0xfe98, 0xfee8, 0xfef8, 0xfec8, 0xfed8, 0xfe28, 0xfe38, 0xfe08, 0xfe18, 0xfe68, 0xfe78, 0xfe48, 0xfe58, 0xffa8, 0xffb8, 0xff88, 0xff98, 0xffe8, 0xfff8, 0xffc8, 0xffd8, 0xff28, 0xff38, 0xff08, 0xff18, 0xff68, 0xff78, 0xff48, 0xff58, 0xfaa0, 0xfae0, 0xfa20, 0xfa60, 0xfba0, 0xfbe0, 0xfb20, 0xfb60, 0xf8a0, 0xf8e0, 0xf820, 0xf860, 0xf9a0, 0xf9e0, 0xf920, 0xf960, 0xfd50, 0xfd70, 0xfd10, 0xfd30, 0xfdd0, 0xfdf0, 0xfd90, 0xfdb0, 0xfc50, 0xfc70, 0xfc10, 0xfc30, 0xfcd0, 0xfcf0, 0xfc90, 0xfcb0, 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1d80, 0x1c80, 0x1f80, 0x1e80, 0x1980, 0x1880, 0x1b80, 0x1a80, 0x0ac0, 0x0a40, 0x0bc0, 0x0b40, 0x08c0, 0x0840, 0x09c0, 0x0940, 0x0ec0, 0x0e40, 0x0fc0, 0x0f40, 0x0cc0, 0x0c40, 0x0dc0, 0x0d40, 0x5600, 0x5200, 0x5e00, 0x5a00, 0x4600, 0x4200, 0x4e00, 0x4a00, 0x7600, 0x7200, 0x7e00, 0x7a00, 0x6600, 0x6200, 0x6e00, 0x6a00, 0x2b00, 0x2900, 0x2f00, 0x2d00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3b00, 0x3900, 0x3f00, 0x3d00, 0x3300, 0x3100, 0x3700, 0x3500, 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01d8, 0x01c8, 0x01f8, 0x01e8, 0x0198, 0x0188, 0x01b8, 0x01a8, 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00d8, 0x00c8, 0x00f8, 0x00e8, 0x0098, 0x0088, 0x00b8, 0x00a8, 0x0560, 0x0520, 0x05e0, 0x05a0, 0x0460, 0x0420, 0x04e0, 0x04a0, 0x0760, 0x0720, 0x07e0, 0x07a0, 0x0660, 0x0620, 0x06e0, 0x06a0, 0x02b0, 0x0290, 0x02f0, 0x02d0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03b0, 0x0390, 0x03f0, 0x03d0, 0x0330, 0x0310, 0x0370, 0x0350 ] private let aLawCompressTable: [UInt8] = [ - 1, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 ] } diff --git a/RootEncoder/Tests/RootEncoderTests/RootEncoderTests.swift b/RootEncoder/Tests/RootEncoderTests/RootEncoderTests.swift index df8fa26..b986597 100644 --- a/RootEncoder/Tests/RootEncoderTests/RootEncoderTests.swift +++ b/RootEncoder/Tests/RootEncoderTests/RootEncoderTests.swift @@ -9,4 +9,24 @@ final class RootEncoderTests: XCTestCase { // Defining Test Cases and Test Methods // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods } + + func testG711Encode() throws { + let pcmBuffer: Array = [0x18, 0x30, 0x40, 0x58] + let g711Buffer: Array = [0xbd, 0xa3] + let codec = G711Codec() + try codec.configure(sampleRate: 8000, channels: 1) + let result = codec.encode(buffer: pcmBuffer, offset: 0, size: pcmBuffer.count) + print(result) + print(g711Buffer) + assert(result == g711Buffer) + } + + func testG711Decode() throws { + let pcmBuffer: Array = [0x18, 0x30, 0x40, 0x58] + let g711Buffer: Array = [0xbd, 0xa3] + let codec = G711Codec() + try codec.configure(sampleRate: 8000, channels: 1) + let result = codec.decode(buffer: g711Buffer, offset: 0, size: g711Buffer.count) + assert(result == pcmBuffer) + } } diff --git a/app/RtspSwiftUIView.swift b/app/RtspSwiftUIView.swift index 816aba7..2f5d41c 100644 --- a/app/RtspSwiftUIView.swift +++ b/app/RtspSwiftUIView.swift @@ -91,7 +91,6 @@ struct RtspSwiftUIView: View, ConnectChecker { camera.onAppear { rtspCamera = RtspCamera(view: cameraView, connectChecker: self) - rtspCamera.setAudioCodec(codec: AudioCodec.G711) rtspCamera.setRetries(reTries: 10) rtspCamera.startPreview() } diff --git a/appTests/appTests.swift b/appTests/appTests.swift index 2695446..5c49724 100644 --- a/appTests/appTests.swift +++ b/appTests/appTests.swift @@ -31,39 +31,4 @@ class appTests: XCTestCase { // Put the code you want to measure the time of here. } } - - func testStapAH265() { - let expectedStapA: [UInt8] = [128, 224, 0, 1, 0, 169, 138, 199, 7, 91, 205, 21, 96, 1, 0, 7, 0, 0, 0, 1, 2, 3, 4, 0, 7, 0, 0, 0, 1, 10, 11, 12] - let fakeSps: [UInt8] = [0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04] - let fakePps: [UInt8] = [0x00, 0x00, 0x00, 0x01, 0x0A, 0x0B, 0x0C] - let fakeVps: [UInt8] = [0x00, 0x00, 0x00, 0x01, 0x0D, 0x0E, 0x0F] - - let header: [UInt8] = [0x00, 0x00, 0x00, 0x01, 0x05, 0x00] - let fakeH265 = header + [UInt8](repeating: 0x00, count: 2500) - - let packet1Size = RtpConstants.MTU - 28 - RtpConstants.rtpHeaderLength - 3 - let chunk1 = fakeH265[header.count.. Date: Sat, 25 May 2024 21:41:49 +0200 Subject: [PATCH 4/5] use AudioConverter to encode alaw --- .../encoder/audio/AudioEncoder.swift | 130 +++++++++++------- .../RootEncoder/encoder/audio/G711Codec.swift | 74 ---------- .../encoder/utils/EncoderUtils.swift | 2 +- .../RootEncoder/library/base/CameraBase.swift | 2 +- .../RootEncoderTests/RootEncoderTests.swift | 20 --- app/RtspSwiftUIView.swift | 1 + 6 files changed, 86 insertions(+), 143 deletions(-) delete mode 100644 RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift diff --git a/RootEncoder/Sources/RootEncoder/encoder/audio/AudioEncoder.swift b/RootEncoder/Sources/RootEncoder/encoder/audio/AudioEncoder.swift index d130176..8d1f7c6 100644 --- a/RootEncoder/Sources/RootEncoder/encoder/audio/AudioEncoder.swift +++ b/RootEncoder/Sources/RootEncoder/encoder/audio/AudioEncoder.swift @@ -17,7 +17,6 @@ public class AudioEncoder { private var initTs: Int64 = 0 private let thread = DispatchQueue(label: "AudioEncoder") private let syncQueue = SynchronizedQueue(label: "AudioEncodeQueue", size: 60) - private let g711Codec = G711Codec() private var codec = AudioCodec.AAC public init(callback: GetAacData) { @@ -29,29 +28,26 @@ public class AudioEncoder { } public func prepareAudio(inputFormat: AVAudioFormat, sampleRate: Double, channels: UInt32, bitrate: Int) -> Bool { - if codec == AudioCodec.AAC { - guard let outputFormat = getAACFormat(sampleRate: sampleRate, channels: channels) else { - return false - } - guard let converter = AVAudioConverter(from: inputFormat, to: outputFormat) else { - return false - } - converter.bitRate = bitrate - self.outputFormat = outputFormat - self.converter = converter + if (codec == AudioCodec.G711 && (sampleRate != 8000 || channels != 1)) { + print("G711 only support samplerate 8000 and mono channel") + return false + } + let format: AVAudioFormat? = if codec == AudioCodec.AAC { + getAACFormat(sampleRate: sampleRate, channels: channels) } else if codec == AudioCodec.G711 { - do { - try g711Codec.configure(sampleRate: sampleRate, channels: channels) - } catch IOException.runtimeError(let error) { - print("Create AudioEncoder failed. \(error)") - return false - } catch { - return false - } + getG711AFormat(sampleRate: sampleRate, channels: channels) } else { - print("invalid codec") + nil + } + guard let outputFormat = format else { return false } + guard let converter = AVAudioConverter(from: inputFormat, to: outputFormat) else { + return false + } + converter.bitRate = bitrate + self.outputFormat = outputFormat + self.converter = converter print("prepare audio success") return true } @@ -70,43 +66,52 @@ public class AudioEncoder { while (self.running) { let b = self.syncQueue.dequeue() if let b = b { - if self.codec == AudioCodec.G711 { - let data = b.audioBufferToBytes() - let mBuffer = self.g711Codec.encode(buffer: data, offset: 0, size: data.count) - let end = Date().millisecondsSince1970 - let elapsedNanoSeconds = (end - self.initTs) * 1000 - var frame = Frame() - frame.buffer = mBuffer - frame.length = UInt32(mBuffer.count) - frame.timeStamp = UInt64(elapsedNanoSeconds) - self.callback?.getAacData(frame: frame) - continue - } var error: NSError? = nil - guard let aacBuffer = self.convertToAAC(buffer: b, error: &error) else { - continue - } - if error != nil { - print("Encode error: \(error.debugDescription)") - } else { - let data = Array(UnsafeBufferPointer(start: aacBuffer.data.assumingMemoryBound(to: UInt8.self), count: Int(aacBuffer.byteLength))) - guard let packetDescriptions = aacBuffer.packetDescriptions else { + if self.codec == AudioCodec.AAC { + guard let aacBuffer = self.convertToAAC(buffer: b, error: &error) else { + continue + } + if error != nil { + print("Encode error: \(error.debugDescription)") + } else { + let data = Array(UnsafeBufferPointer(start: aacBuffer.data.assumingMemoryBound(to: UInt8.self), count: Int(aacBuffer.byteLength))) + guard let packetDescriptions = aacBuffer.packetDescriptions else { + continue + } + for i in 0..(repeating: 0, count: Int(info.mDataByteSize)) + mBuffer[0...mBuffer.count - 1] = data[Int(info.mStartOffset)...Int(info.mStartOffset) + Int(info.mDataByteSize - 1)] + let end = Date().millisecondsSince1970 + let elapsedNanoSeconds = (end - self.initTs) * 1000 + + var frame = Frame() + frame.buffer = mBuffer + frame.length = UInt32(mBuffer.count) + frame.timeStamp = UInt64(elapsedNanoSeconds) + self.callback?.getAacData(frame: frame) + } + } + } else if self.codec == AudioCodec.G711 { + guard let g711Buffer = self.convertToG711(buffer: b, error: &error) else { continue } - for i in 0..(repeating: 0, count: Int(info.mDataByteSize)) - mBuffer[0...mBuffer.count - 1] = data[Int(info.mStartOffset)...Int(info.mStartOffset) + Int(info.mDataByteSize - 1)] + if error != nil { + print("Encode error: \(error.debugDescription)") + } else { + let data = g711Buffer.audioBufferToBytes() let end = Date().millisecondsSince1970 let elapsedNanoSeconds = (end - self.initTs) * 1000 var frame = Frame() - frame.buffer = mBuffer - frame.length = UInt32(mBuffer.count) + frame.buffer = data + frame.length = UInt32(data.count) frame.timeStamp = UInt64(elapsedNanoSeconds) self.callback?.getAacData(frame: frame) + } } + } } } @@ -128,6 +133,16 @@ public class AudioEncoder { return outBuffer } + private func convertToG711(buffer: AVAudioPCMBuffer, error: inout NSError?) -> AVAudioPCMBuffer? { + guard let outputFormat = outputFormat else { + return nil + } + let outBuffer = AVAudioPCMBuffer(pcmFormat: outputFormat, frameCapacity: AVAudioFrameCount(outputFormat.sampleRate) * buffer.frameLength / AVAudioFrameCount(buffer.format.sampleRate))! + outBuffer.frameLength = outBuffer.frameCapacity + self.convert(sourceBuffer: buffer, destinationBuffer: outBuffer, error: &error) + return outBuffer + } + private func convert(sourceBuffer: AVAudioPCMBuffer, destinationBuffer: AVAudioBuffer, error: NSErrorPointer) { if (running) { sourceBuffer.frameLength = sourceBuffer.frameCapacity @@ -149,7 +164,28 @@ public class AudioEncoder { } private func getAACFormat(sampleRate: Double, channels: UInt32) -> AVAudioFormat? { - var description = AudioStreamBasicDescription(mSampleRate: sampleRate, mFormatID: kAudioFormatMPEG4AAC, mFormatFlags: 0, mBytesPerPacket: 0, mFramesPerPacket: 0, mBytesPerFrame: 0, mChannelsPerFrame: channels, mBitsPerChannel: 0, mReserved: 0) + var description = AudioStreamBasicDescription(mSampleRate: sampleRate, + mFormatID: kAudioFormatMPEG4AAC, + mFormatFlags: 0, + mBytesPerPacket: 0, + mFramesPerPacket: 0, + mBytesPerFrame: 0, + mChannelsPerFrame: channels, + mBitsPerChannel: 0, + mReserved: 0) + return AVAudioFormat(streamDescription: &description) + } + + private func getG711AFormat(sampleRate: Double, channels: UInt32) -> AVAudioFormat? { + var description = AudioStreamBasicDescription(mSampleRate: sampleRate, + mFormatID: kAudioFormatALaw, + mFormatFlags: AudioFormatFlags(kAudioFormatALaw), + mBytesPerPacket: 1, + mFramesPerPacket: 1, + mBytesPerFrame: 1, + mChannelsPerFrame: channels, + mBitsPerChannel: 8, + mReserved: 0) return AVAudioFormat(streamDescription: &description) } } diff --git a/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift b/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift deleted file mode 100644 index d0a22cc..0000000 --- a/RootEncoder/Sources/RootEncoder/encoder/audio/G711Codec.swift +++ /dev/null @@ -1,74 +0,0 @@ -// -// File.swift -// -// -// Created by Pedro on 10/5/24. -// - -import Foundation -import AVFoundation - -public class G711Codec { - - public init() {} - - public func configure(sampleRate: Double, channels: UInt32) throws { - if sampleRate != 8000 || channels != 1 { - throw IOException.runtimeError("G711 codec only support 8000 sampleRate and mono channel") - } - } - - public func encode(buffer: Array, offset: Int, size: Int) -> Array{ - var j = offset - let count = size / 2 - var out = [UInt8](repeating: 0, count: count) - for i in 0.., offset: Int, size: Int) -> Array{ - var j = 0 - var out = [UInt8](repeating: 0, count: buffer.count * 2) - for i in 0..> 8) & 0xff) - j += 2 - } - return out - } - - public func linearToALawSample(_ mySample: UInt16) -> UInt8 { - var sample = mySample - let sign = ~sample >> 8 & 0x80 - if sign != 0x80 { - sample = ~sample - } - if sample > cClip { - sample = cClip - } - var s: Int - if sample >= 256 { - let tableValue = Int(sample) >> 8 & 0x7F - let exponent = Int(aLawCompressTable[tableValue]) - let mantissa = Int(sample) >> (exponent + 3) & 0x0F - s = exponent << 4 | mantissa - } else { - s = Int(sample) >> 4 - } - s = s ^ (Int(sign) ^ 0x55) - return s.toUInt8Array()[0] - } - - private let cClip: UInt16 = 32635 - private let aLawDecompressTable: [UInt16] = [ - 0xea80, 0xeb80, 0xe880, 0xe980, 0xee80, 0xef80, 0xec80, 0xed80, 0xe280, 0xe380, 0xe080, 0xe180, 0xe680, 0xe780, 0xe480, 0xe580, 0xf540, 0xf5c0, 0xf440, 0xf4c0, 0xf740, 0xf7c0, 0xf640, 0xf6c0, 0xf140, 0xf1c0, 0xf040, 0xf0c0, 0xf340, 0xf3c0, 0xf240, 0xf2c0, 0xaa00, 0xae00, 0xa200, 0xa600, 0xba00, 0xbe00, 0xb200, 0xb600, 0x8a00, 0x8e00, 0x8200, 0x8600, 0x9a00, 0x9e00, 0x9200, 0x9600, 0xd500, 0xd700, 0xd100, 0xd300, 0xdd00, 0xdf00, 0xd900, 0xdb00, 0xc500, 0xc700, 0xc100, 0xc300, 0xcd00, 0xcf00, 0xc900, 0xcb00, 0xfea8, 0xfeb8, 0xfe88, 0xfe98, 0xfee8, 0xfef8, 0xfec8, 0xfed8, 0xfe28, 0xfe38, 0xfe08, 0xfe18, 0xfe68, 0xfe78, 0xfe48, 0xfe58, 0xffa8, 0xffb8, 0xff88, 0xff98, 0xffe8, 0xfff8, 0xffc8, 0xffd8, 0xff28, 0xff38, 0xff08, 0xff18, 0xff68, 0xff78, 0xff48, 0xff58, 0xfaa0, 0xfae0, 0xfa20, 0xfa60, 0xfba0, 0xfbe0, 0xfb20, 0xfb60, 0xf8a0, 0xf8e0, 0xf820, 0xf860, 0xf9a0, 0xf9e0, 0xf920, 0xf960, 0xfd50, 0xfd70, 0xfd10, 0xfd30, 0xfdd0, 0xfdf0, 0xfd90, 0xfdb0, 0xfc50, 0xfc70, 0xfc10, 0xfc30, 0xfcd0, 0xfcf0, 0xfc90, 0xfcb0, 0x1580, 0x1480, 0x1780, 0x1680, 0x1180, 0x1080, 0x1380, 0x1280, 0x1d80, 0x1c80, 0x1f80, 0x1e80, 0x1980, 0x1880, 0x1b80, 0x1a80, 0x0ac0, 0x0a40, 0x0bc0, 0x0b40, 0x08c0, 0x0840, 0x09c0, 0x0940, 0x0ec0, 0x0e40, 0x0fc0, 0x0f40, 0x0cc0, 0x0c40, 0x0dc0, 0x0d40, 0x5600, 0x5200, 0x5e00, 0x5a00, 0x4600, 0x4200, 0x4e00, 0x4a00, 0x7600, 0x7200, 0x7e00, 0x7a00, 0x6600, 0x6200, 0x6e00, 0x6a00, 0x2b00, 0x2900, 0x2f00, 0x2d00, 0x2300, 0x2100, 0x2700, 0x2500, 0x3b00, 0x3900, 0x3f00, 0x3d00, 0x3300, 0x3100, 0x3700, 0x3500, 0x0158, 0x0148, 0x0178, 0x0168, 0x0118, 0x0108, 0x0138, 0x0128, 0x01d8, 0x01c8, 0x01f8, 0x01e8, 0x0198, 0x0188, 0x01b8, 0x01a8, 0x0058, 0x0048, 0x0078, 0x0068, 0x0018, 0x0008, 0x0038, 0x0028, 0x00d8, 0x00c8, 0x00f8, 0x00e8, 0x0098, 0x0088, 0x00b8, 0x00a8, 0x0560, 0x0520, 0x05e0, 0x05a0, 0x0460, 0x0420, 0x04e0, 0x04a0, 0x0760, 0x0720, 0x07e0, 0x07a0, 0x0660, 0x0620, 0x06e0, 0x06a0, 0x02b0, 0x0290, 0x02f0, 0x02d0, 0x0230, 0x0210, 0x0270, 0x0250, 0x03b0, 0x0390, 0x03f0, 0x03d0, 0x0330, 0x0310, 0x0370, 0x0350 - ] - private let aLawCompressTable: [UInt8] = [ - 0x01, 0x01, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x04, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x05, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x06, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07 - ] -} diff --git a/RootEncoder/Sources/RootEncoder/encoder/utils/EncoderUtils.swift b/RootEncoder/Sources/RootEncoder/encoder/utils/EncoderUtils.swift index 4a5c392..35227ce 100644 --- a/RootEncoder/Sources/RootEncoder/encoder/utils/EncoderUtils.swift +++ b/RootEncoder/Sources/RootEncoder/encoder/utils/EncoderUtils.swift @@ -36,7 +36,7 @@ public extension AVAudioPCMBuffer { } func audioBufferToBytes() -> [UInt8] { - let srcLeft = self.floatChannelData![0] + let srcLeft = self.audioBufferList.pointee.mBuffers.mData! let bytesPerFrame = self.format.streamDescription.pointee.mBytesPerFrame let numBytes = Int(bytesPerFrame * self.frameLength) var audioByteArray = [UInt8](repeating: 0, count: numBytes) diff --git a/RootEncoder/Sources/RootEncoder/library/base/CameraBase.swift b/RootEncoder/Sources/RootEncoder/library/base/CameraBase.swift index 6c336b6..8144331 100644 --- a/RootEncoder/Sources/RootEncoder/library/base/CameraBase.swift +++ b/RootEncoder/Sources/RootEncoder/library/base/CameraBase.swift @@ -48,7 +48,7 @@ public class CameraBase: GetMicrophoneData, GetCameraData, GetAacData, GetH264Da } public func prepareAudio() -> Bool { - prepareAudio(bitrate: 64 * 1024, sampleRate: 8000, isStereo: false) + prepareAudio(bitrate: 64 * 1024, sampleRate: 32000, isStereo: true) } public func prepareVideo(resolution: CameraHelper.Resolution, fps: Int, bitrate: Int, iFrameInterval: Int, rotation: Int) -> Bool { diff --git a/RootEncoder/Tests/RootEncoderTests/RootEncoderTests.swift b/RootEncoder/Tests/RootEncoderTests/RootEncoderTests.swift index b986597..df8fa26 100644 --- a/RootEncoder/Tests/RootEncoderTests/RootEncoderTests.swift +++ b/RootEncoder/Tests/RootEncoderTests/RootEncoderTests.swift @@ -9,24 +9,4 @@ final class RootEncoderTests: XCTestCase { // Defining Test Cases and Test Methods // https://developer.apple.com/documentation/xctest/defining_test_cases_and_test_methods } - - func testG711Encode() throws { - let pcmBuffer: Array = [0x18, 0x30, 0x40, 0x58] - let g711Buffer: Array = [0xbd, 0xa3] - let codec = G711Codec() - try codec.configure(sampleRate: 8000, channels: 1) - let result = codec.encode(buffer: pcmBuffer, offset: 0, size: pcmBuffer.count) - print(result) - print(g711Buffer) - assert(result == g711Buffer) - } - - func testG711Decode() throws { - let pcmBuffer: Array = [0x18, 0x30, 0x40, 0x58] - let g711Buffer: Array = [0xbd, 0xa3] - let codec = G711Codec() - try codec.configure(sampleRate: 8000, channels: 1) - let result = codec.decode(buffer: g711Buffer, offset: 0, size: g711Buffer.count) - assert(result == pcmBuffer) - } } diff --git a/app/RtspSwiftUIView.swift b/app/RtspSwiftUIView.swift index 2f5d41c..816aba7 100644 --- a/app/RtspSwiftUIView.swift +++ b/app/RtspSwiftUIView.swift @@ -91,6 +91,7 @@ struct RtspSwiftUIView: View, ConnectChecker { camera.onAppear { rtspCamera = RtspCamera(view: cameraView, connectChecker: self) + rtspCamera.setAudioCodec(codec: AudioCodec.G711) rtspCamera.setRetries(reTries: 10) rtspCamera.startPreview() } From 454e6b96b4615e3fa3e8cd0d41a4b5c42fc5fee4 Mon Sep 17 00:00:00 2001 From: pedroSG94 Date: Sat, 25 May 2024 21:42:31 +0200 Subject: [PATCH 5/5] remove g711 codec use from rtsp example --- app/RtspSwiftUIView.swift | 1 - 1 file changed, 1 deletion(-) diff --git a/app/RtspSwiftUIView.swift b/app/RtspSwiftUIView.swift index 816aba7..2f5d41c 100644 --- a/app/RtspSwiftUIView.swift +++ b/app/RtspSwiftUIView.swift @@ -91,7 +91,6 @@ struct RtspSwiftUIView: View, ConnectChecker { camera.onAppear { rtspCamera = RtspCamera(view: cameraView, connectChecker: self) - rtspCamera.setAudioCodec(codec: AudioCodec.G711) rtspCamera.setRetries(reTries: 10) rtspCamera.startPreview() }