Bug 1258143 - Remove LocalMediaStream. r=jib,smaug
authorAndreas Pehrson <apehrson@mozilla.com>
Mon, 15 Oct 2018 08:17:07 +0000
changeset 497044 9508a03be7c2ed82678cf62b0ba5356826738e9b
parent 497043 9d3c1734052cb639b5035ac3f652547ccbdfa1a7
child 497045 92b4fac6ea6c74a9292a21fd086fa35f76c8ba92
push id9996
push userarchaeopteryx@coole-files.de
push dateThu, 18 Oct 2018 18:37:15 +0000
treeherdermozilla-beta@8efe26839243 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjib, smaug
bugs1258143
milestone64.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 1258143 - Remove LocalMediaStream. r=jib,smaug Differential Revision: https://phabricator.services.mozilla.com/D8064
dom/bindings/Bindings.conf
dom/locales/en-US/chrome/dom/dom.properties
dom/media/DOMMediaStream.cpp
dom/media/DOMMediaStream.h
dom/media/MediaManager.cpp
dom/media/MediaStreamGraph.h
dom/media/encoder/ContainerWriter.h
dom/media/nsIDOMNavigatorUserMedia.idl
dom/media/test/test_mediarecorder_avoid_recursion.html
dom/media/test/test_mediatrack_consuming_mediastream.html
dom/media/test/test_mediatrack_events.html
dom/media/tests/crashtests/791330.html
dom/media/tests/mochitest/mediaStreamPlayback.js
dom/media/tests/mochitest/mochitest.ini
dom/media/tests/mochitest/test_getUserMedia_addTrackRemoveTrack.html
dom/media/tests/mochitest/test_getUserMedia_audioConstraints_concurrentIframes.html
dom/media/tests/mochitest/test_getUserMedia_audioConstraints_concurrentStreams.html
dom/media/tests/mochitest/test_getUserMedia_basicAudio.html
dom/media/tests/mochitest/test_getUserMedia_basicScreenshare.html
dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html
dom/media/tests/mochitest/test_getUserMedia_basicVideo.html
dom/media/tests/mochitest/test_getUserMedia_basicVideoAudio.html
dom/media/tests/mochitest/test_getUserMedia_basicVideo_playAfterLoadedmetadata.html
dom/media/tests/mochitest/test_getUserMedia_basicWindowshare.html
dom/media/tests/mochitest/test_getUserMedia_callbacks.html
dom/media/tests/mochitest/test_getUserMedia_cubebDisabledFakeStreams.html
dom/media/tests/mochitest/test_getUserMedia_gumWithinGum.html
dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_tracks.html
dom/media/tests/mochitest/test_getUserMedia_mediaStreamClone.html
dom/media/tests/mochitest/test_getUserMedia_playAudioTwice.html
dom/media/tests/mochitest/test_getUserMedia_playVideoAudioTwice.html
dom/media/tests/mochitest/test_getUserMedia_playVideoTwice.html
dom/media/tests/mochitest/test_getUserMedia_stopAudioStream.html
dom/media/tests/mochitest/test_getUserMedia_stopAudioStreamWithFollowupAudio.html
dom/media/tests/mochitest/test_getUserMedia_stopVideoAudioStream.html
dom/media/tests/mochitest/test_getUserMedia_stopVideoAudioStreamWithFollowupVideoAudio.html
dom/media/tests/mochitest/test_getUserMedia_stopVideoStream.html
dom/media/tests/mochitest/test_getUserMedia_stopVideoStreamWithFollowupVideo.html
dom/tests/mochitest/general/test_interfaces.js
dom/webidl/LocalMediaStream.webidl
dom/webidl/moz.build
media/webrtc/signaling/test/FakeMediaStreams.h
mobile/android/tests/browser/robocop/robocop_getusermedia.html
mobile/android/tests/browser/robocop/robocop_getusermedia2.html
testing/web-platform/tests/html/dom/interfaces.https.html
--- a/dom/bindings/Bindings.conf
+++ b/dom/bindings/Bindings.conf
@@ -502,21 +502,16 @@ DOMInterfaces = {
     'concrete': False
 },
 
 'LegacyMozTCPSocket': {
     'headerFile': 'TCPSocket.h',
     'wrapperCache': False,
 },
 
-'LocalMediaStream': {
-    'headerFile': 'DOMMediaStream.h',
-    'nativeType': 'mozilla::DOMLocalMediaStream'
-},
-
 'MatchGlob': {
     'nativeType': 'mozilla::extensions::MatchGlob',
 },
 
 'MatchPattern': {
     'nativeType': 'mozilla::extensions::MatchPattern',
 },
 
--- a/dom/locales/en-US/chrome/dom/dom.properties
+++ b/dom/locales/en-US/chrome/dom/dom.properties
@@ -136,18 +136,16 @@ MediaDecodeWarning=Media resource %1$S c
 MediaCannotPlayNoDecoders=Cannot play media. No decoders for requested formats: %S
 # LOCALIZATION NOTE: %S is a comma-separated list of codecs (e.g. 'video/mp4, video/webm')
 MediaNoDecoders=No decoders for some of the requested formats: %S
 MediaCannotInitializePulseAudio=Unable to use PulseAudio
 # LOCALIZATION NOTE: Do not translate "MediaRecorder".
 MediaRecorderMultiTracksNotSupported=MediaRecorder does not support recording multiple tracks of the same type at this time.
 # LOCALIZATION NOTE: %S is the ID of the MediaStreamTrack passed to MediaStream.addTrack(). Do not translate "MediaStreamTrack" and "AudioChannel".
 MediaStreamAddTrackDifferentAudioChannel=MediaStreamTrack %S could not be added since it belongs to a different AudioChannel.
-# LOCALIZATION NOTE: Do not translate "MediaStream", "stop()" and "MediaStreamTrack"
-MediaStreamStopDeprecatedWarning=MediaStream.stop() is deprecated and will soon be removed. Use MediaStreamTrack.stop() instead.
 # LOCALIZATION NOTE: %S is the URL of the web page which is not served on HTTPS and thus is not encrypted and considered insecure.
 MediaEMEInsecureContextDeprecatedWarning=Using Encrypted Media Extensions at %S on an insecure (i.e. non-HTTPS) context is deprecated and will soon be removed. You should consider switching to a secure origin such as HTTPS.
 # LOCALIZATION NOTE: %S is the URL of the web page which is calling web APIs without passing data (either an audioCapabilities or a videoCapabilities) that will soon be required. See https://bugzilla.mozilla.org/show_bug.cgi?id=1368583#c21 for explanation of this string.
 MediaEMENoCapabilitiesDeprecatedWarning=Calling navigator.requestMediaKeySystemAccess() (at %S) without passing a candidate MediaKeySystemConfiguration containing audioCapabilities or videoCapabilities is deprecated and will soon become unsupported.
 # LOCALIZATION NOTE: %S is the URL of the web page which is calling web APIs without passing data (a "codecs" string in the "contentType") that will soon be required. See https://bugzilla.mozilla.org/show_bug.cgi?id=1368583#c21 for explanation of this string.
 MediaEMENoCodecsDeprecatedWarning=Calling navigator.requestMediaKeySystemAccess() (at %S) passing a candidate MediaKeySystemConfiguration containing audioCapabilities or videoCapabilities without a contentType with a “codecs” string is deprecated and will soon become unsupported.
 # LOCALIZATION NOTE: Do not translate "Mutation Event" and "MutationObserver"
 MutationEventWarning=Use of Mutation Events is deprecated. Use MutationObserver instead.
--- a/dom/media/DOMMediaStream.cpp
+++ b/dom/media/DOMMediaStream.cpp
@@ -13,17 +13,16 @@
 #include "MediaStreamGraphImpl.h"
 #include "MediaStreamListener.h"
 #include "VideoStreamTrack.h"
 #include "mozilla/dom/AudioNode.h"
 #include "mozilla/dom/AudioTrack.h"
 #include "mozilla/dom/AudioTrackList.h"
 #include "mozilla/dom/DocGroup.h"
 #include "mozilla/dom/HTMLCanvasElement.h"
