record_audio.cc
Go to the documentation of this file.
00001 // Copyright (c) 2017, The Regents of the University of California
00002 // All rights reserved.
00003 //
00004 // Redistribution and use in source and binary forms, with or without
00005 // modification, are permitted provided that the following conditions are met:
00006 // * Redistributions of source code must retain the above copyright
00007 //   notice, this list of conditions and the following disclaimer.
00008 // * Redistributions in binary form must reproduce the above copyright
00009 //   notice, this list of conditions and the following disclaimer in the
00010 //   documentation and/or other materials provided with the distribution.
00011 // * Neither the name of the University of California nor the
00012 //   names of its contributors may be used to endorse or promote products
00013 //   derived from this software without specific prior written permission.
00014 //
00015 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
00016 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
00017 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
00018 // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA
00019 // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
00020 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
00021 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
00022 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
00023 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
00024 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
00025 // POSSIBILITY OF SUCH DAMAGE.
00026 
00027 #include "cogrob/cloud/speech/record_audio.h"
00028 
00029 #include <cmath>
00030 #include <memory>
00031 #include <string>
00032 #include <thread>
00033 #include <utility>
00034 #include <vector>
00035 
00036 #include "cogrob/cloud/speech/audio_sample.h"
00037 #include "third_party/portaudio.h"
00038 #include "third_party/glog.h"
00039 #include "third_party/gflags.h"
00040 
00041 DEFINE_string(mic, "USB", "Name of the microphone");
00042 
00043 using std::unique_ptr;
00044 using std::string;
00045 
00046 namespace cogrob {
00047 namespace cloud {
00048 namespace speech {
00049 
00050 AudioRecorder::AudioRecorder(AudioQueue* output_queue) {
00051   queue_ = output_queue;
00052   StartRecording();
00053 }
00054 
00055 AudioRecorder::~AudioRecorder() {
00056   StopRecording();
00057 }
00058 
00059 void AudioRecorder::StartRecording() {
00060   PaError pa_err = paNoError;
00061 
00062   // Intialize PortAudio
00063   pa_err = Pa_Initialize();
00064   if (pa_err != paNoError) {
00065     LOG(FATAL) << "PortAudio init error: " << Pa_GetErrorText(pa_err);
00066   }
00067 
00068   // Find the microphone
00069   PaDeviceIndex num_devices;
00070   num_devices = Pa_GetDeviceCount();
00071   if (num_devices < 0) {
00072       LOG(FATAL) << "Pa_CountDevices returned " << num_devices;
00073   }
00074   bool found_mic = false;
00075   PaDeviceIndex device_index = 0;
00076   const PaDeviceInfo* device_info;
00077   for (PaDeviceIndex i = 0; i < num_devices; ++i) {
00078       device_info = Pa_GetDeviceInfo(i);
00079       LOG(INFO) << "Device " << device_info->name << " has "
00080                 << device_info->maxInputChannels << " input channels.";
00081       if (string(device_info->name).find(FLAGS_mic) != string::npos) {
00082         found_mic = true;
00083         device_index = i;
00084         LOG(INFO) << "Use device " << device_info->name;
00085         break;
00086       }
00087   }
00088   if (!found_mic) {
00089     LOG(FATAL) << "Can not find device " << FLAGS_mic;
00090   }
00091 
00092   // Open an audio I/O stream
00093   PaStreamParameters input_param = {
00094     .device = device_index,
00095     .channelCount = 1,
00096     .sampleFormat = paInt16,
00097     .suggestedLatency = 0,
00098     .hostApiSpecificStreamInfo = nullptr
00099   };
00100 
00101   pa_err = Pa_OpenStream(&pa_stream_, &input_param, nullptr, SAMPLE_RATE,
00102                          SAMPLES_PER_SLICE, paNoFlag,
00103                          AudioRecorder::PortAudioCallback, this);
00104 
00105   if (pa_err != paNoError) {
00106     LOG(FATAL) << "PortAudio open stream error: " << Pa_GetErrorText(pa_err);
00107   }
00108   // Start the stream
00109   Pa_StartStream(pa_stream_);
00110   if (pa_err != paNoError) {
00111     LOG(FATAL) << "PortAudio start stream error: " << Pa_GetErrorText(pa_err);
00112   }
00113 
00114 }
00115 
00116 void AudioRecorder::StopRecording() {
00117   PaError pa_err = paNoError;
00118   Pa_StopStream(pa_stream_);
00119   if (pa_err != paNoError) {
00120     LOG(FATAL) << "PortAudio stop stream error: " << Pa_GetErrorText(pa_err);
00121   }
00122   Pa_CloseStream(pa_stream_);
00123   if (pa_err != paNoError) {
00124     LOG(FATAL) << "PortAudio close stream error: " << Pa_GetErrorText(pa_err);
00125   }
00126 }
00127 
00128 int AudioRecorder::PortAudioCallback(
00129     const void* input, void* output, unsigned long frame_count,
00130     const PaStreamCallbackTimeInfo* time_info,
00131     PaStreamCallbackFlags status_flags, void* user_data) {
00132   AudioRecorder* recorder = static_cast<AudioRecorder*>(user_data);
00133 
00134   LOG_IF(ERROR, frame_count != SAMPLES_PER_SLICE) << "Callback frame_count is "
00135       << frame_count << ", which is not " << SAMPLES_PER_SLICE;
00136   LOG_IF(ERROR, status_flags) << "Callback status flag is " << status_flags;
00137 
00138   std::unique_ptr<AudioSample> audio_sample(new AudioSample());
00139   audio_sample->resize(frame_count * 2);
00140 
00141   memcpy(audio_sample->data(), input, frame_count * 2);
00142 
00143   recorder->queue_->push(std::move(audio_sample));
00144 
00145   return paContinue;
00146 }
00147 
00148 }  // namespace speech
00149 }  // namespace cloud
00150 }  // namespace cogrob


gcloud_speech_utils
Author(s):
autogenerated on Thu Jun 6 2019 17:58:05