Various fixes for offline playback.

* Remove warnings for incorrect argument counts in configure.
* Duration incorrect for multi-Period.
* Multi-Period does not always work with multi-codec.
* Progress meter visible from start and after done.
* Offline buttons enable while storing if asset is switched.

b/29777213

Change-Id: I934bec0e6b5be2d69a908629b187459a6289f7a7
This commit is contained in:
Jacob Trimble
2016-06-28 11:36:24 -07:00
parent 5ac69ca81e
commit 85fe4438b6
5 changed files with 88 additions and 36 deletions
+4
View File
@@ -182,6 +182,10 @@ summary {
cursor: pointer;
}
#progressDiv {
display: none;
}
#logSection {
display: none;
}
+1 -1
View File
@@ -109,7 +109,7 @@
<summary>Offline</summary>
<button id="storeOffline">Store</button>
<button id="deleteOffline" disabled>Delete</button>
<div>
<div id="progressDiv">
<label for="progress">Progress:</label>
<span id="progress">0</span>%
</div>
+40 -23
View File
@@ -24,9 +24,21 @@ var shakaDemo = shakaDemo || {};
shakaDemo.offlineOptGroup_ = null;
/** @private */
shakaDemo.updateButtons_ = function() {
/** @private {boolean} */
shakaDemo.offlineOperationInProgress_ = false;
/**
* @param {boolean} canHide True to hide the progress value if there isn't an
* operation going.
* @private
*/
shakaDemo.updateButtons_ = function(canHide) {
var assetList = document.getElementById('assetList');
var inProgress = shakaDemo.offlineOperationInProgress_;
document.getElementById('progressDiv').style.display =
canHide && !inProgress ? 'none' : 'block';
var option = assetList.options[assetList.selectedIndex];
var storedContent = option.storedContent;
@@ -39,14 +51,23 @@ shakaDemo.updateButtons_ = function() {
});
var storeBtn = document.getElementById('storeOffline');
storeBtn.disabled = (!supportsDrm || storedContent != null);
storeBtn.title = !supportsDrm ?
'This browser does not support persistent licenses' :
(storeBtn.disabled ? 'Selected asset is already stored offline' : '');
storeBtn.disabled = (inProgress || !supportsDrm || storedContent != null);
if (inProgress)
storeBtn.title = 'There is already an operation in progress';
else if (!supportsDrm)
storeBtn.title = 'This browser does not support persistent licenses';
else if (storeBtn.disabled)
storeBtn.title = 'Selected asset is already stored offline';
else
storeBtn.title = '';
var deleteBtn = document.getElementById('deleteOffline');
deleteBtn.disabled = (storedContent == null);
deleteBtn.title =
deleteBtn.disabled ? 'Selected asset is not stored offline' : '';
deleteBtn.disabled = (inProgress || storedContent == null);
if (inProgress)
deleteBtn.title = 'There is already an operation in progress';
else if (deleteBtn.disabled)
deleteBtn.title = 'Selected asset is not stored offline';
else
deleteBtn.title = '';
};
@@ -57,8 +78,8 @@ shakaDemo.setupOffline_ = function() {
document.getElementById('deleteOffline')
.addEventListener('click', shakaDemo.deleteAsset_);
document.getElementById('assetList')
.addEventListener('change', shakaDemo.updateButtons_);
shakaDemo.updateButtons_();
.addEventListener('change', shakaDemo.updateButtons_.bind(null, true));
shakaDemo.updateButtons_(true);
};
@@ -109,24 +130,21 @@ shakaDemo.setupOfflineAssets_ = function() {
/** @private */
shakaDemo.storeAsset_ = function() {
shakaDemo.closeError();
shakaDemo.offlineOperationInProgress_ = true;
shakaDemo.updateButtons_(false);
var assetList = document.getElementById('assetList');
var progress = document.getElementById('progress');
var storeBtn = document.getElementById('storeOffline');
var deleteBtn = document.getElementById('deleteOffline');
var option = assetList.options[assetList.selectedIndex];
var asset = shakaDemo.preparePlayer_(option.asset);
progress.textContent = '0';
storeBtn.disabled = true;
deleteBtn.disabled = true;
var metadata = {name: asset.name || asset.manifestUri};
var storage = new shaka.offline.Storage(shakaDemo.player_);
storage.configure(/** @type {shakaExtern.OfflineConfiguration} */ ({
progressCallback: function(data, percent) {
var progress = document.getElementById('progress');
progress.textContent = (percent * 100).toFixed(2);
}
}));
@@ -137,7 +155,8 @@ shakaDemo.storeAsset_ = function() {
var error = /** @type {!shaka.util.Error} */(reason);
shakaDemo.onError_(error);
}).then(function() {
shakaDemo.updateButtons_();
shakaDemo.offlineOperationInProgress_ = false;
shakaDemo.updateButtons_(false);
return storage.destroy();
});
};
@@ -146,15 +165,12 @@ shakaDemo.storeAsset_ = function() {
/** @private */
shakaDemo.deleteAsset_ = function() {
shakaDemo.closeError();
shakaDemo.offlineOperationInProgress_ = true;
shakaDemo.updateButtons_(false);
var assetList = document.getElementById('assetList');
var storeBtn = document.getElementById('storeOffline');
var deleteBtn = document.getElementById('deleteOffline');
var option = assetList.options[assetList.selectedIndex];
storeBtn.disabled = true;
deleteBtn.disabled = true;
var storage = new shaka.offline.Storage(shakaDemo.player_);
storage.configure(/** @type {shakaExtern.OfflineConfiguration} */ ({
progressCallback: function(data, percent) {
@@ -169,7 +185,8 @@ shakaDemo.deleteAsset_ = function() {
var error = /** @type {!shaka.util.Error} */(reason);
shakaDemo.onError_(error);
}).then(function() {
shakaDemo.updateButtons_();
shakaDemo.offlineOperationInProgress_ = false;
shakaDemo.updateButtons_(false);
return storage.destroy();
});
};
+42 -5
View File
@@ -62,6 +62,9 @@ shaka.offline.Storage = function(player) {
/** @private {boolean} */
this.storeInProgress_ = false;
/** @private {Array.<shakaExtern.Track>} */
this.firstPeriodTracks_ = null;
/**
* The IDs of the segments that have been stored for an in-progress store().
* This is used to cleanup in destroy().
@@ -514,7 +517,7 @@ shaka.offline.Storage.prototype.defaultTrackSelect_ = function(tracks) {
shaka.offline.Storage.prototype.defaultConfig_ = function() {
return {
trackSelectionCallback: this.defaultTrackSelect_.bind(this),
progressCallback: function() {}
progressCallback: new Function('storedContent', 'percent', '')
};
};
@@ -537,8 +540,33 @@ shaka.offline.Storage.prototype.initIfNeeded_ = function() {
* @private
*/
shaka.offline.Storage.prototype.filterPeriod_ = function(period) {
function getFirstStreamOfType(period, tracks, contentType) {
var tracksOfType =
tracks.filter(function(track) { return track.type == contentType; });
if (tracksOfType.length == 0)
return null;
var data =
shaka.util.StreamUtils.findStreamForTrack(period, tracksOfType[0]);
goog.asserts.assert(
data, 'Could not find stream with id ' + tracksOfType[0].id);
return data.stream;
}
var StreamUtils = shaka.util.StreamUtils;
StreamUtils.filterPeriod(this.drmEngine_, /* activeStreams */ {}, period);
var activeStreams = {};
if (this.firstPeriodTracks_) {
// Use the first stream of each content type as the "active stream". This
// is then used to filter out the streams that are not compatible with it.
// This ensures that in multi-Period content, all Periods have streams
// with compatible MIME types.
activeStreams = {
'video': getFirstStreamOfType(
this.manifest_.periods[0], this.firstPeriodTracks_, 'video'),
'audio': getFirstStreamOfType(
this.manifest_.periods[0], this.firstPeriodTracks_, 'audio')
};
}
StreamUtils.filterPeriod(this.drmEngine_, activeStreams, period);
StreamUtils.applyRestrictions(
period, this.player_.getConfiguration().restrictions);
};
@@ -556,6 +584,7 @@ shaka.offline.Storage.prototype.cleanup_ = function() {
this.drmEngine_ = null;
this.manifest_ = null;
this.storeInProgress_ = false;
this.firstPeriodTracks_ = null;
this.inProgressSegmentIds_ = [];
this.manifestId_ = -1;
return ret;
@@ -631,13 +660,19 @@ shaka.offline.Storage.prototype.createOfflineManifest_ = function(
shaka.offline.Storage.prototype.createPeriod_ = function(period) {
var allTracks = shaka.util.StreamUtils.getTracks(period, null);
var tracks = this.config_.trackSelectionCallback(allTracks);
if (this.firstPeriodTracks_ == null) {
this.firstPeriodTracks_ = tracks;
// Now that the first tracks are chosen, filter again. This ensures all
// Periods have compatible content types.
this.manifest_.periods.forEach(this.filterPeriod_.bind(this));
}
// TODO(modmaker): Issue a warning if multiple tracks of the same variety
// are selected (type, kind, and language).
var streams = tracks.map(function(track) {
var data = shaka.util.StreamUtils.findStreamForTrack(period, track);
goog.asserts.assert(data, 'Could not find track with id ' + track.id);
return this.createStream_(data.streamSet, data.stream);
return this.createStream_(period, data.streamSet, data.stream);
}.bind(this));
return {
@@ -651,12 +686,14 @@ shaka.offline.Storage.prototype.createPeriod_ = function(period) {
* Converts a manifest stream to a database stream. This will search the
* segment index and add all the segments to the download manager.
*
* @param {shakaExtern.Period} period
* @param {shakaExtern.StreamSet} streamSet
* @param {shakaExtern.Stream} stream
* @return {shakaExtern.StreamDB}
* @private
*/
shaka.offline.Storage.prototype.createStream_ = function(streamSet, stream) {
shaka.offline.Storage.prototype.createStream_ = function(
period, streamSet, stream) {
/** @type {!Array.<shakaExtern.SegmentDB>} */
var segmentsDb = [];
var startTime = this.manifest_.presentationTimeline.getEarliestStart();
@@ -686,7 +723,7 @@ shaka.offline.Storage.prototype.createStream_ = function(streamSet, stream) {
uri: 'offline:' + this.manifestId_ + '/' + stream.id + '/' + id
});
endTime = ref.endTime;
endTime = ref.endTime + period.startTime;
ref = stream.getSegmentReference(++i);
}
+1 -7
View File
@@ -1167,13 +1167,7 @@ shaka.Player.prototype.defaultConfig_ = function() {
manifest: {
retryParameters: shaka.net.NetworkingEngine.defaultRetryParameters(),
dash: {
customScheme: function(node) {
// Reference node to keep closure from removing it.
// If the argument is removed, it breaks our function length check
// in mergeConfigObjects_().
// TODO: Find a better solution if possible.
if (node) return null;
},
customScheme: new Function('node', ''),
clockSyncUri: ''
}
},