| 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_one_shot_remote_engine.h" | 5 #include "content/browser/speech/google_one_shot_remote_engine.h" |
| 6 | 6 |
| 7 #include <vector> | 7 #include <vector> |
| 8 | 8 |
| 9 #include "base/json/json_reader.h" | 9 #include "base/json/json_reader.h" |
| 10 #include "base/string_number_conversions.h" | 10 #include "base/string_number_conversions.h" |
| 11 #include "base/string_util.h" | 11 #include "base/string_util.h" |
| 12 #include "base/values.h" | 12 #include "base/values.h" |
| 13 #include "content/browser/speech/audio_buffer.h" | 13 #include "content/browser/speech/audio_buffer.h" |
| 14 #include "content/public/common/speech_recognition_error.h" | 14 #include "content/public/common/speech_recognition_error.h" |
| 15 #include "content/public/common/speech_recognition_result.h" | 15 #include "content/public/common/speech_recognition_result.h" |
| 16 #include "google_apis/google_api_keys.h" | 16 #include "google_apis/google_api_keys.h" |
| 17 #include "net/base/escape.h" | 17 #include "net/base/escape.h" |
| 18 #include "net/base/load_flags.h" | 18 #include "net/base/load_flags.h" |
| 19 #include "net/url_request/url_fetcher.h" | 19 #include "net/url_request/url_fetcher.h" |
| 20 #include "net/url_request/url_request_context.h" | 20 #include "net/url_request/url_request_context.h" |
| 21 #include "net/url_request/url_request_context_getter.h" | 21 #include "net/url_request/url_request_context_getter.h" |
| 22 #include "net/url_request/url_request_status.h" | 22 #include "net/url_request/url_request_status.h" |
| 23 | 23 |
| 24 using content::SpeechRecognitionError; | 24 namespace content { |
| 25 using content::SpeechRecognitionHypothesis; | |
| 26 using content::SpeechRecognitionResult; | |
| 27 | |
| 28 namespace { | 25 namespace { |
| 29 | 26 |
| 30 const char* const kDefaultSpeechRecognitionUrl = | 27 const char* const kDefaultSpeechRecognitionUrl = |
| 31 "https://www.google.com/speech-api/v1/recognize?xjerr=1&client=chromium&"; | 28 "https://www.google.com/speech-api/v1/recognize?xjerr=1&client=chromium&"; |
| 32 const char* const kStatusString = "status"; | 29 const char* const kStatusString = "status"; |
| 33 const char* const kHypothesesString = "hypotheses"; | 30 const char* const kHypothesesString = "hypotheses"; |
| 34 const char* const kUtteranceString = "utterance"; | 31 const char* const kUtteranceString = "utterance"; |
| 35 const char* const kConfidenceString = "confidence"; | 32 const char* const kConfidenceString = "confidence"; |
| 36 const int kWebServiceStatusNoError = 0; | 33 const int kWebServiceStatusNoError = 0; |
| 37 const int kWebServiceStatusNoSpeech = 4; | 34 const int kWebServiceStatusNoSpeech = 4; |
| 38 const int kWebServiceStatusNoMatch = 5; | 35 const int kWebServiceStatusNoMatch = 5; |
| 39 const speech::AudioEncoder::Codec kDefaultAudioCodec = | 36 const AudioEncoder::Codec kDefaultAudioCodec = AudioEncoder::CODEC_FLAC; |
| 40 speech::AudioEncoder::CODEC_FLAC; | |
| 41 | 37 |
| 42 bool ParseServerResponse(const std::string& response_body, | 38 bool ParseServerResponse(const std::string& response_body, |
| 43 SpeechRecognitionResult* result, | 39 SpeechRecognitionResult* result, |
| 44 SpeechRecognitionError* error) { | 40 SpeechRecognitionError* error) { |
| 45 if (response_body.empty()) { | 41 if (response_body.empty()) { |
| 46 LOG(WARNING) << "ParseServerResponse: Response was empty."; | 42 LOG(WARNING) << "ParseServerResponse: Response was empty."; |
| 47 return false; | 43 return false; |
| 48 } | 44 } |
| 49 DVLOG(1) << "ParseServerResponse: Parsing response " << response_body; | 45 DVLOG(1) << "ParseServerResponse: Parsing response " << response_body; |
| 50 | 46 |
| (...skipping 20 matching lines...) Expand all Loading... |
| 71 VLOG(1) << "ParseServerResponse: " << kStatusString | 67 VLOG(1) << "ParseServerResponse: " << kStatusString |
| 72 << " is not a valid integer value."; | 68 << " is not a valid integer value."; |
| 73 return false; | 69 return false; |
| 74 } | 70 } |
| 75 | 71 |
| 76 // Process the status. | 72 // Process the status. |
| 77 switch (status) { | 73 switch (status) { |
| 78 case kWebServiceStatusNoError: | 74 case kWebServiceStatusNoError: |
| 79 break; | 75 break; |
| 80 case kWebServiceStatusNoSpeech: | 76 case kWebServiceStatusNoSpeech: |
| 81 error->code = content::SPEECH_RECOGNITION_ERROR_NO_SPEECH; | 77 error->code = SPEECH_RECOGNITION_ERROR_NO_SPEECH; |
| 82 return false; | 78 return false; |
| 83 case kWebServiceStatusNoMatch: | 79 case kWebServiceStatusNoMatch: |
| 84 error->code = content::SPEECH_RECOGNITION_ERROR_NO_MATCH; | 80 error->code = SPEECH_RECOGNITION_ERROR_NO_MATCH; |
| 85 return false; | 81 return false; |
| 86 default: | 82 default: |
| 87 error->code = content::SPEECH_RECOGNITION_ERROR_NETWORK; | 83 error->code = SPEECH_RECOGNITION_ERROR_NETWORK; |
| 88 // Other status codes should not be returned by the server. | 84 // Other status codes should not be returned by the server. |
| 89 VLOG(1) << "ParseServerResponse: unexpected status code " << status; | 85 VLOG(1) << "ParseServerResponse: unexpected status code " << status; |
| 90 return false; | 86 return false; |
| 91 } | 87 } |
| 92 | 88 |
| 93 // Get the hypotheses. | 89 // Get the hypotheses. |
| 94 const Value* hypotheses_value = NULL; | 90 const Value* hypotheses_value = NULL; |
| 95 if (!response_object->Get(kHypothesesString, &hypotheses_value)) { | 91 if (!response_object->Get(kHypothesesString, &hypotheses_value)) { |
| 96 VLOG(1) << "ParseServerResponse: Missing hypotheses attribute."; | 92 VLOG(1) << "ParseServerResponse: Missing hypotheses attribute."; |
| 97 return false; | 93 return false; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 141 | 137 |
| 142 if (index < hypotheses_list->GetSize()) { | 138 if (index < hypotheses_list->GetSize()) { |
| 143 result->hypotheses.clear(); | 139 result->hypotheses.clear(); |
| 144 return false; | 140 return false; |
| 145 } | 141 } |
| 146 return true; | 142 return true; |
| 147 } | 143 } |
| 148 | 144 |
| 149 } // namespace | 145 } // namespace |
| 150 | 146 |
| 151 namespace speech { | |
| 152 | |
| 153 const int GoogleOneShotRemoteEngine::kAudioPacketIntervalMs = 100; | 147 const int GoogleOneShotRemoteEngine::kAudioPacketIntervalMs = 100; |
| 154 int GoogleOneShotRemoteEngine::url_fetcher_id_for_tests = 0; | 148 int GoogleOneShotRemoteEngine::url_fetcher_id_for_tests = 0; |
| 155 | 149 |
| 156 GoogleOneShotRemoteEngine::GoogleOneShotRemoteEngine( | 150 GoogleOneShotRemoteEngine::GoogleOneShotRemoteEngine( |
| 157 net::URLRequestContextGetter* context) | 151 net::URLRequestContextGetter* context) |
| 158 : url_context_(context) { | 152 : url_context_(context) { |
| 159 } | 153 } |
| 160 | 154 |
| 161 GoogleOneShotRemoteEngine::~GoogleOneShotRemoteEngine() {} | 155 GoogleOneShotRemoteEngine::~GoogleOneShotRemoteEngine() {} |
| 162 | 156 |
| (...skipping 96 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 259 DCHECK(!encoded_dummy_data->IsEmpty()); | 253 DCHECK(!encoded_dummy_data->IsEmpty()); |
| 260 encoder_.reset(); | 254 encoder_.reset(); |
| 261 | 255 |
| 262 url_fetcher_->AppendChunkToUpload(encoded_dummy_data->AsString(), true); | 256 url_fetcher_->AppendChunkToUpload(encoded_dummy_data->AsString(), true); |
| 263 } | 257 } |
| 264 | 258 |
| 265 void GoogleOneShotRemoteEngine::OnURLFetchComplete( | 259 void GoogleOneShotRemoteEngine::OnURLFetchComplete( |
| 266 const net::URLFetcher* source) { | 260 const net::URLFetcher* source) { |
| 267 DCHECK_EQ(url_fetcher_.get(), source); | 261 DCHECK_EQ(url_fetcher_.get(), source); |
| 268 SpeechRecognitionResult result; | 262 SpeechRecognitionResult result; |
| 269 SpeechRecognitionError error(content::SPEECH_RECOGNITION_ERROR_NETWORK); | 263 SpeechRecognitionError error(SPEECH_RECOGNITION_ERROR_NETWORK); |
| 270 std::string data; | 264 std::string data; |
| 271 | 265 |
| 272 // The default error code in case of parse errors is NETWORK_FAILURE, however | 266 // The default error code in case of parse errors is NETWORK_FAILURE, however |
| 273 // ParseServerResponse can change the error to a more appropriate one. | 267 // ParseServerResponse can change the error to a more appropriate one. |
| 274 bool error_occurred = (!source->GetStatus().is_success() || | 268 bool error_occurred = (!source->GetStatus().is_success() || |
| 275 source->GetResponseCode() != 200 || | 269 source->GetResponseCode() != 200 || |
| 276 !source->GetResponseAsString(&data) || | 270 !source->GetResponseAsString(&data) || |
| 277 !ParseServerResponse(data, &result, &error)); | 271 !ParseServerResponse(data, &result, &error)); |
| 278 url_fetcher_.reset(); | 272 url_fetcher_.reset(); |
| 279 if (error_occurred) { | 273 if (error_occurred) { |
| 280 DVLOG(1) << "GoogleOneShotRemoteEngine: Network Error " << error.code; | 274 DVLOG(1) << "GoogleOneShotRemoteEngine: Network Error " << error.code; |
| 281 delegate()->OnSpeechRecognitionEngineError(error); | 275 delegate()->OnSpeechRecognitionEngineError(error); |
| 282 } else { | 276 } else { |
| 283 DVLOG(1) << "GoogleOneShotRemoteEngine: Invoking delegate with result."; | 277 DVLOG(1) << "GoogleOneShotRemoteEngine: Invoking delegate with result."; |
| 284 delegate()->OnSpeechRecognitionEngineResult(result); | 278 delegate()->OnSpeechRecognitionEngineResult(result); |
| 285 } | 279 } |
| 286 } | 280 } |
| 287 | 281 |
| 288 bool GoogleOneShotRemoteEngine::IsRecognitionPending() const { | 282 bool GoogleOneShotRemoteEngine::IsRecognitionPending() const { |
| 289 return url_fetcher_ != NULL; | 283 return url_fetcher_ != NULL; |
| 290 } | 284 } |
| 291 | 285 |
| 292 int GoogleOneShotRemoteEngine::GetDesiredAudioChunkDurationMs() const { | 286 int GoogleOneShotRemoteEngine::GetDesiredAudioChunkDurationMs() const { |
| 293 return kAudioPacketIntervalMs; | 287 return kAudioPacketIntervalMs; |
| 294 } | 288 } |
| 295 | 289 |
| 296 } // namespace speech | 290 } // namespace content |
| OLD | NEW |