Backed out 3 changesets (bug 1081819) for frequent mochitest-e10s failures
authorPhil Ringnalda <philringnalda@gmail.com>
Sat, 07 Mar 2015 18:14:05 -0800
changeset 232421 803e783be389
parent 232420 7fa300ea1b1d
child 232453 a444db7e60f3
push id56554
push userphilringnalda@gmail.com
push dateSun, 08 Mar 2015 02:14:15 +0000
treeherdermozilla-inbound@803e783be389 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
bugs1081819
milestone39.0a1
backs outb78fd38002f5
ff063b9a1ea2
322d60fc413e
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
Backed out 3 changesets (bug 1081819) for frequent mochitest-e10s failures Backed out changeset b78fd38002f5 (bug 1081819) Backed out changeset ff063b9a1ea2 (bug 1081819) Backed out changeset 322d60fc413e (bug 1081819)
dom/media/TrackUnionStream.cpp
dom/media/TrackUnionStream.h
dom/media/tests/mochitest/mochitest.ini
dom/media/tests/mochitest/test_peerConnection_webAudio.html
dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
--- a/dom/media/TrackUnionStream.cpp
+++ b/dom/media/TrackUnionStream.cpp
@@ -45,17 +45,18 @@ namespace mozilla {
 #ifdef PR_LOGGING
 PRLogModuleInfo* gTrackUnionStreamLog;
 #define STREAM_LOG(type, msg) PR_LOG(gTrackUnionStreamLog, type, msg)
 #else
 #define STREAM_LOG(type, msg)
 #endif
 
 TrackUnionStream::TrackUnionStream(DOMMediaStream* aWrapper) :
-  ProcessedMediaStream(aWrapper)
+  ProcessedMediaStream(aWrapper),
+  mFilterCallback(nullptr)
 {
 #ifdef PR_LOGGING
   if (!gTrackUnionStreamLog) {
     gTrackUnionStreamLog = PR_NewLogModule("TrackUnionStream");
   }
 #endif
 }
 
@@ -108,17 +109,17 @@ TrackUnionStream::TrackUnionStream(DOMMe
               CopyTrackData(tracks.get(), j, aFrom, aTo, &trackFinished);
             }
             mappedTracksFinished[j] = trackFinished;
             mappedTracksWithMatchingInputTracks[j] = true;
             found = true;
             break;
           }
         }
-        if (!found) {
+        if (!found && (!mFilterCallback || mFilterCallback(tracks.get()))) {
           bool trackFinished = false;
           trackAdded = true;
           uint32_t mapIndex = AddTrack(mInputs[i], tracks.get(), aFrom);
           CopyTrackData(tracks.get(), mapIndex, aFrom, aTo, &trackFinished);
           mappedTracksFinished.AppendElement(trackFinished);
           mappedTracksWithMatchingInputTracks.AppendElement(true);
         }
       }
@@ -147,16 +148,24 @@ TrackUnionStream::TrackUnionStream(DOMMe
       mBuffer.AdvanceKnownTracksTime(GraphTimeToStreamTime(aTo));
     }
     if (allHaveCurrentData) {
       // We can make progress if we're not blocked
       mHasCurrentData = true;
     }
   }
 
