Search code examples
pythonflaskaudio-recordingpyaudio

stop_stream function on pyAudio does not work, any suggestion?


I'm a beginner in using pyAudio library. I have a class that handle the non-blocking recording for my project. I have declared a variable for stream in init function with the data type is None. In short, I made 2 function, start_recording and stop_recording, to handle stream variable too. start_recording works well, but stop_recording function caught the error and said:

"AttributeError: 'NoneType' object has no attribute 'stop_stream'".

I know the problem is caused by the None data type that I gave in self._stream variable of init function, but I don't have any idea how to fix that error, anyone can help me? Thank you :)

p.s. here's my class I have made

class Recorder(object):

    def __init__(self, channels=1, rate=44100, frames_per_buffer=1024):
        self.channels = channels
        self.rate = rate
        self.frames_per_buffer = frames_per_buffer
        self._p = pyaudio.PyAudio()
        self.filewave = None
        self._stream = None

    def start_recording(self, filename, audio_format):
        self.filewave = self.prepare_file(filename, audio_format)
        self._stream = self._p.open(
            format=pyaudio.paInt16,
            channels=self.channels,
            rate=self.rate,
            input=True,
            frames_per_buffer=self.frames_per_buffer,
            stream_callback=self.get_callback())
        self._stream.start_stream()
        return self

    def get_callback(self):
        def callback(data, frame_count, time_info, status):
            self.filewave.writeframes(data)
            return data, pyaudio.paContinue
        return callback

    def prepare_file(self, filename, audio_format="wb"):
        filewave = wave.open(filename, audio_format)
        filewave.setnchannels(self.channels)
        filewave.setsampwidth(self._p.get_sample_size(pyaudio.paInt16))
        filewave.setframerate(self.rate)
        return filewave

    def stop_recording(self):
        self._stream.stop_stream()
        return self

    def close_recording(self):
        self._stream.close()
        self._p.terminate()
        self.filewave.close()

Also note that my code is used with ajax interface.

And my new problem is in the button click event at ajax and now I don't have any idea how to throw Recorder object on url stop at my flask, here's my code of url ajax in my routes flask, can you give me an idea? thanks before

@app.route('/start_recording', methods=['POST'])
def start_recording():
    rfile = Recorder(channels=2)
    rfile.start_recording('output.wav','wb')

@app.route('/stop_recording/<rfile>', methods=['POST'])
def stop_recording(rfile):
    rfile.stop_recording()

Solution

  • In your case rfile should be a global variable.

    If you do not reference rfile as a global variable the object is copied through and the reference to _stream is lost causing

    AttributeError: 'NoneType' object has no attribute 'stop_stream

    Loose the and declare rfile = Recorder(channels=2)outside your function (like a global variable programiz.com/python-programming/…) that way between the call to def start_recording(): and def stop_recording(): you'll know that you are working on the same instance of object Recorder