def play(self, wav=None, data=None, rate=16000, channels=1, width=2, block=True, spectrum=None):
        """
        play wav file or raw audio (string or generator)
        Args:
            wav: wav file path
            data: raw audio data, str or iterator
            rate: sample rate, only for raw audio
            channels: channel number, only for raw data
            width: raw audio data width, 16 bit is 2, only for raw data
            block: if true, block until audio is played.
            spectrum: if true, use a spectrum analyzer thread to analyze data
        """
        if wav:
            f = wave.open(wav, 'rb')
            rate = f.getframerate()
            channels = f.getnchannels()
            width = f.getsampwidth()

            def gen(w):
                d = w.readframes(CHUNK_SIZE)
                while d:
                    yield d
                    d = w.readframes(CHUNK_SIZE)
                w.close()

            data = gen(f)

        self.stop_event.clear()
        if block:
            self._play(data, rate, channels, width, spectrum)
        else:
            thread = threading.Thread(target=self._play, args=(data, rate, channels, width, spectrum))
            thread.start()
play wav file or raw audio (string or generator)
        Args:
            wav: wav file path
            data: raw audio data, str or iterator
            rate: sample rate, only for raw audio
            channels: channel number, only for raw data
            width: raw audio data width, 16 bit is 2, only for raw data
            block: if true, block until audio is played.
            spectrum: if true, use a spectrum analyzer thread to analyze data