Python网络音频问题

2 投票
1 回答
2560 浏览
提问于 2025-04-17 04:03

你好,我在网络上传输音频时遇到了一些问题。在我的本地系统上,距离没有问题,但每当我在远程系统上测试时,虽然有音频,但不是我想要的声音输入,听起来很卡顿/延迟。我觉得问题出在我处理音频发送的方式上,但我已经尝试了四天,还是找不到解决办法。

我会把所有相关的代码贴出来,并尽量解释清楚。

这些是常量/全局值


    #initilaize Speex
    speex_enc = speex.Encoder()
    speex_enc.initialize(speex.SPEEX_MODEID_WB)
    speex_dec = speex.Decoder()
    speex_dec.initialize(speex.SPEEX_MODEID_WB)

    #some constant values
    chunk = 320
    FORMAT = pyaudio.paInt16
    CHANNELS = 1
    RATE = 44100

我发现调整采样率的值可以让更多的噪音通过。

下面是用来初始化音频设备的pyAudio代码,这也是全局的。


    #initalize PyAudio
    p = pyaudio.PyAudio()
    stream = p.open(format = FORMAT,
                    channels = CHANNELS,
                    rate = RATE,
                    input = True,
                    output = True,
                    frames_per_buffer = chunk)

下一个函数是按键函数,它从麦克风写入数据并通过客户端函数发送。我认为我在这里遇到了问题。

我觉得我处理这个的方式有问题,因为如果我按住键来获取音频,它会循环并在每次迭代时发送。我不太确定该怎么做。(有什么想法吗!!!)


    def keypress(event):
        #chunklist = []
        #RECORD_SECONDS = 5
        if event.keysym == 'Escape':
            root.destroy()
        #x = event.char
        if event.keysym == 'Control_L':   
            #for i in range(0, 44100 / chunk * RECORD_SECONDS):
            try:
                #get data from mic
                data = stream.read(chunk)
            except IOError as ex:
                if ex[1] != pyaudio.paInputOverflowed:
                    raise
                data = '\x00' * chunk
            encdata = speex_enc.encode(data)        #Encode the data.
            #chunklist.append(encdata)
            #send audio
            client(chr(CMD_AUDIO), encrypt_my_audio_message(encdata))

这是处理音频的服务器代码。


    ### Server function ###
    def server():
        PORT = 9001
        ### Initialize socket 
        server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        server_socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        server_socket.bind((socket.gethostbyname(socket.gethostname()), PORT))
        # socket.gethostbyname(socket.gethostname())
        server_socket.listen(5)
        read_list = [server_socket]
        ### Start receive loop
        while True:
            readable, writable, errored = select.select(read_list, [], [])
            for s in readable:
                if s is server_socket:
                    conn, addr = s.accept()
                    read_list.append(conn)
                    print "Connection from ", addr
                else:
                    msg = conn.recv(2048)
                    if msg:                
                        cmd, msg = ord(msg[0]),msg[1:]
                        ## get a text message from GUI
                        if cmd == CMD_MSG:
                            listb1.insert(END, decrypt_my_message(msg).strip() + "\n")
                            listb1.yview(END)
                        ## get an audio message
                        elif cmd == CMD_AUDIO:
                            # make sure length is 16 --- HACK ---
                            if len(msg) % 16 != 0:
                                msg += '\x00' * (16 - len(msg) % 16)
                            #decrypt audio
                            data = decrypt_my_message(msg)
                            decdata = speex_dec.decode(data)
                            #Write the data back out to the speaker
                            stream.write(decdata, chunk)
                    else:
                        s.close()
                        read_list.remove(s)

为了完整性,这里是Tkinter中键盘绑定的代码。


    root.bind_all('', keypress)

如果你有什么想法,如何让这个按键方法正常工作,或者建议更好的方法,或者我是不是完全做错了什么,都非常感谢。

*谢谢

请注意,我也测试过没有加密方法的情况,结果也是一样的:-)

1 个回答

0

你有没有用 ping 或 ttcp 来测试这两个主机之间的网络性能?

如果你发现延迟有波动,或者有一些数据包丢失,那么你发送语音流的方式就会受到很大影响。因为 TCP 会等着丢失的数据包,报告它丢失了,然后再等着重新发送等等。

在网络不稳定的情况下,你应该使用 UDP,并且使用能够优雅处理丢失数据包的音频压缩方法。此外,你还需要给发送出去的数据包加上时间戳。

撰写回答