Изменение скорости и высоты звука в режиме реального времени [AudioUnit iOS] - PullRequest
0 голосов
/ 02 марта 2020

Мы работаем с Audio Unit на iOS как часть приложения VOIP. Мы успешно проиграли аудио, но теперь мы хотели бы контролировать скорость воспроизведения и высоту звука в режиме реального времени. Мы получаем аудио байты в реальном времени из UDP-сокета.

Это код инициализации аудиоустройства для воспроизведения:

init(_ client: UDPClient, _ tcpClient: TCPClient, _ opusHelper: OpusHelper, _ tvTemp: UILabel) {
        super.init()
        let success = initCircularBuffer(&circularBuffer, 4096)
        if success {
            print("Circular buffer init was successful")
        } else {
            print("Circular buffer init not successful")
        }

        self.tvTemp = tvTemp
        self.opusHelper = opusHelper
        monotonicTimer = MonotonicTimer()

        udpClient = client
        self.tcpClient = tcpClient

        var desc = AudioComponentDescription(
            componentType: OSType(kAudioUnitType_Output),
            componentSubType: OSType(kAudioUnitSubType_VoiceProcessingIO),
            componentManufacturer: OSType(kAudioUnitManufacturer_Apple),
            componentFlags: 0,
            componentFlagsMask: 0
        )

        let inputComponent = AudioComponentFindNext(nil, &desc)

        status = AudioComponentInstanceNew(inputComponent!, &audioUnit)
        if status != noErr {
            print("Audio component instance new error \(status!)")
        }

        // Enable IO for recording
        var flag: UInt32 = 1

        // Enable IO for playback
        status = AudioUnitSetProperty(
            audioUnit!,
            kAudioOutputUnitProperty_EnableIO,
            kAudioUnitScope_Output,
            kOutputBus,
            &flag,
            MemoryLayoutStride.SizeOf32(flag)
        )
        if status != noErr {
            print("Enable IO for playback error \(status!)")
        }



        var ioFormat = CAStreamBasicDescription(
            sampleRate: 48000.0,
            numChannels: 1,
            pcmf: .int16,
            isInterleaved: false
        )



        status = AudioUnitSetProperty(
            audioUnit!,
            AudioUnitPropertyID(kAudioUnitProperty_StreamFormat),
            AudioUnitScope(kAudioUnitScope_Input),
            0,
            &ioFormat!,
            MemoryLayoutStride.SizeOf32(ioFormat)
        )
        if status != noErr {
            print("Unable to set stream format input to output \(status!)")
        }


        var playbackCallback = AURenderCallbackStruct(
            inputProc: AudioController_PlaybackCallback,
            inputProcRefCon: UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
        )


        status = AudioUnitSetProperty(
            audioUnit!,
            AudioUnitPropertyID(kAudioUnitProperty_SetRenderCallback),
            AudioUnitScope(kAudioUnitScope_Input),
            kOutputBus,
            &playbackCallback,
            MemoryLayout<AURenderCallbackStruct>.size.ui
        )


        if status != noErr {
            print("Failed to set recording render callback \(status!)")
        }

        status = AudioUnitInitialize(audioUnit!)
        if status != noErr {
            print("Failed to initialize audio unit \(status!)")
        }
    }

Мы помещаем аудиоданные из UDP в TPCircular Buffer:

   let decodedData = self.opusHelper?.decodeStream(of: self.jitterGet.buffer)
let _ = TPCircularBufferProduceBytes(&self.circularBuffer, decodedData, UInt32(decodedData!.count * 2))

Вот как мы они воспроизводят аудио.

func performPlayback(
        _ ioActionFlags: UnsafeMutablePointer<AudioUnitRenderActionFlags>,
        inTimeStamp: UnsafePointer<AudioTimeStamp>,
        inBufNumber: UInt32,
        inNumberFrames: UInt32,
        ioData: UnsafeMutablePointer<AudioBufferList>
    ) -> OSStatus {
        let buffer = ioData[0].mBuffers


        let bytesToCopy = ioData[0].mBuffers.mDataByteSize
        var bufferTail: UnsafeMutableRawPointer?
        //        print("BYTES TO COPY: \(bytesToCopy)")
        self.availableBytes = 0
        bufferTail = TPCircularBufferTail(&self.circularBuffer, &self.availableBytes)
        bytesToWrite = min(bytesToCopy, self.availableBytes)




        print("BYTES TO WRITE: \(bytesToWrite)")
        if bytesToWrite >= 3840 {
            memcpy(buffer.mData, bufferTail, Int(bytesToWrite))
            TPCircularBufferConsume(&self.circularBuffer, bytesToWrite)
        } else {
            let silence = [Int16](repeating: 0, count: Int(bytesToCopy))
            memcpy(buffer.mData, silence, Int(bytesToCopy))
        }


        return noErr
    }

Теперь мы хотим изменить СКОРОСТЬ и ТОНУШКУ воспроизводимого аудио, можете ли вы рассказать нам о том, как интегрировать Varispeed и Timepitch в нашу текущую конфигурацию, как мы выяснили? что эти свойства могут помочь нам.

{ ссылка } @ hotpaw2 Ваш ответ указал нам правильный путь. Теперь мы хотим изменить скорость и высоту тона.

...