mirror of
https://github.com/mozilla/gecko-dev.git
synced 2024-10-23 18:26:15 +00:00
Bug 1188099 - (Part 1) Enable/disable global queue depending on voices and pref. r=smaug r=kdavis
This commit is contained in:
parent
9f892563ed
commit
78b76a01ef
@ -15,6 +15,7 @@ struct RemoteVoice {
|
||||
nsString name;
|
||||
nsString lang;
|
||||
bool localService;
|
||||
bool queued;
|
||||
};
|
||||
|
||||
sync protocol PSpeechSynthesis
|
||||
|
@ -7,21 +7,22 @@
|
||||
|
||||
interface nsISpeechService;
|
||||
|
||||
[scriptable, builtinclass, uuid(53dcc868-4193-4c3c-a1d9-fe5a0a6af2fb)]
|
||||
[scriptable, builtinclass, uuid(dac09c3a-156e-4025-a4ab-bc88b0ea92e7)]
|
||||
interface nsISynthVoiceRegistry : nsISupports
|
||||
{
|
||||
/**
|
||||
* Register a speech synthesis voice.
|
||||
*
|
||||
* @param aService the service that provides this voice.
|
||||
* @param aUri a unique identifier for this voice.
|
||||
* @param aName human-readable name for this voice.
|
||||
* @param aLang a BCP 47 language tag.
|
||||
* @param aLocalService true if service does not require network.
|
||||
* @param aService the service that provides this voice.
|
||||
* @param aUri a unique identifier for this voice.
|
||||
* @param aName human-readable name for this voice.
|
||||
* @param aLang a BCP 47 language tag.
|
||||
* @param aLocalService true if service does not require network.
|
||||
* @param aQueuesUtterances true if voice only speaks one utterance at a time
|
||||
*/
|
||||
void addVoice(in nsISpeechService aService, in DOMString aUri,
|
||||
in DOMString aName, in DOMString aLang,
|
||||
in boolean aLocalService);
|
||||
in boolean aLocalService, in boolean aQueuesUtterances);
|
||||
|
||||
/**
|
||||
* Remove a speech synthesis voice.
|
||||
|
@ -17,6 +17,7 @@
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/dom/ContentChild.h"
|
||||
#include "mozilla/dom/ContentParent.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/unused.h"
|
||||
|
||||
#include "SpeechSynthesisChild.h"
|
||||
@ -72,12 +73,14 @@ private:
|
||||
|
||||
public:
|
||||
VoiceData(nsISpeechService* aService, const nsAString& aUri,
|
||||
const nsAString& aName, const nsAString& aLang, bool aIsLocal)
|
||||
const nsAString& aName, const nsAString& aLang,
|
||||
bool aIsLocal, bool aQueuesUtterances)
|
||||
: mService(aService)
|
||||
, mUri(aUri)
|
||||
, mName(aName)
|
||||
, mLang(aLang)
|
||||
, mIsLocal(aIsLocal) {}
|
||||
, mIsLocal(aIsLocal)
|
||||
, mIsQueued(aQueuesUtterances) {}
|
||||
|
||||
NS_INLINE_DECL_REFCOUNTING(VoiceData)
|
||||
|
||||
@ -90,16 +93,20 @@ public:
|
||||
nsString mLang;
|
||||
|
||||
bool mIsLocal;
|
||||
|
||||
bool mIsQueued;
|
||||
};
|
||||
|
||||
// nsSynthVoiceRegistry
|
||||
|
||||
static StaticRefPtr<nsSynthVoiceRegistry> gSynthVoiceRegistry;
|
||||
static bool sForceGlobalQueue = false;
|
||||
|
||||
NS_IMPL_ISUPPORTS(nsSynthVoiceRegistry, nsISynthVoiceRegistry)
|
||||
|
||||
nsSynthVoiceRegistry::nsSynthVoiceRegistry()
|
||||
: mSpeechSynthChild(nullptr)
|
||||
, mUseGlobalQueue(false)
|
||||
{
|
||||
if (XRE_IsContentProcess()) {
|
||||
|
||||
@ -115,7 +122,7 @@ nsSynthVoiceRegistry::nsSynthVoiceRegistry()
|
||||
RemoteVoice voice = voices[i];
|
||||
AddVoiceImpl(nullptr, voice.voiceURI(),
|
||||
voice.name(), voice.lang(),
|
||||
voice.localService());
|
||||
voice.localService(), voice.queued());
|
||||
}
|
||||
|
||||
for (uint32_t i = 0; i < defaults.Length(); ++i) {
|
||||
@ -149,6 +156,8 @@ nsSynthVoiceRegistry::GetInstance()
|
||||
|
||||
if (!gSynthVoiceRegistry) {
|
||||
gSynthVoiceRegistry = new nsSynthVoiceRegistry();
|
||||
Preferences::AddBoolVarCache(&sForceGlobalQueue,
|
||||
"media.webspeech.synth.force_global_queue");
|
||||
}
|
||||
|
||||
return gSynthVoiceRegistry;
|
||||
@ -178,7 +187,7 @@ nsSynthVoiceRegistry::SendVoices(InfallibleTArray<RemoteVoice>* aVoices,
|
||||
nsRefPtr<VoiceData> voice = mVoices[i];
|
||||
|
||||
aVoices->AppendElement(RemoteVoice(voice->mUri, voice->mName, voice->mLang,
|
||||
voice->mIsLocal));
|
||||
voice->mIsLocal, voice->mIsQueued));
|
||||
}
|
||||
|
||||
for (uint32_t i=0; i < mDefaultVoices.Length(); ++i) {
|
||||
@ -209,7 +218,7 @@ nsSynthVoiceRegistry::RecvAddVoice(const RemoteVoice& aVoice)
|
||||
|
||||
gSynthVoiceRegistry->AddVoiceImpl(nullptr, aVoice.voiceURI(),
|
||||
aVoice.name(), aVoice.lang(),
|
||||
aVoice.localService());
|
||||
aVoice.localService(), aVoice.queued());
|
||||
}
|
||||
|
||||
void
|
||||
@ -229,20 +238,21 @@ nsSynthVoiceRegistry::AddVoice(nsISpeechService* aService,
|
||||
const nsAString& aUri,
|
||||
const nsAString& aName,
|
||||
const nsAString& aLang,
|
||||
bool aLocalService)
|
||||
bool aLocalService,
|
||||
bool aQueuesUtterances)
|
||||
{
|
||||
LOG(LogLevel::Debug,
|
||||
("nsSynthVoiceRegistry::AddVoice uri='%s' name='%s' lang='%s' local=%s",
|
||||
("nsSynthVoiceRegistry::AddVoice uri='%s' name='%s' lang='%s' local=%s queued=%s",
|
||||
NS_ConvertUTF16toUTF8(aUri).get(), NS_ConvertUTF16toUTF8(aName).get(),
|
||||
NS_ConvertUTF16toUTF8(aLang).get(),
|
||||
aLocalService ? "true" : "false"));
|
||||
aLocalService ? "true" : "false",
|
||||
aQueuesUtterances ? "true" : "false"));
|
||||
|
||||
if(NS_WARN_IF(XRE_IsContentProcess())) {
|
||||
return NS_ERROR_NOT_AVAILABLE;
|
||||
}
|
||||
|
||||
return AddVoiceImpl(aService, aUri, aName, aLang,
|
||||
aLocalService);
|
||||
return AddVoiceImpl(aService, aUri, aName, aLang, aLocalService, aQueuesUtterances);
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
@ -268,6 +278,22 @@ nsSynthVoiceRegistry::RemoveVoice(nsISpeechService* aService,
|
||||
mDefaultVoices.RemoveElement(retval);
|
||||
mUriVoiceMap.Remove(aUri);
|
||||
|
||||
if (retval->mIsQueued && !sForceGlobalQueue) {
|
||||
// Check if this is the last queued voice, and disable the global queue if
|
||||
// it is.
|
||||
bool queued = false;
|
||||
for (uint32_t i = 0; i < mVoices.Length(); i++) {
|
||||
VoiceData* voice = mVoices[i];
|
||||
if (voice->mIsQueued) {
|
||||
queued = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!queued) {
|
||||
mUseGlobalQueue = false;
|
||||
}
|
||||
}
|
||||
|
||||
nsTArray<SpeechSynthesisParent*> ssplist;
|
||||
GetAllSpeechSynthActors(ssplist);
|
||||
|
||||
@ -395,7 +421,8 @@ nsSynthVoiceRegistry::AddVoiceImpl(nsISpeechService* aService,
|
||||
const nsAString& aUri,
|
||||
const nsAString& aName,
|
||||
const nsAString& aLang,
|
||||
bool aLocalService)
|
||||
bool aLocalService,
|
||||
bool aQueuesUtterances)
|
||||
{
|
||||
bool found = false;
|
||||
mUriVoiceMap.GetWeak(aUri, &found);
|
||||
@ -404,10 +431,11 @@ nsSynthVoiceRegistry::AddVoiceImpl(nsISpeechService* aService,
|
||||
}
|
||||
|
||||
nsRefPtr<VoiceData> voice = new VoiceData(aService, aUri, aName, aLang,
|
||||
aLocalService);
|
||||
aLocalService, aQueuesUtterances);
|
||||
|
||||
mVoices.AppendElement(voice);
|
||||
mUriVoiceMap.Put(aUri, voice);
|
||||
mUseGlobalQueue |= aQueuesUtterances;
|
||||
|
||||
nsTArray<SpeechSynthesisParent*> ssplist;
|
||||
GetAllSpeechSynthActors(ssplist);
|
||||
@ -416,7 +444,8 @@ nsSynthVoiceRegistry::AddVoiceImpl(nsISpeechService* aService,
|
||||
mozilla::dom::RemoteVoice ssvoice(nsString(aUri),
|
||||
nsString(aName),
|
||||
nsString(aLang),
|
||||
aLocalService);
|
||||
aLocalService,
|
||||
aQueuesUtterances);
|
||||
|
||||
for (uint32_t i = 0; i < ssplist.Length(); ++i) {
|
||||
unused << ssplist[i]->SendVoiceAdded(ssvoice);
|
||||
|
@ -65,7 +65,8 @@ private:
|
||||
const nsAString& aUri,
|
||||
const nsAString& aName,
|
||||
const nsAString& aLang,
|
||||
bool aLocalService);
|
||||
bool aLocalService,
|
||||
bool aQueuesUtterances);
|
||||
|
||||
nsTArray<nsRefPtr<VoiceData> > mVoices;
|
||||
|
||||
@ -76,6 +77,8 @@ private:
|
||||
SpeechSynthesisChild* mSpeechSynthChild;
|
||||
|
||||
nsRefPtr<ProcessedMediaStream> mStream;
|
||||
|
||||
bool mUseGlobalQueue;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
@ -519,9 +519,11 @@ PicoAddVoiceTraverser(const nsAString& aUri,
|
||||
name.AssignLiteral("Pico ");
|
||||
name.Append(aVoice->mLanguage);
|
||||
|
||||
// This service is multi-threaded and can handle more than one utterance at a
|
||||
// time before previous utterances end. So, aQueuesUtterances == false
|
||||
DebugOnly<nsresult> rv =
|
||||
data->mRegistry->AddVoice(
|
||||
data->mService, aUri, name, aVoice->mLanguage, true);
|
||||
data->mService, aUri, name, aVoice->mLanguage, true, false);
|
||||
NS_WARN_IF_FALSE(NS_SUCCEEDED(rv), "Failed to add voice");
|
||||
|
||||
return PL_DHASH_NEXT;
|
||||
|
@ -287,7 +287,9 @@ AddVoices(nsISpeechService* aService, const VoiceDetails* aVoices, uint32_t aLen
|
||||
NS_ConvertUTF8toUTF16 name(aVoices[i].name);
|
||||
NS_ConvertUTF8toUTF16 uri(aVoices[i].uri);
|
||||
NS_ConvertUTF8toUTF16 lang(aVoices[i].lang);
|
||||
registry->AddVoice(aService, uri, name, lang, true);
|
||||
// These services can handle more than one utterance at a time and have
|
||||
// several speaking simultaniously. So, aQueuesUtterances == false
|
||||
registry->AddVoice(aService, uri, name, lang, true, false);
|
||||
if (aVoices[i].defaultVoice) {
|
||||
registry->SetDefaultVoice(uri, true);
|
||||
}
|
||||
|
@ -278,8 +278,11 @@ SapiService::RegisterVoices()
|
||||
uri.AppendLiteral("?");
|
||||
uri.Append(locale);
|
||||
|
||||
// This service can only speak one utterance at a time, se we set
|
||||
// aQueuesUtterances to true in order to track global state and schedule
|
||||
// access to this service.
|
||||
rv = registry->AddVoice(this, uri, nsDependentString(description), locale,
|
||||
true);
|
||||
true, true);
|
||||
CoTaskMemFree(description);
|
||||
if (NS_FAILED(rv)) {
|
||||
continue;
|
||||
|
Loading…
Reference in New Issue
Block a user