2015-01-09 18:22:10 +01:00
|
|
|
// Copyright (c) 2012 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 "libcef/browser/speech_recognition_manager_delegate.h"
|
|
|
|
|
|
|
|
#include <set>
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#include "libcef/common/cef_switches.h"
|
|
|
|
|
|
|
|
#include "base/bind.h"
|
|
|
|
#include "base/command_line.h"
|
|
|
|
#include "content/public/browser/browser_thread.h"
|
|
|
|
#include "content/public/browser/notification_observer.h"
|
|
|
|
#include "content/public/browser/notification_registrar.h"
|
|
|
|
#include "content/public/browser/notification_source.h"
|
|
|
|
#include "content/public/browser/notification_types.h"
|
|
|
|
#include "content/public/browser/render_process_host.h"
|
|
|
|
#include "content/public/browser/render_view_host.h"
|
|
|
|
#include "content/public/browser/speech_recognition_manager.h"
|
|
|
|
#include "content/public/browser/speech_recognition_session_context.h"
|
|
|
|
#include "content/public/browser/web_contents.h"
|
|
|
|
#include "content/public/common/speech_recognition_error.h"
|
|
|
|
#include "content/public/common/speech_recognition_result.h"
|
|
|
|
|
|
|
|
using content::BrowserThread;
|
|
|
|
using content::SpeechRecognitionManager;
|
|
|
|
using content::WebContents;
|
|
|
|
|
|
|
|
// Simple utility to get notified when a WebContents is closed or crashes.
|
|
|
|
// Both the callback site and the callback thread are passed by the caller in
|
|
|
|
// the constructor. There is no restriction on the constructor, however this
|
|
|
|
// class must be destroyed on the UI thread, due to the NotificationRegistrar
|
|
|
|
// dependency.
|
|
|
|
class CefSpeechRecognitionManagerDelegate::WebContentsWatcher
|
|
|
|
: public base::RefCountedThreadSafe<WebContentsWatcher>,
|
|
|
|
public content::NotificationObserver {
|
|
|
|
public:
|
|
|
|
typedef base::Callback<void(int render_process_id, int render_view_id)>
|
|
|
|
WebContentsClosedCallback;
|
|
|
|
|
|
|
|
WebContentsWatcher(WebContentsClosedCallback web_contents_closed_callback,
|
2017-05-17 11:29:28 +02:00
|
|
|
BrowserThread::ID callback_thread)
|
2015-01-09 18:22:10 +01:00
|
|
|
: web_contents_closed_callback_(web_contents_closed_callback),
|
2017-05-17 11:29:28 +02:00
|
|
|
callback_thread_(callback_thread) {}
|
2015-01-09 18:22:10 +01:00
|
|
|
|
|
|
|
// Starts monitoring the WebContents corresponding to the given
|
|
|
|
// |render_process_id|, |render_view_id| pair, invoking
|
|
|
|
// |web_contents_closed_callback_| if closed/unloaded.
|
|
|
|
void Watch(int render_process_id, int render_view_id) {
|
|
|
|
if (!BrowserThread::CurrentlyOn(BrowserThread::UI)) {
|
2017-05-17 11:29:28 +02:00
|
|
|
BrowserThread::PostTask(BrowserThread::UI, FROM_HERE,
|
|
|
|
base::Bind(&WebContentsWatcher::Watch, this,
|
|
|
|
render_process_id, render_view_id));
|
2015-01-09 18:22:10 +01:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
WebContents* web_contents = NULL;
|
|
|
|
content::RenderViewHost* render_view_host =
|
2017-05-17 11:29:28 +02:00
|
|
|
content::RenderViewHost::FromID(render_process_id, render_view_id);
|
2015-01-09 18:22:10 +01:00
|
|
|
if (render_view_host)
|
|
|
|
web_contents = WebContents::FromRenderViewHost(render_view_host);
|
|
|
|
DCHECK(web_contents);
|
|
|
|
|
|
|
|
// Avoid multiple registrations on |registrar_| for the same |web_contents|.
|
|
|
|
if (registered_web_contents_.find(web_contents) !=
|
|
|
|
registered_web_contents_.end()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
registered_web_contents_.insert(web_contents);
|
|
|
|
|
|
|
|
// Lazy initialize the registrar.
|
|
|
|
if (!registrar_.get())
|
|
|
|
registrar_.reset(new content::NotificationRegistrar());
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
registrar_->Add(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
|
2015-01-09 18:22:10 +01:00
|
|
|
content::Source<WebContents>(web_contents));
|
|
|
|
}
|
|
|
|
|
|
|
|
// content::NotificationObserver implementation.
|
|
|
|
void Observe(int type,
|
|
|
|
const content::NotificationSource& source,
|
|
|
|
const content::NotificationDetails& details) override {
|
|
|
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
|
DCHECK_EQ(content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED, type);
|
|
|
|
|
|
|
|
WebContents* web_contents = content::Source<WebContents>(source).ptr();
|
2017-10-20 19:45:20 +02:00
|
|
|
int render_process_id =
|
|
|
|
web_contents->GetRenderViewHost()->GetProcess()->GetID();
|
2015-01-09 18:22:10 +01:00
|
|
|
int render_view_id = web_contents->GetRenderViewHost()->GetRoutingID();
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
registrar_->Remove(this, content::NOTIFICATION_WEB_CONTENTS_DISCONNECTED,
|
2015-01-09 18:22:10 +01:00
|
|
|
content::Source<WebContents>(web_contents));
|
|
|
|
registered_web_contents_.erase(web_contents);
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
BrowserThread::PostTask(callback_thread_, FROM_HERE,
|
|
|
|
base::Bind(web_contents_closed_callback_,
|
|
|
|
render_process_id, render_view_id));
|
2015-01-09 18:22:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend class base::RefCountedThreadSafe<WebContentsWatcher>;
|
|
|
|
|
|
|
|
~WebContentsWatcher() override {
|
|
|
|
// Must be destroyed on the UI thread due to |registrar_| non thread-safety.
|
|
|
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::UI));
|
|
|
|
}
|
|
|
|
|
|
|
|
// Lazy-initialized and used on the UI thread to handle web contents
|
|
|
|
// notifications (tab closing).
|
2016-04-27 22:38:52 +02:00
|
|
|
std::unique_ptr<content::NotificationRegistrar> registrar_;
|
2015-01-09 18:22:10 +01:00
|
|
|
|
|
|
|
// Keeps track of which WebContent(s) have been registered, in order to avoid
|
|
|
|
// double registrations on |registrar_|
|
|
|
|
std::set<content::WebContents*> registered_web_contents_;
|
|
|
|
|
|
|
|
// Callback used to notify, on the thread specified by |callback_thread_| the
|
|
|
|
// closure of a registered tab.
|
|
|
|
WebContentsClosedCallback web_contents_closed_callback_;
|
|
|
|
content::BrowserThread::ID callback_thread_;
|
|
|
|
|
|
|
|
DISALLOW_COPY_AND_ASSIGN(WebContentsWatcher);
|
|
|
|
};
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
CefSpeechRecognitionManagerDelegate ::CefSpeechRecognitionManagerDelegate() {
|
2015-01-09 18:22:10 +01:00
|
|
|
const base::CommandLine* command_line =
|
|
|
|
base::CommandLine::ForCurrentProcess();
|
|
|
|
filter_profanities_ =
|
|
|
|
command_line->HasSwitch(switches::kEnableProfanityFilter);
|
|
|
|
}
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
CefSpeechRecognitionManagerDelegate ::~CefSpeechRecognitionManagerDelegate() {}
|
2015-01-09 18:22:10 +01:00
|
|
|
|
|
|
|
void CefSpeechRecognitionManagerDelegate::WebContentsClosedCallback(
|
2017-05-17 11:29:28 +02:00
|
|
|
int render_process_id,
|
|
|
|
int render_view_id) {
|
2015-01-09 18:22:10 +01:00
|
|
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
|
|
|
|
|
|
|
SpeechRecognitionManager* manager = SpeechRecognitionManager::GetInstance();
|
|
|
|
// |manager| becomes NULL if a browser shutdown happens between the post of
|
|
|
|
// this task (from the UI thread) and this call (on the IO thread). In this
|
|
|
|
// case we just return.
|
|
|
|
if (!manager)
|
|
|
|
return;
|
|
|
|
|
|
|
|
manager->AbortAllSessionsForRenderView(render_process_id, render_view_id);
|
|
|
|
}
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
void CefSpeechRecognitionManagerDelegate::OnRecognitionStart(int session_id) {
|
2015-01-09 18:22:10 +01:00
|
|
|
const content::SpeechRecognitionSessionContext& context =
|
|
|
|
SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
|
|
|
|
|
|
|
|
// Register callback to auto abort session on tab closure.
|
|
|
|
// |web_contents_watcher_| is lazyly istantiated on the first call.
|
|
|
|
if (!web_contents_watcher_.get()) {
|
|
|
|
web_contents_watcher_ = new WebContentsWatcher(
|
|
|
|
base::Bind(
|
|
|
|
&CefSpeechRecognitionManagerDelegate::WebContentsClosedCallback,
|
|
|
|
base::Unretained(this)),
|
|
|
|
BrowserThread::IO);
|
|
|
|
}
|
|
|
|
web_contents_watcher_->Watch(context.render_process_id,
|
|
|
|
context.render_view_id);
|
|
|
|
}
|
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
void CefSpeechRecognitionManagerDelegate::OnAudioStart(int session_id) {}
|
2015-01-09 18:22:10 +01:00
|
|
|
|
|
|
|
void CefSpeechRecognitionManagerDelegate::OnEnvironmentEstimationComplete(
|
2017-05-17 11:29:28 +02:00
|
|
|
int session_id) {}
|
2015-01-09 18:22:10 +01:00
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
void CefSpeechRecognitionManagerDelegate::OnSoundStart(int session_id) {}
|
2015-01-09 18:22:10 +01:00
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
void CefSpeechRecognitionManagerDelegate::OnSoundEnd(int session_id) {}
|
2015-01-09 18:22:10 +01:00
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
void CefSpeechRecognitionManagerDelegate::OnAudioEnd(int session_id) {}
|
2015-01-09 18:22:10 +01:00
|
|
|
|
|
|
|
void CefSpeechRecognitionManagerDelegate::OnRecognitionResults(
|
2017-05-17 11:29:28 +02:00
|
|
|
int session_id,
|
|
|
|
const content::SpeechRecognitionResults& result) {}
|
2015-01-09 18:22:10 +01:00
|
|
|
|
|
|
|
void CefSpeechRecognitionManagerDelegate::OnRecognitionError(
|
2017-05-17 11:29:28 +02:00
|
|
|
int session_id,
|
|
|
|
const content::SpeechRecognitionError& error) {}
|
2015-01-09 18:22:10 +01:00
|
|
|
|
|
|
|
void CefSpeechRecognitionManagerDelegate::OnAudioLevelsChange(
|
2017-05-17 11:29:28 +02:00
|
|
|
int session_id,
|
|
|
|
float volume,
|
|
|
|
float noise_volume) {}
|
2015-01-09 18:22:10 +01:00
|
|
|
|
2017-05-17 11:29:28 +02:00
|
|
|
void CefSpeechRecognitionManagerDelegate::OnRecognitionEnd(int session_id) {}
|
2015-01-09 18:22:10 +01:00
|
|
|
|
|
|
|
void CefSpeechRecognitionManagerDelegate::CheckRecognitionIsAllowed(
|
|
|
|
int session_id,
|
2017-07-27 01:19:27 +02:00
|
|
|
base::OnceCallback<void(bool ask_user, bool is_allowed)> callback) {
|
2015-01-09 18:22:10 +01:00
|
|
|
DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO));
|
|
|
|
|
|
|
|
const content::SpeechRecognitionSessionContext& context =
|
|
|
|
SpeechRecognitionManager::GetInstance()->GetSessionContext(session_id);
|
|
|
|
|
|
|
|
// Make sure that initiators properly set the |render_process_id| field.
|
|
|
|
DCHECK_NE(context.render_process_id, 0);
|
|
|
|
|
2017-07-27 01:19:27 +02:00
|
|
|
BrowserThread::PostTask(BrowserThread::IO, FROM_HERE,
|
|
|
|
base::BindOnce(std::move(callback), false, true));
|
2015-01-09 18:22:10 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
content::SpeechRecognitionEventListener*
|
|
|
|
CefSpeechRecognitionManagerDelegate::GetEventListener() {
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CefSpeechRecognitionManagerDelegate::FilterProfanities(
|
|
|
|
int render_process_id) {
|
|
|
|
return filter_profanities_;
|
|
|
|
}
|