-#include "mozilla/dom/LocalMediaStreamBinding.h"
 #include "mozilla/dom/MediaStreamBinding.h"
 #include "mozilla/dom/MediaStreamTrackEvent.h"
 #include "mozilla/dom/Promise.h"
 #include "mozilla/dom/VideoTrack.h"
 #include "mozilla/dom/VideoTrackList.h"
 #include "mozilla/media/MediaUtils.h"
 #include "nsContentUtils.h"
 #include "nsIScriptError.h"
@@ -399,23 +398,16 @@ NS_IMPL_CYCLE_COLLECTION_TRAVERSE_END
 
 NS_IMPL_ADDREF_INHERITED(DOMMediaStream, DOMEventTargetHelper)
 NS_IMPL_RELEASE_INHERITED(DOMMediaStream, DOMEventTargetHelper)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMMediaStream)
   NS_INTERFACE_MAP_ENTRY(DOMMediaStream)
 NS_INTERFACE_MAP_END_INHERITING(DOMEventTargetHelper)
 
-NS_IMPL_ADDREF_INHERITED(DOMLocalMediaStream, DOMMediaStream)
-NS_IMPL_RELEASE_INHERITED(DOMLocalMediaStream, DOMMediaStream)
-
-NS_INTERFACE_MAP_BEGIN(DOMLocalMediaStream)
-  NS_INTERFACE_MAP_ENTRY(DOMLocalMediaStream)
-NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
-
 NS_IMPL_CYCLE_COLLECTION_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream,
                                    mStreamNode)
 
 NS_IMPL_ADDREF_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream)
 NS_IMPL_RELEASE_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream)
 
 NS_INTERFACE_MAP_BEGIN_CYCLE_COLLECTION(DOMAudioNodeMediaStream)
 NS_INTERFACE_MAP_END_INHERITING(DOMMediaStream)
@@ -1528,75 +1520,16 @@ DOMMediaStream::NotifyPlaybackTrackBlock
     // waiting for any further tracks to get blocked. It is now safe to
     // recompute the principal based on our main thread track set state.
     LOG(LogLevel::Debug, ("DOMMediaStream %p saw all tracks pending removal "
                           "finish. Recomputing principal.", this));
     RecomputePrincipal();
   }
 }
 
