<filename>crow/asr/nodes/CloudStream.py
#!/usr/bin/env python3
import rospy
from asr.msg import asr_output
from asr.srv import *
import re
import sys
from google.cloud import  speech
from google.cloud.speech import enums
from google.cloud.speech import types
import pyaudio
from six.moves import queue
import time

# Audio recording parameters
RATE = 16000
CHUNK = int(RATE / 10)  # 100ms



class MicrophoneStream(object):
    """Opens a recording stream as a generator yielding the audio chunks."""
    def __init__(self, rate, chunk):
        self._rate = rate
        self._chunk = chunk

        # Create a thread-safe buffer of audio data
        self._buff = queue.Queue()
        self.closed = True

    def __enter__(self):
        self._audio_interface = pyaudio.PyAudio()
        self._audio_stream = self._audio_interface.open(
            format=pyaudio.paInt16,
            # The API currently only supports 1-channel (mono) audio
            # https://goo.gl/z757pE
            channels=1, rate=self._rate,
            input=True, frames_per_buffer=self._chunk,
            # Run the audio stream asynchronously to fill the buffer object.
            # This is necessary so that the input device's buffer doesn't
            # overflow while the calling thread makes network requests, etc.
            stream_callback=self._fill_buffer,
        )

        self.closed = False

        return self

    def __exit__(self, type, value, traceback):
        self._audio_stream.stop_stream()
        self._audio_stream.close()
        self.closed = True
        # Signal the generator to terminate so that the client's
        # streaming_recognize method will not block the process termination.
        self._buff.put(None)
        self._audio_interface.terminate()

    def _fill_buffer(self, in_data, frame_count, time_info, status_flags):
        """Continuously collect data from the audio stream, into the buffer."""
        self._buff.put(in_data)
        return None, pyaudio.paContinue

    def generator(self):
        while not self.closed:
            # Use a blocking get() to ensure there's at least one chunk of
            # data, and stop iteration if the chunk is None, indicating the
            # end of the audio stream.
            chunk = self._buff.get()
            if chunk is None:
                return
            data = [chunk]

            # Now consume whatever other data's still buffered.
            while True:
                try:
                    chunk = self._buff.get(block=False)
                    if chunk is None:
                        return
                    data.append(chunk)
                except queue.Empty:
                    break

            yield b''.join(data)

class SpeechPipe:
    def __init__(self, lang="en-US"):
        self.lang = lang # a BCP-47 language tag
        self.client = speech.SpeechClient()
        self.config = types.RecognitionConfig(encoding=enums.RecognitionConfig.AudioEncoding.LINEAR16,
            sample_rate_hertz=RATE, language_code=self.lang)
        self.streaming_config = types.StreamingRecognitionConfig(
            config=self.config,
            interim_results=True)
        rospy.init_node("asr_node", disable_signals=True)
        rospy.Service('asr', SpeechReco, self.service_callback)
        self.publisher_continuous()
        rospy.spin()

    def service_callback(self, req):
        with MicrophoneStream(RATE, CHUNK) as stream:
            audio_generator = stream.generator()
            requests = (types.StreamingRecognizeRequest(audio_content=content)
                        for content in audio_generator)
            responses = self.client.streaming_recognize(self.streaming_config, requests)
            text = self.process_response(responses)
            print("ASR service response: {}".format(text))
            resp = SpeechRecoResponse()
            resp.str = text
            return resp

    def publisher_continuous(self):
        pub = rospy.Publisher('/asr_output', asr_output, queue_size=10)
        print("Publisher and service ready \nRunning speech recognition...")
        while True:
            with MicrophoneStream(RATE, CHUNK) as stream:
                audio_generator = stream.generator()
                requests = (types.StreamingRecognizeRequest(audio_content=content)
                            for content in audio_generator)

                responses = self.client.streaming_recognize(self.streaming_config, requests)
                text = self.process_response(responses)
                print("Continuous recognition: {}".format(text))
                msg = asr_output()
                msg.header.stamp = rospy.Time.now()
                msg.data = text.strip()
                pub.publish(msg)

    def process_response(self, responses):
        num_chars_printed = 0
        for response in responses:
            if not response.results:
                continue
            result = response.results[0]
            if not result.alternatives:
                continue
            transcript = result.alternatives[0].transcript
            overwrite_chars = ' ' * (num_chars_printed - len(transcript))

            if not result.is_final:
                sys.stdout.write(transcript + overwrite_chars + '\r')
                sys.stdout.flush()
                num_chars_printed = len(transcript)
            else:
                # Exit recognition if any of the transcribed phrases could be one of keywords.
                if re.search(r'\b(quit speech)\b', transcript, re.I):
                    print('Detected the \'quit speech\' command. Exiting..')
                    rospy.signal_shutdown("Detected the quit keyword")
                    break
                num_chars_printed = 0
                text = str(transcript)
                return text


if __name__ == "__main__":
    SpeechPipe()


<filename>crow/asr/nodes/CloudStream.py
#!/usr/bin/env python3
import rospy
from asr.msg import asr_output
from asr.srv import *
import re
import sys
from google.cloud import  speech
from google.cloud.speech import enums
from google.cloud.speech import types
import pyaudio
from six.moves import queue
import time

# Audio recording parameters
RATE = 16000
CHUNK = int(RATE / 10)  # 100ms



