diff --git a/scripts/default.env b/scripts/default.env
index 6a39a2127153c467bb2dac5e90b6cf485101d0e0..82a69026a22a8eb2ad6c1da4c048095d8e3e3624 100644
--- a/scripts/default.env
+++ b/scripts/default.env
@@ -1,5 +1,5 @@
 # This origin trial token is used to enable WebVR and Gamepad Extensions on Chrome 62+
 # You can find more information about getting your own origin trial token here: https://github.com/GoogleChrome/OriginTrials/blob/gh-pages/developer-guide.md
 ORIGIN_TRIAL_TOKEN="AvIMoF4hyRZQVfSfksoqP+7qzwa4FSBzHRHvUyzC8rMATJVRbcOiLewBxbXtJVyV3N62gsZv7PoSNtDqqtjzYAcAAABkeyJvcmlnaW4iOiJodHRwczovL3JldGljdWx1bS5pbzo0NDMiLCJmZWF0dXJlIjoiV2ViVlIxLjFNNjIiLCJleHBpcnkiOjE1MTYxNDYyMDQsImlzU3ViZG9tYWluIjp0cnVlfQ==",
-ORIGIN_TRIAL_EXPIRES="2018-01-16",
-JANUS_SERVER="wss://dev-janus.reticulum.io"
\ No newline at end of file
+ORIGIN_TRIAL_EXPIRES="2018-05-15",
+JANUS_SERVER="wss://dev-janus.reticulum.io"
diff --git a/src/components/in-world-hud.js b/src/components/in-world-hud.js
index 2c10aad240d6ee2d21ea8d536751b0fc3785a463..aa7e8aae756207dc05a640f7d02f6c0f728b41ca 100644
--- a/src/components/in-world-hud.js
+++ b/src/components/in-world-hud.js
@@ -7,8 +7,18 @@ AFRAME.registerComponent("in-world-hud", {
     this.bg = this.el.querySelector(".bg");
     this.mic = this.el.querySelector(".mic");
     this.nametag = this.el.querySelector(".username");
+    this.avatar = this.el.querySelector(".avatar");
     this.nametag.object3DMap.text.material.depthTest = false;
-    this.data.raycaster.components.line.material.depthTest = false;
+    this.nametag.object3DMap.text.renderOrder = 1;
+    this.mic.object3DMap.mesh.renderOrder = 1;
+    this.avatar.object3DMap.mesh.renderOrder = 1;
+
+    const line = this.data.raycaster.object3DMap.line;
+    line.renderOrder = 2;
+    line.material.depthTest = false;
+    // Set opacity to 0.99 to force the line to render in the
+    // transparent pass, so that it renders on top of the HUD
+    this.data.raycaster.setAttribute("line", "opacity", 0.99);
 
     const muted = this.el.sceneEl.is("muted");
     this.mic.setAttribute("src", muted ? "#muted" : "#unmuted");
diff --git a/src/hub.html b/src/hub.html
index 929d51f9c786a0f3083c138adcae4267070e4f00..014daab5a12b84ca4f65fcabe8c0f23a70454fe0 100644
--- a/src/hub.html
+++ b/src/hub.html
@@ -127,7 +127,7 @@
 
 
             <a-entity id="player-right-controller" class="right-controller" hand-controls2="right" tracked-controls teleport-controls="cameraRig: #player-rig; teleportOrigin: #player-camera; button: action_teleport_"
-                haptic-feedback raycaster="objects:.hud; showLine: true;" cursor="fuse: false; downEvents: action_ui_select_down; upEvents: action_ui_select_up;"
+                haptic-feedback raycaster="objects:.hud; showLine: true; far: 2;" cursor="fuse: false; downEvents: action_ui_select_down; upEvents: action_ui_select_up;"
                 app-mode-toggle-playing__teleport-controls="mode: hud; invert: true;" app-mode-toggle-playing__raycaster="mode: hud;"
                 app-mode-toggle-playing__cursor="mode: hud;" app-mode-toggle-attribute__line="mode: hud; property: visible;"></a-entity>
 
diff --git a/src/react-components/ui-root.js b/src/react-components/ui-root.js
index ce8c569c13742f2ca18877914e186cb1c6a160b1..83ddd1177f5be71efe796f02043bdceedb2cc6cd 100644
--- a/src/react-components/ui-root.js
+++ b/src/react-components/ui-root.js
@@ -225,8 +225,6 @@ class UIRoot extends Component {
   };
 
   performDirectEntryFlow = async enterInVR => {
-    this.startTestTone();
-
     this.setState({ enterInVR });
 
     const hasGrantedMic = await this.hasGrantedMicPermissions();
@@ -235,7 +233,6 @@ class UIRoot extends Component {
       await this.setMediaStreamToDefault();
       await this.beginAudioSetup();
     } else {
-      this.stopTestTone();
       this.setState({ entryStep: ENTRY_STEPS.mic_grant });
     }
   };
@@ -290,8 +287,19 @@ class UIRoot extends Component {
   };
 
   setMediaStreamToDefault = async () => {
-    await this.fetchAudioTrack({ audio: true });
+    let hasAudio = false;
+    const { lastUsedMicDeviceId } = this.props.store.state;
+
+    // Try to fetch last used mic, if there was one.
+    if (lastUsedMicDeviceId) {
+      hasAudio = await this.fetchAudioTrack({ audio: { deviceId: { ideal: lastUsedMicDeviceId } } });
+    } else {
+      hasAudio = await this.fetchAudioTrack({ audio: true });
+    }
+
     await this.setupNewMediaStream();
+
+    return { hasAudio };
   };
 
   setStateAndRequestScreen = async e => {
@@ -322,51 +330,75 @@ class UIRoot extends Component {
     if (this.state.audioTrack) {
       this.state.audioTrack.stop();
     }
-    const mediaStream = await navigator.mediaDevices.getUserMedia(constraints);
-    this.setState({ audioTrack: mediaStream.getAudioTracks()[0] });
+
+    try {
+      const mediaStream = await navigator.mediaDevices.getUserMedia(constraints);
+      this.setState({ audioTrack: mediaStream.getAudioTracks()[0] });
+      return true;
+    } catch (e) {
+      // Error fetching audio track, most likely a permission denial.
+      this.setState({ audioTrack: null });
+      return false;
+    }
   };
 
   setupNewMediaStream = async () => {
     const mediaStream = new MediaStream();
 
-    // we should definitely have an audioTrack at this point.
-    mediaStream.addTrack(this.state.audioTrack);
+    await this.fetchMicDevices();
 
     if (this.state.videoTrack) {
       mediaStream.addTrack(this.state.videoTrack);
     }
 
-    const AudioContext = window.AudioContext || window.webkitAudioContext;
-    const audioContext = new AudioContext();
-    const source = audioContext.createMediaStreamSource(mediaStream);
-    const analyzer = audioContext.createAnalyser();
-    const levels = new Uint8Array(analyzer.fftSize);
+    // we should definitely have an audioTrack at this point unless they denied mic access
+    if (this.state.audioTrack) {
+      mediaStream.addTrack(this.state.audioTrack);
 
-    source.connect(analyzer);
+      const AudioContext = window.AudioContext || window.webkitAudioContext;
+      const audioContext = new AudioContext();
+      const source = audioContext.createMediaStreamSource(mediaStream);
+      const analyzer = audioContext.createAnalyser();
+      const levels = new Uint8Array(analyzer.fftSize);
 
-    const micUpdateInterval = setInterval(() => {
-      analyzer.getByteTimeDomainData(levels);
+      source.connect(analyzer);
 
-      let v = 0;
+      const micUpdateInterval = setInterval(() => {
+        analyzer.getByteTimeDomainData(levels);
 
-      for (let x = 0; x < levels.length; x++) {
-        v = Math.max(levels[x] - 127, v);
+        let v = 0;
+
+        for (let x = 0; x < levels.length; x++) {
+          v = Math.max(levels[x] - 127, v);
+        }
+
+        const level = v / 128.0;
+        this.micLevelMovingAverage.push(Date.now(), level);
+        this.setState({ micLevel: this.micLevelMovingAverage.movingAverage() });
+      }, 50);
+
+      const micDeviceId = this.micDeviceIdForMicLabel(this.micLabelForMediaStream(mediaStream));
+
+      if (micDeviceId) {
+        this.props.store.update({ lastUsedMicDeviceId: micDeviceId });
       }
 
-      const level = v / 128.0;
-      this.micLevelMovingAverage.push(Date.now(), level);
-      this.setState({ micLevel: this.micLevelMovingAverage.movingAverage() });
-    }, 50);
+      this.setState({ micUpdateInterval });
+    }
 
-    this.setState({ mediaStream, micUpdateInterval });
+    this.setState({ mediaStream });
   };
 
   onMicGrantButton = async () => {
     if (this.state.entryStep == ENTRY_STEPS.mic_grant) {
-      await this.setMediaStreamToDefault();
-      this.setState({ entryStep: ENTRY_STEPS.mic_granted });
+      const { hasAudio } = await this.setMediaStreamToDefault();
+
+      if (hasAudio) {
+        this.setState({ entryStep: ENTRY_STEPS.mic_granted });
+      } else {
+        await this.beginAudioSetup();
+      }
     } else {
-      this.startTestTone();
       await this.beginAudioSetup();
     }
   };
@@ -376,14 +408,22 @@ class UIRoot extends Component {
   };
 
   beginAudioSetup = async () => {
-    await this.fetchMicDevices();
+    this.startTestTone();
     this.setState({ entryStep: ENTRY_STEPS.audio_setup });
   };
 
-  fetchMicDevices = async () => {
-    const mediaDevices = await navigator.mediaDevices.enumerateDevices();
-    this.setState({
-      micDevices: mediaDevices.filter(d => d.kind === "audioinput").map(d => ({ deviceId: d.deviceId, label: d.label }))
+  fetchMicDevices = () => {
+    return new Promise(resolve => {
+      navigator.mediaDevices.enumerateDevices().then(mediaDevices => {
+        this.setState(
+          {
+            micDevices: mediaDevices
+              .filter(d => d.kind === "audioinput")
+              .map(d => ({ deviceId: d.deviceId, label: d.label }))
+          },
+          resolve
+        );
+      });
     });
   };
 
@@ -399,17 +439,20 @@ class UIRoot extends Component {
     return !!this.state.micDevices.find(d => HMD_MIC_REGEXES.find(r => d.label.match(r)));
   };
 
+  micLabelForMediaStream = mediaStream => {
+    return (mediaStream && mediaStream.getAudioTracks().length > 0 && mediaStream.getAudioTracks()[0].label) || "";
+  };
+
   selectedMicLabel = () => {
-    return (
-      (this.state.mediaStream &&
-        this.state.mediaStream.getAudioTracks().length > 0 &&
-        this.state.mediaStream.getAudioTracks()[0].label) ||
-      ""
-    );
+    return this.micLabelForMediaStream(this.state.mediaStream);
+  };
+
+  micDeviceIdForMicLabel = label => {
+    return this.state.micDevices.filter(d => d.label === label).map(d => d.deviceId)[0];
   };
 
   selectedMicDeviceId = () => {
-    return this.state.micDevices.filter(d => d.label === this.selectedMicLabel).map(d => d.deviceId)[0];
+    return this.micDeviceIdForMicLabel(this.selectedMicLabel());
   };
 
   onAudioReadyButton = () => {
@@ -566,11 +609,19 @@ class UIRoot extends Component {
           </div>
           <div className="audio-setup-panel__levels">
             <div className="audio-setup-panel__levels__mic">
-              <img
-                src="../assets/images/mic_level.png"
-                srcSet="../assets/images/mic_level@2x.png 2x"
-                className="audio-setup-panel__levels__mic_icon"
-              />
+              {this.state.audioTrack ? (
+                <img
+                  src="../assets/images/mic_level.png"
+                  srcSet="../assets/images/mic_level@2x.png 2x"
+                  className="audio-setup-panel__levels__mic_icon"
+                />
+              ) : (
+                <img
+                  src="../assets/images/mic_denied.png"
+                  srcSet="../assets/images/mic_denied@2x.png 2x"
+                  className="audio-setup-panel__levels__mic_icon"
+                />
+              )}
               <img
                 src="../assets/images/level_fill.png"
                 srcSet="../assets/images/level_fill@2x.png 2x"
@@ -592,22 +643,24 @@ class UIRoot extends Component {
               />
             </div>
           </div>
-          <div className="audio-setup-panel__device-chooser">
-            <select
-              className="audio-setup-panel__device-chooser__dropdown"
-              value={this.selectedMicDeviceId()}
-              onChange={this.micDeviceChanged}
-            >
-              {this.state.micDevices.map(d => (
-                <option key={d.deviceId} value={d.deviceId}>
-                  &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{d.label}
-                </option>
-              ))}
-            </select>
-            <div className="audio-setup-panel__device-chooser__mic-icon">
-              <img src="../assets/images/mic_small.png" srcSet="../assets/images/mic_small@2x.png 2x" />
+          {this.state.audioTrack && (
+            <div className="audio-setup-panel__device-chooser">
+              <select
+                className="audio-setup-panel__device-chooser__dropdown"
+                value={this.selectedMicDeviceId()}
+                onChange={this.micDeviceChanged}
+              >
+                {this.state.micDevices.map(d => (
+                  <option key={d.deviceId} value={d.deviceId}>
+                    &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{d.label}
+                  </option>
+                ))}
+              </select>
+              <div className="audio-setup-panel__device-chooser__mic-icon">
+                <img src="../assets/images/mic_small.png" srcSet="../assets/images/mic_small@2x.png 2x" />
+              </div>
             </div>
-          </div>
+          )}
           {this.shouldShowHmdMicWarning() && (
             <div className="audio-setup-panel__hmd-mic-warning">
               <img
diff --git a/src/storage/store.js b/src/storage/store.js
index a517bfc5749c53eb9a193298194f7ed7fa0ee56f..6f480aa76db6f14904b611cecf5b0b6b84b1f41f 100644
--- a/src/storage/store.js
+++ b/src/storage/store.js
@@ -26,7 +26,8 @@ export const SCHEMA = {
 
   properties: {
     id: { type: "string", pattern: "^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$" },
-    profile: { $ref: "#/definitions/profile" }
+    profile: { $ref: "#/definitions/profile" },
+    lastUsedMicDeviceId: { type: "string" }
   },
 
   additionalProperties: false
diff --git a/src/telemetry.js b/src/telemetry.js
index 2a738593e98541d97e236a0a70d28619b4b10925..6eed4d002b96c507dcdaea78b6a5ab58f9791441 100644
--- a/src/telemetry.js
+++ b/src/telemetry.js
@@ -1,5 +1,7 @@
 import Raven from "raven-js";
 
 export default function registerTelemetry() {
-  Raven.config("https://f571beaf5cee4e3085e0bf436f3eb158@sentry.io/256771").install();
+  if (process.env.NODE_ENV === "production") {
+    Raven.config("https://f571beaf5cee4e3085e0bf436f3eb158@sentry.io/256771").install();
+  }
 }