Skip to content

Commit

Permalink
events: introduce AUDIO_TRACKS_UPDATED/AUDIO_TRACK_SWITCH/AUDIO_TRACK…
Browse files Browse the repository at this point in the history
…_LOADING/AUDIO_TRACK_LOADED

demo page : allow control of audio tracks
audiotrack-controller: re/load audio track as requested by end user
  • Loading branch information
mangui committed May 10, 2016
1 parent a876465 commit 2284bc6
Show file tree
Hide file tree
Showing 7 changed files with 173 additions and 77 deletions.
39 changes: 38 additions & 1 deletion demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
}

#customButtons input { width: 25%; display : inline-block; text-align: center; font-size: 8pt;}
#toggleButtons button { width: 24%; display : inline-block; text-align: center; font-size: 8pt; background-color: #A0A0A0 }
#toggleButtons button { width: 19%; display : inline-block; text-align: center; font-size: 8pt; background-color: #A0A0A0 }

</style>
<title>hls.js demo</title>
Expand Down Expand Up @@ -98,6 +98,7 @@ <h1 class="title"><a href="https://github.com/dailymotion/hls.js">hls.js</a> dem
<div class="center" id="toggleButtons">
<button type="button" class="btn btn-sm" onclick="$('#PlaybackControl').toggle();">toggle playback controls</button>
<button type="button" class="btn btn-sm" onclick="$('#QualityLevelControl').toggle();">toggle Quality Level controls</button>
<button type="button" class="btn btn-sm" onclick="$('#AudioTrackControl').toggle();">toggle Audio Track controls</button>
<button type="button" class="btn btn-sm" onclick="$('#MetricsDisplay').toggle();toggleMetricsDisplay();">toggle Metrics Display</button>
<button type="button" class="btn btn-sm" onclick="$('#StatsDisplay').toggle();">toggle Stats Display</button>
</div>
Expand Down Expand Up @@ -143,6 +144,17 @@ <h4> Quality Control </h4>
</table>
</div>

<div id='AudioTrackControl'>
<h4> Audio Track Control </h4>
<table>
<tr>
<td>current audio track</td>
<td width=10px></td>
<td> <div id="audioTrackControl" style="display: inline;"></div> </td>
</tr>
</table>
</div>

