Javascript audio player for the exported HTML file.

BUG=webrtc:7218
NOTRY=True

Review-Url: https://codereview.webrtc.org/2721023002
Cr-Commit-Position: refs/heads/master@{#17529}
diff --git a/webrtc/modules/audio_processing/test/py_quality_assessment/BUILD.gn b/webrtc/modules/audio_processing/test/py_quality_assessment/BUILD.gn
index 81ef562..3f2fc41 100644
--- a/webrtc/modules/audio_processing/test/py_quality_assessment/BUILD.gn
+++ b/webrtc/modules/audio_processing/test/py_quality_assessment/BUILD.gn
@@ -46,6 +46,7 @@
     "quality_assessment/noise_generation_factory.py",
     "quality_assessment/noise_generation_unittest.py",
     "quality_assessment/results.css",
+    "quality_assessment/results.js",
     "quality_assessment/signal_processing.py",
     "quality_assessment/signal_processing_unittest.py",
     "quality_assessment/simulation.py",
diff --git a/webrtc/modules/audio_processing/test/py_quality_assessment/apm_quality_assessment_export.py b/webrtc/modules/audio_processing/test/py_quality_assessment/apm_quality_assessment_export.py
index 1b2fe36..350a5da 100755
--- a/webrtc/modules/audio_processing/test/py_quality_assessment/apm_quality_assessment_export.py
+++ b/webrtc/modules/audio_processing/test/py_quality_assessment/apm_quality_assessment_export.py
@@ -134,8 +134,8 @@
     score_path, _ = os.path.split(score_filepath)
     audio_in_filepath, audio_ref_filepath = (
         data_access.Metadata.load_audio_in_ref_paths(score_path))
-    audio_out_filepath = os.path.join(
-        score_path, audioproc_wrapper.AudioProcWrapper.OUTPUT_FILENAME)
+    audio_out_filepath = os.path.abspath(os.path.join(
+        score_path, audioproc_wrapper.AudioProcWrapper.OUTPUT_FILENAME))
 
     # Add the score to the nested dictionary.
     scores[score_name][config_name][input_name][noise_name][noise_params] = {
diff --git a/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/export.py b/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/export.py
index 4b02502..a0cb411 100644
--- a/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/export.py
+++ b/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/export.py
@@ -18,7 +18,11 @@
 
   # CSS file parameters.
   _CSS_FILEPATH = os.path.join(_PATH, 'results.css')
-  _INLINE_CSS = True
+  _INLINE_CSS = False
+
+  # JS file parameters.
+  _JS_FILEPATH = os.path.join(_PATH, 'results.js')
+  _INLINE_JS = False
 
   _NEW_LINE = '\n'
 
@@ -43,7 +47,7 @@
     html = (
         '<html>' +
         self._build_header() +
-        '<body>' +
+        '<body onload="initialize()">' +
         '<h1>Results from {}</h1>'.format(self._output_filepath) +
         self._NEW_LINE.join(tables) +
         '</body>' +
@@ -58,19 +62,34 @@
     """
     html = ['<head>', '<title>Results</title>']
 
+    # Function to append the lines of a text file to html.
+    def _embed_file(filepath):
+      with open(filepath) as f:
+        for l in f:
+          html.append(l.strip())
+
     # CSS.
     if self._INLINE_CSS:
       # Embed.
       html.append('<style>')
-      with open(self._CSS_FILEPATH) as f:
-        for l in f:
-          html.append(l.strip())
+      _embed_file(self._CSS_FILEPATH)
       html.append('</style>')
     else:
       # Link.
       html.append('<link rel="stylesheet" type="text/css" '
                   'href="file://{}?">'.format(self._CSS_FILEPATH))
 
+    # Javascript.
+    if self._INLINE_JS:
+      # Embed.
+      html.append('<script>')
+      _embed_file(self._JS_FILEPATH)
+      html.append('</script>')
+    else:
+      # Link.
+      html.append('<script src="file://{}?"></script>'.format(
+          self._JS_FILEPATH))
+
     html.append('</head>')
 
     return self._NEW_LINE.join(html)
diff --git a/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/results.css b/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/results.css
index 313b711..bae25a3 100644
--- a/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/results.css
+++ b/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/results.css
@@ -58,3 +58,33 @@
   padding: 1px;
   font-size: 0.8em;
 }
+
+.inspector{
+  background-color: #FFF;
+  border: 3px solid #000;
+  display: block;
+  padding: 0.5em;
+  position: fixed;
+  right: 1em;
+  top: 1em;
+}
+
+.inspector .property{
+  margin-bottom: 1em;
+}
+
+.inspector .property .name{
+  font-weight: bold;
+}
+
+.inspector .property .value{
+  padding-left: 0.5em;
+}
+
+.inspector .buttons{
+  margin-top: 1em;
+}
+
+.inspector .buttons button{
+  margin: 0 0.25em;
+}
diff --git a/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/results.js b/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/results.js
new file mode 100644
index 0000000..68e4ff9
--- /dev/null
+++ b/webrtc/modules/audio_processing/test/py_quality_assessment/quality_assessment/results.js
@@ -0,0 +1,186 @@
+// Copyright (c) 2017 The WebRTC project authors. All Rights Reserved.
+//
+// Use of this source code is governed by a BSD-style license
+// that can be found in the LICENSE file in the root of the source
+// tree. An additional intellectual property rights grant can be found
+// in the file PATENTS.  All contributing project authors may
+// be found in the AUTHORS file in the root of the source tree.
+
+/**
+ * Inspector UI class.
+ * @constructor
+ */
+function Inspector() {
+  this.audioPlayer_ = new Audio();
+  this.inspectorNode_ = document.createElement('div');
+  this.divNoiseGenerator_ = document.createElement('div');
+  this.divNoiseParameters_ = document.createElement('div');
+  this.buttonPlayAudioIn_ = document.createElement('button');
+  this.buttonPlayAudioOut_ = document.createElement('button');
+  this.buttonPlayAudioRef_ = document.createElement('button');
+  this.buttonStopAudio_ = document.createElement('button');
+
+  this.selectedItem_ = null;
+  this.audioInUrl_ = null;
+  this.audioOutUrl_ = null;
+  this.audioRefUrl_ = null;
+}
+
+/**
+ * Initialize.
+ */
+Inspector.prototype.init = function() {
+  window.event.stopPropagation();
+
+  // Create inspector UI.
+  this.buildInspector_();
+  var body = document.getElementsByTagName('body')[0];
+  body.appendChild(this.inspectorNode_);
+
+  // Bind click handler.
+  var self = this;
+  var items = document.getElementsByClassName('score');
+  for (var index = 0; index < items.length; index++) {
+    items[index].onclick = function() {
+      self.openInspector(this);
+    };
+  }
+
+  // Bind pressed key handlers.
+  var self = this;
+  window.onkeyup = function(e) {
+    var key = e.keyCode ? e.keyCode : e.which;
+    switch (key) {
+      case 49:  // 1.
+        self.playAudioIn();
+        break;
+      case 50:  // 2.
+        self.playAudioOut();
+        break;
+      case 51:  // 3.
+        self.playAudioRef();
+        break;
+      case 83:  // S.
+      case 115:  // s.
+        self.stopAudio();
+        break;
+    }
+  };
+};
+
+/**
+ * Open the inspector.
+ * @param {DOMElement} target: score element that has been clicked.
+ */
+Inspector.prototype.openInspector = function(target) {
+  if (this.selectedItem_ != null) {
+    this.selectedItem_.classList.remove('selected');
+  }
+  this.selectedItem_ = target;
+  this.selectedItem_.classList.add('selected');
+
+  var target = this.selectedItem_.querySelector('.noise-desc');
+  var noiseName = target.querySelector('input[name=noise_name]').value;
+  var noiseParams = target.querySelector('input[name=noise_params]').value;
+  var audioIn = target.querySelector('input[name=audio_in]').value;
+  var audioOut = target.querySelector('input[name=audio_out]').value;
+  var audioRef = target.querySelector('input[name=audio_ref]').value;
+
+  this.divNoiseGenerator_.innerHTML = noiseName;
+  this.divNoiseParameters_.innerHTML = noiseParams;
+
+  this.audioInUrl_ = audioIn;
+  this.audioOutUrl_ = audioOut;
+  this.audioRefUrl_ = audioRef;
+};
+
+/**
+ * Play APM audio input signal.
+ */
+Inspector.prototype.playAudioIn = function() {
+  this.play_(this.audioInUrl_);
+};
+
+/**
+ * Play APM audio output signal.
+ */
+Inspector.prototype.playAudioOut = function() {
+  this.play_(this.audioOutUrl_);
+};
+
+/**
+ * Play APM audio reference signal.
+ */
+Inspector.prototype.playAudioRef = function() {
+  this.play_(this.audioRefUrl_);
+};
+
+/**
+ * Stop playing audio.
+ */
+Inspector.prototype.stopAudio = function() {
+  this.audioPlayer_.pause();
+};
+
+/**
+ * Play audio file from url.
+ * @param {string} url
+ */
+Inspector.prototype.play_ = function(url) {
+  if (url == null) {
+    alert('Select a score first.');
+    return;
+  }
+
+  this.audioPlayer_.src = url;
+  this.audioPlayer_.play();
+};
+
+/**
+ * Build inspector.
+ */
+Inspector.prototype.buildInspector_ = function() {
+  var self = this;
+
+  this.inspectorNode_.setAttribute('class', 'inspector');
+  this.inspectorNode_.innerHTML = '<div class="property noise-generator">' +
+                                     '<div class="name">noise generator</div>' +
+                                   '</div>' +
+                                   '<div class="property noise-parmas">' +
+                                     '<div class="name">parameters</div>' +
+                                   '</div>' +
+                                   '<div class="buttons"></div>';
+
+  // Add value nodes.
+  function addValueNode(node, parent_selector) {
+    node.setAttribute('class', 'value');
+    node.innerHTML = '-';
+    var parentNode = self.inspectorNode_.querySelector(parent_selector);
+    parentNode.appendChild(node);
+  }
+  addValueNode(this.divNoiseGenerator_, 'div.noise-generator');
+  addValueNode(this.divNoiseParameters_, 'div.noise-parmas');
+
+  // Add buttons.
+  var buttonsNode = this.inspectorNode_.querySelector('div.buttons');
+  function addButton(node, caption, callback) {
+    node.innerHTML = caption;
+    buttonsNode.appendChild(node);
+    node.onclick = callback.bind(self);
+  }
+  addButton(this.buttonPlayAudioIn_, 'A_in (<strong>1</strong>)',
+            this.playAudioIn);
+  addButton(this.buttonPlayAudioOut_, 'A_out (<strong>2</strong>)',
+            this.playAudioOut);
+  addButton(this.buttonPlayAudioRef_, 'A_ref (<strong>3</strong>)',
+            this.playAudioRef);
+  addButton(this.buttonStopAudio_, '<strong>S</strong>top', this.stopAudio);
+};
+
+/**
+ * Instance and initialize the inspector.
+ */
+function initialize() {
+  var inspector = new Inspector();
+  inspector.init();
+}