From caa921dafc12b2e2c6bf916ebde0a453009b54e2 Mon Sep 17 00:00:00 2001 From: leo Date: Thu, 28 Sep 2023 14:49:51 -0700 Subject: [PATCH] Restore AudioEffect feature --- HaishinKit.xcodeproj/project.pbxproj | 4 ++++ Sources/Media/AudioEffect.swift | 9 +++++++++ Sources/Media/IOAudioUnit.swift | 12 ++++++++++++ Sources/Net/NetStream.swift | 14 ++++++++++++++ 4 files changed, 39 insertions(+) create mode 100644 Sources/Media/AudioEffect.swift diff --git a/HaishinKit.xcodeproj/project.pbxproj b/HaishinKit.xcodeproj/project.pbxproj index a711f952e..200390d8b 100644 --- a/HaishinKit.xcodeproj/project.pbxproj +++ b/HaishinKit.xcodeproj/project.pbxproj @@ -8,6 +8,7 @@ /* Begin PBXBuildFile section */ 035AFA042263868E009DD0BB /* RTMPStreamTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 035AFA032263868E009DD0BB /* RTMPStreamTests.swift */; }; + 1A216BCE25DBFE269F68C42F /* AudioEffect.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A21649B4F13B31B3CE59AE8 /* AudioEffect.swift */; }; 1A216F07B0BD8E05C8ECC8F1 /* AVAudioFormat+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 1A2166D3A449D813866FE9D9 /* AVAudioFormat+Extension.swift */; }; 2901A4EE1D437170002BBD23 /* MediaLink.swift in Sources */ = {isa = PBXBuildFile; fileRef = 2901A4ED1D437170002BBD23 /* MediaLink.swift */; }; 290686031DFDB7A7008EB7ED /* RTMPConnectionTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 290686021DFDB7A6008EB7ED /* RTMPConnectionTests.swift */; }; @@ -410,6 +411,7 @@ /* Begin PBXFileReference section */ 035AFA032263868E009DD0BB /* RTMPStreamTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RTMPStreamTests.swift; sourceTree = ""; }; + 1A21649B4F13B31B3CE59AE8 /* AudioEffect.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AudioEffect.swift; sourceTree = ""; }; 1A2166D3A449D813866FE9D9 /* AVAudioFormat+Extension.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "AVAudioFormat+Extension.swift"; sourceTree = ""; }; 2901A4ED1D437170002BBD23 /* MediaLink.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MediaLink.swift; sourceTree = ""; }; 290686021DFDB7A6008EB7ED /* RTMPConnectionTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = RTMPConnectionTests.swift; sourceTree = ""; }; @@ -1065,6 +1067,7 @@ BC6FC91D29609A6800A746EE /* ShapeFactory.swift */, 29B8768D1CD70AFE00FC07DA /* SoundTransform.swift */, 29B8768F1CD70AFE00FC07DA /* VideoEffect.swift */, + 1A21649B4F13B31B3CE59AE8 /* AudioEffect.swift */, ); path = Media; sourceTree = ""; @@ -1802,6 +1805,7 @@ 29B876901CD70AFE00FC07DA /* IOAudioUnit.swift in Sources */, 29B876771CD70ACE00FC07DA /* HTTPResponse.swift in Sources */, 1A216F07B0BD8E05C8ECC8F1 /* AVAudioFormat+Extension.swift in Sources */, + 1A216BCE25DBFE269F68C42F /* AudioEffect.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Sources/Media/AudioEffect.swift b/Sources/Media/AudioEffect.swift new file mode 100644 index 000000000..381fd4ce7 --- /dev/null +++ b/Sources/Media/AudioEffect.swift @@ -0,0 +1,9 @@ +import AVFoundation +import Foundation + +/// An object that apply an audio effect. +open class AudioEffect: NSObject { + /// Executes to apply an audio effect. + open func execute(_ buffer: AVAudioBuffer, presentationTimeStamp: CMTime) { + } +} diff --git a/Sources/Media/IOAudioUnit.swift b/Sources/Media/IOAudioUnit.swift index 90fec9e6a..fa0331304 100644 --- a/Sources/Media/IOAudioUnit.swift +++ b/Sources/Media/IOAudioUnit.swift @@ -40,6 +40,7 @@ final class IOAudioUnit: NSObject, IOUnit { return codec.outputFormat?.formatDescription } private(set) var presentationTimeStamp: CMTime = .invalid + private var effects: Set = [] private lazy var resampler: IOAudioResampler = { var resampler = IOAudioResampler() resampler.delegate = self @@ -84,6 +85,14 @@ final class IOAudioUnit: NSObject, IOUnit { presentationTimeStamp = sampleBuffer.presentationTimeStamp resampler.appendSampleBuffer(sampleBuffer.muted(muted)) } + + func registerEffect(_ effect: AudioEffect) -> Bool { + effects.insert(effect).inserted + } + + func unregisterEffect(_ effect: AudioEffect) -> Bool { + effects.remove(effect) != nil + } } extension IOAudioUnit: IOUnitEncoding { @@ -165,6 +174,9 @@ extension IOAudioUnit: IOAudioResamplerDelegate { } func resampler(_ resampler: IOAudioResampler, didOutput audioBuffer: AVAudioPCMBuffer, presentationTimeStamp: CMTime) { + for effect in effects { + effect.execute(audioBuffer, presentationTimeStamp: presentationTimeStamp) + } if let mixer { mixer.delegate?.mixer(mixer, didOutput: audioBuffer, presentationTimeStamp: presentationTimeStamp) if mixer.recorder.isRunning.value, let sampleBuffer = audioBuffer.makeSampleBuffer(presentationTimeStamp) { diff --git a/Sources/Net/NetStream.swift b/Sources/Net/NetStream.swift index 333acfeb5..c0d06805f 100644 --- a/Sources/Net/NetStream.swift +++ b/Sources/Net/NetStream.swift @@ -265,6 +265,20 @@ open class NetStream: NSObject { } } + /// Register a audio effect. + public func registerAudioEffect(_ effect: AudioEffect) -> Bool { + mixer.audioIO.lockQueue.sync { + self.mixer.audioIO.registerEffect(effect) + } + } + + /// Unregister a audio effect. + public func unregisterAudioEffect(_ effect: AudioEffect) -> Bool { + mixer.audioIO.lockQueue.sync { + self.mixer.audioIO.unregisterEffect(effect) + } + } + /// Register a video effect. public func registerVideoEffect(_ effect: VideoEffect) -> Bool { mixer.videoIO.lockQueue.sync {