| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "content/browser/speech/google_streaming_remote_engine.h" | 5 #include "content/browser/speech/google_streaming_remote_engine.h" |
| 6 | 6 |
| 7 #include <algorithm> | 7 #include <algorithm> |
| 8 #include <vector> | 8 #include <vector> |
| 9 | 9 |
| 10 #include "base/big_endian.h" | 10 #include "base/big_endian.h" |
| (...skipping 20 matching lines...) Expand all Loading... |
| 31 | 31 |
| 32 namespace content { | 32 namespace content { |
| 33 namespace { | 33 namespace { |
| 34 | 34 |
| 35 const char kWebServiceBaseUrl[] = | 35 const char kWebServiceBaseUrl[] = |
| 36 "https://www.google.com/speech-api/full-duplex/v1"; | 36 "https://www.google.com/speech-api/full-duplex/v1"; |
| 37 const char kDownstreamUrl[] = "/down?"; | 37 const char kDownstreamUrl[] = "/down?"; |
| 38 const char kUpstreamUrl[] = "/up?"; | 38 const char kUpstreamUrl[] = "/up?"; |
| 39 | 39 |
| 40 // This matches the maximum maxAlternatives value supported by the server. | 40 // This matches the maximum maxAlternatives value supported by the server. |
| 41 const uint32 kMaxMaxAlternatives = 30; | 41 const uint32_t kMaxMaxAlternatives = 30; |
| 42 | 42 |
| 43 // TODO(hans): Remove this and other logging when we don't need it anymore. | 43 // TODO(hans): Remove this and other logging when we don't need it anymore. |
| 44 void DumpResponse(const std::string& response) { | 44 void DumpResponse(const std::string& response) { |
| 45 DVLOG(1) << "------------"; | 45 DVLOG(1) << "------------"; |
| 46 proto::SpeechRecognitionEvent event; | 46 proto::SpeechRecognitionEvent event; |
| 47 if (!event.ParseFromString(response)) { | 47 if (!event.ParseFromString(response)) { |
| 48 DVLOG(1) << "Parse failed!"; | 48 DVLOG(1) << "Parse failed!"; |
| 49 return; | 49 return; |
| 50 } | 50 } |
| 51 if (event.has_status()) | 51 if (event.has_status()) |
| (...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 114 FSMEventArgs event_args(EVENT_AUDIO_CHUNKS_ENDED); | 114 FSMEventArgs event_args(EVENT_AUDIO_CHUNKS_ENDED); |
| 115 DispatchEvent(event_args); | 115 DispatchEvent(event_args); |
| 116 } | 116 } |
| 117 | 117 |
| 118 void GoogleStreamingRemoteEngine::OnURLFetchComplete(const URLFetcher* source) { | 118 void GoogleStreamingRemoteEngine::OnURLFetchComplete(const URLFetcher* source) { |
| 119 const bool kResponseComplete = true; | 119 const bool kResponseComplete = true; |
| 120 DispatchHTTPResponse(source, kResponseComplete); | 120 DispatchHTTPResponse(source, kResponseComplete); |
| 121 } | 121 } |
| 122 | 122 |
| 123 void GoogleStreamingRemoteEngine::OnURLFetchDownloadProgress( | 123 void GoogleStreamingRemoteEngine::OnURLFetchDownloadProgress( |
| 124 const URLFetcher* source, int64 current, int64 total) { | 124 const URLFetcher* source, |
| 125 int64_t current, |
| 126 int64_t total) { |
| 125 const bool kPartialResponse = false; | 127 const bool kPartialResponse = false; |
| 126 DispatchHTTPResponse(source, kPartialResponse); | 128 DispatchHTTPResponse(source, kPartialResponse); |
| 127 } | 129 } |
| 128 | 130 |
| 129 void GoogleStreamingRemoteEngine::DispatchHTTPResponse(const URLFetcher* source, | 131 void GoogleStreamingRemoteEngine::DispatchHTTPResponse(const URLFetcher* source, |
| 130 bool end_of_response) { | 132 bool end_of_response) { |
| 131 DCHECK(CalledOnValidThread()); | 133 DCHECK(CalledOnValidThread()); |
| 132 DCHECK(source); | 134 DCHECK(source); |
| 133 const bool response_is_good = source->GetStatus().is_success() && | 135 const bool response_is_good = source->GetStatus().is_success() && |
| 134 source->GetResponseCode() == 200; | 136 source->GetResponseCode() == 200; |
| (...skipping 199 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 334 std::vector<std::string> upstream_args; | 336 std::vector<std::string> upstream_args; |
| 335 upstream_args.push_back("key=" + | 337 upstream_args.push_back("key=" + |
| 336 net::EscapeQueryParamValue(google_apis::GetAPIKey(), true)); | 338 net::EscapeQueryParamValue(google_apis::GetAPIKey(), true)); |
| 337 upstream_args.push_back("pair=" + request_key); | 339 upstream_args.push_back("pair=" + request_key); |
| 338 upstream_args.push_back("output=pb"); | 340 upstream_args.push_back("output=pb"); |
| 339 upstream_args.push_back( | 341 upstream_args.push_back( |
| 340 "lang=" + net::EscapeQueryParamValue(GetAcceptedLanguages(), true)); | 342 "lang=" + net::EscapeQueryParamValue(GetAcceptedLanguages(), true)); |
| 341 upstream_args.push_back( | 343 upstream_args.push_back( |
| 342 config_.filter_profanities ? "pFilter=2" : "pFilter=0"); | 344 config_.filter_profanities ? "pFilter=2" : "pFilter=0"); |
| 343 if (config_.max_hypotheses > 0U) { | 345 if (config_.max_hypotheses > 0U) { |
| 344 uint32 max_alternatives = | 346 uint32_t max_alternatives = |
| 345 std::min(kMaxMaxAlternatives, config_.max_hypotheses); | 347 std::min(kMaxMaxAlternatives, config_.max_hypotheses); |
| 346 upstream_args.push_back("maxAlternatives=" + | 348 upstream_args.push_back("maxAlternatives=" + |
| 347 base::UintToString(max_alternatives)); | 349 base::UintToString(max_alternatives)); |
| 348 } | 350 } |
| 349 upstream_args.push_back("app=chromium"); | 351 upstream_args.push_back("app=chromium"); |
| 350 if (!config_.hardware_info.empty()) { | 352 if (!config_.hardware_info.empty()) { |
| 351 upstream_args.push_back( | 353 upstream_args.push_back( |
| 352 "xhw=" + net::EscapeQueryParamValue(config_.hardware_info, true)); | 354 "xhw=" + net::EscapeQueryParamValue(config_.hardware_info, true)); |
| 353 } | 355 } |
| 354 for (const SpeechRecognitionGrammar& grammar : config_.grammars) { | 356 for (const SpeechRecognitionGrammar& grammar : config_.grammars) { |
| (...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 391 upstream_fetcher_->SetReferrer(config_.origin_url); | 393 upstream_fetcher_->SetReferrer(config_.origin_url); |
| 392 upstream_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | | 394 upstream_fetcher_->SetLoadFlags(net::LOAD_DO_NOT_SAVE_COOKIES | |
| 393 net::LOAD_DO_NOT_SEND_COOKIES | | 395 net::LOAD_DO_NOT_SEND_COOKIES | |
| 394 net::LOAD_DO_NOT_SEND_AUTH_DATA); | 396 net::LOAD_DO_NOT_SEND_AUTH_DATA); |
| 395 upstream_fetcher_->Start(); | 397 upstream_fetcher_->Start(); |
| 396 previous_response_length_ = 0; | 398 previous_response_length_ = 0; |
| 397 | 399 |
| 398 if (preamble_encoder_) { | 400 if (preamble_encoder_) { |
| 399 // Encode and send preamble right away. | 401 // Encode and send preamble right away. |
| 400 scoped_refptr<AudioChunk> chunk = new AudioChunk( | 402 scoped_refptr<AudioChunk> chunk = new AudioChunk( |
| 401 reinterpret_cast<const uint8*>(config_.preamble->sample_data.data()), | 403 reinterpret_cast<const uint8_t*>(config_.preamble->sample_data.data()), |
| 402 config_.preamble->sample_data.size(), | 404 config_.preamble->sample_data.size(), config_.preamble->sample_depth); |
| 403 config_.preamble->sample_depth); | |
| 404 preamble_encoder_->Encode(*chunk); | 405 preamble_encoder_->Encode(*chunk); |
| 405 preamble_encoder_->Flush(); | 406 preamble_encoder_->Flush(); |
| 406 scoped_refptr<AudioChunk> encoded_data( | 407 scoped_refptr<AudioChunk> encoded_data( |
| 407 preamble_encoder_->GetEncodedDataAndClear()); | 408 preamble_encoder_->GetEncodedDataAndClear()); |
| 408 UploadAudioChunk(encoded_data->AsString(), FRAME_PREAMBLE_AUDIO, false); | 409 UploadAudioChunk(encoded_data->AsString(), FRAME_PREAMBLE_AUDIO, false); |
| 409 } | 410 } |
| 410 return STATE_BOTH_STREAMS_CONNECTED; | 411 return STATE_BOTH_STREAMS_CONNECTED; |
| 411 } | 412 } |
| 412 | 413 |
| 413 GoogleStreamingRemoteEngine::FSMState | 414 GoogleStreamingRemoteEngine::FSMState |
| (...skipping 98 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 512 DCHECK(upstream_fetcher_.get()); | 513 DCHECK(upstream_fetcher_.get()); |
| 513 DCHECK(encoder_.get()); | 514 DCHECK(encoder_.get()); |
| 514 | 515 |
| 515 DVLOG(1) << "Closing upstream."; | 516 DVLOG(1) << "Closing upstream."; |
| 516 | 517 |
| 517 // The encoder requires a non-empty final buffer. So we encode a packet | 518 // The encoder requires a non-empty final buffer. So we encode a packet |
| 518 // of silence in case encoder had no data already. | 519 // of silence in case encoder had no data already. |
| 519 size_t sample_count = | 520 size_t sample_count = |
| 520 config_.audio_sample_rate * kAudioPacketIntervalMs / 1000; | 521 config_.audio_sample_rate * kAudioPacketIntervalMs / 1000; |
| 521 scoped_refptr<AudioChunk> dummy_chunk = new AudioChunk( | 522 scoped_refptr<AudioChunk> dummy_chunk = new AudioChunk( |
| 522 sample_count * sizeof(int16), encoder_->GetBitsPerSample() / 8); | 523 sample_count * sizeof(int16_t), encoder_->GetBitsPerSample() / 8); |
| 523 encoder_->Encode(*dummy_chunk.get()); | 524 encoder_->Encode(*dummy_chunk.get()); |
| 524 encoder_->Flush(); | 525 encoder_->Flush(); |
| 525 scoped_refptr<AudioChunk> encoded_dummy_data = | 526 scoped_refptr<AudioChunk> encoded_dummy_data = |
| 526 encoder_->GetEncodedDataAndClear(); | 527 encoder_->GetEncodedDataAndClear(); |
| 527 DCHECK(!encoded_dummy_data->IsEmpty()); | 528 DCHECK(!encoded_dummy_data->IsEmpty()); |
| 528 encoder_.reset(); | 529 encoder_.reset(); |
| 529 | 530 |
| 530 UploadAudioChunk(encoded_dummy_data->AsString(), | 531 UploadAudioChunk(encoded_dummy_data->AsString(), |
| 531 FRAME_RECOGNITION_AUDIO, | 532 FRAME_RECOGNITION_AUDIO, |
| 532 true); | 533 true); |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 600 langs = accepted_language_list.substr(0, separator); | 601 langs = accepted_language_list.substr(0, separator); |
| 601 } | 602 } |
| 602 } | 603 } |
| 603 if (langs.empty()) | 604 if (langs.empty()) |
| 604 langs = "en-US"; | 605 langs = "en-US"; |
| 605 return langs; | 606 return langs; |
| 606 } | 607 } |
| 607 | 608 |
| 608 // TODO(primiano): Is there any utility in the codebase that already does this? | 609 // TODO(primiano): Is there any utility in the codebase that already does this? |
| 609 std::string GoogleStreamingRemoteEngine::GenerateRequestKey() const { | 610 std::string GoogleStreamingRemoteEngine::GenerateRequestKey() const { |
| 610 const int64 kKeepLowBytes = 0x00000000FFFFFFFFLL; | 611 const int64_t kKeepLowBytes = 0x00000000FFFFFFFFLL; |
| 611 const int64 kKeepHighBytes = 0xFFFFFFFF00000000LL; | 612 const int64_t kKeepHighBytes = 0xFFFFFFFF00000000LL; |
| 612 | 613 |
| 613 // Just keep the least significant bits of timestamp, in order to reduce | 614 // Just keep the least significant bits of timestamp, in order to reduce |
| 614 // probability of collisions. | 615 // probability of collisions. |
| 615 int64 key = (base::Time::Now().ToInternalValue() & kKeepLowBytes) | | 616 int64_t key = (base::Time::Now().ToInternalValue() & kKeepLowBytes) | |
| 616 (base::RandUint64() & kKeepHighBytes); | 617 (base::RandUint64() & kKeepHighBytes); |
| 617 return base::HexEncode(reinterpret_cast<void*>(&key), sizeof(key)); | 618 return base::HexEncode(reinterpret_cast<void*>(&key), sizeof(key)); |
| 618 } | 619 } |
| 619 | 620 |
| 620 void GoogleStreamingRemoteEngine::UploadAudioChunk(const std::string& data, | 621 void GoogleStreamingRemoteEngine::UploadAudioChunk(const std::string& data, |
| 621 FrameType type, | 622 FrameType type, |
| 622 bool is_final) { | 623 bool is_final) { |
| 623 if (use_framed_post_data_) { | 624 if (use_framed_post_data_) { |
| 624 std::string frame(data.size() + 8, 0); | 625 std::string frame(data.size() + 8, 0); |
| 625 base::WriteBigEndian(&frame[0], static_cast<uint32_t>(data.size())); | 626 base::WriteBigEndian(&frame[0], static_cast<uint32_t>(data.size())); |
| 626 base::WriteBigEndian(&frame[4], static_cast<uint32_t>(type)); | 627 base::WriteBigEndian(&frame[4], static_cast<uint32_t>(type)); |
| 627 frame.replace(8, data.size(), data); | 628 frame.replace(8, data.size(), data); |
| 628 upstream_fetcher_->AppendChunkToUpload(frame, is_final); | 629 upstream_fetcher_->AppendChunkToUpload(frame, is_final); |
| 629 } else { | 630 } else { |
| 630 upstream_fetcher_->AppendChunkToUpload(data, is_final); | 631 upstream_fetcher_->AppendChunkToUpload(data, is_final); |
| 631 } | 632 } |
| 632 } | 633 } |
| 633 | 634 |
| 634 GoogleStreamingRemoteEngine::FSMEventArgs::FSMEventArgs(FSMEvent event_value) | 635 GoogleStreamingRemoteEngine::FSMEventArgs::FSMEventArgs(FSMEvent event_value) |
| 635 : event(event_value) { | 636 : event(event_value) { |
| 636 } | 637 } |
| 637 | 638 |
| 638 GoogleStreamingRemoteEngine::FSMEventArgs::~FSMEventArgs() { | 639 GoogleStreamingRemoteEngine::FSMEventArgs::~FSMEventArgs() { |
| 639 } | 640 } |
| 640 | 641 |
| 641 } // namespace content | 642 } // namespace content |
| OLD | NEW |