繁体   English   中英

IOS记录音频并将其实时分割成文件

[英]IOS record audio and split it into files in real time

我正在制作一个需要将音频流传输到服务器的应用程序。 我想要做的是将录制的音频分成块并在录制时上传。

我使用了两台录像机来做到这一点,但效果并不好; 我可以听到块之间的差异(停止几毫秒)。

我怎样才能做到这一点?

您的问题可以分为两部分:录制和分块(和上传,但谁在乎)。

要从麦克风录制并写入文件,您可以使用AVAudioEngineAVAudioFile快速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()
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM