Bug 1188099 - (Part 1) Enable/disable global queue depending on voices and pref. r=smaug r=kdavis

This commit is contained in:
Eitan Isaacson 2015-08-08 10:30:46 -07:00
parent c20e0ea95d
commit 1871cc4124
7 changed files with 65 additions and 24 deletions

View File

@ -15,6 +15,7 @@ struct RemoteVoice {
nsString name;
nsString lang;
bool localService;
bool queued;
};
sync protocol PSpeechSynthesis

View File

@ -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.

View File

@ -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);

View File

@ -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

View File

@ -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;

View File

@ -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);
}

View File

@ -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;