Arjun Biju
Arjun Biju

Reputation: 73

segmentation fault :pyaudio recording in no blocking mode

I've been trying to record audio using pyaudio untill silence is met in the input stream .but segmentation fault happens while running it .i don't think anything is wrong with pyaudio/portaudio installed in my raspberry pi because pyaudio works when i tried to run examples in pyaudio docs it works without any issue .i tried to debug it with pdb and gdb these are the results :

    Recording: Setting up

    Thread 1 "python" received signal SIGSEGV, Segmentation fault.
    0x7652a298 in ?? ()
    from /usr/lib/python2.7/dist-packages/_portaudio.arm-linux-     gnueabihf.so
    (gdb) backtrace
    #0  0x7652a298 in ?? ()
     from /usr/lib/python2.7/dist-packages/_portaudio.arm-linux-  gnueabihf.so
     #1  0x764f47b0 in Pa_GetDeviceInfo ()
     from /usr/lib/arm-linux-gnueabihf/libportaudio.so.2
     #2  0x7effe2c4 in ?? ()
     Backtrace stopped: previous frame identical to this frame (corrupt   stack?)
     (gdb) 

pyaudio callback function

def _callback(self, in_data, frame_count, time_info, status):  # pylint: disable=unused-argument

    debug = logging.getLogger('alexapi').getEffectiveLevel() == logging.DEBUG

    if not in_data:
        self._queue.put(False)
        return None, pyaudio.paAbort

    do_VAD = True
    if self._callback_data['force_record'] and not self._callback_data['force_record'][1]:
        do_VAD = False

    # do not count first 10 frames when doing VAD
    if do_VAD and (self._callback_data['frames'] < self._callback_data['throwaway_frames']):
        self._callback_data['frames'] += 1

    # now do VAD
    elif (self._callback_data['force_record'] and self._callback_data['force_record'][0]()) \
            or (do_VAD and (self._callback_data['thresholdSilenceMet'] is False)
                and ((time.time() - self._callback_data['start']) < self.MAX_RECORDING_LENGTH)):

        if do_VAD:

            if int(len(in_data) / 2) == self.VAD_PERIOD:
                isSpeech = self._vad.is_speech(in_data, self.VAD_SAMPLERATE)

                if not isSpeech:
                    self._callback_data['silenceRun'] += 1
                else:
                    self._callback_data['silenceRun'] = 0
                    self._callback_data['numSilenceRuns'] += 1

            # only count silence runs after the first one
            # (allow user to speak for total of max recording length if they haven't said anything yet)
            if (self._callback_data['numSilenceRuns'] != 0) \
                    and ((self._callback_data['silenceRun'] * self.VAD_FRAME_MS) > self.VAD_SILENCE_TIMEOUT):
                self._callback_data['thresholdSilenceMet'] = True

    else:
        self._queue.put(False)
        return None, pyaudio.paComplete

    self._queue.put(in_data)
    if debug:
        self._callback_data['audio'] += in_data

    return None, pyaudio.paContinue

pyaudio

def _callback(self, in_data, frame_count, time_info, status):  # pylint: disable=unused-argument

    debug = logging.getLogger('alexapi').getEffectiveLevel() == logging.DEBUG

    if not in_data:
        self._queue.put(False)
        return None, pyaudio.paAbort

    do_VAD = True
    if self._callback_data['force_record'] and not self._callback_data['force_record'][1]:
        do_VAD = False

    # do not count first 10 frames when doing VAD
    if do_VAD and (self._callback_data['frames'] < self._callback_data['throwaway_frames']):
        self._callback_data['frames'] += 1

    # now do VAD
    elif (self._callback_data['force_record'] and self._callback_data['force_record'][0]()) \
            or (do_VAD and (self._callback_data['thresholdSilenceMet'] is False)
                and ((time.time() - self._callback_data['start']) < self.MAX_RECORDING_LENGTH)):

        if do_VAD:

            if int(len(in_data) / 2) == self.VAD_PERIOD:
                isSpeech = self._vad.is_speech(in_data, self.VAD_SAMPLERATE)

                if not isSpeech:
                    self._callback_data['silenceRun'] += 1
                else:
                    self._callback_data['silenceRun'] = 0
                    self._callback_data['numSilenceRuns'] += 1

            # only count silence runs after the first one
            # (allow user to speak for total of max recording length if they haven't said anything yet)
            if (self._callback_data['numSilenceRuns'] != 0) \
                    and ((self._callback_data['silenceRun'] * self.VAD_FRAME_MS) > self.VAD_SILENCE_TIMEOUT):
                self._callback_data['thresholdSilenceMet'] = True

    else:
        self._queue.put(False)
        return None, pyaudio.paComplete

    self._queue.put(in_data)
    if debug:
        self._callback_data['audio'] += in_data

    return None, pyaudio.paContinue

These are actually adaptation of the code that i found somewhere on the internet.i double checked my device index and sample rate there is nothing wrong with them can someone help me sort it out ? complete code is here

pdb result

    > /usr/lib/python2.7/dist-packages/pyaudio.py(438)__init__()
   -> arguments['stream_callback'] = stream_callback
   (Pdb) step
    > /usr/lib/python2.7/dist-packages/pyaudio.py(441)__init__()
    -> self._stream = pa.open(**arguments)
   (Pdb) step
   Segmentation fault
    root@raspberrypi:/home/pi/Desktop# python -m pdb rp3test.py 

Upvotes: 3

Views: 1507

Answers (1)

Arjun Biju
Arjun Biju

Reputation: 73

Idk may it's just a bug in pyaudio and everylibs that uses pyaudio such as python sounddevice . cause i tried it with sounddevice library . Finally made it work with this code

def silence_listener(throwaway_frames,filename = "recording.wav"):
# Reenable reading microphone raw data
inp = alsaaudio.PCM(alsaaudio.PCM_CAPTURE, alsaaudio.PCM_NORMAL, alsa_card)
inp.setchannels(1)
inp.setrate(VAD_SAMPLERATE)
inp.setformat(alsaaudio.PCM_FORMAT_S16_LE)
inp.setperiodsize(VAD_PERIOD)
audio = ""


# Buffer as long as we haven't heard enough silence or the total size is within max size
thresholdSilenceMet = False
frames = 0
numSilenceRuns = 0
silenceRun = 0
start = time.time()

# do not count first 10 frames when doing VAD
while (frames < throwaway_frames): # VAD_THROWAWAY_FRAMES):
    l, data = inp.read()
    frames = frames + 1
    if l:
        audio += data
        isSpeech = vad.is_speech(data, VAD_SAMPLERATE)

# now do VAD
while (thresholdSilenceMet == False) and ((time.time() - start) < MAX_RECORDING_LENGTH):
    l, data = inp.read()
    if l:
        audio += data

        if (l == VAD_PERIOD):
            isSpeech = vad.is_speech(data, VAD_SAMPLERATE)

            if (isSpeech == False):
                silenceRun = silenceRun + 1
                #print "0"
            else:
                silenceRun = 0
                numSilenceRuns = numSilenceRuns + 1
                #print "1"

    # only count silence runs after the first one
    # (allow user to speak for total of max recording length if they haven't said anything yet)
    if (numSilenceRuns != 0) and ((silenceRun * VAD_FRAME_MS) > VAD_SILENCE_TIMEOUT):
        thresholdSilenceMet = True

if debug: print ("End recording")

rf = open(filename, 'w')
rf.write(audio)
rf.close()
inp.close()
return

Upvotes: 0

Related Questions