Remove pocketsphinx/speech recognition.
This commit is contained in:
parent
2d0a568f07
commit
b1b822ad39
|
@ -40,12 +40,6 @@ external_dirs += ['media/libwebp']
|
|||
if CONFIG['CPU_ARCH'] == 'arm':
|
||||
external_dirs += ['media/openmax_dl']
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
|
||||
external_dirs += [
|
||||
'media/sphinxbase',
|
||||
'media/pocketsphinx',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_FFVPX']:
|
||||
external_dirs += ['media/ffvpx']
|
||||
|
||||
|
|
|
@ -70,7 +70,6 @@ LOCAL_INCLUDES += [
|
|||
'/dom/html',
|
||||
'/dom/indexedDB',
|
||||
'/dom/media/webaudio',
|
||||
'/dom/media/webspeech/recognition',
|
||||
'/dom/svg',
|
||||
'/dom/workers',
|
||||
'/dom/xbl',
|
||||
|
|
|
@ -1,51 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SpeechRecognitionError.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
SpeechRecognitionError::SpeechRecognitionError(
|
||||
mozilla::dom::EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
WidgetEvent* aEvent)
|
||||
: Event(aOwner, aPresContext, aEvent)
|
||||
, mError()
|
||||
{
|
||||
}
|
||||
|
||||
SpeechRecognitionError::~SpeechRecognitionError() {}
|
||||
|
||||
already_AddRefed<SpeechRecognitionError>
|
||||
SpeechRecognitionError::Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const SpeechRecognitionErrorInit& aParam,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
nsCOMPtr<mozilla::dom::EventTarget> t = do_QueryInterface(aGlobal.GetAsSupports());
|
||||
RefPtr<SpeechRecognitionError> e = new SpeechRecognitionError(t, nullptr, nullptr);
|
||||
bool trusted = e->Init(t);
|
||||
e->InitSpeechRecognitionError(aType, aParam.mBubbles, aParam.mCancelable, aParam.mError, aParam.mMessage);
|
||||
e->SetTrusted(trusted);
|
||||
e->SetComposed(aParam.mComposed);
|
||||
return e.forget();
|
||||
}
|
||||
|
||||
void
|
||||
SpeechRecognitionError::InitSpeechRecognitionError(const nsAString& aType,
|
||||
bool aCanBubble,
|
||||
bool aCancelable,
|
||||
SpeechRecognitionErrorCode aError,
|
||||
const nsAString& aMessage)
|
||||
{
|
||||
Event::InitEvent(aType, aCanBubble, aCancelable);
|
||||
mError = aError;
|
||||
mMessage = aMessage;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,62 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef SpeechRecognitionError_h__
|
||||
#define SpeechRecognitionError_h__
|
||||
|
||||
#include "mozilla/dom/Event.h"
|
||||
#include "mozilla/dom/SpeechRecognitionErrorBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SpeechRecognitionError : public Event
|
||||
{
|
||||
public:
|
||||
SpeechRecognitionError(mozilla::dom::EventTarget* aOwner,
|
||||
nsPresContext* aPresContext,
|
||||
WidgetEvent* aEvent);
|
||||
virtual ~SpeechRecognitionError();
|
||||
|
||||
static already_AddRefed<SpeechRecognitionError>
|
||||
Constructor(const GlobalObject& aGlobal,
|
||||
const nsAString& aType,
|
||||
const SpeechRecognitionErrorInit& aParam,
|
||||
ErrorResult& aRv);
|
||||
|
||||
virtual JSObject* WrapObjectInternal(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override
|
||||
{
|
||||
return mozilla::dom::SpeechRecognitionErrorBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
GetMessage(nsAString& aString)
|
||||
{
|
||||
aString = mMessage;
|
||||
}
|
||||
|
||||
SpeechRecognitionErrorCode
|
||||
Error()
|
||||
{
|
||||
return mError;
|
||||
}
|
||||
|
||||
void
|
||||
InitSpeechRecognitionError(const nsAString& aType,
|
||||
bool aCanBubble,
|
||||
bool aCancelable,
|
||||
SpeechRecognitionErrorCode aError,
|
||||
const nsAString& aMessage);
|
||||
|
||||
protected:
|
||||
SpeechRecognitionErrorCode mError;
|
||||
nsString mMessage;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // SpeechRecognitionError_h__
|
|
@ -73,9 +73,6 @@ EXPORTS.mozilla.dom += [
|
|||
'XULCommandEvent.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH']:
|
||||
EXPORTS.mozilla.dom += ['SpeechRecognitionError.h']
|
||||
|
||||
SOURCES += [
|
||||
'AnimationEvent.cpp',
|
||||
'AsyncEventDispatcher.cpp',
|
||||
|
@ -127,9 +124,6 @@ SOURCES += [
|
|||
'XULCommandEvent.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH']:
|
||||
SOURCES += ['SpeechRecognitionError.cpp']
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
DIRS = ['synth']
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH']:
|
||||
DIRS += ['recognition']
|
||||
DIRS += ['synth']
|
||||
else:
|
||||
IPDL_SOURCES += [
|
||||
'synth/ipc/PSpeechSynthesis.ipdl',
|
||||
'synth/ipc/PSpeechSynthesisRequest.ipdl',
|
||||
]
|
||||
|
|
|
@ -1,357 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "nsXPCOMCIDInternal.h"
|
||||
#include "PocketSphinxSpeechRecognitionService.h"
|
||||
#include "nsIFile.h"
|
||||
#include "SpeechGrammar.h"
|
||||
#include "SpeechRecognition.h"
|
||||
#include "SpeechRecognitionAlternative.h"
|
||||
#include "SpeechRecognitionResult.h"
|
||||
#include "SpeechRecognitionResultList.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "MediaPrefs.h"
|
||||
#include "mozilla/Services.h"
|
||||
#include "nsDirectoryServiceDefs.h"
|
||||
#include "nsDirectoryServiceUtils.h"
|
||||
#include "nsMemory.h"
|
||||
|
||||
extern "C" {
|
||||
#include "pocketsphinx/pocketsphinx.h"
|
||||
#include "sphinxbase/logmath.h"
|
||||
#include "sphinxbase/sphinx_config.h"
|
||||
#include "sphinxbase/jsgf.h"
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace dom;
|
||||
|
||||
class DecodeResultTask : public Runnable
|
||||
{
|
||||
public:
|
||||
DecodeResultTask(const nsString& hypstring,
|
||||
float64 confidence,
|
||||
WeakPtr<dom::SpeechRecognition> recognition)
|
||||
: mResult(hypstring),
|
||||
mConfidence(confidence),
|
||||
mRecognition(recognition),
|
||||
mWorkerThread(do_GetCurrentThread())
|
||||
{
|
||||
MOZ_ASSERT(
|
||||
!NS_IsMainThread()); // This should be running on the worker thread
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread()); // This method is supposed to run on the main
|
||||
// thread!
|
||||
|
||||
// Declare javascript result events
|
||||
RefPtr<SpeechEvent> event = new SpeechEvent(
|
||||
mRecognition, SpeechRecognition::EVENT_RECOGNITIONSERVICE_FINAL_RESULT);
|
||||
SpeechRecognitionResultList* resultList =
|
||||
new SpeechRecognitionResultList(mRecognition);
|
||||
SpeechRecognitionResult* result = new SpeechRecognitionResult(mRecognition);
|
||||
if (0 < mRecognition->MaxAlternatives()) {
|
||||
SpeechRecognitionAlternative* alternative =
|
||||
new SpeechRecognitionAlternative(mRecognition);
|
||||
|
||||
alternative->mTranscript = mResult;
|
||||
alternative->mConfidence = mConfidence;
|
||||
|
||||
result->mItems.AppendElement(alternative);
|
||||
}
|
||||
resultList->mItems.AppendElement(result);
|
||||
|
||||
event->mRecognitionResultList = resultList;
|
||||
NS_DispatchToMainThread(event);
|
||||
|
||||
// If we don't destroy the thread when we're done with it, it will hang
|
||||
// around forever... bad!
|
||||
// But thread->Shutdown must be called from the main thread, not from the
|
||||
// thread itself.
|
||||
return mWorkerThread->Shutdown();
|
||||
}
|
||||
|
||||
private:
|
||||
nsString mResult;
|
||||
float64 mConfidence;
|
||||
WeakPtr<dom::SpeechRecognition> mRecognition;
|
||||
nsCOMPtr<nsIThread> mWorkerThread;
|
||||
};
|
||||
|
||||
class DecodeTask : public Runnable
|
||||
{
|
||||
public:
|
||||
DecodeTask(WeakPtr<dom::SpeechRecognition> recogntion,
|
||||
const nsTArray<int16_t>& audiovector, ps_decoder_t* ps)
|
||||
: mRecognition(recogntion), mAudiovector(audiovector), mPs(ps)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD
|
||||
Run() override
|
||||
{
|
||||
char const* hyp;
|
||||
int rv;
|
||||
int32 final;
|
||||
int32 logprob;
|
||||
float64 confidence;
|
||||
nsAutoCString hypoValue;
|
||||
|
||||
rv = ps_start_utt(mPs);
|
||||
rv = ps_process_raw(mPs, &mAudiovector[0], mAudiovector.Length(), FALSE,
|
||||
FALSE);
|
||||
|
||||
rv = ps_end_utt(mPs);
|
||||
confidence = 0;
|
||||
if (rv >= 0) {
|
||||
hyp = ps_get_hyp_final(mPs, &final);
|
||||
if (hyp && final) {
|
||||
logprob = ps_get_prob(mPs);
|
||||
confidence = logmath_exp(ps_get_logmath(mPs), logprob);
|
||||
hypoValue.Assign(hyp);
|
||||
}
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> resultrunnable =
|
||||
new DecodeResultTask(NS_ConvertUTF8toUTF16(hypoValue), confidence, mRecognition);
|
||||
return NS_DispatchToMainThread(resultrunnable);
|
||||
}
|
||||
|
||||
private:
|
||||
WeakPtr<dom::SpeechRecognition> mRecognition;
|
||||
nsTArray<int16_t> mAudiovector;
|
||||
ps_decoder_t* mPs;
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(PocketSphinxSpeechRecognitionService,
|
||||
nsISpeechRecognitionService, nsIObserver)
|
||||
|
||||
PocketSphinxSpeechRecognitionService::PocketSphinxSpeechRecognitionService()
|
||||
{
|
||||
mSpeexState = nullptr;
|
||||
|
||||
// get root folder
|
||||
nsCOMPtr<nsIFile> tmpFile;
|
||||
nsAutoString aStringAMPath; // am folder
|
||||
nsAutoString aStringDictPath; // dict folder
|
||||
|
||||
NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(tmpFile));
|
||||
#if defined(XP_WIN) // for some reason, on windows NS_GRE_DIR is not bin root,
|
||||
// but bin/browser
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING(".."));
|
||||
#endif
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING("models"));
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING("en-US"));
|
||||
tmpFile->GetPath(aStringAMPath);
|
||||
|
||||
NS_GetSpecialDirectory(NS_GRE_DIR, getter_AddRefs(tmpFile));
|
||||
#if defined(XP_WIN) // for some reason, on windows NS_GRE_DIR is not bin root,
|
||||
// but bin/browser
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING(".."));
|
||||
#endif
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING("models")); //
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING("dict")); //
|
||||
tmpFile->AppendRelativePath(NS_LITERAL_STRING("en-US.dic")); //
|
||||
tmpFile->GetPath(aStringDictPath);
|
||||
|
||||
// FOR B2G PATHS HARDCODED (APPEND /DATA ON THE BEGINING, FOR DESKTOP, ONLY
|
||||
// MODELS/ RELATIVE TO ROOT
|
||||
mPSConfig = cmd_ln_init(nullptr, ps_args(), TRUE, "-bestpath", "yes", "-hmm",
|
||||
ToNewUTF8String(aStringAMPath), // acoustic model
|
||||
"-dict", ToNewUTF8String(aStringDictPath), nullptr);
|
||||
if (mPSConfig == nullptr) {
|
||||
ISDecoderCreated = false;
|
||||
} else {
|
||||
mPSHandle = ps_init(mPSConfig);
|
||||
if (mPSHandle == nullptr) {
|
||||
ISDecoderCreated = false;
|
||||
} else {
|
||||
ISDecoderCreated = true;
|
||||
}
|
||||
}
|
||||
|
||||
ISGrammarCompiled = false;
|
||||
}
|
||||
|
||||
PocketSphinxSpeechRecognitionService::~PocketSphinxSpeechRecognitionService()
|
||||
{
|
||||
if (mPSConfig) {
|
||||
free(mPSConfig);
|
||||
}
|
||||
if (mPSHandle) {
|
||||
free(mPSHandle);
|
||||
}
|
||||
|
||||
mSpeexState = nullptr;
|
||||
}
|
||||
|
||||
// CALL START IN JS FALLS HERE
|
||||
NS_IMETHODIMP
|
||||
PocketSphinxSpeechRecognitionService::Initialize(
|
||||
WeakPtr<SpeechRecognition> aSpeechRecognition)
|
||||
{
|
||||
if (!ISDecoderCreated || !ISGrammarCompiled) {
|
||||
return NS_ERROR_NOT_INITIALIZED;
|
||||
} else {
|
||||
mAudioVector.Clear();
|
||||
|
||||
if (mSpeexState) {
|
||||
mSpeexState = nullptr;
|
||||
}
|
||||
|
||||
mRecognition = aSpeechRecognition;
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
obs->AddObserver(this, SPEECH_RECOGNITION_TEST_EVENT_REQUEST_TOPIC, false);
|
||||
obs->AddObserver(this, SPEECH_RECOGNITION_TEST_END_TOPIC, false);
|
||||
return NS_OK;
|
||||
}
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PocketSphinxSpeechRecognitionService::ProcessAudioSegment(
|
||||
AudioSegment* aAudioSegment, int32_t aSampleRate)
|
||||
{
|
||||
if (!mSpeexState) {
|
||||
mSpeexState = speex_resampler_init(1, aSampleRate, 16000,
|
||||
SPEEX_RESAMPLER_QUALITY_MAX, nullptr);
|
||||
}
|
||||
aAudioSegment->ResampleChunks(mSpeexState, aSampleRate, 16000);
|
||||
|
||||
AudioSegment::ChunkIterator iterator(*aAudioSegment);
|
||||
|
||||
while (!iterator.IsEnded()) {
|
||||
mozilla::AudioChunk& chunk = *(iterator);
|
||||
MOZ_ASSERT(chunk.mBuffer);
|
||||
const int16_t* buf = static_cast<const int16_t*>(chunk.mChannelData[0]);
|
||||
|
||||
for (int i = 0; i < iterator->mDuration; i++) {
|
||||
mAudioVector.AppendElement((int16_t)buf[i]);
|
||||
}
|
||||
iterator.Next();
|
||||
}
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PocketSphinxSpeechRecognitionService::SoundEnd()
|
||||
{
|
||||
speex_resampler_destroy(mSpeexState);
|
||||
mSpeexState = nullptr;
|
||||
|
||||
// To create a new thread, get the thread manager
|
||||
nsCOMPtr<nsIThreadManager> tm = do_GetService(NS_THREADMANAGER_CONTRACTID);
|
||||
nsCOMPtr<nsIThread> decodethread;
|
||||
nsresult rv = tm->NewThread(0, 0, getter_AddRefs(decodethread));
|
||||
if (NS_FAILED(rv)) {
|
||||
// In case of failure, call back immediately with an empty string which
|
||||
// indicates failure
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIRunnable> r =
|
||||
new DecodeTask(mRecognition, mAudioVector, mPSHandle);
|
||||
decodethread->Dispatch(r, nsIEventTarget::DISPATCH_NORMAL);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PocketSphinxSpeechRecognitionService::ValidateAndSetGrammarList(
|
||||
SpeechGrammar* aSpeechGrammar,
|
||||
nsISpeechGrammarCompilationCallback* aCallback)
|
||||
{
|
||||
if (!ISDecoderCreated) {
|
||||
ISGrammarCompiled = false;
|
||||
} else if (aSpeechGrammar) {
|
||||
nsAutoString grammar;
|
||||
ErrorResult rv;
|
||||
aSpeechGrammar->GetSrc(grammar, rv);
|
||||
|
||||
int result = ps_set_jsgf_string(mPSHandle, "name",
|
||||
NS_ConvertUTF16toUTF8(grammar).get());
|
||||
|
||||
if (result != 0) {
|
||||
ISGrammarCompiled = false;
|
||||
} else {
|
||||
ps_set_search(mPSHandle, "name");
|
||||
|
||||
ISGrammarCompiled = true;
|
||||
}
|
||||
} else {
|
||||
ISGrammarCompiled = false;
|
||||
}
|
||||
|
||||
return ISGrammarCompiled ? NS_OK : NS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PocketSphinxSpeechRecognitionService::Abort()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
PocketSphinxSpeechRecognitionService::Observe(nsISupports* aSubject,
|
||||
const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
MOZ_ASSERT(MediaPrefs::WebSpeechFakeRecognitionService(),
|
||||
"Got request to fake recognition service event, "
|
||||
"but " TEST_PREFERENCE_FAKE_RECOGNITION_SERVICE " is not set");
|
||||
|
||||
if (!strcmp(aTopic, SPEECH_RECOGNITION_TEST_END_TOPIC)) {
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
obs->RemoveObserver(this, SPEECH_RECOGNITION_TEST_EVENT_REQUEST_TOPIC);
|
||||
obs->RemoveObserver(this, SPEECH_RECOGNITION_TEST_END_TOPIC);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsDependentString eventName = nsDependentString(aData);
|
||||
|
||||
if (eventName.EqualsLiteral("EVENT_RECOGNITIONSERVICE_ERROR")) {
|
||||
mRecognition->DispatchError(
|
||||
SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR,
|
||||
SpeechRecognitionErrorCode::Network, // TODO different codes?
|
||||
NS_LITERAL_STRING("RECOGNITIONSERVICE_ERROR test event"));
|
||||
|
||||
} else if (eventName.EqualsLiteral("EVENT_RECOGNITIONSERVICE_FINAL_RESULT")) {
|
||||
RefPtr<SpeechEvent> event = new SpeechEvent(
|
||||
mRecognition, SpeechRecognition::EVENT_RECOGNITIONSERVICE_FINAL_RESULT);
|
||||
|
||||
event->mRecognitionResultList = BuildMockResultList();
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SpeechRecognitionResultList*
|
||||
PocketSphinxSpeechRecognitionService::BuildMockResultList()
|
||||
{
|
||||
SpeechRecognitionResultList* resultList =
|
||||
new SpeechRecognitionResultList(mRecognition);
|
||||
SpeechRecognitionResult* result = new SpeechRecognitionResult(mRecognition);
|
||||
if (0 < mRecognition->MaxAlternatives()) {
|
||||
SpeechRecognitionAlternative* alternative =
|
||||
new SpeechRecognitionAlternative(mRecognition);
|
||||
|
||||
alternative->mTranscript = NS_LITERAL_STRING("Mock final result");
|
||||
alternative->mConfidence = 0.0f;
|
||||
|
||||
result->mItems.AppendElement(alternative);
|
||||
}
|
||||
resultList->mItems.AppendElement(result);
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -1,85 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_PocketSphinxRecognitionService_h
|
||||
#define mozilla_dom_PocketSphinxRecognitionService_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsISpeechRecognitionService.h"
|
||||
#include "speex/speex_resampler.h"
|
||||
|
||||
extern "C" {
|
||||
#include <pocketsphinx/pocketsphinx.h>
|
||||
#include <sphinxbase/sphinx_config.h>
|
||||
}
|
||||
|
||||
#define NS_POCKETSPHINX_SPEECH_RECOGNITION_SERVICE_CID \
|
||||
{ \
|
||||
0x0ff5ce56, 0x5b09, 0x4db8, { \
|
||||
0xad, 0xc6, 0x82, 0x66, 0xaf, 0x95, 0xf8, 0x64 \
|
||||
} \
|
||||
};
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
/**
|
||||
* Pocketsphix implementation of the nsISpeechRecognitionService interface
|
||||
*/
|
||||
class PocketSphinxSpeechRecognitionService : public nsISpeechRecognitionService,
|
||||
public nsIObserver
|
||||
{
|
||||
public:
|
||||
// Add XPCOM glue code
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISPEECHRECOGNITIONSERVICE
|
||||
|
||||
// Add nsIObserver code
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
/**
|
||||
* Default constructs a PocketSphinxSpeechRecognitionService loading default
|
||||
* files
|
||||
*/
|
||||
PocketSphinxSpeechRecognitionService();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Private destructor to prevent bypassing of reference counting
|
||||
*/
|
||||
virtual ~PocketSphinxSpeechRecognitionService();
|
||||
|
||||
/** The associated SpeechRecognition */
|
||||
WeakPtr<dom::SpeechRecognition> mRecognition;
|
||||
|
||||
/**
|
||||
* Builds a mock SpeechRecognitionResultList
|
||||
*/
|
||||
dom::SpeechRecognitionResultList* BuildMockResultList();
|
||||
|
||||
/** Speex state */
|
||||
SpeexResamplerState* mSpeexState;
|
||||
|
||||
/** Pocksphix decoder */
|
||||
ps_decoder_t* mPSHandle;
|
||||
|
||||
/** Sphinxbase parsed command line arguments */
|
||||
cmd_ln_t* mPSConfig;
|
||||
|
||||
/** Flag to verify if decoder was created */
|
||||
bool ISDecoderCreated;
|
||||
|
||||
/** Flag to verify if grammar was compiled */
|
||||
bool ISGrammarCompiled;
|
||||
|
||||
/** Audio data */
|
||||
nsTArray<int16_t> mAudioVector;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -1,81 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SpeechGrammar.h"
|
||||
|
||||
#include "mozilla/dom/SpeechGrammarBinding.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechGrammar, mParent)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechGrammar)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechGrammar)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechGrammar)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
SpeechGrammar::SpeechGrammar(nsISupports* aParent)
|
||||
: mParent(aParent)
|
||||
{
|
||||
}
|
||||
|
||||
SpeechGrammar::~SpeechGrammar()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<SpeechGrammar>
|
||||
SpeechGrammar::Constructor(const GlobalObject& aGlobal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<SpeechGrammar> speechGrammar =
|
||||
new SpeechGrammar(aGlobal.GetAsSupports());
|
||||
return speechGrammar.forget();
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
SpeechGrammar::GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
JSObject*
|
||||
SpeechGrammar::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return SpeechGrammarBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
void
|
||||
SpeechGrammar::GetSrc(nsString& aRetVal, ErrorResult& aRv) const
|
||||
{
|
||||
aRetVal = mSrc;
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
SpeechGrammar::SetSrc(const nsAString& aArg, ErrorResult& aRv)
|
||||
{
|
||||
mSrc = aArg;
|
||||
return;
|
||||
}
|
||||
|
||||
float
|
||||
SpeechGrammar::GetWeight(ErrorResult& aRv) const
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
SpeechGrammar::SetWeight(float aArg, ErrorResult& aRv)
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,59 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_SpeechGrammar_h
|
||||
#define mozilla_dom_SpeechGrammar_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsString.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class GlobalObject;
|
||||
|
||||
class SpeechGrammar final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
explicit SpeechGrammar(nsISupports* aParent);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SpeechGrammar)
|
||||
|
||||
nsISupports* GetParentObject() const;
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
static already_AddRefed<SpeechGrammar>
|
||||
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
|
||||
|
||||
void GetSrc(nsString& aRetVal, ErrorResult& aRv) const;
|
||||
|
||||
void SetSrc(const nsAString& aArg, ErrorResult& aRv);
|
||||
|
||||
float GetWeight(ErrorResult& aRv) const;
|
||||
|
||||
void SetWeight(float aArg, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
~SpeechGrammar();
|
||||
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
|
||||
nsString mSrc;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -1,104 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SpeechGrammarList.h"
|
||||
|
||||
#include "mozilla/dom/SpeechGrammarListBinding.h"
|
||||
#include "mozilla/ErrorResult.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsXPCOMStrings.h"
|
||||
#include "SpeechGrammar.h"
|
||||
#include "SpeechRecognition.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechGrammarList, mParent, mItems)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechGrammarList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechGrammarList)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechGrammarList)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
SpeechGrammarList::SpeechGrammarList(nsISupports* aParent)
|
||||
: mParent(aParent)
|
||||
{
|
||||
}
|
||||
|
||||
SpeechGrammarList::~SpeechGrammarList()
|
||||
{
|
||||
}
|
||||
|
||||
already_AddRefed<SpeechGrammarList>
|
||||
SpeechGrammarList::Constructor(const GlobalObject& aGlobal,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<SpeechGrammarList> speechGrammarList =
|
||||
new SpeechGrammarList(aGlobal.GetAsSupports());
|
||||
return speechGrammarList.forget();
|
||||
}
|
||||
|
||||
JSObject*
|
||||
SpeechGrammarList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return SpeechGrammarListBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
SpeechGrammarList::GetParentObject() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SpeechGrammarList::Length() const
|
||||
{
|
||||
return mItems.Length();
|
||||
}
|
||||
|
||||
already_AddRefed<SpeechGrammar>
|
||||
SpeechGrammarList::Item(uint32_t aIndex, ErrorResult& aRv)
|
||||
{
|
||||
RefPtr<SpeechGrammar> result = mItems.ElementAt(aIndex);
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
void
|
||||
SpeechGrammarList::AddFromURI(const nsAString& aSrc,
|
||||
const Optional<float>& aWeight,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
SpeechGrammarList::AddFromString(const nsAString& aString,
|
||||
const Optional<float>& aWeight,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
SpeechGrammar* speechGrammar = new SpeechGrammar(mParent);
|
||||
speechGrammar->SetSrc(aString, aRv);
|
||||
mItems.AppendElement(speechGrammar);
|
||||
return;
|
||||
}
|
||||
|
||||
already_AddRefed<SpeechGrammar>
|
||||
SpeechGrammarList::IndexedGetter(uint32_t aIndex, bool& aPresent,
|
||||
ErrorResult& aRv)
|
||||
{
|
||||
if (aIndex >= Length()) {
|
||||
aPresent = false;
|
||||
return nullptr;
|
||||
}
|
||||
ErrorResult rv;
|
||||
aPresent = true;
|
||||
return Item(aIndex, rv);
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,64 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_SpeechGrammarList_h
|
||||
#define mozilla_dom_SpeechGrammarList_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsTArray.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
|
||||
struct JSContext;
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class ErrorResult;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class GlobalObject;
|
||||
class SpeechGrammar;
|
||||
template<typename> class Optional;
|
||||
|
||||
class SpeechGrammarList final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
explicit SpeechGrammarList(nsISupports* aParent);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SpeechGrammarList)
|
||||
|
||||
static already_AddRefed<SpeechGrammarList> Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
|
||||
|
||||
nsISupports* GetParentObject() const;
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
uint32_t Length() const;
|
||||
|
||||
already_AddRefed<SpeechGrammar> Item(uint32_t aIndex, ErrorResult& aRv);
|
||||
|
||||
void AddFromURI(const nsAString& aSrc, const Optional<float>& aWeight, ErrorResult& aRv);
|
||||
|
||||
void AddFromString(const nsAString& aString, const Optional<float>& aWeight, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<SpeechGrammar> IndexedGetter(uint32_t aIndex, bool& aPresent, ErrorResult& aRv);
|
||||
|
||||
private:
|
||||
~SpeechGrammarList();
|
||||
|
||||
nsCOMPtr<nsISupports> mParent;
|
||||
|
||||
nsTArray<RefPtr<SpeechGrammar>> mItems;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
File diff suppressed because it is too large
Load Diff
|
@ -1,296 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_SpeechRecognition_h
|
||||
#define mozilla_dom_SpeechRecognition_h
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
#include "mozilla/DOMEventTargetHelper.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsString.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsTArray.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
#include "nsIDOMNavigatorUserMedia.h"
|
||||
#include "nsITimer.h"
|
||||
#include "MediaEngine.h"
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "AudioSegment.h"
|
||||
#include "mozilla/WeakPtr.h"
|
||||
|
||||
#include "SpeechGrammarList.h"
|
||||
#include "SpeechRecognitionResultList.h"
|
||||
#include "SpeechStreamListener.h"
|
||||
#include "nsISpeechRecognitionService.h"
|
||||
#include "endpointer.h"
|
||||
|
||||
#include "mozilla/dom/SpeechRecognitionError.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
namespace dom {
|
||||
|
||||
#define SPEECH_RECOGNITION_TEST_EVENT_REQUEST_TOPIC "SpeechRecognitionTest:RequestEvent"
|
||||
#define SPEECH_RECOGNITION_TEST_END_TOPIC "SpeechRecognitionTest:End"
|
||||
|
||||
class GlobalObject;
|
||||
class SpeechEvent;
|
||||
|
||||
LogModule* GetSpeechRecognitionLog();
|
||||
#define SR_LOG(...) MOZ_LOG(GetSpeechRecognitionLog(), mozilla::LogLevel::Debug, (__VA_ARGS__))
|
||||
|
||||
class SpeechRecognition final : public DOMEventTargetHelper,
|
||||
public nsIObserver,
|
||||
public SupportsWeakPtr<SpeechRecognition>
|
||||
{
|
||||
public:
|
||||
MOZ_DECLARE_WEAKREFERENCE_TYPENAME(SpeechRecognition)
|
||||
explicit SpeechRecognition(nsPIDOMWindowInner* aOwnerWindow);
|
||||
|
||||
NS_DECL_ISUPPORTS_INHERITED
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(SpeechRecognition, DOMEventTargetHelper)
|
||||
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsISupports* GetParentObject() const;
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
static bool IsAuthorized(JSContext* aCx, JSObject* aGlobal);
|
||||
|
||||
static already_AddRefed<SpeechRecognition>
|
||||
Constructor(const GlobalObject& aGlobal, ErrorResult& aRv);
|
||||
|
||||
already_AddRefed<SpeechGrammarList> Grammars() const;
|
||||
|
||||
void SetGrammars(mozilla::dom::SpeechGrammarList& aArg);
|
||||
|
||||
void GetLang(nsString& aRetVal) const;
|
||||
|
||||
void SetLang(const nsAString& aArg);
|
||||
|
||||
bool GetContinuous(ErrorResult& aRv) const;
|
||||
|
||||
void SetContinuous(bool aArg, ErrorResult& aRv);
|
||||
|
||||
bool InterimResults() const;
|
||||
|
||||
void SetInterimResults(bool aArg);
|
||||
|
||||
uint32_t MaxAlternatives() const;
|
||||
|
||||
void SetMaxAlternatives(uint32_t aArg);
|
||||
|
||||
void GetServiceURI(nsString& aRetVal, ErrorResult& aRv) const;
|
||||
|
||||
void SetServiceURI(const nsAString& aArg, ErrorResult& aRv);
|
||||
|
||||
void Start(const Optional<NonNull<DOMMediaStream>>& aStream, ErrorResult& aRv);
|
||||
|
||||
void Stop();
|
||||
|
||||
void Abort();
|
||||
|
||||
IMPL_EVENT_HANDLER(audiostart)
|
||||
IMPL_EVENT_HANDLER(soundstart)
|
||||
IMPL_EVENT_HANDLER(speechstart)
|
||||
IMPL_EVENT_HANDLER(speechend)
|
||||
IMPL_EVENT_HANDLER(soundend)
|
||||
IMPL_EVENT_HANDLER(audioend)
|
||||
IMPL_EVENT_HANDLER(result)
|
||||
IMPL_EVENT_HANDLER(nomatch)
|
||||
IMPL_EVENT_HANDLER(error)
|
||||
IMPL_EVENT_HANDLER(start)
|
||||
IMPL_EVENT_HANDLER(end)
|
||||
|
||||
enum EventType {
|
||||
EVENT_START,
|
||||
EVENT_STOP,
|
||||
EVENT_ABORT,
|
||||
EVENT_AUDIO_DATA,
|
||||
EVENT_AUDIO_ERROR,
|
||||
EVENT_RECOGNITIONSERVICE_INTERMEDIATE_RESULT,
|
||||
EVENT_RECOGNITIONSERVICE_FINAL_RESULT,
|
||||
EVENT_RECOGNITIONSERVICE_ERROR,
|
||||
EVENT_COUNT
|
||||
};
|
||||
|
||||
void DispatchError(EventType aErrorType, SpeechRecognitionErrorCode aErrorCode, const nsAString& aMessage);
|
||||
uint32_t FillSamplesBuffer(const int16_t* aSamples, uint32_t aSampleCount);
|
||||
uint32_t SplitSamplesBuffer(const int16_t* aSamplesBuffer, uint32_t aSampleCount, nsTArray<RefPtr<SharedBuffer>>& aResult);
|
||||
AudioSegment* CreateAudioSegment(nsTArray<RefPtr<SharedBuffer>>& aChunks);
|
||||
void FeedAudioData(already_AddRefed<SharedBuffer> aSamples, uint32_t aDuration, MediaStreamListener* aProvider, TrackRate aTrackRate);
|
||||
|
||||
friend class SpeechEvent;
|
||||
private:
|
||||
virtual ~SpeechRecognition() {};
|
||||
|
||||
enum FSMState {
|
||||
STATE_IDLE,
|
||||
STATE_STARTING,
|
||||
STATE_ESTIMATING,
|
||||
STATE_WAITING_FOR_SPEECH,
|
||||
STATE_RECOGNIZING,
|
||||
STATE_WAITING_FOR_RESULT,
|
||||
STATE_COUNT
|
||||
};
|
||||
|
||||
void SetState(FSMState state);
|
||||
bool StateBetween(FSMState begin, FSMState end);
|
||||
|
||||
bool SetRecognitionService(ErrorResult& aRv);
|
||||
bool ValidateAndSetGrammarList(ErrorResult& aRv);
|
||||
|
||||
class GetUserMediaSuccessCallback : public nsIDOMGetUserMediaSuccessCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMGETUSERMEDIASUCCESSCALLBACK
|
||||
|
||||
explicit GetUserMediaSuccessCallback(SpeechRecognition* aRecognition)
|
||||
: mRecognition(aRecognition)
|
||||
{}
|
||||
|
||||
private:
|
||||
virtual ~GetUserMediaSuccessCallback() {}
|
||||
|
||||
RefPtr<SpeechRecognition> mRecognition;
|
||||
};
|
||||
|
||||
class GetUserMediaErrorCallback : public nsIDOMGetUserMediaErrorCallback
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIDOMGETUSERMEDIAERRORCALLBACK
|
||||
|
||||
explicit GetUserMediaErrorCallback(SpeechRecognition* aRecognition)
|
||||
: mRecognition(aRecognition)
|
||||
{}
|
||||
|
||||
private:
|
||||
virtual ~GetUserMediaErrorCallback() {}
|
||||
|
||||
RefPtr<SpeechRecognition> mRecognition;
|
||||
};
|
||||
|
||||
NS_IMETHOD StartRecording(DOMMediaStream* aDOMStream);
|
||||
NS_IMETHOD StopRecording();
|
||||
|
||||
uint32_t ProcessAudioSegment(AudioSegment* aSegment, TrackRate aTrackRate);
|
||||
void NotifyError(SpeechEvent* aEvent);
|
||||
|
||||
void ProcessEvent(SpeechEvent* aEvent);
|
||||
void Transition(SpeechEvent* aEvent);
|
||||
|
||||
void Reset();
|
||||
void ResetAndEnd();
|
||||
void WaitForAudioData(SpeechEvent* aEvent);
|
||||
void StartedAudioCapture(SpeechEvent* aEvent);
|
||||
void StopRecordingAndRecognize(SpeechEvent* aEvent);
|
||||
void WaitForEstimation(SpeechEvent* aEvent);
|
||||
void DetectSpeech(SpeechEvent* aEvent);
|
||||
void WaitForSpeechEnd(SpeechEvent* aEvent);
|
||||
void NotifyFinalResult(SpeechEvent* aEvent);
|
||||
void DoNothing(SpeechEvent* aEvent);
|
||||
void AbortSilently(SpeechEvent* aEvent);
|
||||
void AbortError(SpeechEvent* aEvent);
|
||||
|
||||
RefPtr<DOMMediaStream> mDOMStream;
|
||||
RefPtr<SpeechStreamListener> mSpeechListener;
|
||||
nsCOMPtr<nsISpeechRecognitionService> mRecognitionService;
|
||||
|
||||
FSMState mCurrentState;
|
||||
|
||||
Endpointer mEndpointer;
|
||||
uint32_t mEstimationSamples;
|
||||
|
||||
uint32_t mAudioSamplesPerChunk;
|
||||
|
||||
// buffer holds one chunk of mAudioSamplesPerChunk
|
||||
// samples before feeding it to mEndpointer
|
||||
RefPtr<SharedBuffer> mAudioSamplesBuffer;
|
||||
uint32_t mBufferedSamples;
|
||||
|
||||
nsCOMPtr<nsITimer> mSpeechDetectionTimer;
|
||||
bool mAborted;
|
||||
|
||||
nsString mLang;
|
||||
|
||||
RefPtr<SpeechGrammarList> mSpeechGrammarList;
|
||||
|
||||
// WebSpeechAPI (http://bit.ly/1gIl7DC) states:
|
||||
//
|
||||
// 1. Default value MUST be false
|
||||
// 2. If true, interim results SHOULD be returned
|
||||
// 3. If false, interim results MUST NOT be returned
|
||||
//
|
||||
// Pocketsphinx does not return interm results; so, defaulting
|
||||
// mInterimResults to false, then ignoring its subsequent value
|
||||
// is a conforming implementation.
|
||||
bool mInterimResults;
|
||||
|
||||
// WebSpeechAPI (http://bit.ly/1JAiqeo) states:
|
||||
//
|
||||
// 1. Default value is 1
|
||||
// 2. Subsequent value is the "maximum number of SpeechRecognitionAlternatives per result"
|
||||
//
|
||||
// Pocketsphinx can only return at maximum a single SpeechRecognitionAlternative
|
||||
// per SpeechRecognitionResult. So defaulting mMaxAlternatives to 1, for all non
|
||||
// zero values ignoring mMaxAlternatives while for a 0 value returning no
|
||||
// SpeechRecognitionAlternative per result is a conforming implementation.
|
||||
uint32_t mMaxAlternatives;
|
||||
|
||||
void ProcessTestEventRequest(nsISupports* aSubject, const nsAString& aEventName);
|
||||
|
||||
const char* GetName(FSMState aId);
|
||||
const char* GetName(SpeechEvent* aId);
|
||||
};
|
||||
|
||||
class SpeechEvent : public Runnable
|
||||
{
|
||||
public:
|
||||
SpeechEvent(SpeechRecognition* aRecognition, SpeechRecognition::EventType aType)
|
||||
: mAudioSegment(0)
|
||||
, mRecognitionResultList(nullptr)
|
||||
, mError(nullptr)
|
||||
, mRecognition(aRecognition)
|
||||
, mType(aType)
|
||||
, mTrackRate(0)
|
||||
{
|
||||
}
|
||||
|
||||
~SpeechEvent();
|
||||
|
||||
NS_IMETHOD Run() override;
|
||||
AudioSegment* mAudioSegment;
|
||||
RefPtr<SpeechRecognitionResultList> mRecognitionResultList; // TODO: make this a session being passed which also has index and stuff
|
||||
RefPtr<SpeechRecognitionError> mError;
|
||||
|
||||
friend class SpeechRecognition;
|
||||
private:
|
||||
SpeechRecognition* mRecognition;
|
||||
|
||||
// for AUDIO_DATA events, keep a reference to the provider
|
||||
// of the data (i.e., the SpeechStreamListener) to ensure it
|
||||
// is kept alive (and keeps SpeechRecognition alive) until this
|
||||
// event gets processed.
|
||||
RefPtr<MediaStreamListener> mProvider;
|
||||
SpeechRecognition::EventType mType;
|
||||
TrackRate mTrackRate;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
|
||||
inline nsISupports*
|
||||
ToSupports(dom::SpeechRecognition* aRec)
|
||||
{
|
||||
return ToSupports(static_cast<DOMEventTargetHelper*>(aRec));
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -1,59 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SpeechRecognitionAlternative.h"
|
||||
|
||||
#include "mozilla/dom/SpeechRecognitionAlternativeBinding.h"
|
||||
|
||||
#include "SpeechRecognition.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechRecognitionAlternative, mParent)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechRecognitionAlternative)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechRecognitionAlternative)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechRecognitionAlternative)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
SpeechRecognitionAlternative::SpeechRecognitionAlternative(SpeechRecognition* aParent)
|
||||
: mConfidence(0)
|
||||
, mParent(aParent)
|
||||
{
|
||||
}
|
||||
|
||||
SpeechRecognitionAlternative::~SpeechRecognitionAlternative()
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
SpeechRecognitionAlternative::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return SpeechRecognitionAlternativeBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
SpeechRecognitionAlternative::GetParentObject() const
|
||||
{
|
||||
return static_cast<DOMEventTargetHelper*>(mParent.get());
|
||||
}
|
||||
|
||||
void
|
||||
SpeechRecognitionAlternative::GetTranscript(nsString& aRetVal) const
|
||||
{
|
||||
aRetVal = mTranscript;
|
||||
}
|
||||
|
||||
float
|
||||
SpeechRecognitionAlternative::Confidence() const
|
||||
{
|
||||
return mConfidence;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,50 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_SpeechRecognitionAlternative_h
|
||||
#define mozilla_dom_SpeechRecognitionAlternative_h
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsString.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SpeechRecognition;
|
||||
|
||||
class SpeechRecognitionAlternative final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
explicit SpeechRecognitionAlternative(SpeechRecognition* aParent);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SpeechRecognitionAlternative)
|
||||
|
||||
nsISupports* GetParentObject() const;
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
void GetTranscript(nsString& aRetVal) const;
|
||||
|
||||
float Confidence() const;
|
||||
|
||||
nsString mTranscript;
|
||||
float mConfidence;
|
||||
private:
|
||||
~SpeechRecognitionAlternative();
|
||||
|
||||
RefPtr<SpeechRecognition> mParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -1,76 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SpeechRecognitionResult.h"
|
||||
#include "mozilla/dom/SpeechRecognitionResultBinding.h"
|
||||
|
||||
#include "SpeechRecognition.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechRecognitionResult, mParent)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechRecognitionResult)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechRecognitionResult)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechRecognitionResult)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
SpeechRecognitionResult::SpeechRecognitionResult(SpeechRecognition* aParent)
|
||||
: mParent(aParent)
|
||||
{
|
||||
}
|
||||
|
||||
SpeechRecognitionResult::~SpeechRecognitionResult()
|
||||
{
|
||||
}
|
||||
|
||||
JSObject*
|
||||
SpeechRecognitionResult::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return SpeechRecognitionResultBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
SpeechRecognitionResult::GetParentObject() const
|
||||
{
|
||||
return static_cast<DOMEventTargetHelper*>(mParent.get());
|
||||
}
|
||||
|
||||
already_AddRefed<SpeechRecognitionAlternative>
|
||||
SpeechRecognitionResult::IndexedGetter(uint32_t aIndex, bool& aPresent)
|
||||
{
|
||||
if (aIndex >= Length()) {
|
||||
aPresent = false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aPresent = true;
|
||||
return Item(aIndex);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SpeechRecognitionResult::Length() const
|
||||
{
|
||||
return mItems.Length();
|
||||
}
|
||||
|
||||
already_AddRefed<SpeechRecognitionAlternative>
|
||||
SpeechRecognitionResult::Item(uint32_t aIndex)
|
||||
{
|
||||
RefPtr<SpeechRecognitionAlternative> alternative = mItems.ElementAt(aIndex);
|
||||
return alternative.forget();
|
||||
}
|
||||
|
||||
bool
|
||||
SpeechRecognitionResult::IsFinal() const
|
||||
{
|
||||
return true; // TODO
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,55 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_SpeechRecognitionResult_h
|
||||
#define mozilla_dom_SpeechRecognitionResult_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsTArray.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "SpeechRecognitionAlternative.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SpeechRecognitionResult final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
explicit SpeechRecognitionResult(SpeechRecognition* aParent);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SpeechRecognitionResult)
|
||||
|
||||
nsISupports* GetParentObject() const;
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
uint32_t Length() const;
|
||||
|
||||
already_AddRefed<SpeechRecognitionAlternative> Item(uint32_t aIndex);
|
||||
|
||||
bool IsFinal() const;
|
||||
|
||||
already_AddRefed<SpeechRecognitionAlternative> IndexedGetter(uint32_t aIndex, bool& aPresent);
|
||||
|
||||
nsTArray<RefPtr<SpeechRecognitionAlternative>> mItems;
|
||||
|
||||
private:
|
||||
~SpeechRecognitionResult();
|
||||
|
||||
RefPtr<SpeechRecognition> mParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -1,71 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SpeechRecognitionResultList.h"
|
||||
|
||||
#include "mozilla/dom/SpeechRecognitionResultListBinding.h"
|
||||
|
||||
#include "SpeechRecognition.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION_WRAPPERCACHE(SpeechRecognitionResultList, mParent, mItems)
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(SpeechRecognitionResultList)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(SpeechRecognitionResultList)
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(SpeechRecognitionResultList)
|
||||
NS_WRAPPERCACHE_INTERFACE_MAP_ENTRY
|
||||
NS_INTERFACE_MAP_ENTRY(nsISupports)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
SpeechRecognitionResultList::SpeechRecognitionResultList(SpeechRecognition* aParent)
|
||||
: mParent(aParent)
|
||||
{
|
||||
}
|
||||
|
||||
SpeechRecognitionResultList::~SpeechRecognitionResultList()
|
||||
{
|
||||
}
|
||||
|
||||
nsISupports*
|
||||
SpeechRecognitionResultList::GetParentObject() const
|
||||
{
|
||||
return static_cast<DOMEventTargetHelper*>(mParent.get());
|
||||
}
|
||||
|
||||
JSObject*
|
||||
SpeechRecognitionResultList::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
|
||||
{
|
||||
return SpeechRecognitionResultListBinding::Wrap(aCx, this, aGivenProto);
|
||||
}
|
||||
|
||||
already_AddRefed<SpeechRecognitionResult>
|
||||
SpeechRecognitionResultList::IndexedGetter(uint32_t aIndex, bool& aPresent)
|
||||
{
|
||||
if (aIndex >= Length()) {
|
||||
aPresent = false;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
aPresent = true;
|
||||
return Item(aIndex);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
SpeechRecognitionResultList::Length() const
|
||||
{
|
||||
return mItems.Length();
|
||||
}
|
||||
|
||||
already_AddRefed<SpeechRecognitionResult>
|
||||
SpeechRecognitionResultList::Item(uint32_t aIndex)
|
||||
{
|
||||
RefPtr<SpeechRecognitionResult> result = mItems.ElementAt(aIndex);
|
||||
return result.forget();
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,53 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_SpeechRecognitionResultList_h
|
||||
#define mozilla_dom_SpeechRecognitionResultList_h
|
||||
|
||||
#include "nsCycleCollectionParticipant.h"
|
||||
#include "nsWrapperCache.h"
|
||||
#include "nsTArray.h"
|
||||
#include "js/TypeDecls.h"
|
||||
|
||||
#include "mozilla/Attributes.h"
|
||||
|
||||
#include "SpeechRecognitionResult.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class SpeechRecognition;
|
||||
|
||||
class SpeechRecognitionResultList final : public nsISupports,
|
||||
public nsWrapperCache
|
||||
{
|
||||
public:
|
||||
explicit SpeechRecognitionResultList(SpeechRecognition* aParent);
|
||||
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_SCRIPT_HOLDER_CLASS(SpeechRecognitionResultList)
|
||||
|
||||
nsISupports* GetParentObject() const;
|
||||
|
||||
JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
|
||||
|
||||
uint32_t Length() const;
|
||||
|
||||
already_AddRefed<SpeechRecognitionResult> Item(uint32_t aIndex);
|
||||
|
||||
already_AddRefed<SpeechRecognitionResult> IndexedGetter(uint32_t aIndex, bool& aPresent);
|
||||
|
||||
nsTArray<RefPtr<SpeechRecognitionResult>> mItems;
|
||||
private:
|
||||
~SpeechRecognitionResultList();
|
||||
|
||||
RefPtr<SpeechRecognition> mParent;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -1,94 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "SpeechStreamListener.h"
|
||||
|
||||
#include "SpeechRecognition.h"
|
||||
#include "nsProxyRelease.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
SpeechStreamListener::SpeechStreamListener(SpeechRecognition* aRecognition)
|
||||
: mRecognition(aRecognition)
|
||||
{
|
||||
}
|
||||
|
||||
SpeechStreamListener::~SpeechStreamListener()
|
||||
{
|
||||
nsCOMPtr<nsIThread> mainThread;
|
||||
NS_GetMainThread(getter_AddRefs(mainThread));
|
||||
|
||||
NS_ProxyRelease(mainThread, mRecognition.forget());
|
||||
}
|
||||
|
||||
void
|
||||
SpeechStreamListener::NotifyQueuedAudioData(MediaStreamGraph* aGraph, TrackID aID,
|
||||
StreamTime aTrackOffset,
|
||||
const AudioSegment& aQueuedMedia,
|
||||
MediaStream* aInputStream,
|
||||
TrackID aInputTrackID)
|
||||
{
|
||||
AudioSegment* audio = const_cast<AudioSegment*>(
|
||||
static_cast<const AudioSegment*>(&aQueuedMedia));
|
||||
|
||||
AudioSegment::ChunkIterator iterator(*audio);
|
||||
while (!iterator.IsEnded()) {
|
||||
// Skip over-large chunks so we don't crash!
|
||||
if (iterator->GetDuration() > INT_MAX) {
|
||||
continue;
|
||||
}
|
||||
int duration = int(iterator->GetDuration());
|
||||
|
||||
if (iterator->IsNull()) {
|
||||
nsTArray<int16_t> nullData;
|
||||
PodZero(nullData.AppendElements(duration), duration);
|
||||
ConvertAndDispatchAudioChunk(duration, iterator->mVolume,
|
||||
nullData.Elements(), aGraph->GraphRate());
|
||||
} else {
|
||||
AudioSampleFormat format = iterator->mBufferFormat;
|
||||
|
||||
MOZ_ASSERT(format == AUDIO_FORMAT_S16 || format == AUDIO_FORMAT_FLOAT32);
|
||||
|
||||
if (format == AUDIO_FORMAT_S16) {
|
||||
ConvertAndDispatchAudioChunk(duration,iterator->mVolume,
|
||||
static_cast<const int16_t*>(iterator->mChannelData[0]),
|
||||
aGraph->GraphRate());
|
||||
} else if (format == AUDIO_FORMAT_FLOAT32) {
|
||||
ConvertAndDispatchAudioChunk(duration,iterator->mVolume,
|
||||
static_cast<const float*>(iterator->mChannelData[0]),
|
||||
aGraph->GraphRate());
|
||||
}
|
||||
}
|
||||
|
||||
iterator.Next();
|
||||
}
|
||||
}
|
||||
|
||||
template<typename SampleFormatType> void
|
||||
SpeechStreamListener::ConvertAndDispatchAudioChunk(int aDuration, float aVolume,
|
||||
SampleFormatType* aData,
|
||||
TrackRate aTrackRate)
|
||||
{
|
||||
RefPtr<SharedBuffer> samples(SharedBuffer::Create(aDuration *
|
||||
1 * // channel
|
||||
sizeof(int16_t)));
|
||||
|
||||
int16_t* to = static_cast<int16_t*>(samples->Data());
|
||||
ConvertAudioSamplesWithScale(aData, to, aDuration, aVolume);
|
||||
|
||||
mRecognition->FeedAudioData(samples.forget(), aDuration, this, aTrackRate);
|
||||
}
|
||||
|
||||
void
|
||||
SpeechStreamListener::NotifyEvent(MediaStreamGraph* aGraph,
|
||||
MediaStreamGraphEvent event)
|
||||
{
|
||||
// TODO dispatch SpeechEnd event so services can be informed
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,46 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_SpeechStreamListener_h
|
||||
#define mozilla_dom_SpeechStreamListener_h
|
||||
|
||||
#include "MediaStreamGraph.h"
|
||||
#include "MediaStreamListener.h"
|
||||
#include "AudioSegment.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class AudioSegment;
|
||||
|
||||
namespace dom {
|
||||
|
||||
class SpeechRecognition;
|
||||
|
||||
class SpeechStreamListener : public MediaStreamListener
|
||||
{
|
||||
public:
|
||||
explicit SpeechStreamListener(SpeechRecognition* aRecognition);
|
||||
~SpeechStreamListener();
|
||||
|
||||
void NotifyQueuedAudioData(MediaStreamGraph* aGraph, TrackID aID,
|
||||
StreamTime aTrackOffset,
|
||||
const AudioSegment& aQueuedMedia,
|
||||
MediaStream* aInputStream,
|
||||
TrackID aInputTrackID) override;
|
||||
|
||||
void NotifyEvent(MediaStreamGraph* aGraph,
|
||||
MediaStreamGraphEvent event) override;
|
||||
|
||||
private:
|
||||
template<typename SampleFormatType>
|
||||
void ConvertAndDispatchAudioChunk(int aDuration, float aVolume, SampleFormatType* aData, TrackRate aTrackRate);
|
||||
RefPtr<SpeechRecognition> mRecognition;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -1,193 +0,0 @@
|
|||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "endpointer.h"
|
||||
|
||||
#include "AudioSegment.h"
|
||||
|
||||
namespace {
|
||||
const int kFrameRate = 200; // 1 frame = 5ms of audio.
|
||||
}
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
Endpointer::Endpointer(int sample_rate)
|
||||
: speech_input_possibly_complete_silence_length_us_(-1),
|
||||
speech_input_complete_silence_length_us_(-1),
|
||||
audio_frame_time_us_(0),
|
||||
sample_rate_(sample_rate),
|
||||
frame_size_(0) {
|
||||
Reset();
|
||||
|
||||
frame_size_ = static_cast<int>(sample_rate / static_cast<float>(kFrameRate));
|
||||
|
||||
speech_input_minimum_length_us_ =
|
||||
static_cast<int64_t>(1.7 * 1000000);
|
||||
speech_input_complete_silence_length_us_ =
|
||||
static_cast<int64_t>(0.5 * 1000000);
|
||||
long_speech_input_complete_silence_length_us_ = -1;
|
||||
long_speech_length_us_ = -1;
|
||||
speech_input_possibly_complete_silence_length_us_ =
|
||||
1 * 1000000;
|
||||
|
||||
// Set the default configuration for Push To Talk mode.
|
||||
EnergyEndpointerParams ep_config;
|
||||
ep_config.set_frame_period(1.0f / static_cast<float>(kFrameRate));
|
||||
ep_config.set_frame_duration(1.0f / static_cast<float>(kFrameRate));
|
||||
ep_config.set_endpoint_margin(0.2f);
|
||||
ep_config.set_onset_window(0.15f);
|
||||
ep_config.set_speech_on_window(0.4f);
|
||||
ep_config.set_offset_window(0.15f);
|
||||
ep_config.set_onset_detect_dur(0.09f);
|
||||
ep_config.set_onset_confirm_dur(0.075f);
|
||||
ep_config.set_on_maintain_dur(0.10f);
|
||||
ep_config.set_offset_confirm_dur(0.12f);
|
||||
ep_config.set_decision_threshold(1000.0f);
|
||||
ep_config.set_min_decision_threshold(50.0f);
|
||||
ep_config.set_fast_update_dur(0.2f);
|
||||
ep_config.set_sample_rate(static_cast<float>(sample_rate));
|
||||
ep_config.set_min_fundamental_frequency(57.143f);
|
||||
ep_config.set_max_fundamental_frequency(400.0f);
|
||||
ep_config.set_contamination_rejection_period(0.25f);
|
||||
energy_endpointer_.Init(ep_config);
|
||||
}
|
||||
|
||||
void Endpointer::Reset() {
|
||||
old_ep_status_ = EP_PRE_SPEECH;
|
||||
waiting_for_speech_possibly_complete_timeout_ = false;
|
||||
waiting_for_speech_complete_timeout_ = false;
|
||||
speech_previously_detected_ = false;
|
||||
speech_input_complete_ = false;
|
||||
audio_frame_time_us_ = 0; // Reset time for packets sent to endpointer.
|
||||
speech_end_time_us_ = -1;
|
||||
speech_start_time_us_ = -1;
|
||||
}
|
||||
|
||||
void Endpointer::StartSession() {
|
||||
Reset();
|
||||
energy_endpointer_.StartSession();
|
||||
}
|
||||
|
||||
void Endpointer::EndSession() {
|
||||
energy_endpointer_.EndSession();
|
||||
}
|
||||
|
||||
void Endpointer::SetEnvironmentEstimationMode() {
|
||||
Reset();
|
||||
energy_endpointer_.SetEnvironmentEstimationMode();
|
||||
}
|
||||
|
||||
void Endpointer::SetUserInputMode() {
|
||||
energy_endpointer_.SetUserInputMode();
|
||||
}
|
||||
|
||||
EpStatus Endpointer::Status(int64_t *time) {
|
||||
return energy_endpointer_.Status(time);
|
||||
}
|
||||
|
||||
EpStatus Endpointer::ProcessAudio(const AudioChunk& raw_audio, float* rms_out) {
|
||||
MOZ_ASSERT(raw_audio.mBufferFormat == AUDIO_FORMAT_S16, "Audio is not in 16 bit format");
|
||||
const int16_t* audio_data = static_cast<const int16_t*>(raw_audio.mChannelData[0]);
|
||||
const int num_samples = raw_audio.mDuration;
|
||||
EpStatus ep_status = EP_PRE_SPEECH;
|
||||
|
||||
// Process the input data in blocks of frame_size_, dropping any incomplete
|
||||
// frames at the end (which is ok since typically the caller will be recording
|
||||
// audio in multiples of our frame size).
|
||||
int sample_index = 0;
|
||||
while (sample_index + frame_size_ <= num_samples) {
|
||||
// Have the endpointer process the frame.
|
||||
energy_endpointer_.ProcessAudioFrame(audio_frame_time_us_,
|
||||
audio_data + sample_index,
|
||||
frame_size_,
|
||||
rms_out);
|
||||
sample_index += frame_size_;
|
||||
audio_frame_time_us_ += (frame_size_ * 1000000) /
|
||||
sample_rate_;
|
||||
|
||||
// Get the status of the endpointer.
|
||||
int64_t ep_time;
|
||||
ep_status = energy_endpointer_.Status(&ep_time);
|
||||
if (old_ep_status_ != ep_status)
|
||||
fprintf(stderr, "Status changed old= %d, new= %d\n", old_ep_status_, ep_status);
|
||||
|
||||
// Handle state changes.
|
||||
if ((EP_SPEECH_PRESENT == ep_status) &&
|
||||
(EP_POSSIBLE_ONSET == old_ep_status_)) {
|
||||
speech_end_time_us_ = -1;
|
||||
waiting_for_speech_possibly_complete_timeout_ = false;
|
||||
waiting_for_speech_complete_timeout_ = false;
|
||||
// Trigger SpeechInputDidStart event on first detection.
|
||||
if (false == speech_previously_detected_) {
|
||||
speech_previously_detected_ = true;
|
||||
speech_start_time_us_ = ep_time;
|
||||
}
|
||||
}
|
||||
if ((EP_PRE_SPEECH == ep_status) &&
|
||||
(EP_POSSIBLE_OFFSET == old_ep_status_)) {
|
||||
speech_end_time_us_ = ep_time;
|
||||
waiting_for_speech_possibly_complete_timeout_ = true;
|
||||
waiting_for_speech_complete_timeout_ = true;
|
||||
}
|
||||
if (ep_time > speech_input_minimum_length_us_) {
|
||||
// Speech possibly complete timeout.
|
||||
if ((waiting_for_speech_possibly_complete_timeout_) &&
|
||||
(ep_time - speech_end_time_us_ >
|
||||
speech_input_possibly_complete_silence_length_us_)) {
|
||||
waiting_for_speech_possibly_complete_timeout_ = false;
|
||||
}
|
||||
if (waiting_for_speech_complete_timeout_) {
|
||||
// The length of the silence timeout period can be held constant, or it
|
||||
// can be changed after a fixed amount of time from the beginning of
|
||||
// speech.
|
||||
bool has_stepped_silence =
|
||||
(long_speech_length_us_ > 0) &&
|
||||
(long_speech_input_complete_silence_length_us_ > 0);
|
||||
int64_t requested_silence_length;
|
||||
if (has_stepped_silence &&
|
||||
(ep_time - speech_start_time_us_) > long_speech_length_us_) {
|
||||
requested_silence_length =
|
||||
long_speech_input_complete_silence_length_us_;
|
||||
} else {
|
||||
requested_silence_length =
|
||||
speech_input_complete_silence_length_us_;
|
||||
}
|
||||
|
||||
// Speech complete timeout.
|
||||
if ((ep_time - speech_end_time_us_) > requested_silence_length) {
|
||||
waiting_for_speech_complete_timeout_ = false;
|
||||
speech_input_complete_ = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
old_ep_status_ = ep_status;
|
||||
}
|
||||
return ep_status;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -1,180 +0,0 @@
|
|||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CONTENT_BROWSER_SPEECH_ENDPOINTER_ENDPOINTER_H_
|
||||
#define CONTENT_BROWSER_SPEECH_ENDPOINTER_ENDPOINTER_H_
|
||||
|
||||
#include "energy_endpointer.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
struct AudioChunk;
|
||||
|
||||
// A simple interface to the underlying energy-endpointer implementation, this
|
||||
// class lets callers provide audio as being recorded and let them poll to find
|
||||
// when the user has stopped speaking.
|
||||
//
|
||||
// There are two events that may trigger the end of speech:
|
||||
//
|
||||
// speechInputPossiblyComplete event:
|
||||
//
|
||||
// Signals that silence/noise has been detected for a *short* amount of
|
||||
// time after some speech has been detected. It can be used for low latency
|
||||
// UI feedback. To disable it, set it to a large amount.
|
||||
//
|
||||
// speechInputComplete event:
|
||||
//
|
||||
// This event is intended to signal end of input and to stop recording.
|
||||
// The amount of time to wait after speech is set by
|
||||
// speech_input_complete_silence_length_ and optionally two other
|
||||
// parameters (see below).
|
||||
// This time can be held constant, or can change as more speech is detected.
|
||||
// In the latter case, the time changes after a set amount of time from the
|
||||
// *beginning* of speech. This is motivated by the expectation that there
|
||||
// will be two distinct types of inputs: short search queries and longer
|
||||
// dictation style input.
|
||||
//
|
||||
// Three parameters are used to define the piecewise constant timeout function.
|
||||
// The timeout length is speech_input_complete_silence_length until
|
||||
// long_speech_length, when it changes to
|
||||
// long_speech_input_complete_silence_length.
|
||||
class Endpointer {
|
||||
public:
|
||||
explicit Endpointer(int sample_rate);
|
||||
|
||||
// Start the endpointer. This should be called at the beginning of a session.
|
||||
void StartSession();
|
||||
|
||||
// Stop the endpointer.
|
||||
void EndSession();
|
||||
|
||||
// Start environment estimation. Audio will be used for environment estimation
|
||||
// i.e. noise level estimation.
|
||||
void SetEnvironmentEstimationMode();
|
||||
|
||||
// Start user input. This should be called when the user indicates start of
|
||||
// input, e.g. by pressing a button.
|
||||
void SetUserInputMode();
|
||||
|
||||
// Process a segment of audio, which may be more than one frame.
|
||||
// The status of the last frame will be returned.
|
||||
EpStatus ProcessAudio(const AudioChunk& raw_audio, float* rms_out);
|
||||
|
||||
// Get the status of the endpointer.
|
||||
EpStatus Status(int64_t *time_us);
|
||||
|
||||
// Get the expected frame size for audio chunks. Audio chunks are expected
|
||||
// to contain a number of samples that is a multiple of this number, and extra
|
||||
// samples will be dropped.
|
||||
int32_t FrameSize() const {
|
||||
return frame_size_;
|
||||
}
|
||||
|
||||
// Returns true if the endpointer detected reasonable audio levels above
|
||||
// background noise which could be user speech, false if not.
|
||||
bool DidStartReceivingSpeech() const {
|
||||
return speech_previously_detected_;
|
||||
}
|
||||
|
||||
bool IsEstimatingEnvironment() const {
|
||||
return energy_endpointer_.estimating_environment();
|
||||
}
|
||||
|
||||
void set_speech_input_complete_silence_length(int64_t time_us) {
|
||||
speech_input_complete_silence_length_us_ = time_us;
|
||||
}
|
||||
|
||||
void set_long_speech_input_complete_silence_length(int64_t time_us) {
|
||||
long_speech_input_complete_silence_length_us_ = time_us;
|
||||
}
|
||||
|
||||
void set_speech_input_possibly_complete_silence_length(int64_t time_us) {
|
||||
speech_input_possibly_complete_silence_length_us_ = time_us;
|
||||
}
|
||||
|
||||
void set_long_speech_length(int64_t time_us) {
|
||||
long_speech_length_us_ = time_us;
|
||||
}
|
||||
|
||||
bool speech_input_complete() const {
|
||||
return speech_input_complete_;
|
||||
}
|
||||
|
||||
// RMS background noise level in dB.
|
||||
float NoiseLevelDb() const { return energy_endpointer_.GetNoiseLevelDb(); }
|
||||
|
||||
private:
|
||||
// Reset internal states. Helper method common to initial input utterance
|
||||
// and following input utternaces.
|
||||
void Reset();
|
||||
|
||||
// Minimum allowable length of speech input.
|
||||
int64_t speech_input_minimum_length_us_;
|
||||
|
||||
// The speechInputPossiblyComplete event signals that silence/noise has been
|
||||
// detected for a *short* amount of time after some speech has been detected.
|
||||
// This proporty specifies the time period.
|
||||
int64_t speech_input_possibly_complete_silence_length_us_;
|
||||
|
||||
// The speechInputComplete event signals that silence/noise has been
|
||||
// detected for a *long* amount of time after some speech has been detected.
|
||||
// This property specifies the time period.
|
||||
int64_t speech_input_complete_silence_length_us_;
|
||||
|
||||
// Same as above, this specifies the required silence period after speech
|
||||
// detection. This period is used instead of
|
||||
// speech_input_complete_silence_length_ when the utterance is longer than
|
||||
// long_speech_length_. This parameter is optional.
|
||||
int64_t long_speech_input_complete_silence_length_us_;
|
||||
|
||||
// The period of time after which the endpointer should consider
|
||||
// long_speech_input_complete_silence_length_ as a valid silence period
|
||||
// instead of speech_input_complete_silence_length_. This parameter is
|
||||
// optional.
|
||||
int64_t long_speech_length_us_;
|
||||
|
||||
// First speech onset time, used in determination of speech complete timeout.
|
||||
int64_t speech_start_time_us_;
|
||||
|
||||
// Most recent end time, used in determination of speech complete timeout.
|
||||
int64_t speech_end_time_us_;
|
||||
|
||||
int64_t audio_frame_time_us_;
|
||||
EpStatus old_ep_status_;
|
||||
bool waiting_for_speech_possibly_complete_timeout_;
|
||||
bool waiting_for_speech_complete_timeout_;
|
||||
bool speech_previously_detected_;
|
||||
bool speech_input_complete_;
|
||||
EnergyEndpointer energy_endpointer_;
|
||||
int sample_rate_;
|
||||
int32_t frame_size_;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // CONTENT_BROWSER_SPEECH_ENDPOINTER_ENDPOINTER_H_
|
|
@ -1,393 +0,0 @@
|
|||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "energy_endpointer.h"
|
||||
|
||||
#include <math.h>
|
||||
|
||||
namespace {
|
||||
|
||||
// Returns the RMS (quadratic mean) of the input signal.
|
||||
float RMS(const int16_t* samples, int num_samples) {
|
||||
int64_t ssq_int64_t = 0;
|
||||
int64_t sum_int64_t = 0;
|
||||
for (int i = 0; i < num_samples; ++i) {
|
||||
sum_int64_t += samples[i];
|
||||
ssq_int64_t += samples[i] * samples[i];
|
||||
}
|
||||
// now convert to floats.
|
||||
double sum = static_cast<double>(sum_int64_t);
|
||||
sum /= num_samples;
|
||||
double ssq = static_cast<double>(ssq_int64_t);
|
||||
return static_cast<float>(sqrt((ssq / num_samples) - (sum * sum)));
|
||||
}
|
||||
|
||||
int64_t Secs2Usecs(float seconds) {
|
||||
return static_cast<int64_t>(0.5 + (1.0e6 * seconds));
|
||||
}
|
||||
|
||||
float GetDecibel(float value) {
|
||||
if (value > 1.0e-100)
|
||||
return 20 * log10(value);
|
||||
return -2000.0;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Stores threshold-crossing histories for making decisions about the speech
|
||||
// state.
|
||||
class EnergyEndpointer::HistoryRing {
|
||||
public:
|
||||
HistoryRing() : insertion_index_(0) {}
|
||||
|
||||
// Resets the ring to |size| elements each with state |initial_state|
|
||||
void SetRing(int size, bool initial_state);
|
||||
|
||||
// Inserts a new entry into the ring and drops the oldest entry.
|
||||
void Insert(int64_t time_us, bool decision);
|
||||
|
||||
// Returns the time in microseconds of the most recently added entry.
|
||||
int64_t EndTime() const;
|
||||
|
||||
// Returns the sum of all intervals during which 'decision' is true within
|
||||
// the time in seconds specified by 'duration'. The returned interval is
|
||||
// in seconds.
|
||||
float RingSum(float duration_sec);
|
||||
|
||||
private:
|
||||
struct DecisionPoint {
|
||||
int64_t time_us;
|
||||
bool decision;
|
||||
};
|
||||
|
||||
std::vector<DecisionPoint> decision_points_;
|
||||
int insertion_index_; // Index at which the next item gets added/inserted.
|
||||
|
||||
HistoryRing(const HistoryRing&);
|
||||
void operator=(const HistoryRing&);
|
||||
};
|
||||
|
||||
void EnergyEndpointer::HistoryRing::SetRing(int size, bool initial_state) {
|
||||
insertion_index_ = 0;
|
||||
decision_points_.clear();
|
||||
DecisionPoint init = { -1, initial_state };
|
||||
decision_points_.resize(size, init);
|
||||
}
|
||||
|
||||
void EnergyEndpointer::HistoryRing::Insert(int64_t time_us, bool decision) {
|
||||
decision_points_[insertion_index_].time_us = time_us;
|
||||
decision_points_[insertion_index_].decision = decision;
|
||||
insertion_index_ = (insertion_index_ + 1) % decision_points_.size();
|
||||
}
|
||||
|
||||
int64_t EnergyEndpointer::HistoryRing::EndTime() const {
|
||||
int ind = insertion_index_ - 1;
|
||||
if (ind < 0)
|
||||
ind = decision_points_.size() - 1;
|
||||
return decision_points_[ind].time_us;
|
||||
}
|
||||
|
||||
float EnergyEndpointer::HistoryRing::RingSum(float duration_sec) {
|
||||
if (!decision_points_.size())
|
||||
return 0.0;
|
||||
|
||||
int64_t sum_us = 0;
|
||||
int ind = insertion_index_ - 1;
|
||||
if (ind < 0)
|
||||
ind = decision_points_.size() - 1;
|
||||
int64_t end_us = decision_points_[ind].time_us;
|
||||
bool is_on = decision_points_[ind].decision;
|
||||
int64_t start_us = end_us - static_cast<int64_t>(0.5 + (1.0e6 * duration_sec));
|
||||
if (start_us < 0)
|
||||
start_us = 0;
|
||||
size_t n_summed = 1; // n points ==> (n-1) intervals
|
||||
while ((decision_points_[ind].time_us > start_us) &&
|
||||
(n_summed < decision_points_.size())) {
|
||||
--ind;
|
||||
if (ind < 0)
|
||||
ind = decision_points_.size() - 1;
|
||||
if (is_on)
|
||||
sum_us += end_us - decision_points_[ind].time_us;
|
||||
is_on = decision_points_[ind].decision;
|
||||
end_us = decision_points_[ind].time_us;
|
||||
n_summed++;
|
||||
}
|
||||
|
||||
return 1.0e-6f * sum_us; // Returns total time that was super threshold.
|
||||
}
|
||||
|
||||
EnergyEndpointer::EnergyEndpointer()
|
||||
: status_(EP_PRE_SPEECH),
|
||||
offset_confirm_dur_sec_(0),
|
||||
endpointer_time_us_(0),
|
||||
fast_update_frames_(0),
|
||||
frame_counter_(0),
|
||||
max_window_dur_(4.0),
|
||||
sample_rate_(0),
|
||||
history_(new HistoryRing()),
|
||||
decision_threshold_(0),
|
||||
estimating_environment_(false),
|
||||
noise_level_(0),
|
||||
rms_adapt_(0),
|
||||
start_lag_(0),
|
||||
end_lag_(0),
|
||||
user_input_start_time_us_(0) {
|
||||
}
|
||||
|
||||
EnergyEndpointer::~EnergyEndpointer() {
|
||||
}
|
||||
|
||||
int EnergyEndpointer::TimeToFrame(float time) const {
|
||||
return static_cast<int32_t>(0.5 + (time / params_.frame_period()));
|
||||
}
|
||||
|
||||
void EnergyEndpointer::Restart(bool reset_threshold) {
|
||||
status_ = EP_PRE_SPEECH;
|
||||
user_input_start_time_us_ = 0;
|
||||
|
||||
if (reset_threshold) {
|
||||
decision_threshold_ = params_.decision_threshold();
|
||||
rms_adapt_ = decision_threshold_;
|
||||
noise_level_ = params_.decision_threshold() / 2.0f;
|
||||
frame_counter_ = 0; // Used for rapid initial update of levels.
|
||||
}
|
||||
|
||||
// Set up the memories to hold the history windows.
|
||||
history_->SetRing(TimeToFrame(max_window_dur_), false);
|
||||
|
||||
// Flag that indicates that current input should be used for
|
||||
// estimating the environment. The user has not yet started input
|
||||
// by e.g. pressed the push-to-talk button. By default, this is
|
||||
// false for backward compatibility.
|
||||
estimating_environment_ = false;
|
||||
}
|
||||
|
||||
void EnergyEndpointer::Init(const EnergyEndpointerParams& params) {
|
||||
params_ = params;
|
||||
|
||||
// Find the longest history interval to be used, and make the ring
|
||||
// large enough to accommodate that number of frames. NOTE: This
|
||||
// depends upon ep_frame_period being set correctly in the factory
|
||||
// that did this instantiation.
|
||||
max_window_dur_ = params_.onset_window();
|
||||
if (params_.speech_on_window() > max_window_dur_)
|
||||
max_window_dur_ = params_.speech_on_window();
|
||||
if (params_.offset_window() > max_window_dur_)
|
||||
max_window_dur_ = params_.offset_window();
|
||||
Restart(true);
|
||||
|
||||
offset_confirm_dur_sec_ = params_.offset_window() -
|
||||
params_.offset_confirm_dur();
|
||||
if (offset_confirm_dur_sec_ < 0.0)
|
||||
offset_confirm_dur_sec_ = 0.0;
|
||||
|
||||
user_input_start_time_us_ = 0;
|
||||
|
||||
// Flag that indicates that current input should be used for
|
||||
// estimating the environment. The user has not yet started input
|
||||
// by e.g. pressed the push-to-talk button. By default, this is
|
||||
// false for backward compatibility.
|
||||
estimating_environment_ = false;
|
||||
// The initial value of the noise and speech levels is inconsequential.
|
||||
// The level of the first frame will overwrite these values.
|
||||
noise_level_ = params_.decision_threshold() / 2.0f;
|
||||
fast_update_frames_ =
|
||||
static_cast<int64_t>(params_.fast_update_dur() / params_.frame_period());
|
||||
|
||||
frame_counter_ = 0; // Used for rapid initial update of levels.
|
||||
|
||||
sample_rate_ = params_.sample_rate();
|
||||
start_lag_ = static_cast<int>(sample_rate_ /
|
||||
params_.max_fundamental_frequency());
|
||||
end_lag_ = static_cast<int>(sample_rate_ /
|
||||
params_.min_fundamental_frequency());
|
||||
}
|
||||
|
||||
void EnergyEndpointer::StartSession() {
|
||||
Restart(true);
|
||||
}
|
||||
|
||||
void EnergyEndpointer::EndSession() {
|
||||
status_ = EP_POST_SPEECH;
|
||||
}
|
||||
|
||||
void EnergyEndpointer::SetEnvironmentEstimationMode() {
|
||||
Restart(true);
|
||||
estimating_environment_ = true;
|
||||
}
|
||||
|
||||
void EnergyEndpointer::SetUserInputMode() {
|
||||
estimating_environment_ = false;
|
||||
user_input_start_time_us_ = endpointer_time_us_;
|
||||
}
|
||||
|
||||
void EnergyEndpointer::ProcessAudioFrame(int64_t time_us,
|
||||
const int16_t* samples,
|
||||
int num_samples,
|
||||
float* rms_out) {
|
||||
endpointer_time_us_ = time_us;
|
||||
float rms = RMS(samples, num_samples);
|
||||
|
||||
// Check that this is user input audio vs. pre-input adaptation audio.
|
||||
// Input audio starts when the user indicates start of input, by e.g.
|
||||
// pressing push-to-talk. Audio recieved prior to that is used to update
|
||||
// noise and speech level estimates.
|
||||
if (!estimating_environment_) {
|
||||
bool decision = false;
|
||||
if ((endpointer_time_us_ - user_input_start_time_us_) <
|
||||
Secs2Usecs(params_.contamination_rejection_period())) {
|
||||
decision = false;
|
||||
//PR_LOG(GetSpeechRecognitionLog(), PR_LOG_DEBUG, ("decision: forced to false, time: %d", endpointer_time_us_));
|
||||
} else {
|
||||
decision = (rms > decision_threshold_);
|
||||
}
|
||||
|
||||
history_->Insert(endpointer_time_us_, decision);
|
||||
|
||||
switch (status_) {
|
||||
case EP_PRE_SPEECH:
|
||||
if (history_->RingSum(params_.onset_window()) >
|
||||
params_.onset_detect_dur()) {
|
||||
status_ = EP_POSSIBLE_ONSET;
|
||||
}
|
||||
break;
|
||||
|
||||
case EP_POSSIBLE_ONSET: {
|
||||
float tsum = history_->RingSum(params_.onset_window());
|
||||
if (tsum > params_.onset_confirm_dur()) {
|
||||
status_ = EP_SPEECH_PRESENT;
|
||||
} else { // If signal is not maintained, drop back to pre-speech.
|
||||
if (tsum <= params_.onset_detect_dur())
|
||||
status_ = EP_PRE_SPEECH;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case EP_SPEECH_PRESENT: {
|
||||
// To induce hysteresis in the state residency, we allow a
|
||||
// smaller residency time in the on_ring, than was required to
|
||||
// enter the SPEECH_PERSENT state.
|
||||
float on_time = history_->RingSum(params_.speech_on_window());
|
||||
if (on_time < params_.on_maintain_dur())
|
||||
status_ = EP_POSSIBLE_OFFSET;
|
||||
break;
|
||||
}
|
||||
|
||||
case EP_POSSIBLE_OFFSET:
|
||||
if (history_->RingSum(params_.offset_window()) <=
|
||||
offset_confirm_dur_sec_) {
|
||||
// Note that this offset time may be beyond the end
|
||||
// of the input buffer in a real-time system. It will be up
|
||||
// to the RecognizerSession to decide what to do.
|
||||
status_ = EP_PRE_SPEECH; // Automatically reset for next utterance.
|
||||
} else { // If speech picks up again we allow return to SPEECH_PRESENT.
|
||||
if (history_->RingSum(params_.speech_on_window()) >=
|
||||
params_.on_maintain_dur())
|
||||
status_ = EP_SPEECH_PRESENT;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// If this is a quiet, non-speech region, slowly adapt the detection
|
||||
// threshold to be about 6dB above the average RMS.
|
||||
if ((!decision) && (status_ == EP_PRE_SPEECH)) {
|
||||
decision_threshold_ = (0.98f * decision_threshold_) + (0.02f * 2 * rms);
|
||||
rms_adapt_ = decision_threshold_;
|
||||
} else {
|
||||
// If this is in a speech region, adapt the decision threshold to
|
||||
// be about 10dB below the average RMS. If the noise level is high,
|
||||
// the threshold is pushed up.
|
||||
// Adaptation up to a higher level is 5 times faster than decay to
|
||||
// a lower level.
|
||||
if ((status_ == EP_SPEECH_PRESENT) && decision) {
|
||||
if (rms_adapt_ > rms) {
|
||||
rms_adapt_ = (0.99f * rms_adapt_) + (0.01f * rms);
|
||||
} else {
|
||||
rms_adapt_ = (0.95f * rms_adapt_) + (0.05f * rms);
|
||||
}
|
||||
float target_threshold = 0.3f * rms_adapt_ + noise_level_;
|
||||
decision_threshold_ = (.90f * decision_threshold_) +
|
||||
(0.10f * target_threshold);
|
||||
}
|
||||
}
|
||||
|
||||
// Set a floor
|
||||
if (decision_threshold_ < params_.min_decision_threshold())
|
||||
decision_threshold_ = params_.min_decision_threshold();
|
||||
}
|
||||
|
||||
// Update speech and noise levels.
|
||||
UpdateLevels(rms);
|
||||
++frame_counter_;
|
||||
|
||||
if (rms_out)
|
||||
*rms_out = GetDecibel(rms);
|
||||
}
|
||||
|
||||
float EnergyEndpointer::GetNoiseLevelDb() const {
|
||||
return GetDecibel(noise_level_);
|
||||
}
|
||||
|
||||
void EnergyEndpointer::UpdateLevels(float rms) {
|
||||
// Update quickly initially. We assume this is noise and that
|
||||
// speech is 6dB above the noise.
|
||||
if (frame_counter_ < fast_update_frames_) {
|
||||
// Alpha increases from 0 to (k-1)/k where k is the number of time
|
||||
// steps in the initial adaptation period.
|
||||
float alpha = static_cast<float>(frame_counter_) /
|
||||
static_cast<float>(fast_update_frames_);
|
||||
noise_level_ = (alpha * noise_level_) + ((1 - alpha) * rms);
|
||||
//PR_LOG(GetSpeechRecognitionLog(), PR_LOG_DEBUG, ("FAST UPDATE, frame_counter_ %d, fast_update_frames_ %d", frame_counter_, fast_update_frames_));
|
||||
} else {
|
||||
// Update Noise level. The noise level adapts quickly downward, but
|
||||
// slowly upward. The noise_level_ parameter is not currently used
|
||||
// for threshold adaptation. It is used for UI feedback.
|
||||
if (noise_level_ < rms)
|
||||
noise_level_ = (0.999f * noise_level_) + (0.001f * rms);
|
||||
else
|
||||
noise_level_ = (0.95f * noise_level_) + (0.05f * rms);
|
||||
}
|
||||
if (estimating_environment_ || (frame_counter_ < fast_update_frames_)) {
|
||||
decision_threshold_ = noise_level_ * 2; // 6dB above noise level.
|
||||
// Set a floor
|
||||
if (decision_threshold_ < params_.min_decision_threshold())
|
||||
decision_threshold_ = params_.min_decision_threshold();
|
||||
}
|
||||
}
|
||||
|
||||
EpStatus EnergyEndpointer::Status(int64_t* status_time) const {
|
||||
*status_time = history_->EndTime();
|
||||
return status_;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -1,180 +0,0 @@
|
|||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// The EnergyEndpointer class finds likely speech onset and offset points.
|
||||
//
|
||||
// The implementation described here is about the simplest possible.
|
||||
// It is based on timings of threshold crossings for overall signal
|
||||
// RMS. It is suitable for light weight applications.
|
||||
//
|
||||
// As written, the basic idea is that one specifies intervals that
|
||||
// must be occupied by super- and sub-threshold energy levels, and
|
||||
// defers decisions re onset and offset times until these
|
||||
// specifications have been met. Three basic intervals are tested: an
|
||||
// onset window, a speech-on window, and an offset window. We require
|
||||
// super-threshold to exceed some mimimum total durations in the onset
|
||||
// and speech-on windows before declaring the speech onset time, and
|
||||
// we specify a required sub-threshold residency in the offset window
|
||||
// before declaring speech offset. As the various residency requirements are
|
||||
// met, the EnergyEndpointer instance assumes various states, and can return the
|
||||
// ID of these states to the client (see EpStatus below).
|
||||
//
|
||||
// The levels of the speech and background noise are continuously updated. It is
|
||||
// important that the background noise level be estimated initially for
|
||||
// robustness in noisy conditions. The first frames are assumed to be background
|
||||
// noise and a fast update rate is used for the noise level. The duration for
|
||||
// fast update is controlled by the fast_update_dur_ paramter.
|
||||
//
|
||||
// If used in noisy conditions, the endpointer should be started and run in the
|
||||
// EnvironmentEstimation mode, for at least 200ms, before switching to
|
||||
// UserInputMode.
|
||||
// Audio feedback contamination can appear in the input audio, if not cut
|
||||
// out or handled by echo cancellation. Audio feedback can trigger a false
|
||||
// accept. The false accepts can be ignored by setting
|
||||
// ep_contamination_rejection_period.
|
||||
|
||||
#ifndef CONTENT_BROWSER_SPEECH_ENDPOINTER_ENERGY_ENDPOINTER_H_
|
||||
#define CONTENT_BROWSER_SPEECH_ENDPOINTER_ENERGY_ENDPOINTER_H_
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "nsAutoPtr.h"
|
||||
|
||||
#include "energy_endpointer_params.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Endpointer status codes
|
||||
enum EpStatus {
|
||||
EP_PRE_SPEECH = 10,
|
||||
EP_POSSIBLE_ONSET,
|
||||
EP_SPEECH_PRESENT,
|
||||
EP_POSSIBLE_OFFSET,
|
||||
EP_POST_SPEECH,
|
||||
};
|
||||
|
||||
class EnergyEndpointer {
|
||||
public:
|
||||
// The default construction MUST be followed by Init(), before any
|
||||
// other use can be made of the instance.
|
||||
EnergyEndpointer();
|
||||
virtual ~EnergyEndpointer();
|
||||
|
||||
void Init(const EnergyEndpointerParams& params);
|
||||
|
||||
// Start the endpointer. This should be called at the beginning of a session.
|
||||
void StartSession();
|
||||
|
||||
// Stop the endpointer.
|
||||
void EndSession();
|
||||
|
||||
// Start environment estimation. Audio will be used for environment estimation
|
||||
// i.e. noise level estimation.
|
||||
void SetEnvironmentEstimationMode();
|
||||
|
||||
// Start user input. This should be called when the user indicates start of
|
||||
// input, e.g. by pressing a button.
|
||||
void SetUserInputMode();
|
||||
|
||||
// Computes the next input frame and modifies EnergyEndpointer status as
|
||||
// appropriate based on the computation.
|
||||
void ProcessAudioFrame(int64_t time_us,
|
||||
const int16_t* samples, int num_samples,
|
||||
float* rms_out);
|
||||
|
||||
// Returns the current state of the EnergyEndpointer and the time
|
||||
// corresponding to the most recently computed frame.
|
||||
EpStatus Status(int64_t* status_time_us) const;
|
||||
|
||||
bool estimating_environment() const {
|
||||
return estimating_environment_;
|
||||
}
|
||||
|
||||
// Returns estimated noise level in dB.
|
||||
float GetNoiseLevelDb() const;
|
||||
|
||||
private:
|
||||
class HistoryRing;
|
||||
|
||||
// Resets the endpointer internal state. If reset_threshold is true, the
|
||||
// state will be reset completely, including adaptive thresholds and the
|
||||
// removal of all history information.
|
||||
void Restart(bool reset_threshold);
|
||||
|
||||
// Update internal speech and noise levels.
|
||||
void UpdateLevels(float rms);
|
||||
|
||||
// Returns the number of frames (or frame number) corresponding to
|
||||
// the 'time' (in seconds).
|
||||
int TimeToFrame(float time) const;
|
||||
|
||||
EpStatus status_; // The current state of this instance.
|
||||
float offset_confirm_dur_sec_; // max on time allowed to confirm POST_SPEECH
|
||||
int64_t endpointer_time_us_; // Time of the most recently received audio frame.
|
||||
int64_t fast_update_frames_; // Number of frames for initial level adaptation.
|
||||
int64_t frame_counter_; // Number of frames seen. Used for initial adaptation.
|
||||
float max_window_dur_; // Largest search window size (seconds)
|
||||
float sample_rate_; // Sampling rate.
|
||||
|
||||
// Ring buffers to hold the speech activity history.
|
||||
nsAutoPtr<HistoryRing> history_;
|
||||
|
||||
// Configuration parameters.
|
||||
EnergyEndpointerParams params_;
|
||||
|
||||
// RMS which must be exceeded to conclude frame is speech.
|
||||
float decision_threshold_;
|
||||
|
||||
// Flag to indicate that audio should be used to estimate environment, prior
|
||||
// to receiving user input.
|
||||
bool estimating_environment_;
|
||||
|
||||
// Estimate of the background noise level. Used externally for UI feedback.
|
||||
float noise_level_;
|
||||
|
||||
// An adaptive threshold used to update decision_threshold_ when appropriate.
|
||||
float rms_adapt_;
|
||||
|
||||
// Start lag corresponds to the highest fundamental frequency.
|
||||
int start_lag_;
|
||||
|
||||
// End lag corresponds to the lowest fundamental frequency.
|
||||
int end_lag_;
|
||||
|
||||
// Time when mode switched from environment estimation to user input. This
|
||||
// is used to time forced rejection of audio feedback contamination.
|
||||
int64_t user_input_start_time_us_;
|
||||
|
||||
// prevent copy constructor and assignment
|
||||
EnergyEndpointer(const EnergyEndpointer&);
|
||||
void operator=(const EnergyEndpointer&);
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // CONTENT_BROWSER_SPEECH_ENDPOINTER_ENERGY_ENDPOINTER_H_
|
|
@ -1,77 +0,0 @@
|
|||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "energy_endpointer_params.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
EnergyEndpointerParams::EnergyEndpointerParams() {
|
||||
SetDefaults();
|
||||
}
|
||||
|
||||
void EnergyEndpointerParams::SetDefaults() {
|
||||
frame_period_ = 0.01f;
|
||||
frame_duration_ = 0.01f;
|
||||
endpoint_margin_ = 0.2f;
|
||||
onset_window_ = 0.15f;
|
||||
speech_on_window_ = 0.4f;
|
||||
offset_window_ = 0.15f;
|
||||
onset_detect_dur_ = 0.09f;
|
||||
onset_confirm_dur_ = 0.075f;
|
||||
on_maintain_dur_ = 0.10f;
|
||||
offset_confirm_dur_ = 0.12f;
|
||||
decision_threshold_ = 150.0f;
|
||||
min_decision_threshold_ = 50.0f;
|
||||
fast_update_dur_ = 0.2f;
|
||||
sample_rate_ = 8000.0f;
|
||||
min_fundamental_frequency_ = 57.143f;
|
||||
max_fundamental_frequency_ = 400.0f;
|
||||
contamination_rejection_period_ = 0.25f;
|
||||
}
|
||||
|
||||
void EnergyEndpointerParams::operator=(const EnergyEndpointerParams& source) {
|
||||
frame_period_ = source.frame_period();
|
||||
frame_duration_ = source.frame_duration();
|
||||
endpoint_margin_ = source.endpoint_margin();
|
||||
onset_window_ = source.onset_window();
|
||||
speech_on_window_ = source.speech_on_window();
|
||||
offset_window_ = source.offset_window();
|
||||
onset_detect_dur_ = source.onset_detect_dur();
|
||||
onset_confirm_dur_ = source.onset_confirm_dur();
|
||||
on_maintain_dur_ = source.on_maintain_dur();
|
||||
offset_confirm_dur_ = source.offset_confirm_dur();
|
||||
decision_threshold_ = source.decision_threshold();
|
||||
min_decision_threshold_ = source.min_decision_threshold();
|
||||
fast_update_dur_ = source.fast_update_dur();
|
||||
sample_rate_ = source.sample_rate();
|
||||
min_fundamental_frequency_ = source.min_fundamental_frequency();
|
||||
max_fundamental_frequency_ = source.max_fundamental_frequency();
|
||||
contamination_rejection_period_ = source.contamination_rejection_period();
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -1,159 +0,0 @@
|
|||
// Copyright (c) 2013 The Chromium Authors. All rights reserved.
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CONTENT_BROWSER_SPEECH_ENDPOINTER_ENERGY_ENDPOINTER_PARAMS_H_
|
||||
#define CONTENT_BROWSER_SPEECH_ENDPOINTER_ENERGY_ENDPOINTER_PARAMS_H_
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
// Input parameters for the EnergyEndpointer class.
|
||||
class EnergyEndpointerParams {
|
||||
public:
|
||||
EnergyEndpointerParams();
|
||||
|
||||
void SetDefaults();
|
||||
|
||||
void operator=(const EnergyEndpointerParams& source);
|
||||
|
||||
// Accessors and mutators
|
||||
float frame_period() const { return frame_period_; }
|
||||
void set_frame_period(float frame_period) {
|
||||
frame_period_ = frame_period;
|
||||
}
|
||||
|
||||
float frame_duration() const { return frame_duration_; }
|
||||
void set_frame_duration(float frame_duration) {
|
||||
frame_duration_ = frame_duration;
|
||||
}
|
||||
|
||||
float endpoint_margin() const { return endpoint_margin_; }
|
||||
void set_endpoint_margin(float endpoint_margin) {
|
||||
endpoint_margin_ = endpoint_margin;
|
||||
}
|
||||
|
||||
float onset_window() const { return onset_window_; }
|
||||
void set_onset_window(float onset_window) { onset_window_ = onset_window; }
|
||||
|
||||
float speech_on_window() const { return speech_on_window_; }
|
||||
void set_speech_on_window(float speech_on_window) {
|
||||
speech_on_window_ = speech_on_window;
|
||||
}
|
||||
|
||||
float offset_window() const { return offset_window_; }
|
||||
void set_offset_window(float offset_window) {
|
||||
offset_window_ = offset_window;
|
||||
}
|
||||
|
||||
float onset_detect_dur() const { return onset_detect_dur_; }
|
||||
void set_onset_detect_dur(float onset_detect_dur) {
|
||||
onset_detect_dur_ = onset_detect_dur;
|
||||
}
|
||||
|
||||
float onset_confirm_dur() const { return onset_confirm_dur_; }
|
||||
void set_onset_confirm_dur(float onset_confirm_dur) {
|
||||
onset_confirm_dur_ = onset_confirm_dur;
|
||||
}
|
||||
|
||||
float on_maintain_dur() const { return on_maintain_dur_; }
|
||||
void set_on_maintain_dur(float on_maintain_dur) {
|
||||
on_maintain_dur_ = on_maintain_dur;
|
||||
}
|
||||
|
||||
float offset_confirm_dur() const { return offset_confirm_dur_; }
|
||||
void set_offset_confirm_dur(float offset_confirm_dur) {
|
||||
offset_confirm_dur_ = offset_confirm_dur;
|
||||
}
|
||||
|
||||
float decision_threshold() const { return decision_threshold_; }
|
||||
void set_decision_threshold(float decision_threshold) {
|
||||
decision_threshold_ = decision_threshold;
|
||||
}
|
||||
|
||||
float min_decision_threshold() const { return min_decision_threshold_; }
|
||||
void set_min_decision_threshold(float min_decision_threshold) {
|
||||
min_decision_threshold_ = min_decision_threshold;
|
||||
}
|
||||
|
||||
float fast_update_dur() const { return fast_update_dur_; }
|
||||
void set_fast_update_dur(float fast_update_dur) {
|
||||
fast_update_dur_ = fast_update_dur;
|
||||
}
|
||||
|
||||
float sample_rate() const { return sample_rate_; }
|
||||
void set_sample_rate(float sample_rate) { sample_rate_ = sample_rate; }
|
||||
|
||||
float min_fundamental_frequency() const { return min_fundamental_frequency_; }
|
||||
void set_min_fundamental_frequency(float min_fundamental_frequency) {
|
||||
min_fundamental_frequency_ = min_fundamental_frequency;
|
||||
}
|
||||
|
||||
float max_fundamental_frequency() const { return max_fundamental_frequency_; }
|
||||
void set_max_fundamental_frequency(float max_fundamental_frequency) {
|
||||
max_fundamental_frequency_ = max_fundamental_frequency;
|
||||
}
|
||||
|
||||
float contamination_rejection_period() const {
|
||||
return contamination_rejection_period_;
|
||||
}
|
||||
void set_contamination_rejection_period(
|
||||
float contamination_rejection_period) {
|
||||
contamination_rejection_period_ = contamination_rejection_period;
|
||||
}
|
||||
|
||||
private:
|
||||
float frame_period_; // Frame period
|
||||
float frame_duration_; // Window size
|
||||
float onset_window_; // Interval scanned for onset activity
|
||||
float speech_on_window_; // Inverval scanned for ongoing speech
|
||||
float offset_window_; // Interval scanned for offset evidence
|
||||
float offset_confirm_dur_; // Silence duration required to confirm offset
|
||||
float decision_threshold_; // Initial rms detection threshold
|
||||
float min_decision_threshold_; // Minimum rms detection threshold
|
||||
float fast_update_dur_; // Period for initial estimation of levels.
|
||||
float sample_rate_; // Expected sample rate.
|
||||
|
||||
// Time to add on either side of endpoint threshold crossings
|
||||
float endpoint_margin_;
|
||||
// Total dur within onset_window required to enter ONSET state
|
||||
float onset_detect_dur_;
|
||||
// Total on time within onset_window required to enter SPEECH_ON state
|
||||
float onset_confirm_dur_;
|
||||
// Minimum dur in SPEECH_ON state required to maintain ON state
|
||||
float on_maintain_dur_;
|
||||
// Minimum fundamental frequency for autocorrelation.
|
||||
float min_fundamental_frequency_;
|
||||
// Maximum fundamental frequency for autocorrelation.
|
||||
float max_fundamental_frequency_;
|
||||
// Period after start of user input that above threshold values are ignored.
|
||||
// This is to reject audio feedback contamination.
|
||||
float contamination_rejection_period_;
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif // CONTENT_BROWSER_SPEECH_ENDPOINTER_ENERGY_ENDPOINTER_PARAMS_H_
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
|
@ -1,34 +0,0 @@
|
|||
/* ====================================================================
|
||||
* Copyright (c) 2015 Alpha Cephei Inc. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY ALPHA CEPHEI INC. ``AS IS'' AND.
|
||||
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,.
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL ALPHA CEPHEI INC.
|
||||
* NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT.
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,.
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY.
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT.
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE.
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ====================================================================
|
||||
*
|
||||
*/
|
||||
|
||||
This directory contains generic US english acoustic model trained with
|
||||
latest sphinxtrain.
|
|
@ -1,12 +0,0 @@
|
|||
-lowerf 130
|
||||
-upperf 3700
|
||||
-nfilt 20
|
||||
-transform dct
|
||||
-lifter 22
|
||||
-feat 1s_c_d_dd
|
||||
-svspec 0-12/13-25/26-38
|
||||
-agc none
|
||||
-cmn current
|
||||
-varnorm no
|
||||
-cmninit 30.09,0.49,5.51,7.43,-2.39,-1.64,-4.71,0.03,-5.11,0.20,4.84,6.14,0.35
|
||||
-model ptm
|
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
|
@ -1,5 +0,0 @@
|
|||
<s> SIL
|
||||
</s> SIL
|
||||
<sil> SIL
|
||||
[NOISE] +NSN+
|
||||
[SPEECH] +SPN+
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1,88 +0,0 @@
|
|||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
MOCHITEST_MANIFESTS += ['test/mochitest.ini']
|
||||
|
||||
XPIDL_MODULE = 'dom_webspeechrecognition'
|
||||
|
||||
XPIDL_SOURCES = [
|
||||
'nsISpeechRecognitionService.idl'
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'SpeechGrammar.h',
|
||||
'SpeechGrammarList.h',
|
||||
'SpeechRecognition.h',
|
||||
'SpeechRecognitionAlternative.h',
|
||||
'SpeechRecognitionResult.h',
|
||||
'SpeechRecognitionResultList.h',
|
||||
'SpeechStreamListener.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_TEST_BACKEND']:
|
||||
EXPORTS.mozilla.dom += [
|
||||
'test/FakeSpeechRecognitionService.h',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
|
||||
EXPORTS.mozilla.dom += [
|
||||
'PocketSphinxSpeechRecognitionService.h',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'endpointer.cc',
|
||||
'energy_endpointer.cc',
|
||||
'energy_endpointer_params.cc',
|
||||
'SpeechGrammar.cpp',
|
||||
'SpeechGrammarList.cpp',
|
||||
'SpeechRecognition.cpp',
|
||||
'SpeechRecognitionAlternative.cpp',
|
||||
'SpeechRecognitionResult.cpp',
|
||||
'SpeechRecognitionResultList.cpp',
|
||||
'SpeechStreamListener.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_TEST_BACKEND']:
|
||||
SOURCES += [
|
||||
'test/FakeSpeechRecognitionService.cpp',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
|
||||
SOURCES += [
|
||||
'PocketSphinxSpeechRecognitionService.cpp',
|
||||
]
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/base',
|
||||
'/media/sphinxbase',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
|
||||
LOCAL_INCLUDES += [
|
||||
'/media/pocketsphinx',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_MODELS']:
|
||||
FINAL_TARGET_FILES.models.dict += [
|
||||
'models/dict/en-US.dic',
|
||||
'models/dict/en-US.dic.dmp',
|
||||
]
|
||||
FINAL_TARGET_FILES.models['en-US'] += [
|
||||
'models/en-US/feat.params',
|
||||
'models/en-US/mdef',
|
||||
'models/en-US/means',
|
||||
'models/en-US/mixture_weights',
|
||||
'models/en-US/noisedict',
|
||||
'models/en-US/sendump',
|
||||
'models/en-US/transition_matrices',
|
||||
'models/en-US/variances',
|
||||
]
|
||||
|
||||
include('/ipc/chromium/chromium-config.mozbuild')
|
||||
|
||||
FINAL_LIBRARY = 'xul'
|
||||
|
||||
if CONFIG['GNU_CXX']:
|
||||
CXXFLAGS += ['-Wno-error=shadow']
|
|
@ -1,43 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.idl"
|
||||
|
||||
%{C++
|
||||
#include "mozilla/WeakPtr.h"
|
||||
|
||||
namespace mozilla {
|
||||
class AudioSegment;
|
||||
namespace dom {
|
||||
class SpeechRecognition;
|
||||
class SpeechRecognitionResultList;
|
||||
class SpeechGrammarList;
|
||||
class SpeechGrammar;
|
||||
}
|
||||
}
|
||||
%}
|
||||
|
||||
native SpeechRecognitionWeakPtr(mozilla::WeakPtr<mozilla::dom::SpeechRecognition>);
|
||||
[ptr] native AudioSegmentPtr(mozilla::AudioSegment);
|
||||
[ptr] native SpeechGrammarPtr(mozilla::dom::SpeechGrammar);
|
||||
[ptr] native SpeechGrammarListPtr(mozilla::dom::SpeechGrammarList);
|
||||
|
||||
[uuid(6fcb6ee8-a6db-49ba-9f06-355d7ee18ea7)]
|
||||
interface nsISpeechGrammarCompilationCallback : nsISupports {
|
||||
void grammarCompilationEnd(in SpeechGrammarPtr grammarObject, in boolean success);
|
||||
};
|
||||
|
||||
[uuid(8e97f287-f322-44e8-8888-8344fa408ef8)]
|
||||
interface nsISpeechRecognitionService : nsISupports {
|
||||
void initialize(in SpeechRecognitionWeakPtr aSpeechRecognition);
|
||||
void processAudioSegment(in AudioSegmentPtr aAudioSegment, in long aSampleRate);
|
||||
void validateAndSetGrammarList(in SpeechGrammarPtr aSpeechGrammar, in nsISpeechGrammarCompilationCallback aCallback);
|
||||
void soundEnd();
|
||||
void abort();
|
||||
};
|
||||
|
||||
%{C++
|
||||
#define NS_SPEECH_RECOGNITION_SERVICE_CONTRACTID_PREFIX "@mozilla.org/webspeech/service;1?name="
|
||||
%}
|
|
@ -1,119 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
|
||||
#include "FakeSpeechRecognitionService.h"
|
||||
#include "MediaPrefs.h"
|
||||
|
||||
#include "SpeechRecognition.h"
|
||||
#include "SpeechRecognitionAlternative.h"
|
||||
#include "SpeechRecognitionResult.h"
|
||||
#include "SpeechRecognitionResultList.h"
|
||||
#include "nsIObserverService.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
using namespace dom;
|
||||
|
||||
NS_IMPL_ISUPPORTS(FakeSpeechRecognitionService, nsISpeechRecognitionService, nsIObserver)
|
||||
|
||||
FakeSpeechRecognitionService::FakeSpeechRecognitionService()
|
||||
{
|
||||
}
|
||||
|
||||
FakeSpeechRecognitionService::~FakeSpeechRecognitionService()
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeSpeechRecognitionService::Initialize(WeakPtr<SpeechRecognition> aSpeechRecognition)
|
||||
{
|
||||
mRecognition = aSpeechRecognition;
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
obs->AddObserver(this, SPEECH_RECOGNITION_TEST_EVENT_REQUEST_TOPIC, false);
|
||||
obs->AddObserver(this, SPEECH_RECOGNITION_TEST_END_TOPIC, false);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeSpeechRecognitionService::ProcessAudioSegment(AudioSegment* aAudioSegment, int32_t aSampleRate)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeSpeechRecognitionService::SoundEnd()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeSpeechRecognitionService::ValidateAndSetGrammarList(mozilla::dom::SpeechGrammar*, nsISpeechGrammarCompilationCallback*)
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeSpeechRecognitionService::Abort()
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeSpeechRecognitionService::Observe(nsISupports* aSubject, const char* aTopic, const char16_t* aData)
|
||||
{
|
||||
MOZ_ASSERT(MediaPrefs::WebSpeechFakeRecognitionService(),
|
||||
"Got request to fake recognition service event, but "
|
||||
TEST_PREFERENCE_FAKE_RECOGNITION_SERVICE " is not set");
|
||||
|
||||
if (!strcmp(aTopic, SPEECH_RECOGNITION_TEST_END_TOPIC)) {
|
||||
nsCOMPtr<nsIObserverService> obs = services::GetObserverService();
|
||||
obs->RemoveObserver(this, SPEECH_RECOGNITION_TEST_EVENT_REQUEST_TOPIC);
|
||||
obs->RemoveObserver(this, SPEECH_RECOGNITION_TEST_END_TOPIC);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
const nsDependentString eventName = nsDependentString(aData);
|
||||
|
||||
if (eventName.EqualsLiteral("EVENT_RECOGNITIONSERVICE_ERROR")) {
|
||||
mRecognition->DispatchError(SpeechRecognition::EVENT_RECOGNITIONSERVICE_ERROR,
|
||||
SpeechRecognitionErrorCode::Network, // TODO different codes?
|
||||
NS_LITERAL_STRING("RECOGNITIONSERVICE_ERROR test event"));
|
||||
|
||||
} else if (eventName.EqualsLiteral("EVENT_RECOGNITIONSERVICE_FINAL_RESULT")) {
|
||||
RefPtr<SpeechEvent> event =
|
||||
new SpeechEvent(mRecognition,
|
||||
SpeechRecognition::EVENT_RECOGNITIONSERVICE_FINAL_RESULT);
|
||||
|
||||
event->mRecognitionResultList = BuildMockResultList();
|
||||
NS_DispatchToMainThread(event);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
SpeechRecognitionResultList*
|
||||
FakeSpeechRecognitionService::BuildMockResultList()
|
||||
{
|
||||
SpeechRecognitionResultList* resultList = new SpeechRecognitionResultList(mRecognition);
|
||||
SpeechRecognitionResult* result = new SpeechRecognitionResult(mRecognition);
|
||||
if (0 < mRecognition->MaxAlternatives()) {
|
||||
SpeechRecognitionAlternative* alternative = new SpeechRecognitionAlternative(mRecognition);
|
||||
|
||||
alternative->mTranscript = NS_LITERAL_STRING("Mock final result");
|
||||
alternative->mConfidence = 0.0f;
|
||||
|
||||
result->mItems.AppendElement(alternative);
|
||||
}
|
||||
resultList->mItems.AppendElement(result);
|
||||
|
||||
return resultList;
|
||||
}
|
||||
|
||||
} // namespace mozilla
|
|
@ -1,38 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef mozilla_dom_FakeSpeechRecognitionService_h
|
||||
#define mozilla_dom_FakeSpeechRecognitionService_h
|
||||
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsISpeechRecognitionService.h"
|
||||
|
||||
#define NS_FAKE_SPEECH_RECOGNITION_SERVICE_CID \
|
||||
{0x48c345e7, 0x9929, 0x4f9a, {0xa5, 0x63, 0xf4, 0x78, 0x22, 0x2d, 0xab, 0xcd}};
|
||||
|
||||
namespace mozilla {
|
||||
|
||||
class FakeSpeechRecognitionService : public nsISpeechRecognitionService,
|
||||
public nsIObserver
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISPEECHRECOGNITIONSERVICE
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
FakeSpeechRecognitionService();
|
||||
|
||||
private:
|
||||
virtual ~FakeSpeechRecognitionService();
|
||||
|
||||
WeakPtr<dom::SpeechRecognition> mRecognition;
|
||||
dom::SpeechRecognitionResultList* BuildMockResultList();
|
||||
};
|
||||
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -1,181 +0,0 @@
|
|||
"use strict";
|
||||
|
||||
const DEFAULT_AUDIO_SAMPLE_FILE = "hello.ogg";
|
||||
const SPEECH_RECOGNITION_TEST_REQUEST_EVENT_TOPIC = "SpeechRecognitionTest:RequestEvent";
|
||||
const SPEECH_RECOGNITION_TEST_END_TOPIC = "SpeechRecognitionTest:End";
|
||||
|
||||
var errorCodes = {
|
||||
NO_SPEECH : "no-speech",
|
||||
ABORTED : "aborted",
|
||||
AUDIO_CAPTURE : "audio-capture",
|
||||
NETWORK : "network",
|
||||
NOT_ALLOWED : "not-allowed",
|
||||
SERVICE_NOT_ALLOWED : "service-not-allowed",
|
||||
BAD_GRAMMAR : "bad-grammar",
|
||||
LANGUAGE_NOT_SUPPORTED : "language-not-supported"
|
||||
};
|
||||
|
||||
var Services = SpecialPowers.Cu.import("resource://gre/modules/Services.jsm").Services;
|
||||
|
||||
function EventManager(sr) {
|
||||
var self = this;
|
||||
var nEventsExpected = 0;
|
||||
self.eventsReceived = [];
|
||||
|
||||
var allEvents = [
|
||||
"audiostart",
|
||||
"soundstart",
|
||||
"speechstart",
|
||||
"speechend",
|
||||
"soundend",
|
||||
"audioend",
|
||||
"result",
|
||||
"nomatch",
|
||||
"error",
|
||||
"start",
|
||||
"end"
|
||||
];
|
||||
|
||||
var eventDependencies = {
|
||||
"speechend": "speechstart",
|
||||
"soundend": "soundstart",
|
||||
"audioend": "audiostart"
|
||||
};
|
||||
|
||||
var isDone = false;
|
||||
|
||||
// set up grammar
|
||||
var sgl = new SpeechGrammarList();
|
||||
sgl.addFromString("#JSGF V1.0; grammar test; public <simple> = hello ;", 1);
|
||||
sr.grammars = sgl;
|
||||
|
||||
// AUDIO_DATA events are asynchronous,
|
||||
// so we queue events requested while they are being
|
||||
// issued to make them seem synchronous
|
||||
var isSendingAudioData = false;
|
||||
var queuedEventRequests = [];
|
||||
|
||||
// register default handlers
|
||||
for (var i = 0; i < allEvents.length; i++) {
|
||||
(function (eventName) {
|
||||
sr["on" + eventName] = function (evt) {
|
||||
var message = "unexpected event: " + eventName;
|
||||
if (eventName == "error") {
|
||||
message += " -- " + evt.message;
|
||||
}
|
||||
|
||||
ok(false, message);
|
||||
if (self.doneFunc && !isDone) {
|
||||
isDone = true;
|
||||
self.doneFunc();
|
||||
}
|
||||
};
|
||||
})(allEvents[i]);
|
||||
}
|
||||
|
||||
self.expect = function EventManager_expect(eventName, cb) {
|
||||
nEventsExpected++;
|
||||
|
||||
sr["on" + eventName] = function(evt) {
|
||||
self.eventsReceived.push(eventName);
|
||||
ok(true, "received event " + eventName);
|
||||
|
||||
var dep = eventDependencies[eventName];
|
||||
if (dep) {
|
||||
ok(self.eventsReceived.indexOf(dep) >= 0,
|
||||
eventName + " must come after " + dep);
|
||||
}
|
||||
|
||||
cb && cb(evt, sr);
|
||||
if (self.doneFunc && !isDone &&
|
||||
nEventsExpected === self.eventsReceived.length) {
|
||||
isDone = true;
|
||||
self.doneFunc();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.start = function EventManager_start() {
|
||||
isSendingAudioData = true;
|
||||
var audioTag = document.createElement("audio");
|
||||
audioTag.src = self.audioSampleFile;
|
||||
|
||||
var stream = audioTag.mozCaptureStreamUntilEnded();
|
||||
audioTag.addEventListener("ended", function() {
|
||||
info("Sample stream ended, requesting queued events");
|
||||
isSendingAudioData = false;
|
||||
while (queuedEventRequests.length) {
|
||||
self.requestFSMEvent(queuedEventRequests.shift());
|
||||
}
|
||||
});
|
||||
|
||||
audioTag.play();
|
||||
sr.start(stream);
|
||||
}
|
||||
|
||||
self.requestFSMEvent = function EventManager_requestFSMEvent(eventName) {
|
||||
if (isSendingAudioData) {
|
||||
info("Queuing event " + eventName + " until we're done sending audio data");
|
||||
queuedEventRequests.push(eventName);
|
||||
return;
|
||||
}
|
||||
|
||||
info("requesting " + eventName);
|
||||
Services.obs.notifyObservers(null,
|
||||
SPEECH_RECOGNITION_TEST_REQUEST_EVENT_TOPIC,
|
||||
eventName);
|
||||
}
|
||||
|
||||
self.requestTestEnd = function EventManager_requestTestEnd() {
|
||||
Services.obs.notifyObservers(null, SPEECH_RECOGNITION_TEST_END_TOPIC, null);
|
||||
}
|
||||
}
|
||||
|
||||
function buildResultCallback(transcript) {
|
||||
return (function(evt) {
|
||||
is(evt.results[0][0].transcript, transcript, "expect correct transcript");
|
||||
});
|
||||
}
|
||||
|
||||
function buildErrorCallback(errcode) {
|
||||
return (function(err) {
|
||||
is(err.error, errcode, "expect correct error code");
|
||||
});
|
||||
}
|
||||
|
||||
function performTest(options) {
|
||||
var prefs = options.prefs;
|
||||
|
||||
prefs.unshift(
|
||||
["media.webspeech.recognition.enable", true],
|
||||
["media.webspeech.test.enable", true]
|
||||
);
|
||||
|
||||
SpecialPowers.pushPrefEnv({set: prefs}, function() {
|
||||
var sr = new SpeechRecognition();
|
||||
var em = new EventManager(sr);
|
||||
|
||||
for (var eventName in options.expectedEvents) {
|
||||
var cb = options.expectedEvents[eventName];
|
||||
em.expect(eventName, cb);
|
||||
}
|
||||
|
||||
em.doneFunc = function() {
|
||||
em.requestTestEnd();
|
||||
if (options.doneFunc) {
|
||||
options.doneFunc();
|
||||
}
|
||||
}
|
||||
|
||||
em.audioSampleFile = DEFAULT_AUDIO_SAMPLE_FILE;
|
||||
if (options.audioSampleFile) {
|
||||
em.audioSampleFile = options.audioSampleFile;
|
||||
}
|
||||
|
||||
em.start();
|
||||
|
||||
for (var i = 0; i < options.eventsToRequest.length; i++) {
|
||||
em.requestFSMEvent(options.eventsToRequest[i]);
|
||||
}
|
||||
});
|
||||
}
|
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
Cache-Control: no-store
|
|
@ -1,21 +0,0 @@
|
|||
[DEFAULT]
|
||||
tags=msg
|
||||
subsuite = media
|
||||
support-files =
|
||||
head.js
|
||||
hello.ogg
|
||||
hello.ogg^headers^
|
||||
silence.ogg
|
||||
silence.ogg^headers^
|
||||
[test_abort.html]
|
||||
skip-if = toolkit == 'android' # bug 1037287
|
||||
[test_audio_capture_error.html]
|
||||
[test_call_start_from_end_handler.html]
|
||||
tags=capturestream
|
||||
skip-if = (android_version == '18' && debug) # bug 967606
|
||||
[test_nested_eventloop.html]
|
||||
skip-if = toolkit == 'android'
|
||||
[test_preference_enable.html]
|
||||
[test_recognition_service_error.html]
|
||||
[test_success_without_recognition_service.html]
|
||||
[test_timeout.html]
|
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
Cache-Control: no-store
|
|
@ -1,71 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=650295
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 650295 -- Call abort from inside handlers</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
// Abort inside event handlers, should't get a
|
||||
// result after that
|
||||
|
||||
var nextEventIdx = 0;
|
||||
var eventsToAbortOn = [
|
||||
"start",
|
||||
"audiostart",
|
||||
"speechstart",
|
||||
"speechend",
|
||||
"audioend"
|
||||
];
|
||||
|
||||
function doNextTest() {
|
||||
var nextEvent = eventsToAbortOn[nextEventIdx];
|
||||
var expectedEvents = {
|
||||
"start": null,
|
||||
"audiostart": null,
|
||||
"audioend": null,
|
||||
"end": null
|
||||
};
|
||||
|
||||
if (nextEventIdx >= eventsToAbortOn.indexOf("speechstart")) {
|
||||
expectedEvents["speechstart"] = null;
|
||||
}
|
||||
|
||||
if (nextEventIdx >= eventsToAbortOn.indexOf("speechend")) {
|
||||
expectedEvents["speechend"] = null;
|
||||
}
|
||||
|
||||
info("Aborting on " + nextEvent);
|
||||
expectedEvents[nextEvent] = function(evt, sr) {
|
||||
sr.abort();
|
||||
};
|
||||
|
||||
nextEventIdx++;
|
||||
|
||||
performTest({
|
||||
eventsToRequest: [],
|
||||
expectedEvents: expectedEvents,
|
||||
doneFunc: (nextEventIdx < eventsToAbortOn.length) ? doNextTest : SimpleTest.finish,
|
||||
prefs: [["media.webspeech.test.fake_fsm_events", true], ["media.webspeech.test.fake_recognition_service", true]]
|
||||
});
|
||||
}
|
||||
|
||||
doNextTest();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,40 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=650295
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 650295 -- Behavior on audio error</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
performTest({
|
||||
eventsToRequest: ['EVENT_AUDIO_ERROR'],
|
||||
expectedEvents: {
|
||||
'start': null,
|
||||
'audiostart': null,
|
||||
'speechstart': null,
|
||||
'speechend': null,
|
||||
'audioend': null,
|
||||
'error': buildErrorCallback(errorCodes.AUDIO_CAPTURE),
|
||||
'end': null
|
||||
},
|
||||
doneFunc: SimpleTest.finish,
|
||||
prefs: [["media.webspeech.test.fake_fsm_events", true], ["media.webspeech.test.fake_recognition_service", true]]
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,100 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=650295
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 650295 -- Restart recognition from end handler</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
function createAudioStream() {
|
||||
var audioTag = document.createElement("audio");
|
||||
audioTag.src = DEFAULT_AUDIO_SAMPLE_FILE;
|
||||
|
||||
var stream = audioTag.mozCaptureStreamUntilEnded();
|
||||
audioTag.play();
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
var done = false;
|
||||
function endHandler(evt, sr) {
|
||||
if (done) {
|
||||
SimpleTest.finish();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
var stream = createAudioStream();
|
||||
sr.start(stream); // shouldn't fail
|
||||
} catch (err) {
|
||||
ok(false, "Failed to start() from end() callback");
|
||||
}
|
||||
|
||||
// calling start() may cause some callbacks to fire, but we're
|
||||
// no longer interested in them, except for onend, which is where
|
||||
// we'll conclude the test.
|
||||
sr.onstart = null;
|
||||
sr.onaudiostart = null;
|
||||
sr.onspeechstart = null;
|
||||
sr.onspeechend = null;
|
||||
sr.onaudioend = null;
|
||||
sr.onresult = null;
|
||||
|
||||
// FIXME(ggp) the state transition caused by start() is async,
|
||||
// but abort() is sync (see bug 1055093). until we normalize
|
||||
// state transitions, we need to setTimeout here to make sure
|
||||
// abort() finds the speech recognition object in the correct
|
||||
// state (namely, STATE_STARTING).
|
||||
setTimeout(function() {
|
||||
sr.abort();
|
||||
done = true;
|
||||
});
|
||||
|
||||
info("Successfully start() from end() callback");
|
||||
}
|
||||
|
||||
function expectExceptionHandler(evt, sr) {
|
||||
try {
|
||||
sr.start(createAudioStream());
|
||||
} catch (err) {
|
||||
is(err.name, "InvalidStateError");
|
||||
return;
|
||||
}
|
||||
|
||||
ok(false, "Calling start() didn't raise InvalidStateError");
|
||||
}
|
||||
|
||||
performTest({
|
||||
eventsToRequest: [
|
||||
'EVENT_RECOGNITIONSERVICE_FINAL_RESULT'
|
||||
],
|
||||
expectedEvents: {
|
||||
'start': expectExceptionHandler,
|
||||
'audiostart': expectExceptionHandler,
|
||||
'speechstart': expectExceptionHandler,
|
||||
'speechend': expectExceptionHandler,
|
||||
'audioend': expectExceptionHandler,
|
||||
'result': buildResultCallback("Mock final result"),
|
||||
'end': endHandler,
|
||||
},
|
||||
prefs: [["media.webspeech.test.fake_fsm_events", true], ["media.webspeech.test.fake_recognition_service", true]]
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,81 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=650295
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 650295 -- Spin the event loop from inside a callback</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
/*
|
||||
* SpecialPowers.spinEventLoop can be used to spin the event loop, causing
|
||||
* queued SpeechEvents (such as those created by calls to start(), stop()
|
||||
* or abort()) to be processed immediately.
|
||||
* When this is done from inside DOM event handlers, it is possible to
|
||||
* cause reentrancy in our C++ code, which we should be able to withstand.
|
||||
*/
|
||||
function abortAndSpinEventLoop(evt, sr) {
|
||||
sr.abort();
|
||||
SpecialPowers.spinEventLoop(window);
|
||||
}
|
||||
function doneFunc() {
|
||||
// Trigger gc now and wait some time to make sure this test gets the blame
|
||||
// for any assertions caused by spinning the event loop.
|
||||
//
|
||||
// NB - The assertions should be gone, but this looks too scary to touch
|
||||
// during batch cleanup.
|
||||
var count = 0, GC_COUNT = 4;
|
||||
|
||||
function triggerGCOrFinish() {
|
||||
SpecialPowers.gc();
|
||||
count++;
|
||||
|
||||
if (count == GC_COUNT) {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < GC_COUNT; i++) {
|
||||
setTimeout(triggerGCOrFinish, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* We start by performing a normal start, then abort from the audiostart
|
||||
* callback and force the EVENT_ABORT to be processed while still inside
|
||||
* the event handler. This causes the recording to stop, which raises
|
||||
* the audioend and (later on) end events.
|
||||
* Then, we abort (once again spinning the event loop) from the audioend
|
||||
* handler, attempting to cause a re-entry into the abort code. This second
|
||||
* call should be ignored, and we get the end callback and finish.
|
||||
*/
|
||||
|
||||
performTest({
|
||||
eventsToRequest: [],
|
||||
expectedEvents: {
|
||||
"audiostart": abortAndSpinEventLoop,
|
||||
"audioend": abortAndSpinEventLoop,
|
||||
"end": null
|
||||
},
|
||||
doneFunc: doneFunc,
|
||||
prefs: [["media.webspeech.test.fake_fsm_events", true],
|
||||
["media.webspeech.test.fake_recognition_service", true]]
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,43 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=650295
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 650295 -- No objects should be visible with preference disabled</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv({
|
||||
set: [["media.webspeech.recognition.enable", false]]
|
||||
}, function() {
|
||||
var objects = [
|
||||
"SpeechRecognition",
|
||||
"SpeechGrammar",
|
||||
"SpeechRecognitionResult",
|
||||
"SpeechRecognitionResultList",
|
||||
"SpeechRecognitionAlternative"
|
||||
];
|
||||
|
||||
for (var i = 0; i < objects.length; i++) {
|
||||
is(window[objects[i]], undefined,
|
||||
objects[i] + " should be undefined with pref off");
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,43 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=650295
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 650295 -- Behavior on recognition service error</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
performTest({
|
||||
eventsToRequest: [
|
||||
'EVENT_RECOGNITIONSERVICE_ERROR'
|
||||
],
|
||||
expectedEvents: {
|
||||
'start': null,
|
||||
'audiostart': null,
|
||||
'speechstart': null,
|
||||
'speechend': null,
|
||||
'audioend': null,
|
||||
'error': buildErrorCallback(errorCodes.NETWORK),
|
||||
'end': null
|
||||
},
|
||||
doneFunc: SimpleTest.finish,
|
||||
prefs: [["media.webspeech.test.fake_fsm_events", true], ["media.webspeech.test.fake_recognition_service", true]]
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,43 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=650295
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 650295 -- Success with fake recognition service</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
performTest({
|
||||
eventsToRequest: [
|
||||
'EVENT_RECOGNITIONSERVICE_FINAL_RESULT'
|
||||
],
|
||||
expectedEvents: {
|
||||
'start': null,
|
||||
'audiostart': null,
|
||||
'speechstart': null,
|
||||
'speechend': null,
|
||||
'audioend': null,
|
||||
'result': buildResultCallback("Mock final result"),
|
||||
'end': null
|
||||
},
|
||||
doneFunc:SimpleTest.finish,
|
||||
prefs: [["media.webspeech.test.fake_fsm_events", true], ["media.webspeech.test.fake_recognition_service", true]]
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,40 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=650295
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 650295 -- Timeout for user speech</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
<script type="application/javascript" src="head.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="text/javascript">
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
performTest({
|
||||
eventsToRequest: [],
|
||||
expectedEvents: {
|
||||
"start": null,
|
||||
"audiostart": null,
|
||||
"audioend": null,
|
||||
"error": buildErrorCallback(errorCodes.NO_SPEECH),
|
||||
"end": null
|
||||
},
|
||||
doneFunc: SimpleTest.finish,
|
||||
audioSampleFile: "silence.ogg",
|
||||
prefs: [["media.webspeech.test.fake_fsm_events", true], ["media.webspeech.test.fake_recognition_service", true]]
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -3,56 +3,44 @@
|
|||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH']:
|
||||
MOCHITEST_MANIFESTS += [
|
||||
'test/mochitest.ini',
|
||||
'test/startup/mochitest.ini',
|
||||
]
|
||||
XPIDL_MODULE = 'dom_webspeechsynth'
|
||||
|
||||
XPIDL_MODULE = 'dom_webspeechsynth'
|
||||
XPIDL_SOURCES += [
|
||||
'nsISpeechService.idl',
|
||||
'nsISynthVoiceRegistry.idl'
|
||||
]
|
||||
|
||||
XPIDL_SOURCES += [
|
||||
'nsISpeechService.idl',
|
||||
'nsISynthVoiceRegistry.idl'
|
||||
]
|
||||
EXPORTS.mozilla.dom += [
|
||||
'ipc/SpeechSynthesisChild.h',
|
||||
'ipc/SpeechSynthesisParent.h',
|
||||
'nsSpeechTask.h',
|
||||
'nsSynthVoiceRegistry.h',
|
||||
'SpeechSynthesis.h',
|
||||
'SpeechSynthesisUtterance.h',
|
||||
'SpeechSynthesisVoice.h',
|
||||
]
|
||||
|
||||
EXPORTS.mozilla.dom += [
|
||||
'ipc/SpeechSynthesisChild.h',
|
||||
'ipc/SpeechSynthesisParent.h',
|
||||
'nsSpeechTask.h',
|
||||
'nsSynthVoiceRegistry.h',
|
||||
'SpeechSynthesis.h',
|
||||
'SpeechSynthesisUtterance.h',
|
||||
'SpeechSynthesisVoice.h',
|
||||
]
|
||||
SOURCES += [
|
||||
'ipc/SpeechSynthesisChild.cpp',
|
||||
'ipc/SpeechSynthesisParent.cpp',
|
||||
'nsSpeechTask.cpp',
|
||||
'nsSynthVoiceRegistry.cpp',
|
||||
'SpeechSynthesis.cpp',
|
||||
'SpeechSynthesisUtterance.cpp',
|
||||
'SpeechSynthesisVoice.cpp',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'ipc/SpeechSynthesisChild.cpp',
|
||||
'ipc/SpeechSynthesisParent.cpp',
|
||||
'nsSpeechTask.cpp',
|
||||
'nsSynthVoiceRegistry.cpp',
|
||||
'SpeechSynthesis.cpp',
|
||||
'SpeechSynthesisUtterance.cpp',
|
||||
'SpeechSynthesisVoice.cpp',
|
||||
]
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
DIRS += ['windows']
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_TEST_BACKEND']:
|
||||
SOURCES += [
|
||||
'test/FakeSynthModule.cpp',
|
||||
'test/nsFakeSynthServices.cpp'
|
||||
]
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
DIRS += ['cocoa']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'windows':
|
||||
DIRS += ['windows']
|
||||
if CONFIG['MOZ_SYNTH_SPEECHD']:
|
||||
DIRS += ['speechd']
|
||||
|
||||
if CONFIG['MOZ_WIDGET_TOOLKIT'] == 'cocoa':
|
||||
DIRS += ['cocoa']
|
||||
|
||||
if CONFIG['MOZ_SYNTH_SPEECHD']:
|
||||
DIRS += ['speechd']
|
||||
|
||||
if CONFIG['MOZ_SYNTH_PICO']:
|
||||
DIRS += ['pico']
|
||||
if CONFIG['MOZ_SYNTH_PICO']:
|
||||
DIRS += ['pico']
|
||||
|
||||
IPDL_SOURCES += [
|
||||
'ipc/PSpeechSynthesis.ipdl',
|
||||
|
|
|
@ -1,55 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "mozilla/ModuleUtils.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
|
||||
#include "nsFakeSynthServices.h"
|
||||
|
||||
using namespace mozilla::dom;
|
||||
|
||||
#define FAKESYNTHSERVICE_CID \
|
||||
{0xe7d52d9e, 0xc148, 0x47d8, {0xab, 0x2a, 0x95, 0xd7, 0xf4, 0x0e, 0xa5, 0x3d}}
|
||||
|
||||
#define FAKESYNTHSERVICE_CONTRACTID "@mozilla.org/fakesynth;1"
|
||||
|
||||
// Defines nsFakeSynthServicesConstructor
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(nsFakeSynthServices,
|
||||
nsFakeSynthServices::GetInstanceForService)
|
||||
|
||||
// Defines kFAKESYNTHSERVICE_CID
|
||||
NS_DEFINE_NAMED_CID(FAKESYNTHSERVICE_CID);
|
||||
|
||||
static const mozilla::Module::CIDEntry kCIDs[] = {
|
||||
{ &kFAKESYNTHSERVICE_CID, true, nullptr, nsFakeSynthServicesConstructor },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::ContractIDEntry kContracts[] = {
|
||||
{ FAKESYNTHSERVICE_CONTRACTID, &kFAKESYNTHSERVICE_CID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static const mozilla::Module::CategoryEntry kCategories[] = {
|
||||
{ "speech-synth-started", "Fake Speech Synth", FAKESYNTHSERVICE_CONTRACTID },
|
||||
{ nullptr }
|
||||
};
|
||||
|
||||
static void
|
||||
UnloadFakeSynthmodule()
|
||||
{
|
||||
nsFakeSynthServices::Shutdown();
|
||||
}
|
||||
|
||||
static const mozilla::Module kModule = {
|
||||
mozilla::Module::kVersion,
|
||||
kCIDs,
|
||||
kContracts,
|
||||
kCategories,
|
||||
nullptr,
|
||||
nullptr,
|
||||
UnloadFakeSynthmodule
|
||||
};
|
||||
|
||||
NSMODULE_DEFN(fakesynth) = &kModule;
|
|
@ -1,91 +0,0 @@
|
|||
function synthTestQueue(aTestArgs, aEndFunc) {
|
||||
var utterances = [];
|
||||
for (var i in aTestArgs) {
|
||||
var uargs = aTestArgs[i][0];
|
||||
var win = uargs.win || window;
|
||||
var u = new win.SpeechSynthesisUtterance(uargs.text);
|
||||
|
||||
if (uargs.args) {
|
||||
for (var attr in uargs.args)
|
||||
u[attr] = uargs.args[attr];
|
||||
}
|
||||
|
||||
function onend_handler(e) {
|
||||
is(e.target, utterances.shift(), "Target matches utterances");
|
||||
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking.");
|
||||
|
||||
if (utterances.length) {
|
||||
ok(speechSynthesis.pending, "other utterances queued");
|
||||
} else {
|
||||
ok(!speechSynthesis.pending, "queue is empty, nothing pending.");
|
||||
if (aEndFunc)
|
||||
aEndFunc();
|
||||
}
|
||||
}
|
||||
|
||||
u.addEventListener('start',
|
||||
(function (expectedUri) {
|
||||
return function (e) {
|
||||
if (expectedUri) {
|
||||
var chosenVoice = SpecialPowers.wrap(e).target.chosenVoiceURI;
|
||||
is(chosenVoice, expectedUri, "Incorrect URI is used");
|
||||
}
|
||||
};
|
||||
})(aTestArgs[i][1] ? aTestArgs[i][1].uri : null));
|
||||
|
||||
u.addEventListener('end', onend_handler);
|
||||
u.addEventListener('error', onend_handler);
|
||||
|
||||
u.addEventListener('error',
|
||||
(function (expectedError) {
|
||||
return function onerror_handler(e) {
|
||||
ok(expectedError, "Error in speech utterance '" + e.target.text + "'");
|
||||
};
|
||||
})(aTestArgs[i][1] ? aTestArgs[i][1].err : false));
|
||||
|
||||
utterances.push(u);
|
||||
win.speechSynthesis.speak(u);
|
||||
}
|
||||
|
||||
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking yet.");
|
||||
ok(speechSynthesis.pending, "speechSynthesis has an utterance queued.");
|
||||
}
|
||||
|
||||
function loadFrame(frameId) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
var frame = document.getElementById(frameId);
|
||||
frame.addEventListener('load', function (e) {
|
||||
frame.contentWindow.document.title = frameId;
|
||||
resolve(frame);
|
||||
});
|
||||
frame.src = 'data:text/html,' + encodeURI('<html><head></head><body></body></html>');
|
||||
});
|
||||
}
|
||||
|
||||
function waitForVoices(win) {
|
||||
return new Promise(resolve => {
|
||||
function resolver() {
|
||||
if (win.speechSynthesis.getVoices().length) {
|
||||
win.speechSynthesis.removeEventListener('voiceschanged', resolver);
|
||||
resolve();
|
||||
}
|
||||
}
|
||||
|
||||
win.speechSynthesis.addEventListener('voiceschanged', resolver);
|
||||
resolver();
|
||||
});
|
||||
}
|
||||
|
||||
function loadSpeechTest(fileName, prefs, frameId="testFrame") {
|
||||
loadFrame(frameId).then(frame => {
|
||||
waitForVoices(frame.contentWindow).then(
|
||||
() => document.getElementById("testFrame").src = fileName);
|
||||
});
|
||||
}
|
||||
|
||||
function testSynthState(win, expectedState) {
|
||||
for (var attr in expectedState) {
|
||||
is(win.speechSynthesis[attr], expectedState[attr],
|
||||
win.document.title + ": '" + attr + '" does not match');
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<script type="application/javascript">
|
||||
var frameUnloaded = function() {
|
||||
var u = new SpeechSynthesisUtterance('hi');
|
||||
u.addEventListener('end', function () {
|
||||
parent.ok(true, 'Successfully spoke utterance from new frame.');
|
||||
parent.onDone();
|
||||
});
|
||||
speechSynthesis.speak(u);
|
||||
}
|
||||
addEventListener('pageshow', function onshow(evt) {
|
||||
var u = new SpeechSynthesisUtterance('hello');
|
||||
u.lang = 'it-IT-noend';
|
||||
u.addEventListener('start', function() {
|
||||
location =
|
||||
'data:text/html,<html><body onpageshow="' +
|
||||
frameUnloaded.toSource() + '()"></body></html>';
|
||||
});
|
||||
speechSynthesis.speak(u);
|
||||
});
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
</body>
|
||||
</html>
|
|
@ -1,69 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1188099
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1188099: Global queue should correctly schedule utterances</title>
|
||||
<script type="application/javascript">
|
||||
window.SimpleTest = parent.SimpleTest;
|
||||
window.info = parent.info;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
window.todo = parent.todo;
|
||||
</script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188099">Mozilla Bug 1188099</a>
|
||||
<iframe id="frame1"></iframe>
|
||||
<iframe id="frame2"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
Promise.all([loadFrame('frame1'), loadFrame('frame2')]).then(function ([frame1, frame2]) {
|
||||
var win1 = frame1.contentWindow;
|
||||
var win2 = frame2.contentWindow;
|
||||
var utterance1 = new win1.SpeechSynthesisUtterance("hello, losers");
|
||||
var utterance2 = new win1.SpeechSynthesisUtterance("hello, losers three");
|
||||
var utterance3 = new win2.SpeechSynthesisUtterance("hello, losers too");
|
||||
var eventOrder = ['start1', 'end1', 'start3', 'end3', 'start2', 'end2'];
|
||||
utterance1.addEventListener('start', function(e) {
|
||||
is(eventOrder.shift(), 'start1', 'start1');
|
||||
testSynthState(win1, { speaking: true, pending: true });
|
||||
testSynthState(win2, { speaking: true, pending: true });
|
||||
});
|
||||
utterance1.addEventListener('end', function(e) {
|
||||
is(eventOrder.shift(), 'end1', 'end1');
|
||||
});
|
||||
utterance3.addEventListener('start', function(e) {
|
||||
is(eventOrder.shift(), 'start3', 'start3');
|
||||
testSynthState(win1, { speaking: true, pending: true });
|
||||
testSynthState(win2, { speaking: true, pending: false });
|
||||
});
|
||||
utterance3.addEventListener('end', function(e) {
|
||||
is(eventOrder.shift(), 'end3', 'end3');
|
||||
});
|
||||
utterance2.addEventListener('start', function(e) {
|
||||
is(eventOrder.shift(), 'start2', 'start2');
|
||||
testSynthState(win1, { speaking: true, pending: false });
|
||||
testSynthState(win2, { speaking: true, pending: false });
|
||||
});
|
||||
utterance2.addEventListener('end', function(e) {
|
||||
is(eventOrder.shift(), 'end2', 'end2');
|
||||
testSynthState(win1, { speaking: false, pending: false });
|
||||
testSynthState(win2, { speaking: false, pending: false });
|
||||
SimpleTest.finish();
|
||||
});
|
||||
win1.speechSynthesis.speak(utterance1);
|
||||
win1.speechSynthesis.speak(utterance2);
|
||||
win2.speechSynthesis.speak(utterance3);
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,88 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1188099
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1188099: Calling cancel() should work correctly with global queue</title>
|
||||
<script type="application/javascript">
|
||||
window.SimpleTest = parent.SimpleTest;
|
||||
window.info = parent.info;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
window.todo = parent.todo;
|
||||
</script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188099">Mozilla Bug 1188099</a>
|
||||
<iframe id="frame1"></iframe>
|
||||
<iframe id="frame2"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
Promise.all([loadFrame('frame1'), loadFrame('frame2')]).then(function ([frame1, frame2]) {
|
||||
var win1 = frame1.contentWindow;
|
||||
var win2 = frame2.contentWindow;
|
||||
|
||||
var utterance1 = new win1.SpeechSynthesisUtterance(
|
||||
"u1: Donec ac nunc feugiat, posuere");
|
||||
utterance1.lang = 'it-IT-noend';
|
||||
var utterance2 = new win1.SpeechSynthesisUtterance("u2: hello, losers too");
|
||||
utterance2.lang = 'it-IT-noend';
|
||||
var utterance3 = new win1.SpeechSynthesisUtterance("u3: hello, losers three");
|
||||
|
||||
var utterance4 = new win2.SpeechSynthesisUtterance("u4: hello, losers same!");
|
||||
utterance4.lang = 'it-IT-noend';
|
||||
var utterance5 = new win2.SpeechSynthesisUtterance("u5: hello, losers too");
|
||||
utterance5.lang = 'it-IT-noend';
|
||||
|
||||
var eventOrder = ['start1', 'end1', 'start2', 'end2'];
|
||||
utterance1.addEventListener('start', function(e) {
|
||||
is(eventOrder.shift(), 'start1', 'start1');
|
||||
testSynthState(win1, { speaking: true, pending: true });
|
||||
testSynthState(win2, { speaking: true, pending: true });
|
||||
win2.speechSynthesis.cancel();
|
||||
SpecialPowers.wrap(win1.speechSynthesis).forceEnd();
|
||||
|
||||
});
|
||||
utterance1.addEventListener('end', function(e) {
|
||||
is(eventOrder.shift(), 'end1', 'end1');
|
||||
testSynthState(win1, { pending: true });
|
||||
testSynthState(win2, { pending: false });
|
||||
});
|
||||
utterance2.addEventListener('start', function(e) {
|
||||
is(eventOrder.shift(), 'start2', 'start2');
|
||||
testSynthState(win1, { speaking: true, pending: true });
|
||||
testSynthState(win2, { speaking: true, pending: false });
|
||||
win1.speechSynthesis.cancel();
|
||||
});
|
||||
utterance2.addEventListener('end', function(e) {
|
||||
is(eventOrder.shift(), 'end2', 'end2');
|
||||
testSynthState(win1, { speaking: false, pending: false });
|
||||
testSynthState(win2, { speaking: false, pending: false });
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
function wrongUtterance(e) {
|
||||
ok(false, 'This shall not be uttered: "' + e.target.text + '"');
|
||||
}
|
||||
|
||||
utterance3.addEventListener('start', wrongUtterance);
|
||||
utterance4.addEventListener('start', wrongUtterance);
|
||||
utterance5.addEventListener('start', wrongUtterance);
|
||||
|
||||
win1.speechSynthesis.speak(utterance1);
|
||||
win1.speechSynthesis.speak(utterance2);
|
||||
win1.speechSynthesis.speak(utterance3);
|
||||
win2.speechSynthesis.speak(utterance4);
|
||||
win2.speechSynthesis.speak(utterance5);
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,131 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1188099
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1188099: Calling pause() should work correctly with global queue</title>
|
||||
<script type="application/javascript">
|
||||
window.SimpleTest = parent.SimpleTest;
|
||||
window.info = parent.info;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
window.todo = parent.todo;
|
||||
</script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188099">Mozilla Bug 1188099</a>
|
||||
<iframe id="frame1"></iframe>
|
||||
<iframe id="frame2"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
Promise.all([loadFrame('frame1'), loadFrame('frame2')]).then(function ([frame1, frame2]) {
|
||||
var win1 = frame1.contentWindow;
|
||||
var win2 = frame2.contentWindow;
|
||||
|
||||
var utterance1 = new win1.SpeechSynthesisUtterance("Speak utterance 1.");
|
||||
utterance1.lang = 'it-IT-noend';
|
||||
var utterance2 = new win2.SpeechSynthesisUtterance("Speak utterance 2.");
|
||||
var utterance3 = new win1.SpeechSynthesisUtterance("Speak utterance 3.");
|
||||
var utterance4 = new win2.SpeechSynthesisUtterance("Speak utterance 4.");
|
||||
var eventOrder = ['start1', 'pause1', 'resume1', 'end1', 'start2', 'end2',
|
||||
'start4', 'end4', 'start3', 'end3'];
|
||||
|
||||
utterance1.addEventListener('start', function(e) {
|
||||
is(eventOrder.shift(), 'start1', 'start1');
|
||||
win1.speechSynthesis.pause();
|
||||
});
|
||||
utterance1.addEventListener('pause', function(e) {
|
||||
var expectedEvent = eventOrder.shift()
|
||||
is(expectedEvent, 'pause1', 'pause1');
|
||||
testSynthState(win1, { speaking: true, pending: false, paused: true});
|
||||
testSynthState(win2, { speaking: true, pending: true, paused: false});
|
||||
|
||||
if (expectedEvent == 'pause1') {
|
||||
win1.speechSynthesis.resume();
|
||||
}
|
||||
});
|
||||
utterance1.addEventListener('resume', function(e) {
|
||||
is(eventOrder.shift(), 'resume1', 'resume1');
|
||||
testSynthState(win1, { speaking: true, pending: false, paused: false});
|
||||
testSynthState(win2, { speaking: true, pending: true, paused: false});
|
||||
|
||||
win2.speechSynthesis.pause();
|
||||
|
||||
testSynthState(win1, { speaking: true, pending: false, paused: false});
|
||||
// 1188099: currently, paused state is not gaurenteed to be immediate.
|
||||
testSynthState(win2, { speaking: true, pending: true });
|
||||
|
||||
// We now make the utterance end.
|
||||
SpecialPowers.wrap(win1.speechSynthesis).forceEnd();
|
||||
});
|
||||
utterance1.addEventListener('end', function(e) {
|
||||
is(eventOrder.shift(), 'end1', 'end1');
|
||||
testSynthState(win1, { speaking: false, pending: false, paused: false});
|
||||
testSynthState(win2, { speaking: false, pending: true, paused: true});
|
||||
|
||||
win2.speechSynthesis.resume();
|
||||
});
|
||||
|
||||
utterance2.addEventListener('start', function(e) {
|
||||
is(eventOrder.shift(), 'start2', 'start2');
|
||||
testSynthState(win1, { speaking: true, pending: false, paused: false});
|
||||
testSynthState(win2, { speaking: true, pending: false, paused: false});
|
||||
});
|
||||
utterance2.addEventListener('end', function(e) {
|
||||
is(eventOrder.shift(), 'end2', 'end2');
|
||||
testSynthState(win1, { speaking: false, pending: false, paused: false});
|
||||
testSynthState(win2, { speaking: false, pending: false, paused: false});
|
||||
|
||||
win1.speechSynthesis.pause();
|
||||
|
||||
testSynthState(win1, { speaking: false, pending: false, paused: true});
|
||||
testSynthState(win2, { speaking: false, pending: false, paused: false});
|
||||
|
||||
win1.speechSynthesis.speak(utterance3);
|
||||
win2.speechSynthesis.speak(utterance4);
|
||||
|
||||
testSynthState(win1, { speaking: false, pending: true, paused: true});
|
||||
testSynthState(win2, { speaking: false, pending: true, paused: false});
|
||||
});
|
||||
|
||||
utterance4.addEventListener('start', function(e) {
|
||||
is(eventOrder.shift(), 'start4', 'start4');
|
||||
testSynthState(win1, { speaking: true, pending: true, paused: true});
|
||||
testSynthState(win2, { speaking: true, pending: false, paused: false});
|
||||
|
||||
win1.speechSynthesis.resume();
|
||||
});
|
||||
utterance4.addEventListener('end', function(e) {
|
||||
is(eventOrder.shift(), 'end4', 'end4');
|
||||
testSynthState(win1, { speaking: false, pending: true, paused: false});
|
||||
testSynthState(win2, { speaking: false, pending: false, paused: false});
|
||||
});
|
||||
|
||||
utterance3.addEventListener('start', function(e) {
|
||||
is(eventOrder.shift(), 'start3', 'start3');
|
||||
testSynthState(win1, { speaking: true, pending: false, paused: false});
|
||||
testSynthState(win2, { speaking: true, pending: false, paused: false});
|
||||
});
|
||||
|
||||
utterance3.addEventListener('end', function(e) {
|
||||
is(eventOrder.shift(), 'end3', 'end3');
|
||||
testSynthState(win1, { speaking: false, pending: false, paused: false});
|
||||
testSynthState(win2, { speaking: false, pending: false, paused: false});
|
||||
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
win1.speechSynthesis.speak(utterance1);
|
||||
win2.speechSynthesis.speak(utterance2);
|
||||
});
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,102 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1155034
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1155034: Check that indirect audio services dispatch their own events</title>
|
||||
<script type="application/javascript">
|
||||
window.SimpleTest = parent.SimpleTest;
|
||||
window.info = parent.info;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
</script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1155034">Mozilla Bug 1155034</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1155034 **/
|
||||
|
||||
function testFunc(done_cb) {
|
||||
function test_with_events() {
|
||||
info('test_with_events');
|
||||
var utterance = new SpeechSynthesisUtterance("never end, callback events");
|
||||
utterance.lang = 'it-IT-noend';
|
||||
|
||||
utterance.addEventListener('start', function(e) {
|
||||
info('start test_with_events');
|
||||
speechSynthesis.pause();
|
||||
// Wait to see if we get some bad events we didn't expect.
|
||||
});
|
||||
|
||||
utterance.addEventListener('pause', function(e) {
|
||||
is(e.charIndex, 1, 'pause event charIndex matches service arguments');
|
||||
is(e.elapsedTime, 1.5, 'pause event elapsedTime matches service arguments');
|
||||
speechSynthesis.resume();
|
||||
});
|
||||
|
||||
utterance.addEventListener('resume', function(e) {
|
||||
is(e.charIndex, 1, 'resume event charIndex matches service arguments');
|
||||
is(e.elapsedTime, 1.5, 'resume event elapsedTime matches service arguments');
|
||||
speechSynthesis.cancel();
|
||||
});
|
||||
|
||||
utterance.addEventListener('end', function(e) {
|
||||
ok(e.charIndex, 1, 'resume event charIndex matches service arguments');
|
||||
ok(e.elapsedTime, 1.5, 'end event elapsedTime matches service arguments');
|
||||
test_no_events();
|
||||
});
|
||||
|
||||
info('start speak');
|
||||
speechSynthesis.speak(utterance);
|
||||
}
|
||||
|
||||
function forbiddenEvent(e) {
|
||||
ok(false, 'no "' + e.type + '" event was explicitly dispatched from the service')
|
||||
}
|
||||
|
||||
function test_no_events() {
|
||||
info('test_no_events');
|
||||
var utterance = new SpeechSynthesisUtterance("never end");
|
||||
utterance.lang = "it-IT-noevents-noend";
|
||||
utterance.addEventListener('start', function(e) {
|
||||
speechSynthesis.pause();
|
||||
// Wait to see if we get some bad events we didn't expect.
|
||||
setTimeout(function() {
|
||||
ok(true, 'didn\'t get any unwanted events');
|
||||
utterance.removeEventListener('end', forbiddenEvent);
|
||||
SpecialPowers.wrap(speechSynthesis).forceEnd();
|
||||
done_cb();
|
||||
}, 1000);
|
||||
});
|
||||
|
||||
utterance.addEventListener('pause', forbiddenEvent);
|
||||
utterance.addEventListener('end', forbiddenEvent);
|
||||
|
||||
speechSynthesis.speak(utterance);
|
||||
}
|
||||
|
||||
test_with_events();
|
||||
}
|
||||
|
||||
// Run test with no global queue, and then run it with a global queue.
|
||||
testFunc(function() {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [['media.webspeech.synth.force_global_queue', true]] }, function() {
|
||||
testFunc(SimpleTest.finish)
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,95 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=525444
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 525444: Web Speech API check all classes are present</title>
|
||||
<script type="application/javascript">
|
||||
window.SimpleTest = parent.SimpleTest;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
</script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
ok(SpeechSynthesis, "SpeechSynthesis exists in global scope");
|
||||
ok(SpeechSynthesisVoice, "SpeechSynthesisVoice exists in global scope");
|
||||
ok(SpeechSynthesisErrorEvent, "SpeechSynthesisErrorEvent exists in global scope");
|
||||
ok(SpeechSynthesisEvent, "SpeechSynthesisEvent exists in global scope");
|
||||
|
||||
// SpeechSynthesisUtterance is the only type that has a constructor
|
||||
// and writable properties
|
||||
ok(SpeechSynthesisUtterance, "SpeechSynthesisUtterance exists in global scope");
|
||||
var ssu = new SpeechSynthesisUtterance("hello world");
|
||||
is(typeof ssu, "object", "SpeechSynthesisUtterance instance is an object");
|
||||
is(ssu.text, "hello world", "SpeechSynthesisUtterance.text is correct");
|
||||
is(ssu.volume, 1, "SpeechSynthesisUtterance.volume default is correct");
|
||||
is(ssu.rate, 1, "SpeechSynthesisUtterance.rate default is correct");
|
||||
is(ssu.pitch, 1, "SpeechSynthesisUtterance.pitch default is correct");
|
||||
ssu.lang = "he-IL";
|
||||
ssu.volume = 0.5;
|
||||
ssu.rate = 2.0;
|
||||
ssu.pitch = 1.5;
|
||||
is(ssu.lang, "he-IL", "SpeechSynthesisUtterance.lang is correct");
|
||||
is(ssu.volume, 0.5, "SpeechSynthesisUtterance.volume is correct");
|
||||
is(ssu.rate, 2.0, "SpeechSynthesisUtterance.rate is correct");
|
||||
is(ssu.pitch, 1.5, "SpeechSynthesisUtterance.pitch is correct");
|
||||
|
||||
// Assign a rate that is out of bounds
|
||||
ssu.rate = 20;
|
||||
is(ssu.rate, 10, "SpeechSynthesisUtterance.rate enforces max of 10");
|
||||
ssu.rate = 0;
|
||||
is(ssu.rate.toPrecision(1), "0.1", "SpeechSynthesisUtterance.rate enforces min of 0.1");
|
||||
|
||||
// Assign a volume which is out of bounds
|
||||
ssu.volume = 2;
|
||||
is(ssu.volume, 1, "SpeechSynthesisUtterance.volume enforces max of 1");
|
||||
ssu.volume = -1;
|
||||
is(ssu.volume, 0, "SpeechSynthesisUtterance.volume enforces min of 0");
|
||||
|
||||
// Assign a pitch which is out of bounds
|
||||
ssu.pitch = 2.1;
|
||||
is(ssu.pitch, 2, "SpeechSynthesisUtterance.pitch enforces max of 2");
|
||||
ssu.pitch = -1;
|
||||
is(ssu.pitch, 0, "SpeechSynthesisUtterance.pitch enforces min of 0");
|
||||
|
||||
// Test for singleton instance hanging off of window.
|
||||
ok(speechSynthesis, "speechSynthesis exists in global scope");
|
||||
is(typeof speechSynthesis, "object", "speechSynthesis instance is an object");
|
||||
is(typeof speechSynthesis.speak, "function", "speechSynthesis.speak is a function");
|
||||
is(typeof speechSynthesis.cancel, "function", "speechSynthesis.cancel is a function");
|
||||
is(typeof speechSynthesis.pause, "function", "speechSynthesis.pause is a function");
|
||||
is(typeof speechSynthesis.resume, "function", "speechSynthesis.resume is a function");
|
||||
is(typeof speechSynthesis.getVoices, "function", "speechSynthesis.getVoices is a function");
|
||||
|
||||
is(typeof speechSynthesis.pending, "boolean", "speechSynthesis.pending is a boolean");
|
||||
is(typeof speechSynthesis.speaking, "boolean", "speechSynthesis.speaking is a boolean");
|
||||
is(typeof speechSynthesis.paused, "boolean", "speechSynthesis.paused is a boolean");
|
||||
|
||||
var voices1 = speechSynthesis.getVoices();
|
||||
var voices2 = speechSynthesis.getVoices();
|
||||
|
||||
ok(voices1.length == voices2.length, "Voice count matches");
|
||||
|
||||
for (var i in voices1) {
|
||||
ok(voices1[i] == voices2[i], "Voice instance matches");
|
||||
}
|
||||
|
||||
SimpleTest.finish();
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,100 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1150315
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1150315: Check that successive cancel/speak calls work</title>
|
||||
<script type="application/javascript">
|
||||
window.SimpleTest = parent.SimpleTest;
|
||||
window.info = parent.info;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
</script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1150315">Mozilla Bug 1150315</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1150315 **/
|
||||
|
||||
function testFunc(done_cb) {
|
||||
var gotEndEvent = false;
|
||||
// A long utterance that we will interrupt.
|
||||
var utterance = new SpeechSynthesisUtterance("Donec ac nunc feugiat, posuere " +
|
||||
"mauris id, pharetra velit. Donec fermentum orci nunc, sit amet maximus" +
|
||||
"dui tincidunt ut. Sed ultricies ac nisi a laoreet. Proin interdum," +
|
||||
"libero maximus hendrerit posuere, lorem risus egestas nisl, a" +
|
||||
"ultricies massa justo eu nisi. Duis mattis nibh a ligula tincidunt" +
|
||||
"tincidunt non eu erat. Sed bibendum varius vulputate. Cras leo magna," +
|
||||
"ornare ac posuere vel, luctus id metus. Mauris nec quam ac augue" +
|
||||
"consectetur bibendum. Integer a commodo tortor. Duis semper dolor eu" +
|
||||
"facilisis facilisis. Etiam venenatis turpis est, quis tincidunt velit" +
|
||||
"suscipit a. Cras semper orci in sapien rhoncus bibendum. Suspendisse" +
|
||||
"eu ex lobortis, finibus enim in, condimentum quam. Maecenas eget dui" +
|
||||
"ipsum. Aliquam tortor leo, interdum eget congue ut, tempor id elit.");
|
||||
utterance.addEventListener('start', function(e) {
|
||||
ok(true, 'start utterance 1');
|
||||
speechSynthesis.cancel();
|
||||
info('cancel!');
|
||||
speechSynthesis.speak(utterance2);
|
||||
info('speak??');
|
||||
});
|
||||
|
||||
var utterance2 = new SpeechSynthesisUtterance("Proin ornare neque vitae " +
|
||||
"risus mattis rutrum. Suspendisse a velit ut est convallis aliquet." +
|
||||
"Nullam ante elit, malesuada vel luctus rutrum, ultricies nec libero." +
|
||||
"Praesent eu iaculis orci. Sed nisl diam, sodales ac purus et," +
|
||||
"volutpat interdum tortor. Nullam aliquam porta elit et maximus. Cras" +
|
||||
"risus lectus, elementum vel sodales vel, ultricies eget lectus." +
|
||||
"Curabitur velit lacus, mollis vel finibus et, molestie sit amet" +
|
||||
"sapien. Proin vitae dolor ac augue posuere efficitur ac scelerisque" +
|
||||
"diam. Nulla sed odio elit.");
|
||||
utterance2.addEventListener('start', function() {
|
||||
info('start');
|
||||
speechSynthesis.cancel();
|
||||
speechSynthesis.speak(utterance3);
|
||||
});
|
||||
utterance2.addEventListener('end', function(e) {
|
||||
gotEndEvent = true;
|
||||
});
|
||||
|
||||
var utterance3 = new SpeechSynthesisUtterance("Hello, world 3!");
|
||||
utterance3.addEventListener('start', function() {
|
||||
ok(gotEndEvent, "didn't get start event for this utterance");
|
||||
});
|
||||
utterance3.addEventListener('end', done_cb);
|
||||
|
||||
// Speak/cancel while paused (Bug 1187105)
|
||||
speechSynthesis.pause();
|
||||
speechSynthesis.speak(new SpeechSynthesisUtterance("hello."));
|
||||
ok(speechSynthesis.pending, "paused speechSynthesis has an utterance queued.");
|
||||
speechSynthesis.cancel();
|
||||
ok(!speechSynthesis.pending, "paused speechSynthesis has no utterance queued.");
|
||||
speechSynthesis.resume();
|
||||
|
||||
speechSynthesis.speak(utterance);
|
||||
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking yet.");
|
||||
ok(speechSynthesis.pending, "speechSynthesis has an utterance queued.");
|
||||
}
|
||||
|
||||
// Run test with no global queue, and then run it with a global queue.
|
||||
testFunc(function() {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [['media.webspeech.synth.force_global_queue', true]] }, function() {
|
||||
testFunc(SimpleTest.finish)
|
||||
});
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,46 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1226015
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1226015</title>
|
||||
<script type="application/javascript">
|
||||
window.SimpleTest = parent.SimpleTest;
|
||||
window.info = parent.info;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
</script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1226015">Mozilla Bug 1226015</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1226015 **/
|
||||
|
||||
function testFunc(done_cb) {
|
||||
var utterance = new SpeechSynthesisUtterance();
|
||||
utterance.lang = 'it-IT-failatstart';
|
||||
|
||||
speechSynthesis.speak(utterance);
|
||||
speechSynthesis.cancel();
|
||||
|
||||
ok(true, "we didn't crash, that is good.")
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
// Run test with no global queue, and then run it with a global queue.
|
||||
testFunc();
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,85 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=525444
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 525444: Web Speech API, check speech synth queue</title>
|
||||
<script type="application/javascript">
|
||||
window.SimpleTest = parent.SimpleTest;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
</script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=525444">Mozilla Bug 525444</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
// XXX: Rate and pitch are not tested.
|
||||
|
||||
var langUriMap = {};
|
||||
|
||||
for (var voice of speechSynthesis.getVoices()) {
|
||||
langUriMap[voice.lang] = voice.voiceURI;
|
||||
ok(true, voice.lang + ' ' + voice.voiceURI + ' ' + voice.default);
|
||||
is(voice.default, voice.lang == 'en-JM', 'Only Jamaican voice should be default');
|
||||
}
|
||||
|
||||
ok(langUriMap['en-JM'], 'No English-Jamaican voice');
|
||||
ok(langUriMap['en-GB'], 'No English-British voice');
|
||||
ok(langUriMap['en-CA'], 'No English-Canadian voice');
|
||||
ok(langUriMap['fr-CA'], 'No French-Canadian voice');
|
||||
ok(langUriMap['es-MX'], 'No Spanish-Mexican voice');
|
||||
ok(langUriMap['it-IT-fail'], 'No Failing Italian voice');
|
||||
|
||||
function testFunc(done_cb) {
|
||||
synthTestQueue(
|
||||
[[{text: "Hello, world."},
|
||||
{ uri: langUriMap['en-JM'] }],
|
||||
[{text: "Bonjour tout le monde .",
|
||||
args: { lang: "fr", rate: 0.5, pitch: 0.75 }},
|
||||
{ uri: langUriMap['fr-CA'], rate: 0.5, pitch: 0.75}],
|
||||
[{text: "How are you doing?", args: { lang: "en-GB" } },
|
||||
{ rate: 1, pitch: 1, uri: langUriMap['en-GB']}],
|
||||
[{text: "Come stai?", args: { lang: "it-IT-fail" } },
|
||||
{ rate: 1, pitch: 1, uri: langUriMap['it-IT-fail'], err: true }],
|
||||
[{text: "¡hasta mañana!", args: { lang: "es-MX" } },
|
||||
{ uri: langUriMap['es-MX'] }]],
|
||||
function () {
|
||||
var test_data = [];
|
||||
var voices = speechSynthesis.getVoices();
|
||||
for (var voice of voices) {
|
||||
if (voice.voiceURI.indexOf('urn:moz-tts:fake-direct') < 0) {
|
||||
continue;
|
||||
}
|
||||
test_data.push([{text: "Hello world", args: { voice: voice} },
|
||||
{uri: voice.voiceURI}]);
|
||||
}
|
||||
|
||||
synthTestQueue(test_data, done_cb);
|
||||
});
|
||||
}
|
||||
|
||||
// Run test with no global queue, and then run it with a global queue.
|
||||
testFunc(function() {
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [['media.webspeech.synth.force_global_queue', true]] }, function() {
|
||||
testFunc(SimpleTest.finish)
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,53 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=650295
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 650295: Web Speech API check all classes are present</title>
|
||||
<script type="application/javascript">
|
||||
window.SimpleTest = parent.SimpleTest;
|
||||
window.info = parent.info;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
</script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
var gotStartEvent = false;
|
||||
var gotBoundaryEvent = false;
|
||||
var utterance = new SpeechSynthesisUtterance("Hello, world!");
|
||||
utterance.addEventListener('start', function(e) {
|
||||
ok(speechSynthesis.speaking, "speechSynthesis is speaking.");
|
||||
ok(!speechSynthesis.pending, "speechSynthesis has no other utterances queued.");
|
||||
gotStartEvent = true;
|
||||
});
|
||||
|
||||
utterance.addEventListener('end', function(e) {
|
||||
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking.");
|
||||
ok(!speechSynthesis.pending, "speechSynthesis has no other utterances queued.");
|
||||
ok(gotStartEvent, "Got 'start' event.");
|
||||
info('end ' + e.elapsedTime);
|
||||
SimpleTest.finish();
|
||||
});
|
||||
|
||||
speechSynthesis.speak(utterance);
|
||||
ok(!speechSynthesis.speaking, "speechSynthesis is not speaking yet.");
|
||||
ok(speechSynthesis.pending, "speechSynthesis has an utterance queued.");
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,26 +0,0 @@
|
|||
[DEFAULT]
|
||||
tags=msg
|
||||
subsuite = media
|
||||
support-files =
|
||||
common.js
|
||||
file_bfcache_frame.html
|
||||
file_setup.html
|
||||
file_speech_queue.html
|
||||
file_speech_simple.html
|
||||
file_speech_cancel.html
|
||||
file_speech_error.html
|
||||
file_indirect_service_events.html
|
||||
file_global_queue.html
|
||||
file_global_queue_cancel.html
|
||||
file_global_queue_pause.html
|
||||
|
||||
[test_setup.html]
|
||||
[test_speech_queue.html]
|
||||
[test_speech_simple.html]
|
||||
[test_speech_cancel.html]
|
||||
[test_speech_error.html]
|
||||
[test_indirect_service_events.html]
|
||||
[test_global_queue.html]
|
||||
[test_global_queue_cancel.html]
|
||||
[test_global_queue_pause.html]
|
||||
[test_bfcache.html]
|
|
@ -1,401 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#include "nsISupports.h"
|
||||
#include "nsFakeSynthServices.h"
|
||||
#include "nsPrintfCString.h"
|
||||
#include "nsIWeakReferenceUtils.h"
|
||||
#include "SharedBuffer.h"
|
||||
#include "nsISimpleEnumerator.h"
|
||||
|
||||
#include "mozilla/dom/nsSynthVoiceRegistry.h"
|
||||
#include "mozilla/dom/nsSpeechTask.h"
|
||||
|
||||
#include "nsThreadUtils.h"
|
||||
#include "prenv.h"
|
||||
#include "mozilla/Preferences.h"
|
||||
#include "mozilla/DebugOnly.h"
|
||||
|
||||
#define CHANNELS 1
|
||||
#define SAMPLERATE 1600
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
StaticRefPtr<nsFakeSynthServices> nsFakeSynthServices::sSingleton;
|
||||
|
||||
enum VoiceFlags
|
||||
{
|
||||
eSuppressEvents = 1,
|
||||
eSuppressEnd = 2,
|
||||
eFailAtStart = 4,
|
||||
eFail = 8
|
||||
};
|
||||
|
||||
struct VoiceDetails
|
||||
{
|
||||
const char* uri;
|
||||
const char* name;
|
||||
const char* lang;
|
||||
bool defaultVoice;
|
||||
uint32_t flags;
|
||||
};
|
||||
|
||||
static const VoiceDetails sDirectVoices[] = {
|
||||
{"urn:moz-tts:fake-direct:bob", "Bob Marley", "en-JM", true, 0},
|
||||
{"urn:moz-tts:fake-direct:amy", "Amy Winehouse", "en-GB", false, 0},
|
||||
{"urn:moz-tts:fake-direct:lenny", "Leonard Cohen", "en-CA", false, 0},
|
||||
{"urn:moz-tts:fake-direct:celine", "Celine Dion", "fr-CA", false, 0},
|
||||
{"urn:moz-tts:fake-direct:julie", "Julieta Venegas", "es-MX", false, },
|
||||
};
|
||||
|
||||
static const VoiceDetails sIndirectVoices[] = {
|
||||
{"urn:moz-tts:fake-indirect:zanetta", "Zanetta Farussi", "it-IT", false, 0},
|
||||
{"urn:moz-tts:fake-indirect:margherita", "Margherita Durastanti", "it-IT-noevents-noend", false, eSuppressEvents | eSuppressEnd},
|
||||
{"urn:moz-tts:fake-indirect:teresa", "Teresa Cornelys", "it-IT-noend", false, eSuppressEnd},
|
||||
{"urn:moz-tts:fake-indirect:cecilia", "Cecilia Bartoli", "it-IT-failatstart", false, eFailAtStart},
|
||||
{"urn:moz-tts:fake-indirect:gottardo", "Gottardo Aldighieri", "it-IT-fail", false, eFail},
|
||||
};
|
||||
|
||||
// FakeSynthCallback
|
||||
class FakeSynthCallback : public nsISpeechTaskCallback
|
||||
{
|
||||
public:
|
||||
explicit FakeSynthCallback(nsISpeechTask* aTask) : mTask(aTask) { }
|
||||
NS_DECL_CYCLE_COLLECTING_ISUPPORTS
|
||||
NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(FakeSynthCallback, nsISpeechTaskCallback)
|
||||
|
||||
NS_IMETHOD OnPause() override
|
||||
{
|
||||
if (mTask) {
|
||||
mTask->DispatchPause(1.5, 1);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnResume() override
|
||||
{
|
||||
if (mTask) {
|
||||
mTask->DispatchResume(1.5, 1);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnCancel() override
|
||||
{
|
||||
if (mTask) {
|
||||
mTask->DispatchEnd(1.5, 1);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHOD OnVolumeChanged(float aVolume) override
|
||||
{
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
virtual ~FakeSynthCallback() { }
|
||||
|
||||
nsCOMPtr<nsISpeechTask> mTask;
|
||||
};
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTION(FakeSynthCallback, mTask);
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FakeSynthCallback)
|
||||
NS_INTERFACE_MAP_ENTRY(nsISpeechTaskCallback)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechTaskCallback)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_CYCLE_COLLECTING_ADDREF(FakeSynthCallback)
|
||||
NS_IMPL_CYCLE_COLLECTING_RELEASE(FakeSynthCallback)
|
||||
|
||||
// FakeDirectAudioSynth
|
||||
|
||||
class FakeDirectAudioSynth : public nsISpeechService
|
||||
{
|
||||
|
||||
public:
|
||||
FakeDirectAudioSynth() { }
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISPEECHSERVICE
|
||||
|
||||
private:
|
||||
virtual ~FakeDirectAudioSynth() { }
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(FakeDirectAudioSynth, nsISpeechService)
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeDirectAudioSynth::Speak(const nsAString& aText, const nsAString& aUri,
|
||||
float aVolume, float aRate, float aPitch,
|
||||
nsISpeechTask* aTask)
|
||||
{
|
||||
class Runnable final : public mozilla::Runnable
|
||||
{
|
||||
public:
|
||||
Runnable(nsISpeechTask* aTask, const nsAString& aText) :
|
||||
mTask(aTask), mText(aText)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
RefPtr<FakeSynthCallback> cb = new FakeSynthCallback(nullptr);
|
||||
mTask->Setup(cb, CHANNELS, SAMPLERATE, 2);
|
||||
|
||||
// Just an arbitrary multiplier. Pretend that each character is
|
||||
// synthesized to 40 frames.
|
||||
uint32_t frames_length = 40 * mText.Length();
|
||||
auto frames = MakeUnique<int16_t[]>(frames_length);
|
||||
mTask->SendAudioNative(frames.get(), frames_length);
|
||||
|
||||
mTask->SendAudioNative(nullptr, 0);
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISpeechTask> mTask;
|
||||
nsString mText;
|
||||
};
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new Runnable(aTask, aText);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeDirectAudioSynth::GetServiceType(SpeechServiceType* aServiceType)
|
||||
{
|
||||
*aServiceType = nsISpeechService::SERVICETYPE_DIRECT_AUDIO;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// FakeDirectAudioSynth
|
||||
|
||||
class FakeIndirectAudioSynth : public nsISpeechService
|
||||
{
|
||||
|
||||
public:
|
||||
FakeIndirectAudioSynth() {}
|
||||
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSISPEECHSERVICE
|
||||
|
||||
private:
|
||||
virtual ~FakeIndirectAudioSynth() { }
|
||||
};
|
||||
|
||||
NS_IMPL_ISUPPORTS(FakeIndirectAudioSynth, nsISpeechService)
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeIndirectAudioSynth::Speak(const nsAString& aText, const nsAString& aUri,
|
||||
float aVolume, float aRate, float aPitch,
|
||||
nsISpeechTask* aTask)
|
||||
{
|
||||
class DispatchStart final : public Runnable
|
||||
{
|
||||
public:
|
||||
explicit DispatchStart(nsISpeechTask* aTask) :
|
||||
mTask(aTask)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
mTask->DispatchStart();
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISpeechTask> mTask;
|
||||
};
|
||||
|
||||
class DispatchEnd final : public Runnable
|
||||
{
|
||||
public:
|
||||
DispatchEnd(nsISpeechTask* aTask, const nsAString& aText) :
|
||||
mTask(aTask), mText(aText)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
mTask->DispatchEnd(mText.Length()/2, mText.Length());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISpeechTask> mTask;
|
||||
nsString mText;
|
||||
};
|
||||
|
||||
class DispatchError final : public Runnable
|
||||
{
|
||||
public:
|
||||
DispatchError(nsISpeechTask* aTask, const nsAString& aText) :
|
||||
mTask(aTask), mText(aText)
|
||||
{
|
||||
}
|
||||
|
||||
NS_IMETHOD Run() override
|
||||
{
|
||||
mTask->DispatchError(mText.Length()/2, mText.Length());
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
private:
|
||||
nsCOMPtr<nsISpeechTask> mTask;
|
||||
nsString mText;
|
||||
};
|
||||
|
||||
uint32_t flags = 0;
|
||||
for (uint32_t i = 0; i < ArrayLength(sIndirectVoices); i++) {
|
||||
if (aUri.EqualsASCII(sIndirectVoices[i].uri)) {
|
||||
flags = sIndirectVoices[i].flags;
|
||||
}
|
||||
}
|
||||
|
||||
if (flags & eFailAtStart) {
|
||||
return NS_ERROR_FAILURE;
|
||||
}
|
||||
|
||||
RefPtr<FakeSynthCallback> cb = new FakeSynthCallback(
|
||||
(flags & eSuppressEvents) ? nullptr : aTask);
|
||||
|
||||
aTask->Setup(cb, 0, 0, 0);
|
||||
|
||||
nsCOMPtr<nsIRunnable> runnable = new DispatchStart(aTask);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
|
||||
if (flags & eFail) {
|
||||
runnable = new DispatchError(aTask, aText);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
} else if ((flags & eSuppressEnd) == 0) {
|
||||
runnable = new DispatchEnd(aTask, aText);
|
||||
NS_DispatchToMainThread(runnable);
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
NS_IMETHODIMP
|
||||
FakeIndirectAudioSynth::GetServiceType(SpeechServiceType* aServiceType)
|
||||
{
|
||||
*aServiceType = nsISpeechService::SERVICETYPE_INDIRECT_AUDIO;
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// nsFakeSynthService
|
||||
|
||||
NS_INTERFACE_MAP_BEGIN(nsFakeSynthServices)
|
||||
NS_INTERFACE_MAP_ENTRY(nsIObserver)
|
||||
NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
|
||||
NS_INTERFACE_MAP_END
|
||||
|
||||
NS_IMPL_ADDREF(nsFakeSynthServices)
|
||||
NS_IMPL_RELEASE(nsFakeSynthServices)
|
||||
|
||||
nsFakeSynthServices::nsFakeSynthServices()
|
||||
{
|
||||
}
|
||||
|
||||
nsFakeSynthServices::~nsFakeSynthServices()
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
AddVoices(nsISpeechService* aService, const VoiceDetails* aVoices, uint32_t aLength)
|
||||
{
|
||||
RefPtr<nsSynthVoiceRegistry> registry = nsSynthVoiceRegistry::GetInstance();
|
||||
for (uint32_t i = 0; i < aLength; i++) {
|
||||
NS_ConvertUTF8toUTF16 name(aVoices[i].name);
|
||||
NS_ConvertUTF8toUTF16 uri(aVoices[i].uri);
|
||||
NS_ConvertUTF8toUTF16 lang(aVoices[i].lang);
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
registry->NotifyVoicesChanged();
|
||||
}
|
||||
|
||||
void
|
||||
nsFakeSynthServices::Init()
|
||||
{
|
||||
mDirectService = new FakeDirectAudioSynth();
|
||||
AddVoices(mDirectService, sDirectVoices, ArrayLength(sDirectVoices));
|
||||
|
||||
mIndirectService = new FakeIndirectAudioSynth();
|
||||
AddVoices(mIndirectService, sIndirectVoices, ArrayLength(sIndirectVoices));
|
||||
}
|
||||
|
||||
// nsIObserver
|
||||
|
||||
NS_IMETHODIMP
|
||||
nsFakeSynthServices::Observe(nsISupports* aSubject, const char* aTopic,
|
||||
const char16_t* aData)
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if(NS_WARN_IF(!(!strcmp(aTopic, "speech-synth-started")))) {
|
||||
return NS_ERROR_UNEXPECTED;
|
||||
}
|
||||
|
||||
if (Preferences::GetBool("media.webspeech.synth.test")) {
|
||||
NS_DispatchToMainThread(NewRunnableMethod(this, &nsFakeSynthServices::Init));
|
||||
}
|
||||
|
||||
return NS_OK;
|
||||
}
|
||||
|
||||
// static methods
|
||||
|
||||
nsFakeSynthServices*
|
||||
nsFakeSynthServices::GetInstance()
|
||||
{
|
||||
MOZ_ASSERT(NS_IsMainThread());
|
||||
if (!XRE_IsParentProcess()) {
|
||||
MOZ_ASSERT(false, "nsFakeSynthServices can only be started on main gecko process");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (!sSingleton) {
|
||||
sSingleton = new nsFakeSynthServices();
|
||||
}
|
||||
|
||||
return sSingleton;
|
||||
}
|
||||
|
||||
already_AddRefed<nsFakeSynthServices>
|
||||
nsFakeSynthServices::GetInstanceForService()
|
||||
{
|
||||
RefPtr<nsFakeSynthServices> picoService = GetInstance();
|
||||
return picoService.forget();
|
||||
}
|
||||
|
||||
void
|
||||
nsFakeSynthServices::Shutdown()
|
||||
{
|
||||
if (!sSingleton) {
|
||||
return;
|
||||
}
|
||||
|
||||
sSingleton = nullptr;
|
||||
}
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
|
@ -1,52 +0,0 @@
|
|||
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* vim:set ts=2 sw=2 sts=2 et cindent: */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
#ifndef nsFakeSynthServices_h
|
||||
#define nsFakeSynthServices_h
|
||||
|
||||
#include "nsTArray.h"
|
||||
#include "nsIObserver.h"
|
||||
#include "nsIThread.h"
|
||||
#include "nsISpeechService.h"
|
||||
#include "nsRefPtrHashtable.h"
|
||||
#include "mozilla/StaticPtr.h"
|
||||
#include "mozilla/Monitor.h"
|
||||
|
||||
namespace mozilla {
|
||||
namespace dom {
|
||||
|
||||
class nsFakeSynthServices : public nsIObserver
|
||||
{
|
||||
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
NS_DECL_NSIOBSERVER
|
||||
|
||||
nsFakeSynthServices();
|
||||
|
||||
static nsFakeSynthServices* GetInstance();
|
||||
|
||||
static already_AddRefed<nsFakeSynthServices> GetInstanceForService();
|
||||
|
||||
static void Shutdown();
|
||||
|
||||
private:
|
||||
|
||||
virtual ~nsFakeSynthServices();
|
||||
|
||||
void Init();
|
||||
|
||||
nsCOMPtr<nsISpeechService> mDirectService;
|
||||
|
||||
nsCOMPtr<nsISpeechService> mIndirectService;
|
||||
|
||||
static StaticRefPtr<nsFakeSynthServices> sSingleton;
|
||||
};
|
||||
|
||||
} // namespace dom
|
||||
} // namespace mozilla
|
||||
|
||||
#endif
|
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1254378
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1254378: Web Speech API check all classes are present</title>
|
||||
<script type="application/javascript">
|
||||
window.SimpleTest = parent.SimpleTest;
|
||||
window.is = parent.is;
|
||||
window.isnot = parent.isnot;
|
||||
window.ok = parent.ok;
|
||||
</script>
|
||||
</head>
|
||||
<body>
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1254378 **/
|
||||
|
||||
function onVoicesChanged() {
|
||||
isnot(speechSynthesis.getVoices().length, 0, "Voices added");
|
||||
speechSynthesis.removeEventListener("voiceschanged", onVoicesChanged);
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
speechSynthesis.addEventListener("voiceschanged", onVoicesChanged);
|
||||
|
||||
is(speechSynthesis.getVoices().length, 0, "No voices added initially");
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
|
@ -1,7 +0,0 @@
|
|||
[DEFAULT]
|
||||
tags=msg
|
||||
subsuite = media
|
||||
support-files =
|
||||
file_voiceschanged.html
|
||||
|
||||
[test_voiceschanged.html]
|
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1254378
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1254378: Emit onvoiceschanged when voices first added</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1254378">Mozilla Bug 1254378</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1254378 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
|
||||
function() { document.getElementById("testFrame").src = "file_voiceschanged.html"; });
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,45 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1230533
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1230533: Test speech is stopped from a window when unloaded</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1230533">Mozilla Bug 1230533</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
var iframe;
|
||||
|
||||
function onDone() {
|
||||
SimpleTest.finish();
|
||||
}
|
||||
|
||||
SpecialPowers.pushPrefEnv({ set: [
|
||||
['media.webspeech.synth.enabled', true],
|
||||
['media.webspeech.synth.force_global_queue', true],
|
||||
['browser.sessionhistory.cache_subframes', true],
|
||||
['browser.sessionhistory.max_total_viewers', 10]] },
|
||||
function() {
|
||||
loadSpeechTest("file_bfcache_frame.html");
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,35 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1188099
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1188099: Global queue should correctly schedule utterances</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188099">Mozilla Bug 1188099</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [['media.webspeech.synth.enabled', true],
|
||||
['media.webspeech.synth.force_global_queue', true]] },
|
||||
function() { loadSpeechTest("file_global_queue.html"); });
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,35 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1188099
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1188099: Calling cancel() should work correctly with global queue</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188099">Mozilla Bug 1188099</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [['media.webspeech.synth.enabled', true],
|
||||
['media.webspeech.synth.force_global_queue', true]] },
|
||||
function() { loadSpeechTest("file_global_queue_cancel.html"); });
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,35 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1188099
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1188099: Calling pause() should work correctly with global queue</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1188099">Mozilla Bug 1188099</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [['media.webspeech.synth.enabled', true],
|
||||
['media.webspeech.synth.force_global_queue', true]] },
|
||||
function() { loadSpeechTest("file_global_queue_pause.html"); });
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,36 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1155034
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1155034: Check that indirect audio services dispatch their own events</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1155034">Mozilla Bug 1155034</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1155034 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [['media.webspeech.synth.enabled', true],
|
||||
['media.webspeech.synth.force_global_queue', false]] },
|
||||
function() { loadSpeechTest("file_indirect_service_events.html"); });
|
||||
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,32 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=525444
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 525444: Web Speech API check all classes are present</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv({ set: [['media.webspeech.synth.enabled', true]] },
|
||||
function() { document.getElementById("testFrame").src = "file_setup.html"; });
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,35 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1150315
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1150315: Web Speech API check all classes are present</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1150315">Mozilla Bug 1150315</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1150315 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [['media.webspeech.synth.enabled', true],
|
||||
['media.webspeech.synth.force_global_queue', false]] },
|
||||
function() { loadSpeechTest("file_speech_cancel.html"); });
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,35 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=1226015
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 1150315: Web Speech API check all classes are present</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=1226015">Mozilla Bug 1226015</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 1226015 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [['media.webspeech.synth.enabled', true],
|
||||
['media.webspeech.synth.force_global_queue', false]] },
|
||||
function() { loadSpeechTest("file_speech_error.html"); });
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,37 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html lang="en-US">
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=525444
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 525444: Web Speech API, check speech synth queue</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=525444">Mozilla Bug 525444</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [['media.webspeech.synth.enabled', true],
|
||||
['media.webspeech.synth.force_global_queue', false]] },
|
||||
function() {
|
||||
loadSpeechTest("file_speech_queue.html");
|
||||
});
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,34 +0,0 @@
|
|||
<!DOCTYPE HTML>
|
||||
<html>
|
||||
<!--
|
||||
https://bugzilla.mozilla.org/show_bug.cgi?id=650295
|
||||
-->
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Test for Bug 650295: Web Speech API check all classes are present</title>
|
||||
<script type="application/javascript" src="/tests/SimpleTest/SimpleTest.js"></script>
|
||||
<script type="application/javascript" src="common.js"></script>
|
||||
<link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css"/>
|
||||
</head>
|
||||
<body>
|
||||
<a target="_blank" href="https://bugzilla.mozilla.org/show_bug.cgi?id=650295">Mozilla Bug 650295</a>
|
||||
<p id="display"></p>
|
||||
<iframe id="testFrame"></iframe>
|
||||
<div id="content" style="display: none">
|
||||
|
||||
</div>
|
||||
<pre id="test">
|
||||
<script type="application/javascript">
|
||||
|
||||
/** Test for Bug 525444 **/
|
||||
|
||||
SimpleTest.waitForExplicitFinish();
|
||||
|
||||
SpecialPowers.pushPrefEnv(
|
||||
{ set: [['media.webspeech.synth.enabled', true]] },
|
||||
function() { loadSpeechTest("file_speech_simple.html"); });
|
||||
|
||||
</script>
|
||||
</pre>
|
||||
</body>
|
||||
</html>
|
|
@ -1,22 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Constructor,
|
||||
Pref="media.webspeech.recognition.enable",
|
||||
Func="SpeechRecognition::IsAuthorized"]
|
||||
interface SpeechGrammar {
|
||||
[Throws]
|
||||
attribute DOMString src;
|
||||
[Throws]
|
||||
attribute float weight;
|
||||
};
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Constructor, Pref="media.webspeech.recognition.enable",
|
||||
Func="SpeechRecognition::IsAuthorized"]
|
||||
interface SpeechGrammarList {
|
||||
readonly attribute unsigned long length;
|
||||
[Throws]
|
||||
getter SpeechGrammar item(unsigned long index);
|
||||
[Throws]
|
||||
void addFromURI(DOMString src, optional float weight);
|
||||
[Throws]
|
||||
void addFromString(DOMString string, optional float weight);
|
||||
};
|
|
@ -1,45 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Constructor,
|
||||
Pref="media.webspeech.recognition.enable",
|
||||
Func="SpeechRecognition::IsAuthorized"]
|
||||
interface SpeechRecognition : EventTarget {
|
||||
// recognition parameters
|
||||
attribute SpeechGrammarList grammars;
|
||||
attribute DOMString lang;
|
||||
[Throws]
|
||||
attribute boolean continuous;
|
||||
attribute boolean interimResults;
|
||||
attribute unsigned long maxAlternatives;
|
||||
[Throws]
|
||||
attribute DOMString serviceURI;
|
||||
|
||||
// methods to drive the speech interaction
|
||||
[Throws, UnsafeInPrerendering]
|
||||
void start(optional MediaStream stream);
|
||||
void stop();
|
||||
void abort();
|
||||
|
||||
// event methods
|
||||
attribute EventHandler onaudiostart;
|
||||
attribute EventHandler onsoundstart;
|
||||
attribute EventHandler onspeechstart;
|
||||
attribute EventHandler onspeechend;
|
||||
attribute EventHandler onsoundend;
|
||||
attribute EventHandler onaudioend;
|
||||
attribute EventHandler onresult;
|
||||
attribute EventHandler onnomatch;
|
||||
attribute EventHandler onerror;
|
||||
attribute EventHandler onstart;
|
||||
attribute EventHandler onend;
|
||||
};
|
|
@ -1,18 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Pref="media.webspeech.recognition.enable",
|
||||
Func="SpeechRecognition::IsAuthorized"]
|
||||
interface SpeechRecognitionAlternative {
|
||||
readonly attribute DOMString transcript;
|
||||
readonly attribute float confidence;
|
||||
};
|
|
@ -1,31 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
enum SpeechRecognitionErrorCode {
|
||||
"no-speech",
|
||||
"aborted",
|
||||
"audio-capture",
|
||||
"network",
|
||||
"not-allowed",
|
||||
"service-not-allowed",
|
||||
"bad-grammar",
|
||||
"language-not-supported"
|
||||
};
|
||||
|
||||
[Pref="media.webspeech.recognition.enable",
|
||||
Func="SpeechRecognition::IsAuthorized",
|
||||
Constructor(DOMString type, optional SpeechRecognitionErrorInit eventInitDict)]
|
||||
interface SpeechRecognitionError : Event
|
||||
{
|
||||
readonly attribute SpeechRecognitionErrorCode error;
|
||||
readonly attribute DOMString? message;
|
||||
};
|
||||
|
||||
dictionary SpeechRecognitionErrorInit : EventInit
|
||||
{
|
||||
SpeechRecognitionErrorCode error = "no-speech";
|
||||
DOMString message = "";
|
||||
};
|
|
@ -1,25 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
interface nsISupports;
|
||||
|
||||
[Pref="media.webspeech.recognition.enable",
|
||||
Func="SpeechRecognition::IsAuthorized",
|
||||
Constructor(DOMString type, optional SpeechRecognitionEventInit eventInitDict)]
|
||||
interface SpeechRecognitionEvent : Event
|
||||
{
|
||||
readonly attribute unsigned long resultIndex;
|
||||
readonly attribute SpeechRecognitionResultList? results;
|
||||
readonly attribute any interpretation;
|
||||
readonly attribute Document? emma;
|
||||
};
|
||||
|
||||
dictionary SpeechRecognitionEventInit : EventInit
|
||||
{
|
||||
unsigned long resultIndex = 0;
|
||||
SpeechRecognitionResultList? results = null;
|
||||
any interpretation = null;
|
||||
Document? emma = null;
|
||||
};
|
|
@ -1,19 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Pref="media.webspeech.recognition.enable",
|
||||
Func="SpeechRecognition::IsAuthorized"]
|
||||
interface SpeechRecognitionResult {
|
||||
readonly attribute unsigned long length;
|
||||
getter SpeechRecognitionAlternative item(unsigned long index);
|
||||
readonly attribute boolean isFinal;
|
||||
};
|
|
@ -1,18 +0,0 @@
|
|||
/* -*- Mode: IDL; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
|
||||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
* You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*
|
||||
* The origin of this IDL file is
|
||||
* http://dvcs.w3.org/hg/speech-api/raw-file/tip/speechapi.html
|
||||
*
|
||||
* Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
|
||||
* liability, trademark and document use rules apply.
|
||||
*/
|
||||
|
||||
[Pref="media.webspeech.recognition.enable",
|
||||
Func="SpeechRecognition::IsAuthorized"]
|
||||
interface SpeechRecognitionResultList {
|
||||
readonly attribute unsigned long length;
|
||||
getter SpeechRecognitionResult item(unsigned long index);
|
||||
};
|
|
@ -616,14 +616,6 @@ if CONFIG['MOZ_WEBRTC']:
|
|||
|
||||
if CONFIG['MOZ_WEBSPEECH']:
|
||||
WEBIDL_FILES += [
|
||||
'SpeechGrammar.webidl',
|
||||
'SpeechGrammarList.webidl',
|
||||
'SpeechRecognition.webidl',
|
||||
'SpeechRecognitionAlternative.webidl',
|
||||
'SpeechRecognitionError.webidl',
|
||||
'SpeechRecognitionEvent.webidl',
|
||||
'SpeechRecognitionResult.webidl',
|
||||
'SpeechRecognitionResultList.webidl',
|
||||
'SpeechSynthesis.webidl',
|
||||
'SpeechSynthesisErrorEvent.webidl',
|
||||
'SpeechSynthesisEvent.webidl',
|
||||
|
@ -725,7 +717,6 @@ if CONFIG['MOZ_WEBRTC']:
|
|||
|
||||
if CONFIG['MOZ_WEBSPEECH']:
|
||||
GENERATED_EVENTS_WEBIDL_FILES += [
|
||||
'SpeechRecognitionEvent.webidl',
|
||||
'SpeechSynthesisErrorEvent.webidl',
|
||||
'SpeechSynthesisEvent.webidl',
|
||||
]
|
||||
|
|
|
@ -76,16 +76,9 @@ elif CONFIG['MOZ_WIDGET_TOOLKIT'] == 'android':
|
|||
|
||||
if CONFIG['MOZ_WEBSPEECH']:
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/media/webspeech/recognition',
|
||||
'/dom/media/webspeech/synth',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_WEBSPEECH_POCKETSPHINX']:
|
||||
LOCAL_INCLUDES += [
|
||||
'/media/pocketsphinx',
|
||||
'/media/sphinxbase',
|
||||
]
|
||||
|
||||
if CONFIG['MOZ_SECUREELEMENT']:
|
||||
LOCAL_INCLUDES += [
|
||||
'/dom/secureelement',
|
||||
|
|
|
@ -91,12 +91,6 @@
|
|||
#include "mozilla/OSFileConstants.h"
|
||||
#include "mozilla/Services.h"
|
||||
|
||||
#ifdef MOZ_WEBSPEECH_TEST_BACKEND
|
||||
#include "mozilla/dom/FakeSpeechRecognitionService.h"
|
||||
#endif
|
||||
#ifdef MOZ_WEBSPEECH_POCKETSPHINX
|
||||
#include "mozilla/dom/PocketSphinxSpeechRecognitionService.h"
|
||||
#endif
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
#include "mozilla/dom/nsSynthVoiceRegistry.h"
|
||||
#endif
|
||||
|
@ -518,13 +512,6 @@ NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(AudioChannelService, AudioChannelServic
|
|||
|
||||
NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR(WebSocketEventService, WebSocketEventService::GetOrCreate)
|
||||
|
||||
#ifdef MOZ_WEBSPEECH_TEST_BACKEND
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(FakeSpeechRecognitionService)
|
||||
#endif
|
||||
#ifdef MOZ_WEBSPEECH_POCKETSPHINX
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(PocketSphinxSpeechRecognitionService)
|
||||
#endif
|
||||
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsContentSecurityManager)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(nsCSPContext)
|
||||
NS_GENERIC_FACTORY_CONSTRUCTOR(CSPService)
|
||||
|
@ -681,12 +668,6 @@ NS_DEFINE_NAMED_CID(UDPSOCKETCHILD_CID);
|
|||
NS_DEFINE_NAMED_CID(NS_TIMESERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_MEDIASTREAMCONTROLLERSERVICE_CID);
|
||||
NS_DEFINE_NAMED_CID(NS_MEDIAMANAGERSERVICE_CID);
|
||||
#ifdef MOZ_WEBSPEECH_TEST_BACKEND
|
||||
NS_DEFINE_NAMED_CID(NS_FAKE_SPEECH_RECOGNITION_SERVICE_CID);
|
||||
#endif
|
||||
#ifdef MOZ_WEBSPEECH_POCKETSPHINX
|
||||
NS_DEFINE_NAMED_CID(NS_POCKETSPHINX_SPEECH_RECOGNITION_SERVICE_CID);
|
||||
#endif
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
NS_DEFINE_NAMED_CID(NS_SYNTHVOICEREGISTRY_CID);
|
||||
#endif
|
||||
|
@ -917,12 +898,6 @@ static const mozilla::Module::CIDEntry kLayoutCIDs[] = {
|
|||
{ &kNS_AUDIOCHANNEL_SERVICE_CID, false, nullptr, AudioChannelServiceConstructor },
|
||||
{ &kNS_WEBSOCKETEVENT_SERVICE_CID, false, nullptr, WebSocketEventServiceConstructor },
|
||||
{ &kNS_FOCUSMANAGER_CID, false, nullptr, CreateFocusManager },
|
||||
#ifdef MOZ_WEBSPEECH_TEST_BACKEND
|
||||
{ &kNS_FAKE_SPEECH_RECOGNITION_SERVICE_CID, false, nullptr, FakeSpeechRecognitionServiceConstructor },
|
||||
#endif
|
||||
#ifdef MOZ_WEBSPEECH_POCKETSPHINX
|
||||
{ &kNS_POCKETSPHINX_SPEECH_RECOGNITION_SERVICE_CID, false, nullptr, PocketSphinxSpeechRecognitionServiceConstructor },
|
||||
#endif
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
{ &kNS_SYNTHVOICEREGISTRY_CID, true, nullptr, nsSynthVoiceRegistryConstructor },
|
||||
#endif
|
||||
|
@ -1045,12 +1020,6 @@ static const mozilla::Module::ContractIDEntry kLayoutContracts[] = {
|
|||
{ "@mozilla.org/audiochannel/service;1", &kNS_AUDIOCHANNEL_SERVICE_CID },
|
||||
{ "@mozilla.org/websocketevent/service;1", &kNS_WEBSOCKETEVENT_SERVICE_CID },
|
||||
{ "@mozilla.org/focus-manager;1", &kNS_FOCUSMANAGER_CID },
|
||||
#ifdef MOZ_WEBSPEECH_TEST_BACKEND
|
||||
{ NS_SPEECH_RECOGNITION_SERVICE_CONTRACTID_PREFIX "fake", &kNS_FAKE_SPEECH_RECOGNITION_SERVICE_CID },
|
||||
#endif
|
||||
#ifdef MOZ_WEBSPEECH_POCKETSPHINX
|
||||
{ NS_SPEECH_RECOGNITION_SERVICE_CONTRACTID_PREFIX "pocketsphinx-en-US", &kNS_POCKETSPHINX_SPEECH_RECOGNITION_SERVICE_CID },
|
||||
#endif
|
||||
#ifdef MOZ_WEBSPEECH
|
||||
{ NS_SYNTHVOICEREGISTRY_CONTRACTID, &kNS_SYNTHVOICEREGISTRY_CID },
|
||||
#endif
|
||||
|
|
|
@ -1,386 +0,0 @@
|
|||
/* -*- c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
/* ====================================================================
|
||||
* Copyright (c) 2006 Carnegie Mellon University. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* This work was supported in part by funding from the Defense Advanced
|
||||
* Research Projects Agency and the National Science Foundation of the
|
||||
* United States of America, and the CMU Sphinx Speech Consortium.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
|
||||
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
|
||||
* NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ====================================================================
|
||||
*
|
||||
*/
|
||||
|
||||
/* cmdln_macro.h - Command line definitions for PocketSphinx */
|
||||
|
||||
#ifndef __PS_CMDLN_MACRO_H__
|
||||
#define __PS_CMDLN_MACRO_H__
|
||||
|
||||
#include <sphinxbase/cmd_ln.h>
|
||||
#include <sphinxbase/feat.h>
|
||||
#include <sphinxbase/fe.h>
|
||||
|
||||
/** Minimal set of command-line options for PocketSphinx. */
|
||||
#define POCKETSPHINX_OPTIONS \
|
||||
waveform_to_cepstral_command_line_macro(), \
|
||||
cepstral_to_feature_command_line_macro(), \
|
||||
POCKETSPHINX_ACMOD_OPTIONS, \
|
||||
POCKETSPHINX_BEAM_OPTIONS, \
|
||||
POCKETSPHINX_SEARCH_OPTIONS, \
|
||||
POCKETSPHINX_DICT_OPTIONS, \
|
||||
POCKETSPHINX_NGRAM_OPTIONS, \
|
||||
POCKETSPHINX_FSG_OPTIONS, \
|
||||
POCKETSPHINX_KWS_OPTIONS, \
|
||||
POCKETSPHINX_DEBUG_OPTIONS
|
||||
|
||||
/** Options for debugging and logging. */
|
||||
#define POCKETSPHINX_DEBUG_OPTIONS \
|
||||
{ "-logfn", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"File to write log messages in" \
|
||||
}, \
|
||||
{ "-debug", \
|
||||
ARG_INT32, \
|
||||
NULL, \
|
||||
"Verbosity level for debugging messages" \
|
||||
}, \
|
||||
{ "-mfclogdir", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Directory to log feature files to" \
|
||||
}, \
|
||||
{ "-rawlogdir", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Directory to log raw audio files to" }, \
|
||||
{ "-senlogdir", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Directory to log senone score files to" \
|
||||
}
|
||||
|
||||
/** Options defining beam width parameters for tuning the search. */
|
||||
#define POCKETSPHINX_BEAM_OPTIONS \
|
||||
{ "-beam", \
|
||||
ARG_FLOAT64, \
|
||||
"1e-48", \
|
||||
"Beam width applied to every frame in Viterbi search (smaller values mean wider beam)" }, \
|
||||
{ "-wbeam", \
|
||||
ARG_FLOAT64, \
|
||||
"7e-29", \
|
||||
"Beam width applied to word exits" }, \
|
||||
{ "-pbeam", \
|
||||
ARG_FLOAT64, \
|
||||
"1e-48", \
|
||||
"Beam width applied to phone transitions" }, \
|
||||
{ "-lpbeam", \
|
||||
ARG_FLOAT64, \
|
||||
"1e-40", \
|
||||
"Beam width applied to last phone in words" }, \
|
||||
{ "-lponlybeam", \
|
||||
ARG_FLOAT64, \
|
||||
"7e-29", \
|
||||
"Beam width applied to last phone in single-phone words" }, \
|
||||
{ "-fwdflatbeam", \
|
||||
ARG_FLOAT64, \
|
||||
"1e-64", \
|
||||
"Beam width applied to every frame in second-pass flat search" }, \
|
||||
{ "-fwdflatwbeam", \
|
||||
ARG_FLOAT64, \
|
||||
"7e-29", \
|
||||
"Beam width applied to word exits in second-pass flat search" }, \
|
||||
{ "-pl_window", \
|
||||
ARG_INT32, \
|
||||
"5", \
|
||||
"Phoneme lookahead window size, in frames" }, \
|
||||
{ "-pl_beam", \
|
||||
ARG_FLOAT64, \
|
||||
"1e-10", \
|
||||
"Beam width applied to phone loop search for lookahead" }, \
|
||||
{ "-pl_pbeam", \
|
||||
ARG_FLOAT64, \
|
||||
"1e-10", \
|
||||
"Beam width applied to phone loop transitions for lookahead" }, \
|
||||
{ "-pl_pip", \
|
||||
ARG_FLOAT32, \
|
||||
"1.0", \
|
||||
"Phone insertion penalty for phone loop" }, \
|
||||
{ "-pl_weight", \
|
||||
ARG_FLOAT64, \
|
||||
"3.0", \
|
||||
"Weight for phoneme lookahead penalties" } \
|
||||
|
||||
/** Options defining other parameters for tuning the search. */
|
||||
#define POCKETSPHINX_SEARCH_OPTIONS \
|
||||
{ "-compallsen", \
|
||||
ARG_BOOLEAN, \
|
||||
"no", \
|
||||
"Compute all senone scores in every frame (can be faster when there are many senones)" }, \
|
||||
{ "-fwdtree", \
|
||||
ARG_BOOLEAN, \
|
||||
"yes", \
|
||||
"Run forward lexicon-tree search (1st pass)" }, \
|
||||
{ "-fwdflat", \
|
||||
ARG_BOOLEAN, \
|
||||
"yes", \
|
||||
"Run forward flat-lexicon search over word lattice (2nd pass)" }, \
|
||||
{ "-bestpath", \
|
||||
ARG_BOOLEAN, \
|
||||
"yes", \
|
||||
"Run bestpath (Dijkstra) search over word lattice (3rd pass)" }, \
|
||||
{ "-backtrace", \
|
||||
ARG_BOOLEAN, \
|
||||
"no", \
|
||||
"Print results and backtraces to log file." }, \
|
||||
{ "-latsize", \
|
||||
ARG_INT32, \
|
||||
"5000", \
|
||||
"Initial backpointer table size" }, \
|
||||
{ "-maxwpf", \
|
||||
ARG_INT32, \
|
||||
"-1", \
|
||||
"Maximum number of distinct word exits at each frame (or -1 for no pruning)" }, \
|
||||
{ "-maxhmmpf", \
|
||||
ARG_INT32, \
|
||||
"30000", \
|
||||
"Maximum number of active HMMs to maintain at each frame (or -1 for no pruning)" }, \
|
||||
{ "-min_endfr", \
|
||||
ARG_INT32, \
|
||||
"0", \
|
||||
"Nodes ignored in lattice construction if they persist for fewer than N frames" }, \
|
||||
{ "-fwdflatefwid", \
|
||||
ARG_INT32, \
|
||||
"4", \
|
||||
"Minimum number of end frames for a word to be searched in fwdflat search" }, \
|
||||
{ "-fwdflatsfwin", \
|
||||
ARG_INT32, \
|
||||
"25", \
|
||||
"Window of frames in lattice to search for successor words in fwdflat search " }
|
||||
|
||||
/** Command-line options for keyword spotting */
|
||||
#define POCKETSPHINX_KWS_OPTIONS \
|
||||
{ "-keyphrase", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Keyphrase to spot"}, \
|
||||
{ "-kws", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"A file with keyphrases to spot, one per line"}, \
|
||||
{ "-kws_plp", \
|
||||
ARG_FLOAT64, \
|
||||
"1e-1", \
|
||||
"Phone loop probability for keyword spotting" }, \
|
||||
{ "-kws_threshold", \
|
||||
ARG_FLOAT64, \
|
||||
"1", \
|
||||
"Threshold for p(hyp)/p(alternatives) ratio" }
|
||||
|
||||
/** Command-line options for finite state grammars. */
|
||||
#define POCKETSPHINX_FSG_OPTIONS \
|
||||
{ "-fsg", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Sphinx format finite state grammar file"}, \
|
||||
{ "-jsgf", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"JSGF grammar file" }, \
|
||||
{ "-toprule", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Start rule for JSGF (first public rule is default)" }, \
|
||||
{ "-fsgusealtpron", \
|
||||
ARG_BOOLEAN, \
|
||||
"yes", \
|
||||
"Add alternate pronunciations to FSG"}, \
|
||||
{ "-fsgusefiller", \
|
||||
ARG_BOOLEAN, \
|
||||
"yes", \
|
||||
"Insert filler words at each state."}
|
||||
|
||||
/** Command-line options for statistical language models. */
|
||||
#define POCKETSPHINX_NGRAM_OPTIONS \
|
||||
{ "-allphone", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Perform phoneme decoding with phonetic lm" }, \
|
||||
{ "-allphone_ci", \
|
||||
ARG_BOOLEAN, \
|
||||
"no", \
|
||||
"Perform phoneme decoding with phonetic lm and context-independent units only" }, \
|
||||
{ "-lm", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Word trigram language model input file" }, \
|
||||
{ "-lmctl", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Specify a set of language model\n"}, \
|
||||
{ "-lmname", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Which language model in -lmctl to use by default"}, \
|
||||
{ "-lw", \
|
||||
ARG_FLOAT32, \
|
||||
"6.5", \
|
||||
"Language model probability weight" }, \
|
||||
{ "-fwdflatlw", \
|
||||
ARG_FLOAT32, \
|
||||
"8.5", \
|
||||
"Language model probability weight for flat lexicon (2nd pass) decoding" }, \
|
||||
{ "-bestpathlw", \
|
||||
ARG_FLOAT32, \
|
||||
"9.5", \
|
||||
"Language model probability weight for bestpath search" }, \
|
||||
{ "-ascale", \
|
||||
ARG_FLOAT32, \
|
||||
"20.0", \
|
||||
"Inverse of acoustic model scale for confidence score calculation" }, \
|
||||
{ "-wip", \
|
||||
ARG_FLOAT32, \
|
||||
"0.65", \
|
||||
"Word insertion penalty" }, \
|
||||
{ "-nwpen", \
|
||||
ARG_FLOAT32, \
|
||||
"1.0", \
|
||||
"New word transition penalty" }, \
|
||||
{ "-pip", \
|
||||
ARG_FLOAT32, \
|
||||
"1.0", \
|
||||
"Phone insertion penalty" }, \
|
||||
{ "-uw", \
|
||||
ARG_FLOAT32, \
|
||||
"1.0", \
|
||||
"Unigram weight" }, \
|
||||
{ "-silprob", \
|
||||
ARG_FLOAT32, \
|
||||
"0.005", \
|
||||
"Silence word transition probability" }, \
|
||||
{ "-fillprob", \
|
||||
ARG_FLOAT32, \
|
||||
"1e-8", \
|
||||
"Filler word transition probability" } \
|
||||
|
||||
/** Command-line options for dictionaries. */
|
||||
#define POCKETSPHINX_DICT_OPTIONS \
|
||||
{ "-dict", \
|
||||
REQARG_STRING, \
|
||||
NULL, \
|
||||
"Main pronunciation dictionary (lexicon) input file" }, \
|
||||
{ "-fdict", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Noise word pronunciation dictionary input file" }, \
|
||||
{ "-dictcase", \
|
||||
ARG_BOOLEAN, \
|
||||
"no", \
|
||||
"Dictionary is case sensitive (NOTE: case insensitivity applies to ASCII characters only)" } \
|
||||
|
||||
/** Command-line options for acoustic modeling */
|
||||
#define POCKETSPHINX_ACMOD_OPTIONS \
|
||||
{ "-hmm", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Directory containing acoustic model files."}, \
|
||||
{ "-featparams", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"File containing feature extraction parameters."}, \
|
||||
{ "-mdef", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Model definition input file" }, \
|
||||
{ "-senmgau", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Senone to codebook mapping input file (usually not needed)" }, \
|
||||
{ "-tmat", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"HMM state transition matrix input file" }, \
|
||||
{ "-tmatfloor", \
|
||||
ARG_FLOAT32, \
|
||||
"0.0001", \
|
||||
"HMM state transition probability floor (applied to -tmat file)" }, \
|
||||
{ "-mean", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Mixture gaussian means input file" }, \
|
||||
{ "-var", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Mixture gaussian variances input file" }, \
|
||||
{ "-varfloor", \
|
||||
ARG_FLOAT32, \
|
||||
"0.0001", \
|
||||
"Mixture gaussian variance floor (applied to data from -var file)" }, \
|
||||
{ "-mixw", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Senone mixture weights input file (uncompressed)" }, \
|
||||
{ "-mixwfloor", \
|
||||
ARG_FLOAT32, \
|
||||
"0.0000001", \
|
||||
"Senone mixture weights floor (applied to data from -mixw file)" }, \
|
||||
{ "-aw", \
|
||||
ARG_INT32, \
|
||||
"1", \
|
||||
"Inverse weight applied to acoustic scores." }, \
|
||||
{ "-sendump", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"Senone dump (compressed mixture weights) input file" }, \
|
||||
{ "-mllr", \
|
||||
ARG_STRING, \
|
||||
NULL, \
|
||||
"MLLR transformation to apply to means and variances" }, \
|
||||
{ "-mmap", \
|
||||
ARG_BOOLEAN, \
|
||||
"yes", \
|
||||
"Use memory-mapped I/O (if possible) for model files" }, \
|
||||
{ "-ds", \
|
||||
ARG_INT32, \
|
||||
"1", \
|
||||
"Frame GMM computation downsampling ratio" }, \
|
||||
{ "-topn", \
|
||||
ARG_INT32, \
|
||||
"4", \
|
||||
"Maximum number of top Gaussians to use in scoring." }, \
|
||||
{ "-topn_beam", \
|
||||
ARG_STRING, \
|
||||
"0", \
|
||||
"Beam width used to determine top-N Gaussians (or a list, per-feature)" },\
|
||||
{ "-logbase", \
|
||||
ARG_FLOAT32, \
|
||||
"1.0001", \
|
||||
"Base in which all log-likelihoods calculated" }
|
||||
|
||||
#define CMDLN_EMPTY_OPTION { NULL, 0, NULL, NULL }
|
||||
|
||||
#endif /* __PS_CMDLN_MACRO_H__ */
|
|
@ -1,61 +0,0 @@
|
|||
# -*- Mode: python; indent-tabs-mode: nil; tab-width: 40 -*-
|
||||
# vim: set filetype=python:
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
LOCAL_INCLUDES += [
|
||||
'/media/sphinxbase',
|
||||
]
|
||||
|
||||
EXPORTS.pocketsphinx += [
|
||||
'pocketsphinx.h',
|
||||
]
|
||||
|
||||
UNIFIED_SOURCES += [
|
||||
'src/acmod.c',
|
||||
'src/bin_mdef.c',
|
||||
'src/blkarray_list.c',
|
||||
'src/dict.c',
|
||||
'src/dict2pid.c',
|
||||
'src/fsg_history.c',
|
||||
'src/fsg_lextree.c',
|
||||
'src/fsg_search.c',
|
||||
'src/hmm.c',
|
||||
'src/kws_detections.c',
|
||||
'src/kws_search.c',
|
||||
'src/mdef.c',
|
||||
'src/ms_gauden.c',
|
||||
'src/ms_mgau.c',
|
||||
'src/ms_senone.c',
|
||||
'src/ngram_search_fwdflat.c',
|
||||
'src/ngram_search_fwdtree.c',
|
||||
'src/phone_loop_search.c',
|
||||
'src/pocketsphinx.c',
|
||||
'src/ps_alignment.c',
|
||||
'src/ps_lattice.c',
|
||||
'src/ps_mllr.c',
|
||||
'src/ptm_mgau.c',
|
||||
'src/tmat.c',
|
||||
'src/vector.c',
|
||||
]
|
||||
|
||||
SOURCES += [
|
||||
'src/allphone_search.c',
|
||||
'src/ngram_search.c',
|
||||
'src/s2_semi_mgau.c',
|
||||
'src/state_align_search.c',
|
||||
]
|
||||
|
||||
# Suppress warnings in third-party code.
|
||||
if CONFIG['GNU_CC']:
|
||||
CFLAGS += [
|
||||
'-Wno-sign-compare',
|
||||
]
|
||||
if CONFIG['CLANG_CXX']:
|
||||
CFLAGS += ['-Wno-incompatible-pointer-types-discards-qualifiers']
|
||||
|
||||
# We allow warnings for third-party code that can be updated from upstream.
|
||||
ALLOW_COMPILER_WARNINGS = True
|
||||
|
||||
FINAL_LIBRARY = 'gkmedias'
|
|
@ -1,36 +0,0 @@
|
|||
/* ====================================================================
|
||||
* Copyright (c) 1999-2015 Carnegie Mellon University. All rights
|
||||
* reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* This work was supported in part by funding from the Defense Advanced
|
||||
* Research Projects Agency and the National Science Foundation of the
|
||||
* United States of America, and the CMU Sphinx Speech Consortium.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY CARNEGIE MELLON UNIVERSITY ``AS IS'' AND
|
||||
* ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
||||
* THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
||||
* PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL CARNEGIE MELLON UNIVERSITY
|
||||
* NOR ITS EMPLOYEES BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*
|
||||
* ====================================================================
|
||||
*
|
||||
*/
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue