微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Python:使用tkinter和sounddevice的线程GUI冻结问题

如何解决Python:使用tkinter和sounddevice的线程GUI冻结问题

我有一个用于处理来自声音设备的音频数据的代码

我的代码通过 tkinter 构建 GUI,并在按下按钮时通过 sounddevice 处理音频数据。

我成功地使用线程类实时处理音频数据。

当我按下开始按钮时,来自麦克风的输入声音完美地输出到扬声器。

但是,停止按钮有问题。

当我按下停止按钮时,我的代码尝试终止线程,但会出现 GUI 冻结。而且线程不会死。

根据堆栈溢出的大量信息,我做了几次尝试,但都失败了。

请检查我的代码并给我一些建议。

这是我的代码

import sounddevice as sd
import numpy as np
import tkinter as tk
from tkinter import ttk
from threading import Thread


class StreamThread(Thread):
    def __init__(self):
        super().__init__()
        self.input_device_index = 0
        self.output_device_index = 4
        self.BLOCK_SHIFT = 128
        self.SAMPLING_RATE = 16000
        self.BLOCK_LEN = 512
        self.soUND_DEVICE_LATENCY = 0.2

    def run(self):
        with sd.Stream(device=(self.input_device_index,self.output_device_index),samplerate=self.SAMPLING_RATE,blocksize=self.BLOCK_SHIFT,dtype=np.float32,latency=self.soUND_DEVICE_LATENCY,channels=1,callback=self.callback):
            input()  # Input start

    def callback(indata,outdata,frames,time,status):
        outdata[:] = indata

class App(tk.Tk):
    def __init__(self):
        super().__init__()

        self.title("Please Help Me")
        self.geometry("400x300")
        self.resizable(0,0)

        start_button = tk.Button(self,overrelief="solid",width=15,command=lambda: start_button_clicked(),text="Start",repeatdelay=1000,repeatinterval=100)
        start_button.grid(column=0,row=5)

        stop_button = tk.Button(self,command=lambda: stop_button_clicked(),text="Stop",repeatinterval=100)
        stop_button.grid(column=0,row=6)


def start_button_clicked():
    stream_thead.start()


def stop_button_clicked():
    # this is problem point
    if stream_thead.isAlive():
        sd.CallbackStop()
        sd.CallbackAbort()
        stream_thead.join()


if __name__ == "__main__":
    stream_thead = StreamThread()
    stream_thead.daemon = True  # set Daemon thread

    app = App()
    app.mainloop()

解决方法

您的代码存在问题:

  • 在 GUI 应用程序中使用控制台 input()。据我了解,您使用 input() 将线程任务置于等待状态。建议改用 threading.Event.wait()
  • sd.CallbackStop()sd.CallbackAbort() 不能破坏 input()。使用 threading.Event.set() 打破 threading.Event.wait()
  • self 中缺少 def callback(indata,...) 参数。应该是 def callback(self,indata,...)

下面是修改代码以解决上述问题:

...
from threading import Thread,Event
...
class StreamThread(Thread):
    ...

    def run(self):
        self.event = Event()
        with sd.Stream(device=(self.input_device_index,self.output_device_index),samplerate=self.SAMPLING_RATE,blocksize=self.BLOCK_SHIFT,dtype=np.float32,latency=self.SOUND_DEVICE_LATENCY,channels=1,callback=self.callback) as self.stream:
            #input()  # Input start
            self.event.wait()

    def terminate(self):
        self.stream.abort() # abort the stream processing
        self.event.set() # break self.event.wait()

    def callback(self,outdata,frames,time,status):
        outdata[:] = indata

...

def stop_button_clicked():
    if stream_thread.is_alive():
        stream_thread.terminate()
        stream_thread.join()

...

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐


Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其他元素将获得点击?
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。)
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbcDriver发生异常。为什么?
这是用Java进行XML解析的最佳库。
Java的PriorityQueue的内置迭代器不会以任何特定顺序遍历数据结构。为什么?
如何在Java中聆听按键时移动图像。
Java“Program to an interface”。这是什么意思?