如何在Python socket中流式传输实时数据

0 投票
1 回答
4905 浏览
提问于 2025-04-18 04:26

我正在开发一个实时应用程序。这个应用程序会接收实时音频,发送给识别器,然后得到结果。我使用一个套接字来进行发送和接收。为了调试,我使用了一个波形文件。所以我读取音频,想要像实时播放一样发送音频。我尝试使用time.sleep来同步发送,但这导致发送速度比实时还慢。我是不是应该使用两个线程,一个用于发送,一个用于接收呢?

while True:
    readable, writable, exceptional = select.select([s], [s], [])
    if readable:
        try:
            data = s.recv(1024)
        except:
            break
        if data == "":
            break
        else:
            for line in data.split("\n"):
                if not line: continue
                t, w = line.split()
                if w == "<EOL>":
                    w = ""
                addResult(t, w)
    if writable:
        now = time.time()
        if (now - start_time) / 0.01 >= frame_count - 5:
            frame_count += 1
            data = wav.readframes(80)
            if data is None:
                s.shutdown(s.SHUT_WR)
                continue
            s.send(struct.pack('I', len(data)) + data)
        else:
            time.sleep(0.005)
    if exceptional:
        print "Hangup"
        break

1 个回答

4

发送实时数据有两种方法:

  • 发送方以特定的速率发送数据:在这种情况下,发送方会在特定的时间段内发送数据,然后再发送下一段。由于每个数据包在传输过程中可能会有不同的延迟,因此会添加某种时间戳,以便接收方知道什么时候播放这个数据包。在这种情况下,使用TCP并不是一个好主意,因为如果数据包丢失,TCP会重新发送,而重新发送的数据包到达时可能已经太晚了。所以通常会使用UDP,并且编码器需要能够处理数据包丢失。这种协议的典型例子是RTP,它在VoIP和其他场景中使用。
  • 接收方以特定的速率接收数据:这仅适用于软实时场景,比如延迟几秒钟或更长时间是可以接受的。在这种情况下,发送方只需使用TCP发送数据,每个流中的“帧”都包含一些时间戳,以便接收方知道什么时候播放它。接收方会根据需要快速或慢速读取数据包。如果数据包到达的速度比需要的慢,它就需要暂停播放,等待更多数据(就像在YouTube等平台上看到的那样);如果数据包到达的速度比需要的快,它会慢慢读取,这样会自动导致发送方减慢发送速度(这是TCP的固有特性)。

你程序的原始方法是发送方以特定的速率传输数据。要继续这种方式,你应该:

  • 使用UDP而不是TCP,这样就不会因为数据包丢失而导致的重传造成延迟
  • 使用能够处理数据包丢失的编码器,比如G.711或类似的
  • 给每个数据包添加时间戳,以便发送方知道什么时候播放它
  • 添加准确的时间控制:使用sleep本身并不能考虑发送数据包前所需的时间,因此你应该记录开始时间,并计算每个数据包需要发送的时间(例如 next_time = last_time + time_span_in_packet)。然后只需睡眠 next_time - current_time 的时间。

撰写回答