diff --git a/Sources/Media/IOAudioUnit.swift b/Sources/Media/IOAudioUnit.swift index 7b06db778..9bc7adf97 100644 --- a/Sources/Media/IOAudioUnit.swift +++ b/Sources/Media/IOAudioUnit.swift @@ -7,11 +7,6 @@ import SwiftPMSupport final class IOAudioUnit: NSObject, IOUnit { typealias FormatDescription = CMAudioFormatDescription - lazy var codec: AudioCodec = { - var codec = AudioCodec() - codec.lockQueue = lockQueue - return codec - }() let lockQueue = DispatchQueue(label: "com.haishinkit.HaishinKit.AudioIOComponent.lock") var soundTransform: SoundTransform = .init() { didSet { @@ -39,7 +34,15 @@ final class IOAudioUnit: NSObject, IOUnit { var outputFormat: FormatDescription? { return codec.outputFormat?.formatDescription } + var inputBuffer: AVAudioBuffer? { + return codec.inputBuffer + } private(set) var presentationTimeStamp: CMTime = .invalid + private lazy var codec: AudioCodec = { + var codec = AudioCodec() + codec.lockQueue = lockQueue + return codec + }() private lazy var resampler: IOAudioResampler = { var resampler = IOAudioResampler() resampler.delegate = self @@ -90,6 +93,26 @@ final class IOAudioUnit: NSObject, IOUnit { codec.appendSampleBuffer(sampleBuffer) } } + + func appendAudioBuffer(_ audioBuffer: AVAudioBuffer, presentationTimeStamp: CMTime) { + codec.appendAudioBuffer(audioBuffer, presentationTimeStamp: presentationTimeStamp) + } + + func setAudioStreamBasicDescription(_ audioStreamBasicDescription: AudioStreamBasicDescription?) { + guard var audioStreamBasicDescription else { + return + } + let status = CMAudioFormatDescriptionCreate( + allocator: kCFAllocatorDefault, + asbd: &audioStreamBasicDescription, + layoutSize: 0, + layout: nil, + magicCookieSize: 0, + magicCookie: nil, + extensions: nil, + formatDescriptionOut: &inputFormat + ) + } } extension IOAudioUnit: IOUnitEncoding { @@ -108,6 +131,7 @@ extension IOAudioUnit: IOUnitEncoding { extension IOAudioUnit: IOUnitDecoding { // MARK: IOUnitDecoding func startDecoding() { + codec.settings.format = .pcm if let playerNode = mixer?.mediaLink.playerNode { mixer?.audioEngine?.attach(playerNode) } diff --git a/Sources/Media/IOMixer.swift b/Sources/Media/IOMixer.swift index 711cde671..fccee2711 100644 --- a/Sources/Media/IOMixer.swift +++ b/Sources/Media/IOMixer.swift @@ -24,12 +24,6 @@ public final class IOMixer { return AVAudioEngine() } - enum ReadyState { - case standby - case encoding - case decoding - } - public var hasVideo: Bool { get { mediaLink.hasVideo @@ -200,7 +194,6 @@ public final class IOMixer { } #endif - private var readyState: ReadyState = .standby private(set) lazy var audioEngine: AVAudioEngine? = { return IOMixer.audioEngineHolder.retain() }() @@ -247,46 +240,30 @@ public final class IOMixer { extension IOMixer: IOUnitEncoding { /// Starts encoding for video and audio data. public func startEncoding(_ delegate: any AVCodecDelegate) { - guard readyState == .standby else { - return - } - readyState = .encoding videoIO.startEncoding(delegate) audioIO.startEncoding(delegate) } /// Stop encoding. public func stopEncoding() { - guard readyState == .encoding else { - return - } videoIO.stopEncoding() audioIO.stopEncoding() - readyState = .standby } } extension IOMixer: IOUnitDecoding { /// Starts decoding for video and audio data. public func startDecoding() { - guard readyState == .standby else { - return - } audioIO.startDecoding() videoIO.startDecoding() mediaLink.startRunning() - readyState = .decoding } /// Stop decoding. public func stopDecoding() { - guard readyState == .decoding else { - return - } mediaLink.stopRunning() audioIO.stopDecoding() videoIO.stopDecoding() - readyState = .standby } } @@ -375,8 +352,8 @@ extension IOMixer: Running { let isMultiCamSupported = true #endif guard let device = error.device, let format = device.videoFormat( - width: sessionPreset.width ?? Int32(videoIO.codec.settings.videoSize.width), - height: sessionPreset.height ?? Int32(videoIO.codec.settings.videoSize.height), + width: sessionPreset.width ?? Int32(videoIO.settings.videoSize.width), + height: sessionPreset.height ?? Int32(videoIO.settings.videoSize.height), frameRate: videoIO.frameRate, isMultiCamSupported: isMultiCamSupported ), device.activeFormat != format else { diff --git a/Sources/Media/IOVideoUnit.swift b/Sources/Media/IOVideoUnit.swift index 8c3972dc1..3b309d987 100644 --- a/Sources/Media/IOVideoUnit.swift +++ b/Sources/Media/IOVideoUnit.swift @@ -17,11 +17,6 @@ final class IOVideoUnit: NSObject, IOUnit { } } var multiCamCaptureSettings: MultiCamCaptureSettings = .default - lazy var codec: VideoCodec = { - var codec = VideoCodec() - codec.lockQueue = lockQueue - return codec - }() weak var mixer: IOMixer? var muted: Bool { get { @@ -31,7 +26,14 @@ final class IOVideoUnit: NSObject, IOUnit { videoMixer.muted = newValue } } - + var settings: VideoCodecSettings { + get { + return codec.settings + } + set { + codec.settings = newValue + } + } #if os(iOS) || os(macOS) || os(tvOS) var frameRate = IOMixer.defaultFrameRate { didSet { @@ -111,6 +113,11 @@ final class IOVideoUnit: NSObject, IOUnit { videoMixer.delegate = self return videoMixer }() + private lazy var codec: VideoCodec = { + var codec = VideoCodec() + codec.lockQueue = lockQueue + return codec + }() deinit { if Thread.isMainThread { diff --git a/Sources/Net/NetStream.swift b/Sources/Net/NetStream.swift index 0979a7184..c5516a9d7 100644 --- a/Sources/Net/NetStream.swift +++ b/Sources/Net/NetStream.swift @@ -171,10 +171,10 @@ open class NetStream: NSObject { /// Specifies the video compression properties. public var videoSettings: VideoCodecSettings { get { - mixer.videoIO.codec.settings + mixer.videoIO.settings } set { - mixer.videoIO.codec.settings = newValue + mixer.videoIO.settings = newValue } } diff --git a/Sources/RTMP/RTMPConnection.swift b/Sources/RTMP/RTMPConnection.swift index cd96c8954..9472dbdf0 100644 --- a/Sources/RTMP/RTMPConnection.swift +++ b/Sources/RTMP/RTMPConnection.swift @@ -311,7 +311,7 @@ public class RTMPConnection: EventDispatcher { var outputBufferSize: Int = 0 for stream in streams { // in bytes. - outputBufferSize += (Int(stream.mixer.videoIO.codec.settings.bitRate) + stream.mixer.audioIO.codec.settings.bitRate) / 8 + outputBufferSize += (Int(stream.mixer.videoIO.settings.bitRate) + stream.mixer.audioIO.settings.bitRate) / 8 } if socket.outputBufferSize < outputBufferSize { socket.outputBufferSize = outputBufferSize diff --git a/Sources/RTMP/RTMPMessage.swift b/Sources/RTMP/RTMPMessage.swift index 989c9d889..0d4b18f76 100644 --- a/Sources/RTMP/RTMPMessage.swift +++ b/Sources/RTMP/RTMPMessage.swift @@ -586,15 +586,13 @@ final class RTMPAudioMessage: RTMPMessage { switch payload[1] { case FLVAACPacketType.seq.rawValue: let config = AudioSpecificConfig(bytes: [UInt8](payload[codec.headerSize.. AVAudioBuffer? { return payload.withUnsafeMutableBytes { (buffer: UnsafeMutableRawBufferPointer) -> AVAudioBuffer? in - guard let baseAddress = buffer.baseAddress, let buffer = stream.mixer.audioIO.codec.inputBuffer as? AVAudioCompressedBuffer else { + guard let baseAddress = buffer.baseAddress, let buffer = stream.mixer.audioIO.inputBuffer as? AVAudioCompressedBuffer else { return nil } let byteCount = payload.count - codec.headerSize @@ -653,7 +651,7 @@ final class RTMPVideoMessage: RTMPMessage { makeFormatDescription(stream, format: .h264) case FLVAVCPacketType.nal.rawValue: if let sampleBuffer = makeSampleBuffer(stream, type: type, offset: 0) { - stream.mixer.videoIO.codec.appendSampleBuffer(sampleBuffer) + stream.mixer.videoIO.appendSampleBuffer(sampleBuffer) } default: break @@ -668,7 +666,7 @@ final class RTMPVideoMessage: RTMPMessage { makeFormatDescription(stream, format: .hevc) case FLVVideoPacketType.codedFrames.rawValue: if let sampleBuffer = makeSampleBuffer(stream, type: type, offset: 3) { - stream.mixer.videoIO.codec.appendSampleBuffer(sampleBuffer) + stream.mixer.videoIO.appendSampleBuffer(sampleBuffer) } default: break