Index: content/browser/speech/speech_recognition_dispatcher_host.cc |
diff --git a/content/browser/speech/speech_recognition_dispatcher_host.cc b/content/browser/speech/speech_recognition_dispatcher_host.cc |
index f920c51e779d6632c6eab3f1c8ee304080c789aa..737a610f48fad5ebb29e65e67e27db11b4dbfed6 100644 |
--- a/content/browser/speech/speech_recognition_dispatcher_host.cc |
+++ b/content/browser/speech/speech_recognition_dispatcher_host.cc |
@@ -9,23 +9,77 @@ |
#include "base/lazy_instance.h" |
#include "content/browser/browser_plugin/browser_plugin_guest.h" |
#include "content/browser/child_process_security_policy_impl.h" |
-#include "content/browser/renderer_host/render_view_host_impl.h" |
#include "content/browser/speech/speech_recognition_manager_impl.h" |
#include "content/browser/web_contents/web_contents_impl.h" |
#include "content/common/speech_recognition_messages.h" |
+#include "content/public/browser/browser_context.h" |
+#include "content/public/browser/browser_thread.h" |
+#include "content/public/browser/render_frame_host.h" |
#include "content/public/browser/speech_recognition_manager_delegate.h" |
#include "content/public/browser/speech_recognition_session_config.h" |
#include "content/public/browser/speech_recognition_session_context.h" |
-#include "content/public/common/content_switches.h" |
+#include "content/public/common/child_process_host.h" |
namespace content { |
+namespace { |
+ |
+void SendMessageToFrameOnUI(int render_process_id, |
+ int render_frame_id, |
+ IPC::Message* message) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ RenderFrameHost* render_frame_host = |
+ RenderFrameHost::FromID(render_process_id, render_frame_id); |
+ if (render_frame_host) |
+ render_frame_host->Send(message); |
+} |
+ |
+void SendMessageToFrame(int render_process_id, |
+ int render_frame_id, |
+ IPC::Message* message) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ BrowserThread::PostTask( |
+ BrowserThread::UI, FROM_HERE, |
+ base::Bind(&SendMessageToFrameOnUI, |
+ render_process_id, render_frame_id, message)); |
+} |
+ |
+} // anonymous namespace |
+ |
+using FrameDeletedCallback = base::Callback<void(int)>; |
+using WebContentsDeletedCallback = base::Callback<void(WebContents*)>; |
+ |
+class SpeechRecognitionDispatcherHost::FrameDeletedObserver |
+ : public WebContentsObserver { |
+ public: |
+ FrameDeletedObserver(WebContents* web_contents, |
+ FrameDeletedCallback frame_deleted_cb, |
+ WebContentsDeletedCallback web_contents_deleted_cb) |
+ : WebContentsObserver(web_contents) { |
+ } |
+ |
+ ~FrameDeletedObserver() override { |
+ } |
+ |
+ private: |
+ void RenderFrameDeleted(RenderFrameHost* render_frame_host) override { |
+ frame_deleted_cb_.Run(render_frame_host->GetRoutingID()); |
+ } |
+ |
+ void WebContentsDestroyed() override { |
+ web_contents_deleted_cb_.Run(web_contents()); |
+ } |
+ |
+ const FrameDeletedCallback frame_deleted_cb_; |
+ const WebContentsDeletedCallback web_contents_deleted_cb_; |
+}; |
+ |
SpeechRecognitionDispatcherHost::SpeechRecognitionDispatcherHost( |
- int render_process_id, |
- net::URLRequestContextGetter* context_getter) |
+ int render_process_id) |
: BrowserMessageFilter(SpeechRecognitionMsgStart), |
render_process_id_(render_process_id), |
- context_getter_(context_getter), |
weak_factory_(this) { |
// Do not add any non-trivial initialization here, instead do it lazily when |
// required (e.g. see the method |SpeechRecognitionManager::GetInstance()|) or |
@@ -33,8 +87,11 @@ SpeechRecognitionDispatcherHost::SpeechRecognitionDispatcherHost( |
} |
SpeechRecognitionDispatcherHost::~SpeechRecognitionDispatcherHost() { |
- SpeechRecognitionManager::GetInstance()->AbortAllSessionsForRenderProcess( |
- render_process_id_); |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ weak_factory_.InvalidateWeakPtrs(); |
+ |
+ STLDeleteContainerPairSecondPointers(frame_deleted_observers_.begin(), |
+ frame_deleted_observers_.end()); |
} |
base::WeakPtr<SpeechRecognitionDispatcherHost> |
@@ -46,9 +103,20 @@ void SpeechRecognitionDispatcherHost::OnDestruct() const { |
BrowserThread::DeleteOnIOThread::Destruct(this); |
} |
+void SpeechRecognitionDispatcherHost::OnChannelClosing() { |
+ weak_factory_.InvalidateWeakPtrs(); |
+} |
+ |
+void SpeechRecognitionDispatcherHost::OverrideThreadForMessage( |
+ const IPC::Message& message, BrowserThread::ID* thread) { |
+ if (message.type() == SpeechRecognitionHostMsg_StartRequest::ID) |
+ *thread = BrowserThread::UI; |
+} |
+ |
bool SpeechRecognitionDispatcherHost::OnMessageReceived( |
const IPC::Message& message) { |
bool handled = true; |
+ |
IPC_BEGIN_MESSAGE_MAP(SpeechRecognitionDispatcherHost, message) |
IPC_MESSAGE_HANDLER(SpeechRecognitionHostMsg_StartRequest, |
OnStartRequest) |
@@ -60,23 +128,13 @@ bool SpeechRecognitionDispatcherHost::OnMessageReceived( |
OnAbortAllRequests) |
IPC_MESSAGE_UNHANDLED(handled = false) |
IPC_END_MESSAGE_MAP() |
- return handled; |
-} |
- |
-void SpeechRecognitionDispatcherHost::OverrideThreadForMessage( |
- const IPC::Message& message, |
- BrowserThread::ID* thread) { |
- if (message.type() == SpeechRecognitionHostMsg_StartRequest::ID) |
- *thread = BrowserThread::UI; |
-} |
-void SpeechRecognitionDispatcherHost::OnChannelClosing() { |
- weak_factory_.InvalidateWeakPtrs(); |
+ return handled; |
} |
void SpeechRecognitionDispatcherHost::OnStartRequest( |
const SpeechRecognitionHostMsg_StartRequest_Params& params) { |
- SpeechRecognitionHostMsg_StartRequest_Params input_params(params); |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
// Check that the origin specified by the renderer process is one |
// that it is allowed to access. |
@@ -89,72 +147,60 @@ void SpeechRecognitionDispatcherHost::OnStartRequest( |
} |
int embedder_render_process_id = 0; |
- int embedder_render_view_id = MSG_ROUTING_NONE; |
- RenderViewHostImpl* render_view_host = |
- RenderViewHostImpl::FromID(render_process_id_, params.render_view_id); |
- if (!render_view_host) { |
- // RVH can be null if the tab was closed while continuous mode speech |
- // recognition was running. This seems to happen on mac. |
- LOG(WARNING) << "SRDH::OnStartRequest, RenderViewHost does not exist"; |
- return; |
- } |
- WebContentsImpl* web_contents = static_cast<WebContentsImpl*>( |
- WebContents::FromRenderViewHost(render_view_host)); |
- BrowserPluginGuest* guest = web_contents->GetBrowserPluginGuest(); |
+ int embedder_render_frame_id = MSG_ROUTING_NONE; |
+ |
+ WebContents* web_contents = WebContents::FromRenderFrameHost( |
+ RenderFrameHost::FromID(render_process_id_, params.render_frame_id)); |
+ DCHECK(web_contents); |
+ |
+ BrowserPluginGuest* guest = |
+ static_cast<WebContentsImpl*>(web_contents)->GetBrowserPluginGuest(); |
+ |
if (guest) { |
// If the speech API request was from a guest, save the context of the |
// embedder since we will use it to decide permission. |
embedder_render_process_id = |
guest->embedder_web_contents()->GetRenderProcessHost()->GetID(); |
DCHECK_NE(embedder_render_process_id, 0); |
- embedder_render_view_id = |
- guest->embedder_web_contents()->GetRenderViewHost()->GetRoutingID(); |
- DCHECK_NE(embedder_render_view_id, MSG_ROUTING_NONE); |
+ embedder_render_frame_id = |
+ guest->embedder_web_contents()->GetMainFrame()->GetRoutingID(); |
+ DCHECK_NE(embedder_render_frame_id, MSG_ROUTING_NONE); |
} |
- // TODO(lazyboy): Check if filter_profanities should use |render_process_id| |
- // instead of |render_process_id_|. |
bool filter_profanities = |
SpeechRecognitionManagerImpl::GetInstance() && |
SpeechRecognitionManagerImpl::GetInstance()->delegate() && |
SpeechRecognitionManagerImpl::GetInstance()->delegate()-> |
FilterProfanities(render_process_id_); |
- // TODO(miu): This is a hack to allow SpeechRecognition to operate with the |
- // MediaStreamManager, which partitions requests per RenderFrame, not per |
- // RenderView. http://crbug.com/390749 |
- const int params_render_frame_id = render_view_host ? |
- render_view_host->GetMainFrame()->GetRoutingID() : MSG_ROUTING_NONE; |
- |
- BrowserThread::PostTask( |
- BrowserThread::IO, |
- FROM_HERE, |
- base::Bind(&SpeechRecognitionDispatcherHost::OnStartRequestOnIO, |
- this, |
- embedder_render_process_id, |
- embedder_render_view_id, |
- input_params, |
- params_render_frame_id, |
- filter_profanities)); |
-} |
- |
-void SpeechRecognitionDispatcherHost::OnStartRequestOnIO( |
- int embedder_render_process_id, |
- int embedder_render_view_id, |
- const SpeechRecognitionHostMsg_StartRequest_Params& params, |
- int params_render_frame_id, |
- bool filter_profanities) { |
SpeechRecognitionSessionContext context; |
context.context_name = params.origin_url; |
context.render_process_id = render_process_id_; |
- context.render_view_id = params.render_view_id; |
- context.render_frame_id = params_render_frame_id; |
+ context.render_frame_id = params.render_frame_id; |
context.embedder_render_process_id = embedder_render_process_id; |
- context.embedder_render_view_id = embedder_render_view_id; |
+ context.embedder_render_frame_id = embedder_render_frame_id; |
if (embedder_render_process_id) |
- context.guest_render_view_id = params.render_view_id; |
+ context.guest_render_frame_id = params.render_frame_id; |
context.request_id = params.request_id; |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&SpeechRecognitionDispatcherHost::StartSession, |
+ base::Unretained(this), |
+ params, |
+ context, |
+ base::Unretained(web_contents->GetBrowserContext()-> |
+ GetRequestContextForRenderProcess(render_process_id_)), |
+ filter_profanities)); |
+} |
+ |
+void SpeechRecognitionDispatcherHost::StartSession( |
+ const SpeechRecognitionHostMsg_StartRequest_Params& params, |
+ const SpeechRecognitionSessionContext& context, |
+ net::URLRequestContextGetter* url_request_context_getter, |
+ bool filter_profanities) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
SpeechRecognitionSessionConfig config; |
config.is_legacy_api = false; |
config.language = params.language; |
@@ -162,7 +208,7 @@ void SpeechRecognitionDispatcherHost::OnStartRequestOnIO( |
config.max_hypotheses = params.max_hypotheses; |
config.origin_url = params.origin_url; |
config.initial_context = context; |
- config.url_request_context_getter = context_getter_.get(); |
+ config.url_request_context_getter = url_request_context_getter; |
config.filter_profanities = filter_profanities; |
config.continuous = params.continuous; |
config.interim_results = params.interim_results; |
@@ -174,10 +220,12 @@ void SpeechRecognitionDispatcherHost::OnStartRequestOnIO( |
SpeechRecognitionManager::GetInstance()->StartSession(session_id); |
} |
-void SpeechRecognitionDispatcherHost::OnAbortRequest(int render_view_id, |
+void SpeechRecognitionDispatcherHost::OnAbortRequest(int render_frame_id, |
int request_id) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
int session_id = SpeechRecognitionManager::GetInstance()->GetSession( |
- render_process_id_, render_view_id, request_id); |
+ render_process_id_, render_frame_id, request_id); |
// The renderer might provide an invalid |request_id| if the session was not |
// started as expected, e.g., due to unsatisfied security requirements. |
@@ -185,15 +233,19 @@ void SpeechRecognitionDispatcherHost::OnAbortRequest(int render_view_id, |
SpeechRecognitionManager::GetInstance()->AbortSession(session_id); |
} |
-void SpeechRecognitionDispatcherHost::OnAbortAllRequests(int render_view_id) { |
- SpeechRecognitionManager::GetInstance()->AbortAllSessionsForRenderView( |
- render_process_id_, render_view_id); |
+void SpeechRecognitionDispatcherHost::OnAbortAllRequests(int render_frame_id) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
+ SpeechRecognitionManager::GetInstance()->AbortAllSessionsForRenderFrame( |
+ render_process_id_, render_frame_id); |
} |
void SpeechRecognitionDispatcherHost::OnStopCaptureRequest( |
- int render_view_id, int request_id) { |
+ int render_frame_id, int request_id) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::IO); |
+ |
int session_id = SpeechRecognitionManager::GetInstance()->GetSession( |
- render_process_id_, render_view_id, request_id); |
+ render_process_id_, render_frame_id, request_id); |
// The renderer might provide an invalid |request_id| if the session was not |
// started as expected, e.g., due to unsatisfied security requirements. |
@@ -203,48 +255,103 @@ void SpeechRecognitionDispatcherHost::OnStopCaptureRequest( |
} |
} |
+void SpeechRecognitionDispatcherHost::CreateObserverFor( |
+ WebContents* web_contents) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ if (frame_deleted_observers_.find(web_contents) != |
+ frame_deleted_observers_.end()) { |
+ return; |
+ } |
+ |
+ frame_deleted_observers_.emplace( |
+ web_contents, |
+ new FrameDeletedObserver( |
+ web_contents, |
+ base::Bind(&SpeechRecognitionDispatcherHost::AbortAllRequestsFromUI, |
+ AsWeakPtr()), |
+ base::Bind(&SpeechRecognitionDispatcherHost::RemoveObserverFor, |
+ AsWeakPtr()))); |
+} |
+ |
+void SpeechRecognitionDispatcherHost::RemoveObserverFor( |
+ WebContents* web_contents) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ FrameDeletedObservers::iterator it = |
+ frame_deleted_observers_.find(web_contents); |
+ if (it == frame_deleted_observers_.end()) |
+ return; |
+ |
+ delete it->second; |
+ frame_deleted_observers_.erase(web_contents); |
+} |
+ |
+void SpeechRecognitionDispatcherHost::AbortAllRequestsFromUI( |
+ int render_frame_id) { |
+ DCHECK_CURRENTLY_ON(BrowserThread::UI); |
+ |
+ BrowserThread::PostTask( |
+ BrowserThread::IO, FROM_HERE, |
+ base::Bind(&SpeechRecognitionDispatcherHost::OnAbortAllRequests, |
+ this, |
+ render_frame_id)); |
+} |
+ |
// -------- SpeechRecognitionEventListener interface implementation ----------- |
void SpeechRecognitionDispatcherHost::OnRecognitionStart(int session_id) { |
const SpeechRecognitionSessionContext& context = |
SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); |
- Send(new SpeechRecognitionMsg_Started(context.render_view_id, |
- context.request_id)); |
+ |
+ SendMessageToFrame(context.render_process_id, context.render_frame_id, |
+ new SpeechRecognitionMsg_Started(context.render_frame_id, |
+ context.request_id)); |
} |
void SpeechRecognitionDispatcherHost::OnAudioStart(int session_id) { |
const SpeechRecognitionSessionContext& context = |
SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); |
- Send(new SpeechRecognitionMsg_AudioStarted(context.render_view_id, |
- context.request_id)); |
+ |
+ SendMessageToFrame(context.render_process_id, context.render_frame_id, |
+ new SpeechRecognitionMsg_AudioStarted( |
+ context.render_frame_id, context.request_id)); |
} |
void SpeechRecognitionDispatcherHost::OnSoundStart(int session_id) { |
const SpeechRecognitionSessionContext& context = |
SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); |
- Send(new SpeechRecognitionMsg_SoundStarted(context.render_view_id, |
- context.request_id)); |
+ |
+ SendMessageToFrame(context.render_process_id, context.render_frame_id, |
+ new SpeechRecognitionMsg_SoundStarted( |
+ context.render_frame_id, context.request_id)); |
} |
void SpeechRecognitionDispatcherHost::OnSoundEnd(int session_id) { |
const SpeechRecognitionSessionContext& context = |
SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); |
- Send(new SpeechRecognitionMsg_SoundEnded(context.render_view_id, |
- context.request_id)); |
+ |
+ SendMessageToFrame(context.render_process_id, context.render_frame_id, |
+ new SpeechRecognitionMsg_SoundEnded( |
+ context.render_frame_id, context.request_id)); |
} |
void SpeechRecognitionDispatcherHost::OnAudioEnd(int session_id) { |
const SpeechRecognitionSessionContext& context = |
SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); |
- Send(new SpeechRecognitionMsg_AudioEnded(context.render_view_id, |
- context.request_id)); |
+ |
+ SendMessageToFrame(context.render_process_id, context.render_frame_id, |
+ new SpeechRecognitionMsg_AudioEnded( |
+ context.render_frame_id, context.request_id)); |
} |
void SpeechRecognitionDispatcherHost::OnRecognitionEnd(int session_id) { |
const SpeechRecognitionSessionContext& context = |
SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); |
- Send(new SpeechRecognitionMsg_Ended(context.render_view_id, |
- context.request_id)); |
+ |
+ SendMessageToFrame(context.render_process_id, context.render_frame_id, |
+ new SpeechRecognitionMsg_Ended( |
+ context.render_frame_id, context.request_id)); |
} |
void SpeechRecognitionDispatcherHost::OnRecognitionResults( |
@@ -252,9 +359,10 @@ void SpeechRecognitionDispatcherHost::OnRecognitionResults( |
const SpeechRecognitionResults& results) { |
const SpeechRecognitionSessionContext& context = |
SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); |
- Send(new SpeechRecognitionMsg_ResultRetrieved(context.render_view_id, |
- context.request_id, |
- results)); |
+ |
+ SendMessageToFrame(context.render_process_id, context.render_frame_id, |
+ new SpeechRecognitionMsg_ResultRetrieved( |
+ context.render_frame_id, context.request_id, results)); |
} |
void SpeechRecognitionDispatcherHost::OnRecognitionError( |
@@ -262,9 +370,10 @@ void SpeechRecognitionDispatcherHost::OnRecognitionError( |
const SpeechRecognitionError& error) { |
const SpeechRecognitionSessionContext& context = |
SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id); |
- Send(new SpeechRecognitionMsg_ErrorOccurred(context.render_view_id, |
- context.request_id, |
- error)); |
+ |
+ SendMessageToFrame(context.render_process_id, context.render_frame_id, |
+ new SpeechRecognitionMsg_ErrorOccurred( |
+ context.render_frame_id, context.request_id, error)); |
} |
// The events below are currently not used by speech JS APIs implementation. |