diff --git a/demo/index.html b/demo/index.html index d1d6a5b8989..32cbab23f54 100644 --- a/demo/index.html +++ b/demo/index.html @@ -1,22 +1,16 @@ - - - - + hls.js demo - - - + -
@@ -49,86 +43,77 @@

- -
- - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + +
- +
+
+
+ Loading... +
+
+
+ + +
+
-
- - -

- +
+

 
diff --git a/demo/main.js b/demo/main.js
index 95bf23aa546..29432071819 100644
--- a/demo/main.js
+++ b/demo/main.js
@@ -1,5 +1,10 @@
 import {sortObject, copyTextToClipboard} from './demo-utils'
 
+const STORAGE_KEYS = {
+  Editor_Persistence: 'hlsjs:config-editor-persist',
+  Hls_Config        : 'hlsjs:config'
+};
+
 const testStreams = require('../tests/test-streams');
 const defaultTestStreamUrl = testStreams['bbb'].url;
 const sourceURL = decodeURIComponent(getURLParam('src', defaultTestStreamUrl))
@@ -11,13 +16,15 @@ if (demoConfig) {
   demoConfig = {}
 }
 
+const hlsjsDefaults = {
+  debug: true,
+  enableWorker: true
+};
+
 let enableStreaming = getDemoConfigPropOrDefault('enableStreaming', true);
 let autoRecoverError = getDemoConfigPropOrDefault('autoRecoverError', true);
-let enableWorker = getDemoConfigPropOrDefault('enableWorker', true);
 let levelCapping = getDemoConfigPropOrDefault('levelCapping', -1);
 let limitMetrics = getDemoConfigPropOrDefault('limitMetrics', -1);
-let defaultAudioCodec = getDemoConfigPropOrDefault('defaultAudioCodec', undefined);
-let widevineLicenseUrl = getDemoConfigPropOrDefault('widevineLicenseURL', undefined);
 let dumpfMP4 = getDemoConfigPropOrDefault('dumpfMP4', false);
 
 let bufferingIdx = -1;
@@ -35,8 +42,12 @@ let events;
 let stats;
 let tracks;
 let fmp4Data;
