Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to record and play with AVAudioEngine with 8000 PCM format?

I want to use this code for VoIP service.

i'm using web-socket and sending with it: let data = self.toNSData(PCMBuffer: buffer) and playback:let audioBuffer = self.toPCMBuffer(data: data) in another device)

I'm used: https://github.com/Lkember/IntercomTest and worked it but the size of data is big. I'm feeling 41100 rates is a very big size for send data, I want to reduce buffer size with the lower rate to 8000.

but I do not know how to reduce sample rate without according error!

my failing code is below:

@IBAction func start(_ sender: Any) {


        var engine = AVAudioEngine()
        let input = engine.inputNode
        let bus = 0

        let localAudioPlayer: AVAudioPlayerNode = AVAudioPlayerNode()

        let mixer = AVAudioMixerNode()

        let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)

        engine.attach(mixer)

        engine.connect(input, to: mixer, format: input.outputFormat(forBus: 0))

        mixer.volume = 0
        engine.connect(mixer, to: localAudioPlayer, format: fmt)

        localAudioPlayer.installTap(onBus: bus, bufferSize: 512, format: fmt) { (buffer, time) -> Void in
            // 8kHz buffers!
            print(buffer.format)
            localAudioPlayer.scheduleBuffer(buffer)
        }

        let data = self.toNSData(PCMBuffer: buffer)

        let audioBuffer = self.toPCMBuffer(data: data)

        localAudioPlayer.scheduleBuffer(audioBuffer)
        if (!localAudioPlayer.isPlaying) {
            localAudioPlayer.play()


        try! engine.start()

    }
}
    func toNSData(PCMBuffer: AVAudioPCMBuffer) -> NSData {
        let channelCount = 1  // given PCMBuffer channel count is 1
        let channels = UnsafeBufferPointer(start: PCMBuffer.floatChannelData, count: channelCount)
        let ch0Data = NSData(bytes: channels[0], length:Int(PCMBuffer.frameCapacity * PCMBuffer.format.streamDescription.pointee.mBytesPerFrame))
        return ch0Data
    }

    func toPCMBuffer(data: NSData) -> AVAudioPCMBuffer {
        let audioFormat = AVAudioFormat(commonFormat: AVAudioCommonFormat.pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false)  // given NSData audio format
        let PCMBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: UInt32(data.length) / audioFormat.streamDescription.pointee.mBytesPerFrame)
        PCMBuffer.frameLength = PCMBuffer.frameCapacity
        let channels = UnsafeBufferPointer(start: PCMBuffer.floatChannelData, count: Int(PCMBuffer.format.channelCount))
        data.getBytes(UnsafeMutableRawPointer(channels[0]) , length: data.length)
        return PCMBuffer
    }
like image 253
ehsan Avatar asked Mar 13 '18 08:03

ehsan


People also ask

What is PCM audio recording equipment?

Today, with the introduction of computing, PCM audio recording equipment no longer uses tapes but computer hard drives to record from 1 to multiple channels, using hardware such as sound cards, high-quality microphones. and mixing consoles along with commercial or free software components for audio recording, editing, and mastering.

How to convert analog to digital PCM audio?

The conversion from analog to digital PCM audio is done through a process called sampling ( 5 ). In the process of sampling, we will consider the sampling rate ( 7) and the bit depth ( 6 ). First, we will define PCM audio, then we will explain how we go from analog to digital. We will also compare it with Dolby Digital and Bitstream. Let´s go.

What is the best way to play audio from AVR?

AVR's high speed PWM is used to play the audio. It almost sound fine and can be used for simple projects that require sound effects. The code is compiled in winavr GCC compiler. The microcontroller used is ATmega32, though any AVR processor can be used for the purpose.

When did the BBC start using PCM audio?

In the United Kingdom, the British corporation BBC also experimented with the use of PCM audio technology with the development of a 13-channel audio system, made in 1972 to improve the audio of its television broadcasts. This system continued to be used until 10 years later.


1 Answers

You can use below code to convert as you want.

let inputNode = audioEngine.inputNode
    let downMixer = AVAudioMixerNode()
    let main = audioEngine.mainMixerNode

    let format = inputNode.inputFormat(forBus: 0)
    let format16KHzMono = AVAudioFormat(commonFormat: AVAudioCommonFormat.pcmFormatInt16, sampleRate: 8000, channels: 1, interleaved: true)

    audioEngine.attach(downMixer)
    downMixer.installTap(onBus: 0, bufferSize: 640, format: format16KHzMono) { (buffer, time) -> Void in
        do{
            print(buffer.description)
            if let channel1Buffer = buffer.int16ChannelData?[0] {
                // print(channel1Buffer[0])
                for i in 0 ... Int(buffer.frameLength-1) {
                    print((channel1Buffer[i]))
                }
            }
        }
    }

    audioEngine.connect(inputNode, to: downMixer, format: format)
    audioEngine.connect(downMixer, to: main, format: format16KHzMono)
    audioEngine.prepare()
    try! audioEngine.start()

In Addition

you can use commonFormat instead settings parameter.

let format16KHzMono = AVAudioFormat(settings: [AVFormatIDKey: AVAudioCommonFormat.pcmFormatInt16,
                                                               AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue,
                                                               AVEncoderBitRateKey: 16,
                                                               AVNumberOfChannelsKey: 1,
                                                               AVSampleRateKey: 8000.0] as [String : AnyObject])
like image 153
Pranavan SP Avatar answered Sep 18 '22 08:09

Pranavan SP