google_speech.cc
Go to the documentation of this file.
1 // Copyright (c) 2017, The Regents of the University of California
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are met:
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above copyright
9 // notice, this list of conditions and the following disclaimer in the
10 // documentation and/or other materials provided with the distribution.
11 // * Neither the name of the University of California nor the
12 // names of its contributors may be used to endorse or promote products
13 // derived from this software without specific prior written permission.
14 //
15 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 // ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OF THE UNIVERSITY OF CALIFORNIA
19 // BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 // POSSIBILITY OF SUCH DAMAGE.
26 
28 
29 #include <grpc++/grpc++.h>
30 #include <grpc/impl/codegen/connectivity_state.h>
31 #include <chrono>
32 #include <memory>
33 #include <string>
34 #include <utility>
35 #include <vector>
36 
38 #include "third_party/gflags.h"
39 #include "third_party/glog.h"
40 
41 DEFINE_int32(grpc_speech_connect_timeout_secs, 5,
42  "Timeout (seconds) to connect to gRPC service.");
43 
44 DEFINE_int32(gspeech_wait_input_timeout_msecs, 100,
45  "Timeout (seconds) to wait for input samples.");
46 
47 namespace gspeech = ::google::cloud::speech::v1;
48 
49 using gspeech::RecognitionConfig;
50 using gspeech::StreamingRecognizeRequest;
51 using gspeech::StreamingRecognizeResponse;
52 
53 using std::string;
54 using std::unique_ptr;
55 using util::Status;
56 using util::StatusOr;
57 
58 namespace cogrob {
59 namespace cloud {
60 namespace speech {
61 
63  std::lock_guard<std::mutex> lock(general_mutex_);
64  // Creates a stub connected to the speech service.
65  channel_ = grpc::CreateChannel(
66  "speech.googleapis.com", grpc::GoogleDefaultCredentials());
67  gspeech_stub_ = std::move(gspeech::Speech::NewStub(channel_));
68 
69  // Resets status.
71  util::error::FAILED_PRECONDITION, "Recognizer not yet started.");
72 }
73 
75  Stop();
76 }
77 
80  const std::vector<string>& hints, int max_audio_seconds,
81  int max_wait_seconds, int max_alternatives) {
82  // This method is not re-entryable.
83  std::lock_guard<std::mutex> lock(general_mutex_);
84 
85  if (thread_) {
86  return Status(
87  util::error::ALREADY_EXISTS, "Recognizer is already running.");
88  }
89 
90  // Starts a new thread.
91  stop_flag_.store(false);
92  done_flag_.store(false);
94  "Recognizer just started, nothing received yet.");
95  // Hints is passed by value because it is used in a new thread.
96  thread_.reset(new std::thread([
97  this, audio_queue, result_queue, hints, max_audio_seconds,
98  max_wait_seconds, max_alternatives] {
99  RecognitionThread(audio_queue, result_queue, hints, max_audio_seconds,
100  max_wait_seconds, max_alternatives);
101  }));
102  return Status::OK;
103 }
104 
106  // Returns the latest result.
107  std::lock_guard<std::mutex> lock(general_mutex_);
108  return latest_result_;
109 }
110 
111 // Waits until recognizer finishes.
113  // Methods are not re-entryable.
114  std::lock_guard<std::mutex> lock(general_mutex_);
115  if (thread_) {
116  thread_->join();
117  thread_.reset(nullptr);
118  }
119  return Status::OK;
120 }
121 
122 // Stops the recognizer.
124  // Methods are not re-entryable.
125  std::lock_guard<std::mutex> lock(general_mutex_);
126 
127  // If the thread is still running, set the stop flag and wait for it to stop.
128  if (thread_) {
129  stop_flag_.store(true);
130  thread_->join();
131  thread_.reset(nullptr);
132  }
133  return Status::OK;
134 }
135 
136 // Test whether the recognizer is still running.
138  // Methods are not re-entryable.
139  std::lock_guard<std::mutex> lock(general_mutex_);
140 
141  // If the thread is stopped, join the thread and destories the thread object.
142  if (done_flag_.load() && thread_) {
143  thread_->join();
144  thread_.reset(nullptr);
145  }
146 
147  if (thread_) {
148  return true;
149  }
150  return false;
151 }
152 
153 // This runs in a seperate thread
156  const std::vector<string>& hints, int max_audio_seconds,
157  int max_wait_seconds, int max_alternatives) {
158 
159  // If any gRPC failure happens in the, this flags will be set and will exit
160  // the thread loop.
161  bool fail_flag = false;
162 
163  if (max_audio_seconds < 1) {
166  "max_audio_seconds must be greater than 0");
167  LOG(ERROR) << latest_result_.status();
168  fail_flag = true;
169  }
170 
171  if (max_audio_seconds >= 65) {
174  "max_audio_seconds must be less than 65");
175  LOG(ERROR) << latest_result_.status();
176  fail_flag = true;
177  }
178 
179  if (max_wait_seconds <= max_audio_seconds) {
182  "max_wait_seconds must be greater than max_audio_seconds.");
183  LOG(ERROR) << latest_result_.status();
184  fail_flag = true;
185  }
186 
187  if (fail_flag) {
188  done_flag_.store(true);
189  LOG(ERROR) << "There are some errors on preconditions, "
190  << "finishing RecognitionThread.";
191  return;
192  }
193 
194  LOG(INFO) << "RecognitionThread started, will listen for "
195  << max_audio_seconds << " seconds, and will return in "
196  << max_wait_seconds << " seconds.";
197 
198  // The deadline that the thread must return.
199  std::chrono::system_clock::time_point deadline
200  = std::chrono::system_clock::now() + std::chrono::seconds(max_wait_seconds);
201  double left_audio_time = max_audio_seconds;
202 
203  // gRPC request handles.
204  grpc::ClientContext context;
205  grpc::CompletionQueue completion_queue;
206  // Sequence number in the completion_queue, increase before use.
207  uintptr_t cq_seq = 0;
208 
209  // After this point, we must drain the CompletionQueue before the can destory
210  // the instance.
211 
212  // Deadline to wait to connect and channel and for AsyncStreamingRecognize
213  // (stream creation) to return, if the time is exceed, we will give up.
214  std::chrono::system_clock::time_point stream_connect_deadline =
215  std::chrono::system_clock::now()
216  + std::chrono::seconds(FLAGS_grpc_speech_connect_timeout_secs);
217 
218  // If the channel is in IDLE and try_to_connect is set to true, try to
219  // connect. If connection timeout, give up.
220  channel_->GetState(true);
221  if (!channel_->WaitForConnected(stream_connect_deadline)) {
223  "gRPC error: Channel connection took too long.");
224  LOG(ERROR) << latest_result_.status();
225  fail_flag = true;
226  }
227 
228  // Check the channel state for debugging purpose.
229  string channel_state = "";
230  grpc_connectivity_state channel_state_enum = channel_->GetState(false);
231  switch (channel_state_enum) {
232  case GRPC_CHANNEL_IDLE:
233  channel_state = "GRPC_CHANNEL_IDLE";
234  break;
235  case GRPC_CHANNEL_CONNECTING:
236  channel_state = "GRPC_CHANNEL_CONNECTING";
237  break;
238  case GRPC_CHANNEL_READY:
239  channel_state = "GRPC_CHANNEL_READY";
240  break;
241  case GRPC_CHANNEL_TRANSIENT_FAILURE:
242  channel_state = "GRPC_CHANNEL_TRANSIENT_FAILURE";
243  break;
244  case GRPC_CHANNEL_SHUTDOWN:
245  channel_state = "GRPC_CHANNEL_SHUTDOWN";
246  break;
247  default:
248  CHECK(false) << "Unknown channel state: " << channel_state_enum;
249  break;
250  }
251 
252  if (channel_state_enum == GRPC_CHANNEL_READY) {
253  LOG(INFO) << "Channel state is " << channel_state;
254  } else {
255  LOG(ERROR) << "Channel state is " << channel_state;
256  }
257 
258  if (fail_flag) {
259  done_flag_.store(true);
260  LOG(ERROR) << "There are some errors on gRPC channels, "
261  << "finishing RecognitionThread.";
262  return;
263  }
264 
265  // Starts a async call if channel connection is successful.
266  auto /* std::unique_ptr<ClientAsyncReaderWriterInterface> */ streamer
267  = gspeech_stub_->AsyncStreamingRecognize(
268  &context, &completion_queue, reinterpret_cast<void*>(++cq_seq));
269  uintptr_t stream_cq_seq = cq_seq;
270  LOG(INFO) << "Start a call to Google Speech gRPC server, cq_seq: "
271  << stream_cq_seq;
272 
273  // Blocks until the creation of the stream is done, we cannot start writing
274  // until that happens.
275  // See: https://github.com/GoogleCloudPlatform/cpp-docs-samples/issues/16
276  // Result from CompletionQueue::AsyncNext
277  void* stream_cq_tag = nullptr;
278  bool stream_cq_ok = false;
279  // Read from the completion_queue with some timeout
280  grpc::CompletionQueue::NextStatus stream_cq_state
281  = completion_queue.AsyncNext(&stream_cq_tag, &stream_cq_ok,
282  stream_connect_deadline);
283  if (stream_cq_state == grpc::CompletionQueue::GOT_EVENT) {
284  if (!stream_cq_ok) {
286  "gRPC error: Stream failed to create.");
287  LOG(ERROR) << latest_result_.status();
288  fail_flag = true;
289  }
290 
291  // stream_cq_ok is true here.
292  if (stream_cq_tag == reinterpret_cast<void*>(stream_cq_seq)) {
293  // This is the expected condition.
294  LOG(INFO) << "gRPC created stream, tag is "
295  << reinterpret_cast<uintptr_t>(stream_cq_tag);
296  } else {
298  "gRPC fatal error: wrong stream creation tag.");
299  LOG(ERROR) << latest_result_.status();
300  fail_flag = true;
301  }
302  } else if (stream_cq_state == grpc::CompletionQueue::TIMEOUT) {
304  "gRPC error: Stream creation timed out.");
305  LOG(ERROR) << latest_result_.status();
306  fail_flag = true;
307  } else if (stream_cq_state == grpc::CompletionQueue::SHUTDOWN) {
309  "gRPC gRPC server shuted down the connection.");
310  LOG(ERROR) << latest_result_.status();
311  fail_flag = true;
312  }
313 
314  // Prepares and sends speech recognition configurations.
315  gspeech::StreamingRecognizeRequest config_request;
316  auto* streaming_config = config_request.mutable_streaming_config();
317  streaming_config->set_single_utterance(false);
318  streaming_config->set_interim_results(true);
319  streaming_config->mutable_config()->set_encoding(RecognitionConfig::LINEAR16);
320  streaming_config->mutable_config()->set_sample_rate_hertz(SAMPLE_RATE);
321  streaming_config->mutable_config()->set_language_code("en-US");
322  streaming_config->mutable_config()->set_max_alternatives(max_alternatives);
323  // Prepare the speech context (hints).
324  gspeech::SpeechContext* speech_context =
325  streaming_config->mutable_config()->add_speech_contexts();
326  for (const string& hint : hints) {
327  speech_context->add_phrases(hint);
328  }
329 
330  // Tracks writing.
331  uintptr_t last_write_seq = 0;
332  uintptr_t write_done_seq = 0;
333  bool allow_write = true;
334  bool write_done_issued = false;
335  bool write_done_finished = false;
336  bool final_read_returned = false;
337 
338  // Tracking reading.
339  uintptr_t last_read_seq = 0; // Never read before
340  gspeech::StreamingRecognizeResponse response;
341  bool allow_read = true;
342 
343  // If fail_flag is set, all these steps will be skipped and we will start
344  // draining the CompletionQueue.
345  if (!fail_flag) {
346  // Writes the first request, containing the config only, last_write_seq will
347  // be updated after calling Write.
348  CHECK(allow_write);
349  streamer->Write(
350  config_request, reinterpret_cast<void*>(last_write_seq = ++cq_seq));
351  allow_write = false;
352  LOG(INFO) << "Wrote speech config to Google Speech gRPC server with tag "
353  << last_write_seq;
354 
355  // Starts trying to read from the server, it would only respond when it
356  // has something to report back, last_read_seq will be updated after calling
357  // Read.
358  CHECK(allow_read);
359  streamer->Read(&response,
360  reinterpret_cast<void*>(last_read_seq = ++cq_seq));
361  allow_read = false;
362  LOG(INFO) << "Issued first Read request with tag " << cq_seq;
363  }
364 
365  // The body of the loop should not take long to finish, so that we can check
366  // stop request and deadline.
367  // If fail_flag is set, all these steps will be skipped and we will start
368  // force draining the CompletionQueue.
369  while (!fail_flag && std::chrono::system_clock::now() < deadline) {
370  // Try to read everything in the completion_queue
371  while (true) {
372  // Deadline to wait CompletionQueue to return a result, fix to 10ms. The
373  // CompletionQueue should quickly return the results it has, and wait 10ms
374  // before it reports it is empty.
375  std::chrono::system_clock::time_point cq_deadline
376  = std::chrono::system_clock::now() + std::chrono::milliseconds(10);
377 
378  // These are the results from CompletionQueue::AsyncNext.
379  void* cq_tag = nullptr;
380  bool cq_ok = false;
381 
382  // Reads from the completion_queue with timeout.
383  grpc::CompletionQueue::NextStatus cq_state = completion_queue.AsyncNext(
384  &cq_tag, &cq_ok, cq_deadline);
385 
386  if (cq_state == grpc::CompletionQueue::GOT_EVENT) {
387  if (cq_tag == reinterpret_cast<void*>(last_read_seq)) {
388  LOG(INFO) << "Got Read result from completion queue, cq_tag is "
389  << reinterpret_cast<uintptr_t>(cq_tag)
390  << ", cq_ok is " << cq_ok;
391  if (!cq_ok) {
392  if (write_done_finished) {
393  final_read_returned = true;
394  break;
395  } else {
396  fail_flag = true;
398  util::error::INTERNAL, "gRPC Read failed.");
399  LOG(ERROR) << latest_result_.status();
400  break;
401  }
402  }
403 
404  // Unlock reading if last read is done.
405  allow_read = true;
406 
407  // We got the read result
408  LOG(INFO) << "Got recognition response from server "
409  << response.DebugString();
410 
411 
412  if (response.has_error()) {
414  util::error::INTERNAL, response.error().message());
415  LOG(ERROR) << "Response has error: " << response.error().message();
416  fail_flag = true;
417  break;
418  }
419 
420  for (auto& result_record : response.results()) {
421  // Put the recognition result to output queue.
422  RecognitionResult recog_result;
423  recog_result.set_is_final(result_record.is_final());
424  recog_result.set_stability(result_record.stability());
425  for (auto& alternative : result_record.alternatives()) {
426  RecognitionResult::Candidate* can = recog_result.add_candidates();
427  can->set_transcript(alternative.transcript());
428  can->set_confidence(alternative.confidence());
429  }
430  latest_result_ = recog_result;
431  if (result_queue) {
432  result_queue->push(recog_result);
433  }
434  }
435 
436  // Submit another Read request to the the gRPC server.
437  CHECK(allow_read);
438  streamer->Read(
439  &response, reinterpret_cast<void*>(last_read_seq = ++cq_seq));
440  allow_read = false;
441  LOG(INFO) << "Issued Read request with tag " << last_read_seq;
442  } else if (cq_tag == reinterpret_cast<void*>(last_write_seq)) {
443  LOG(INFO) << "Got Write result from completion queue, cq_tag is "
444  << reinterpret_cast<uintptr_t>(cq_tag)
445  << ", cq_ok is " << cq_ok;
446  if (!cq_ok) {
447  fail_flag = true;
449  util::error::INTERNAL, "gRPC Write failed.");
450  LOG(ERROR) << latest_result_.status();
451  break;
452  }
453  // Unlock writing if last write is done when there are still more
454  // samples to write.
455  if (!write_done_issued) {
456  allow_write = true;
457  }
458  } else if (cq_tag == reinterpret_cast<void*>(write_done_seq)) {
459  LOG(INFO) << "Got WritesDone result from completion queue, cq_tag is "
460  << reinterpret_cast<uintptr_t>(cq_tag)
461  << ", cq_ok is " << cq_ok;
462  if (!cq_ok) {
463  fail_flag = true;
465  util::error::INTERNAL, "gRPC WritesDone failed.");
466  LOG(ERROR) << latest_result_.status();
467  break;
468  }
469  write_done_finished = true;
470  } else {
471  // Got some other results, this is unexpected.
472  LOG(ERROR) << "Got unknown result from completion queue, cq_tag is "
473  << reinterpret_cast<uintptr_t>(cq_tag)
474  << ", cq_ok is " << cq_ok;
475  if (!cq_ok) {
476  fail_flag = true;
479  "Got non-read/write results, and it is a failure.");
480  LOG(ERROR) << latest_result_.status();
481  break;
482  }
483  }
484  } else if (cq_state == grpc::CompletionQueue::TIMEOUT) {
485  LOG(INFO) << "CompletionQueue timeout (expected behavior).";
486  break;
487  } else if (cq_state == grpc::CompletionQueue::SHUTDOWN) {
488  fail_flag = true;
489  LOG(ERROR) << "gRPC server shuted down the connection.";
490  break;
491  }
492  }
493 
494  if (fail_flag) {
495  break;
496  }
497 
498  if (final_read_returned) {
499  break;
500  }
501 
502  if (allow_write && !write_done_issued) {
503  // We can still write.
504  if (left_audio_time > 0 && !stop_flag_.load()) {
505  // If there is time left, sends audio data to the server.
506  gspeech::StreamingRecognizeRequest request;
507  // Block some time for reading. We will waste at most this much here.
508  // Increase this number should reduce CPU load, but make the program
509  // respond to Stop request or new results slower.
511  = audio_queue->blocking_pop(FLAGS_gspeech_wait_input_timeout_msecs);
512  if (pop_result.ok()) {
513  unique_ptr<AudioSample> audio_sample = pop_result.ConsumeValueOrDie();
514  left_audio_time -= static_cast<double>(audio_sample->size())
515  / (SAMPLE_RATE * 2);
516  // And write the chunk to the stream.
517  request.set_audio_content(audio_sample->data(), audio_sample->size());
518  LOG(INFO) << "Prepare to send " << audio_sample->size()
519  << " bytes of data to the server.";
520  CHECK(allow_write);
521  streamer->Write(
522  request, reinterpret_cast<void*>(last_write_seq = ++cq_seq));
523  allow_write = false;
524  LOG(INFO) << "Issued Write request with tag " << last_write_seq;
525  } else {
526  LOG(WARNING) << "Read from audio_queue failed.";
527  }
528  } else {
529  // If this is the last time we to write, issues a done flag.
530  CHECK(allow_write);
531  CHECK(!write_done_issued);
532  streamer->WritesDone(
533  reinterpret_cast<void*>(write_done_seq = ++cq_seq));
534  LOG(INFO) << "Issued WritesDone request with tag " << write_done_seq;
535  allow_write = false;
536  write_done_issued = true;
537  }
538  }
539  }
540 
541  if (fail_flag) {
542  LOG(ERROR) << "gRPC failed, continue to finish the requests. "
543  << "There could be more failures, be prepared.";
544  }
545 
546  bool late_issue_write_done = false;
547  if (!write_done_issued) {
548  LOG(ERROR) << "WritesDone not issued, but we are not streaming anymore. "
549  << "Is max_wait_seconds is too close to max_audio_seconds? "
550  << "Is network connection too slow?";
551  if (allow_write) {
552  streamer->WritesDone(reinterpret_cast<void*>(write_done_seq = ++cq_seq));
553  allow_write = false;
554  write_done_issued = true;
555  late_issue_write_done = true;
556  LOG(INFO) << "Issued WritesDone request with tag " << write_done_seq;
557  } else {
558  LOG(ERROR) << "WritesDone is not yet issued, but not able to write.";
559  }
560  }
561 
562  grpc::Status finish_status;
563  uintptr_t finish_seq = 0;
564  streamer->Finish(&finish_status,
565  reinterpret_cast<void*>(finish_seq = ++cq_seq));
566  LOG(INFO) << "Issued Finish request with tag " << finish_seq;
567  completion_queue.Shutdown();
568 
569  // Drains the completion_queue.
570  bool tried_cancel = false;
571  while (true) {
572  void* cq_tag = nullptr;
573  bool cq_ok = false;
574  // Deadline to wait CompletionQueue to return a result, fix to 100ms.
575  std::chrono::system_clock::time_point cq_deadline
576  = std::chrono::system_clock::now() + std::chrono::milliseconds(100);
577 
578  // Read from the completion_queue with some timeout.
579  grpc::CompletionQueue::NextStatus cq_state = completion_queue.AsyncNext(
580  &cq_tag, &cq_ok, cq_deadline);
581 
582  if (cq_state == grpc::CompletionQueue::GOT_EVENT) {
583  if (cq_tag == reinterpret_cast<void*>(last_read_seq)) {
584  // This should not happen normally because most of the Read requests
585  // should have been drained in the previous big while loop. But it is
586  // still possible if timeout on max_wait_seconds. In this case, the Read
587  // result will be abandoned.
588  LOG(WARNING) << "Got unexpected Read from completion queue, cq_tag is "
589  << reinterpret_cast<uintptr_t>(cq_tag)
590  << ", cq_ok is " << cq_ok;
591  } else if (cq_tag == reinterpret_cast<void*>(last_write_seq)) {
592  LOG(ERROR) << "Got unexpected Write from completion queue, cq_tag is "
593  << reinterpret_cast<uintptr_t>(cq_tag)
594  << ", cq_ok is " << cq_ok;
595  } else if (cq_tag == reinterpret_cast<void*>(write_done_seq)) {
596  if (late_issue_write_done) {
597  LOG(WARNING) << "Got WritesDone (late issued) from completion queue, "
598  << "cq_tag is " << reinterpret_cast<uintptr_t>(cq_tag)
599  << ", cq_ok is " << cq_ok;
600  } else {
601  LOG(ERROR) << "Got WritesDone from completion queue, cq_tag is "
602  << reinterpret_cast<uintptr_t>(cq_tag)
603  << ", cq_ok is " << cq_ok;
604  }
605  } else if (cq_tag == reinterpret_cast<void*>(finish_seq)) {
606  if (!finish_status.ok()) {
608  util::error::INTERNAL, finish_status.error_message());
609  LOG(ERROR) << "Finish not OK: " << finish_status.error_message();
610  } else {
611  LOG(INFO) << "Finish OK.";
612  }
613  } else {
614  LOG(ERROR) << "Got unexpected event from completion queue, cq_tag is "
615  << reinterpret_cast<uintptr_t>(cq_tag)
616  << ", cq_ok is " << cq_ok;
617  }
618  } else if (cq_state == grpc::CompletionQueue::TIMEOUT) {
619  LOG(ERROR) << "CompletionQueue AsyncNext timeout";
620  // We still need to wait, otherwise we get gRPC internal error, but we can
621  // try force canceling.
622  if (!tried_cancel) {
623  context.TryCancel();
624  tried_cancel = true;
625  }
626  // TODO(shengye): If this is waiting too long, let's crash the program and
627  // let a superviosr restart it.
628  } else if (cq_state == grpc::CompletionQueue::SHUTDOWN) {
629  // This is expected.
630  LOG(INFO) << "CompletionQueue Shutdown";
631  break;
632  }
633  }
634 
635  done_flag_.store(true);
636  LOG(INFO) << "RecognitionThread finished";
637 }
638 
639 
640 } // namespace speech
641 } // namespace cloud
642 } // namespace cogrob
void RecognitionThread(AudioQueue *audio_queue, util::SimpleThreadSafeQueue< RecognitionResult > *result_queue, const std::vector< std::string > &hints, int max_audio_seconds, int max_wait_seconds, int max_alternatives)
std::unique_ptr< std::thread > thread_
Definition: google_speech.h:82
T ConsumeValueOrDie()
Definition: statusor.h:299
bool ok() const
Definition: statusor.h:277
util::Status StartRecognize(AudioQueue *audio_queue, util::SimpleThreadSafeQueue< RecognitionResult > *result_queue, const std::vector< std::string > &hints, int max_audio_seconds, int max_wait_seconds, int max_alternatives) override
std::string error_message() const
Definition: status.h:85
util::StatusOr< RecognitionResult > latest_result_
Definition: google_speech.h:83
std::unique_ptr<::google::cloud::speech::v1::Speech::Stub > gspeech_stub_
Definition: google_speech.h:79
constexpr size_t SAMPLE_RATE
Definition: audio_sample.h:39
const Status & status() const
Definition: statusor.h:272
util::StatusOr< RecognitionResult > GetLastResult() override
std::shared_ptr< grpc::ChannelInterface > channel_
Definition: google_speech.h:78
DEFINE_int32(grpc_speech_connect_timeout_secs, 5,"Timeout (seconds) to connect to gRPC service.")


gcloud_speech
Author(s):
autogenerated on Mon Jun 10 2019 13:20:53