--- /dev/null
+/**
+ * @licstart The following is the entire license notice for the JavaScript code in this page.
+ *
+ * IceCast Stream Monitor
+ * Copyright © 2015 David Thompson <davet@gnu.org>
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Affero General Public License
+ * as published by the Free Software Foundation, either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see
+ * <http://www.gnu.org/licenses/>.
+ *
+ * @licend The above is the entire license notice for the JavaScript code in this page
+ */
+
+/**
+ * Call a function with the statistics from an IceCast mount.
+ */
+function withStreamStats(serverUrl, mount, callback) {
+ var statsUrl = serverUrl.concat('/status-json.xsl');
+
+ return $.ajax({
+ url: statsUrl,
+ type: 'GET',
+ crossDomain: true,
+ success: function(data) {
+ // Match the end of the listen URL for the mount point.
+ var regexp = new RegExp(mount.concat('$'));
+
+ // Due to <https://trac.xiph.org/ticket/2174>, we must
+ // explicitly test if icestats.source is an array.
+ if(!data.icestats.source.isArray()) {
+ data.icestats.source = [data.icestats.source];
+ }
+
+ var stats = data.icestats.source.find(function(source) {
+ return regexp.test(source.listenurl);
+ });
+
+ if(stats) {
+ callback(stats);
+ }
+ }
+ });
+}
+
+/**
+ * Schedule a thunk... forever!
+ */
+function scheduleEvery(duration, thunk) {
+ thunk();
+ setTimeout(function() {
+ scheduleEvery(duration, thunk);
+ }, duration);
+}
+
+/**
+ * Update the document with stats from an IceCast mount.
+ */
+function renderStreamStats(stats) {
+ function viewCountMessage(viewers) {
+ var noun = viewers === 1 ? 'viewer' : 'viewers';
+ return [viewers.toString(), noun].join(' ');
+ }
+
+ $('#viewer-counter').html(viewCountMessage(stats.listeners));
+ $('#speaker-name').html(stats.server_name);
+ $('#talk-title').html(stats.server_description);
+}
+
+/**
+ * Update the document every 10 seconds with stats from an IceCast
+ * mount.
+ */
+function monitorStream(mount) {
+ scheduleEvery(10000, function() {
+ withStreamStats('http://live.fsf.org', mount, renderStreamStats);
+ });
+}
<h1> Room 123 </h1>
+<p>Now presenting: <strong id="speaker-name"></strong> - "<i id="talk-title"></i>"</p>
+<p id="viewer-counter"></p>
+
<div class="row margin-top">
<div class="col-sm-8"> <!-- start of main content -->
- <div class="thumbnail"> <!-- start Live Player -->
- <video class="lp-video" controls>
- <source
- src="http://live.fsf.org/room123.ogv"
- type="video/ogg" />
- <p><em>Your browser does not support the video
- tag, <a href="http://live.fsf.org/room123.ogv">
- [ please download ]</a> the video instead.</em></p>
- </video>
- </div> <!-- end Live Player -->
+ <div class="thumbnail"> <!-- start Live Player -->
+ <video class="lp-video" controls>
+ <source src="http://live.fsf.org/test.webm" type="video/webm" />
+ <p><em>Your browser does not support the video
+ tag, <a href="http://live.fsf.org/room123.ogv">
+ [ please download ]</a> the video instead.</em></p>
+ </video>
+ </div> <!-- end Live Player -->
<!--#include virtual="/server/2015/live_menu.html" -->
<div class="panel panel-default">
<div class="panel-body text-center">
<!--#include virtual="/server/2015/footer.html"-->
<!--#include virtual="/server/2015/common_js.html"-->
+<script type="text/javascript" src="/2015/assets/js/stream.js"></script>
<script type="text/javascript">
- $("#room123").addClass("active").html("<strong>Room 123</strong>");
+ $("#room123").addClass("active").html("<strong>Room 123</strong>");
+ monitorStream('/test.webm');
</script>
<!--#include virtual="/server/2015/close.html" -->