mirror of
https://forge.fsky.io/oneflux/omegafox.git
synced 2026-02-10 21:12:04 -08:00
feat: Voice spoofing
- Added `voices` parameter, which takes a list maps for each voice to add. Example:
`[ {"isLocalService": true, "isDefault": true, "voiceUri": "Ting-Ting", "name": "Ting-Ting", "lang": "zh-CN" } ... ]`
- Added `voices:blockIfNotDefined` has been added to block system voices
- Added `voices:fakeCompletion: bool` and `voices:fakeCompletion:charsPerSecond: double` to set a fake playback speed.
This commit is contained in:
parent
30001a4507
commit
74d016e9a9
3 changed files with 120 additions and 0 deletions
|
|
@ -283,4 +283,30 @@ inline std::optional<std::array<int32_t, 3UL>> MShaderData(
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline std::optional<
|
||||||
|
std::vector<std::tuple<std::string, std::string, std::string, bool, bool>>>
|
||||||
|
MVoices() {
|
||||||
|
auto data = GetJson();
|
||||||
|
if (!data.contains("voices") || !data["voices"].is_array()) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<std::tuple<std::string, std::string, std::string, bool, bool>>
|
||||||
|
voices;
|
||||||
|
for (const auto& voice : data["voices"]) {
|
||||||
|
// Check if voice has all required fields
|
||||||
|
if (!voice.contains("lang") || !voice.contains("name") ||
|
||||||
|
!voice.contains("voiceUri") || !voice.contains("isDefault") ||
|
||||||
|
!voice.contains("isLocalService")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
voices.emplace_back(
|
||||||
|
voice["lang"].get<std::string>(), voice["name"].get<std::string>(),
|
||||||
|
voice["voiceUri"].get<std::string>(), voice["isDefault"].get<bool>(),
|
||||||
|
voice["isLocalService"].get<bool>());
|
||||||
|
}
|
||||||
|
return voices;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace MaskConfig
|
} // namespace MaskConfig
|
||||||
90
patches/voice-spoofing.patch
Normal file
90
patches/voice-spoofing.patch
Normal file
|
|
@ -0,0 +1,90 @@
|
||||||
|
diff --git a/dom/media/webspeech/synth/moz.build b/dom/media/webspeech/synth/moz.build
|
||||||
|
index 2cf19982b2..dcdcdb5cbf 100644
|
||||||
|
--- a/dom/media/webspeech/synth/moz.build
|
||||||
|
+++ b/dom/media/webspeech/synth/moz.build
|
||||||
|
@@ -63,3 +63,6 @@ FINAL_LIBRARY = "xul"
|
||||||
|
LOCAL_INCLUDES += [
|
||||||
|
"ipc",
|
||||||
|
]
|
||||||
|
+
|
||||||
|
+# DOM Mask
|
||||||
|
+LOCAL_INCLUDES += ['/camoucfg']
|
||||||
|
\ No newline at end of file
|
||||||
|
diff --git a/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp b/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp
|
||||||
|
index e5a1353d6b..4a4a5b080b 100644
|
||||||
|
--- a/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp
|
||||||
|
+++ b/dom/media/webspeech/synth/nsSynthVoiceRegistry.cpp
|
||||||
|
@@ -27,6 +27,7 @@
|
||||||
|
|
||||||
|
#include "SpeechSynthesisChild.h"
|
||||||
|
#include "SpeechSynthesisParent.h"
|
||||||
|
+#include "MaskConfig.hpp"
|
||||||
|
|
||||||
|
using mozilla::intl::LocaleService;
|
||||||
|
|
||||||
|
@@ -169,6 +170,20 @@ nsSynthVoiceRegistry* nsSynthVoiceRegistry::GetInstance() {
|
||||||
|
// Start up all speech synth services.
|
||||||
|
NS_CreateServicesFromCategory(NS_SPEECH_SYNTH_STARTED, nullptr,
|
||||||
|
NS_SPEECH_SYNTH_STARTED);
|
||||||
|
+ // Load voices from MaskConfig
|
||||||
|
+ if (auto voices = MaskConfig::MVoices()) {
|
||||||
|
+ for (const auto& [lang, name, uri, isDefault, isLocal] :
|
||||||
|
+ voices.value()) {
|
||||||
|
+ gSynthVoiceRegistry->AddVoiceImpl(
|
||||||
|
+ nullptr, NS_ConvertUTF8toUTF16(uri), NS_ConvertUTF8toUTF16(name),
|
||||||
|
+ NS_ConvertUTF8toUTF16(lang), isLocal,
|
||||||
|
+ false); // queuesUtterances set to false
|
||||||
|
+ if (isDefault) {
|
||||||
|
+ gSynthVoiceRegistry->SetDefaultVoice(NS_ConvertUTF8toUTF16(uri),
|
||||||
|
+ true);
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@@ -305,6 +320,8 @@ nsSynthVoiceRegistry::AddVoice(nsISpeechService* aService,
|
||||||
|
return NS_ERROR_NOT_AVAILABLE;
|
||||||
|
}
|
||||||
|
|
||||||
|
+ if (MaskConfig::GetBool("voices:blockIfNotDefined")) return NS_OK;
|
||||||
|
+
|
||||||
|
return AddVoiceImpl(aService, aUri, aName, aLang, aLocalService,
|
||||||
|
aQueuesUtterances);
|
||||||
|
}
|
||||||
|
@@ -779,6 +796,35 @@ void nsSynthVoiceRegistry::SpeakImpl(VoiceData* aVoice, nsSpeechTask* aTask,
|
||||||
|
NS_ConvertUTF16toUTF8(aText).get(),
|
||||||
|
NS_ConvertUTF16toUTF8(aVoice->mUri).get(), aRate, aPitch));
|
||||||
|
|
||||||
|
+ // Check if this voice is in our MVoices config
|
||||||
|
+ if (auto voices = MaskConfig::MVoices()) {
|
||||||
|
+ for (const auto& [lang, name, uri, isDefault, isLocal] : voices.value()) {
|
||||||
|
+ if (NS_ConvertUTF8toUTF16(uri).Equals(aVoice->mUri)) {
|
||||||
|
+ printf_stderr("Tried to speak a fake voice: %s",
|
||||||
|
+ NS_ConvertUTF16toUTF8(aVoice->mUri).get());
|
||||||
|
+ aTask->Init();
|
||||||
|
+ // If fake completion is disabled, throw an error
|
||||||
|
+ if (!MaskConfig::GetBool("voices:fakeCompletion")) {
|
||||||
|
+ aTask->DispatchError(0, 0);
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ float charsPerSecond;
|
||||||
|
+ if (auto value =
|
||||||
|
+ MaskConfig::GetDouble("voices:fakeCompletion:charsPerSecond")) {
|
||||||
|
+ charsPerSecond = value.value();
|
||||||
|
+ } else {
|
||||||
|
+ charsPerSecond = 12.5f;
|
||||||
|
+ }
|
||||||
|
+ // Return a fake success with a speach rate of 150wpm
|
||||||
|
+ aTask->DispatchStart();
|
||||||
|
+ float fakeElapsedTime =
|
||||||
|
+ static_cast<float>(aText.Length()) / (charsPerSecond * aRate);
|
||||||
|
+ aTask->DispatchEnd(fakeElapsedTime, aText.Length());
|
||||||
|
+ return;
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+ }
|
||||||
|
+
|
||||||
|
aTask->Init();
|
||||||
|
|
||||||
|
if (NS_FAILED(aVoice->mService->Speak(aText, aVoice->mUri, aVolume, aRate,
|
||||||
|
|
@ -83,6 +83,10 @@
|
||||||
{ "property": "webGl2:shaderPrecisionFormats:blockIfNotDefined", "type": "bool" },
|
{ "property": "webGl2:shaderPrecisionFormats:blockIfNotDefined", "type": "bool" },
|
||||||
{ "property": "webGl:contextAttributes", "type": "dict" },
|
{ "property": "webGl:contextAttributes", "type": "dict" },
|
||||||
{ "property": "webGl2:contextAttributes", "type": "dict" },
|
{ "property": "webGl2:contextAttributes", "type": "dict" },
|
||||||
|
{ "property": "voices", "type": "array" },
|
||||||
|
{ "property": "voices:blockIfNotDefined", "type": "bool" },
|
||||||
|
{ "property": "voices:fakeCompletion", "type": "bool" },
|
||||||
|
{ "property": "voices:fakeCompletion:charsPerSecond", "type": "double" },
|
||||||
{ "property": "memorysaver", "type": "bool" },
|
{ "property": "memorysaver", "type": "bool" },
|
||||||
{ "property": "debug", "type": "bool" }
|
{ "property": "debug", "type": "bool" }
|
||||||
]
|
]
|
||||||
Loading…
Add table
Reference in a new issue