fixed: mic redirection not working on iOS 12
This commit is contained in:
@@ -23,7 +23,8 @@ public class MicHandler: NSObject {
|
||||
private var isRecording = 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 var timer: SafeTimer?
|
||||
|
||||
@@ -201,21 +202,38 @@ public class MicHandler: NSObject {
|
||||
}
|
||||
}
|
||||
|
||||
private func sendOpusFrame() {
|
||||
private func sendOpusFrameFromDequeBuffer() {
|
||||
bufferQueue.sync {
|
||||
if pcm16Buffer.count >= 960 {
|
||||
let chunk = Array(pcm16Buffer.prefix(960))
|
||||
if pcm16BufferDeque.count >= 960 {
|
||||
let chunk = Array(pcm16BufferDeque.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, pcm16Buffer.count)
|
||||
let removeCount = min(960, pcm16BufferDeque.count)
|
||||
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 {
|
||||
let input = engine.inputNode
|
||||
@@ -232,9 +250,6 @@ public class MicHandler: NSObject {
|
||||
try AVAudioSession.sharedInstance().setPreferredIOBufferDuration(0.02)
|
||||
|
||||
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}
|
||||
|
||||
@@ -250,7 +265,7 @@ public class MicHandler: NSObject {
|
||||
}
|
||||
|
||||
// 追加到缓冲区
|
||||
self.pcm16Buffer.append(contentsOf: chunk)
|
||||
self.pcm16BufferDeque.append(contentsOf: chunk)
|
||||
|
||||
return noErr
|
||||
}
|
||||
@@ -261,44 +276,54 @@ public class MicHandler: NSObject {
|
||||
|
||||
// 开定时器,每 20ms 触发一次
|
||||
self.timer = SafeTimer(interval:0.02, delay: 0.05) {
|
||||
self.sendOpusFrame()
|
||||
self.sendOpusFrameFromDequeBuffer()
|
||||
}
|
||||
}
|
||||
else{
|
||||
engine.attach(playerNode)
|
||||
engine.connect(playerNode, to: engine.mainMixerNode, format: micInputFormat)
|
||||
|
||||
input.installTap(onBus: 0, bufferSize: 5760, format: micInputFormat) { [weak self] buffer, _ in
|
||||
guard let self = self, self.isRecording else { return }
|
||||
|
||||
DispatchQueue.global().async {
|
||||
let pcm16Buffer = AVAudioPCMBuffer(pcmFormat: pcm16Format!, frameCapacity: buffer.frameCapacity)
|
||||
try? converter?.convert(to: pcm16Buffer!, from: buffer)
|
||||
// 处理转换后的 outputBuffer
|
||||
|
||||
// ===============================
|
||||
// 🔹 改动 1:把 buffer 转成 PCM16 并保存
|
||||
let frameLength = Int(buffer.frameLength)
|
||||
let channels = Int(buffer.format.channelCount)
|
||||
var pcm16InterleavedBuffer = [Int16](repeating: 0, count: frameLength * channels)
|
||||
|
||||
let pcm16Buffer = AVAudioPCMBuffer(pcmFormat: pcm16Format!, frameCapacity: buffer.frameCapacity)
|
||||
try? converter?.convert(to: pcm16Buffer!, from: buffer)
|
||||
|
||||
// ===============================
|
||||
// 把 buffer 转成 PCM16 并保存
|
||||
let frameLength = Int(buffer.frameLength)
|
||||
let channels = Int(buffer.format.channelCount)
|
||||
var pcm16InterleavedBuffer = [Int16](repeating: 0, count: frameLength * channels)
|
||||
|
||||
if let floatPtrs = buffer.floatChannelData {
|
||||
for ch in 0..<channels {
|
||||
if let pcm16Data = pcm16Buffer?.int16ChannelData?[ch] {
|
||||
for i in 0..<frameLength {
|
||||
pcm16InterleavedBuffer[i * channels + ch] = pcm16Data[i]
|
||||
let floatPtr = floatPtrs[ch]
|
||||
for i in 0..<frameLength {
|
||||
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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
engine.prepare()
|
||||
try engine.start()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user