• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2013 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #include "content/browser/speech/speech_recognizer_impl_android.h"
6 
7 #include "base/android/jni_android.h"
8 #include "base/android/jni_array.h"
9 #include "base/android/jni_string.h"
10 #include "base/android/scoped_java_ref.h"
11 #include "base/bind.h"
12 #include "base/strings/utf_string_conversions.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/browser/speech_recognition_event_listener.h"
15 #include "content/public/browser/speech_recognition_manager.h"
16 #include "content/public/browser/speech_recognition_session_config.h"
17 #include "content/public/common/speech_recognition_grammar.h"
18 #include "content/public/common/speech_recognition_result.h"
19 #include "jni/SpeechRecognition_jni.h"
20 
21 using base::android::AppendJavaStringArrayToStringVector;
22 using base::android::AttachCurrentThread;
23 using base::android::ConvertUTF8ToJavaString;
24 using base::android::GetApplicationContext;
25 using base::android::JavaFloatArrayToFloatVector;
26 
27 namespace content {
28 
SpeechRecognizerImplAndroid(SpeechRecognitionEventListener * listener,int session_id)29 SpeechRecognizerImplAndroid::SpeechRecognizerImplAndroid(
30     SpeechRecognitionEventListener* listener,
31     int session_id)
32     : SpeechRecognizer(listener, session_id),
33       state_(STATE_IDLE) {
34 }
35 
~SpeechRecognizerImplAndroid()36 SpeechRecognizerImplAndroid::~SpeechRecognizerImplAndroid() { }
37 
StartRecognition(const std::string & device_id)38 void SpeechRecognizerImplAndroid::StartRecognition(
39     const std::string& device_id) {
40   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
41   // TODO(xians): Open the correct device for speech on Android.
42   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
43       &SpeechRecognitionEventListener::OnRecognitionStart,
44       base::Unretained(listener()),
45       session_id()));
46   SpeechRecognitionSessionConfig config =
47       SpeechRecognitionManager::GetInstance()->GetSessionConfig(session_id());
48   BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
49       &content::SpeechRecognizerImplAndroid::StartRecognitionOnUIThread, this,
50       config.language, config.continuous, config.interim_results));
51 }
52 
StartRecognitionOnUIThread(std::string language,bool continuous,bool interim_results)53 void SpeechRecognizerImplAndroid::StartRecognitionOnUIThread(
54     std::string language, bool continuous, bool interim_results) {
55   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
56   JNIEnv* env = AttachCurrentThread();
57   j_recognition_.Reset(Java_SpeechRecognition_createSpeechRecognition(env,
58       GetApplicationContext(), reinterpret_cast<intptr_t>(this)));
59   Java_SpeechRecognition_startRecognition(env, j_recognition_.obj(),
60       ConvertUTF8ToJavaString(env, language).obj(), continuous,
61       interim_results);
62 }
63 
AbortRecognition()64 void SpeechRecognizerImplAndroid::AbortRecognition() {
65   if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
66     state_ = STATE_IDLE;
67     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
68         &content::SpeechRecognizerImplAndroid::AbortRecognition, this));
69     return;
70   }
71   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
72   JNIEnv* env = AttachCurrentThread();
73   if (!j_recognition_.is_null())
74     Java_SpeechRecognition_abortRecognition(env, j_recognition_.obj());
75 }
76 
StopAudioCapture()77 void SpeechRecognizerImplAndroid::StopAudioCapture() {
78   if (BrowserThread::CurrentlyOn(BrowserThread::IO)) {
79     BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, base::Bind(
80         &content::SpeechRecognizerImplAndroid::StopAudioCapture, this));
81     return;
82   }
83   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
84   JNIEnv* env = AttachCurrentThread();
85   if (!j_recognition_.is_null())
86     Java_SpeechRecognition_stopRecognition(env, j_recognition_.obj());
87 }
88 
IsActive() const89 bool SpeechRecognizerImplAndroid::IsActive() const {
90   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
91   return state_ != STATE_IDLE;
92 }
93 
IsCapturingAudio() const94 bool SpeechRecognizerImplAndroid::IsCapturingAudio() const {
95   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
96   return state_ == STATE_CAPTURING_AUDIO;
97 }
98 
OnAudioStart(JNIEnv * env,jobject obj)99 void SpeechRecognizerImplAndroid::OnAudioStart(JNIEnv* env, jobject obj) {
100   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
101     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
102         &SpeechRecognizerImplAndroid::OnAudioStart, this,
103         static_cast<JNIEnv*>(NULL), static_cast<jobject>(NULL)));
104     return;
105   }
106   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
107   state_ = STATE_CAPTURING_AUDIO;
108   listener()->OnAudioStart(session_id());
109 }
110 
OnSoundStart(JNIEnv * env,jobject obj)111 void SpeechRecognizerImplAndroid::OnSoundStart(JNIEnv* env, jobject obj) {
112   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
113     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
114         &SpeechRecognizerImplAndroid::OnSoundStart, this,
115         static_cast<JNIEnv*>(NULL), static_cast<jobject>(NULL)));
116     return;
117   }
118   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
119   listener()->OnSoundStart(session_id());
120 }
121 
OnSoundEnd(JNIEnv * env,jobject obj)122 void SpeechRecognizerImplAndroid::OnSoundEnd(JNIEnv* env, jobject obj) {
123   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
124     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
125         &SpeechRecognizerImplAndroid::OnSoundEnd, this,
126         static_cast<JNIEnv*>(NULL), static_cast<jobject>(NULL)));
127     return;
128   }
129   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
130   listener()->OnSoundEnd(session_id());
131 }
132 
OnAudioEnd(JNIEnv * env,jobject obj)133 void SpeechRecognizerImplAndroid::OnAudioEnd(JNIEnv* env, jobject obj) {
134   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
135     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
136         &SpeechRecognizerImplAndroid::OnAudioEnd, this,
137         static_cast<JNIEnv*>(NULL), static_cast<jobject>(NULL)));
138     return;
139   }
140   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
141   if (state_ == STATE_CAPTURING_AUDIO)
142     state_ = STATE_AWAITING_FINAL_RESULT;
143   listener()->OnAudioEnd(session_id());
144 }
145 
OnRecognitionResults(JNIEnv * env,jobject obj,jobjectArray strings,jfloatArray floats,jboolean provisional)146 void SpeechRecognizerImplAndroid::OnRecognitionResults(JNIEnv* env, jobject obj,
147     jobjectArray strings, jfloatArray floats, jboolean provisional) {
148   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
149   std::vector<base::string16> options;
150   AppendJavaStringArrayToStringVector(env, strings, &options);
151   std::vector<float> scores(options.size(), 0.0);
152   if (floats != NULL)
153     JavaFloatArrayToFloatVector(env, floats, &scores);
154   SpeechRecognitionResults results;
155   results.push_back(SpeechRecognitionResult());
156   SpeechRecognitionResult& result = results.back();
157   CHECK_EQ(options.size(), scores.size());
158   for (size_t i = 0; i < options.size(); ++i) {
159     result.hypotheses.push_back(SpeechRecognitionHypothesis(
160         options[i], static_cast<double>(scores[i])));
161   }
162   result.is_provisional = provisional;
163   BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
164       &SpeechRecognizerImplAndroid::OnRecognitionResultsOnIOThread,
165       this, results));
166 }
167 
OnRecognitionResultsOnIOThread(SpeechRecognitionResults const & results)168 void SpeechRecognizerImplAndroid::OnRecognitionResultsOnIOThread(
169     SpeechRecognitionResults const &results) {
170   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
171   listener()->OnRecognitionResults(session_id(), results);
172 }
173 
OnRecognitionError(JNIEnv * env,jobject obj,jint error)174 void SpeechRecognizerImplAndroid::OnRecognitionError(JNIEnv* env,
175     jobject obj, jint error) {
176   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
177     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
178         &SpeechRecognizerImplAndroid::OnRecognitionError, this,
179         static_cast<JNIEnv*>(NULL), static_cast<jobject>(NULL), error));
180     return;
181   }
182   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
183   SpeechRecognitionErrorCode code =
184       static_cast<SpeechRecognitionErrorCode>(error);
185   listener()->OnRecognitionError(session_id(), SpeechRecognitionError(code));
186 }
187 
OnRecognitionEnd(JNIEnv * env,jobject obj)188 void SpeechRecognizerImplAndroid::OnRecognitionEnd(JNIEnv* env,
189     jobject obj) {
190   if (BrowserThread::CurrentlyOn(BrowserThread::UI)) {
191     BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, base::Bind(
192         &SpeechRecognizerImplAndroid::OnRecognitionEnd, this,
193         static_cast<JNIEnv*>(NULL), static_cast<jobject>(NULL)));
194     return;
195   }
196   DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
197   state_ = STATE_IDLE;
198   listener()->OnRecognitionEnd(session_id());
199 }
200 
201 // static
RegisterSpeechRecognizer(JNIEnv * env)202 bool SpeechRecognizerImplAndroid::RegisterSpeechRecognizer(JNIEnv* env) {
203   return RegisterNativesImpl(env);
204 }
205 
206 }  // namespace content
207