<div id='MetricsDisplay'>
<h4> Real Time Metrics Display </h4>
<div id="metricsButton">
Expand Down Expand Up @@ -201,6 +213,7 @@ <h4> Stats Display </h4>
$('#videoSize').change(function() { $('#video').width($('#videoSize').val()); $('#buffered_c').width($('#videoSize').val()); });
$("#PlaybackControl").hide();
$("#QualityLevelControl").hide();
$("#AudioTrackControl").hide();
$("#MetricsDisplay").hide();
$("#StatsDisplay").hide();
$('#metricsButtonWindow').toggle(windowSliding);
Expand Down Expand Up @@ -298,6 +311,10 @@ <h4> Stats Display </h4>
stats = {levelNb: data.levels.length};
updateLevelInfo();
});
hls.on(Hls.Events.AUDIO_TRACKS_UPDATED,function(event,data) {
$("#HlsStatus").text(data.audioTracks.length + " audio tracks found");
updateAudioTrackInfo();
});
hls.on(Hls.Events.LEVEL_LOADED,function(event,data) {
events.isLive = data.details.live;
var event = {
Expand Down Expand Up @@ -927,6 +944,26 @@ <h4> Stats Display </h4>
}
}

function updateAudioTrackInfo() {
var button_template = '<button type="button" class="btn btn-sm ';
var button_enabled = 'btn-primary" ';
var button_disabled = 'btn-success" ';
var html1 = '';
var audioTrackId = hls.audioTrack, len = hls.audioTracks.length;

for (var i=0; i < len; i++) {
html1 += button_template;
if(audioTrackId === i) {
html1 += button_enabled;
} else {
html1 += button_disabled;
}
html1 += 'onclick="hls.audioTrack=' + i + '">' + hls.audioTracks[i].name + '</button>';
}
$("#audioTrackControl").html(html1);
}


function level2label(index) {
if(hls && hls.levels.length-1 >= index) {
var level = hls.levels[index];
Expand Down
49 changes: 47 additions & 2 deletions src/controller/audioTrack-controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@

import Event from '../events';
import EventHandler from '../event-handler';
import {logger} from '../utils/logger';

class AudioTrackController extends EventHandler {

constructor(hls) {
super(hls, Event.MANIFEST_LOADING,
Event.MANIFEST_LOADED);
Event.MANIFEST_LOADED,
Event.AUDIO_TRACK_LOADED
);
this.tracks = [];
this.trackId = 0;
}
Expand All @@ -26,6 +29,25 @@ class AudioTrackController extends EventHandler {

onManifestLoaded(data) {
this.tracks = data.audioTracks || [];
this.hls.trigger(Event.AUDIO_TRACKS_UPDATED, {audioTracks : this.tracks});
}

onAudioTrackLoaded(data) {
if (data.id < this.tracks.length) {
logger.log(`audioTrack ${data.id} loaded`);
this.tracks[data.id].details = data.details;
// check if current playlist is a live playlist
if (data.details.live && !this.timer) {
// if live playlist we will have to reload it periodically
// set reload period to playlist target duration
this.timer = setInterval(this.ontick, 1000 * data.details.targetduration);
}
if (!data.details.live && this.timer) {
// playlist is not live and timer is armed : stopping it
clearInterval(this.timer);
this.timer = null;
}
}
}

/** get alternate audio tracks list from playlist **/
Expand All @@ -40,7 +62,30 @@ class AudioTrackController extends EventHandler {

/** select an audio track, based on its index in audio track lists**/
set audioTrack(audioTrackId) {
this.trackId = audioTrackId;
if (this.trackId !== audioTrackId || this.tracks[audioTrackId].details === undefined) {
this.setAudioTrackInternal(audioTrackId);
}
}

setAudioTrackInternal(newId) {
// check if level idx is valid
if (newId >= 0 && newId < this.tracks.length) {
// stopping live reloading timer if any
if (this.timer) {
clearInterval(this.timer);
this.timer = null;
}
this.trackId = newId;
logger.log(`switching to audioTrack ${newId}`);
this.hls.trigger(Event.AUDIO_TRACK_SWITCH, {id: newId});
var audioTrack = this.tracks[newId];
// check if we need to load playlist for this audio Track
if (audioTrack.details === undefined || audioTrack.details.live === true) {
// track not retrieved yet, or live playlist we need to (re)load it
logger.log(`(re)loading playlist for audioTrack ${newId}`);
this.hls.trigger(Event.AUDIO_TRACK_LOADING, {url: audioTrack.url, id: newId});
}
}
}
}

Expand Down
8 changes: 6 additions & 2 deletions src/errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,16 @@ export const ErrorDetails = {
MANIFEST_PARSING_ERROR: 'manifestParsingError',
// Identifier for a manifest with only incompatible codecs error - data: { url : faulty URL, reason : error reason}
MANIFEST_INCOMPATIBLE_CODECS_ERROR: 'manifestIncompatibleCodecsError',
// Identifier for playlist load error - data: { url : faulty URL, response : XHR response}
// Identifier for a level load error - data: { url : faulty URL, response : XHR response}
LEVEL_LOAD_ERROR: 'levelLoadError',
// Identifier for playlist load timeout - data: { url : faulty URL, response : XHR response}
// Identifier for a level load timeout - data: { url : faulty URL, response : XHR response}
LEVEL_LOAD_TIMEOUT: 'levelLoadTimeOut',
// Identifier for a level switch error - data: { level : faulty level Id, event : error description}
LEVEL_SWITCH_ERROR: 'levelSwitchError',
// Identifier for an audio track load error - data: { url : faulty URL, response : XHR response}
AUDIO_TRACK_LOAD_ERROR: 'audioTrackLoadError',
// Identifier for an audio track load timeout - data: { url : faulty URL, response : XHR response}
AUDIO_TRACK_LOAD_TIMEOUT: 'audioTrackLoadTimeOut',
// Identifier for fragment load error - data: { frag : fragment object, response : XHR response}
FRAG_LOAD_ERROR: 'fragLoadError',
// Identifier for fragment loop loading error - data: { frag : fragment object}
Expand Down
8 changes: 8 additions & 0 deletions src/events.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,14 @@ module.exports = {
LEVEL_PTS_UPDATED: 'hlsLevelPtsUpdated',
// fired when a level switch is requested - data: { level : id of new level }
LEVEL_SWITCH: 'hlsLevelSwitch',
// fired to notify that audio track lists has been updated data: { audioTracks : audioTracks}
AUDIO_TRACKS_UPDATED: 'hlsAudioTracksUpdated',
// fired when an audio track switch occurs - data: { id : audio track id}
AUDIO_TRACK_SWITCH: 'hlsAudioTrackSwitch',
// fired when an audio track loading starts - data: { url : audio track URL id : audio track id}
AUDIO_TRACK_LOADING: 'hlsAudioTrackLoading',
// fired when an audio track loading finishes - data: { details : levelDetails object, id : audio track id, stats : { trequest, tfirst, tload, mtime} }
AUDIO_TRACK_LOADED: 'hlsAudioTrackLoaded',
// fired when a fragment loading starts - data: { frag : fragment object}
FRAG_LOADING: 'hlsFragLoading',
// fired when a fragment loading is progressing - data: { frag : fragment object, { trequest, tfirst, loaded}}
Expand Down
2 changes: 1 addition & 1 deletion src/loader/fragment-loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ class FragmentLoader extends EventHandler {
this.frag.loaded = 0;
var config = this.hls.config;
frag.loader = this.loader = typeof(config.fLoader) !== 'undefined' ? new config.fLoader(config) : new config.loader(config);
this.loader.load(frag.url, 'arraybuffer', this.loadsuccess.bind(this), this.loaderror.bind(this), this.loadtimeout.bind(this), config.fragLoadingTimeOut, 1, 0, this.loadprogress.bind(this), frag);
this.loader.load(frag.url, null, 'arraybuffer', this.loadsuccess.bind(this), this.loaderror.bind(this), this.loadtimeout.bind(this), config.fragLoadingTimeOut, 1, 0, this.loadprogress.bind(this), frag);
}

loadsuccess(event, stats) {
Expand Down
Loading

0 comments on commit 2284bc6

Please sign in to comment.