Bug 1258143 - Remove LocalMediaStream. r=jib,smaug
authorAndreas Pehrson <apehrson@mozilla.com>
Mon, 15 Oct 2018 08:17:07 +0000
changeset 489649 9508a03be7c2ed82678cf62b0ba5356826738e9b
parent 489648 9d3c1734052cb639b5035ac3f652547ccbdfa1a7
child 489650 92b4fac6ea6c74a9292a21fd086fa35f76c8ba92
push id247
push userfmarier@mozilla.com
push dateSat, 27 Oct 2018 01:06:44 +0000
reviewersjib, smaug
bugs1258143
milestone64.0a1
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: [],