blob: 6043ffc211f3d92cab39d4d5e0835ed2a1997fa1 [file] [log] [blame]
// Copyright 2016 The Cobalt Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "cobalt/speech/speech_recognition_manager.h"
#include "base/bind.h"
#include "base/threading/thread_task_runner_handle.h"
#include "cobalt/speech/cobalt_speech_recognizer.h"
#include "cobalt/speech/speech_configuration.h"
#include "cobalt/speech/speech_recognition_error.h"
#include "cobalt/web/dom_exception.h"
namespace cobalt {
namespace speech {
SpeechRecognitionManager::SpeechRecognitionManager(
network::NetworkModule* network_module, const EventCallback& event_callback,
const Microphone::Options& microphone_options)
: ALLOW_THIS_IN_INITIALIZER_LIST(weak_ptr_factory_(this)),
weak_this_(weak_ptr_factory_.GetWeakPtr()),
main_message_loop_task_runner_(base::ThreadTaskRunnerHandle::Get()),
event_callback_(event_callback),
state_(kStopped) {
if (GoogleSpeechService::GetSpeechAPIKey()) {
recognizer_.reset(new CobaltSpeechRecognizer(
network_module, microphone_options,
base::Bind(&SpeechRecognitionManager::OnEventAvailable,
base::Unretained(this))));
}
}
SpeechRecognitionManager::~SpeechRecognitionManager() { Abort(); }
void SpeechRecognitionManager::Start(const SpeechRecognitionConfig& config,
script::ExceptionState* exception_state) {
DCHECK(main_message_loop_task_runner_->BelongsToCurrentThread());
// If the start method is called on an already started object, the user agent
// MUST throw an InvalidStateError exception and ignore the call.
if (state_ == kStarted) {
web::DOMException::Raise(web::DOMException::kInvalidStateErr,
exception_state);
return;
}
// If no recognizer is available on this platform, immediately generate a
// "no-speech" error.
// https://w3c.github.io/speech-api/speechapi.html#speechreco-events
if (!recognizer_) {
OnEventAvailable(
new SpeechRecognitionError(kSpeechRecognitionErrorCodeNoSpeech, ""));
return;
}
recognizer_->Start(config);
state_ = kStarted;
}
void SpeechRecognitionManager::Stop() {
DCHECK(main_message_loop_task_runner_->BelongsToCurrentThread());
// If the stop method is called on an object which is already stopped or being
// stopped, the user agent MUST ignore the call.
if (state_ != kStarted) {
return;
}
recognizer_->Stop();
state_ = kStopped;
}
void SpeechRecognitionManager::Abort() {
DCHECK(main_message_loop_task_runner_->BelongsToCurrentThread());
// If the abort method is called on an object which is already stopped or
// aborting, the user agent MUST ignore the call.
if (state_ != kStarted) {
return;
}
state_ = kAborted;
recognizer_->Stop();
}
void SpeechRecognitionManager::OnEventAvailable(
const scoped_refptr<web::Event>& event) {
if (!main_message_loop_task_runner_->BelongsToCurrentThread()) {
// Called from recognizer. |event_callback_| is required to be run on
// the |main_message_loop_task_runner_|.
main_message_loop_task_runner_->PostTask(
FROM_HERE, base::Bind(&SpeechRecognitionManager::OnEventAvailable,
weak_this_, event));
return;
}
// Do not return any information if in the abort state.
if (state_ != kAborted) {
event_callback_.Run(event);
}
}
} // namespace speech
} // namespace cobalt