fixed: mic redirection not working on iOS 12
This commit is contained in:
1 parent
9124a1fee5
commit
9a053d9ed8
1 file changed
+58
-33
@@ -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,21 +202,38 @@ 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
|
||||||
@@ -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,44 +276,54 @@ 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
|
// ===============================
|
||||||
|
// 把 buffer 转成 PCM16 并保存
|
||||||
// ===============================
|
let frameLength = Int(buffer.frameLength)
|
||||||
// 🔹 改动 1:把 buffer 转成 PCM16 并保存
|
let channels = Int(buffer.format.channelCount)
|
||||||
let frameLength = Int(buffer.frameLength)
|
var pcm16InterleavedBuffer = [Int16](repeating: 0, count: frameLength * channels)
|
||||||
let channels = Int(buffer.format.channelCount)
|
|
||||||
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
engine.prepare()
|
engine.prepare()
|
||||||
try engine.start()
|
try engine.start()
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user