+  // Consumers may specify a filtering callback to apply to every input track.
+  // Returns true to allow the track to act as an input; false to reject it entirely.
+
+  void TrackUnionStream::SetTrackIDFilter(TrackIDFilterCallback aCallback)
+  {
+    mFilterCallback = aCallback;
+  }
+
   // Forward SetTrackEnabled(output_track_id, enabled) to the Source MediaStream,
   // translating the output track ID into the correct ID in the source.
   void TrackUnionStream::ForwardTrackEnabled(TrackID aOutputID, bool aEnabled)
   {
     for (int32_t i = mTrackMap.Length() - 1; i >= 0; --i) {
       if (mTrackMap[i].mOutputTrackID == aOutputID) {
         mTrackMap[i].mInputPort->GetSource()->
           SetTrackEnabled(mTrackMap[i].mInputTrackID, aEnabled);
@@ -267,18 +276,16 @@ TrackUnionStream::TrackUnionStream(DOMMe
 
       StreamTime outputStart = outputTrack->GetEnd();
 
       if (interval.mInputIsBlocked) {
         // Maybe the input track ended?
         segment->AppendNullData(ticks);
         STREAM_LOG(PR_LOG_DEBUG+1, ("TrackUnionStream %p appending %lld ticks of null data to track %d",
                    this, (long long)ticks, outputTrack->GetID()));
-      } else if (InMutedCycle()) {
-        segment->AppendNullData(ticks);
       } else {
         MOZ_ASSERT(outputTrack->GetEnd() == GraphTimeToStreamTime(interval.mStart),
                    "Samples missing");
         StreamTime inputStart = source->GraphTimeToStreamTime(interval.mStart);
         segment->AppendSlice(*aInputTrack->GetSegment(),
                              std::min(inputTrackEndPoint, inputStart),
                              std::min(inputTrackEndPoint, inputEnd));
       }
--- a/dom/media/TrackUnionStream.h
+++ b/dom/media/TrackUnionStream.h
@@ -16,21 +16,29 @@ namespace mozilla {
  */
 class TrackUnionStream : public ProcessedMediaStream {
 public:
   explicit TrackUnionStream(DOMMediaStream* aWrapper);
 
   virtual void RemoveInput(MediaInputPort* aPort) MOZ_OVERRIDE;
   virtual void ProcessInput(GraphTime aFrom, GraphTime aTo, uint32_t aFlags) MOZ_OVERRIDE;
 
+  // Consumers may specify a filtering callback to apply to every input track.
+  // Returns true to allow the track to act as an input; false to reject it entirely.
+  typedef bool (*TrackIDFilterCallback)(StreamBuffer::Track*);
+
+  void SetTrackIDFilter(TrackIDFilterCallback aCallback);
+
   // Forward SetTrackEnabled(output_track_id, enabled) to the Source MediaStream,
   // translating the output track ID into the correct ID in the source.
   virtual void ForwardTrackEnabled(TrackID aOutputID, bool aEnabled) MOZ_OVERRIDE;
 
 protected:
+  TrackIDFilterCallback mFilterCallback;
+
   // Only non-ended tracks are allowed to persist in this map.
   struct TrackMapEntry {
     // mEndOfConsumedInputTicks is the end of the input ticks that we've consumed.
     // 0 if we haven't consumed any yet.
     StreamTime mEndOfConsumedInputTicks;
     // mEndOfLastInputIntervalInInputStream is the timestamp for the end of the
     // previous interval which was unblocked for both the input and output
     // stream, in the input stream's timeline, or -1 if there wasn't one.
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -173,13 +173,11 @@ skip-if = toolkit == 'gonk' # b2g (Bug 1
 [test_peerConnection_addSecondVideoStreamNoBundle.html]
 skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
 [test_peerConnection_removeThenAddVideoTrackNoBundle.html]
 skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
 [test_peerConnection_addDataChannel.html]
 skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
 [test_peerConnection_addDataChannelNoBundle.html]
 skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
-[test_peerConnection_webAudio.html]
-skip-if = toolkit == 'gonk' # b2g (Bug 1059867)
 
 # Bug 950317: Hack for making a cleanup hook after finishing all WebRTC cases
 [test_zmedia_cleanup.html]
deleted file mode 100644
--- a/dom/media/tests/mochitest/test_peerConnection_webAudio.html
+++ /dev/null
@@ -1,97 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <script type="application/javascript" src="pc.js"></script>
-</head>
-<body>
-<pre id="test">
-<script type="application/javascript;version=1.8">
-createHTML({
-  bug: "1081819",
-  title: "WebAudio on both input and output side of peerconnection"
-});
-
-// This tests WebAudio as input to a PeerConnection and a PeerConnection as
-// input to WebAudio. This is done by piping a 700Hz oscillator through an
-// analyser on the input side, the PeerConnection, and an analyser on the
-// output side. We then sanity check the audio by comparing the frequency domain
-// data from both analysers.
-
-runNetworkTest(function() {
-  var test = new PeerConnectionTest();
-
-  var audioContext = new AudioContext();
-  var inputAnalyser;
-  var outputAnalyser;
-
-  test.setMediaConstraints([{audio: true}], []);
-  test.chain.replace("PC_LOCAL_GUM", [
-    function PC_LOCAL_WEBAUDIO_SOURCE(test) {
-      var oscillator = audioContext.createOscillator();
-      oscillator.type = 'sine';
-      oscillator.frequency.value = 700;
-      oscillator.start();
-      inputAnalyser = audioContext.createAnalyser();
-      var dest = audioContext.createMediaStreamDestination();
-
-      oscillator.connect(inputAnalyser);
-      inputAnalyser.connect(dest);
-      test.pcLocal.attachMedia(dest.stream, 'audio', 'local');
-
-      return Promise.resolve();
-    }
-  ]);
-  test.chain.insertBefore("PC_REMOTE_SETUP_ADDSTREAM_HANDLER", [
-    function PC_REMOTE_REPLACE_ATTACHMEDIA(test) {
-      var realAttachMedia = test.pcRemote.attachMedia.bind(test.pcRemote);
-      test.pcRemote.attachMedia = function(stream, type, side) {
-        var source = audioContext.createMediaStreamSource(stream);
-        outputAnalyser = audioContext.createAnalyser();
-        var dest = audioContext.createMediaStreamDestination();
-
-        source.connect(outputAnalyser);
-        outputAnalyser.connect(dest);
-        realAttachMedia(dest.stream, type, side);
-      };
-      return Promise.resolve();
-  }]);
-  test.chain.append([
-    function CHECK_AUDIO_FLOW(test) {
-      var inputData = new Uint8Array(inputAnalyser.frequencyBinCount);
-      inputAnalyser.getByteFrequencyData(inputData);
-
-      var outputData = new Uint8Array(outputAnalyser.frequencyBinCount);
-      outputAnalyser.getByteFrequencyData(outputData);
-
-      is(inputData.length, outputData.length, "Equally sized datasets");
-      var numChecks = 0;
-      var sanityCheckFrequencyValue = function(i, input, output) {
-        // This is for sanity check only. The audio encoding applied on the
-        // output will cause some fairly large deviations from the input around
-        // the oscillator's frequency. However, the input analyser will reach
-        // its max value of 255 for multiple indices, so allowing a deviation
-        // of 50 for these is fine.
-        if (input < 200 && output < 200) {
-          // Save us some log output by skipping when both input and output
-          // are sufficiently low. 200 is a bit higher than preferred, but on
-          // Android we've seen the output being quite high (100-150) when
-          // input is fairly low (0-50), i.e., on frequencies neighboring 700Hz.
-          return 0;
-        }
-        ok(Math.abs(input - output) < 50,
-           "Sane audio frequency values at index " + i + "/" + inputData.length +
-           ", input=" + input + ", output=" + output);
-        return 1;
-      }
-      for (i = 0; i < inputData.length; ++i) {
-        numChecks += sanityCheckFrequencyValue(i, inputData[i], outputData[i]);
-      }
-      isnot(numChecks, 0, "Should have had some non-zero values analyzed");
-      return Promise.resolve();
-    }]);
-  test.run();
-});
-</script>
-</pre>
-</body>
-</html>
--- a/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
+++ b/dom/media/webaudio/MediaStreamAudioDestinationNode.cpp
@@ -18,31 +18,70 @@ namespace dom {
 NS_IMPL_CYCLE_COLLECTION_INHERITED(MediaStreamAudioDestinationNode, AudioNode, mDOMStream)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION_INHERITED(MediaStreamAudioDestinationNode)
 NS_INTERFACE_MAP_END_INHERITING(AudioNode)
 
 NS_IMPL_ADDREF_INHERITED(MediaStreamAudioDestinationNode, AudioNode)
 NS_IMPL_RELEASE_INHERITED(MediaStreamAudioDestinationNode, AudioNode)
 
+static const int MEDIA_STREAM_DEST_TRACK_ID = 2;
+static_assert(MEDIA_STREAM_DEST_TRACK_ID != AudioNodeStream::AUDIO_TRACK,
+              "MediaStreamAudioDestinationNode::MEDIA_STREAM_DEST_TRACK_ID must be a different value than AudioNodeStream::AUDIO_TRACK");
+
+class MediaStreamDestinationEngine : public AudioNodeEngine {
+public:
+  MediaStreamDestinationEngine(AudioNode* aNode, ProcessedMediaStream* aOutputStream)
+    : AudioNodeEngine(aNode)
+    , mOutputStream(aOutputStream)
+  {
+    MOZ_ASSERT(mOutputStream);
+  }
+
+  virtual void ProcessBlock(AudioNodeStream* aStream,
+                            const AudioChunk& aInput,
+                            AudioChunk* aOutput,
+                            bool* aFinished) MOZ_OVERRIDE
+  {
+    *aOutput = aInput;
+    StreamBuffer::Track* track = mOutputStream->EnsureTrack(MEDIA_STREAM_DEST_TRACK_ID);
+    AudioSegment* segment = track->Get<AudioSegment>();
+    segment->AppendAndConsumeChunk(aOutput);
+  }
+
+  virtual size_t SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const MOZ_OVERRIDE
+  {
+    return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
+  }
+
+private:
+  ProcessedMediaStream* mOutputStream;
+};
+
+// This callback is used to ensure that only the audio data for this track is audible
+static bool FilterAudioNodeStreamTrack(StreamBuffer::Track* aTrack)
+{
+  return aTrack->GetID() == MEDIA_STREAM_DEST_TRACK_ID;
+}
+
 MediaStreamAudioDestinationNode::MediaStreamAudioDestinationNode(AudioContext* aContext)
   : AudioNode(aContext,
               2,
               ChannelCountMode::Explicit,
               ChannelInterpretation::Speakers)
-  , mDOMStream(DOMAudioNodeMediaStream::CreateTrackUnionStream(GetOwner(), this))
+  , mDOMStream(DOMAudioNodeMediaStream::CreateTrackUnionStream(GetOwner(),
+                                                               this))
 {
-  // Ensure an audio track with the correct ID is exposed to JS
-  mDOMStream->CreateDOMTrack(AudioNodeStream::AUDIO_TRACK, MediaSegment::AUDIO);
+  TrackUnionStream* tus = static_cast<TrackUnionStream*>(mDOMStream->GetStream());
+  MOZ_ASSERT(tus == mDOMStream->GetStream()->AsProcessedStream());
+  tus->SetTrackIDFilter(FilterAudioNodeStreamTrack);
 
-  ProcessedMediaStream* outputStream = mDOMStream->GetStream()->AsProcessedStream();
-  MOZ_ASSERT(!!outputStream);
-  AudioNodeEngine* engine = new AudioNodeEngine(this);
-  mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::EXTERNAL_STREAM);
-  mPort = outputStream->AllocateInputPort(mStream);
+  MediaStreamDestinationEngine* engine = new MediaStreamDestinationEngine(this, tus);
+  mStream = aContext->Graph()->CreateAudioNodeStream(engine, MediaStreamGraph::INTERNAL_STREAM);
+  mPort = tus->AllocateInputPort(mStream, 0);
 
   nsIDocument* doc = aContext->GetParentObject()->GetExtantDoc();
   if (doc) {
     mDOMStream->CombineWithPrincipal(doc->NodePrincipal());
   }
 }
 
 MediaStreamAudioDestinationNode::~MediaStreamAudioDestinationNode()