fixed: mic redirection not working on iOS 12

This commit is contained in:
TrueZhuanjia committed 2025-09-24 22:43:14 +08:00
1 parent 9124a1fee5
commit 9a053d9ed8
1 file changed
+55 -30
+55 -30
View File
@@ -23,7 +23,8 @@ public class MicHandler: NSObject {
private var isRecording = false private var isRecording = false
private var useBuiltinMic = false private var useBuiltinMic = false
private var pcm16Buffer = Deque<Int16>() private var pcm16BufferDeque = Deque<Int16>()
private var pcm16BufferArray: [Int16] = []
private let bufferQueue = DispatchQueue(label: "pcm.buffer.queue") private let bufferQueue = DispatchQueue(label: "pcm.buffer.queue")
private var timer: SafeTimer? private var timer: SafeTimer?
@@ -201,22 +202,39 @@ public class MicHandler: NSObject {
} }
} }
private func sendOpusFrame() { private func sendOpusFrameFromDequeBuffer() {
bufferQueue.sync { bufferQueue.sync {
if pcm16Buffer.count >= 960 { if pcm16BufferDeque.count >= 960 {
let chunk = Array(pcm16Buffer.prefix(960)) let chunk = Array(pcm16BufferDeque.prefix(960))
var packet = [UInt8](repeating: 0, count: 4000) var packet = [UInt8](repeating: 0, count: 4000)
guard let enc = self.opusEncoder else {return} guard let enc = self.opusEncoder else {return}
let outBytes = opus_encode(enc, chunk, 960, &packet, Int32(packet.count)) let outBytes = opus_encode(enc, chunk, 960, &packet, Int32(packet.count))
sendMicrophoneData(packet, outBytes) sendMicrophoneData(packet, outBytes)
let removeCount = min(960, pcm16Buffer.count) let removeCount = min(960, pcm16BufferDeque.count)
if removeCount > 0 { if removeCount > 0 {
pcm16Buffer.removeFirst(removeCount) pcm16BufferDeque.removeFirst(removeCount)
} }
} }
} }
} }
private func sendOpusFrameFromArrayBuffer() {
bufferQueue.sync {
if pcm16BufferArray.count >= 960 {
let chunk = Array(pcm16BufferArray.prefix(960))
var packet = [UInt8](repeating: 0, count: 4000)
guard let enc = self.opusEncoder else {return}
let outBytes = opus_encode(enc, chunk, 960, &packet, Int32(packet.count))
sendMicrophoneData(packet, outBytes)
let removeCount = min(960, pcm16BufferArray.count)
if removeCount > 0 {
pcm16BufferArray.removeFirst(removeCount)
}
}
}
}
private func configureEngine() throws { private func configureEngine() throws {
let input = engine.inputNode let input = engine.inputNode
micInputFormat = input.inputFormat(forBus: 0) micInputFormat = input.inputFormat(forBus: 0)
@@ -232,9 +250,6 @@ public class MicHandler: NSObject {
try AVAudioSession.sharedInstance().setPreferredIOBufferDuration(0.02) try AVAudioSession.sharedInstance().setPreferredIOBufferDuration(0.02)
let sinkNode = AVAudioSinkNode { timestamp, frameCount, audioBufferList -> OSStatus in let sinkNode = AVAudioSinkNode { timestamp, frameCount, audioBufferList -> OSStatus in
// 访问 AudioBufferList 数据
// print("sink interval: \((CACurrentMediaTime()-self.globalTimestamp)*1000),frameCount: \(frameCount)")
// self.globalTimestamp = CACurrentMediaTime()
guard self.isRecording else { return noErr} guard self.isRecording else { return noErr}
@@ -250,7 +265,7 @@ public class MicHandler: NSObject {
} }
// 追加到缓冲区 // 追加到缓冲区
self.pcm16Buffer.append(contentsOf: chunk) self.pcm16BufferDeque.append(contentsOf: chunk)
return noErr return noErr
} }
@@ -261,41 +276,51 @@ public class MicHandler: NSObject {
// 开定时器,每 20ms 触发一次 // 开定时器,每 20ms 触发一次
self.timer = SafeTimer(interval:0.02, delay: 0.05) { self.timer = SafeTimer(interval:0.02, delay: 0.05) {
self.sendOpusFrame() self.sendOpusFrameFromDequeBuffer()
} }
} }
else{ else{
engine.attach(playerNode) engine.attach(playerNode)
engine.connect(playerNode, to: engine.mainMixerNode, format: micInputFormat) engine.connect(playerNode, to: engine.mainMixerNode, format: micInputFormat)
input.installTap(onBus: 0, bufferSize: 5760, format: micInputFormat) { [weak self] buffer, _ in input.installTap(onBus: 0, bufferSize: 5760, format: micInputFormat) { [weak self] buffer, _ in
guard let self = self, self.isRecording else { return } guard let self = self, self.isRecording else { return }
DispatchQueue.global().async { let pcm16Buffer = AVAudioPCMBuffer(pcmFormat: pcm16Format!, frameCapacity: buffer.frameCapacity)
let pcm16Buffer = AVAudioPCMBuffer(pcmFormat: pcm16Format!, frameCapacity: buffer.frameCapacity) try? converter?.convert(to: pcm16Buffer!, from: buffer)
try? converter?.convert(to: pcm16Buffer!, from: buffer)
// 处理转换后的 outputBuffer
// =============================== // ===============================
// 🔹 改动 1:把 buffer 转成 PCM16 并保存 // 把 buffer 转成 PCM16 并保存
let frameLength = Int(buffer.frameLength) let frameLength = Int(buffer.frameLength)
let channels = Int(buffer.format.channelCount) let channels = Int(buffer.format.channelCount)
var pcm16InterleavedBuffer = [Int16](repeating: 0, count: frameLength * channels) var pcm16InterleavedBuffer = [Int16](repeating: 0, count: frameLength * channels)
if let floatPtrs = buffer.floatChannelData {
for ch in 0..<channels { for ch in 0..<channels {
if let pcm16Data = pcm16Buffer?.int16ChannelData?[ch] { let floatPtr = floatPtrs[ch]
for i in 0..<frameLength { for i in 0..<frameLength {
pcm16InterleavedBuffer[i * channels + ch] = pcm16Data[i] let f = floatPtr[i]
// 把 float 转到 Int16 范围:假设 float 在 -1…+1 之间
// 乘以 Int16.max (32767),再做裁剪
let scaled = f * Float(Int16.max)
let clipped: Float
if scaled > Float(Int16.max) {
clipped = Float(Int16.max)
} else if scaled < Float(Int16.min) {
clipped = Float(Int16.min)
} else {
clipped = scaled
} }
pcm16InterleavedBuffer[i * channels + ch] = Int16(clipped)
} }
} }
// 🔹 新增:Opus 编码并存入缓存
if let enc = self.opusEncoder {
var packet = [UInt8](repeating: 0, count: 8000)
let outBytes = opus_encode(enc, pcm16InterleavedBuffer, Int32(frameLength), &packet, Int32(packet.count))
sendMicrophoneData(packet, outBytes)
}
} }
// 现在 pcm16InterleavedBuffer 里就是转换后的 Int16 数据
self.pcm16BufferArray.append(contentsOf: pcm16InterleavedBuffer)
}
// 开定时器,每 20ms 触发一次
self.timer = SafeTimer(interval:0.02, delay: 0.05) {
self.sendOpusFrameFromArrayBuffer()
} }
} }