Bug 1123660 - add logging to Loop media connection telemetry, r=Standard8
authorDan Mosedale <dmose@meer.net>
Fri, 20 Mar 2015 10:44:40 -0700
changeset 263466 f79e4acd9172351661d55456ccc406fe08190ccf
parent 263465 aa2b8bc620db9e80b6c8254e654c2f7d2153f9af
child 263467 933b795a1fc1d165b38a5449871120d0b331350d
push id4718
push userraliiev@mozilla.com
push dateMon, 11 May 2015 18:39:53 +0000
treeherdermozilla-beta@c20c4ef55f08 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersStandard8
bugs1123660
milestone39.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1123660 - add logging to Loop media connection telemetry, r=Standard8
browser/app/profile/firefox.js
browser/components/loop/content/shared/js/otSdkDriver.js
browser/components/loop/test/functional/test_1_browser_call.py
browser/components/loop/test/shared/otSdkDriver_test.js
--- a/browser/app/profile/firefox.js
+++ b/browser/app/profile/firefox.js
@@ -1693,16 +1693,17 @@ pref("loop.retry_delay.limit", 300000);
 pref("loop.ping.interval", 1800000);
 pref("loop.ping.timeout", 10000);
 pref("loop.feedback.baseUrl", "https://input.mozilla.org/api/v1/feedback");
 pref("loop.feedback.product", "Loop");
 pref("loop.debug.loglevel", "Error");
 pref("loop.debug.dispatcher", false);
 pref("loop.debug.websocket", false);
 pref("loop.debug.sdk", false);
+pref("loop.debug.twoWayMediaTelemetry", false);
 #ifdef DEBUG
 pref("loop.CSP", "default-src 'self' about: file: chrome: http://localhost:*; img-src 'self' data: https://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net http://localhost:* ws://localhost:*; media-src blob:");
 #else
 pref("loop.CSP", "default-src 'self' about: file: chrome:; img-src 'self' data: https://www.gravatar.com/ about: file: chrome:; font-src 'none'; connect-src wss://*.tokbox.com https://*.opentok.com https://*.tokbox.com wss://*.mozilla.com https://*.mozilla.org wss://*.mozaws.net; media-src blob:");
 #endif
 pref("loop.oauth.google.redirect_uri", "urn:ietf:wg:oauth:2.0:oob:auto");
 pref("loop.oauth.google.scope", "https://www.google.com/m8/feeds");
 pref("loop.fxa_oauth.tokendata", "");
