mirror of
https://forge.fsky.io/oneflux/omegafox.git
synced 2026-02-10 12:52:06 -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;
|
||||
}
|
||||
|
||||
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
|
||||
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": "webGl: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": "debug", "type": "bool" }
|
||||
]
|
||||
Loading…
Add table
Reference in a new issue