Я работаю над приложением VoIP и собираюсь транслировать голос с живого микрофона через сокет.
Мне удалось записать звук с AudioQueue
, а затем воспроизвести его, но как я могу отправлять данные с буферизацией в реальном времени через UDPСокет, а затем воспроизводить потоковые данные?
Я также тестировал BlueSocket с простой передачей Data
для UDP Socket и работает хорошо.
Я гуглю, но там не ясноспособ сделать это.
Кто-нибудь может направить меня в правильном направлении?
моя запись / воспроизведение AudioQueue
реализация:
import Foundation
import AudioToolbox
import AVFoundation
func AQAudioQueueInputCallback(inUserData: UnsafeMutableRawPointer?,
inAQ: AudioQueueRef,
inBuffer: AudioQueueBufferRef,
inStartTime: UnsafePointer<AudioTimeStamp>,
inNumberPacketDescriptions: UInt32,
inPacketDescs: UnsafePointer<AudioStreamPacketDescription>?) {
let audioService = unsafeBitCast(inUserData!, to:AudioService.self)
audioService.writePackets(inBuffer: inBuffer)
AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, nil);
print("startingPacketCount: \(audioService.startingPacketCount), maxPacketCount: \(audioService.maxPacketCount)")
if (audioService.maxPacketCount <= audioService.startingPacketCount) {
audioService.stopRecord()
}
}
func AQAudioQueueOutputCallback(inUserData: UnsafeMutableRawPointer?,
inAQ: AudioQueueRef,
inBuffer: AudioQueueBufferRef) {
let audioService = unsafeBitCast(inUserData!, to:AudioService.self)
audioService.readPackets(inBuffer: inBuffer)
AudioQueueEnqueueBuffer(inAQ, inBuffer, 0, nil);
print("startingPacketCount: \(audioService.startingPacketCount), maxPacketCount: \(audioService.maxPacketCount)")
if (audioService.maxPacketCount <= audioService.startingPacketCount) {
audioService.startingPacketCount = 0;
}
}
class AudioService {
var buffer: UnsafeMutableRawPointer
var writeAudioQueueObject: AudioQueueRef?
var readAudioQueueObject: AudioQueueRef?
let numPacketsToRead: UInt32 = 1024
let numPacketsToWrite: UInt32 = 1024
var startingPacketCount: UInt32
var startingReadPacketCount: UInt32
var maxPacketCount: UInt32
let bytesPerPacket: UInt32 = 2
let seconds: UInt32 = 10
var audioFormat: AudioStreamBasicDescription {
return AudioStreamBasicDescription(mSampleRate: 48000.0,
mFormatID: kAudioFormatLinearPCM,
mFormatFlags: AudioFormatFlags(kLinearPCMFormatFlagIsSignedInteger | kLinearPCMFormatFlagIsPacked),
mBytesPerPacket: 2,
mFramesPerPacket: 1,
mBytesPerFrame: 2,
mChannelsPerFrame: 1,
mBitsPerChannel: 16,
mReserved: 0)
}
init(_ obj: Any?) {
startingPacketCount = 0
startingReadPacketCount = 0
maxPacketCount = (48000 * seconds)
buffer = UnsafeMutableRawPointer(malloc(Int(maxPacketCount * bytesPerPacket)))
}
deinit {
buffer.deallocate()
}
func startRecord() {
print("startRecord")
guard writeAudioQueueObject == nil else { return }
data = nil
prepareForRecord()
let err: OSStatus = AudioQueueStart(writeAudioQueueObject!, nil)
print("err: \(err)")
}
func stopRecord() {
if let writeAudioQueue = writeAudioQueueObject {
AudioQueueStop(writeAudioQueue, true)
AudioQueueDispose(writeAudioQueue, true)
writeAudioQueueObject = nil
}
}
func play() {
readAudioQueueObject = nil
prepareForPlay()
guard let readAudioQueue = readAudioQueueObject else {
return
}
let err: OSStatus = AudioQueueStart(readAudioQueue, nil)
print("err: \(err)")
}
func stop() {
if let readAudioQueue = readAudioQueueObject {
AudioQueueStop(readAudioQueue, true)
AudioQueueDispose(readAudioQueue, true)
readAudioQueueObject = nil
}
}
private func prepareForRecord() {
print("prepareForRecord")
var audioFormat = self.audioFormat
AudioQueueNewInput(&audioFormat,
AQAudioQueueInputCallback,
unsafeBitCast(self, to: UnsafeMutableRawPointer.self),
CFRunLoopGetCurrent(),
CFRunLoopMode.commonModes.rawValue,
0,
&writeAudioQueueObject)
startingPacketCount = 0;
var buffers = Array<AudioQueueBufferRef?>(repeating: nil, count: 3)
let bufferByteSize: UInt32 = numPacketsToWrite * audioFormat.mBytesPerPacket
for bufferIndex in 0 ..< buffers.count {
AudioQueueAllocateBuffer(writeAudioQueueObject!, bufferByteSize, &buffers[bufferIndex])
AudioQueueEnqueueBuffer(writeAudioQueueObject!, buffers[bufferIndex]!, 0, nil)
}
}
private func prepareForPlay() {
print("prepareForPlay")
var audioFormat = self.audioFormat
AudioQueueNewOutput(&audioFormat,
AQAudioQueueOutputCallback,
unsafeBitCast(self, to: UnsafeMutableRawPointer.self),
CFRunLoopGetCurrent(),
CFRunLoopMode.commonModes.rawValue,
0,
&readAudioQueueObject)
startingPacketCount = 0
var buffers = Array<AudioQueueBufferRef?>(repeating: nil, count: 3)
let bufferByteSize: UInt32 = numPacketsToRead * audioFormat.mBytesPerPacket
for bufferIndex in 0 ..< buffers.count {
guard let readAudioQueue = readAudioQueueObject else { return }
AudioQueueAllocateBuffer(readAudioQueue, bufferByteSize, &buffers[bufferIndex])
AQAudioQueueOutputCallback(inUserData: unsafeBitCast(self, to: UnsafeMutableRawPointer.self),
inAQ: readAudioQueue,
inBuffer: buffers[bufferIndex]!)
}
}
func readPackets(inBuffer: AudioQueueBufferRef) {
print("readPackets")
// var numPackets: UInt32 = startingPacketCount
var numPackets: UInt32 = maxPacketCount - startingPacketCount
if numPacketsToRead < numPackets {
numPackets = numPacketsToRead
}
if 0 < numPackets {
memcpy(inBuffer.pointee.mAudioData,
buffer.advanced(by: Int(bytesPerPacket * startingPacketCount)),
(Int(bytesPerPacket * numPackets)))
inBuffer.pointee.mAudioDataByteSize = (bytesPerPacket * numPackets)
inBuffer.pointee.mPacketDescriptionCount = numPackets
startingPacketCount += numPackets
}
else {
inBuffer.pointee.mAudioDataByteSize = 0;
inBuffer.pointee.mPacketDescriptionCount = 0;
}
}
func writePackets(inBuffer: AudioQueueBufferRef) {
print("writePackets")
print("writePackets mAudioDataByteSize: \(inBuffer.pointee.mAudioDataByteSize), numPackets: \(inBuffer.pointee.mAudioDataByteSize / 2)")
var numPackets: UInt32 = (inBuffer.pointee.mAudioDataByteSize / bytesPerPacket)
if ((maxPacketCount - startingPacketCount) < numPackets) {
numPackets = (maxPacketCount - startingPacketCount)
}
if 0 < numPackets {
memcpy(buffer.advanced(by: Int(bytesPerPacket * startingPacketCount)),
inBuffer.pointee.mAudioData,
Int(bytesPerPacket * numPackets))
startingPacketCount += numPackets;
}
}
}