class MicrophoneStream(object):
    """Opens a recording stream as a generator yielding the audio chunks."""
    def __init__(self, rate, chunk):
        self._rate = rate
        self._chunk = chunk

        # Create a thread-safe buffer of audio data
        self._buff = queue.Queue()
        self.closed = True

    def __enter__(self):
        self._audio_interface = pyaudio.PyAudio()
        self._audio_stream = self._audio_interface.open(
            format=pyaudio.paInt16,
            # The API currently only supports 1-channel (mono) audio
            # https://goo.gl/z757pE
            channels=1, rate=self._rate,
            input=True, frames_per_buffer=self._chunk,
            # Run the audio stream asynchronously to fill the buffer object.
            # This is necessary so that the input device's buffer doesn't
            # overflow while the calling thread makes network requests, etc.
            stream_callback=self._fill_buffer,
        )

        self.closed = False

        return self

    def __exit__(self, type, value, traceback):
        self._audio_stream.stop_stream()
        self._audio_stream.close()
        self.closed = True
        # Signal the generator to terminate so that the client's
        # streaming_recognize method will not block the process termination.
        self._buff.put(None)
        self._audio_interface.terminate()

    def _fill_buffer(self, in_data, frame_count, time_info, status_flags):
        """Continuously collect data from the audio stream, into the buffer."""
        self._buff.put(in_data)
        return None, pyaudio.paContinue

    def generator(self):
        while not self.closed:
            # Use a blocking get() to ensure there's at least one chunk of
            # data, and stop iteration if the chunk is None, indicating the
            # end of the audio stream.
            chunk = self._buff.get()
            if chunk is None:
                return
            data = [chunk]

            # Now consume whatever other data's still buffered.
            while True:
                try:
                    chunk = self._buff.get(block=False)
                    if chunk is None:
                        return
                    data.append(chunk)
                except queue.Empty:
                    break

            yield b''.join(data)

class SpeechPipe:
    def __init__(self, lang="en-US"):
        self.lang = lang # a BCP-47 language tag
        self.client = speech.SpeechClient()
        self.config = types.RecognitionConfig(encoding=enums.RecognitionConfig.AudioEncoding.LINEAR16,
            sample_rate_hertz=RATE, language_code=self.lang)
        self.streaming_config = types.StreamingRecognitionConfig(
            config=self.config,
            interim_results=True)
        rospy.init_node("asr_node", disable_signals=True)
        rospy.Service('asr', SpeechReco, self.service_callback)
        self.publisher_continuous()
        rospy.spin()

    def service_callback(self, req):
        with MicrophoneStream(RATE, CHUNK) as stream:
            audio_generator = stream.generator()
            requests = (types.StreamingRecognizeRequest(audio_content=content)
                        for content in audio_generator)
            responses = self.client.streaming_recognize(self.streaming_config, requests)
            text = self.process_response(responses)
            print("ASR service response: {}".format(text))
            resp = SpeechRecoResponse()
            resp.str = text
            return resp

    def publisher_continuous(self):
        pub = rospy.Publisher('/asr_output', asr_output, queue_size=10)
        print("Publisher and service ready \nRunning speech recognition...")
        while True:
            with MicrophoneStream(RATE, CHUNK) as stream:
                audio_generator = stream.generator()
                requests = (types.StreamingRecognizeRequest(audio_content=content)
                            for content in audio_generator)

                responses = self.client.streaming_recognize(self.streaming_config, requests)
                text = self.process_response(responses)
                print("Continuous recognition: {}".format(text))
                msg = asr_output()
                msg.header.stamp = rospy.Time.now()
                msg.data = text.strip()
                pub.publish(msg)

    def process_response(self, responses):
        num_chars_printed = 0
        for response in responses:
            if not response.results:
                continue
            result = response.results[0]
            if not result.alternatives:
                continue
            transcript = result.alternatives[0].transcript
            overwrite_chars = ' ' * (num_chars_printed - len(transcript))

            if not result.is_final:
                sys.stdout.write(transcript + overwrite_chars + '\r')
                sys.stdout.flush()
                num_chars_printed = len(transcript)
            else:
                # Exit recognition if any of the transcribed phrases could be one of keywords.
                if re.search(r'\b(quit speech)\b', transcript, re.I):
                    print('Detected the \'quit speech\' command. Exiting..')
                    rospy.signal_shutdown("Detected the quit keyword")
                    break
                num_chars_printed = 0
                text = str(transcript)
                return text


if __name__ == "__main__":
    SpeechPipe()


#!/usr/bin/env python3 # Audio recording parameters # 100ms Opens a recording stream as a generator yielding the audio chunks. # Create a thread-safe buffer of audio data # The API currently only supports 1-channel (mono) audio # https://goo.gl/z757pE # Run the audio stream asynchronously to fill the buffer object. # This is necessary so that the input device's buffer doesn't # overflow while the calling thread makes network requests, etc. # Signal the generator to terminate so that the client's # streaming_recognize method will not block the process termination. Continuously collect data from the audio stream, into the buffer. # Use a blocking get() to ensure there's at least one chunk of # data, and stop iteration if the chunk is None, indicating the # end of the audio stream. # Now consume whatever other data's still buffered. # a BCP-47 language tag # Exit recognition if any of the transcribed phrases could be one of keywords.