Во время воспроизведения аудиоданных PCM, передаваемых через WebSocket, в React Native и Swift наблюдается только шумIOS

Программируем под IOS
Ответить Пред. темаСлед. тема
Anonymous
 Во время воспроизведения аудиоданных PCM, передаваемых через WebSocket, в React Native и Swift наблюдается только шум

Сообщение Anonymous »

Я разрабатываю приложение React Native, которое получает аудиоданные PCM через WebSocket, декодирует их из строки base64 и пытается воспроизвести их в реальном времени, используя настройку AVAudioEngine в Swift. Несмотря на подтверждение того, что аудиоданные получены правильно путем записи в файл и его воспроизведения в Audacity, воспроизведение в моем приложении представляет собой только шум. Я не могу определить причину.
Код JavaScript:
const handleAudioOutput = async (event) => {
const arrayBuffer = event.data;
const base64Data = Buffer.from(arrayBuffer).toString('base64');
// await RNFS.appendFile(`${RNFS.DocumentDirectoryPath}/audioData.raw`, base64Data, 'base64');
audioPlayer.current.playAudioData(base64Data);
};

useEffect(() => {
audioOutputWs.current = new WebSocket(audioOutputUrl);
audioOutputWs.current.onopen = () => console.log("Audio output ws open");
audioOutputWs.current.binaryType = 'arraybuffer';
audioOutputWs.current.onmessage = handleAudioOutput;
}, []);

На быстрой стороне мы буферизуем полученный звук и воспроизводим из буфера в другом потоке.
Реализация на быстрой стороне:
import Foundation
import AVFoundation

@objc(AudioPlayer)
class AudioPlayer: NSObject {

private var audioEngine: AVAudioEngine
private var audioPlayerNode: AVAudioPlayerNode
private var audioFormat: AVAudioFormat
private var audioQueue: [Data]
private let queueLock = NSLock()
private var isProcessing = false

override init() {
audioEngine = AVAudioEngine()
audioPlayerNode = AVAudioPlayerNode()

// Try using a common sample rate and format
let sampleRate: Double = 24000.0
let channelCount: AVAudioChannelCount = 1
let commonFormat: AVAudioCommonFormat = .pcmFormatInt16

guard let format = AVAudioFormat(commonFormat: commonFormat, sampleRate: sampleRate, channels: channelCount, interleaved: false) else {
fatalError("Failed to create AVAudioFormat")
}

audioFormat = format
audioQueue = []

super.init()

audioEngine.attach(audioPlayerNode)
// If I did format: audioFormat the constructor would crash So I found the below solution from some corner of the internet.
audioEngine.connect(audioPlayerNode, to: audioEngine.outputNode, format: AVAudioFormat.init(standardFormatWithSampleRate: 24000.0, channels: 1)!)

do {
try audioEngine.start()
} catch {
print("Failed to start AVAudioEngine: \(error)")
}

DispatchQueue.global(qos: .background).async {
self.processAudioQueue()
}
}

@objc(multiply:withB:withResolver:withRejecter:)
func multiply(a: Float, b: Float, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
resolve(a * b)
}

@objc(add:withB:withResolver:withRejecter:)
func add(a: Float, b: Float, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
resolve(a + b)
}

@objc(playAudioData:withResolver:withRejecter:)
func playAudioData(base64String: String, resolve: RCTPromiseResolveBlock, reject: RCTPromiseRejectBlock) -> Void {
guard let data = Data(base64Encoded: base64String) else {
reject("error", "Invalid base64 string", nil)
return
}

queueLock.lock()
audioQueue.append(data)
queueLock.unlock()

resolve(true) // Immediately resolve to not block the JS thread
}

private func processAudioQueue() {
isProcessing = true
while isProcessing {
queueLock.lock()
if !audioQueue.isEmpty {
let data: Data = audioQueue.removeFirst()
queueLock.unlock()

let frameCount = AVAudioFrameCount(data.count / MemoryLayout.size)
guard let audioBuffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: frameCount) else {
continue
}
audioBuffer.frameLength = frameCount

// Safe memory transfer using buffer pointers
data.withUnsafeBytes { rawBufferPointer in
guard let bufferPointer = rawBufferPointer.bindMemory(to: Int16.self).baseAddress else {
return
}
guard let channelData = audioBuffer.int16ChannelData else {
return
}

for frameIndex in 0..

Подробнее здесь: https://stackoverflow.com/questions/787 ... -websocket
Реклама
Ответить Пред. темаСлед. тема

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

  • Похожие темы
    Ответы
    Просмотры
    Последнее сообщение

Вернуться в «IOS»