Bug 1038061 - Allow specifying audio stream for speech recognition. r=smaug,ggp sr=smaug
authorShih-Chiang Chien <schien@mozilla.com>
Wed, 16 Jul 2014 09:38:59 +0800
changeset 216482 a038f26e9bbdf6c4a9e8badb7a1a0bed1d11293a
parent 216481 6a192af9008c889b1804cec1971e9242adb7bebd
child 216483 f41eab62f108ebed6f1edf4813528c8f446ca53e
push id515
push userraliiev@mozilla.com
push dateMon, 06 Oct 2014 12:51:51 +0000
treeherdermozilla-release@267c7a481bef [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerssmaug, ggp, smaug
bugs1038061
milestone33.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1038061 - Allow specifying audio stream for speech recognition. r=smaug,ggp sr=smaug
content/media/webspeech/recognition/SpeechRecognition.cpp
content/media/webspeech/recognition/SpeechRecognition.h
content/media/webspeech/recognition/test/head.js
content/media/webspeech/recognition/test/test_abort.html
content/media/webspeech/recognition/test/test_audio_capture_error.html
content/media/webspeech/recognition/test/test_call_start_from_end_handler.html
content/media/webspeech/recognition/test/test_nested_eventloop.html
content/media/webspeech/recognition/test/test_recognition_service_error.html
content/media/webspeech/recognition/test/test_success_without_recognition_service.html
content/media/webspeech/recognition/test/test_timeout.html
dom/webidl/SpeechRecognition.webidl
--- a/content/media/webspeech/recognition/SpeechRecognition.cpp
+++ b/content/media/webspeech/recognition/SpeechRecognition.cpp
@@ -579,29 +579,22 @@ SpeechRecognition::Observe(nsISupports* 
   }
 
   return NS_OK;
 }
 
 void
 SpeechRecognition::ProcessTestEventRequest(nsISupports* aSubject, const nsAString& aEventName)
 {
-  if (aEventName.EqualsLiteral("EVENT_START")) {
-    ErrorResult err;
-    Start(err);
-  } else if (aEventName.EqualsLiteral("EVENT_STOP")) {
-    Stop();
-  } else if (aEventName.EqualsLiteral("EVENT_ABORT")) {
+  if (aEventName.EqualsLiteral("EVENT_ABORT")) {
     Abort();
   } else if (aEventName.EqualsLiteral("EVENT_AUDIO_ERROR")) {
     DispatchError(SpeechRecognition::EVENT_AUDIO_ERROR,
                   SpeechRecognitionErrorCode::Audio_capture, // TODO different codes?
                   NS_LITERAL_STRING("AUDIO_ERROR test event"));
-  } else if (aEventName.EqualsLiteral("EVENT_AUDIO_DATA")) {
-    StartRecording(static_cast<DOMMediaStream*>(aSubject));
   } else {
     NS_ASSERTION(mTestConfig.mFakeRecognitionService,
                  "Got request for fake recognition service event, but "
                  TEST_PREFERENCE_FAKE_RECOGNITION_SERVICE " is unset");
 
     // let the fake recognition service handle the request
   }
 
@@ -688,17 +681,17 @@ SpeechRecognition::GetServiceURI(nsStrin
 void
 SpeechRecognition::SetServiceURI(const nsAString& aArg, ErrorResult& aRv)
 {
   aRv.Throw(NS_ERROR_NOT_IMPLEMENTED);
   return;
 }
 
 void
-SpeechRecognition::Start(ErrorResult& aRv)
+SpeechRecognition::Start(const Optional<NonNull<DOMMediaStream>>& aStream, ErrorResult& aRv)
 {
   if (mCurrentState != STATE_IDLE) {
     aRv.Throw(NS_ERROR_DOM_INVALID_STATE_ERR);
     return;
   }
 
   nsAutoCString speechRecognitionServiceCID;
   GetRecognitionServiceCID(speechRecognitionServiceCID);
@@ -708,17 +701,19 @@ SpeechRecognition::Start(ErrorResult& aR
   NS_ENSURE_SUCCESS_VOID(rv);
 
   rv = mRecognitionService->Initialize(this->asWeakPtr());
   NS_ENSURE_SUCCESS_VOID(rv);
 
   MediaStreamConstraints constraints;
   constraints.mAudio.SetAsBoolean() = true;
 
-  if (!mTestConfig.mFakeFSMEvents) {
+  if (aStream.WasPassed()) {
+    StartRecording(&aStream.Value());
+  } else {
     MediaManager* manager = MediaManager::Get();
     manager->GetUserMedia(false,
                           GetOwner(),
                           constraints,
                           new GetUserMediaSuccessCallback(this),
                           new GetUserMediaErrorCallback(this));
   }
 
--- a/content/media/webspeech/recognition/SpeechRecognition.h
+++ b/content/media/webspeech/recognition/SpeechRecognition.h
@@ -91,17 +91,17 @@ public:
   uint32_t GetMaxAlternatives(ErrorResult& aRv) const;
 
   void SetMaxAlternatives(uint32_t aArg, ErrorResult& aRv);
 
   void GetServiceURI(nsString& aRetVal, ErrorResult& aRv) const;
 
   void SetServiceURI(const nsAString& aArg, ErrorResult& aRv);
 
-  void Start(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)
--- a/content/media/webspeech/recognition/test/head.js
+++ b/content/media/webspeech/recognition/test/head.js
@@ -85,44 +85,43 @@ function EventManager(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;
     }
 
-    var subject = null;
-
-    if (eventName === "EVENT_AUDIO_DATA") {
-      isSendingAudioData = true;
-      var audioTag = document.createElement("audio");
-      audioTag.src = self.audioSampleFile;
-
-      subject = audioTag.mozCaptureStreamUntilEnded();
-      audioTag.addEventListener("ended", function() {
-        info("Sample stream ended, requesting queued events");
-        isSendingAudioData = false;
-        while (queuedEventRequests.length) {
-          self.requestFSMEvent(queuedEventRequests.shift());
-        }
-      });
-
-      audioTag.play();
-    }
-
     info("requesting " + eventName);
-    Services.obs.notifyObservers(subject,
+    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);
   }
 }
@@ -163,13 +162,15 @@ function performTest(options) {
       }
     }
 
     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]);
     }
   });
 }
