오디오를 서버로 스트리밍해야하는 앱을 만들고 있습니다. 제가하고 싶은 것은 녹음 된 오디오를 청크로 나누어 녹음하는 동안 업로드하는 것입니다.
두 대의 레코더를 사용했지만 제대로 작동하지 않았습니다. 청크의 차이를들을 수 있습니다 (몇 밀리 초 동안 멈춤).
어떻게 할 수 있습니까?
문제는 두 부분으로 나눌 수 있습니다 : 녹음과 청크 (그리고 업로드,하지만 누가 신경 쓰는지).
마이크에서 녹음하고 파일에 쓰는 경우 AVAudioEngine
및로 빠르게 시작할 수 있습니다 AVAudioFile
. 장치의 기본 입력 샘플링 속도로 청크를 기록하는 샘플은 아래를 참조하십시오 (아마도 속도 변환을 원할 것입니다).
"청크 간의 차이"에 대해 이야기 할 때 오디오 데이터를 여러 조각으로 나눌 수있는 기능을 언급하는 것입니다. 이러한 기능을 연결하면 불연속 소리가 들리지 않습니다. 예를 들어 LPCM 오디오 데이터는 샘플 수준에서 청크로 나눌 수 있지만 LPCM 비트 전송률이 높기 때문에 adpcm (iOS에서는 ima4라고 함) 또는 mp3 또는 aac와 같은 패킷 화 된 형식을 사용할 가능성이 더 큽니다. 이러한 형식은 패킷 경계 (예 : 64, 576 또는 1024 샘플)에서만 나눌 수 있습니다. 청크가 헤더없이 작성 되었다면 (일반적으로 mp3 및 aac, ima4에 대해 확실하지 않음) 연결은 간단합니다. 청크를 끝에서 끝까지 배치하기 만하면됩니다.cat
명령 줄 도구를 사용합니다. 안타깝게도 iOS에는 mp3 인코더가 없으므로 aac를 가능한 형식으로 남겨 두지 만 재생 요구 사항에 따라 다릅니다. iOS 기기 및 Mac에서 확실히 재생할 수 있습니다.
import AVFoundation
class ViewController: UIViewController {
let engine = AVAudioEngine()
struct K {
static let secondsPerChunk: Float64 = 10
}
var chunkFile: AVAudioFile! = nil
var outputFramesPerSecond: Float64 = 0 // aka input sample rate
var chunkFrames: AVAudioFrameCount = 0
var chunkFileNumber: Int = 0
func writeBuffer(_ buffer: AVAudioPCMBuffer) {
let samplesPerSecond = buffer.format.sampleRate
if chunkFile == nil {
createNewChunkFile(numChannels: buffer.format.channelCount, samplesPerSecond: samplesPerSecond)
}
try! chunkFile.write(from: buffer)
chunkFrames += buffer.frameLength
if chunkFrames > AVAudioFrameCount(K.secondsPerChunk * samplesPerSecond) {
chunkFile = nil // close file
}
}
func createNewChunkFile(numChannels: AVAudioChannelCount, samplesPerSecond: Float64) {
let fileUrl = NSURL(fileURLWithPath: NSTemporaryDirectory()).appendingPathComponent("chunk-\(chunkFileNumber).aac")!
print("writing chunk to \(fileUrl)")
let settings: [String: Any] = [
AVFormatIDKey: kAudioFormatMPEG4AAC,
AVEncoderBitRateKey: 64000,
AVNumberOfChannelsKey: numChannels,
AVSampleRateKey: samplesPerSecond
]
chunkFile = try! AVAudioFile(forWriting: fileUrl, settings: settings)
chunkFileNumber += 1
chunkFrames = 0
}
override func viewDidLoad() {
super.viewDidLoad()
let input = engine.inputNode!
let bus = 0
let inputFormat = input.inputFormat(forBus: bus)
input.installTap(onBus: bus, bufferSize: 512, format: inputFormat) { (buffer, time) -> Void in
DispatchQueue.main.async {
self.writeBuffer(buffer)
}
}
try! engine.start()
}
}
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다