2017-03-15 50 views
1

編輯2:如何轉換音頻,以便它可以跨設備流式傳輸

我已經創建了一個模擬此問題的項目。它所做的只是錄製音頻,將其轉換爲數據,將其轉換回AVAudioPCMBuffer並播放音頻。

這裏是鏈接: https://github.com/Lkember/IntercomTest

有崩潰使用2個頻道的設備時,但我已經固定它。


我一直在尋找的答案,這個問題現在大約一個月左右,所以任何幫助表示讚賞!

我正在使用AVAudioEngine錄製音頻。該音頻是使用自來水記錄:

localInput?.installTap(onBus: 0, bufferSize: 4096, format: localInputFormat) { 

據記載鍵入AVAudioPCMBuffer。它需要被轉換爲類型[UINT8]

我用此方法這樣做:

func audioBufferToBytes(audioBuffer: AVAudioPCMBuffer) -> [UInt8] { 
    let srcLeft = audioBuffer.floatChannelData![0] 
    let bytesPerFrame = audioBuffer.format.streamDescription.pointee.mBytesPerFrame 
    let numBytes = Int(bytesPerFrame * audioBuffer.frameLength) 

    // initialize bytes by 0 
    var audioByteArray = [UInt8](repeating: 0, count: numBytes) 

    srcLeft.withMemoryRebound(to: UInt8.self, capacity: numBytes) { srcByteData in 
     audioByteArray.withUnsafeMutableBufferPointer { 
      $0.baseAddress!.initialize(from: srcByteData, count: numBytes) 
     } 
    } 

    return audioByteArray 
} 

音頻然後被寫入到輸出流。在另一臺設備上,需要將數據轉換回AVAudioPCMBuffer以便播放。我用這個方法:

func bytesToAudioBuffer(_ buf: [UInt8]) -> AVAudioPCMBuffer { 

    let fmt = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: true) 
    let frameLength = UInt32(buf.count)/fmt.streamDescription.pointee.mBytesPerFrame 

    let audioBuffer = AVAudioPCMBuffer(pcmFormat: fmt, frameCapacity: frameLength) 
    audioBuffer.frameLength = frameLength 

    let dstLeft = audioBuffer.floatChannelData![0] 

    buf.withUnsafeBufferPointer { 
     let src = UnsafeRawPointer($0.baseAddress!).bindMemory(to: Float.self, capacity: Int(frameLength)) 
     dstLeft.initialize(from: src, count: Int(frameLength)) 
    } 

    return audioBuffer 
} 

但是,一定是因爲設備上有毛病我的邏輯,當我播放音頻,我聽到的東西,但它只是聽起來像靜態的。

任何幫助表示讚賞,正如我所說,我一直在這個問題上停留了一段時間。


編輯:

感謝您的幫助迄今。我已切換到使用數據。所以我的轉換看起來像這樣(我發現這個代碼在線):

func audioBufferToData(audioBuffer: AVAudioPCMBuffer) -> Data { 
    let channelCount = 1 
    let bufferLength = (audioBuffer.frameCapacity * audioBuffer.format.streamDescription.pointee.mBytesPerFrame) 

    let channels = UnsafeBufferPointer(start: audioBuffer.floatChannelData, count: channelCount) 
    let data = Data(bytes: channels[0], count: Int(bufferLength)) 

    return data 
} 

和轉換回AVAudioPCMBuffer看起來是這樣的:

func dataToAudioBuffer(data: Data) -> AVAudioPCMBuffer { 
    let audioFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 8000, channels: 1, interleaved: false) 
    let audioBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: UInt32(data.count)/2) 
    audioBuffer.frameLength = audioBuffer.frameCapacity 
    for i in 0..<data.count/2 { 
     audioBuffer.floatChannelData?.pointee[i] = Float(Int16(data[i*2+1]) << 8 | Int16(data[i*2]))/Float(INT16_MAX) 
    } 

    return audioBuffer 
} 

不幸的是,同樣的問題依然存在......


編輯4:

提交的答案,在我的樣本項目的問題,H但它並沒有解決我的主要項目中的問題。我這裏補充一個新的問題:

How to send NSData over an OutputStream

回答

0

在這裏你去:

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

func dataToAudioBuffer(data: NSData) -> AVAudioPCMBuffer { 
    let audioFormat = AVAudioFormat(commonFormat: .pcmFormatFloat32, sampleRate: 44100, channels: 1, interleaved: false) 
    let audioBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: UInt32(data.length)/audioFormat.streamDescription.pointee.mBytesPerFrame) 
    audioBuffer.frameLength = audioBuffer.frameCapacity 
    let channels = UnsafeBufferPointer(start: audioBuffer.floatChannelData, count: Int(audioBuffer.format.channelCount)) 
    data.getBytes(UnsafeMutableRawPointer(channels[0]) , length: data.length) 
    return audioBuffer 
} 
+0

這並沒有完全解決我的問題(它在示例項目中做過),但問題仍然存在於我的主項目中。 – Kember

+0

嗨,希望你能幫助我...你有任何使用多路連接的流式麥克風語音樣本 –

+0

@saurabh我沒有樣本,但過去我做過。只需使用AVAudioEngine對象錄製音頻,並使用上述公式將緩衝區轉換爲NSData,然後再傳輸該NSData。然後在其他設備上使用上述功能將其轉換回緩衝區,然後使用AVAudioPlayer播放該緩衝區。 – Logan

1

免責聲明:好吧,這是完全基於來自蘋果文檔的理論 - 我沒有,以前做的,也不是你的代碼足夠的信息,以瞭解你正在努力完成的所有事情。

首先,您要轉換.floatChannelDataUint8其中,根據docsets

四捨五入到零的給定的浮點值創建一個新的實例。

這將導致在充滿可能錯誤或更糟的是,空值(空,如零)的陣列。

以我的理解,.withMemoryRebound不是讓你訪問一個浮點數作爲一個整數。隱含的轉換削減了數字,因此應該扭曲你的結果。這不是你想要的。

相反,你應該使用Audio Converter Services (documentation)

要將浮點audioBuffer 安全和無損轉換爲整數audioBuffer。

我認爲這應該指向正確的方向。 在開始轉換之前,您還應該檢查AVAudioPCMBuffer的格式。處理可能與案例有關。

我希望我可以幫忙。

+0

感謝您的答覆。我一定會查看你發給我的鏈接,看看我能弄明白。否則,如果你想了解更多信息,請告訴我。或者我可以將你鏈接到我的github上? – Kember

+0

雅,給我發GitHub,我可能會爲你弄點東西。我可悲的是不使用迅速而客觀的自己,但我想我可以解決這個問題。 – Maurice

+0

感謝您的關注,這裏是鏈接:https://github.com/Lkember/MotoIntercom – Kember

相關問題