Merge f-t to m-c, a=merge
authorPhil Ringnalda <philringnalda@gmail.com>
Sun, 13 Sep 2015 10:55:06 -0700
changeset 262206 3ea2f8d4e8b6abd3c7d4dce42352c2f2748f18e7
parent 262199 d9ec62232cf50817b4e082824a16d596ef4c3970 (current diff)
parent 262205 085137ec0ab2905eaafaf572317e4ad51f162d63 (diff)
child 262240 9ed17db42e3e46f1c712e4dffd62d54e915e0fac
push id29365
push userphilringnalda@gmail.com
push dateSun, 13 Sep 2015 17:55:14 +0000
treeherdermozilla-central@3ea2f8d4e8b6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersmerge
milestone43.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
Merge f-t to m-c, a=merge
--- a/browser/components/loop/content/js/conversationViews.js
+++ b/browser/components/loop/content/js/conversationViews.js
@@ -649,28 +649,28 @@ loop.conversationViews = (function(mozL1
     /**
      * Should we render a visual cue to the user (e.g. a spinner) that a local
      * stream is on its way from the camera?
      *
      * @returns {boolean}
      * @private
      */
     _isLocalLoading: function () {
-      return !this.state.localSrcVideoObject && !this.props.localPosterUrl;
+      return !this.state.localSrcMediaElement && !this.props.localPosterUrl;
     },
 
     /**
      * Should we render a visual cue to the user (e.g. a spinner) that a remote
      * stream is on its way from the other user?
      *
      * @returns {boolean}
      * @private
      */
     _isRemoteLoading: function() {
-      return !!(!this.state.remoteSrcVideoObject &&
+      return !!(!this.state.remoteSrcMediaElement &&
                 !this.props.remotePosterUrl &&
                 !this.state.mediaConnected);
     },
 
     shouldRenderRemoteVideo: function() {
       if (this.props.mediaConnected) {
         // If remote video is not enabled, we're muted, so we'll show an avatar
         // instead.
@@ -697,24 +697,24 @@ loop.conversationViews = (function(mozL1
         React.createElement("div", {className: "desktop-call-wrapper"}, 
           React.createElement(sharedViews.MediaLayoutView, {
             dispatcher: this.props.dispatcher, 
             displayScreenShare: false, 
             isLocalLoading: this._isLocalLoading(), 
             isRemoteLoading: this._isRemoteLoading(), 
             isScreenShareLoading: false, 
             localPosterUrl: this.props.localPosterUrl, 
-            localSrcVideoObject: this.state.localSrcVideoObject, 
+            localSrcMediaElement: this.state.localSrcMediaElement, 
             localVideoMuted: !this.props.video.enabled, 
             matchMedia: this.state.matchMedia || window.matchMedia.bind(window), 
             remotePosterUrl: this.props.remotePosterUrl, 
-            remoteSrcVideoObject: this.state.remoteSrcVideoObject, 
+            remoteSrcMediaElement: this.state.remoteSrcMediaElement, 
             renderRemoteVideo: this.shouldRenderRemoteVideo(), 
+            screenShareMediaElement: this.state.screenShareMediaElement, 
             screenSharePosterUrl: null, 
-            screenShareVideoObject: this.state.screenShareVideoObject, 
             showContextRoomName: false, 
             useDesktopPaths: true}, 
             React.createElement(loop.shared.views.ConversationToolbar, {
               audio: this.props.audio, 
               dispatcher: this.props.dispatcher, 
               hangup: this.hangup, 
               mozLoop: this.props.mozLoop, 
               publishStream: this.publishStream, 
@@ -817,17 +817,17 @@ loop.conversationViews = (function(mozL1
         }
         case CALL_STATES.ONGOING: {
           return (React.createElement(OngoingConversationView, {
             audio: { enabled: !this.state.audioMuted, visible: true}, 
             conversationStore: this.getStore(), 
             dispatcher: this.props.dispatcher, 
             mediaConnected: this.state.mediaConnected, 
             mozLoop: this.props.mozLoop, 
-            remoteSrcVideoObject: this.state.remoteSrcVideoObject, 
+            remoteSrcMediaElement: this.state.remoteSrcMediaElement, 
             remoteVideoEnabled: this.state.remoteVideoEnabled, 
             video: { enabled: !this.state.videoMuted, visible: true}})
           );
         }
         case CALL_STATES.FINISHED: {
           this.play("terminated");
 
           // When conversation ended we either display a feedback form or
--- a/browser/components/loop/content/js/conversationViews.jsx
+++ b/browser/components/loop/content/js/conversationViews.jsx
@@ -649,28 +649,28 @@ loop.conversationViews = (function(mozL1
     /**
      * Should we render a visual cue to the user (e.g. a spinner) that a local
      * stream is on its way from the camera?
      *
      * @returns {boolean}
      * @private
      */
     _isLocalLoading: function () {
-      return !this.state.localSrcVideoObject && !this.props.localPosterUrl;
+      return !this.state.localSrcMediaElement && !this.props.localPosterUrl;
     },
 
     /**
      * Should we render a visual cue to the user (e.g. a spinner) that a remote
      * stream is on its way from the other user?
      *
      * @returns {boolean}
      * @private
      */
     _isRemoteLoading: function() {
-      return !!(!this.state.remoteSrcVideoObject &&
+      return !!(!this.state.remoteSrcMediaElement &&
                 !this.props.remotePosterUrl &&
                 !this.state.mediaConnected);
     },
 
     shouldRenderRemoteVideo: function() {
       if (this.props.mediaConnected) {
         // If remote video is not enabled, we're muted, so we'll show an avatar
         // instead.
@@ -697,24 +697,24 @@ loop.conversationViews = (function(mozL1
         <div className="desktop-call-wrapper">
           <sharedViews.MediaLayoutView
             dispatcher={this.props.dispatcher}
             displayScreenShare={false}
             isLocalLoading={this._isLocalLoading()}
             isRemoteLoading={this._isRemoteLoading()}
             isScreenShareLoading={false}
             localPosterUrl={this.props.localPosterUrl}
-            localSrcVideoObject={this.state.localSrcVideoObject}
+            localSrcMediaElement={this.state.localSrcMediaElement}
             localVideoMuted={!this.props.video.enabled}
             matchMedia={this.state.matchMedia || window.matchMedia.bind(window)}
             remotePosterUrl={this.props.remotePosterUrl}
-            remoteSrcVideoObject={this.state.remoteSrcVideoObject}
+            remoteSrcMediaElement={this.state.remoteSrcMediaElement}
             renderRemoteVideo={this.shouldRenderRemoteVideo()}
+            screenShareMediaElement={this.state.screenShareMediaElement}
             screenSharePosterUrl={null}
-            screenShareVideoObject={this.state.screenShareVideoObject}
             showContextRoomName={false}
             useDesktopPaths={true}>
             <loop.shared.views.ConversationToolbar
               audio={this.props.audio}
               dispatcher={this.props.dispatcher}
               hangup={this.hangup}
               mozLoop={this.props.mozLoop}
               publishStream={this.publishStream}
@@ -817,17 +817,17 @@ loop.conversationViews = (function(mozL1
         }
         case CALL_STATES.ONGOING: {
           return (<OngoingConversationView
             audio={{ enabled: !this.state.audioMuted, visible: true }}
             conversationStore={this.getStore()}
             dispatcher={this.props.dispatcher}
             mediaConnected={this.state.mediaConnected}
             mozLoop={this.props.mozLoop}
-            remoteSrcVideoObject={this.state.remoteSrcVideoObject}
+            remoteSrcMediaElement={this.state.remoteSrcMediaElement}
             remoteVideoEnabled={this.state.remoteVideoEnabled}
             video={{ enabled: !this.state.videoMuted, visible: true }} />
           );
         }
         case CALL_STATES.FINISHED: {
           this.play("terminated");
 
           // When conversation ended we either display a feedback form or
--- a/browser/components/loop/content/js/roomViews.js
+++ b/browser/components/loop/content/js/roomViews.js
@@ -702,29 +702,29 @@ loop.roomViews = (function(mozL10n) {
      * Should we render a visual cue to the user (e.g. a spinner) that a local
      * stream is on its way from the camera?
      *
      * @returns {boolean}
      * @private
      */
     _isLocalLoading: function () {
       return this.state.roomState === ROOM_STATES.MEDIA_WAIT &&
-             !this.state.localSrcVideoObject;
+             !this.state.localSrcMediaElement;
     },
 
     /**
      * Should we render a visual cue to the user (e.g. a spinner) that a remote
      * stream is on its way from the other user?
      *
      * @returns {boolean}
      * @private
      */
     _isRemoteLoading: function() {
       return !!(this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS &&
-                !this.state.remoteSrcVideoObject &&
+                !this.state.remoteSrcMediaElement &&
                 !this.state.mediaConnected);
     },
 
     handleAddContextClick: function() {
       this.setState({ showEditContext: true });
     },
 
     handleEditContextClick: function() {
@@ -796,24 +796,24 @@ loop.roomViews = (function(mozL10n) {
             React.createElement("div", {className: "room-conversation-wrapper desktop-room-wrapper"}, 
               React.createElement(sharedViews.MediaLayoutView, {
                 dispatcher: this.props.dispatcher, 
                 displayScreenShare: false, 
                 isLocalLoading: this._isLocalLoading(), 
                 isRemoteLoading: this._isRemoteLoading(), 
                 isScreenShareLoading: false, 
                 localPosterUrl: this.props.localPosterUrl, 
-                localSrcVideoObject: this.state.localSrcVideoObject, 
+                localSrcMediaElement: this.state.localSrcMediaElement, 
                 localVideoMuted: this.state.videoMuted, 
                 matchMedia: this.state.matchMedia || window.matchMedia.bind(window), 
                 remotePosterUrl: this.props.remotePosterUrl, 
-                remoteSrcVideoObject: this.state.remoteSrcVideoObject, 
+                remoteSrcMediaElement: this.state.remoteSrcMediaElement, 
                 renderRemoteVideo: this.shouldRenderRemoteVideo(), 
+                screenShareMediaElement: this.state.screenShareMediaElement, 
                 screenSharePosterUrl: null, 
-                screenShareVideoObject: this.state.screenShareVideoObject, 
                 showContextRoomName: false, 
                 useDesktopPaths: true}, 
                 React.createElement(sharedViews.ConversationToolbar, {
                   audio: {enabled: !this.state.audioMuted, visible: true}, 
                   dispatcher: this.props.dispatcher, 
                   hangup: this.leaveRoom, 
                   mozLoop: this.props.mozLoop, 
                   publishStream: this.publishStream, 
--- a/browser/components/loop/content/js/roomViews.jsx
+++ b/browser/components/loop/content/js/roomViews.jsx
@@ -702,29 +702,29 @@ loop.roomViews = (function(mozL10n) {
      * Should we render a visual cue to the user (e.g. a spinner) that a local
      * stream is on its way from the camera?
      *
      * @returns {boolean}
      * @private
      */
     _isLocalLoading: function () {
       return this.state.roomState === ROOM_STATES.MEDIA_WAIT &&
-             !this.state.localSrcVideoObject;
+             !this.state.localSrcMediaElement;
     },
 
     /**
      * Should we render a visual cue to the user (e.g. a spinner) that a remote
      * stream is on its way from the other user?
      *
      * @returns {boolean}
      * @private
      */
     _isRemoteLoading: function() {
       return !!(this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS &&
-                !this.state.remoteSrcVideoObject &&
+                !this.state.remoteSrcMediaElement &&
                 !this.state.mediaConnected);
     },
 
     handleAddContextClick: function() {
       this.setState({ showEditContext: true });
     },
 
     handleEditContextClick: function() {
@@ -796,24 +796,24 @@ loop.roomViews = (function(mozL10n) {
             <div className="room-conversation-wrapper desktop-room-wrapper">
               <sharedViews.MediaLayoutView
                 dispatcher={this.props.dispatcher}
                 displayScreenShare={false}
                 isLocalLoading={this._isLocalLoading()}
                 isRemoteLoading={this._isRemoteLoading()}
                 isScreenShareLoading={false}
                 localPosterUrl={this.props.localPosterUrl}
-                localSrcVideoObject={this.state.localSrcVideoObject}
+                localSrcMediaElement={this.state.localSrcMediaElement}
                 localVideoMuted={this.state.videoMuted}
                 matchMedia={this.state.matchMedia || window.matchMedia.bind(window)}
                 remotePosterUrl={this.props.remotePosterUrl}
-                remoteSrcVideoObject={this.state.remoteSrcVideoObject}
+                remoteSrcMediaElement={this.state.remoteSrcMediaElement}
                 renderRemoteVideo={this.shouldRenderRemoteVideo()}
+                screenShareMediaElement={this.state.screenShareMediaElement}
                 screenSharePosterUrl={null}
-                screenShareVideoObject={this.state.screenShareVideoObject}
                 showContextRoomName={false}
                 useDesktopPaths={true}>
                 <sharedViews.ConversationToolbar
                   audio={{enabled: !this.state.audioMuted, visible: true}}
                   dispatcher={this.props.dispatcher}
                   hangup={this.leaveRoom}
                   mozLoop={this.props.mozLoop}
                   publishStream={this.publishStream}
--- a/browser/components/loop/content/shared/js/actions.js
+++ b/browser/components/loop/content/shared/js/actions.js
@@ -228,17 +228,17 @@ loop.shared.actions = (function() {
     }),
 
     /**
      * A stream from local or remote media has been created.
      */
     MediaStreamCreated: Action.define("mediaStreamCreated", {
       hasVideo: Boolean,
       isLocal: Boolean,
-      srcVideoObject: Object
+      srcMediaElement: Object
     }),
 
     /**
      * A stream from local or remote media has been destroyed.
      */
     MediaStreamDestroyed: Action.define("mediaStreamDestroyed", {
       isLocal: Boolean
     }),
@@ -289,17 +289,17 @@ loop.shared.actions = (function() {
 
     /**
      * Used to notify that a shared screen is being received (or not).
      *
      * XXX this should be split into multiple actions to make the code clearer.
      */
     ReceivingScreenShare: Action.define("receivingScreenShare", {
       receiving: Boolean
-      // srcVideoObject: Object (only present if receiving is true)
+      // srcMediaElement: Object (only present if receiving is true)
     }),
 
     /**
      * Creates a new room.
      * XXX: should move to some roomActions module - refs bug 1079284
      */
     CreateRoom: Action.define("createRoom", {
       // The localized template to use to name the new room
--- a/browser/components/loop/content/shared/js/activeRoomStore.js
+++ b/browser/components/loop/content/shared/js/activeRoomStore.js
@@ -101,25 +101,25 @@ loop.store.ActiveRoomStore = (function()
      * due to user choice, failure or other reason. It is a subset of
      * getInitialStoreState as some items (e.g. roomState, failureReason,
      * context information) can persist across room exit & re-entry.
      *
      * @type {Array}
      */
     _statesToResetOnLeave: [
       "audioMuted",
-      "localSrcVideoObject",
+      "localSrcMediaElement",
       "localVideoDimensions",
       "mediaConnected",
       "receivingScreenShare",
-      "remoteSrcVideoObject",
+      "remoteSrcMediaElement",
       "remoteVideoDimensions",
       "remoteVideoEnabled",
       "screenSharingState",
-      "screenShareVideoObject",
+      "screenShareMediaElement",
       "videoMuted"
     ],
 
     /**
      * Returns initial state data for this active room.
      *
      * When adding states, consider if _statesToResetOnLeave needs updating
      * as well.
@@ -635,42 +635,42 @@ loop.store.ActiveRoomStore = (function()
      * Handles a media stream being created. This may be a local or a remote stream.
      *
      * @param {sharedActions.MediaStreamCreated} actionData
      */
     mediaStreamCreated: function(actionData) {
       if (actionData.isLocal) {
         this.setStoreState({
           localVideoEnabled: actionData.hasVideo,
-          localSrcVideoObject: actionData.srcVideoObject
+          localSrcMediaElement: actionData.srcMediaElement
         });
         return;
       }
 
       this.setStoreState({
         remoteVideoEnabled: actionData.hasVideo,
-        remoteSrcVideoObject: actionData.srcVideoObject
+        remoteSrcMediaElement: actionData.srcMediaElement
       });
     },
 
     /**
      * Handles a media stream being destroyed. This may be a local or a remote stream.
      *
      * @param {sharedActions.MediaStreamDestroyed} actionData
      */
     mediaStreamDestroyed: function(actionData) {
       if (actionData.isLocal) {
         this.setStoreState({
-          localSrcVideoObject: null
+          localSrcMediaElement: null
         });
         return;
       }
 
       this.setStoreState({
-        remoteSrcVideoObject: null
+        remoteSrcMediaElement: null
       });
     },
 
     /**
      * Handles a remote stream having video enabled or disabled.
      *
      * @param {sharedActions.RemoteVideoStatus} actionData
      */
@@ -708,23 +708,23 @@ loop.store.ActiveRoomStore = (function()
           this.getStoreState().remoteVideoDimensions.screen) {
         // Remove the remote video dimensions for type screen as we're not
         // getting the share anymore.
         var newDimensions = _.extend(this.getStoreState().remoteVideoDimensions);
         delete newDimensions.screen;
         this.setStoreState({
           receivingScreenShare: actionData.receiving,
           remoteVideoDimensions: newDimensions,
-          screenShareVideoObject: null
+          screenShareMediaElement: null
         });
       } else {
         this.setStoreState({
           receivingScreenShare: actionData.receiving,
-          screenShareVideoObject: actionData.srcVideoObject ?
-                                  actionData.srcVideoObject : null
+          screenShareMediaElement: actionData.srcMediaElement ?
+                                  actionData.srcMediaElement : null
         });
       }
     },
 
     /**
      * Handles switching browser (aka tab) sharing to a new window. Should
      * only be used for browser sharing.
      *
@@ -824,17 +824,17 @@ loop.store.ActiveRoomStore = (function()
           return participant.owner;
         });
       }
 
       this.setStoreState({
         mediaConnected: false,
         participants: participants,
         roomState: ROOM_STATES.SESSION_CONNECTED,
-        remoteSrcVideoObject: null
+        remoteSrcMediaElement: null
       });
     },
 
     /**
      * Handles an SDK status update, forwarding it to the server.
      *
      * @param {sharedActions.ConnectionStatus} actionData
      */
--- a/browser/components/loop/content/shared/js/conversationStore.js
+++ b/browser/components/loop/content/shared/js/conversationStore.js
@@ -443,42 +443,42 @@ loop.store = loop.store || {};
      * Handles a media stream being created. This may be a local or a remote stream.
      *
      * @param {sharedActions.MediaStreamCreated} actionData
      */
     mediaStreamCreated: function(actionData) {
       if (actionData.isLocal) {
         this.setStoreState({
           localVideoEnabled: actionData.hasVideo,
-          localSrcVideoObject: actionData.srcVideoObject
+          localSrcMediaElement: actionData.srcMediaElement
         });
         return;
       }
 
       this.setStoreState({
         remoteVideoEnabled: actionData.hasVideo,
-        remoteSrcVideoObject: actionData.srcVideoObject
+        remoteSrcMediaElement: actionData.srcMediaElement
       });
     },
 
     /**
      * Handles a media stream being destroyed. This may be a local or a remote stream.
      *
      * @param {sharedActions.MediaStreamDestroyed} actionData
      */
     mediaStreamDestroyed: function(actionData) {
       if (actionData.isLocal) {
         this.setStoreState({
-          localSrcVideoObject: null
+          localSrcMediaElement: null
         });
         return;
       }
 
       this.setStoreState({
-        remoteSrcVideoObject: null
+        remoteSrcMediaElement: null
       });
     },
 
     /**
      * Handles a remote stream having video enabled or disabled.
      *
      * @param {sharedActions.RemoteVideoStatus} actionData
      */
--- a/browser/components/loop/content/shared/js/otSdkDriver.js
+++ b/browser/components/loop/content/shared/js/otSdkDriver.js
@@ -596,17 +596,17 @@ loop.OTSdkDriver = (function() {
       }
 
       sdkSubscriberObject.on("videoEnabled", this._onVideoEnabled.bind(this));
       sdkSubscriberObject.on("videoDisabled", this._onVideoDisabled.bind(this));
 
       this.dispatcher.dispatch(new sharedActions.MediaStreamCreated({
         hasVideo: sdkSubscriberObject.stream[STREAM_PROPERTIES.HAS_VIDEO],
         isLocal: false,
-        srcVideoObject: sdkSubscriberVideo
+        srcMediaElement: sdkSubscriberVideo
       }));
 
       this._subscribedRemoteStream = true;
       if (this._checkAllStreamsConnected()) {
         this._setTwoWayMediaStartTime(performance.now());
         this.dispatcher.dispatch(new sharedActions.MediaConnected());
       }
 
@@ -630,17 +630,17 @@ loop.OTSdkDriver = (function() {
 
       var sdkSubscriberVideo = subscriberVideo ? subscriberVideo :
         this._mockScreenShareEl.querySelector("video");
 
       // XXX no idea why this is necessary in addition to the dispatch in
       // _handleRemoteScreenShareCreated.  Maybe these should be separate
       // actions.  But even so, this shouldn't be necessary....
       this.dispatcher.dispatch(new sharedActions.ReceivingScreenShare({
-        receiving: true, srcVideoObject: sdkSubscriberVideo
+        receiving: true, srcMediaElement: sdkSubscriberVideo
       }));
 
     },
 
     /**
      * Once a remote stream has been subscribed to, this triggers the data
      * channel set-up routines. A data channel cannot be requested before this
      * time as the peer connection is not set up.
@@ -762,17 +762,17 @@ loop.OTSdkDriver = (function() {
       this._notifyMetricsEvent("Publisher.streamCreated");
 
       var sdkLocalVideo = this._mockPublisherEl.querySelector("video");
       var hasVideo = event.stream[STREAM_PROPERTIES.HAS_VIDEO];
 
       this.dispatcher.dispatch(new sharedActions.MediaStreamCreated({
         hasVideo: hasVideo,
         isLocal: true,
-        srcVideoObject: sdkLocalVideo
+        srcMediaElement: sdkLocalVideo
       }));
 
       // Only dispatch the video dimensions if we actually have video.
       if (hasVideo) {
         this.dispatcher.dispatch(new sharedActions.VideoDimensionsChanged({
           isLocal: true,
           videoType: event.stream.videoType,
           dimensions: event.stream[STREAM_PROPERTIES.VIDEO_DIMENSIONS]
--- a/browser/components/loop/content/shared/js/views.js
+++ b/browser/components/loop/content/shared/js/views.js
@@ -1070,53 +1070,53 @@ loop.shared.views = (function(_, mozL10n
     }
   });
 
   /**
    * Renders a media element for display. This also handles displaying an avatar
    * instead of the video, and attaching a video stream to the video element.
    */
   var MediaView = React.createClass({displayName: "MediaView",
-    // srcVideoObject should be ok for a shallow comparison, so we are safe
+    // srcMediaElement should be ok for a shallow comparison, so we are safe
     // to use the pure render mixin here.
     mixins: [React.addons.PureRenderMixin],
 
     propTypes: {
       displayAvatar: React.PropTypes.bool.isRequired,
       isLoading: React.PropTypes.bool.isRequired,
       mediaType: React.PropTypes.string.isRequired,
       posterUrl: React.PropTypes.string,
       // Expecting "local" or "remote".
-      srcVideoObject: React.PropTypes.object
+      srcMediaElement: React.PropTypes.object
     },
 
     componentDidMount: function() {
       if (!this.props.displayAvatar) {
-        this.attachVideo(this.props.srcVideoObject);
+        this.attachVideo(this.props.srcMediaElement);
       }
     },
 
     componentDidUpdate: function() {
       if (!this.props.displayAvatar) {
-        this.attachVideo(this.props.srcVideoObject);
+        this.attachVideo(this.props.srcMediaElement);
       }
     },
 
     /**
      * Attaches a video stream from a donor video element to this component's
      * video element if the component is displaying one.
      *
-     * @param {Object} srcVideoObject The src video object to clone the stream
+     * @param {Object} srcMediaElement The src video object to clone the stream
      *                                from.
      *
      * XXX need to have a corresponding detachVideo or change this to syncVideo
      * to protect from leaks (bug 1171978)
      */
-    attachVideo: function(srcVideoObject) {
-      if (!srcVideoObject) {
+    attachVideo: function(srcMediaElement) {
+      if (!srcMediaElement) {
         // Not got anything to display.
         return;
       }
 
       var videoElement = this.getDOMNode();
 
       if (videoElement.tagName.toLowerCase() !== "video") {
         // Must be displaying the avatar view, so don't try and attach video.
@@ -1136,32 +1136,32 @@ loop.shared.views = (function(_, mozL10n
         attrName = "src";
       } else {
         console.error("Error attaching stream to element - no supported" +
                       "attribute found");
         return;
       }
 
       // If the object hasn't changed it, then don't reattach it.
-      if (videoElement[attrName] !== srcVideoObject[attrName]) {
-        videoElement[attrName] = srcVideoObject[attrName];
+      if (videoElement[attrName] !== srcMediaElement[attrName]) {
+        videoElement[attrName] = srcMediaElement[attrName];
       }
       videoElement.play();
     },
 
     render: function() {
       if (this.props.isLoading) {
         return React.createElement(LoadingView, null);
       }
 
       if (this.props.displayAvatar) {
         return React.createElement(AvatarView, null);
       }
 
-      if (!this.props.srcVideoObject && !this.props.posterUrl) {
+      if (!this.props.srcMediaElement && !this.props.posterUrl) {
         return React.createElement("div", {className: "no-video"});
       }
 
       var optionalPoster = {};
       if (this.props.posterUrl) {
         optionalPoster.poster = this.props.posterUrl;
       }
 
@@ -1187,26 +1187,26 @@ loop.shared.views = (function(_, mozL10n
       children: React.PropTypes.node,
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       displayScreenShare: React.PropTypes.bool.isRequired,
       isLocalLoading: React.PropTypes.bool.isRequired,
       isRemoteLoading: React.PropTypes.bool.isRequired,
       isScreenShareLoading: React.PropTypes.bool.isRequired,
       // The poster URLs are for UI-showcase testing and development.
       localPosterUrl: React.PropTypes.string,
-      localSrcVideoObject: React.PropTypes.object,
+      localSrcMediaElement: React.PropTypes.object,
       localVideoMuted: React.PropTypes.bool.isRequired,
       // Passing in matchMedia, allows it to be overriden for ui-showcase's
       // benefit. We expect either the override or window.matchMedia.
       matchMedia: React.PropTypes.func.isRequired,
       remotePosterUrl: React.PropTypes.string,
-      remoteSrcVideoObject: React.PropTypes.object,
+      remoteSrcMediaElement: React.PropTypes.object,
       renderRemoteVideo: React.PropTypes.bool.isRequired,
+      screenShareMediaElement: React.PropTypes.object,
       screenSharePosterUrl: React.PropTypes.string,
-      screenShareVideoObject: React.PropTypes.object,
       showContextRoomName: React.PropTypes.bool.isRequired,
       useDesktopPaths: React.PropTypes.bool.isRequired
     },
 
     isLocalMediaAbsolutelyPositioned: function(matchMedia) {
       if (!matchMedia) {
         matchMedia = this.props.matchMedia;
       }
@@ -1250,17 +1250,17 @@ loop.shared.views = (function(_, mozL10n
 
     renderLocalVideo: function() {
       return (
         React.createElement("div", {className: "local"}, 
           React.createElement(MediaView, {displayAvatar: this.props.localVideoMuted, 
             isLoading: this.props.isLocalLoading, 
             mediaType: "local", 
             posterUrl: this.props.localPosterUrl, 
-            srcVideoObject: this.props.localSrcVideoObject})
+            srcMediaElement: this.props.localSrcMediaElement})
         )
       );
     },
 
     render: function() {
       var remoteStreamClasses = React.addons.classSet({
         "remote": true,
         "focus-stream": !this.props.displayScreenShare
@@ -1269,45 +1269,45 @@ loop.shared.views = (function(_, mozL10n
       var screenShareStreamClasses = React.addons.classSet({
         "screen": true,
         "focus-stream": this.props.displayScreenShare
       });
 
       var mediaWrapperClasses = React.addons.classSet({
         "media-wrapper": true,
         "receiving-screen-share": this.props.displayScreenShare,
-        "showing-local-streams": this.props.localSrcVideoObject ||
+        "showing-local-streams": this.props.localSrcMediaElement ||
           this.props.localPosterUrl,
-        "showing-remote-streams": this.props.remoteSrcVideoObject ||
+        "showing-remote-streams": this.props.remoteSrcMediaElement ||
           this.props.remotePosterUrl || this.props.isRemoteLoading
       });
 
       return (
         React.createElement("div", {className: "media-layout"}, 
           React.createElement("div", {className: mediaWrapperClasses}, 
             React.createElement("span", {className: "self-view-hidden-message"}, 
               mozL10n.get("self_view_hidden_message")
             ), 
             React.createElement("div", {className: remoteStreamClasses}, 
               React.createElement(MediaView, {displayAvatar: !this.props.renderRemoteVideo, 
                 isLoading: this.props.isRemoteLoading, 
                 mediaType: "remote", 
                 posterUrl: this.props.remotePosterUrl, 
-                srcVideoObject: this.props.remoteSrcVideoObject}), 
+                srcMediaElement: this.props.remoteSrcMediaElement}), 
                this.state.localMediaAboslutelyPositioned ?
                 this.renderLocalVideo() : null, 
                this.props.children
 
             ), 
             React.createElement("div", {className: screenShareStreamClasses}, 
               React.createElement(MediaView, {displayAvatar: false, 
                 isLoading: this.props.isScreenShareLoading, 
                 mediaType: "screen-share", 
                 posterUrl: this.props.screenSharePosterUrl, 
-                srcVideoObject: this.props.screenShareVideoObject})
+                srcMediaElement: this.props.screenShareMediaElement})
             ), 
             React.createElement(loop.shared.views.chat.TextChatView, {
               dispatcher: this.props.dispatcher, 
               showRoomName: this.props.showContextRoomName, 
               useDesktopPaths: this.props.useDesktopPaths}), 
              this.state.localMediaAboslutelyPositioned ?
               null : this.renderLocalVideo()
           )
--- a/browser/components/loop/content/shared/js/views.jsx
+++ b/browser/components/loop/content/shared/js/views.jsx
@@ -1070,53 +1070,53 @@ loop.shared.views = (function(_, mozL10n
     }
   });
 
   /**
    * Renders a media element for display. This also handles displaying an avatar
    * instead of the video, and attaching a video stream to the video element.
    */
   var MediaView = React.createClass({
-    // srcVideoObject should be ok for a shallow comparison, so we are safe
+    // srcMediaElement should be ok for a shallow comparison, so we are safe
     // to use the pure render mixin here.
     mixins: [React.addons.PureRenderMixin],
 
     propTypes: {
       displayAvatar: React.PropTypes.bool.isRequired,
       isLoading: React.PropTypes.bool.isRequired,
       mediaType: React.PropTypes.string.isRequired,
       posterUrl: React.PropTypes.string,
       // Expecting "local" or "remote".
-      srcVideoObject: React.PropTypes.object
+      srcMediaElement: React.PropTypes.object
     },
 
     componentDidMount: function() {
       if (!this.props.displayAvatar) {
-        this.attachVideo(this.props.srcVideoObject);
+        this.attachVideo(this.props.srcMediaElement);
       }
     },
 
     componentDidUpdate: function() {
       if (!this.props.displayAvatar) {
-        this.attachVideo(this.props.srcVideoObject);
+        this.attachVideo(this.props.srcMediaElement);
       }
     },
 
     /**
      * Attaches a video stream from a donor video element to this component's
      * video element if the component is displaying one.
      *
-     * @param {Object} srcVideoObject The src video object to clone the stream
+     * @param {Object} srcMediaElement The src video object to clone the stream
      *                                from.
      *
      * XXX need to have a corresponding detachVideo or change this to syncVideo
      * to protect from leaks (bug 1171978)
      */
-    attachVideo: function(srcVideoObject) {
-      if (!srcVideoObject) {
+    attachVideo: function(srcMediaElement) {
+      if (!srcMediaElement) {
         // Not got anything to display.
         return;
       }
 
       var videoElement = this.getDOMNode();
 
       if (videoElement.tagName.toLowerCase() !== "video") {
         // Must be displaying the avatar view, so don't try and attach video.
@@ -1136,32 +1136,32 @@ loop.shared.views = (function(_, mozL10n
         attrName = "src";
       } else {
         console.error("Error attaching stream to element - no supported" +
                       "attribute found");
         return;
       }
 
       // If the object hasn't changed it, then don't reattach it.
-      if (videoElement[attrName] !== srcVideoObject[attrName]) {
-        videoElement[attrName] = srcVideoObject[attrName];
+      if (videoElement[attrName] !== srcMediaElement[attrName]) {
+        videoElement[attrName] = srcMediaElement[attrName];
       }
       videoElement.play();
     },
 
     render: function() {
       if (this.props.isLoading) {
         return <LoadingView />;
       }
 
       if (this.props.displayAvatar) {
         return <AvatarView />;
       }
 
-      if (!this.props.srcVideoObject && !this.props.posterUrl) {
+      if (!this.props.srcMediaElement && !this.props.posterUrl) {
         return <div className="no-video"/>;
       }
 
       var optionalPoster = {};
       if (this.props.posterUrl) {
         optionalPoster.poster = this.props.posterUrl;
       }
 
@@ -1187,26 +1187,26 @@ loop.shared.views = (function(_, mozL10n
       children: React.PropTypes.node,
       dispatcher: React.PropTypes.instanceOf(loop.Dispatcher).isRequired,
       displayScreenShare: React.PropTypes.bool.isRequired,
       isLocalLoading: React.PropTypes.bool.isRequired,
       isRemoteLoading: React.PropTypes.bool.isRequired,
       isScreenShareLoading: React.PropTypes.bool.isRequired,
       // The poster URLs are for UI-showcase testing and development.
       localPosterUrl: React.PropTypes.string,
-      localSrcVideoObject: React.PropTypes.object,
+      localSrcMediaElement: React.PropTypes.object,
       localVideoMuted: React.PropTypes.bool.isRequired,
       // Passing in matchMedia, allows it to be overriden for ui-showcase's
       // benefit. We expect either the override or window.matchMedia.
       matchMedia: React.PropTypes.func.isRequired,
       remotePosterUrl: React.PropTypes.string,
-      remoteSrcVideoObject: React.PropTypes.object,
+      remoteSrcMediaElement: React.PropTypes.object,
       renderRemoteVideo: React.PropTypes.bool.isRequired,
+      screenShareMediaElement: React.PropTypes.object,
       screenSharePosterUrl: React.PropTypes.string,
-      screenShareVideoObject: React.PropTypes.object,
       showContextRoomName: React.PropTypes.bool.isRequired,
       useDesktopPaths: React.PropTypes.bool.isRequired
     },
 
     isLocalMediaAbsolutelyPositioned: function(matchMedia) {
       if (!matchMedia) {
         matchMedia = this.props.matchMedia;
       }
@@ -1250,17 +1250,17 @@ loop.shared.views = (function(_, mozL10n
 
     renderLocalVideo: function() {
       return (
         <div className="local">
           <MediaView displayAvatar={this.props.localVideoMuted}
             isLoading={this.props.isLocalLoading}
             mediaType="local"
             posterUrl={this.props.localPosterUrl}
-            srcVideoObject={this.props.localSrcVideoObject} />
+            srcMediaElement={this.props.localSrcMediaElement} />
         </div>
       );
     },
 
     render: function() {
       var remoteStreamClasses = React.addons.classSet({
         "remote": true,
         "focus-stream": !this.props.displayScreenShare
@@ -1269,45 +1269,45 @@ loop.shared.views = (function(_, mozL10n
       var screenShareStreamClasses = React.addons.classSet({
         "screen": true,
         "focus-stream": this.props.displayScreenShare
       });
 
       var mediaWrapperClasses = React.addons.classSet({
         "media-wrapper": true,
         "receiving-screen-share": this.props.displayScreenShare,
-        "showing-local-streams": this.props.localSrcVideoObject ||
+        "showing-local-streams": this.props.localSrcMediaElement ||
           this.props.localPosterUrl,
-        "showing-remote-streams": this.props.remoteSrcVideoObject ||
+        "showing-remote-streams": this.props.remoteSrcMediaElement ||
           this.props.remotePosterUrl || this.props.isRemoteLoading
       });
 
       return (
         <div className="media-layout">
           <div className={mediaWrapperClasses}>
             <span className="self-view-hidden-message">
               {mozL10n.get("self_view_hidden_message")}
             </span>
             <div className={remoteStreamClasses}>
               <MediaView displayAvatar={!this.props.renderRemoteVideo}
                 isLoading={this.props.isRemoteLoading}
                 mediaType="remote"
                 posterUrl={this.props.remotePosterUrl}
-                srcVideoObject={this.props.remoteSrcVideoObject} />
+                srcMediaElement={this.props.remoteSrcMediaElement} />
               { this.state.localMediaAboslutelyPositioned ?
                 this.renderLocalVideo() : null }
               { this.props.children }
 
             </div>
             <div className={screenShareStreamClasses}>
               <MediaView displayAvatar={false}
                 isLoading={this.props.isScreenShareLoading}
                 mediaType="screen-share"
                 posterUrl={this.props.screenSharePosterUrl}
-                srcVideoObject={this.props.screenShareVideoObject} />
+                srcMediaElement={this.props.screenShareMediaElement} />
             </div>
             <loop.shared.views.chat.TextChatView
               dispatcher={this.props.dispatcher}
               showRoomName={this.props.showContextRoomName}
               useDesktopPaths={this.props.useDesktopPaths} />
             { this.state.localMediaAboslutelyPositioned ?
               null : this.renderLocalVideo() }
           </div>
--- a/browser/components/loop/standalone/content/js/standaloneRoomViews.js
+++ b/browser/components/loop/standalone/content/js/standaloneRoomViews.js
@@ -508,42 +508,42 @@ loop.standaloneRoomViews = (function(moz
      * Should we render a visual cue to the user (e.g. a spinner) that a local
      * stream is on its way from the camera?
      *
      * @returns {boolean}
      * @private
      */
     _isLocalLoading: function () {
       return this.state.roomState === ROOM_STATES.MEDIA_WAIT &&
-             !this.state.localSrcVideoObject;
+             !this.state.localSrcMediaElement;
     },
 
     /**
      * Should we render a visual cue to the user (e.g. a spinner) that a remote
      * stream is on its way from the other user?
      *
      * @returns {boolean}
      * @private
      */
     _isRemoteLoading: function() {
       return !!(this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS &&
-                !this.state.remoteSrcVideoObject &&
+                !this.state.remoteSrcMediaElement &&
                 !this.state.mediaConnected);
     },
 
     /**
      * Should we render a visual cue to the user (e.g. a spinner) that a remote
      * screen-share is on its way from the other user?
      *
      * @returns {boolean}
      * @private
      */
     _isScreenShareLoading: function() {
       return this.state.receivingScreenShare &&
-             !this.state.screenShareVideoObject &&
+             !this.state.screenShareMediaElement &&
              !this.props.screenSharePosterUrl;
     },
 
     render: function() {
       var displayScreenShare = !!(this.state.receivingScreenShare ||
         this.props.screenSharePosterUrl);
 
       return (
@@ -552,24 +552,24 @@ loop.standaloneRoomViews = (function(moz
           React.createElement(StandaloneRoomHeader, {dispatcher: this.props.dispatcher}), 
           React.createElement(sharedViews.MediaLayoutView, {
             dispatcher: this.props.dispatcher, 
             displayScreenShare: displayScreenShare, 
             isLocalLoading: this._isLocalLoading(), 
             isRemoteLoading: this._isRemoteLoading(), 
             isScreenShareLoading: this._isScreenShareLoading(), 
             localPosterUrl: this.props.localPosterUrl, 
-            localSrcVideoObject: this.state.localSrcVideoObject, 
+            localSrcMediaElement: this.state.localSrcMediaElement, 
             localVideoMuted: this.state.videoMuted, 
             matchMedia: this.state.matchMedia || window.matchMedia.bind(window), 
             remotePosterUrl: this.props.remotePosterUrl, 
-            remoteSrcVideoObject: this.state.remoteSrcVideoObject, 
+            remoteSrcMediaElement: this.state.remoteSrcMediaElement, 
             renderRemoteVideo: this.shouldRenderRemoteVideo(), 
+            screenShareMediaElement: this.state.screenShareMediaElement, 
             screenSharePosterUrl: this.props.screenSharePosterUrl, 
-            screenShareVideoObject: this.state.screenShareVideoObject, 
             showContextRoomName: true, 
             useDesktopPaths: false}, 
             React.createElement(StandaloneRoomInfoArea, {activeRoomStore: this.props.activeRoomStore, 
               dispatcher: this.props.dispatcher, 
               failureReason: this.state.failureReason, 
               isFirefox: this.props.isFirefox, 
               joinRoom: this.joinRoom, 
               roomState: this.state.roomState, 
--- a/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx
+++ b/browser/components/loop/standalone/content/js/standaloneRoomViews.jsx
@@ -508,42 +508,42 @@ loop.standaloneRoomViews = (function(moz
      * Should we render a visual cue to the user (e.g. a spinner) that a local
      * stream is on its way from the camera?
      *
      * @returns {boolean}
      * @private
      */
     _isLocalLoading: function () {
       return this.state.roomState === ROOM_STATES.MEDIA_WAIT &&
-             !this.state.localSrcVideoObject;
+             !this.state.localSrcMediaElement;
     },
 
     /**
      * Should we render a visual cue to the user (e.g. a spinner) that a remote
      * stream is on its way from the other user?
      *
      * @returns {boolean}
      * @private
      */
     _isRemoteLoading: function() {
       return !!(this.state.roomState === ROOM_STATES.HAS_PARTICIPANTS &&
-                !this.state.remoteSrcVideoObject &&
+                !this.state.remoteSrcMediaElement &&
                 !this.state.mediaConnected);
     },
 
     /**
      * Should we render a visual cue to the user (e.g. a spinner) that a remote
      * screen-share is on its way from the other user?
      *
      * @returns {boolean}
      * @private
      */
     _isScreenShareLoading: function() {
       return this.state.receivingScreenShare &&
-             !this.state.screenShareVideoObject &&
+             !this.state.screenShareMediaElement &&
              !this.props.screenSharePosterUrl;
     },
 
     render: function() {
       var displayScreenShare = !!(this.state.receivingScreenShare ||
         this.props.screenSharePosterUrl);
 
       return (
@@ -552,24 +552,24 @@ loop.standaloneRoomViews = (function(moz
           <StandaloneRoomHeader dispatcher={this.props.dispatcher} />
           <sharedViews.MediaLayoutView
             dispatcher={this.props.dispatcher}
             displayScreenShare={displayScreenShare}
             isLocalLoading={this._isLocalLoading()}
             isRemoteLoading={this._isRemoteLoading()}
             isScreenShareLoading={this._isScreenShareLoading()}
             localPosterUrl={this.props.localPosterUrl}
-            localSrcVideoObject={this.state.localSrcVideoObject}
+            localSrcMediaElement={this.state.localSrcMediaElement}
             localVideoMuted={this.state.videoMuted}
             matchMedia={this.state.matchMedia || window.matchMedia.bind(window)}
             remotePosterUrl={this.props.remotePosterUrl}
-            remoteSrcVideoObject={this.state.remoteSrcVideoObject}
+            remoteSrcMediaElement={this.state.remoteSrcMediaElement}
             renderRemoteVideo={this.shouldRenderRemoteVideo()}
+            screenShareMediaElement={this.state.screenShareMediaElement}
             screenSharePosterUrl={this.props.screenSharePosterUrl}
-            screenShareVideoObject={this.state.screenShareVideoObject}
             showContextRoomName={true}
             useDesktopPaths={false}>
             <StandaloneRoomInfoArea activeRoomStore={this.props.activeRoomStore}
               dispatcher={this.props.dispatcher}
               failureReason={this.state.failureReason}
               isFirefox={this.props.isFirefox}
               joinRoom={this.joinRoom}
               roomState={this.state.roomState}
--- a/browser/components/loop/test/desktop-local/conversationViews_test.js
+++ b/browser/components/loop/test/desktop-local/conversationViews_test.js
@@ -533,30 +533,30 @@ describe("loop.conversationViews", funct
 
         sinon.assert.calledOnce(dispatcher.dispatch);
         sinon.assert.calledWithMatch(dispatcher.dispatch,
           sinon.match.hasOwn("name", "setupStreamElements"));
       });
 
     it("should display the remote video when the stream is enabled", function() {
       conversationStore.setStoreState({
-        remoteSrcVideoObject: { fake: 1 }
+        remoteSrcMediaElement: { fake: 1 }
       });
 
       view = mountTestComponent({
         mediaConnected: true,
         remoteVideoEnabled: true
       });
 
       expect(view.getDOMNode().querySelector(".remote video")).not.eql(null);
     });
 
     it("should display the local video when the stream is enabled", function() {
       conversationStore.setStoreState({
-        localSrcVideoObject: { fake: 1 }
+        localSrcMediaElement: { fake: 1 }
       });
 
       view = mountTestComponent({
         video: {
           enabled: true
         }
       });
 
--- a/browser/components/loop/test/desktop-local/roomViews_test.js
+++ b/browser/components/loop/test/desktop-local/roomViews_test.js
@@ -589,60 +589,60 @@ describe("loop.roomViews", function () {
 
         view = mountTestComponent();
         // Force a state change so that it triggers componentDidUpdate
         view.setState({ foo: "bar" });
 
         sinon.assert.calledOnce(onCallTerminatedStub);
       });
 
-      it("should display loading spinner when localSrcVideoObject is null",
+      it("should display loading spinner when localSrcMediaElement is null",
          function() {
            activeRoomStore.setStoreState({
              roomState: ROOM_STATES.MEDIA_WAIT,
-             localSrcVideoObject: null
+             localSrcMediaElement: null
            });
 
            view = mountTestComponent();
 
            expect(view.getDOMNode().querySelector(".local .loading-stream"))
                .not.eql(null);
          });
 
       it("should not display a loading spinner when local stream available",
          function() {
            activeRoomStore.setStoreState({
              roomState: ROOM_STATES.MEDIA_WAIT,
-             localSrcVideoObject: { fake: "video" }
+             localSrcMediaElement: { fake: "video" }
            });
 
            view = mountTestComponent();
 
            expect(view.getDOMNode().querySelector(".local .loading-stream"))
                .eql(null);
          });
 
       it("should display loading spinner when remote stream is not available",
          function() {
            activeRoomStore.setStoreState({
              roomState: ROOM_STATES.HAS_PARTICIPANTS,
-             remoteSrcVideoObject: null
+             remoteSrcMediaElement: null
            });
 
            view = mountTestComponent();
 
            expect(view.getDOMNode().querySelector(".remote .loading-stream"))
                .not.eql(null);
          });
 
       it("should not display a loading spinner when remote stream available",
          function() {
            activeRoomStore.setStoreState({
              roomState: ROOM_STATES.HAS_PARTICIPANTS,
-             remoteSrcVideoObject: { fake: "video" }
+             remoteSrcMediaElement: { fake: "video" }
            });
 
            view = mountTestComponent();
 
            expect(view.getDOMNode().querySelector(".remote .loading-stream"))
                .eql(null);
          });
 
@@ -659,17 +659,17 @@ describe("loop.roomViews", function () {
           TestUtils.findRenderedComponentWithType(view, sharedViews.AvatarView);
         });
 
       it("should display the remote video when there are participants and video is enabled", function() {
         activeRoomStore.setStoreState({
           roomState: ROOM_STATES.HAS_PARTICIPANTS,
           mediaConnected: true,
           remoteVideoEnabled: true,
-          remoteSrcVideoObject: { fake: 1 }
+          remoteSrcMediaElement: { fake: 1 }
         });
 
         view = mountTestComponent();
 
         expect(view.getDOMNode().querySelector(".remote video")).not.eql(null);
       });
 
       it("should display an avatar for local video when the stream is muted", function() {
@@ -679,17 +679,17 @@ describe("loop.roomViews", function () {
 
         view = mountTestComponent();
 
         TestUtils.findRenderedComponentWithType(view, sharedViews.AvatarView);
       });
 
       it("should display the local video when the stream is enabled", function() {
         activeRoomStore.setStoreState({
-          localSrcVideoObject: { fake: 1 },
+          localSrcMediaElement: { fake: 1 },
           videoMuted: false
         });
 
         view = mountTestComponent();
 
         expect(view.getDOMNode().querySelector(".local video")).not.eql(null);
       });
 
--- a/browser/components/loop/test/shared/activeRoomStore_test.js
+++ b/browser/components/loop/test/shared/activeRoomStore_test.js
@@ -990,109 +990,109 @@ describe("loop.store.ActiveRoomStore", f
         enabled: false
       }));
 
       expect(store.getStoreState().videoMuted).eql(true);
     });
   });
 
   describe("#mediaStreamCreated", function() {
-    var fakeVideoElement;
+    var fakeStreamElement;
 
     beforeEach(function() {
-      fakeVideoElement = {name: "fakeVideoElement"};
+      fakeStreamElement = {name: "fakeStreamElement"};
     });
 
     it("should add a local video object to the store", function() {
-      expect(store.getStoreState()).to.not.have.property("localSrcVideoObject");
+      expect(store.getStoreState()).to.not.have.property("localSrcMediaElement");
 
       store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
         hasVideo: false,
         isLocal: true,
-        srcVideoObject: fakeVideoElement
+        srcMediaElement: fakeStreamElement
       }));
 
-      expect(store.getStoreState().localSrcVideoObject).eql(fakeVideoElement);
-      expect(store.getStoreState()).to.not.have.property("remoteSrcVideoObject");
+      expect(store.getStoreState().localSrcMediaElement).eql(fakeStreamElement);
+      expect(store.getStoreState()).to.not.have.property("remoteSrcMediaElement");
     });
 
     it("should set the local video enabled", function() {
       store.setStoreState({
         localVideoEnabled: false,
         remoteVideoEnabled: false
       });
 
       store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
         hasVideo: true,
         isLocal: true,
-        srcVideoObject: fakeVideoElement
+        srcMediaElement: fakeStreamElement
       }));
 
       expect(store.getStoreState().localVideoEnabled).eql(true);
       expect(store.getStoreState().remoteVideoEnabled).eql(false);
     });
 
     it("should add a remote video object to the store", function() {
-      expect(store.getStoreState()).to.not.have.property("remoteSrcVideoObject");
+      expect(store.getStoreState()).to.not.have.property("remoteSrcMediaElement");
 
       store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
         hasVideo: false,
         isLocal: false,
-        srcVideoObject: fakeVideoElement
+        srcMediaElement: fakeStreamElement
       }));
 
-      expect(store.getStoreState()).not.have.property("localSrcVideoObject");
-      expect(store.getStoreState().remoteSrcVideoObject).eql(fakeVideoElement);
+      expect(store.getStoreState()).not.have.property("localSrcMediaElement");
+      expect(store.getStoreState().remoteSrcMediaElement).eql(fakeStreamElement);
     });
 
     it("should set the remote video enabled", function() {
       store.setStoreState({
         localVideoEnabled: false,
         remoteVideoEnabled: false
       });
 
       store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
         hasVideo: true,
         isLocal: false,
-        srcVideoObject: fakeVideoElement
+        srcMediaElement: fakeStreamElement
       }));
 
       expect(store.getStoreState().localVideoEnabled).eql(false);
       expect(store.getStoreState().remoteVideoEnabled).eql(true);
     });
   });
 
   describe("#mediaStreamDestroyed", function() {
-    var fakeVideoElement;
+    var fakeStreamElement;
 
     beforeEach(function() {
-      fakeVideoElement = {name: "fakeVideoElement"};
+      fakeStreamElement = {name: "fakeStreamElement"};
 
       store.setStoreState({
-        localSrcVideoObject: fakeVideoElement,
-        remoteSrcVideoObject: fakeVideoElement
+        localSrcMediaElement: fakeStreamElement,
+        remoteSrcMediaElement: fakeStreamElement
       });
     });
 
     it("should clear the local video object", function() {
       store.mediaStreamDestroyed(new sharedActions.MediaStreamDestroyed({
         isLocal: true
       }));
 
-      expect(store.getStoreState().localSrcVideoObject).eql(null);
-      expect(store.getStoreState().remoteSrcVideoObject).eql(fakeVideoElement);
+      expect(store.getStoreState().localSrcMediaElement).eql(null);
+      expect(store.getStoreState().remoteSrcMediaElement).eql(fakeStreamElement);
     });
 
     it("should clear the remote video object", function() {
       store.mediaStreamDestroyed(new sharedActions.MediaStreamDestroyed({
         isLocal: false
       }));
 
-      expect(store.getStoreState().localSrcVideoObject).eql(fakeVideoElement);
-      expect(store.getStoreState().remoteSrcVideoObject).eql(null);
+      expect(store.getStoreState().localSrcMediaElement).eql(fakeStreamElement);
+      expect(store.getStoreState().remoteSrcMediaElement).eql(null);
     });
   });
 
   describe("#remoteVideoStatus", function() {
     it("should set remoteVideoEnabled to true", function() {
       store.setStoreState({
         remoteVideoEnabled: false
       });
@@ -1161,42 +1161,42 @@ describe("loop.store.ActiveRoomStore", f
     it("should save the state", function() {
       store.receivingScreenShare(new sharedActions.ReceivingScreenShare({
         receiving: true
       }));
 
       expect(store.getStoreState().receivingScreenShare).eql(true);
     });
 
-    it("should add a screenShareVideoObject to the store when sharing is active", function() {
-      var fakeVideoElement = {name: "fakeVideoElement"};
-      expect(store.getStoreState()).to.not.have.property("screenShareVideoObject");
+    it("should add a screenShareMediaElement to the store when sharing is active", function() {
+      var fakeStreamElement = {name: "fakeStreamElement"};
+      expect(store.getStoreState()).to.not.have.property("screenShareMediaElement");
 
       store.receivingScreenShare(new sharedActions.ReceivingScreenShare({
         receiving: true,
-        srcVideoObject: fakeVideoElement
+        srcMediaElement: fakeStreamElement
       }));
 
-      expect(store.getStoreState()).to.have.property("screenShareVideoObject",
-        fakeVideoElement);
+      expect(store.getStoreState()).to.have.property("screenShareMediaElement",
+        fakeStreamElement);
     });
 
-    it("should clear the screenShareVideoObject from the store when sharing is inactive", function() {
+    it("should clear the screenShareMediaElement from the store when sharing is inactive", function() {
       store.setStoreState({
-        screenShareVideoObject: {
-          name: "fakeVideoElement"
+        screenShareMediaElement: {
+          name: "fakeStreamElement"
         }
       });
 
       store.receivingScreenShare(new sharedActions.ReceivingScreenShare({
         receiving: false,
-        srcVideoObject: null
+        srcMediaElement: null
       }));
 
-      expect(store.getStoreState().screenShareVideoObject).eql(null);
+      expect(store.getStoreState().screenShareMediaElement).eql(null);
     });
 
     it("should delete the screen remote video dimensions if screen sharing is not active", function() {
       store.setStoreState({
         remoteVideoDimensions: {
           screen: {fake: 10},
           camera: {fake: 20}
         }
@@ -1351,24 +1351,24 @@ describe("loop.store.ActiveRoomStore", f
         mediaConnected: true
       });
 
       store.remotePeerDisconnected();
 
       expect(store.getStoreState().mediaConnected).eql(false);
     });
 
-    it("should clear the remoteSrcVideoObject", function() {
+    it("should clear the remoteSrcMediaElement", function() {
       store.setStoreState({
-        remoteSrcVideoObject: { name: "fakeVideoElement" }
+        remoteSrcMediaElement: { name: "fakeStreamElement" }
       });
 
       store.remotePeerDisconnected();
 
-      expect(store.getStoreState().remoteSrcVideoObject).eql(null);
+      expect(store.getStoreState().remoteSrcMediaElement).eql(null);
     });
 
     it("should remove non-owner participants", function() {
       store.setStoreState({
         participants: [{owner: true}, {}]
       });
 
       store.remotePeerDisconnected();
--- a/browser/components/loop/test/shared/conversationStore_test.js
+++ b/browser/components/loop/test/shared/conversationStore_test.js
@@ -9,17 +9,17 @@ describe("loop.store.ConversationStore",
   var WS_STATES = loop.store.WS_STATES;
   var CALL_TYPES = loop.shared.utils.CALL_TYPES;
   var WEBSOCKET_REASONS = loop.shared.utils.WEBSOCKET_REASONS;
   var REST_ERRNOS = loop.shared.utils.REST_ERRNOS;
   var FAILURE_DETAILS = loop.shared.utils.FAILURE_DETAILS;
   var sharedActions = loop.shared.actions;
   var sharedUtils = loop.shared.utils;
   var sandbox, dispatcher, client, store, fakeSessionData, sdkDriver;
-  var contact, fakeMozLoop, fakeVideoElement;
+  var contact, fakeMozLoop, fakeStreamElement;
   var connectPromise, resolveConnectPromise, rejectConnectPromise;
   var wsCancelSpy, wsCloseSpy, wsDeclineSpy, wsMediaUpSpy, fakeWebsocket;
 
   function checkFailures(done, f) {
     try {
       f();
       done();
     } catch (err) {
@@ -90,17 +90,17 @@ describe("loop.store.ConversationStore",
       callId: "142536",
       sessionId: "321456",
       sessionToken: "341256",
       websocketToken: "543216",
       windowId: "28",
       progressURL: "fakeURL"
     };
 
-    fakeVideoElement = { id: "fakeVideoElement" };
+    fakeStreamElement = { id: "fakeStreamElement" };
 
     var dummySocket = {
       close: sinon.spy(),
       send: sinon.spy()
     };
 
     connectPromise = new Promise(function(resolve, reject) {
       resolveConnectPromise = resolve;
@@ -952,98 +952,98 @@ describe("loop.store.ConversationStore",
       store.mediaConnected(new sharedActions.MediaConnected());
 
       expect(store.getStoreState("mediaConnected")).eql(true);
     });
   });
 
   describe("#mediaStreamCreated", function() {
     it("should add a local video object to the store", function() {
-      expect(store.getStoreState()).to.not.have.property("localSrcVideoObject");
+      expect(store.getStoreState()).to.not.have.property("localSrcMediaElement");
 
       store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
         hasVideo: false,
         isLocal: true,
-        srcVideoObject: fakeVideoElement
+        srcMediaElement: fakeStreamElement
       }));
 
-      expect(store.getStoreState().localSrcVideoObject).eql(fakeVideoElement);
-      expect(store.getStoreState()).to.not.have.property("remoteSrcVideoObject");
+      expect(store.getStoreState().localSrcMediaElement).eql(fakeStreamElement);
+      expect(store.getStoreState()).to.not.have.property("remoteSrcMediaElement");
     });
 
     it("should set the local video enabled", function() {
       store.setStoreState({
         localVideoEnabled: false,
         remoteVideoEnabled: false
       });
 
       store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
         hasVideo: true,
         isLocal: true,
-        srcVideoObject: fakeVideoElement
+        srcMediaElement: fakeStreamElement
       }));
 
       expect(store.getStoreState().localVideoEnabled).eql(true);
       expect(store.getStoreState().remoteVideoEnabled).eql(false);
     });
 
     it("should add a remote video object to the store", function() {
-      expect(store.getStoreState()).to.not.have.property("remoteSrcVideoObject");
+      expect(store.getStoreState()).to.not.have.property("remoteSrcMediaElement");
 
       store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
         hasVideo: false,
         isLocal: false,
-        srcVideoObject: fakeVideoElement
+        srcMediaElement: fakeStreamElement
       }));
 
-      expect(store.getStoreState()).not.have.property("localSrcVideoObject");
-      expect(store.getStoreState().remoteSrcVideoObject).eql(fakeVideoElement);
+      expect(store.getStoreState()).not.have.property("localSrcMediaElement");
+      expect(store.getStoreState().remoteSrcMediaElement).eql(fakeStreamElement);
     });
 
     it("should set the remote video enabled", function() {
       store.setStoreState({
         localVideoEnabled: false,
         remoteVideoEnabled: false
       });
 
       store.mediaStreamCreated(new sharedActions.MediaStreamCreated({
         hasVideo: true,
         isLocal: false,
-        srcVideoObject: fakeVideoElement
+        srcMediaElement: fakeStreamElement
       }));
 
       expect(store.getStoreState().localVideoEnabled).eql(false);
       expect(store.getStoreState().remoteVideoEnabled).eql(true);
     });
   });
 
   describe("#mediaStreamDestroyed", function() {
     beforeEach(function() {
       store.setStoreState({
-        localSrcVideoObject: fakeVideoElement,
-        remoteSrcVideoObject: fakeVideoElement
+        localSrcMediaElement: fakeStreamElement,
+        remoteSrcMediaElement: fakeStreamElement
       });
     });
 
     it("should clear the local video object", function() {
       store.mediaStreamDestroyed(new sharedActions.MediaStreamDestroyed({
         isLocal: true
       }));
 
-      expect(store.getStoreState().localSrcVideoObject).eql(null);
-      expect(store.getStoreState().remoteSrcVideoObject).eql(fakeVideoElement);
+      expect(store.getStoreState().localSrcMediaElement).eql(null);
+      expect(store.getStoreState().remoteSrcMediaElement).eql(fakeStreamElement);
     });
 
     it("should clear the remote video object", function() {
       store.mediaStreamDestroyed(new sharedActions.MediaStreamDestroyed({
         isLocal: false
       }));
 
-      expect(store.getStoreState().localSrcVideoObject).eql(fakeVideoElement);
-      expect(store.getStoreState().remoteSrcVideoObject).eql(null);
+      expect(store.getStoreState().localSrcMediaElement).eql(fakeStreamElement);
+      expect(store.getStoreState().remoteSrcMediaElement).eql(null);
     });
   });
 
   describe("#remoteVideoStatus", function() {
     it("should set remoteVideoEnabled to true", function() {
       store.setStoreState({
         remoteVideoEnabled: false
       });
--- a/browser/components/loop/test/shared/otSdkDriver_test.js
+++ b/browser/components/loop/test/shared/otSdkDriver_test.js
@@ -896,30 +896,30 @@ describe("loop.OTSdkDriver", function ()
       it("should dispatch a MediaStreamCreated action", function() {
         publisher.trigger("streamCreated", { stream: stream });
 
         sinon.assert.called(dispatcher.dispatch);
         sinon.assert.calledWithExactly(dispatcher.dispatch,
           new sharedActions.MediaStreamCreated({
             hasVideo: true,
             isLocal: true,
-            srcVideoObject: fakeMockVideo
+            srcMediaElement: fakeMockVideo
           }));
       });
 
       it("should dispatch a MediaStreamCreated action with hasVideo false for audio-only streams", function() {
         stream.hasVideo = false;
         publisher.trigger("streamCreated", { stream: stream });
 
         sinon.assert.called(dispatcher.dispatch);
         sinon.assert.calledWithExactly(dispatcher.dispatch,
           new sharedActions.MediaStreamCreated({
             hasVideo: false,
             isLocal: true,
-            srcVideoObject: fakeMockVideo
+            srcMediaElement: fakeMockVideo
           }));
       });
 
       it("should dispatch a ConnectionStatus action", function() {
         driver._metrics.recvStreams = 1;
         driver._metrics.connections = 2;
 
         publisher.trigger("streamCreated", {stream: stream});
@@ -984,34 +984,34 @@ describe("loop.OTSdkDriver", function ()
 
         session.trigger("streamCreated", { stream: fakeStream });
 
         sinon.assert.called(dispatcher.dispatch);
         sinon.assert.calledWithExactly(dispatcher.dispatch,
           new sharedActions.MediaStreamCreated({
             hasVideo: true,
             isLocal: false,
-            srcVideoObject: videoElement
+            srcMediaElement: videoElement
           }));
       });
 
       it("should dispatch MediaStreamCreated after subscribe with audio-only indication if hasVideo=false", function() {
         session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
           videoElement);
         fakeStream.connection = fakeConnection;
         fakeStream.hasVideo = false;
 
         session.trigger("streamCreated", { stream: fakeStream });
 
         sinon.assert.called(dispatcher.dispatch);
         sinon.assert.calledWithExactly(dispatcher.dispatch,
           new sharedActions.MediaStreamCreated({
             hasVideo: false,
             isLocal: false,
-            srcVideoObject: videoElement
+            srcMediaElement: videoElement
           }));
       });
 
       it("should trigger a readyForDataChannel signal after subscribe is complete", function() {
         session.subscribe.yieldsOn(driver, null, fakeSubscriberObject,
           document.createElement("video"));
         driver._useDataChannels = true;
         fakeStream.connection = fakeConnection;
--- a/browser/components/loop/test/shared/views_test.js
+++ b/browser/components/loop/test/shared/views_test.js
@@ -1241,17 +1241,17 @@ describe("loop.shared.views", function()
     });
 
     it("should display a video element if a source object is supplied", function() {
       view = mountTestComponent({
         displayAvatar: false,
         mediaType: "local",
         // This doesn't actually get assigned to the video element, but is enough
         // for this test to check display of the video element.
-        srcVideoObject: {
+        srcMediaElement: {
           fake: 1
         }
       });
 
       var element = view.getDOMNode();
 
       expect(element).not.eql(null);
       expect(element.className).eql("local-video");
@@ -1267,17 +1267,17 @@ describe("loop.shared.views", function()
         fakeViewElement = {
           play: sinon.stub(),
           tagName: "VIDEO"
         };
 
         view = mountTestComponent({
           displayAvatar: false,
           mediaType: "local",
-          srcVideoObject: {
+          srcMediaElement: {
             fake: 1
           }
         });
       });
 
       it("should not throw if no source object is specified", function() {
         expect(function() {
           view.attachVideo(null);
@@ -1399,67 +1399,67 @@ describe("loop.shared.views", function()
       });
 
       expect(view.getDOMNode().querySelector(".media-wrapper")
         .classList.contains("receiving-screen-share")).eql(true);
     });
 
     it("should not mark the wrapper as showing local streams when not displaying a stream", function() {
       view = mountTestComponent({
-        localSrcVideoObject: null,
+        localSrcMediaElement: null,
         localPosterUrl: null
       });
 
       expect(view.getDOMNode().querySelector(".media-wrapper")
         .classList.contains("showing-local-streams")).eql(false);
     });
 
     it("should mark the wrapper as showing local streams when displaying a stream", function() {
       view = mountTestComponent({
-        localSrcVideoObject: {},
+        localSrcMediaElement: {},
         localPosterUrl: null
       });
 
       expect(view.getDOMNode().querySelector(".media-wrapper")
         .classList.contains("showing-local-streams")).eql(true);
     });
 
     it("should mark the wrapper as showing local streams when displaying a poster url", function() {
       view = mountTestComponent({
-        localSrcVideoObject: {},
+        localSrcMediaElement: {},
         localPosterUrl: "fake/url"
       });
 
       expect(view.getDOMNode().querySelector(".media-wrapper")
         .classList.contains("showing-local-streams")).eql(true);
     });
 
     it("should not mark the wrapper as showing remote streams when not displaying a stream", function() {
       view = mountTestComponent({
-        remoteSrcVideoObject: null,
+        remoteSrcMediaElement: null,
         remotePosterUrl: null
       });
 
       expect(view.getDOMNode().querySelector(".media-wrapper")
         .classList.contains("showing-remote-streams")).eql(false);
     });
 
     it("should mark the wrapper as showing remote streams when displaying a stream", function() {
       view = mountTestComponent({
-        remoteSrcVideoObject: {},
+        remoteSrcMediaElement: {},
         remotePosterUrl: null
       });
 
       expect(view.getDOMNode().querySelector(".media-wrapper")
         .classList.contains("showing-remote-streams")).eql(true);
     });
 
     it("should mark the wrapper as showing remote streams when displaying a poster url", function() {
       view = mountTestComponent({
-        remoteSrcVideoObject: {},
+        remoteSrcMediaElement: {},
         remotePosterUrl: "fake/url"
       });
 
       expect(view.getDOMNode().querySelector(".media-wrapper")
         .classList.contains("showing-remote-streams")).eql(true);
     });
   });
 });
--- a/browser/components/loop/test/standalone/standaloneRoomViews_test.js
+++ b/browser/components/loop/test/standalone/standaloneRoomViews_test.js
@@ -481,44 +481,44 @@ describe("loop.standaloneRoomViews", fun
 
           sinon.assert.calledOnce(dispatch);
           sinon.assert.calledWithExactly(dispatch, new sharedActions.JoinRoom());
         });
       });
 
       describe("screenShare", function() {
         it("should show a loading screen if receivingScreenShare is true " +
-           "but no screenShareVideoObject is present", function() {
+           "but no screenShareMediaElement is present", function() {
           view.setState({
             "receivingScreenShare": true,
-            "screenShareVideoObject": null
+            "screenShareMediaElement": null
           });
 
           expect(view.getDOMNode().querySelector(".screen .loading-stream"))
               .not.eql(null);
         });
 
         it("should not show loading screen if receivingScreenShare is false " +
-           "and screenShareVideoObject is null", function() {
+           "and screenShareMediaElement is null", function() {
              view.setState({
                "receivingScreenShare": false,
-               "screenShareVideoObject": null
+               "screenShareMediaElement": null
              });
 
              expect(view.getDOMNode().querySelector(".screen .loading-stream"))
                  .eql(null);
         });
 
-        it("should not show a loading screen if screenShareVideoObject is set",
+        it("should not show a loading screen if screenShareMediaElement is set",
            function() {
              var videoElement = document.createElement("video");
 
              view.setState({
                "receivingScreenShare": true,
-               "screenShareVideoObject": videoElement
+               "screenShareMediaElement": videoElement
              });
 
              expect(view.getDOMNode().querySelector(".screen .loading-stream"))
                  .eql(null);
         });
       });
 
       describe("Participants", function() {
@@ -526,149 +526,149 @@ describe("loop.standaloneRoomViews", fun
 
         beforeEach(function() {
           videoElement = document.createElement("video");
         });
 
         it("should render local video when video_muted is false", function() {
           activeRoomStore.setStoreState({
             roomState: ROOM_STATES.HAS_PARTICIPANTS,
-            localSrcVideoObject: videoElement,
+            localSrcMediaElement: videoElement,
             videoMuted: false
           });
 
           expect(view.getDOMNode().querySelector(".local video")).not.eql(null);
         });
 
         it("should not render a local avatar when video_muted is false", function() {
           activeRoomStore.setStoreState({
             roomState: ROOM_STATES.HAS_PARTICIPANTS,
             videoMuted: false
           });
 
           expect(view.getDOMNode().querySelector(".local .avatar")).eql(null);
         });
 
-        it("should render local loading screen when no srcVideoObject",
+        it("should render local loading screen when no srcMediaElement",
            function() {
              activeRoomStore.setStoreState({
                roomState: ROOM_STATES.MEDIA_WAIT,
-               remoteSrcVideoObject: null
+               remoteSrcMediaElement: null
              });
 
              expect(view.getDOMNode().querySelector(".local .loading-stream"))
                  .not.eql(null);
         });
 
-        it("should not render local loading screen when srcVideoObject is set",
+        it("should not render local loading screen when srcMediaElement is set",
            function() {
              activeRoomStore.setStoreState({
                roomState: ROOM_STATES.MEDIA_WAIT,
-               localSrcVideoObject: videoElement
+               localSrcMediaElement: videoElement
              });
 
              expect(view.getDOMNode().querySelector(".local .loading-stream"))
                   .eql(null);
         });
 
-        it("should not render remote loading screen when srcVideoObject is set",
+        it("should not render remote loading screen when srcMediaElement is set",
            function() {
              activeRoomStore.setStoreState({
                roomState: ROOM_STATES.HAS_PARTICIPANTS,
-               remoteSrcVideoObject: videoElement
+               remoteSrcMediaElement: videoElement
              });
 
              expect(view.getDOMNode().querySelector(".remote .loading-stream"))
                   .eql(null);
         });
 
         it("should render remote video when the room HAS_PARTICIPANTS and" +
           " remoteVideoEnabled is true", function() {
           activeRoomStore.setStoreState({
             roomState: ROOM_STATES.HAS_PARTICIPANTS,
-            remoteSrcVideoObject: videoElement,
+            remoteSrcMediaElement: videoElement,
             remoteVideoEnabled: true
           });
 
           expect(view.getDOMNode().querySelector(".remote video")).not.eql(null);
         });
 
         it("should render remote video when the room HAS_PARTICIPANTS and" +
           " remoteVideoEnabled is true", function() {
           activeRoomStore.setStoreState({
             roomState: ROOM_STATES.HAS_PARTICIPANTS,
-            remoteSrcVideoObject: videoElement,
+            remoteSrcMediaElement: videoElement,
             remoteVideoEnabled: true
           });
 
           expect(view.getDOMNode().querySelector(".remote video")).not.eql(null);
         });
 
         it("should not render remote video when the room HAS_PARTICIPANTS," +
           " remoteVideoEnabled is false, and mediaConnected is true", function() {
           activeRoomStore.setStoreState({
             roomState: ROOM_STATES.HAS_PARTICIPANTS,
-            remoteSrcVideoObject: videoElement,
+            remoteSrcMediaElement: videoElement,
             mediaConnected: true,
             remoteVideoEnabled: false
           });
 
           expect(view.getDOMNode().querySelector(".remote video")).eql(null);
         });
 
         it("should render remote video when the room HAS_PARTICIPANTS," +
           " and both remoteVideoEnabled and mediaConnected are false", function() {
           activeRoomStore.setStoreState({
             roomState: ROOM_STATES.HAS_PARTICIPANTS,
-            remoteSrcVideoObject: videoElement,
+            remoteSrcMediaElement: videoElement,
             mediaConnected: false,
             remoteVideoEnabled: false
           });
 
           expect(view.getDOMNode().querySelector(".remote video")).not.eql(null);
         });
 
         it("should not render a remote avatar when the room is in MEDIA_WAIT", function() {
           activeRoomStore.setStoreState({
             roomState: ROOM_STATES.MEDIA_WAIT,
-            remoteSrcVideoObject: videoElement,
+            remoteSrcMediaElement: videoElement,
             remoteVideoEnabled: false
           });
 
           expect(view.getDOMNode().querySelector(".remote .avatar")).eql(null);
         });
 
         it("should not render a remote avatar when the room is CLOSING and" +
           " remoteVideoEnabled is false", function() {
           activeRoomStore.setStoreState({
             roomState: ROOM_STATES.CLOSING,
-            remoteSrcVideoObject: videoElement,
+            remoteSrcMediaElement: videoElement,
             remoteVideoEnabled: false
           });
 
           expect(view.getDOMNode().querySelector(".remote .avatar")).eql(null);
         });
 
         it("should render a remote avatar when the room HAS_PARTICIPANTS, " +
           "remoteVideoEnabled is false, and mediaConnected is true", function() {
           activeRoomStore.setStoreState({
             roomState: ROOM_STATES.HAS_PARTICIPANTS,
-            remoteSrcVideoObject: videoElement,
+            remoteSrcMediaElement: videoElement,
             remoteVideoEnabled: false,
             mediaConnected: true
           });
 
           expect(view.getDOMNode().querySelector(".remote .avatar")).not.eql(null);
         });
 
         it("should render a remote avatar when the room HAS_PARTICIPANTS, " +
-          "remoteSrcVideoObject is false, mediaConnected is true", function() {
+          "remoteSrcMediaElement is false, mediaConnected is true", function() {
           activeRoomStore.setStoreState({
             roomState: ROOM_STATES.HAS_PARTICIPANTS,
-            remoteSrcVideoObject: null,
+            remoteSrcMediaElement: null,
             remoteVideoEnabled: false,
             mediaConnected: true
           });
 
           expect(view.getDOMNode().querySelector(".remote .avatar")).not.eql(null);
         });
       });
 
--- a/browser/components/loop/ui/ui-showcase.js
+++ b/browser/components/loop/ui/ui-showcase.js
@@ -200,17 +200,17 @@
     mediaConnected: false,
     roomState: ROOM_STATES.JOINED,
     remoteVideoEnabled: false
   });
 
   var loadingRemoteVideoRoomStore = makeActiveRoomStore({
     mediaConnected: false,
     roomState: ROOM_STATES.HAS_PARTICIPANTS,
-    remoteSrcVideoObject: false
+    remoteSrcMediaElement: false
   });
 
   var readyRoomStore = makeActiveRoomStore({
     mediaConnected: false,
     roomState: ROOM_STATES.READY
   });
 
   var updatingActiveRoomStore = makeActiveRoomStore({
@@ -241,31 +241,31 @@
     roomState: ROOM_STATES.HAS_PARTICIPANTS,
     receivingScreenShare: true
   });
 
   var loadingRemoteLoadingScreenStore = makeActiveRoomStore({
     mediaConnected: false,
     receivingScreenShare: true,
     roomState: ROOM_STATES.HAS_PARTICIPANTS,
-    remoteSrcVideoObject: false
+    remoteSrcMediaElement: false
   });
   var loadingScreenSharingRoomStore = makeActiveRoomStore({
     receivingScreenShare: true,
     roomState: ROOM_STATES.HAS_PARTICIPANTS
   });
 
   /* Set up the stores for pending screen sharing */
   loadingScreenSharingRoomStore.receivingScreenShare({
     receiving: true,
-    srcVideoObject: false
+    srcMediaElement: false
   });
   loadingRemoteLoadingScreenStore.receivingScreenShare({
     receiving: true,
-    srcVideoObject: false
+    srcMediaElement: false
   });
 
   var fullActiveRoomStore = makeActiveRoomStore({
     roomState: ROOM_STATES.FULL
   });
 
   var failedRoomStore = makeActiveRoomStore({
     roomState: ROOM_STATES.FAILED
@@ -290,17 +290,17 @@
     })
   });
 
   var desktopRoomStoreLoading = new loop.store.RoomStore(dispatcher, {
     mozLoop: navigator.mozLoop,
     activeRoomStore: makeActiveRoomStore({
       roomState: ROOM_STATES.HAS_PARTICIPANTS,
       mediaConnected: false,
-      remoteSrcVideoObject: false
+      remoteSrcMediaElement: false
     })
   });
 
   var desktopRoomStoreMedium = new loop.store.RoomStore(dispatcher, {
     mozLoop: navigator.mozLoop,
     activeRoomStore: makeActiveRoomStore({
       roomState: ROOM_STATES.HAS_PARTICIPANTS
     })
--- a/browser/components/loop/ui/ui-showcase.jsx
+++ b/browser/components/loop/ui/ui-showcase.jsx
@@ -200,17 +200,17 @@
     mediaConnected: false,
     roomState: ROOM_STATES.JOINED,
     remoteVideoEnabled: false
   });
 
   var loadingRemoteVideoRoomStore = makeActiveRoomStore({
     mediaConnected: false,
     roomState: ROOM_STATES.HAS_PARTICIPANTS,
-    remoteSrcVideoObject: false
+    remoteSrcMediaElement: false
   });
 
   var readyRoomStore = makeActiveRoomStore({
     mediaConnected: false,
     roomState: ROOM_STATES.READY
   });
 
   var updatingActiveRoomStore = makeActiveRoomStore({
@@ -241,31 +241,31 @@
     roomState: ROOM_STATES.HAS_PARTICIPANTS,
     receivingScreenShare: true
   });
 
   var loadingRemoteLoadingScreenStore = makeActiveRoomStore({
     mediaConnected: false,
     receivingScreenShare: true,
     roomState: ROOM_STATES.HAS_PARTICIPANTS,
-    remoteSrcVideoObject: false
+    remoteSrcMediaElement: false
   });
   var loadingScreenSharingRoomStore = makeActiveRoomStore({
     receivingScreenShare: true,
     roomState: ROOM_STATES.HAS_PARTICIPANTS
   });
 
   /* Set up the stores for pending screen sharing */
   loadingScreenSharingRoomStore.receivingScreenShare({
     receiving: true,
-    srcVideoObject: false
+    srcMediaElement: false
   });
   loadingRemoteLoadingScreenStore.receivingScreenShare({
     receiving: true,
-    srcVideoObject: false
+    srcMediaElement: false
   });
 
   var fullActiveRoomStore = makeActiveRoomStore({
     roomState: ROOM_STATES.FULL
   });
 
   var failedRoomStore = makeActiveRoomStore({
     roomState: ROOM_STATES.FAILED
@@ -290,17 +290,17 @@
     })
   });
 
   var desktopRoomStoreLoading = new loop.store.RoomStore(dispatcher, {
     mozLoop: navigator.mozLoop,
     activeRoomStore: makeActiveRoomStore({
       roomState: ROOM_STATES.HAS_PARTICIPANTS,
       mediaConnected: false,
-      remoteSrcVideoObject: false
+      remoteSrcMediaElement: false
     })
   });
 
   var desktopRoomStoreMedium = new loop.store.RoomStore(dispatcher, {
     mozLoop: navigator.mozLoop,
     activeRoomStore: makeActiveRoomStore({
       roomState: ROOM_STATES.HAS_PARTICIPANTS
     })
--- a/mobile/android/base/GeckoApp.java
+++ b/mobile/android/base/GeckoApp.java
@@ -2109,17 +2109,17 @@ public abstract class GeckoApp
 
         final HealthRecorder rec = mHealthRecorder;
         mHealthRecorder = null;
         if (rec != null && rec.isEnabled()) {
             // Closing a BrowserHealthRecorder could incur a write.
             ThreadUtils.postToBackgroundThread(new Runnable() {
                 @Override
                 public void run() {
-                    rec.close();
+                    rec.close(GeckoApp.this);
                 }
             });
         }
 
         Favicons.close();
 
         super.onDestroy();
 
--- a/mobile/android/base/background/healthreport/ProfileInformationCache.java
+++ b/mobile/android/base/background/healthreport/ProfileInformationCache.java
@@ -29,18 +29,19 @@ public class ProfileInformationCache imp
   private static final String CACHE_FILE = "profile_info_cache.json";
 
   /*
    * FORMAT_VERSION history:
    *   -: No version number; implicit v1.
    *   1: Add versioning (Bug 878670).
    *   2: Bump to regenerate add-on set after landing Bug 900694 (Bug 901622).
    *   3: Add distribution, osLocale, appLocale.
+   *   4: Add experiments as add-ons.
    */
-  public static final int FORMAT_VERSION = 3;
+  public static final int FORMAT_VERSION = 4;
 
   protected boolean initialized = false;
   protected boolean needsWrite = false;
 
   protected final File file;
 
   private volatile boolean blocklistEnabled = true;
   private volatile boolean telemetryEnabled = false;
--- a/mobile/android/base/health/BrowserHealthRecorder.java
+++ b/mobile/android/base/health/BrowserHealthRecorder.java
@@ -3,16 +3,17 @@
  * 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/. */
 
 package org.mozilla.gecko.health;
 
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.OutputStreamWriter;
+import java.lang.String;
 import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
 import java.util.Iterator;
 import java.util.List;
 import java.util.Scanner;
@@ -33,19 +34,25 @@ import org.mozilla.gecko.background.heal
 import org.mozilla.gecko.background.healthreport.HealthReportStorage.Field;
 import org.mozilla.gecko.background.healthreport.HealthReportStorage.MeasurementFields;
 import org.mozilla.gecko.background.healthreport.ProfileInformationCache;
 import org.mozilla.gecko.distribution.Distribution;
 import org.mozilla.gecko.distribution.Distribution.DistributionDescriptor;
 import org.mozilla.gecko.util.GeckoEventListener;
 import org.mozilla.gecko.util.ThreadUtils;
 
+import com.keepsafe.switchboard.SwitchBoard;
+
+import android.content.BroadcastReceiver;
 import android.content.ContentProviderClient;
 import android.content.Context;
+import android.content.Intent;
+import android.content.IntentFilter;
 import android.content.SharedPreferences;
+import android.support.v4.content.LocalBroadcastManager;
 import android.util.Log;
 
 /**
  * BrowserHealthRecorder is the browser's interface to the Firefox Health
  * Report storage system. It manages environments (a collection of attributes
  * that are tracked longitudinally) on the browser's behalf, exposing a simpler
  * interface for recording changes.
  *
@@ -54,17 +61,17 @@ import android.util.Log;
  * Tell it when an environment attribute has changed: call {@link
  * #onAppLocaleChanged(String)} followed by {@link
  * #onEnvironmentChanged()}.
  *
  * Use it to record events: {@link #recordSearch(String, String)}.
  *
  * Shut it down when you're done being a browser: {@link #close()}.
  */
-public class BrowserHealthRecorder implements HealthRecorder, GeckoEventListener {
+public class BrowserHealthRecorder extends BroadcastReceiver implements HealthRecorder, GeckoEventListener {
     private static final String LOG_TAG = "GeckoHealthRec";
     private static final String PREF_ACCEPT_LANG = "intl.accept_languages";
     private static final String PREF_BLOCKLIST_ENABLED = "extensions.blocklist.enabled";
     private static final String EVENT_SNAPSHOT = "HealthReport:Snapshot";
     private static final String EVENT_ADDONS_CHANGE = "Addons:Change";
     private static final String EVENT_ADDONS_UNINSTALLING = "Addons:Uninstalling";
     private static final String EVENT_PREF_CHANGE = "Pref:Change";
 
@@ -172,30 +179,33 @@ public class BrowserHealthRecorder imple
         return true;
     }
 
     /**
      * Shut down database connections, unregister event listeners, and perform
      * provider-specific uninitialization.
      */
     @Override
-    public synchronized void close() {
+    public synchronized void close(final Context context) {
         switch (this.state) {
             case CLOSED:
                 Log.w(LOG_TAG, "Ignoring attempt to double-close closed BrowserHealthRecorder.");
                 return;
             case INITIALIZED:
                 Log.i(LOG_TAG, "Closing Health Report client.");
                 break;
             default:
                 Log.i(LOG_TAG, "Closing incompletely initialized BrowserHealthRecorder.");
         }
 
         this.state = State.CLOSED;
         this.unregisterEventListeners();
+        if (AppConstants.MOZ_SWITCHBOARD) {
+            LocalBroadcastManager.getInstance(context).unregisterReceiver(this);
+        }
 
         // Add any necessary provider uninitialization here.
         this.storage = null;
         if (this.client != null) {
             this.client.release();
             this.client = null;
         }
     }
@@ -518,16 +528,22 @@ public class BrowserHealthRecorder imple
         Log.d(LOG_TAG, "Initializing profile cache.");
         this.state = State.INITIALIZING;
 
         // If we can restore state from last time, great.
         if (this.profileCache.restoreUnlessInitialized()) {
             this.profileCache.updateLocales(osLocale, appLocale);
             this.profileCache.completeInitialization();
 
+            // Listen for experiment changes.
+            if (AppConstants.MOZ_SWITCHBOARD) {
+                IntentFilter intentFilter = new IntentFilter(SwitchBoard.ACTION_CONFIG_FETCHED);
+                LocalBroadcastManager.getInstance(context).registerReceiver(this, intentFilter);
+            }
+
             Log.d(LOG_TAG, "Successfully restored state. Initializing storage.");
             initializeStorage();
             return;
         }
 
         // Otherwise, let's initialize it from scratch.
         this.profileCache.beginInitialization();
         this.profileCache.setProfileCreationTime(getAndPersistProfileInitTime(context, profilePath));
@@ -621,16 +637,33 @@ public class BrowserHealthRecorder imple
     @Override
     public void handleMessage(String event, JSONObject message) {
         try {
             if (EVENT_SNAPSHOT.equals(event)) {
                 Log.d(LOG_TAG, "Got all add-ons and prefs.");
                 try {
                     JSONObject json = message.getJSONObject("json");
                     JSONObject addons = json.getJSONObject("addons");
+
+                    // Treat active experiments as add-ons
+                    if (AppConstants.MOZ_SWITCHBOARD) {
+                        List<String> experiments = SwitchBoard.getActiveExperiments(GeckoAppShell.getContext());
+                        for (String experiment : experiments) {
+                            // Create a fake add-on name
+                            String fakeName = experiment + "@experiments.mozilla.org";
+                            try {
+                                // Create a dummy JSON object for the experiment.
+                                JSONObject fakeAddon = new JSONObject();
+                                fakeAddon.put("type", "experiment");
+                                addons.put(fakeName, fakeAddon);
+                            } catch (JSONException je) {
+                            }
+                        }
+                    }
+
                     Log.i(LOG_TAG, "Persisting " + addons.length() + " add-ons.");
                     profileCache.setJSONForAddons(addons);
 
                     JSONObject prefs = json.getJSONObject("prefs");
                     Log.i(LOG_TAG, "Persisting prefs.");
                     Iterator<?> keys = prefs.keys();
                     while (keys.hasNext()) {
                         String pref = (String) keys.next();
@@ -689,16 +722,81 @@ public class BrowserHealthRecorder imple
                 recordSearch(message.optString("identifier", null), message.getString("location"));
                 return;
             }
         } catch (Exception e) {
             Log.e(LOG_TAG, "Exception handling message \"" + event + "\":", e);
         }
     }
 
+    @Override
+    public void onReceive(Context context, Intent intent) {
+        String action = intent.getAction();
+        switch (action) {
+            case SwitchBoard.ACTION_CONFIG_FETCHED:
+                Log.d(LOG_TAG, "Handle the new experiments.");
+                // Get the list of active experiments.
+                List<String> experiments = SwitchBoard.getActiveExperiments(context);
+
+                // We need to figure out which ones are new and which ones were removed. Convert
+                // the active experiments to the fake add-on names for easier lookup.
+                ArrayList<String> addToProfile = new ArrayList<String>();
+                for (String experiment : experiments) {
+                    addToProfile.add(experiment + "@experiments.mozilla.org");
+                }
+
+                // Create a list of add-ons(experiments) we need to remove.
+                ArrayList<String> removeFromProfile = new ArrayList<String>();
+
+                // Loop over the current profile set of add-ons, and figure out
+                // which add-ons (experiments) are new and which need to be removed.
+                JSONObject addons = this.profileCache.getAddonsJSON();
+                Iterator<?> keys = addons.keys();
+                while (keys.hasNext()) {
+                    String addon = (String) keys.next();
+                    if (addon.endsWith("@experiments.mozilla.org")) {
+                        if (addToProfile.contains(addon)) {
+                            // This experiment is already in the profile. We don't need to add it again.
+                            addToProfile.remove(addon);
+                        } else {
+                            // The active set of experiments does not include this fake add-on.
+                            removeFromProfile.add(addon);
+                        }
+                    }
+                }
+
+                // If we don't have any changes, exit early.
+                if (addToProfile.isEmpty() && removeFromProfile.isEmpty()) {
+                    return;
+                }
+
+                // Add the newly active experiments into the profile.
+                for (String fakeName : addToProfile) {
+                    try {
+                        // Create a dummy JSON object for the experiment.
+                        JSONObject fakeAddon = new JSONObject();
+                        fakeAddon.put("type", "experiment");
+                        this.onAddonChanged(fakeName, fakeAddon);
+                        Log.d(LOG_TAG, "Add this experiment: " + fakeName);
+                    } catch (JSONException je) {
+                    }
+                }
+
+                // Remove experiments that are no longer active from the profile.
+                for (String fakeName : removeFromProfile) {
+                    this.onAddonUninstalling(fakeName);
+                    Log.d(LOG_TAG, "Remove this experiment: " + fakeName);
+                }
+
+                // Something changed, so update the environment.
+                this.onEnvironmentChanged();
+                break;
+        }
+    }
+
     /*
      * Searches.
      */
 
     public static final String MEASUREMENT_NAME_SEARCH_COUNTS = "org.mozilla.searches.counts";
     public static final int MEASUREMENT_VERSION_SEARCH_COUNTS = 6;
 
     public static final Set<String> SEARCH_LOCATIONS = Collections.unmodifiableSet(new HashSet<String>(Arrays.asList(new String[] {
--- a/mobile/android/base/health/HealthRecorder.java
+++ b/mobile/android/base/health/HealthRecorder.java
@@ -1,15 +1,16 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko.health;
 
+import android.content.Context;
 import android.content.SharedPreferences;
 
 import org.json.JSONObject;
 
 /**
  * HealthRecorder is an interface into the Firefox Health Report storage system.
  */
 public interface HealthRecorder {
@@ -28,12 +29,12 @@ public interface HealthRecorder {
     public void recordSessionEnd(String reason, SharedPreferences.Editor editor, final int environment);
 
     public void onAppLocaleChanged(String to);
     public void onAddonChanged(String id, JSONObject json);
     public void onAddonUninstalling(String id);
     public void onEnvironmentChanged();
     public void onEnvironmentChanged(final boolean startNewSession, final String sessionEndReason);
 
-    public void close();
+    public void close(final Context context);
 
     public void processDelayed();
 }
--- a/mobile/android/base/health/StubbedHealthRecorder.java
+++ b/mobile/android/base/health/StubbedHealthRecorder.java
@@ -1,15 +1,16 @@
 /* -*- Mode: Java; c-basic-offset: 4; tab-width: 20; indent-tabs-mode: nil; -*-
  * 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/. */
 
 package org.mozilla.gecko.health;
 
+import android.content.Context;
 import android.content.SharedPreferences;
 
 import org.json.JSONObject;
 
 /**
  * StubbedHealthRecorder is an implementation of HealthRecorder that does (you guessed it!)
  * nothing.
  */
@@ -40,13 +41,13 @@ public class StubbedHealthRecorder imple
     @Override
     public void onAddonUninstalling(String id) { }
     @Override
     public void onEnvironmentChanged() { }
     @Override
     public void onEnvironmentChanged(final boolean startNewSession, final String sessionEndReason) { }
 
     @Override
-    public void close() { }
+    public void close(final Context context) { }
 
     @Override
     public void processDelayed() { }
 }
--- a/mobile/android/thirdparty/com/keepsafe/switchboard/SwitchBoard.java
+++ b/mobile/android/thirdparty/com/keepsafe/switchboard/SwitchBoard.java
@@ -17,30 +17,34 @@ package com.keepsafe.switchboard;
 
 import java.io.BufferedReader;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.net.HttpURLConnection;
 import java.net.ProtocolException;
 import java.net.URL;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Locale;
 import java.util.MissingResourceException;
 import java.util.UUID;
 import java.util.zip.CRC32;
 
 import org.json.JSONException;
 import org.json.JSONObject;
 
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.os.Build;
+import android.support.v4.content.LocalBroadcastManager;
 import android.util.Log;
 
-
 /**
  * SwitchBoard is the core class of the KeepSafe Switchboard mobile A/B testing framework.
  * This class provides a bunch of static methods that can be used in your app to run A/B tests. 
  * 
  * The SwitchBoard supports production and staging environment. 
  * 
  * For usage <code>initDefaultServerUrls</code> for first time usage. Server URLs can be updates from
  * a remote location with <code>initConfigServerUrl</code>.
@@ -61,17 +65,18 @@ public class SwitchBoard {
 	public static boolean DEBUG = true;
 	
 	/** Production server to update the remote server URLs. http://staging.domain/path_to/SwitchboardURLs.php */
 	private static String DYNAMIC_CONFIG_SERVER_URL_UPDATE;
 	
 	/** Production server for getting the actual config file. http://staging.domain/path_to/SwitchboardDriver.php */
 	private static String DYNAMIC_CONFIG_SERVER_DEFAULT_URL;
 	
-	
+	public static final String ACTION_CONFIG_FETCHED = ".SwitchBoard.CONFIG_FETCHED";
+
 	private static final String kUpdateServerUrl = "updateServerUrl";
 	private static final String kConfigServerUrl = "configServerUrl";
 	
 	private static final String IS_EXPERIMENT_ACTIVE = "isActive";
 	private static final String EXPERIMENT_VALUES = "values";
 	
 	
 	/**
@@ -224,16 +229,20 @@ public class SwitchBoard {
 				//store experiments in shared prefs (one variable)
 				if(serverConfig != null)
 					Preferences.setDynamicConfigJson(c, serverConfig);
 			}
 			
 		} catch (NullPointerException e) {
 			e.printStackTrace();
 		}
+
+		//notify listeners that the config fetch has completed
+		Intent i = new Intent(ACTION_CONFIG_FETCHED);
+		LocalBroadcastManager.getInstance(c).sendBroadcast(i);
 	}
 
 	public static boolean isInBucket(Context c, int low, int high) {
 		int userBucket = getUserBucket(c);
 		if (userBucket >= low && userBucket < high)
 			return true;
 		else
 			return false;
@@ -284,16 +293,47 @@ public class SwitchBoard {
 		
 			//return false when JSON fails
 			return defaultReturnVal;
 		}
 		
 	}
 	
 	/**
+	 * @returns a list of all active experiments.
+	 */
+	public static List<String> getActiveExperiments(Context c) {
+		ArrayList<String> returnList = new ArrayList<String>();
+
+		// lookup experiment in config
+		String config = Preferences.getDynamicConfigJson(c);
+
+		// if it does not exist
+		if (config == null) {
+			return returnList;
+		}
+
+		try {
+			JSONObject experiments = new JSONObject(config);
+			Iterator<?> iter = experiments.keys();
+			while (iter.hasNext()) {
+				String key = (String)iter.next();
+				JSONObject experiment = experiments.getJSONObject(key);
+				if (experiment.getBoolean(IS_EXPERIMENT_ACTIVE)) {
+					returnList.add(key);
+				}
+			}
+		} catch (JSONException e) {
+			// Something went wrong!
+		}
+
+		return returnList;
+	}
+
+	/**
 	 * Checks if a certain experiment exists. 
 	 * @param c ApplicationContext
 	 * @param experimentName Name of the experiment
 	 * @return true when experiment exists
 	 */
 	public static boolean hasExperimentValues(Context c, String experimentName) {
 		if(getExperimentValueFromJson(c, experimentName) == null)
 			return false;