--- a/content/media/webspeech/recognition/test/test_abort.html
+++ b/content/media/webspeech/recognition/test/test_abort.html
@@ -52,17 +52,17 @@ https://bugzilla.mozilla.org/show_bug.cg
     info("Aborting on " + nextEvent);
     expectedEvents[nextEvent] = function(evt, sr) {
       sr.abort();
     };
 
     nextEventIdx++;
 
     performTest({
-      eventsToRequest: ["EVENT_START", "EVENT_AUDIO_DATA"],
+      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>
--- a/content/media/webspeech/recognition/test/test_audio_capture_error.html
+++ b/content/media/webspeech/recognition/test/test_audio_capture_error.html
@@ -16,17 +16,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 <script type="text/javascript">
   SimpleTest.waitForExplicitFinish();
 
   performTest({
-    eventsToRequest: ['EVENT_START', 'EVENT_AUDIO_ERROR'],
+    eventsToRequest: ['EVENT_AUDIO_ERROR'],
     expectedEvents: {
       'error': buildErrorCallback(errorCodes.AUDIO_CAPTURE),
       'end': null
     },
     doneFunc: SimpleTest.finish,
     prefs: [["media.webspeech.test.fake_fsm_events", true]]
   });
 </script>
--- a/content/media/webspeech/recognition/test/test_call_start_from_end_handler.html
+++ b/content/media/webspeech/recognition/test/test_call_start_from_end_handler.html
@@ -15,41 +15,49 @@ https://bugzilla.mozilla.org/show_bug.cg
 <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;
+  }
+
   function endHandler(evt, sr) {
     try {
-      sr.start(); // shouldn't fail
+      sr.start(createAudioStream()); // shouldn't fail
     } catch (err) {
       ok(false, "Failed to start() from end() callback");
     }
 
     info("Successfully start() from end() callback");
   }
 
   function expectExceptionHandler(evt, sr) {
     try {
-      sr.start();
+      sr.start(createAudioStream());
     } catch (err) {
       is(err.name, "InvalidStateError");
       return;
     }
 
     ok(false, "Calling start() didn't raise InvalidStateError");
   }
 
   performTest({
     eventsToRequest: [
-      'EVENT_START',
-      'EVENT_AUDIO_DATA',
       'EVENT_RECOGNITIONSERVICE_FINAL_RESULT'
     ],
     expectedEvents: {
       'start': expectExceptionHandler,
       'audiostart': expectExceptionHandler,
       'speechstart': expectExceptionHandler,
       'speechend': expectExceptionHandler,
       'audioend': expectExceptionHandler,
--- a/content/media/webspeech/recognition/test/test_nested_eventloop.html
+++ b/content/media/webspeech/recognition/test/test_nested_eventloop.html
@@ -61,20 +61,17 @@ https://bugzilla.mozilla.org/show_bug.cg
    * 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: [
-      "EVENT_START",
-      "EVENT_AUDIO_DATA",
-    ],
+    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]]
--- a/content/media/webspeech/recognition/test/test_recognition_service_error.html
+++ b/content/media/webspeech/recognition/test/test_recognition_service_error.html
@@ -17,18 +17,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 </div>
 <pre id="test">
 <script type="text/javascript">
   SimpleTest.waitForExplicitFinish();
 
   performTest({
     eventsToRequest: [
-      'EVENT_START',
-      'EVENT_AUDIO_DATA',
       'EVENT_RECOGNITIONSERVICE_ERROR'
     ],
     expectedEvents: {
       'start': null,
       'audiostart': null,
       'speechstart': null,
       'speechend': null,
       'audioend': null,
--- a/content/media/webspeech/recognition/test/test_success_without_recognition_service.html
+++ b/content/media/webspeech/recognition/test/test_success_without_recognition_service.html
@@ -17,18 +17,16 @@ https://bugzilla.mozilla.org/show_bug.cg
 
 </div>
 <pre id="test">
 <script type="text/javascript">
   SimpleTest.waitForExplicitFinish();
 
   performTest({
     eventsToRequest: [
-      'EVENT_START',
-      'EVENT_AUDIO_DATA',
       'EVENT_RECOGNITIONSERVICE_FINAL_RESULT'
     ],
     expectedEvents: {
       'start': null,
       'audiostart': null,
       'speechstart': null,
       'speechend': null,
       'audioend': null,
--- a/content/media/webspeech/recognition/test/test_timeout.html
+++ b/content/media/webspeech/recognition/test/test_timeout.html
@@ -16,20 +16,17 @@ https://bugzilla.mozilla.org/show_bug.cg
 <div id="content" style="display: none">
 
 </div>
 <pre id="test">
 <script type="text/javascript">
   SimpleTest.waitForExplicitFinish();
 
   performTest({
-    eventsToRequest: [
-      "EVENT_START",
-      "EVENT_AUDIO_DATA"
-    ],
+    eventsToRequest: [],
     expectedEvents: {
       "start": null,
       "audiostart": null,
       "audioend": null,
       "error": buildErrorCallback(errorCodes.NO_SPEECH),
       "end": null
     },
     doneFunc: SimpleTest.finish,
--- a/dom/webidl/SpeechRecognition.webidl
+++ b/dom/webidl/SpeechRecognition.webidl
@@ -24,17 +24,17 @@ interface SpeechRecognition : EventTarge
     attribute boolean interimResults;
     [Throws]
     attribute unsigned long maxAlternatives;
     [Throws]
     attribute DOMString serviceURI;
 
     // methods to drive the speech interaction
     [Throws]
-    void start();
+    void start(optional MediaStream stream);
     void stop();
     void abort();
 
     // event methods
     attribute EventHandler onaudiostart;
     attribute EventHandler onsoundstart;
     attribute EventHandler onspeechstart;
     attribute EventHandler onspeechend;