1 // Copyright 2020 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "chrome/browser/speech/speech_recognition_service.h" 6 7 #include "chrome/browser/browser_process.h" 8 #include "chrome/browser/service_sandbox_type.h" 9 #include "chrome/common/pref_names.h" 10 #include "chrome/grit/generated_resources.h" 11 #include "components/prefs/pref_service.h" 12 #include "components/soda/constants.h" 13 #include "components/user_prefs/user_prefs.h" 14 #include "content/public/browser/browser_context.h" 15 #include "content/public/browser/service_process_host.h" 16 #include "content/public/browser/storage_partition.h" 17 #include "services/network/network_context.h" 18 #include "services/network/public/cpp/shared_url_loader_factory.h" 19 20 namespace speech { 21 22 constexpr base::TimeDelta kIdleProcessTimeout = base::TimeDelta::FromSeconds(5); 23 SpeechRecognitionService(content::BrowserContext * context)24SpeechRecognitionService::SpeechRecognitionService( 25 content::BrowserContext* context) 26 : context_(context), 27 enable_soda_( 28 base::FeatureList::IsEnabled(media::kUseSodaForLiveCaption)) {} 29 30 SpeechRecognitionService::~SpeechRecognitionService() = default; 31 Create(mojo::PendingReceiver<media::mojom::SpeechRecognitionContext> receiver)32void SpeechRecognitionService::Create( 33 mojo::PendingReceiver<media::mojom::SpeechRecognitionContext> receiver) { 34 LaunchIfNotRunning(); 35 36 if (speech_recognition_service_.is_bound()) 37 speech_recognition_service_->BindContext(std::move(receiver)); 38 } 39 OnNetworkServiceDisconnect()40void SpeechRecognitionService::OnNetworkServiceDisconnect() { 41 if (!enable_soda_) { 42 // If the Speech On-Device API 43 // is not enabled, pass the URL 44 // loader factory to 45 // the speech recognition service to allow network requests to the Open 46 // Speech API. 47 mojo::PendingRemote<network::mojom::URLLoaderFactory> url_loader_factory; 48 network::mojom::URLLoaderFactoryParamsPtr params = 49 network::mojom::URLLoaderFactoryParams::New(); 50 params->process_id = network::mojom::kBrowserProcessId; 51 params->is_trusted = false; 52 params->automatically_assign_isolation_info = true; 53 network::mojom::NetworkContext* network_context = 54 content::BrowserContext::GetDefaultStoragePartition(context_) 55 ->GetNetworkContext(); 56 network_context->CreateURLLoaderFactory( 57 url_loader_factory.InitWithNewPipeAndPassReceiver(), std::move(params)); 58 speech_recognition_service_->SetUrlLoaderFactory( 59 std::move(url_loader_factory)); 60 } 61 } 62 LaunchIfNotRunning()63void SpeechRecognitionService::LaunchIfNotRunning() { 64 if (speech_recognition_service_.is_bound()) 65 return; 66 67 PrefService* profile_prefs = user_prefs::UserPrefs::Get(context_); 68 PrefService* global_prefs = g_browser_process->local_state(); 69 DCHECK(profile_prefs); 70 DCHECK(global_prefs); 71 72 auto binary_path = global_prefs->GetFilePath(prefs::kSodaBinaryPath); 73 auto config_path = SpeechRecognitionService::GetSodaConfigPath(profile_prefs); 74 if (enable_soda_ && (binary_path.empty() || config_path.empty())) { 75 LOG(ERROR) << "Unable to find SODA files on the device."; 76 return; 77 } 78 79 content::ServiceProcessHost::Launch( 80 speech_recognition_service_.BindNewPipeAndPassReceiver(), 81 content::ServiceProcessHost::Options() 82 .WithDisplayName(IDS_UTILITY_PROCESS_SPEECH_RECOGNITION_SERVICE_NAME) 83 .Pass()); 84 85 // Ensure that if the interface is ever disconnected (e.g. the service 86 // process crashes) or goes idle for a short period of time -- meaning there 87 // are no in-flight messages and no other interfaces bound through this 88 // one -- then we will reset |remote|, causing the service process to be 89 // terminated if it isn't already. 90 speech_recognition_service_.reset_on_disconnect(); 91 speech_recognition_service_.reset_on_idle_timeout(kIdleProcessTimeout); 92 93 speech_recognition_service_client_.reset(); 94 95 if (enable_soda_) 96 speech_recognition_service_->SetSodaPath(binary_path, config_path); 97 98 speech_recognition_service_->BindSpeechRecognitionServiceClient( 99 speech_recognition_service_client_.BindNewPipeAndPassRemote()); 100 OnNetworkServiceDisconnect(); 101 } 102 GetSodaConfigPath(PrefService * prefs)103base::FilePath SpeechRecognitionService::GetSodaConfigPath(PrefService* prefs) { 104 speech::LanguageCode language = speech::GetLanguageCode( 105 prefs->GetString(prefs::kLiveCaptionLanguageCode)); 106 PrefService* global_prefs = g_browser_process->local_state(); 107 switch (language) { 108 case speech::LanguageCode::kNone: 109 NOTREACHED(); 110 return base::FilePath(); 111 case speech::LanguageCode::kEnUs: 112 return global_prefs->GetFilePath(prefs::kSodaEnUsConfigPath); 113 case speech::LanguageCode::kJaJp: 114 return global_prefs->GetFilePath(prefs::kSodaJaJpConfigPath); 115 } 116 117 return base::FilePath(); 118 } 119 } // namespace speech 120