我正在编写一个JavaScript Web客户端,并且我想播放客户端中UDP流(原始RTP)中编码为PCM的音频(我可以自由更改流的目标主机和端口)。怎么办?
我阅读了有关Howler的文章,但找不到任何UDP侦听选项或PCM支持。我也看过WebRTC,但它似乎不支持PCM(如果我正确理解的话)。
非常感谢!
答案 0 :(得分:0)
所以我终于做到了! 我写了一个小python服务器将UDP转换为websocket。 我是用Quart编写的,它就像一个异步烧瓶,目的是使websocket和UDP选择更加容易:
import json
import struct
import socket
import asyncio
from quart import Quart, websocket
app = Quart(__name__)
class PcmServerProtocol:
def __init__(self, queue: asyncio.Queue):
self._queue = queue
def connection_made(self, transport):
self.transport = transport
def datagram_received(self, data, addr):
pcm_chunks = struct.unpack(
# Convert the data to pulses
"<" + "h" * (len(data) // struct.calcsize("h")),
data
)
self._queue.put_nowait(json.dumps(pcm_chunks))
async def sending(queue: asyncio.Queue):
while True:
data = await queue.get()
await websocket.send(data)
@app.websocket("/sound")
async def sound():
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
sock.bind(("127.0.0.1", 15000))
pcm_queue = asyncio.Queue()
streamer = asyncio.create_task(sending(pcm_queue))
pcm_receiver = asyncio.create_task(
asyncio.get_event_loop().create_datagram_endpoint(
lambda: PcmServerProtocol(pcm_queue), sock=sock
)
)
await asyncio.gather(streamer, pcm_receiver)
if __name__ == "__main__":
app.run()
现在我们所需要做的就是连接网络插座并播放javascript的声音 为此,我使用了Web Audio API:
let audioCtx = new AudioContext();
let ws = new WebSocket('ws://' + document.domain + ':' + location.port + '/sound');
ws.onmessage = function (event) {
let pcm_chunks = JSON.parse(event.data);
let node = audioCtx.createBufferSource();
let buffer = audioCtx.createBuffer(1, pcm_chunks.length, 44100);
let data = buffer.getChannelData(0);
for (let i = 0; i < pcm_chunks.length; i++) {
// Normalize to between -1.0 and 1.0, my PCM was signed 16bit
data[i] = pcm_chunks[i] / 32768;
}
node.buffer = buffer;
node.loop = false;
node.connect(audioCtx.destination);
node.start(0);
};
我发现的一个缺点是,即使在localhost上运行时声音完美,通过网络进行操作也会使声音滞后。
很显然,我们非常欢迎您发表评论并提出其他想法。