LCOV - code coverage report
Current view: top level - dom/media/webspeech/synth/test - nsFakeSynthServices.cpp (source / functions) Hit Total Coverage
Test: output.info Lines: 2 146 1.4 %
Date: 2017-07-14 16:53:18 Functions: 2 66 3.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim:set ts=2 sw=2 sts=2 et cindent: */
       3             : /* This Source Code Form is subject to the terms of the Mozilla Public
       4             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       5             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
       6             : 
       7             : #include "nsISupports.h"
       8             : #include "nsFakeSynthServices.h"
       9             : #include "nsPrintfCString.h"
      10             : #include "nsIWeakReferenceUtils.h"
      11             : #include "SharedBuffer.h"
      12             : #include "nsISimpleEnumerator.h"
      13             : 
      14             : #include "mozilla/dom/nsSynthVoiceRegistry.h"
      15             : #include "mozilla/dom/nsSpeechTask.h"
      16             : 
      17             : #include "nsThreadUtils.h"
      18             : #include "prenv.h"
      19             : #include "mozilla/Preferences.h"
      20             : #include "mozilla/DebugOnly.h"
      21             : 
      22             : #define CHANNELS 1
      23             : #define SAMPLERATE 1600
      24             : 
      25             : namespace mozilla {
      26             : namespace dom {
      27             : 
      28           3 : StaticRefPtr<nsFakeSynthServices> nsFakeSynthServices::sSingleton;
      29             : 
      30             : enum VoiceFlags
      31             : {
      32             :   eSuppressEvents = 1,
      33             :   eSuppressEnd = 2,
      34             :   eFailAtStart = 4,
      35             :   eFail = 8
      36             : };
      37             : 
      38             : struct VoiceDetails
      39             : {
      40             :   const char* uri;
      41             :   const char* name;
      42             :   const char* lang;
      43             :   bool defaultVoice;
      44             :   uint32_t flags;
      45             : };
      46             : 
      47             : static const VoiceDetails sDirectVoices[] = {
      48             :   {"urn:moz-tts:fake-direct:bob", "Bob Marley", "en-JM", true, 0},
      49             :   {"urn:moz-tts:fake-direct:amy", "Amy Winehouse", "en-GB", false, 0},
      50             :   {"urn:moz-tts:fake-direct:lenny", "Leonard Cohen", "en-CA", false, 0},
      51             :   {"urn:moz-tts:fake-direct:celine", "Celine Dion", "fr-CA", false, 0},
      52             :   {"urn:moz-tts:fake-direct:julie", "Julieta Venegas", "es-MX", false, },
      53             : };
      54             : 
      55             : static const VoiceDetails sIndirectVoices[] = {
      56             :   {"urn:moz-tts:fake-indirect:zanetta", "Zanetta Farussi", "it-IT", false, 0},
      57             :   {"urn:moz-tts:fake-indirect:margherita", "Margherita Durastanti", "it-IT-noevents-noend", false, eSuppressEvents | eSuppressEnd},
      58             :   {"urn:moz-tts:fake-indirect:teresa", "Teresa Cornelys", "it-IT-noend", false, eSuppressEnd},
      59             :   {"urn:moz-tts:fake-indirect:cecilia", "Cecilia Bartoli", "it-IT-failatstart", false, eFailAtStart},
      60             :   {"urn:moz-tts:fake-indirect:gottardo", "Gottardo Aldighieri", "it-IT-fail", false, eFail},
      61             : };
      62             : 
      63             : // FakeSynthCallback
      64             : class FakeSynthCallback : public nsISpeechTaskCallback
      65             : {
      66             : public:
      67           0 :   explicit FakeSynthCallback(nsISpeechTask* aTask) : mTask(aTask) { }
      68             :   NS_DECL_CYCLE_COLLECTING_ISUPPORTS
      69           0 :   NS_DECL_CYCLE_COLLECTION_CLASS_AMBIGUOUS(FakeSynthCallback, nsISpeechTaskCallback)
      70             : 
      71           0 :   NS_IMETHOD OnPause() override
      72             :   {
      73           0 :     if (mTask) {
      74           0 :       mTask->DispatchPause(1.5, 1);
      75             :     }
      76             : 
      77           0 :     return NS_OK;
      78             :   }
      79             : 
      80           0 :   NS_IMETHOD OnResume() override
      81             :   {
      82           0 :     if (mTask) {
      83           0 :       mTask->DispatchResume(1.5, 1);
      84             :     }
      85             : 
      86           0 :     return NS_OK;
      87             :   }
      88             : 
      89           0 :   NS_IMETHOD OnCancel() override
      90             :   {
      91           0 :     if (mTask) {
      92           0 :       mTask->DispatchEnd(1.5, 1);
      93             :     }
      94             : 
      95           0 :     return NS_OK;
      96             :   }
      97             : 
      98           0 :   NS_IMETHOD OnVolumeChanged(float aVolume) override
      99             :   {
     100           0 :     return NS_OK;
     101             :   }
     102             : 
     103             : private:
     104           0 :   virtual ~FakeSynthCallback() { }
     105             : 
     106             :   nsCOMPtr<nsISpeechTask> mTask;
     107             : };
     108             : 
     109           0 : NS_IMPL_CYCLE_COLLECTION(FakeSynthCallback, mTask);
     110             : 
     111           0 : NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(FakeSynthCallback)
     112           0 :   NS_INTERFACE_MAP_ENTRY(nsISpeechTaskCallback)
     113           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsISpeechTaskCallback)
     114           0 : NS_INTERFACE_MAP_END
     115             : 
     116           0 : NS_IMPL_CYCLE_COLLECTING_ADDREF(FakeSynthCallback)
     117           0 : NS_IMPL_CYCLE_COLLECTING_RELEASE(FakeSynthCallback)
     118             : 
     119             : // FakeDirectAudioSynth
     120             : 
     121             : class FakeDirectAudioSynth : public nsISpeechService
     122             : {
     123             : 
     124             : public:
     125           0 :   FakeDirectAudioSynth() { }
     126             : 
     127             :   NS_DECL_ISUPPORTS
     128             :   NS_DECL_NSISPEECHSERVICE
     129             : 
     130             : private:
     131           0 :   virtual ~FakeDirectAudioSynth() { }
     132             : };
     133             : 
     134           0 : NS_IMPL_ISUPPORTS(FakeDirectAudioSynth, nsISpeechService)
     135             : 
     136             : NS_IMETHODIMP
     137           0 : FakeDirectAudioSynth::Speak(const nsAString& aText, const nsAString& aUri,
     138             :                             float aVolume, float aRate, float aPitch,
     139             :                             nsISpeechTask* aTask)
     140             : {
     141           0 :   class Runnable final : public mozilla::Runnable
     142             :   {
     143             :   public:
     144           0 :     Runnable(nsISpeechTask* aTask, const nsAString& aText)
     145           0 :       : mozilla::Runnable("Runnable")
     146             :       , mTask(aTask)
     147           0 :       , mText(aText)
     148             :     {
     149           0 :     }
     150             : 
     151           0 :     NS_IMETHOD Run() override
     152             :     {
     153           0 :       RefPtr<FakeSynthCallback> cb = new FakeSynthCallback(nullptr);
     154           0 :       mTask->Setup(cb, CHANNELS, SAMPLERATE, 2);
     155             : 
     156             :       // Just an arbitrary multiplier. Pretend that each character is
     157             :       // synthesized to 40 frames.
     158           0 :       uint32_t frames_length = 40 * mText.Length();
     159           0 :       auto frames = MakeUnique<int16_t[]>(frames_length);
     160           0 :       mTask->SendAudioNative(frames.get(), frames_length);
     161             : 
     162           0 :       mTask->SendAudioNative(nullptr, 0);
     163             : 
     164           0 :       return NS_OK;
     165             :     }
     166             : 
     167             :   private:
     168             :     nsCOMPtr<nsISpeechTask> mTask;
     169             :     nsString mText;
     170             :   };
     171             : 
     172           0 :   nsCOMPtr<nsIRunnable> runnable = new Runnable(aTask, aText);
     173           0 :   NS_DispatchToMainThread(runnable);
     174           0 :   return NS_OK;
     175             : }
     176             : 
     177             : NS_IMETHODIMP
     178           0 : FakeDirectAudioSynth::GetServiceType(SpeechServiceType* aServiceType)
     179             : {
     180           0 :   *aServiceType = nsISpeechService::SERVICETYPE_DIRECT_AUDIO;
     181           0 :   return NS_OK;
     182             : }
     183             : 
     184             : // FakeDirectAudioSynth
     185             : 
     186             : class FakeIndirectAudioSynth : public nsISpeechService
     187             : {
     188             : 
     189             : public:
     190           0 :   FakeIndirectAudioSynth() {}
     191             : 
     192             :   NS_DECL_ISUPPORTS
     193             :   NS_DECL_NSISPEECHSERVICE
     194             : 
     195             : private:
     196           0 :   virtual ~FakeIndirectAudioSynth() { }
     197             : };
     198             : 
     199           0 : NS_IMPL_ISUPPORTS(FakeIndirectAudioSynth, nsISpeechService)
     200             : 
     201             : NS_IMETHODIMP
     202           0 : FakeIndirectAudioSynth::Speak(const nsAString& aText, const nsAString& aUri,
     203             :                               float aVolume, float aRate, float aPitch,
     204             :                               nsISpeechTask* aTask)
     205             : {
     206           0 :   class DispatchStart final : public Runnable
     207             :   {
     208             :   public:
     209           0 :     explicit DispatchStart(nsISpeechTask* aTask)
     210           0 :       : mozilla::Runnable("DispatchStart")
     211           0 :       , mTask(aTask)
     212             :     {
     213           0 :     }
     214             : 
     215           0 :     NS_IMETHOD Run() override
     216             :     {
     217           0 :       mTask->DispatchStart();
     218             : 
     219           0 :       return NS_OK;
     220             :     }
     221             : 
     222             :   private:
     223             :     nsCOMPtr<nsISpeechTask> mTask;
     224             :   };
     225             : 
     226           0 :   class DispatchEnd final : public Runnable
     227             :   {
     228             :   public:
     229           0 :     DispatchEnd(nsISpeechTask* aTask, const nsAString& aText)
     230           0 :       : mozilla::Runnable("DispatchEnd")
     231             :       , mTask(aTask)
     232           0 :       , mText(aText)
     233             :     {
     234           0 :     }
     235             : 
     236           0 :     NS_IMETHOD Run() override
     237             :     {
     238           0 :       mTask->DispatchEnd(mText.Length()/2, mText.Length());
     239             : 
     240           0 :       return NS_OK;
     241             :     }
     242             : 
     243             :   private:
     244             :     nsCOMPtr<nsISpeechTask> mTask;
     245             :     nsString mText;
     246             :   };
     247             : 
     248           0 :   class DispatchError final : public Runnable
     249             :   {
     250             :   public:
     251           0 :     DispatchError(nsISpeechTask* aTask, const nsAString& aText)
     252           0 :       : mozilla::Runnable("DispatchError")
     253             :       , mTask(aTask)
     254           0 :       , mText(aText)
     255             :     {
     256           0 :     }
     257             : 
     258           0 :     NS_IMETHOD Run() override
     259             :     {
     260           0 :       mTask->DispatchError(mText.Length()/2, mText.Length());
     261             : 
     262           0 :       return NS_OK;
     263             :     }
     264             : 
     265             :   private:
     266             :     nsCOMPtr<nsISpeechTask> mTask;
     267             :     nsString mText;
     268             :   };
     269             : 
     270           0 :   uint32_t flags = 0;
     271           0 :   for (uint32_t i = 0; i < ArrayLength(sIndirectVoices); i++) {
     272           0 :     if (aUri.EqualsASCII(sIndirectVoices[i].uri)) {
     273           0 :       flags = sIndirectVoices[i].flags;
     274             :     }
     275             :   }
     276             : 
     277           0 :   if (flags & eFailAtStart) {
     278           0 :     return NS_ERROR_FAILURE;
     279             :   }
     280             : 
     281             :   RefPtr<FakeSynthCallback> cb = new FakeSynthCallback(
     282           0 :     (flags & eSuppressEvents) ? nullptr : aTask);
     283             : 
     284           0 :   aTask->Setup(cb, 0, 0, 0);
     285             : 
     286           0 :   nsCOMPtr<nsIRunnable> runnable = new DispatchStart(aTask);
     287           0 :   NS_DispatchToMainThread(runnable);
     288             : 
     289           0 :   if (flags & eFail) {
     290           0 :     runnable = new DispatchError(aTask, aText);
     291           0 :     NS_DispatchToMainThread(runnable);
     292           0 :   } else if ((flags & eSuppressEnd) == 0) {
     293           0 :     runnable = new DispatchEnd(aTask, aText);
     294           0 :     NS_DispatchToMainThread(runnable);
     295             :   }
     296             : 
     297           0 :   return NS_OK;
     298             : }
     299             : 
     300             : NS_IMETHODIMP
     301           0 : FakeIndirectAudioSynth::GetServiceType(SpeechServiceType* aServiceType)
     302             : {
     303           0 :   *aServiceType = nsISpeechService::SERVICETYPE_INDIRECT_AUDIO;
     304           0 :   return NS_OK;
     305             : }
     306             : 
     307             : // nsFakeSynthService
     308             : 
     309           0 : NS_INTERFACE_MAP_BEGIN(nsFakeSynthServices)
     310           0 :   NS_INTERFACE_MAP_ENTRY(nsIObserver)
     311           0 :   NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
     312           0 : NS_INTERFACE_MAP_END
     313             : 
     314           0 : NS_IMPL_ADDREF(nsFakeSynthServices)
     315           0 : NS_IMPL_RELEASE(nsFakeSynthServices)
     316             : 
     317           0 : nsFakeSynthServices::nsFakeSynthServices()
     318             : {
     319           0 : }
     320             : 
     321           0 : nsFakeSynthServices::~nsFakeSynthServices()
     322             : {
     323           0 : }
     324             : 
     325             : static void
     326           0 : AddVoices(nsISpeechService* aService, const VoiceDetails* aVoices, uint32_t aLength)
     327             : {
     328           0 :   RefPtr<nsSynthVoiceRegistry> registry = nsSynthVoiceRegistry::GetInstance();
     329           0 :   for (uint32_t i = 0; i < aLength; i++) {
     330           0 :     NS_ConvertUTF8toUTF16 name(aVoices[i].name);
     331           0 :     NS_ConvertUTF8toUTF16 uri(aVoices[i].uri);
     332           0 :     NS_ConvertUTF8toUTF16 lang(aVoices[i].lang);
     333             :     // These services can handle more than one utterance at a time and have
     334             :     // several speaking simultaniously. So, aQueuesUtterances == false
     335           0 :     registry->AddVoice(aService, uri, name, lang, true, false);
     336           0 :     if (aVoices[i].defaultVoice) {
     337           0 :       registry->SetDefaultVoice(uri, true);
     338             :     }
     339             :   }
     340             : 
     341           0 :   registry->NotifyVoicesChanged();
     342           0 : }
     343             : 
     344             : void
     345           0 : nsFakeSynthServices::Init()
     346             : {
     347           0 :   mDirectService = new FakeDirectAudioSynth();
     348           0 :   AddVoices(mDirectService, sDirectVoices, ArrayLength(sDirectVoices));
     349             : 
     350           0 :   mIndirectService = new FakeIndirectAudioSynth();
     351           0 :   AddVoices(mIndirectService, sIndirectVoices, ArrayLength(sIndirectVoices));
     352           0 : }
     353             : 
     354             : // nsIObserver
     355             : 
     356             : NS_IMETHODIMP
     357           0 : nsFakeSynthServices::Observe(nsISupports* aSubject, const char* aTopic,
     358             :                              const char16_t* aData)
     359             : {
     360           0 :   MOZ_ASSERT(NS_IsMainThread());
     361           0 :   if(NS_WARN_IF(!(!strcmp(aTopic, "speech-synth-started")))) {
     362           0 :     return NS_ERROR_UNEXPECTED;
     363             :   }
     364             : 
     365           0 :   if (Preferences::GetBool("media.webspeech.synth.test")) {
     366           0 :     NS_DispatchToMainThread(NewRunnableMethod(
     367           0 :       "dom::nsFakeSynthServices::Init", this, &nsFakeSynthServices::Init));
     368             :   }
     369             : 
     370           0 :   return NS_OK;
     371             : }
     372             : 
     373             : // static methods
     374             : 
     375             : nsFakeSynthServices*
     376           0 : nsFakeSynthServices::GetInstance()
     377             : {
     378           0 :   MOZ_ASSERT(NS_IsMainThread());
     379           0 :   if (!XRE_IsParentProcess()) {
     380           0 :     MOZ_ASSERT(false, "nsFakeSynthServices can only be started on main gecko process");
     381             :     return nullptr;
     382             :   }
     383             : 
     384           0 :   if (!sSingleton) {
     385           0 :     sSingleton = new nsFakeSynthServices();
     386             :   }
     387             : 
     388           0 :   return sSingleton;
     389             : }
     390             : 
     391             : already_AddRefed<nsFakeSynthServices>
     392           0 : nsFakeSynthServices::GetInstanceForService()
     393             : {
     394           0 :   RefPtr<nsFakeSynthServices> picoService = GetInstance();
     395           0 :   return picoService.forget();
     396             : }
     397             : 
     398             : void
     399           0 : nsFakeSynthServices::Shutdown()
     400             : {
     401           0 :   if (!sSingleton) {
     402           0 :     return;
     403             :   }
     404             : 
     405           0 :   sSingleton = nullptr;
     406             : }
     407             : 
     408             : } // namespace dom
     409           9 : } // namespace mozilla

Generated by: LCOV version 1.13