+let configPersistenceEnabled = false;
+let configEditor = null;
 
 $(document).ready(function() {
+  setupConfigEditor();
+
   Object.keys(testStreams).forEach((key) => {
     const stream = testStreams[key];
     const option = new Option(stream.description, key);
@@ -70,11 +81,6 @@ $(document).ready(function() {
     onDemoConfigChanged();
   });
 
-  $('#enableWorker').click(function() {
-    enableWorker = this.checked;
-    onDemoConfigChanged();
-  });
-
   $('#dumpfMP4').click(function() {
     dumpfMP4 = this.checked;
     onDemoConfigChanged();
@@ -90,18 +96,11 @@ $(document).ready(function() {
     onDemoConfigChanged();
   });
 
-  $('#defaultAudioCodec').change(function() {
-    defaultAudioCodec = this.value;
-    onDemoConfigChanged();
-  });
-
   $('#limitMetrics').val(limitMetrics);
   $('#enableStreaming').prop('checked', enableStreaming );
   $('#autoRecoverError').prop('checked', autoRecoverError );
-  $('#enableWorker').prop('checked', enableWorker );
   $('#dumpfMP4').prop('checked', dumpfMP4 );
   $('#levelCapping').val(levelCapping);
-  $('#defaultAudioCodec').val(defaultAudioCodec || 'undefined');
 
   $('h2').append(' v' + Hls.version + '');
   $('#currentVersion').html('Hls version:' + Hls.version);
@@ -146,7 +145,7 @@ function setupGlobals() {
   window.createfMP4 = createfMP4;
   window.goToMetricsPermaLink = goToMetricsPermaLink;
   window.toggleTab = toggleTab;
-  window.onDemoConfigChanged = onDemoConfigChanged;
+  window.applyConfigEditorValue = applyConfigEditorValue;
 }
 
 function trimArray( target, limit ) {
@@ -202,29 +201,14 @@ function loadSelectedStream() {
 
   logStatus('Loading ' + url);
 
-  if (widevineLicenseUrl) {
-    widevineLicenseUrl = unescape(widevineLicenseUrl)
-  }
 
-  const hlsConfig = {
-    debug            : true,
-    enableWorker     : enableWorker,
-    defaultAudioCodec: defaultAudioCodec,
-    widevineLicenseUrl: widevineLicenseUrl
-  };
+  // Extending both a demo-specific config and the user config which can override all
+  const hlsConfig = $.extend({}, hlsjsDefaults, getEditorValue({ parse: true }));
 
   if (selectedTestStream && selectedTestStream.config) {
-    Object.assign(hlsConfig, selectedTestStream.config)
-  }
-
-  if (hlsConfig.widevineLicenseUrl) {
-    $('#widevineLicenseUrl').val(hlsConfig.widevineLicenseUrl);
-  }
-
-  widevineLicenseUrl = hlsConfig.widevineLicenseUrl = $('#widevineLicenseUrl').val();
-
-  if (hlsConfig.widevineLicenseUrl) {
-    hlsConfig.emeEnabled = true;
+    console.info('[loadSelectedStream] extending hls config with stream-specific config: ', selectedTestStream.config);
+    $.extend(hlsConfig, selectedTestStream.config);
+    updateConfigEditorValue(hlsConfig);
   }
 
   onDemoConfigChanged();
@@ -943,7 +927,6 @@ function copyMetricsToClipBoard() {
 function goToMetrics() {
   let url = document.URL;
   url = url.substr(0, url.lastIndexOf('/')+1) + 'metrics.html';
-  // console.log(url);
   window.open(url, '_blank');
 }
 
@@ -951,7 +934,6 @@ function goToMetricsPermaLink() {
   let url = document.URL;
   let b64 = getMetrics();
   url = url.substr(0, url.lastIndexOf('/')+1) + 'metrics.html#data=' + b64;
-  // console.log(url);
   window.open(url, '_blank');
 }
 
@@ -1137,25 +1119,101 @@ function getURLParam(sParam, defaultValue) {
 }
 
 function onDemoConfigChanged() {
-  const url = $('#streamURL').val();
-
   demoConfig = {
     enableStreaming,
     autoRecoverError,
-    enableWorker,
     dumpfMP4,
     levelCapping,
     limitMetrics,
-    defaultAudioCodec,
-    widevineLicenseUrl: escape(widevineLicenseUrl)
+  };
+
+  if (configPersistenceEnabled) {
+    persistEditorValue();
+  }
+
+  const serializedDemoConfig = btoa(JSON.stringify(demoConfig));
+  const baseURL = document.URL.split('?')[0];
+  const streamURL = $('#streamURL').val();
+  const permalinkURL = `${baseURL}?src=${encodeURIComponent(streamURL)}&demoConfig=${serializedDemoConfig}`;
+
+  $('#StreamPermalink').html(`${permalinkURL}`);
+}
+
+function onConfigPersistenceChanged(event) {
+  configPersistenceEnabled = event.target.checked;
+  localStorage.setItem(STORAGE_KEYS.Editor_Persistence, JSON.stringify(configPersistenceEnabled));
+
+  if (configPersistenceEnabled) {
+    persistEditorValue();
+  } else {
+    localStorage.removeItem(STORAGE_KEYS.Hls_Config);
+  }
+}
+
+function getEditorValue(options) {
+  options = $.extend({ parse: false }, options || {});
+  const value = configEditor.session.getValue();
+
+  if (options.parse) {
+    try {
+      value = JSON.parse(value);
+    } catch (e) {
+      console.warn('[getEditorValue] could not parse editor value', e);
+      value = {};
+    }
+  }
+
+  return value;
+}
+
+function getPersistedHlsConfig() {
+  var value = localStorage.getItem(STORAGE_KEYS.Hls_Config);
+
+  if (value === null) {
+    return value;
+  }
+
+  try {
+    value = JSON.parse(value);
+  } catch (e) {
+    console.warn('[getPersistedHlsConfig] could not hls config json', e);
+    value = {};
   }
 
-  const serializedDemoConfig = btoa(JSON.stringify(demoConfig))
+  return value;
+}
+
+function persistEditorValue() {
+  localStorage.setItem(STORAGE_KEYS.Hls_Config, getEditorValue());
+}
+
+function setupConfigEditor() {
+  configEditor = ace.edit('config-editor');
+  configEditor.setTheme('ace/theme/github');
+  configEditor.session.setMode('ace/mode/json');
+
+  const contents = hlsjsDefaults;
+  const shouldRestorePersisted = JSON.parse(localStorage.getItem(STORAGE_KEYS.Editor_Persistence)) === true;
+
+  if (shouldRestorePersisted) {
+    $.extend(contents, getPersistedHlsConfig());
+  }
 
-  const baseURL = document.URL.split('?')[0]
-  const permalinkURL = baseURL + `?src=${encodeURIComponent(url)}&demoConfig=${serializedDemoConfig}`
+  const elPersistence = document.querySelector('#configPersistence');
+  elPersistence.addEventListener('change', onConfigPersistenceChanged);
+  elPersistence.checked = shouldRestorePersisted;
 
-  $('#StreamPermalink').html('' + permalinkURL + '');
+  updateConfigEditorValue(contents);
+}
+
+function updateConfigEditorValue(obj) {
+  const json = JSON.stringify(obj, null, 2);
+  configEditor.session.setValue(json);
+}
+
+function applyConfigEditorValue() {
+  onDemoConfigChanged();
+  loadSelectedStream();
 }
 
 function createfMP4(type) {
diff --git a/demo/style.css b/demo/style.css
index 43fc384839c..e27a04b80b4 100644
--- a/demo/style.css
+++ b/demo/style.css
@@ -9,12 +9,12 @@ th, td {
 select {
   padding: 2px 15px;
   background-color: rgb(181, 222, 255);
-  font-weight: bolder;
-
+  font-weight: 600;
+  padding: 5px 0;
 }
 
 select option {
-  font-size: 10pt;
+  font-size: 11px;
 }
 
 .innerControls input {
@@ -23,44 +23,86 @@ select option {
 }
 
 #controls {
-    width: 70%;
-    min-width: 615px;
-    padding: 3px;
-    margin: 0px auto 20px auto;
-    border: 1px solid #606060;
-    overflow: hidden;
+  display: flex;
+  flex-direction: column;
+  width: 80%;
+  max-width: 1200px;
+  margin: 0 auto 20px auto;
+  border: 1px solid #606060;
+  overflow: hidden;
+}
+
+.demo-controls-wrapper {
+  flex: 1 1 auto;
+  max-width: 100%;
+  padding: 5px 5px 0 3px;
+}
+
+.config-editor-wrapper {
+  flex: 1 1 auto;
+  display: flex;
+  flex-direction: column;
+  border-top: solid 1px #ccc;
+  height: 256px;
+}
+
+.config-editor-container {
+  flex: 1 1 auto;
+  position: relative;
+  width: 100%;
+  height: 100%;
+}
+
+#config-editor {
+  position: absolute;
+  top: 0;
+  right: 0;
+  bottom: 0;
+  left: 0;
+}
+
+.config-editor-commands {
+  flex: 1 1 auto;
+  background-color: #ddd;
+  border-top: solid 1px #ccc;
+  padding: 5px;
+  display: flex;
+  justify-content: space-between;
+  align-items: center;
+}
+
+.config-editor-commands label {
+  margin-bottom: 0;
+}
+
+.config-editor-commands button {
+  padding: 5px 8px;
+  font-size: 14px;
 }
 
 .innerControls {
-    display:block;
-    float: left;
-    width: 99%;
-    margin: 3px;
-    padding-left: 3px;
-    font-size: 10pt
+  display: flex;
+  font-size: 12px;
+  align-items: center;
+  margin-bottom: 5px;
+  padding-left: 5px;
+  justify-content: space-between;
 }
 
 .videoCentered {
-    width: 720px;
-    margin-left: auto;
-    margin-right: auto;
-    display: block
+  width: 720px;
+  margin-left: auto;
+  margin-right: auto;
+  display: block
 }
 
 .center {
-    width: 70%;
-    min-width: 615px;
-    overflow: hidden;
-    margin-left: auto;
-    margin-right: auto;
-    display: block
-}
-
-#customButtons input {
-  width: 25%;
-  display : inline-block;
-  text-align: center;
-  font-size: 8pt;
+  width: 70%;
+  min-width: 615px;
+  overflow: hidden;
+  margin-left: auto;
+  margin-right: auto;
+  display: block
 }
 
 #toggleButtons button {
@@ -76,12 +118,57 @@ select option {
   height: auto;
   max-height: 4em;
   overflow: auto;
-  /*overflow-y: none;*/
 }
 
 #errorOut {
   height: auto;
   max-height: 4em;
   overflow: auto;
-  /*overflow-y: none;*/
+}
+
+
+#streamURL,
+#streamSelect {
+  width: calc(100% - 4px);
+  margin-left: 3px;
+}
+
+#streamURL {
+  margin-bottom: 10px;
+  padding-left: 3px;
+}
+
+#streamSelect {
+  padding: 5px 0;
+}
+
+#StreamPermalink {
+  flex: 1 1 auto;
+  min-width: 0;
+  overflow-wrap: break-word;
+  overflow: hidden;  /* for IE11 */
+  padding: 10px 0 0 10px;
+}
+
+#StreamPermalink a {
+  font-size: 10px;
+  font-family: monospace;
+}
+
+/* Small devices (portrait tablets and large phones, 600px and up) */
+@media only screen and (min-width: 600px) {
+  #controls {
+    flex-direction: row;
+  }
+
+  .demo-controls-wrapper {
+    max-width: 50%;
+  }
+
+  .config-editor-wrapper {
+    height: auto;
+    border-top: 0;
+    border-left: solid 1px #ccc;
+  }
+
 }
\ No newline at end of file