Chromium Code Reviews| Index: content/browser/speech/speech_recognizer_impl_android.cc |
| diff --git a/content/browser/speech/speech_recognizer_impl_android.cc b/content/browser/speech/speech_recognizer_impl_android.cc |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..8251eb9eebc59fb07e2dfc56db742314e6344775 |
| --- /dev/null |
| +++ b/content/browser/speech/speech_recognizer_impl_android.cc |
| @@ -0,0 +1,232 @@ |
| +// Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| +// Use of this source code is governed by a BSD-style license that can be |
| +// found in the LICENSE file. |
| + |
| +#include "content/browser/speech/speech_recognizer_impl_android.h" |
| + |
| +#include "base/android/jni_android.h" |
| +#include "base/android/jni_array.h" |
| +#include "base/android/jni_string.h" |
| +#include "base/android/scoped_java_ref.h" |
| +#include "base/bind.h" |
| +#include "base/utf_string_conversions.h" |
| +#include "content/public/browser/browser_thread.h" |
| +#include "content/public/browser/speech_recognition_event_listener.h" |
| +#include "content/public/browser/speech_recognition_manager.h" |
| +#include "content/public/browser/speech_recognition_session_config.h" |
| +#include "content/public/common/speech_recognition_grammar.h" |
| +#include "content/public/common/speech_recognition_result.h" |
| +#include "jni/SpeechRecognition_jni.h" |
| + |
| +using base::android::AppendJavaStringArrayToStringVector; |
| +using base::android::AttachCurrentThread; |
| +using base::android::GetApplicationContext; |
| +using base::android::JavaFloatArrayToFloatVector; |
| + |
| +namespace content { |
| + |
| +void SpeechRecognizerImplAndroid::Init(JNIEnv* env) { |
| + RegisterNativesImpl(env); |
|
bulach
2013/06/07 15:35:10
as above, the way to do this is to expose a Regist
janx
2013/06/10 16:51:18
Fixed. Thanks for the explanation!
|
| +} |
| + |
| +SpeechRecognizerImplAndroid::SpeechRecognizerImplAndroid( |
| + SpeechRecognitionEventListener* listener, |
| + int session_id) |
| + : SpeechRecognizer(listener, session_id), |
| + state_(STATE_IDLE) { |
| +} |
| + |
| +SpeechRecognizerImplAndroid::~SpeechRecognizerImplAndroid() { } |
| + |
| +void SpeechRecognizerImplAndroid::StartRecognition() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + listener_->OnRecognitionStart(session_id_); |
|
janx
2013/06/07 12:43:58
Primiano Tucci 2013/06/03 16:24:11
I'd like to hav
|
| + SpeechRecognitionSessionConfig config_ = |
| + SpeechRecognitionManager::GetInstance()->GetSessionConfig(session_id_); |
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| + base::Bind(&content::SpeechRecognizerImplAndroid::StartRecognitionJNI, |
|
bulach
2013/06/07 15:35:10
ahn, right.. so there are two ways of doing this:
janx
2013/06/10 16:51:18
I refactored most of them into single functions, e
|
| + this, config_.continuous, config_.interim_results)); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::StartRecognitionJNI(bool continuous, |
| + bool interim_results) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + j_recognition_.Reset(Java_SpeechRecognition_createSpeechRecognition( |
| + AttachCurrentThread(), |
|
bulach
2013/06/07 15:35:10
AttachCurrentThread is a bit expensive. common pat
janx
2013/06/10 16:51:18
Done.
|
| + GetApplicationContext(), |
| + reinterpret_cast<jint>(this))); |
| + Java_SpeechRecognition_StartRecognition(AttachCurrentThread(), |
| + j_recognition_.obj(), continuous, interim_results); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::AbortRecognition() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| + base::Bind(&content::SpeechRecognizerImplAndroid::AbortRecognitionJNI, |
| + this)); |
| + OnRecognitionError(SpeechRecognitionError(SPEECH_RECOGNITION_ERROR_ABORTED)); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::AbortRecognitionJNI() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + if (!j_recognition_.is_null()) |
| + Java_SpeechRecognition_AbortRecognition(AttachCurrentThread(), |
| + j_recognition_.obj()); |
|
bulach
2013/06/07 15:35:10
nit: indent
janx
2013/06/10 16:51:18
Done.
|
| +} |
| + |
| +void SpeechRecognizerImplAndroid::StopAudioCapture() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + BrowserThread::PostTask(BrowserThread::UI, FROM_HERE, |
| + base::Bind(&content::SpeechRecognizerImplAndroid::StopRecognitionJNI, |
| + this)); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::StopRecognitionJNI() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + if (!j_recognition_.is_null()) |
| + Java_SpeechRecognition_StopRecognition(AttachCurrentThread(), |
| + j_recognition_.obj()); |
| +} |
| + |
| +bool SpeechRecognizerImplAndroid::IsActive() const { |
| + return state_ != STATE_IDLE; |
| +} |
| + |
| +bool SpeechRecognizerImplAndroid::IsCapturingAudio() const { |
| + return state_ == STATE_CAPTURING_AUDIO; |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnAudioStartJNI(JNIEnv* env, jobject obj) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| + base::Bind(&SpeechRecognizerImplAndroid::OnAudioStart, this)); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnAudioStart() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + state_ = STATE_CAPTURING_AUDIO; |
| + listener_->OnAudioStart(session_id_); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnSoundStartJNI(JNIEnv* env, jobject obj) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| + base::Bind(&SpeechRecognizerImplAndroid::OnSoundStart, this)); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnSoundStart() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + listener_->OnSoundStart(session_id_); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnSoundEndJNI(JNIEnv* env, jobject obj) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| + base::Bind(&SpeechRecognizerImplAndroid::OnSoundEnd, this)); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnSoundEnd() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + listener_->OnSoundEnd(session_id_); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnAudioEndJNI(JNIEnv* env, jobject obj) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| + base::Bind(&SpeechRecognizerImplAndroid::OnAudioEnd, this)); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnAudioEnd() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + state_ = STATE_AWAITING_FINAL_RESULT; |
| + listener_->OnAudioEnd(session_id_); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnRecognitionResultsJNI(JNIEnv* env, |
| + jobject obj, jobjectArray strings, jfloatArray floats, |
| + jboolean provisional) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + std::vector<string16> options; |
| + AppendJavaStringArrayToStringVector(env, strings, &options); |
| + std::vector<float> scores(options.size(), 0.0); |
| + if (floats != NULL) |
| + JavaFloatArrayToFloatVector(env, floats, &scores); |
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| + base::Bind(&SpeechRecognizerImplAndroid::OnRecognitionResults, |
| + this, options, scores, provisional)); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnRecognitionResults( |
| + std::vector<string16> options, std::vector<float> scores, |
| + bool provisional) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + SpeechRecognitionResults results; |
| + results.push_back(SpeechRecognitionResult()); |
| + SpeechRecognitionResult& result = results.back(); |
| + for (unsigned int i = 0; i < options.size(); i++) { |
| + result.hypotheses.push_back( |
| + SpeechRecognitionHypothesis(options[i], |
| + static_cast<double>(scores[i]))); |
| + } |
| + result.is_provisional = provisional; |
| + listener_->OnRecognitionResults(session_id_, results); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnRecognitionErrorJNI(JNIEnv* env, |
| + jobject obj, jint error) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + SpeechRecognitionErrorCode code; |
| + |
| + // Translate Android speech recognition errors to Web Speech API errors. |
| + // TODO(janx): Do this in SpeechRecognition.java instead. |
| + switch(error) { |
| + case 3: // ERROR_AUDIO |
| + code = SPEECH_RECOGNITION_ERROR_AUDIO; |
| + break; |
| + case 5: // ERROR_CLIENT |
| + code = SPEECH_RECOGNITION_ERROR_ABORTED; |
| + break; |
| + case 8: // ERROR_RECOGNIZER_BUSY |
| + case 9: // ERROR_INSUFFICIENT_PERMISSIONS |
| + code = SPEECH_RECOGNITION_ERROR_NOT_ALLOWED; |
| + break; |
| + case 1: // ERROR_NETWORK_TIMEOUT |
| + case 2: // ERROR_NETWORK |
| + case 4: // ERROR_SERVER |
| + code = SPEECH_RECOGNITION_ERROR_NETWORK; |
| + break; |
| + case 7: // ERROR_NO_MATCH |
| + code = SPEECH_RECOGNITION_ERROR_NO_MATCH; |
| + break; |
| + case 6: // ERROR_SPEECH_TIMEOUT |
| + code = SPEECH_RECOGNITION_ERROR_NO_SPEECH; |
| + break; |
| + default: |
| + NOTREACHED(); |
| + return; |
| + } |
| + |
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| + base::Bind(&SpeechRecognizerImplAndroid::OnRecognitionError, this, |
| + SpeechRecognitionError(code))); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnRecognitionError( |
| + SpeechRecognitionError error) { |
| + listener_->OnRecognitionError(session_id_, error); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnRecognitionEndJNI(JNIEnv* env, |
| + jobject obj) { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI)); |
| + BrowserThread::PostTask(BrowserThread::IO, FROM_HERE, |
| + base::Bind(&SpeechRecognizerImplAndroid::OnRecognitionEnd, this)); |
| +} |
| + |
| +void SpeechRecognizerImplAndroid::OnRecognitionEnd() { |
| + DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO)); |
| + state_ = STATE_IDLE; |
| + listener_->OnRecognitionEnd(session_id_); |
| +} |
| + |
| +} // namespace content |