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 |