--- a/browser/components/loop/content/shared/js/otSdkDriver.js
+++ b/browser/components/loop/content/shared/js/otSdkDriver.js
@@ -22,48 +22,57 @@ loop.OTSdkDriver = (function() {
       }
       if (!options.sdk) {
         throw new Error("Missing option sdk");
       }
 
       this.dispatcher = options.dispatcher;
       this.sdk = options.sdk;
 
-      // Note that this will only be defined and usable in a desktop-local
-      // context, not in the standalone web client.
-      this.mozLoop = options.mozLoop;
+      this._isDesktop = !!options.isDesktop;
+
+      if (this._isDesktop) {
+        if (!options.mozLoop) {
+          throw new Error("Missing option mozLoop");
+        }
+        this.mozLoop = options.mozLoop;
+      }
 
       this.connections = {};
-      this.connectionStartTime = this.CONNECTION_START_TIME_UNINITIALIZED;
+      this._setTwoWayMediaStartTime(this.CONNECTION_START_TIME_UNINITIALIZED);
 
       this.dispatcher.register(this, [
         "setupStreamElements",
         "setMute"
       ]);
 
+      // Set loop.debug.twoWayMediaTelemetry to true in the browser
+      // by changing the hidden pref loop.debug.twoWayMediaTelemetry using
+      // about:config, or use
+      //
+      // localStorage.setItem("debug.twoWayMediaTelemetry", true);
+      this._debugTwoWayMediaTelemetry =
+        loop.shared.utils.getBoolPreference("debug.twoWayMediaTelemetry");
+
     /**
      * XXX This is a workaround for desktop machines that do not have a
      * camera installed. As we don't yet have device enumeration, when
      * we do, this can be removed (bug 1138851), and the sdk should handle it.
      */
-    if ("isDesktop" in options && options.isDesktop &&
-        !window.MediaStreamTrack.getSources) {
+    if (this._isDesktop && !window.MediaStreamTrack.getSources) {
       // If there's no getSources function, the sdk defines its own and caches
       // the result. So here we define the "normal" one which doesn't get cached, so
       // we can change it later.
       window.MediaStreamTrack.getSources = function(callback) {
         callback([{kind: "audio"}, {kind: "video"}]);
       };
     }
   };
 
   OTSdkDriver.prototype = {
-    CONNECTION_START_TIME_UNINITIALIZED: -1,
-    CONNECTION_START_TIME_ALREADY_NOTED: -2,
-
     /**
      * Clones the publisher config into a new object, as the sdk modifies the
      * properties object.
      */
     _getCopyPublisherConfig: function() {
       return _.extend({}, this.publisherConfig);
     },
 
@@ -231,25 +240,25 @@ loop.OTSdkDriver = (function() {
         delete this.session;
       }
       if (this.publisher) {
         this.publisher.off("accessAllowed accessDenied accessDialogOpened streamCreated");
         this.publisher.destroy();
         delete this.publisher;
       }
 
-      this._noteConnectionLengthIfNeeded(this.connectionStartTime, performance.now());
+      this._noteConnectionLengthIfNeeded(this._getTwoWayMediaStartTime(), performance.now());
 
       // Also, tidy these variables ready for next time.
       delete this._sessionConnected;
       delete this._publisherReady;
       delete this._publishedLocalStream;
       delete this._subscribedRemoteStream;
       this.connections = {};
-      this.connectionStartTime = this.CONNECTION_START_TIME_UNINITIALIZED;
+      this._setTwoWayMediaStartTime(this.CONNECTION_START_TIME_UNINITIALIZED);
     },
 
     /**
      * Oust all users from an ongoing session. This is typically done when a room
      * owner deletes the room.
      *
      * @param {Function} callback Function to be invoked once all connections are
      *                            ousted
@@ -303,17 +312,17 @@ loop.OTSdkDriver = (function() {
      * @param {ConnectionEvent} event The event details
      * https://tokbox.com/opentok/libraries/client/js/reference/ConnectionEvent.html
      */
     _onConnectionDestroyed: function(event) {
       var connection = event.connection;
       if (connection && (connection.id in this.connections)) {
         delete this.connections[connection.id];
       }
-      this._noteConnectionLengthIfNeeded(this.connectionStartTime, performance.now());
+      this._noteConnectionLengthIfNeeded(this._getTwoWayMediaStartTime(), performance.now());
       this.dispatcher.dispatch(new sharedActions.RemotePeerDisconnected({
         peerHungup: event.reason === "clientDisconnected"
       }));
     },
 
     /**
      * Handles the session event for the connection for this client being
      * destroyed.
@@ -330,17 +339,17 @@ loop.OTSdkDriver = (function() {
         case "forceDisconnected":
           reason = FAILURE_DETAILS.EXPIRED_OR_INVALID;
           break;
         default:
           // Other cases don't need to be handled.
           return;
       }
 
-      this._noteConnectionLengthIfNeeded(this.connectionStartTime,
+      this._noteConnectionLengthIfNeeded(this._getTwoWayMediaStartTime(),
         performance.now());
       this.dispatcher.dispatch(new sharedActions.ConnectionFailure({
         reason: reason
       }));
     },
 
     /**
      * Handles the connection event for a newly connecting peer.
@@ -403,17 +412,17 @@ loop.OTSdkDriver = (function() {
 
       var remoteElement = this.getRemoteElement();
 
       this.session.subscribe(event.stream,
         remoteElement, this._getCopyPublisherConfig());
 
       this._subscribedRemoteStream = true;
       if (this._checkAllStreamsConnected()) {
-        this.connectionStartTime = performance.now();
+        this._setTwoWayMediaStartTime(performance.now());
         this.dispatcher.dispatch(new sharedActions.MediaConnected());
       }
     },
 
     /**
      * Handles the event when the local stream is created.
      *
      * @param {StreamEvent} event The event details:
@@ -424,16 +433,66 @@ loop.OTSdkDriver = (function() {
         this.dispatcher.dispatch(new sharedActions.VideoDimensionsChanged({
           isLocal: true,
           videoType: event.stream.videoType,
           dimensions: event.stream[STREAM_PROPERTIES.VIDEO_DIMENSIONS]
         }));
       }
     },
 
+    /**
+     * Implementation detail, may be set to one of the CONNECTION_START_TIME
+     * constants, or a positive integer in milliseconds.
+     *
+     * @private
+     */
+    __twoWayMediaStartTime: undefined,
+
+    /**
+     * Used as a guard to make sure we don't inadvertently use an
+     * uninitialized value.
+     */
+    CONNECTION_START_TIME_UNINITIALIZED: -1,
+
+    /**
+     * Use as a guard to ensure that we don't note any bidirectional sessions
+     * twice.
+     */
+    CONNECTION_START_TIME_ALREADY_NOTED: -2,
+
+    /**
+     * Set and get the start time of the two-way media connection.  These
+     * are done as wrapper functions so that we can log sets to make manual
+     * verification of various telemetry scenarios possible.  The get API is
+     * analogous in order to follow the principle of least surprise for
+     * people consuming this code.
+     *
+     * If this._isDesktop is not true, returns immediately without making
+     * any changes, since this data is not used, and it makes reading
+     * the logs confusing for manual verification of both ends of the call in
+     * the same browser, which is a case we care about.
+     *
+     * @param start  start time in milliseconds, as returned by
+     *               performance.now()
+     * @private
+     */
+    _setTwoWayMediaStartTime: function(start) {
+      if (!this._isDesktop) {
+        return;
+      }
+
+      this.__twoWayMediaStartTime = start;
+      if (this._debugTwoWayMediaTelemetry) {
+        console.log("Loop Telemetry: noted two-way connection start, " +
+                    "start time in ms:", start);
+      }
+    },
+    _getTwoWayMediaStartTime: function() {
+      return this.__twoWayMediaStartTime;
+    },
 
     /**
      * Handles the event when the remote stream is destroyed.
      *
      * @param {StreamEvent} event The event details:
      * https://tokbox.com/opentok/libraries/client/js/reference/StreamEvent.html
      */
     _onRemoteStreamDestroyed: function(event) {
@@ -523,17 +582,17 @@ loop.OTSdkDriver = (function() {
     _maybePublishLocalStream: function() {
       if (this._sessionConnected && this._publisherReady) {
         // We are clear to publish the stream to the session.
         this.session.publish(this.publisher);
 
         // Now record the fact, and check if we've got all media yet.
         this._publishedLocalStream = true;
         if (this._checkAllStreamsConnected()) {
-          this.connectionStartTime = performance.now();
+          this._setTwoWayMediaStartTime(performance.now);
           this.dispatcher.dispatch(new sharedActions.MediaConnected());
         }
       }
     },
 
     /**
      * Used to check if both local and remote streams are available
      * and send an action if they are.
@@ -557,29 +616,37 @@ loop.OTSdkDriver = (function() {
      * Called when a screenshare is denied. Notifies the other stores.
      */
     _onScreenShareDenied: function() {
       this.dispatcher.dispatch(new sharedActions.ScreenSharingState({
         state: SCREEN_SHARE_STATES.INACTIVE
       }));
     },
 
+    /*
+     * XXX all of the bi-directional media connection telemetry stuff in this
+     * file, (much, but not all, of it is below) should be hoisted into its
+     * own object for maintainability and clarity, also in part because this
+     * stuff only wants to run one side of the connection, not both (tracked
+     * by bug 1145237).
+     */
+
     /**
      * A hook exposed only for the use of the functional tests so that
      * they can check that the bi-directional media count is being updated
      * correctly.
      *
      * @type number
      * @private
      */
     _connectionLengthNotedCalls: 0,
 
     /**
      * Wrapper for adding a keyed value that also updates
-     * connectionLengthNoted calls and sets this.connectionStartTime to
+     * connectionLengthNoted calls and sets the twoWayMediaStartTime to
      * this.CONNECTION_START_TIME_ALREADY_NOTED.
      *
      * @param {number} callLengthSeconds  the call length in seconds
      * @private
      */
     _noteConnectionLength: function(callLengthSeconds) {
 
       var bucket = this.mozLoop.TWO_WAY_MEDIA_CONN_LENGTH.SHORTER_THAN_10S;
@@ -589,46 +656,58 @@ loop.OTSdkDriver = (function() {
       } else if (callLengthSeconds > 30 && callLengthSeconds <= 300) {
         bucket = this.mozLoop.TWO_WAY_MEDIA_CONN_LENGTH.BETWEEN_30S_AND_5M;
       } else if (callLengthSeconds > 300) {
         bucket = this.mozLoop.TWO_WAY_MEDIA_CONN_LENGTH.MORE_THAN_5M;
       }
 
       this.mozLoop.telemetryAddKeyedValue("LOOP_TWO_WAY_MEDIA_CONN_LENGTH",
         bucket);
-      this.connectionStartTime = this.CONNECTION_START_TIME_ALREADY_NOTED;
+      this._setTwoWayMediaStartTime(this.CONNECTION_START_TIME_ALREADY_NOTED);
 
       this._connectionLengthNotedCalls++;
+      if (this._debugTwoWayMediaTelemetry) {
+        console.log('Loop Telemetry: noted two-way media connection ' +
+          'in bucket: ', bucket);
+      }
     },
 
     /**
      * Note connection length if it's valid (the startTime has been initialized
      * and is not later than endTime) and not yet already noted.  If
-     * this.mozLoop is not defined, we're assumed to be running in the
+     * this._isDesktop is not true, we're assumed to be running in the
      * standalone client and return immediately.
      *
      * @param {number} startTime  in milliseconds
      * @param {number} endTime  in milliseconds
      * @private
      */
     _noteConnectionLengthIfNeeded: function(startTime, endTime) {
-      if (!this.mozLoop) {
+      if (!this._isDesktop) {
         return;
       }
 
       if (startTime == this.CONNECTION_START_TIME_ALREADY_NOTED ||
           startTime == this.CONNECTION_START_TIME_UNINITIALIZED ||
           startTime > endTime) {
-        console.log("_noteConnectionLengthIfNeeded called with " +
-                    " invalid params, either the calls were never" +
-                    " connected or there is a bug; startTime:", startTime,
-                    "endTime:", endTime);
+        if (this._debugTwoWayMediaTelemetry) {
+          console.log("_noteConnectionLengthIfNeeded called with " +
+            " invalid params, either the calls were never" +
+            " connected or there is a bug; startTime:", startTime,
+            "endTime:", endTime);
+        }
         return;
       }
 
       var callLengthSeconds = (endTime - startTime) / 1000;
       this._noteConnectionLength(callLengthSeconds);
-    }
+    },
+
+    /**
+     * If set to true, make it easy to test/verify 2-way media connection
+     * telemetry code operation by viewing the logs.
+     */
+    _debugTwoWayMediaTelemetry: false
   };
 
   return OTSdkDriver;
 
 })();
--- a/browser/components/loop/test/functional/test_1_browser_call.py
+++ b/browser/components/loop/test/functional/test_1_browser_call.py
@@ -188,17 +188,17 @@ class Test1BrowserCall(MarionetteTestCas
             let chatGlobal = chatBrowser.contentWindow.wrappedJSObject;
 
             return chatGlobal.''' + expr
 
         return self.marionette.execute_script(script, [chatbox])
 
     def local_get_media_start_time(self):
         return self.local_get_chatbox_window_expr(
-            "loop.conversation._sdkDriver.connectionStartTime")
+            "loop.conversation._sdkDriver._getTwoWayMediaStartTime()")
 
     # XXX could be memoized
     def local_get_media_start_time_uninitialized(self):
         return self.local_get_chatbox_window_expr(
             "loop.conversation._sdkDriver.CONNECTION_START_TIME_UNINITIALIZED"
         )
 
     def local_check_media_start_time_uninitialized(self):
@@ -216,17 +216,17 @@ class Test1BrowserCall(MarionetteTestCas
             "media is bidirectionally connected")
 
     def local_check_connection_length_noted(self):
         noted_calls = self.local_get_chatbox_window_expr(
             "loop.conversation._sdkDriver._connectionLengthNotedCalls")
 
         self.assertGreater(noted_calls, 0,
                            "OTSdkDriver._connectionLengthNotedCalls should be "
-                           "> 0")
+                           "> 0, noted_calls = " + str(noted_calls))
 
     def test_1_browser_call(self):
         self.switch_to_panel()
 
         self.local_start_a_conversation()
 
         # Check the self video in the conversation window
         self.local_check_room_self_video()
@@ -247,18 +247,18 @@ class Test1BrowserCall(MarionetteTestCas
         # the start time
         self.local_check_media_start_time_initialized()
 
         # XXX To enable this, we either need to navigate the permissions prompt
         # or have a route where we don't need the permissions prompt.
         # self.local_enable_screenshare()
         # self.standalone_check_remote_screenshare()
 
-        # We hangup on the remote side, because this also leaves the
-        # local chatbox with the local publishing media still connected,
+        # We hangup on the remote (standalone) side, because this also leaves
+        # the local chatbox with the local publishing media still connected,
         # which means that the local_check_connection_length below
         # verifies that the connection is noted at the time the remote media
         # drops, rather than waiting until the window closes.
         self.remote_leave_room_and_verify_feedback()
 
         self.local_check_connection_length_noted()
 
     def tearDown(self):
--- a/browser/components/loop/test/shared/otSdkDriver_test.js
+++ b/browser/components/loop/test/shared/otSdkDriver_test.js
@@ -72,17 +72,18 @@ describe("loop.OTSdkDriver", function ()
         BETWEEN_30S_AND_5M: "BETWEEN_30S_AND_5M",
         MORE_THAN_5M: "MORE_THAN_5M"
       }
     };
 
     driver = new loop.OTSdkDriver({
       dispatcher: dispatcher,
       sdk: sdk,
-      mozLoop: mozLoop
+      mozLoop: mozLoop,
+      isDesktop: true
     });
   });
 
   afterEach(function() {
     sandbox.restore();
   });
 
   describe("Constructor", function() {
@@ -93,20 +94,22 @@ describe("loop.OTSdkDriver", function ()
     });
 
     it("should throw an error if the sdk is missing", function() {
       expect(function() {
         new loop.OTSdkDriver({dispatcher: dispatcher});
       }).to.Throw(/sdk/);
     });
 
-    it("should initialize the connectionStartTime to 'uninitialized'", function() {
-      var driver = new loop.OTSdkDriver({sdk: sdk, dispatcher: dispatcher, mozLoop: mozLoop});
+    it("should set the two-way media start time to 'uninitialized'", function() {
+      var driver = new loop.OTSdkDriver(
+        {sdk: sdk, dispatcher: dispatcher, mozLoop: mozLoop, isDesktop: true});
 
-      expect(driver.connectionStartTime).to.eql(driver.CONNECTION_START_TIME_UNINITIALIZED);
+      expect(driver._getTwoWayMediaStartTime()).to.
+        eql(driver.CONNECTION_START_TIME_UNINITIALIZED);
     });
   });
 
   describe("#setupStreamElements", function() {
     it("should call initPublisher", function() {
       dispatcher.dispatch(new sharedActions.SetupStreamElements({
         getLocalElementFunc: function() {return fakeLocalElement;},
         getRemoteElementFunc: function() {return fakeRemoteElement;},
@@ -326,52 +329,53 @@ describe("loop.OTSdkDriver", function ()
 
       sinon.assert.calledOnce(publisher.destroy);
     });
 
     it("should call _noteConnectionLengthIfNeeded with connection duration", function() {
       driver.session = session;
       var startTime = 1;
       var endTime = 3;
-      driver.connectionStartTime = startTime;
+      driver._setTwoWayMediaStartTime(startTime);
       sandbox.stub(performance, "now").returns(endTime);
       sandbox.stub(driver, "_noteConnectionLengthIfNeeded");
 
       driver.disconnectSession();
 
       sinon.assert.calledWith(driver._noteConnectionLengthIfNeeded, startTime,
                               endTime);
     });
 
-    it("should reset the connectionStartTime", function() {
+    it("should reset the two-way media connection start time", function() {
       driver.session = session;
       var startTime = 1;
-      driver.connectionStartTime = startTime;
+      driver._setTwoWayMediaStartTime(startTime);
       sandbox.stub(performance, "now");
       sandbox.stub(driver, "_noteConnectionLengthIfNeeded");
 
       driver.disconnectSession();
 
-      expect(driver.connectionStartTime).to.eql(driver.CONNECTION_START_TIME_UNINITIALIZED);
+      expect(driver._getTwoWayMediaStartTime()).to.
+        eql(driver.CONNECTION_START_TIME_UNINITIALIZED);
     });
   });
 
   describe("#_noteConnectionLengthIfNeeded", function() {
     var startTimeMS;
     beforeEach(function() {
       startTimeMS = 1;
-      driver.connectionStartTime = startTimeMS;
+      driver._setTwoWayMediaStartTime(startTimeMS);
     });
 
-
-    it("should set connectionStartTime to CONNECTION_START_TIME_ALREADY_NOTED", function() {
+    it("should set two-way media start time to CONNECTION_START_TIME_ALREADY_NOTED", function() {
       var endTimeMS = 3;
       driver._noteConnectionLengthIfNeeded(startTimeMS, endTimeMS);
 
-      expect(driver.connectionStartTime).to.eql(driver.CONNECTION_START_TIME_ALREADY_NOTED);
+      expect(driver._getTwoWayMediaStartTime()).to.
+        eql(driver.CONNECTION_START_TIME_ALREADY_NOTED);
     });
 
     it("should call mozLoop.noteConnectionLength with SHORTER_THAN_10S for calls less than 10s", function() {
       var endTimeMS = 9000;
 
       driver._noteConnectionLengthIfNeeded(startTimeMS, endTimeMS);
 
       sinon.assert.calledOnce(mozLoop.telemetryAddKeyedValue);
@@ -409,16 +413,27 @@ describe("loop.OTSdkDriver", function ()
 
       driver._noteConnectionLengthIfNeeded(startTimeMS, endTimeMS);
 
       sinon.assert.calledOnce(mozLoop.telemetryAddKeyedValue);
       sinon.assert.calledWith(mozLoop.telemetryAddKeyedValue,
         "LOOP_TWO_WAY_MEDIA_CONN_LENGTH",
         mozLoop.TWO_WAY_MEDIA_CONN_LENGTH.MORE_THAN_5M);
     });
+
+    it("should not call mozLoop.noteConnectionLength if driver._isDesktop " +
+       "is false",
+      function() {
+        var endTimeMS = 10 * 60 * 1000;
+        driver._isDesktop = false;
+
+        driver._noteConnectionLengthIfNeeded(startTimeMS, endTimeMS);
+
+        sinon.assert.notCalled(mozLoop.telemetryAddKeyedValue);
+      });
   });
 
   describe("#forceDisconnectAll", function() {
     it("should not disconnect anything when not connected", function() {
       driver.session = session;
       driver.forceDisconnectAll(function() {});
 
       sinon.assert.notCalled(session.forceDisconnect);
@@ -494,17 +509,17 @@ describe("loop.OTSdkDriver", function ()
             sinon.match.hasOwn("peerHungup", false));
       });
 
 
       it("should call _noteConnectionLengthIfNeeded with connection duration", function() {
         driver.session = session;
         var startTime = 1;
         var endTime = 3;
-        driver.connectionStartTime = startTime;
+        driver._setTwoWayMediaStartTime(startTime);
         sandbox.stub(performance, "now").returns(endTime);
         sandbox.stub(driver, "_noteConnectionLengthIfNeeded");
 
         session.trigger("connectionDestroyed", {
           reason: "clientDisconnected"
         });
 
         sinon.assert.calledWith(driver._noteConnectionLengthIfNeeded, startTime,
@@ -538,17 +553,17 @@ describe("loop.OTSdkDriver", function ()
           sinon.assert.calledWithMatch(dispatcher.dispatch,
             sinon.match.hasOwn("reason", FAILURE_DETAILS.EXPIRED_OR_INVALID));
         });
 
       it("should call _noteConnectionLengthIfNeeded with connection duration", function() {
         driver.session = session;
         var startTime = 1;
         var endTime = 3;
-        driver.connectionStartTime = startTime;
+        driver._setTwoWayMediaStartTime(startTime);
         sandbox.stub(performance, "now").returns(endTime);
         sandbox.stub(driver, "_noteConnectionLengthIfNeeded");
 
         session.trigger("sessionDisconnected", {
           reason: "networkDisconnected"
         });
 
         sinon.assert.calledWith(driver._noteConnectionLengthIfNeeded, startTime,
@@ -624,24 +639,37 @@ describe("loop.OTSdkDriver", function ()
         session.trigger("streamCreated", {stream: fakeStream});
 
         // Called twice due to the VideoDimensionsChanged above.
         sinon.assert.calledTwice(dispatcher.dispatch);
         sinon.assert.calledWithMatch(dispatcher.dispatch,
           sinon.match.hasOwn("name", "mediaConnected"));
       });
 
-      it("should store the start time when both streams are up", function() {
+      it("should store the start time when both streams are up and" +
+      " driver._isDesktop is true", function() {
         driver._publishedLocalStream = true;
         var startTime = 1;
         sandbox.stub(performance, "now").returns(startTime);
 
         session.trigger("streamCreated", {stream: fakeStream});
 
-        expect(driver.connectionStartTime).to.eql(startTime);
+        expect(driver._getTwoWayMediaStartTime()).to.eql(startTime);
+      });
+
+      it("should not store the start time when both streams are up and" +
+         " driver._isDesktop is false", function() {
+        driver._isDesktop = false ;
+        driver._publishedLocalStream = true;
+        var startTime = 73;
+        sandbox.stub(performance, "now").returns(startTime);
+
+        session.trigger("streamCreated", {stream: fakeStream});
+
+        expect(driver._getTwoWayMediaStartTime()).to.not.eql(startTime);
       });
 
 
       it("should not dispatch a mediaConnected action for screen sharing streams",
         function() {
           driver._publishedLocalStream = true;
           fakeStream.videoType = "screen";