-DOMLocalMediaStream::~DOMLocalMediaStream()
-{
-  if (mInputStream) {
-    // Make sure Listeners of this stream know it's going away
-    StopImpl();
-  }
-}
-
-JSObject*
-DOMLocalMediaStream::WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto)
-{
-  return dom::LocalMediaStream_Binding::Wrap(aCx, this, aGivenProto);
-}
-
-void
-DOMLocalMediaStream::Stop()
-{
-  LOG(LogLevel::Debug, ("DOMMediaStream %p Stop()", this));
-  nsCOMPtr<nsPIDOMWindowInner> pWindow = GetParentObject();
-  nsIDocument* document = pWindow ? pWindow->GetExtantDoc() : nullptr;
-  nsContentUtils::ReportToConsole(nsIScriptError::warningFlag,
-                                  NS_LITERAL_CSTRING("Media"),
-                                  document,
-                                  nsContentUtils::eDOM_PROPERTIES,
-                                  "MediaStreamStopDeprecatedWarning");
-
-  StopImpl();
-}
-
-void
-DOMLocalMediaStream::StopImpl()
-{
-  if (mInputStream && mInputStream->AsSourceStream()) {
-    mInputStream->AsSourceStream()->EndAllTrackAndFinish();
-  }
-}
-
-already_AddRefed<DOMLocalMediaStream>
-DOMLocalMediaStream::CreateSourceStreamAsInput(nsPIDOMWindowInner* aWindow,
-                                               MediaStreamGraph* aGraph,
-                                               MediaStreamTrackSourceGetter* aTrackSourceGetter)
-{
-  RefPtr<DOMLocalMediaStream> stream =
-    new DOMLocalMediaStream(aWindow, aTrackSourceGetter);
-  stream->InitSourceStream(aGraph);
-  return stream.forget();
-}
-
-already_AddRefed<DOMLocalMediaStream>
-DOMLocalMediaStream::CreateTrackUnionStreamAsInput(nsPIDOMWindowInner* aWindow,
-                                                   MediaStreamGraph* aGraph,
-                                                   MediaStreamTrackSourceGetter* aTrackSourceGetter)
-{
-  RefPtr<DOMLocalMediaStream> stream =
-    new DOMLocalMediaStream(aWindow, aTrackSourceGetter);
-  stream->InitTrackUnionStream(aGraph);
-  return stream.forget();
-}
-
 DOMAudioNodeMediaStream::DOMAudioNodeMediaStream(nsPIDOMWindowInner* aWindow, AudioNode* aNode)
   : DOMMediaStream(aWindow, nullptr),
     mStreamNode(aNode)
 {
 }
 
 DOMAudioNodeMediaStream::~DOMAudioNodeMediaStream()
 {
--- a/dom/media/DOMMediaStream.h
+++ b/dom/media/DOMMediaStream.h
@@ -23,17 +23,16 @@
 // See dom/media/webaudio/AudioContext.h for more fun!
 #ifdef CurrentTime
 #undef CurrentTime
 #endif
 
 namespace mozilla {
 
 class AbstractThread;
-class DOMLocalMediaStream;
 class DOMMediaStream;
 class MediaStream;
 class MediaInputPort;
 class MediaStreamGraph;
 class ProcessedMediaStream;
 
 enum class BlockingMode;
 
@@ -201,17 +200,16 @@ protected:
  *                   \                                 (pointing to t1 in A')
  *                    ----> t2 ------------> t2     <- MediaStreamTrack Z'
  *                                                     (pointing to t2 in A')
  */
 class DOMMediaStream : public DOMEventTargetHelper,
                        public dom::PrincipalChangeObserver<dom::MediaStreamTrack>,
                        public RelativeTimeline
 {
-  friend class DOMLocalMediaStream;
   friend class dom::MediaStreamTrack;
   typedef dom::MediaStreamTrack MediaStreamTrack;
   typedef dom::AudioStreamTrack AudioStreamTrack;
   typedef dom::VideoStreamTrack VideoStreamTrack;
   typedef dom::MediaStreamTrackSource MediaStreamTrackSource;
   typedef dom::AudioTrack AudioTrack;
   typedef dom::VideoTrack VideoTrack;
   typedef dom::AudioTrackList AudioTrackList;
@@ -751,59 +749,16 @@ private:
   nsCOMPtr<nsIPrincipal> mVideoPrincipal;
   nsTArray<dom::PrincipalChangeObserver<DOMMediaStream>*> mPrincipalChangeObservers;
   CORSMode mCORSMode;
 };
 
 NS_DEFINE_STATIC_IID_ACCESSOR(DOMMediaStream,
                               NS_DOMMEDIASTREAM_IID)
 
-#define NS_DOMLOCALMEDIASTREAM_IID \
-{ 0xb1437260, 0xec61, 0x4dfa, \
-  { 0x92, 0x54, 0x04, 0x44, 0xe2, 0xb5, 0x94, 0x9c } }
-
-class DOMLocalMediaStream : public DOMMediaStream
-{
-public:
-  explicit DOMLocalMediaStream(nsPIDOMWindowInner* aWindow,
-                               MediaStreamTrackSourceGetter* aTrackSourceGetter)
-    : DOMMediaStream(aWindow, aTrackSourceGetter) {}
-
-  NS_DECL_ISUPPORTS_INHERITED
-  NS_DECLARE_STATIC_IID_ACCESSOR(NS_DOMLOCALMEDIASTREAM_IID)
-
-  virtual JSObject* WrapObject(JSContext* aCx, JS::Handle<JSObject*> aGivenProto) override;
-
-  void Stop();
-
-  /**
-   * Create an nsDOMLocalMediaStream whose underlying stream is a SourceMediaStream.
-   */
-  static already_AddRefed<DOMLocalMediaStream>
-  CreateSourceStreamAsInput(nsPIDOMWindowInner* aWindow,
-                            MediaStreamGraph* aGraph,
-                            MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
-
-  /**
-   * Create an nsDOMLocalMediaStream whose underlying stream is a TrackUnionStream.
-   */
-  static already_AddRefed<DOMLocalMediaStream>
-  CreateTrackUnionStreamAsInput(nsPIDOMWindowInner* aWindow,
-                                MediaStreamGraph* aGraph,
-                                MediaStreamTrackSourceGetter* aTrackSourceGetter = nullptr);
-
-protected:
-  virtual ~DOMLocalMediaStream();
-
-  void StopImpl();
-};
-
-NS_DEFINE_STATIC_IID_ACCESSOR(DOMLocalMediaStream,
-                              NS_DOMLOCALMEDIASTREAM_IID)
-
 class DOMAudioNodeMediaStream : public DOMMediaStream
 {
   typedef dom::AudioNode AudioNode;
 public:
   DOMAudioNodeMediaStream(nsPIDOMWindowInner* aWindow, AudioNode* aNode);
 
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_CYCLE_COLLECTION_CLASS_INHERITED(DOMAudioNodeMediaStream, DOMMediaStream)
--- a/dom/media/MediaManager.cpp
+++ b/dom/media/MediaManager.cpp
@@ -1515,18 +1515,18 @@ public:
         principal = window->GetExtantDoc()->NodePrincipal();
       }
 
       // Normal case, connect the source stream to the track union stream to
       // avoid us blocking. Pass a simple TrackSourceGetter for potential
       // fake tracks. Apart from them gUM never adds tracks dynamically.
       domStream = new nsMainThreadPtrHolder<DOMMediaStream>(
         "GetUserMediaStreamRunnable::DOMMediaStreamMainThreadHolder",
-        DOMLocalMediaStream::CreateSourceStreamAsInput(window, msg,
-                                                       new FakeTrackSourceGetter(principal)));
+        DOMMediaStream::CreateSourceStreamAsInput(window, msg,
+                                                  new FakeTrackSourceGetter(principal)));
       stream = domStream->GetInputStream()->AsSourceStream();
 
       if (mAudioDevice) {
         nsString audioDeviceName;
         mAudioDevice->GetName(audioDeviceName);
         const MediaSourceEnum source = mAudioDevice->GetMediaSource();
         RefPtr<MediaStreamTrackSource> audioSource =
           new LocalTrackSource(principal, audioDeviceName, mSourceListener,
--- a/dom/media/MediaStreamGraph.h
+++ b/dom/media/MediaStreamGraph.h
@@ -820,18 +820,18 @@ public:
                       MediaSegment* aRawSegment = nullptr) override {
     mMutex.AssertCurrentThreadOwns();
     MediaStream::ApplyTrackDisabling(aTrackID, aSegment, aRawSegment);
   }
 
   void RemoveAllDirectListenersImpl() override;
 
   /**
-   * End all tracks and Finish() this stream.  Used to voluntarily revoke access
-   * to a LocalMediaStream.
+   * End all tracks and Finish() this stream. Used to voluntarily revoke access
+   * to a MediaStream.
    */
   void EndAllTrackAndFinish();
 
   /**
    * Returns true if this SourceMediaStream contains at least one audio track
    * that is in pending state.
    * This is thread safe, and takes the SourceMediaStream mutex.
    */
--- a/dom/media/encoder/ContainerWriter.h
+++ b/dom/media/encoder/ContainerWriter.h
@@ -16,17 +16,17 @@ namespace mozilla {
  */
 class ContainerWriter {
 public:
   ContainerWriter()
     : mInitialized(false)
     , mIsWritingComplete(false)
   {}
   virtual ~ContainerWriter() {}
-  // Mapping to DOMLocalMediaStream::TrackTypeHints
+  // Mapping to DOMMediaStream::TrackTypeHints
   enum {
     CREATE_AUDIO_TRACK = 1 << 0,
     CREATE_VIDEO_TRACK = 1 << 1,
   };
   enum {
     END_OF_STREAM = 1 << 0
   };
 
--- a/dom/media/nsIDOMNavigatorUserMedia.idl
+++ b/dom/media/nsIDOMNavigatorUserMedia.idl
@@ -22,17 +22,17 @@ interface nsIGetUserMediaDevicesSuccessC
   void onSuccess(in nsIVariant devices);
 };
 
 [scriptable, function, uuid(f2a144fc-3534-4761-8c5d-989ae720f89a)]
 interface nsIDOMGetUserMediaSuccessCallback : nsISupports
 {
   /*
    * value must be a Blob if picture is true and a
-   * DOMLocalMediaStream if either audio or video are true.
+   * DOMMediaStream if either audio or video are true.
    */
   void onSuccess(in nsISupports value);
 };
 
 [scriptable, function, uuid(39e96c61-2636-4f0e-918e-9bb64276492a)]
 interface nsIDOMGetUserMediaErrorCallback : nsISupports
 {
   void onError(in nsISupports error);
--- a/dom/media/test/test_mediarecorder_avoid_recursion.html
+++ b/dom/media/test/test_mediarecorder_avoid_recursion.html
@@ -25,18 +25,18 @@ async function startTest() {
       ok(false, 'Unexpected onwarning callback fired');
     };
     mediaRecorder.ondataavailable = function (e) {
       ++count;
       info("got ondataavailable data size = " + e.data.size);
       // no more requestData() to prevent busy main thread from starving
       // the encoding thread
       if (count == 30) {
-        info("stream.stop");
-        stream.stop();
+        info("track.stop");
+        stream.getTracks()[0].stop();
       } else if (count < 30 && mediaRecorder.state == 'recording') {
         info("requestData again");
         mediaRecorder.requestData();
       }
     };
     mediaRecorder.onstop = function () {
       ok(true, "requestData within ondataavailable successfully avoided infinite recursion");
       SimpleTest.finish();
--- a/dom/media/test/test_mediatrack_consuming_mediastream.html
+++ b/dom/media/test/test_mediatrack_consuming_mediastream.html
@@ -126,17 +126,17 @@ async function startTest() {
       element.pause();
       checkTrackAdded();
     } else if (steps == 2) {
       element.onpause = onpause;
       element.pause();
       checkTrackChanged(1, false);
     } else if (steps == 3) {
       checkTrackChanged(2, true);
-      stream.stop();
+      stream.getTracks().forEach(t => t.stop());
     }
   }
 
   element.onplaying = onplaying;
   element.srcObject = stream;
 
   steps++;
   await element.play();
--- a/dom/media/test/test_mediatrack_events.html
+++ b/dom/media/test/test_mediatrack_events.html
@@ -100,17 +100,17 @@ async function startTest() {
     element.onplaying = null;
     if (element.ended) {
       return;
     }
     if (steps == 1) {
       element.onpause = onpause;
       element.pause();
     } else if (steps == 2) {
-      stream.stop();
+      stream.getTracks().forEach(t => t.stop());
     }
   }
 
   element.onplaying = onplaying;
   element.srcObject = stream;
 
   isnot(element.audioTracks, undefined,
         'HTMLMediaElement::AudioTracks() property should be available.');
--- a/dom/media/tests/crashtests/791330.html
+++ b/dom/media/tests/crashtests/791330.html
@@ -16,17 +16,17 @@ https://bugzilla.mozilla.org/show_bug.cg
       pc.close();
 
       navigator.mozGetUserMedia({audio: true, fake: true}, function (stream) {
         try {
           pc.addStream(stream);
           pc.createOffer(function (offer) {});
         }
         finally {
-          stream.stop();
+          stream.getTracks().forEach(t => t.stop());
 
           finish();
         }
       }, function () {});
     }
   </script>
 </head>
 
--- a/dom/media/tests/mochitest/mediaStreamPlayback.js
+++ b/dom/media/tests/mochitest/mediaStreamPlayback.js
@@ -138,86 +138,16 @@ MediaStreamPlayback.prototype = {
    *               being played.
    */
   detachFromMediaElement : function() {
     this.mediaElement.pause();
     this.mediaElement.srcObject = null;
   }
 }
 
-
-/**
- * This class is basically the same as MediaStreamPlayback except
- * ensures that the instance provided startMedia is a MediaStream.
- *
- * @param {HTMLMediaElement} mediaElement the media element for playback
- * @param {LocalMediaStream} mediaStream the media stream used in
- *                                       the mediaElement for playback
- */
-function LocalMediaStreamPlayback(mediaElement, mediaStream) {
-  ok(mediaStream instanceof LocalMediaStream,
-     "Stream should be a LocalMediaStream");
-  MediaStreamPlayback.call(this, mediaElement, mediaStream);
-}
-
-LocalMediaStreamPlayback.prototype = Object.create(MediaStreamPlayback.prototype, {
-
-  /**
-   * DEPRECATED - MediaStream.stop() is going away. Use MediaStreamTrack.stop()!
-   *
-   * Starts media with a media stream, runs it until a canplaythrough and
-   * timeupdate event fires, and calls stop() on the stream.
-   *
-   * @param {Boolean} isResume specifies if this media element is being resumed
-   *                           from a previous run
-   */
-  playMediaWithDeprecatedStreamStop : {
-    value: function(isResume) {
-      this.startMedia(isResume);
-      return this.verifyPlaying()
-        .then(() => this.deprecatedStopStreamInMediaPlayback())
-        .then(() => this.detachFromMediaElement());
-    }
-  },
-
-  /**
-   * DEPRECATED - MediaStream.stop() is going away. Use MediaStreamTrack.stop()!
-   *
-   * Stops the local media stream while it's currently in playback in
-   * a media element.
-   *
-   * Precondition: The media stream and element should both be actively
-   *               being played.
-   *
-   */
-  deprecatedStopStreamInMediaPlayback : {
-    value: function () {
-      return new Promise((resolve, reject) => {
-        /**
-         * Callback fired when the ended event fires when stop() is called on the
-         * stream.
-         */
-        var endedCallback = () => {
-          this.mediaElement.removeEventListener('ended', endedCallback);
-          ok(true, "ended event successfully fired");
-          resolve();
-        };
-
-        this.mediaElement.addEventListener('ended', endedCallback);
-        this.mediaStream.stop();
-
-        // If ended doesn't fire in enough time, then we fail the test
-        setTimeout(() => {
-          reject(new Error("ended event never fired"));
-        }, ENDED_TIMEOUT_LENGTH);
-      });
-    }
-  }
-});
-
 // haxx to prevent SimpleTest from failing at window.onload
 function addLoadEvent() {}
 
 var scriptsReady = Promise.all([
   "/tests/SimpleTest/SimpleTest.js",
   "head.js"
 ].map(script  => {
   var el = document.createElement("script");
--- a/dom/media/tests/mochitest/mochitest.ini
+++ b/dom/media/tests/mochitest/mochitest.ini
@@ -94,22 +94,16 @@ skip-if = android_version == '18' # andr
 [test_getUserMedia_mediaStreamTrackClone.html]
 skip-if = android_version == '18' # android(Bug 1189784, timeouts on 4.3 emulator)
 [test_getUserMedia_playAudioTwice.html]
 [test_getUserMedia_playVideoAudioTwice.html]
 [test_getUserMedia_playVideoTwice.html]
 [test_getUserMedia_scarySources.html]
 skip-if = toolkit == 'android' # no screenshare or windowshare on android
 [test_getUserMedia_spinEventLoop.html]
-[test_getUserMedia_stopAudioStream.html]
-[test_getUserMedia_stopAudioStreamWithFollowupAudio.html]
-[test_getUserMedia_stopVideoAudioStream.html]
-[test_getUserMedia_stopVideoAudioStreamWithFollowupVideoAudio.html]
-[test_getUserMedia_stopVideoStream.html]
-[test_getUserMedia_stopVideoStreamWithFollowupVideo.html]
 [test_getUserMedia_trackCloneCleanup.html]
 [test_getUserMedia_trackEnded.html]
 [test_getUserMedia_peerIdentity.html]
 [test_peerConnection_addIceCandidate.html]
 [test_peerConnection_addtrack_removetrack_events.html]
 skip-if = android_version == '18' # android(Bug 1189784, timeouts on 4.3 emulator)
 [test_peerConnection_audioCodecs.html]
 skip-if = (android_version == '18') # android(Bug 1189784, timeouts on 4.3 emulator)
--- a/dom/media/tests/mochitest/test_getUserMedia_addTrackRemoveTrack.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_addTrackRemoveTrack.html
@@ -22,33 +22,33 @@
 
         stream.addTrack(track);
         checkMediaStreamContains(stream, [track], "Re-added audio");
 
         stream.addTrack(otherTrack);
         checkMediaStreamContains(stream, [track, otherTrack], "Added video");
 
         var testElem = createMediaElement('video', 'testAddTrackAudioVideo');
-        var playback = new LocalMediaStreamPlayback(testElem, stream);
+        var playback = new MediaStreamPlayback(testElem, stream);
         return playback.playMedia(false);
     }))
     .then(() => getUserMedia({video: true})).then(stream =>
       getUserMedia({video: true}).then(otherStream => {
         info("Test addTrack()ing a video track to a video-only gUM stream");
         var track = stream.getTracks()[0];
         var otherTrack = otherStream.getTracks()[0];
 
         stream.addTrack(track);
         checkMediaStreamContains(stream, [track], "Re-added video");
 
         stream.addTrack(otherTrack);
         checkMediaStreamContains(stream, [track, otherTrack], "Added video");
 
         var test = createMediaElement('video', 'testAddTrackDoubleVideo');
-        var playback = new LocalMediaStreamPlayback(test, stream);
+        var playback = new MediaStreamPlayback(test, stream);
         return playback.playMedia(false);
     }))
     .then(() => getUserMedia({video: true})).then(stream =>
       getUserMedia({video: true}).then(otherStream => {
         info("Test removeTrack() existing and added video tracks from a video-only gUM stream");
         var track = stream.getTracks()[0];
         var otherTrack = otherStream.getTracks()[0];
 
@@ -75,17 +75,17 @@
         return wait(500).then(() => {
           ok(!loadeddata, "Stream without tracks shall not raise 'loadeddata' on media element");
           elem.pause();
           elem.srcObject = null;
         })
         .then(() => {
           stream.addTrack(track);
           checkMediaStreamContains(stream, [track], "Re-added added-then-removed track");
-          var playback = new LocalMediaStreamPlayback(elem, stream);
+          var playback = new MediaStreamPlayback(elem, stream);
           return playback.playMedia(false);
         })
         .then(() => otherTrack.stop());
     }))
     .then(() => getUserMedia({ audio: true })).then(audioStream =>
       getUserMedia({ video: true }).then(videoStream => {
         info("Test adding track and removing the original");
         var audioTrack = audioStream.getTracks()[0];
@@ -93,17 +93,17 @@
         videoStream.removeTrack(videoTrack);
         audioStream.addTrack(videoTrack);
 
         checkMediaStreamContains(videoStream, [], "1, Removed original track");
         checkMediaStreamContains(audioStream, [audioTrack, videoTrack],
                                  "2, Added external track");
 
         var elem = createMediaElement('video', 'testAddRemoveOriginalTrackVideo');
-        var playback = new LocalMediaStreamPlayback(elem, audioStream);
+        var playback = new MediaStreamPlayback(elem, audioStream);
         return playback.playMedia(false);
       }))
     .then(() => getUserMedia({ audio: true, video: true })).then(stream => {
       info("Test removing stopped tracks");
       stream.getTracks().forEach(t => {
         t.stop();
         stream.removeTrack(t);
       });
--- a/dom/media/tests/mochitest/test_getUserMedia_audioConstraints_concurrentIframes.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_audioConstraints_concurrentIframes.html
@@ -129,17 +129,17 @@ runTest(async function() {
     }
 
     // We do not currently have tests to verify the behaviour of the different
     // constraints. Once we do we should do further verification here. See
     // bug 1406372, bug 1406376, and bug 1406377.
 
     for (let testCase of testCases) {
       let testAudio = createMediaElement("audio", `testAudio.${testCase.id}`);
-      let playback = new LocalMediaStreamPlayback(testAudio, testCase.gumStream);
+      let playback = new MediaStreamPlayback(testAudio, testCase.gumStream);
       await playback.playMediaWithoutStoppingTracks(false);
     }
 
     // Stop the tracks for each stream, we left them running above via
     // playMediaWithoutStoppingTracks to make sure they can play concurrently.
     for (let testCase of testCases) {
       testCase.gumStream.getTracks().map(t => t.stop());
     }
--- a/dom/media/tests/mochitest/test_getUserMedia_audioConstraints_concurrentStreams.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_audioConstraints_concurrentStreams.html
@@ -102,17 +102,17 @@ runTest(async function() {
   }
 
   // We do not currently have tests to verify the behaviour of the different
   // constraints. Once we do we should do further verificaiton here. See
   // bug 1406372, bug 1406376, and bug 1406377.
 
   for (let testCase of testCases) {
     let testAudio = createMediaElement("audio", `testAudio.${testCase.id}`);
-    let playback = new LocalMediaStreamPlayback(testAudio, testCase.gumStream);
+    let playback = new MediaStreamPlayback(testAudio, testCase.gumStream);
     await playback.playMediaWithoutStoppingTracks(false);
   }
 
   // Stop the tracks for each stream, we left them running above via
   // playMediaWithoutStoppingTracks to make sure they can play concurrently.
   for (let testCase of testCases) {
     testCase.gumStream.getTracks().map(t => t.stop());
   }
--- a/dom/media/tests/mochitest/test_getUserMedia_basicAudio.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicAudio.html
@@ -4,24 +4,24 @@
   <script type="application/javascript" src="mediaStreamPlayback.js"></script>
 </head>
 <body>
 <pre id="test">
 <script type="application/javascript">
   createHTML({ title: "getUserMedia Basic Audio Test", bug: "781534" });
   /**
    * Run a test to verify that we can complete a start and stop media playback
-   * cycle for an audio LocalMediaStream on an audio HTMLMediaElement.
+   * cycle for an audio MediaStream on an audio HTMLMediaElement.
    */
   runTest(function () {
     var testAudio = createMediaElement('audio', 'testAudio');
     var constraints = {audio: true};
 
     return getUserMedia(constraints).then(stream => {
-      var playback = new LocalMediaStreamPlayback(testAudio, stream);
+      var playback = new MediaStreamPlayback(testAudio, stream);
       return playback.playMedia(false);
     });
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_basicScreenshare.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicScreenshare.html
@@ -101,17 +101,17 @@
     let stream = await getUserMedia({video: {mediaSource: "screen"}});
     let settings = stream.getTracks()[0].getSettings();
     ok(settings.width <= 8192,
        `Width setting ${settings.width} should be set after gUM (or 0 per bug 1453247)`);
     ok(settings.height <= 8192,
        `Height setting ${settings.height} should be set after gUM (or 0 per bug 1453247)`);
     draw(helper.red, helper.blue,
          helper.green, helper.grey);
-    let playback = new LocalMediaStreamPlayback(testVideo, stream);
+    let playback = new MediaStreamPlayback(testVideo, stream);
     playback.startMedia();
     await playback.verifyPlaying();
     settings = stream.getTracks()[0].getSettings();
     is(settings.width, testVideo.videoWidth,
        "Width setting should match video width");
     is(settings.height, testVideo.videoHeight,
        "Height setting should match video height");
     let screenWidth = testVideo.videoWidth;
@@ -144,17 +144,17 @@
     });
     settings = stream.getTracks()[0].getSettings();
     ok(settings.width == 0 || (settings.width >= 10 && settings.width <= 100),
        `Width setting ${settings.width} should be correct after gUM (or 0 per bug 1453247)`);
     ok(settings.height == 0 || (settings.height >= 10 && settings.height <= 100),
        `Height setting ${settings.height} should be correct after gUM (or 0 per bug 1453247)`);
     draw(helper.green, helper.red,
          helper.grey, helper.blue);
-    playback = new LocalMediaStreamPlayback(testVideo, stream);
+    playback = new MediaStreamPlayback(testVideo, stream);
     playback.startMedia();
     await playback.verifyPlaying();
     settings = stream.getTracks()[0].getSettings();
     ok(settings.width >= 10 && settings.width <= 100,
        `Width setting ${settings.width} should be within constraints`);
     ok(settings.height >= 10 && settings.height <= 100,
        `Height setting ${settings.height} should be within constraints`);
     is(settings.width, testVideo.videoWidth,
@@ -201,17 +201,17 @@
     ok(Math.abs(expectedHeight - settings.height) <= 1,
        "Aspect ratio after applying constraints should be close enough");
     draw(helper.grey, helper.green,
          helper.blue, helper.red);
     await playback.verifyPlaying(); // still playing
     await verifyScreenshare(testVideo, helper,
                             helper.grey, helper.green,
                             helper.blue, helper.red);
-    await playback.deprecatedStopStreamInMediaPlayback();
+    await playback.stopTracksForStreamInMediaPlayback();
     playback.detachFromMediaElement();
 
     SpecialPowers.wrap(document).exitFullscreen();
   });
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicTabshare.html
@@ -7,60 +7,60 @@
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     title: "getUserMedia Basic Tabshare Test",
     bug: "1193075"
   });
   /**
    * Run a test to verify that we can complete a start and stop media playback
-   * cycle for a tabshare LocalMediaStream on a video HTMLMediaElement.
+   * cycle for a tabshare MediaStream on a video HTMLMediaElement.
    *
    * Additionally, exercise applyConstraints code for tabshare viewport offset.
    */
   runTest(function () {
     var testVideo = createMediaElement('video', 'testVideo');
 
     return Promise.resolve()
       .then(() => pushPrefs(["media.getusermedia.browser.enabled", true]))
       .then(() => getUserMedia({
         video: { mediaSource: "browser",
                  scrollWithPage: true },
         fake: false
       }))
       .then(stream => {
-        var playback = new LocalMediaStreamPlayback(testVideo, stream);
-        return playback.playMediaWithDeprecatedStreamStop(false);
+        var playback = new MediaStreamPlayback(testVideo, stream);
+        return playback.playMedia(false);
       })
       .then(() => getUserMedia({
         video: {
           mediaSource: "browser",
           viewportOffsetX: 0,
           viewportOffsetY: 0,
           viewportWidth: 100,
           viewportHeight: 100
         },
         fake: false
       }))
       .then(stream => {
-        var playback = new LocalMediaStreamPlayback(testVideo, stream);
+        var playback = new MediaStreamPlayback(testVideo, stream);
         playback.startMedia(false);
         return playback.verifyPlaying()
           .then(() => Promise.all([
             () => testVideo.srcObject.getVideoTracks()[0].applyConstraints({
               mediaSource: "browser",
               viewportOffsetX: 10,
               viewportOffsetY: 50,
               viewportWidth: 90,
               viewportHeight: 50
             }),
             () => listenUntil(testVideo, "resize", () => true)
           ]))
           .then(() => playback.verifyPlaying()) // still playing
-          .then(() => playback.deprecatedStopStreamInMediaPlayback())
+          .then(() => playback.stopTracksForStreamInMediaPlayback())
           .then(() => playback.detachFromMediaElement());
       });
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_basicVideo.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicVideo.html
@@ -7,24 +7,24 @@
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     title: "getUserMedia Basic Video Test",
     bug: "781534"
   });
   /**
    * Run a test to verify that we can complete a start and stop media playback
-   * cycle for an video LocalMediaStream on a video HTMLMediaElement.
+   * cycle for an video MediaStream on a video HTMLMediaElement.
    */
   runTest(function () {
     var testVideo = createMediaElement('video', 'testVideo');
     var constraints = {video: true};
 
     return getUserMedia(constraints).then(stream => {
-      var playback = new LocalMediaStreamPlayback(testVideo, stream);
+      var playback = new MediaStreamPlayback(testVideo, stream);
       return playback.playMedia(false);
     });
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_basicVideoAudio.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicVideoAudio.html
@@ -7,24 +7,24 @@
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     title: "getUserMedia Basic Video & Audio Test",
     bug: "781534"
   });
   /**
    * Run a test to verify that we can complete a start and stop media playback
-   * cycle for a video and audio LocalMediaStream on a video HTMLMediaElement.
+   * cycle for a video and audio MediaStream on a video HTMLMediaElement.
    */
   runTest(function () {
     var testVideoAudio = createMediaElement('video', 'testVideoAudio');
     var constraints = {video: true, audio: true};
 
     return getUserMedia(constraints).then(stream => {
-      var playback = new LocalMediaStreamPlayback(testVideoAudio, stream);
+      var playback = new MediaStreamPlayback(testVideoAudio, stream);
       return playback.playMedia(false);
     });
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_basicVideo_playAfterLoadedmetadata.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicVideo_playAfterLoadedmetadata.html
@@ -14,17 +14,17 @@
    * Run a test to verify that we will always get 'loadedmetadata' from a video
    * HTMLMediaElement playing a gUM MediaStream.
    */
   runTest(() => {
     var testVideo = createMediaElement('video', 'testVideo');
     var constraints = {video: true};
 
     return getUserMedia(constraints).then(stream => {
-      var playback = new LocalMediaStreamPlayback(testVideo, stream);
+      var playback = new MediaStreamPlayback(testVideo, stream);
       var video = playback.mediaElement;
 
       video.srcObject = stream;
       return new Promise(resolve => {
         ok(playback.mediaElement.paused,
            "Media element should be paused before play()ing");
         video.addEventListener('loadedmetadata', function() {
           ok(video.videoWidth > 0, "Expected nonzero video width");
--- a/dom/media/tests/mochitest/test_getUserMedia_basicWindowshare.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_basicWindowshare.html
@@ -7,31 +7,31 @@
 <pre id="test">
 <script type="application/javascript">
   createHTML({
     title: "getUserMedia Basic Windowshare Test",
     bug: "1038926"
   });
   /**
    * Run a test to verify that we can complete a start and stop media playback
-   * cycle for an screenshare LocalMediaStream on a video HTMLMediaElement.
+   * cycle for an screenshare MediaStream on a video HTMLMediaElement.
    */
   runTest(function () {
     var testVideo = createMediaElement('video', 'testVideo');
     var constraints = {
       video: {
          mozMediaSource: "window",
          mediaSource: "window"
       },
       fake: false
     };
 
     return getUserMedia(constraints).then(stream => {
-      var playback = new LocalMediaStreamPlayback(testVideo, stream);
-      return playback.playMediaWithDeprecatedStreamStop(false);
+      var playback = new MediaStreamPlayback(testVideo, stream);
+      return playback.playMedia(false);
     });
 
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_callbacks.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_callbacks.html
@@ -17,17 +17,17 @@
     var testAudio = createMediaElement('audio', 'testAudio');
     var constraints = {audio: true};
 
     SimpleTest.waitForExplicitFinish();
     return new Promise(resolve =>
       navigator.mozGetUserMedia(constraints, stream => {
         checkMediaStreamTracks(constraints, stream);
 
-        var playback = new LocalMediaStreamPlayback(testAudio, stream);
+        var playback = new MediaStreamPlayback(testAudio, stream);
         return playback.playMedia(false)
           .then(() => resolve(), generateErrorCallback());
       }, generateErrorCallback())
     );
   });
 
 </script>
 </pre>
--- a/dom/media/tests/mochitest/test_getUserMedia_cubebDisabledFakeStreams.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_cubebDisabledFakeStreams.html
@@ -27,17 +27,17 @@
     try {
       stream = await getUserMedia(constraints);
     } catch (e) {
       // We've got no audio backend, so we expect gUM to fail
       ok(false, `Did not expect to fail, but got ${e}`);
       return;
     }
     ok(stream, "getUserMedia should get a stream!");
-    let playback = new LocalMediaStreamPlayback(testAudio, stream);
+    let playback = new MediaStreamPlayback(testAudio, stream);
     return playback.playMedia(false);
   });
 
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_gumWithinGum.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_gumWithinGum.html
@@ -11,29 +11,28 @@
    * Run a test that we can complete a playback cycle for a video,
    * then upon completion, do a playback cycle with audio, such that
    * the audio gum call happens within the video gum call.
    */
   runTest(function () {
     return getUserMedia({video: true})
       .then(videoStream => {
         var testVideo = createMediaElement('video', 'testVideo');
-        var videoPlayback = new LocalMediaStreamPlayback(testVideo,
-                                                         videoStream);
+        var videoPlayback = new MediaStreamPlayback(testVideo,
+                                                    videoStream);
 
-        return videoPlayback.playMedia(false)
+        return videoPlayback.playMediaWithoutStoppingTracks(false)
           .then(() => getUserMedia({audio: true}))
           .then(audioStream => {
             var testAudio = createMediaElement('audio', 'testAudio');
-            var audioPlayback = new LocalMediaStreamPlayback(testAudio,
-                                                             audioStream);
+            var audioPlayback = new MediaStreamPlayback(testAudio,
+                                                        audioStream);
 
-            return audioPlayback.playMedia(false)
-              .then(() => audioStream.stop());
+            return audioPlayback.playMedia(false);
           })
-          .then(() => videoStream.stop());
+          .then(() => videoStream.getTracks().forEach(t => t.stop()));
       });
   });
 
 </script>
 </pre>
 </body>
 </html>
--- a/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_tracks.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_mediaElementCapture_tracks.html
@@ -152,18 +152,16 @@ runTest(() => getUserMedia({audio: true,
     streamUntilEnded = untilEndedElement.mozCaptureStreamUntilEnded();
 
     is(streamUntilEnded.getAudioTracks().length, 3,
        "video element should capture all 3 audio tracks until ended");
     is(streamUntilEnded.getVideoTracks().length, 1,
        "video element should capture only 1 video track until ended");
 
     untilEndedElement.srcObject.getTracks().forEach(t => t.stop());
-    // TODO(1208316) We stop the stream to make the media element end.
-    untilEndedElement.srcObject.stop();
 
     return Promise.all([
       haveEvent(untilEndedElement, "ended", wait(50000, new Error("Timeout"))),
       ...streamUntilEnded.getTracks()
            .map(t => haveEvent(t, "ended", wait(50000, new Error("Timeout"))))
     ]);
   })
   .then(() => {
--- a/dom/media/tests/mochitest/test_getUserMedia_mediaStreamClone.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_mediaStreamClone.html
@@ -64,17 +64,16 @@ runTest(async () => {
     streamClone.addTrack(track);
     checkMediaStreamContains(streamClone, [trackClone, track],
                              "Added video to clone");
     checkMediaStreamContains(stream, [otherTrack],
                              "Original not affected");
 
     // Not part of streamClone. Does not get stopped by the playback test.
     otherTrack.stop();
-    otherStream.stop();
 
     let test = createMediaElement('video', 'testClonePlayback');
     let playback = new MediaStreamPlayback(test, streamClone);
     await playback.playMedia(false);
   }
 
   {
     info("Test cloning a stream into inception");
--- a/dom/media/tests/mochitest/test_getUserMedia_playAudioTwice.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_playAudioTwice.html
@@ -8,17 +8,17 @@
 <script type="application/javascript">
   createHTML({title: "getUserMedia Play Audio Twice", bug: "822109" });
   /**
    * Run a test that we can complete an audio playback cycle twice in a row.
    */
   runTest(function () {
     return getUserMedia({audio: true}).then(audioStream => {
       var testAudio = createMediaElement('audio', 'testAudio');
-      var playback = new LocalMediaStreamPlayback(testAudio, audioStream);
+      var playback = new MediaStreamPlayback(testAudio, audioStream);
 
       return playback.playMediaWithoutStoppingTracks(false)
         .then(() => playback.playMedia(true));
     });
   });
 </script>
 </pre>
 </body>
--- a/dom/media/tests/mochitest/test_getUserMedia_playVideoAudioTwice.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_playVideoAudioTwice.html
@@ -8,17 +8,17 @@
 <script type="application/javascript">
   createHTML({title: "getUserMedia Play Video and Audio Twice", bug: "822109" });
   /**
    * Run a test that we can complete a video playback cycle twice in a row.
    */
   runTest(function () {
     return getUserMedia({video: true, audio: true}).then(stream => {
       var testVideo = createMediaElement('video', 'testVideo');
-      var playback = new LocalMediaStreamPlayback(testVideo, stream);
+      var playback = new MediaStreamPlayback(testVideo, stream);
 
       return playback.playMediaWithoutStoppingTracks(false)
         .then(() => playback.playMedia(true));
     });
   });
 
 </script>
 </pre>
--- a/dom/media/tests/mochitest/test_getUserMedia_playVideoTwice.html
+++ b/dom/media/tests/mochitest/test_getUserMedia_playVideoTwice.html
@@ -8,17 +8,17 @@
 <script type="application/javascript">
   createHTML({ title: "getUserMedia Play Video Twice", bug: "822109" });
   /**
    * Run a test that we can complete a video playback cycle twice in a row.
    */
   runTest(function () {
     return getUserMedia({video: true}).then(stream => {
       var testVideo = createMediaElement('video', 'testVideo');
-      var streamPlayback = new LocalMediaStreamPlayback(testVideo, stream);
+      var streamPlayback = new MediaStreamPlayback(testVideo, stream);
 
       return streamPlayback.playMediaWithoutStoppingTracks(false)
         .then(() => streamPlayback.playMedia(true));
     });
   });
 
 </script>
 </pre>
deleted file mode 100644
--- a/dom/media/tests/mochitest/test_getUserMedia_stopAudioStream.html
+++ /dev/null
@@ -1,27 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
-</head>
-<body>
-<pre id="test">
-<script type="application/javascript">
-  createHTML({ title: "getUserMedia Stop Audio Stream", bug: "822109" });
-  /**
-   * Run a test to verify that we can start an audio stream in a media element,
-   * call stop() on the stream, and successfully get an ended event fired.
-   */
-  runTest(function () {
-    return getUserMedia({audio: true})
-      .then(stream => {
-        var testAudio = createMediaElement('audio', 'testAudio');
-        var streamPlayback = new LocalMediaStreamPlayback(testAudio, stream);
-
-        return streamPlayback.playMediaWithDeprecatedStreamStop(false);
-      });
-  });
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/dom/media/tests/mochitest/test_getUserMedia_stopAudioStreamWithFollowupAudio.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
-</head>
-<body>
-<pre id="test">
-<script type="application/javascript">
-  createHTML({ title: "getUserMedia Stop Audio Stream With Followup Audio", bug: "822109" });
-  /**
-   * Run a test to verify that I can complete an audio gum playback in a media
-   * element, stop the stream, and then complete another audio gum playback
-   * in a media element.
-   */
-  runTest(function () {
-    return getUserMedia({audio: true})
-      .then(firstStream => {
-        var testAudio = createMediaElement('audio', 'testAudio');
-        var streamPlayback = new LocalMediaStreamPlayback(testAudio, firstStream);
-
-        return streamPlayback.playMediaWithDeprecatedStreamStop(false)
-          .then(() => getUserMedia({audio: true}))
-          .then(secondStream => {
-            streamPlayback.mediaStream = secondStream;
-
-            return streamPlayback.playMedia(false)
-              .then(() => secondStream.stop());
-          });
-      });
-  });
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/dom/media/tests/mochitest/test_getUserMedia_stopVideoAudioStream.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
-</head>
-<body>
-<pre id="test">
-<script type="application/javascript">
-  createHTML({ title: "getUserMedia Stop Video Audio Stream", bug: "822109" });
-  /**
-   * Run a test to verify that we can start a video+audio stream in a
-   * media element, call stop() on the stream, and successfully get an
-   * ended event fired.
-   */
-  runTest(function () {
-    return getUserMedia({video: true, audio: true})
-      .then(stream => {
-        var testVideo = createMediaElement('video', 'testVideo');
-        var playback = new LocalMediaStreamPlayback(testVideo, stream);
-
-        return playback.playMediaWithDeprecatedStreamStop(false);
-      });
-  });
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/dom/media/tests/mochitest/test_getUserMedia_stopVideoAudioStreamWithFollowupVideoAudio.html
+++ /dev/null
@@ -1,38 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
-</head>
-<body>
-<pre id="test">
-<script type="application/javascript">
-  createHTML({
-    title: "getUserMedia Stop Video+Audio Stream With Followup Video+Audio",
-    bug: "822109"
-  });
-  /**
-   * Run a test to verify that I can complete an video+audio gum playback in a
-   * media element, stop the stream, and then complete another video+audio gum
-   * playback in a media element.
-   */
-  runTest(function () {
-    return getUserMedia({video: true, audio: true})
-      .then(stream => {
-        var testVideo = createMediaElement('video', 'testVideo');
-        var streamPlayback = new LocalMediaStreamPlayback(testVideo, stream);
-
-        return streamPlayback.playMediaWithDeprecatedStreamStop(false)
-          .then(() => getUserMedia({video: true, audio: true}))
-          .then(secondStream => {
-            streamPlayback.mediaStream = secondStream;
-
-            return streamPlayback.playMedia(false)
-              .then(() => secondStream.stop());
-          });
-      });
-  });
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/dom/media/tests/mochitest/test_getUserMedia_stopVideoStream.html
+++ /dev/null
@@ -1,28 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <script type="application/javascript" src="mediaStreamPlayback.js"></script>
-</head>
-<body>
-<pre id="test">
-<script type="application/javascript">
-  createHTML({ title: "getUserMedia Stop Video Stream", bug: "822109" });
-  /**
-   * Run a test to verify that we can start a video stream in a
-   * media element, call stop() on the stream, and successfully get an
-   * ended event fired.
-   */
-  runTest(function () {
-    return getUserMedia({video: true})
-      .then(stream => {
-        var testVideo = createMediaElement('video', 'testVideo');
-        var streamPlayback = new LocalMediaStreamPlayback(testVideo, stream);
-
-        return streamPlayback.playMediaWithDeprecatedStreamStop(false);
-      });
-  });
-
-</script>
-</pre>
-</body>
-</html>
deleted file mode 100644
--- a/dom/media/tests/mochitest/test_getUserMedia_stopVideoStreamWithFollowupVideo.html
+++ /dev/null
@@ -1,35 +0,0 @@
-<!DOCTYPE HTML>
-<html>
-<head>
-  <script src="mediaStreamPlayback.js"></script>
-</head>
-<body>
-<pre id="test">
-<script type="application/javascript">
-  createHTML({ title: "getUserMedia Stop Video Stream With Followup Video", bug: "822109" });
-  /**
-   * Run a test to verify that I can complete an video gum playback in a
-   * media element, stop the stream, and then complete another video gum
-   * playback in a media element.
-   */
-  runTest(function () {
-    return getUserMedia({video: true})
-      .then(stream => {
-        var testVideo = createMediaElement('video', 'testVideo');
-        var streamPlayback = new LocalMediaStreamPlayback(testVideo, stream);
-
-        return streamPlayback.playMediaWithDeprecatedStreamStop(false)
-          .then(() => getUserMedia({video: true}))
-          .then(secondStream => {
-            streamPlayback.mediaStream = secondStream;
-
-            return streamPlayback.playMedia(false)
-              .then(() => secondStream.stop());
-          });
-      });
-  });
-
-</script>
-</pre>
-</body>
-</html>
--- a/dom/tests/mochitest/general/test_interfaces.js
+++ b/dom/tests/mochitest/general/test_interfaces.js
@@ -602,18 +602,16 @@ var interfaceNamesInGlobalScope =
     {name: "IntersectionObserverEntry", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "KeyEvent", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "KeyboardEvent", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "KeyframeEffect", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
-    {name: "LocalMediaStream", insecureContext: true},
-// IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "Location", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MediaCapabilities", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MediaCapabilitiesInfo", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
     {name: "MediaDeviceInfo", insecureContext: true},
 // IMPORTANT: Do not change this list without review from a DOM peer!
deleted file mode 100644
--- a/dom/webidl/LocalMediaStream.webidl
+++ /dev/null
@@ -1,15 +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 origins of this IDL file are
- * http://dev.w3.org/2011/webrtc/editor/getusermedia.html
- *
- * Copyright © 2012 W3C® (MIT, ERCIM, Keio), All Rights Reserved. W3C
- * liability, trademark and document use rules apply.
- */
-
-interface LocalMediaStream : MediaStream {
-    void stop();
-};
--- a/dom/webidl/moz.build
+++ b/dom/webidl/moz.build
@@ -167,19 +167,16 @@ with Files("Key*Event*"):
     BUG_COMPONENT = ("Core", "DOM: Events")
 
 with Files("KeyIdsInitData.webidl"):
     BUG_COMPONENT = ("Core", "Audio/Video: Playback")
 
 with Files("Keyframe*"):
     BUG_COMPONENT = ("Core", "DOM: Animation")
 
-with Files("LocalMediaStream.webidl"):
-    BUG_COMPONENT = ("Core", "Audio/Video")
-
 with Files("MediaDevice*"):
     BUG_COMPONENT = ("Core", "WebRTC")
 
 with Files("Media*Source*"):
     BUG_COMPONENT = ("Core", "Web Audio")
 
 with Files("MediaStream*"):
     BUG_COMPONENT = ("Core", "WebRTC")
@@ -633,17 +630,16 @@ WEBIDL_FILES = [
     'KeyboardEvent.webidl',
     'KeyEvent.webidl',
     'KeyframeAnimationOptions.webidl',
     'KeyframeEffect.webidl',
     'KeyIdsInitData.webidl',
     'L10nUtils.webidl',
     'LegacyQueryInterface.webidl',
     'LinkStyle.webidl',
-    'LocalMediaStream.webidl',
     'Location.webidl',
     'MediaCapabilities.webidl',
     'MediaDeviceInfo.webidl',
     'MediaDevices.webidl',
     'MediaElementAudioSourceNode.webidl',
     'MediaEncryptedEvent.webidl',
     'MediaError.webidl',
     'MediaKeyError.webidl',
--- a/media/webrtc/signaling/test/FakeMediaStreams.h
+++ b/media/webrtc/signaling/test/FakeMediaStreams.h
@@ -487,18 +487,16 @@ public:
     Fake_SourceMediaStream *source = new Fake_SourceMediaStream();
 
     RefPtr<Fake_DOMMediaStream> ds = new Fake_DOMMediaStream(source);
     ds->SetHintContents(aHintContents);
 
     return ds.forget();
   }
 
-  virtual void Stop() {} // Really DOMLocalMediaStream
-
   virtual bool AddDirectListener(Fake_MediaStreamListener *aListener) { return false; }
   virtual void RemoveDirectListener(Fake_MediaStreamListener *aListener) {}
 
   Fake_MediaStream *GetInputStream() { return mMediaStream; }
   Fake_MediaStream *GetOwnedStream() { return mMediaStream; }
   Fake_MediaStream *GetPlaybackStream() { return mMediaStream; }
   Fake_MediaStream *GetStream() { return mMediaStream; }
   std::string GetId() const { return mID; }
@@ -640,17 +638,16 @@ class Fake_VideoStreamSource : public Fa
 
 namespace mozilla {
 typedef Fake_MediaStream MediaStream;
 typedef Fake_SourceMediaStream SourceMediaStream;
 typedef Fake_MediaStreamListener MediaStreamListener;
 typedef Fake_MediaStreamTrackListener MediaStreamTrackListener;
 typedef Fake_DirectMediaStreamTrackListener DirectMediaStreamTrackListener;
 typedef Fake_DOMMediaStream DOMMediaStream;
-typedef Fake_DOMMediaStream DOMLocalMediaStream;
 typedef Fake_MediaStreamVideoSink MediaStreamVideoSink;
 
 namespace dom {
 typedef Fake_MediaStreamTrack MediaStreamTrack;
 typedef Fake_MediaStreamTrackSource MediaStreamTrackSource;
 typedef Fake_MediaStreamTrack VideoStreamTrack;
 }
 }
--- a/mobile/android/tests/browser/robocop/robocop_getusermedia.html
+++ b/mobile/android/tests/browser/robocop/robocop_getusermedia.html
@@ -30,24 +30,24 @@
       },
       audio: true
     };
     startMedia(mediaConstraints);
   }
 
   function stopMedia() {
     if (video_status) {
-      video.srcObject.stop();
+      video.srcObject.getTracks().forEach(t => t.stop());
       video.srcObject = null;
       content.removeChild(video);
       capturing = false;
       video_status = false;
     }
     if (audio_status) {
-      audio.srcObject.stop();
+      audio.srcObject.getTracks().forEach(t => t.stop());
       audio.srcObject = null;
       content.removeChild(audio);
       audio_status = false;
     }
   }
 
   function startMedia(param) {
     try {
@@ -67,18 +67,18 @@
         document.title = "";
         if (audioTracks.length > 0) {
           document.title += "audio";
         }
         if (videoTracks.length > 0) {
           document.title += "video";
         }
         document.title += " gumtest";
-        audio.srcObject.stop();
-        video.srcObject.stop();
+        audio.srcObject.getTracks().forEach(t => t.stop());
+        video.srcObject.getTracks().forEach(t => t.stop());
       }, function(err) {
         document.title = "failed gumtest";
         stopMedia();
       });
     } catch (e) {
       stopMedia();
     }
   }
--- a/mobile/android/tests/browser/robocop/robocop_getusermedia2.html
+++ b/mobile/android/tests/browser/robocop/robocop_getusermedia2.html
@@ -27,24 +27,24 @@
       video: true,
       audio: true
     };
     startMedia(mediaConstraints);
   }
 
   function stopMedia() {
     if (video_status) {
-      video.srcObject.stop();
+      video.srcObject.getTracks().forEach(t => t.stop());
       video.srcObject = null;
       content.removeChild(video);
       capturing = false;
       video_status = false;
     }
     if (audio_status) {
-      audio.srcObject.stop();
+      audio.srcObject.getTracks().forEach(t => t.stop());
       audio.srcObject = null;
       content.removeChild(audio);
       audio_status = false;
     }
   }
 
   function startMedia(param) {
     try {
@@ -64,18 +64,18 @@
         document.title = "";
         if (audioTracks.length > 0) {
           document.title += "audio";
         }
         if (videoTracks.length > 0) {
           document.title += "video";
         }
         document.title += " gumtest";
-        audio.srcObject.stop();
-        video.srcObject.stop();
+        audio.srcObject.getTracks().forEach(t => t.stop());
+        video.srcObject.getTracks().forEach(t => t.stop());
       }, function(err) {
         document.title = "failed gumtest";
         stopMedia();
       });
     } catch (e) {
       stopMedia();
     }
   }
--- a/testing/web-platform/tests/html/dom/interfaces.https.html
+++ b/testing/web-platform/tests/html/dom/interfaces.https.html
@@ -189,17 +189,16 @@ idl_test(
       Navigator: ['window.navigator'],
       External: ['window.external'],
       DataTransfer: [],
       DataTransferItemList: [],
       DataTransferItem: [],
       DragEvent: [],
       NavigatorUserMediaError: [],
       MediaStream: [],
-      LocalMediaStream: [],
       MediaStreamTrack: [],
       MediaStreamRecorder: [],
       PeerConnection: [],
       MediaStreamEvent: [],
       ErrorEvent: [],
       WebSocket: ['new WebSocket("wss://foo")'],
       CloseEvent: ['new CloseEvent("close")'],
       AbstractWorker: [],