blob: 50b9aec9d86e54f6e95a6a25b8a510139615aabd [file] [log] [blame]
// Copyright (c) 2010 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 "chrome/browser/speech/speech_input_dispatcher_host.h"
#include "base/lazy_instance.h"
#include "chrome/common/render_messages.h"
namespace speech_input {
//----------------------------- SpeechInputCallers -----------------------------
// A singleton class to map the tuple
// (render-process-id, render-view-id, requestid) to a single ID which is passed
// through rest of the speech code.
class SpeechInputDispatcherHost::SpeechInputCallers {
public:
// Creates a new ID for a given tuple.
int CreateId(int render_process_id, int render_view_id, int request_id);
// Returns the ID for a tuple assuming the ID was created earlier.
int GetId(int render_process_id, int render_view_id, int request_id);
// Removes the ID and associated tuple from the map.
void RemoveId(int id);
// Getters for the various tuple elements for the given ID.
int render_process_id(int id);
int render_view_id(int id);
int request_id(int id);
private:
struct CallerInfo {
int render_process_id;
int render_view_id;
int request_id;
};
friend struct base::DefaultLazyInstanceTraits<SpeechInputCallers>;
SpeechInputCallers();
std::map<int, CallerInfo> callers_;
int next_id_;
};
static base::LazyInstance<SpeechInputDispatcherHost::SpeechInputCallers>
g_speech_input_callers(base::LINKER_INITIALIZED);
SpeechInputDispatcherHost::SpeechInputCallers::SpeechInputCallers()
: next_id_(1) {
}
int SpeechInputDispatcherHost::SpeechInputCallers::GetId(int render_process_id,
int render_view_id,
int request_id) {
for (std::map<int, CallerInfo>::iterator it = callers_.begin();
it != callers_.end(); it++) {
const CallerInfo& item = it->second;
if (item.render_process_id == render_process_id &&
item.render_view_id == render_view_id &&
item.request_id == request_id) {
return it->first;
}
}
// Not finding an entry here is valid since a cancel/stop may have been issued
// by the renderer and before it received our response the user may have
// clicked the button to stop again. The caller of this method should take
// care of this case.
return 0;
}
int SpeechInputDispatcherHost::SpeechInputCallers::CreateId(
int render_process_id,
int render_view_id,
int request_id) {
CallerInfo info;
info.render_process_id = render_process_id;
info.render_view_id = render_view_id;
info.request_id = request_id;
callers_[next_id_] = info;
return next_id_++;
}
void SpeechInputDispatcherHost::SpeechInputCallers::RemoveId(int id) {
callers_.erase(id);
}
int SpeechInputDispatcherHost::SpeechInputCallers::render_process_id(int id) {
return callers_[id].render_process_id;
}
int SpeechInputDispatcherHost::SpeechInputCallers::render_view_id(int id) {
return callers_[id].render_view_id;
}
int SpeechInputDispatcherHost::SpeechInputCallers::request_id(int id) {
return callers_[id].request_id;
}
//-------------------------- SpeechInputDispatcherHost -------------------------
SpeechInputManager::AccessorMethod*
SpeechInputDispatcherHost::manager_accessor_ = &SpeechInputManager::Get;
SpeechInputDispatcherHost::SpeechInputDispatcherHost(int render_process_id)
: render_process_id_(render_process_id) {
// This is initialized by Browser. Do not add any non-trivial
// initialization here, instead do it lazily when required (e.g. see the
// method |manager()|) or add an Init() method.
}
SpeechInputDispatcherHost::~SpeechInputDispatcherHost() {
}
SpeechInputManager* SpeechInputDispatcherHost::manager() {
return (*manager_accessor_)();
}
bool SpeechInputDispatcherHost::OnMessageReceived(
const IPC::Message& message, bool* message_was_ok) {
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
uint32 message_type = message.type();
if (message_type == ViewHostMsg_SpeechInput_StartRecognition::ID ||
message_type == ViewHostMsg_SpeechInput_CancelRecognition::ID ||
message_type == ViewHostMsg_SpeechInput_StopRecording::ID) {
if (!SpeechInputManager::IsFeatureEnabled()) {
*message_was_ok = false;
return true;
}
IPC_BEGIN_MESSAGE_MAP_EX(SpeechInputDispatcherHost, message,
*message_was_ok)
IPC_MESSAGE_HANDLER(ViewHostMsg_SpeechInput_StartRecognition,
OnStartRecognition)
IPC_MESSAGE_HANDLER(ViewHostMsg_SpeechInput_CancelRecognition,
OnCancelRecognition)
IPC_MESSAGE_HANDLER(ViewHostMsg_SpeechInput_StopRecording,
OnStopRecording)
IPC_END_MESSAGE_MAP()
return true;
}
return false;
}
void SpeechInputDispatcherHost::OnStartRecognition(
int render_view_id,
int request_id,
const gfx::Rect& element_rect,
const std::string& language,
const std::string& grammar) {
int caller_id = g_speech_input_callers.Get().CreateId(
render_process_id_, render_view_id, request_id);
manager()->StartRecognition(this, caller_id,
render_process_id_,
render_view_id, element_rect,
language, grammar);
}
void SpeechInputDispatcherHost::OnCancelRecognition(int render_view_id,
int request_id) {
int caller_id = g_speech_input_callers.Get().GetId(
render_process_id_, render_view_id, request_id);
if (caller_id) {
manager()->CancelRecognition(caller_id);
// Request sequence ended so remove mapping.
g_speech_input_callers.Get().RemoveId(caller_id);
}
}
void SpeechInputDispatcherHost::OnStopRecording(int render_view_id,
int request_id) {
int caller_id = g_speech_input_callers.Get().GetId(
render_process_id_, render_view_id, request_id);
if (caller_id)
manager()->StopRecording(caller_id);
}
void SpeechInputDispatcherHost::SetRecognitionResult(
int caller_id, const SpeechInputResultArray& result) {
VLOG(1) << "SpeechInputDispatcherHost::SetRecognitionResult enter";
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
int caller_render_view_id =
g_speech_input_callers.Get().render_view_id(caller_id);
int caller_request_id = g_speech_input_callers.Get().request_id(caller_id);
Send(new ViewMsg_SpeechInput_SetRecognitionResult(caller_render_view_id,
caller_request_id,
result));
VLOG(1) << "SpeechInputDispatcherHost::SetRecognitionResult exit";
}
void SpeechInputDispatcherHost::DidCompleteRecording(int caller_id) {
VLOG(1) << "SpeechInputDispatcherHost::DidCompleteRecording enter";
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
int caller_render_view_id =
g_speech_input_callers.Get().render_view_id(caller_id);
int caller_request_id = g_speech_input_callers.Get().request_id(caller_id);
Send(new ViewMsg_SpeechInput_RecordingComplete(caller_render_view_id,
caller_request_id));
VLOG(1) << "SpeechInputDispatcherHost::DidCompleteRecording exit";
}
void SpeechInputDispatcherHost::DidCompleteRecognition(int caller_id) {
VLOG(1) << "SpeechInputDispatcherHost::DidCompleteRecognition enter";
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
int caller_render_view_id =
g_speech_input_callers.Get().render_view_id(caller_id);
int caller_request_id = g_speech_input_callers.Get().request_id(caller_id);
Send(new ViewMsg_SpeechInput_RecognitionComplete(caller_render_view_id,
caller_request_id));
// Request sequence ended, so remove mapping.
g_speech_input_callers.Get().RemoveId(caller_id);
VLOG(1) << "SpeechInputDispatcherHost::DidCompleteRecognition exit";
}
} // namespace speech_input