| 33 | )"""; |
| 34 | |
| 35 | class Handler : public std::enable_shared_from_this<Handler> { |
| 36 | public: |
| 37 | static std::shared_ptr<Handler> Create(google::cloud::CompletionQueue cq, |
| 38 | ParseResult args) { |
| 39 | return std::shared_ptr<Handler>( |
| 40 | new Handler(std::move(cq), std::move(args))); |
| 41 | } |
| 42 | |
| 43 | g::future<g::Status> Start(speech::SpeechClient& client) { |
| 44 | // Get ready to write audio content. Create the stream, and start it. |
| 45 | stream_ = client.AsyncStreamingRecognize(); |
| 46 | // The stream can fail to start; `.get()` returns `false` in this case. |
| 47 | if (!stream_->Start().get()) return StartFailure(); |
| 48 | // Write the first request, containing the config only. |
| 49 | if (!stream_->Write(request_, grpc::WriteOptions{}).get()) { |
| 50 | // Write().get() returns false if the stream is closed. |
| 51 | return StartFailure(); |
| 52 | } |
| 53 | auto self = shared_from_this(); |
| 54 | // This creates a series of reads; when each read completes successfully a |
| 55 | // new one starts. |
| 56 | stream_->Read().then([self](auto f) { self->OnRead(f.get()); }); |
| 57 | // This creates a series of timer -> write -> timer -> ... steps. |
| 58 | cq_.MakeRelativeTimer(std::chrono::seconds(1)).then([self](auto f) { |
| 59 | self->OnTimer(f.get().status()); |
| 60 | }); |
| 61 | return done_.get_future(); |
| 62 | } |
| 63 | |
| 64 | private: |
| 65 | Handler(google::cloud::CompletionQueue cq, ParseResult args) |
| 66 | : cq_(std::move(cq)), file_(args.path, std::ios::binary) { |
| 67 | auto& streaming_config = *request_.mutable_streaming_config(); |
| 68 | *streaming_config.mutable_config() = std::move(args.config); |
| 69 | } |
| 70 | |
| 71 | g::future<g::Status> StartFailure() { |
| 72 | auto self = shared_from_this(); |
| 73 | writing_ = false; |
| 74 | reading_ = false; |
| 75 | stream_->Finish().then([self](auto f) { self->OnFinish(f.get()); }); |
| 76 | return done_.get_future(); |
| 77 | } |
| 78 | |
| 79 | void OnFinish(g::Status s) { done_.set_value(s); } |
| 80 | |
| 81 | void OnTimer(g::Status s) { |
| 82 | // On a timer error the completion queue is not usable so just return. |
| 83 | if (!s.ok()) return; |
| 84 | auto self = shared_from_this(); |
| 85 | auto constexpr kChunkSize = 64 * 1024; |
| 86 | std::vector<char> chunk(kChunkSize); |
| 87 | file_.read(chunk.data(), chunk.size()); |
| 88 | auto const bytes_read = file_.gcount(); |
| 89 | if (bytes_read > 0) { |
| 90 | request_.clear_streaming_config(); |
| 91 | request_.set_audio_content(chunk.data(), bytes_read); |
| 92 | std::cout << "Sending " << bytes_read / 1024 << "k bytes." << std::endl; |
nothing calls this directly
no outgoing calls
no test coverage detected