【发布时间】:2021-04-01 18:07:41
【问题描述】:
我正在使用 AVAudioEngine 来播放和录制音频。对于我的用例,我需要在开始录制音频时播放声音。目前,我的录音似乎是在播放声音之前开始的。如何让声音和录音同时开始?理想情况下,我希望同时开始录音和播放声音,而不是在后期处理中同步它们。
这是我目前的代码:
class Recorder {
enum RecordingState {
case recording, paused, stopped
}
private var engine: AVAudioEngine!
private var mixerNode: AVAudioMixerNode!
private var state: RecordingState = .stopped
private var audioPlayer = AVAudioPlayerNode()
init() {
setupSession()
setupEngine()
}
fileprivate func setupSession() {
let session = AVAudioSession.sharedInstance()
try? session.setCategory(.playAndRecord, options: [.mixWithOthers, .defaultToSpeaker])
try? session.setActive(true, options: .notifyOthersOnDeactivation)
}
fileprivate func setupEngine() {
engine = AVAudioEngine()
mixerNode = AVAudioMixerNode()
// Set volume to 0 to avoid audio feedback while recording.
mixerNode.volume = 0
engine.attach(mixerNode)
engine.attach(audioPlayer)
makeConnections()
// Prepare the engine in advance, in order for the system to allocate the necessary resources.
engine.prepare()
}
fileprivate func makeConnections() {
let inputNode = engine.inputNode
let inputFormat = inputNode.outputFormat(forBus: 0)
print("Input Sample Rate: \(inputFormat.sampleRate)")
engine.connect(inputNode, to: mixerNode, format: inputFormat)
let mainMixerNode = engine.mainMixerNode
let mixerFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: inputFormat.sampleRate, channels: 1, interleaved: false)
engine.connect(mixerNode, to: mainMixerNode, format: mixerFormat)
let path = Bundle.main.path(forResource: "effect1.wav", ofType:nil)!
let url = URL(fileURLWithPath: path)
let file = try! AVAudioFile(forReading: url)
audioPlayer.scheduleFile(file, at: nil)
engine.connect(audioPlayer, to: mainMixerNode, format: nil)
}
//MARK: Start Recording Function
func startRecording() throws {
print("Start Recording!")
let tapNode: AVAudioNode = mixerNode
let format = tapNode.outputFormat(forBus: 0)
let documentURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
// AVAudioFile uses the Core Audio Format (CAF) to write to disk.
// So we're using the caf file extension.
let file = try AVAudioFile(forWriting: documentURL.appendingPathComponent("recording.caf"), settings: format.settings)
tapNode.installTap(onBus: 0, bufferSize: 4096, format: format, block: {
(buffer, time) in
try? file.write(from: buffer)
print(buffer.description)
print(buffer.stride)
//Do Stuff
print("Doing Stuff")
})
try engine.start()
audioPlayer.play()
state = .recording
}
//MARK: Other recording functions
func resumeRecording() throws {
try engine.start()
state = .recording
}
func pauseRecording() {
engine.pause()
state = .paused
}
func stopRecording() {
// Remove existing taps on nodes
mixerNode.removeTap(onBus: 0)
engine.stop()
state = .stopped
}
}
【问题讨论】:
-
不幸的是(也许令人惊讶)我认为没有一种准确的方法可以在不测量延迟的情况下确定延迟
-
@sbooth 我如何测量延迟?
-
理想的方式是使用从设备输出到输入的环回电缆。您将测试信号发送到输出,记录它发送的时间,然后在输入中检测相同的信号。时间差是往返延迟。有多种方法可以使用
AVAudioEngine进行估计,但在我的实验中,没有一个是样本准确的。 -
嗯...我可以这样做,但如果用户降低音量会怎样?这将使检测输出信号变得困难。如果您有办法使用
AVAudioEngine估算往返延迟,请分享它们作为答案。估计总比没有好!
标签: ios swift avfoundation avaudioengine