Воспроизведение int16 pyaudio bytearray из UDP-сокета в AVAudioPlayer, iOS - PullRequest
1 голос
/ 25 марта 2020

У меня есть сервер сокетов, который отправляет данные микрофона через UDP с помощью PyAudio. Код выглядит примерно так:

stream = pa.open(
    format=pyaudio.paInt16,
    channels=1,
    rate=44100,
    output=False,
    input=True,
    input_device_index=0,
    frames_per_buffer=4096,
    stream_callback=callback
)

def callback(in_data, frame_count, time_info, status):
    server_socket.sendto(in_data, udp_client)

Используя Python, легко создать клиент, воспроизводящий аудио в режиме реального времени:

stream = pa.open(
    format=pyaudio.paInt16,
    channels=1,
    rate=44100,
    frames_per_buffer=chunk,
    output=True,
    input=False
)

d = client_socket.recvfrom(chunk)
stream.write(d, chunk)

Даже обработка этого байтового массива в Python это очень просто, с этим oneline:

np.frombuffer(in_data, dtype=np.int16)

Тем не менее я понятия не имею, как обрабатывать эту потоковую передачу в Swift 5. Теперь я попытался сделать то же самое в Swift. Это выглядит примерно так:

var stream_buffer = NSMutableData()
self.connection?.receiveMessage { (data, context, isComplete, error) in
    self.stream_buffer.append(data!)
}

И как только stream_buffer получил достаточно данных ...

let format = AVAudioFormat(
    commonFormat: AVAudioCommonFormat.pcmFormatInt16,
    sampleRate: 44100,
    channels: 1,
    interleaved: true
)
let buffer_data = stream_buffer as Data
let buffer = buffer_data.toPCMBuffer(format: format!)

toPCMBuffer здесь

Пока что, Я понятия не имею, правильно ли я выполняю преобразование байтовых массивов, или AVPlayer даже поддерживает байтовые массивы Int16. Если нет, то как мне конвертировать stream_buffer в Float32? Кто-нибудь успешно транслировал звук PCM на iOS?

1 Ответ

0 голосов
/ 26 марта 2020

Не знаю почему, но iOS, похоже, не работает с pcmFormatInt16. Вместо этого у вас есть два варианта: преобразовать байтовый массив на сервере в float32 и установить формат на AVAudioCommonFormat.pcmFormatFloat32 или преобразовать его на устройстве iOS. Последнее, конечно, снижает сетевую активность:

преобразование PCM16 в PCM32, Swift

let fromFormat = AVAudioFormat(
    commonFormat: AVAudioCommonFormat.pcmFormatInt16,
    sampleRate: 44100,
    channels: 1,
    interleaved: true
)
let toFormat = AVAudioFormat(
    commonFormat: AVAudioCommonFormat.pcmFormatFloat32,
    sampleRate: 44100,
    channels: 1,
    interleaved: true
)

...


let buffer = AVAudioPCMBuffer(pcmFormat: toFormat!, frameCapacity: AVAudioFrameCount(44100))

let inputBlock : AVAudioConverterInputBlock = { (inNumPackets, outStatus) -> AVAudioBuffer? in
    outStatus.pointee = AVAudioConverterInputStatus.haveData
    let audioBuffer: AVAudioBuffer = (self.stream_buffer as Data).toPCMBuffer(format: self.fromFormat!)!
    return audioBuffer
}
var error : NSError?
self.converter?.convert(to: buffer!, error: &error, withInputFrom: inputBlock)  

преобразование PCM16 в PCM32, Python

def int16_to_float32(y):
    """Convert int16 numpy array of audio samples to float32."""
    return y.astype(np.float32) / np.iinfo(np.int16).max

audio_data = np.frombuffer(in_data, dtype=np.int16)
audio_data = int16_to_float32(audio_data)
udp_server.send_data(audio_data.data)
...