1 // Copyright 2014 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/tts_controller_delegate_impl.h"
6
7 #include <stddef.h>
8
9 #include <string>
10
11 #include "base/json/json_reader.h"
12 #include "base/values.h"
13 #include "build/build_config.h"
14 #include "chrome/browser/browser_process.h"
15 #include "chrome/browser/profiles/profile.h"
16 #include "chrome/common/pref_names.h"
17 #include "components/prefs/pref_service.h"
18 #include "content/public/browser/tts_controller.h"
19 #include "third_party/blink/public/mojom/speech/speech_synthesis.mojom.h"
20 #include "ui/base/l10n/l10n_util.h"
21
22 namespace {
23
24 base::Optional<content::TtsControllerDelegate::PreferredVoiceId>
PreferredVoiceIdFromString(const base::DictionaryValue * pref,const std::string & pref_key)25 PreferredVoiceIdFromString(const base::DictionaryValue* pref,
26 const std::string& pref_key) {
27 std::string voice_id;
28 pref->GetString(l10n_util::GetLanguage(pref_key), &voice_id);
29 if (voice_id.empty())
30 return base::nullopt;
31
32 std::unique_ptr<base::DictionaryValue> json =
33 base::DictionaryValue::From(base::JSONReader::ReadDeprecated(voice_id));
34 std::string name;
35 std::string id;
36 json->GetString("name", &name);
37 json->GetString("extension", &id);
38 return base::Optional<content::TtsControllerDelegate::PreferredVoiceId>(
39 {name, id});
40 }
41
42 } // namespace
43
44 //
45 // TtsControllerDelegateImpl
46 //
47
48 // static
GetInstance()49 TtsControllerDelegateImpl* TtsControllerDelegateImpl::GetInstance() {
50 return base::Singleton<TtsControllerDelegateImpl>::get();
51 }
52
53 TtsControllerDelegateImpl::TtsControllerDelegateImpl() = default;
54
55 TtsControllerDelegateImpl::~TtsControllerDelegateImpl() = default;
56
57 std::unique_ptr<content::TtsControllerDelegate::PreferredVoiceIds>
GetPreferredVoiceIdsForUtterance(content::TtsUtterance * utterance)58 TtsControllerDelegateImpl::GetPreferredVoiceIdsForUtterance(
59 content::TtsUtterance* utterance) {
60 const base::DictionaryValue* lang_to_voice_pref =
61 GetLangToVoicePref(utterance);
62 if (!lang_to_voice_pref)
63 return nullptr;
64
65 std::unique_ptr<PreferredVoiceIds> preferred_ids =
66 std::make_unique<PreferredVoiceIds>();
67
68 if (!utterance->GetLang().empty()) {
69 preferred_ids->lang_voice_id = PreferredVoiceIdFromString(
70 lang_to_voice_pref, l10n_util::GetLanguage(utterance->GetLang()));
71 }
72
73 const std::string app_lang = g_browser_process->GetApplicationLocale();
74 preferred_ids->locale_voice_id = PreferredVoiceIdFromString(
75 lang_to_voice_pref, l10n_util::GetLanguage(app_lang));
76
77 preferred_ids->any_locale_voice_id =
78 PreferredVoiceIdFromString(lang_to_voice_pref, "noLanguageCode");
79 return preferred_ids;
80 }
81
UpdateUtteranceDefaultsFromPrefs(content::TtsUtterance * utterance,double * rate,double * pitch,double * volume)82 void TtsControllerDelegateImpl::UpdateUtteranceDefaultsFromPrefs(
83 content::TtsUtterance* utterance,
84 double* rate,
85 double* pitch,
86 double* volume) {
87 // Update pitch, rate and volume from user prefs if not set explicitly
88 // on this utterance.
89 const PrefService* prefs = GetPrefService(utterance);
90 if (*rate == blink::mojom::kSpeechSynthesisDoublePrefNotSet) {
91 *rate = prefs ? prefs->GetDouble(prefs::kTextToSpeechRate)
92 : blink::mojom::kSpeechSynthesisDefaultRate;
93 }
94 if (*pitch == blink::mojom::kSpeechSynthesisDoublePrefNotSet) {
95 *pitch = prefs ? prefs->GetDouble(prefs::kTextToSpeechPitch)
96 : blink::mojom::kSpeechSynthesisDefaultPitch;
97 }
98 if (*volume == blink::mojom::kSpeechSynthesisDoublePrefNotSet) {
99 *volume = prefs ? prefs->GetDouble(prefs::kTextToSpeechVolume)
100 : blink::mojom::kSpeechSynthesisDefaultVolume;
101 }
102 }
103
GetPrefService(content::TtsUtterance * utterance)104 const PrefService* TtsControllerDelegateImpl::GetPrefService(
105 content::TtsUtterance* utterance) {
106 // The utterance->GetBrowserContext() is null in tests.
107 if (!utterance->GetBrowserContext())
108 return nullptr;
109
110 const Profile* profile =
111 Profile::FromBrowserContext(utterance->GetBrowserContext());
112 return profile ? profile->GetPrefs() : nullptr;
113 }
114
GetLangToVoicePref(content::TtsUtterance * utterance)115 const base::DictionaryValue* TtsControllerDelegateImpl::GetLangToVoicePref(
116 content::TtsUtterance* utterance) {
117 const PrefService* prefs = GetPrefService(utterance);
118 return prefs == nullptr
119 ? nullptr
120 : prefs->GetDictionary(prefs::kTextToSpeechLangToVoiceName);
121 }
122