mirror of
https://github.com/shaka-project/shaka-player.git
synced 2026-06-14 15:56:38 +03:00
4cc4e96dbd
* Updates all Copyright years to 2015. * Adds licenses annotations to all JS. * Makes all licenses identical to avoid repeated appearance in the compiled output. * Drops fileoverview annotations, which do not affect docs output. * The linter still requires fileoverview on externs. This patch required a newer closure compiler, since the previous version we used had a bug regarding license annotations that caused the license comment block to appear in the output once per file regardless of uniqueness. Change-Id: I2e9272db680cba7ecc4613d97f1d3a94ac2244cc
322 lines
8.3 KiB
JavaScript
322 lines
8.3 KiB
JavaScript
/**
|
|
* @license
|
|
* Copyright 2015 Google Inc.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
goog.provide('shaka.util.ContentDatabase');
|
|
|
|
goog.require('shaka.asserts');
|
|
goog.require('shaka.util.FakeEventTarget');
|
|
goog.require('shaka.util.PublicPromise');
|
|
goog.require('shaka.util.TypedBind');
|
|
|
|
|
|
|
|
/**
|
|
* Creates a new ContentDatabase, which manages a database for reading and
|
|
* writing streams to and from persistent storage.
|
|
*
|
|
* @param {string} mode The I/O mode, which must be either 'readonly' or
|
|
* 'readwrite'.
|
|
* @param {shaka.util.FakeEventTarget} parent
|
|
*
|
|
* @constructor
|
|
* @struct
|
|
* @extends {shaka.util.FakeEventTarget}
|
|
*/
|
|
shaka.util.ContentDatabase = function(mode, parent) {
|
|
shaka.asserts.assert(mode == 'readonly' || mode == 'readwrite');
|
|
|
|
shaka.util.FakeEventTarget.call(this, parent);
|
|
|
|
/** @private {IDBDatabase} */
|
|
this.db_ = null;
|
|
|
|
/** @private {string} */
|
|
this.mode_ = mode;
|
|
};
|
|
goog.inherits(shaka.util.ContentDatabase, shaka.util.FakeEventTarget);
|
|
|
|
|
|
/**
|
|
* The name of the IndexedDb instance.
|
|
*
|
|
* @const {string}
|
|
*/
|
|
shaka.util.ContentDatabase.DB_NAME = 'content_database';
|
|
|
|
|
|
/**
|
|
* The current version of the database.
|
|
*
|
|
* @private {number}
|
|
* @const
|
|
*/
|
|
shaka.util.ContentDatabase.DB_VERSION_ = 1;
|
|
|
|
|
|
/**
|
|
* The name of the group store in the IndexedDb instance.
|
|
*
|
|
* @private {string}
|
|
* @const
|
|
*/
|
|
shaka.util.ContentDatabase.GROUP_STORE_ = 'group_store';
|
|
|
|
|
|
/**
|
|
* The name of the index store in the IndexedDb instance.
|
|
*
|
|
* @private {string}
|
|
* @const
|
|
*/
|
|
shaka.util.ContentDatabase.INDEX_STORE_ = 'stream_index_store';
|
|
|
|
|
|
/**
|
|
* The name of the content store in the IndexedDb instance.
|
|
*
|
|
* @private {string}
|
|
* @const
|
|
*/
|
|
shaka.util.ContentDatabase.CONTENT_STORE_ = 'content_store';
|
|
|
|
|
|
/**
|
|
* @typedef {{
|
|
* group_id: number,
|
|
* stream_ids: !Array.<number>,
|
|
* session_ids: !Array.<string>,
|
|
* duration: ?number,
|
|
* key_system: string
|
|
* }}
|
|
*/
|
|
shaka.util.ContentDatabase.GroupInformation;
|
|
|
|
|
|
/**
|
|
* @typedef {{
|
|
* stream_id: number,
|
|
* mime_type: string,
|
|
* codecs: string,
|
|
* init_segment: ArrayBuffer,
|
|
* references: !Array.<shaka.util.ContentDatabase.SegmentInformation>
|
|
* }}
|
|
*/
|
|
shaka.util.ContentDatabase.StreamIndex;
|
|
|
|
|
|
/**
|
|
* @typedef {{
|
|
* index: number,
|
|
* start_time: number,
|
|
* end_time: number,
|
|
* start_byte: number,
|
|
* url: string
|
|
* }}
|
|
*/
|
|
shaka.util.ContentDatabase.SegmentInformation;
|
|
|
|
|
|
/**
|
|
* Opens a connection to the database and sets up the database if required. If
|
|
* a new version number is given the onupgradeneeded event will be fired. Must
|
|
* be run before any operations can be performed on the database.
|
|
* The database will have the structure:
|
|
* Group Store: {
|
|
* group_id: number
|
|
* stream_ids: Array.<number>
|
|
* session_ids: Array.<string>
|
|
* }
|
|
* Index Store: {
|
|
* stream_id: number,
|
|
* mime_type: string,
|
|
* references: [{shaka.util.ContentDatabase.SegmentInformation}]
|
|
* }
|
|
* Content Store: {
|
|
* stream_id: number,
|
|
* segment_id: number,
|
|
* content: ArrayBuffer
|
|
* }
|
|
* @return {!Promise}
|
|
*/
|
|
shaka.util.ContentDatabase.prototype.setUpDatabase = function() {
|
|
if (!window.indexedDB) {
|
|
var error = new Error('Persistant storage requires IndexedDB support.');
|
|
return Promise.reject(error);
|
|
}
|
|
|
|
if (this.db_) {
|
|
var error = new Error('A database connection is already open.');
|
|
return Promise.reject(error);
|
|
}
|
|
|
|
var p = new shaka.util.PublicPromise();
|
|
var indexedDB = window.indexedDB;
|
|
var request = indexedDB.open(shaka.util.ContentDatabase.DB_NAME,
|
|
shaka.util.ContentDatabase.DB_VERSION_);
|
|
|
|
request.onupgradeneeded = shaka.util.TypedBind(this,
|
|
/** @param {!Event} e */
|
|
function(e) {
|
|
this.db_ = e.target.result;
|
|
|
|
this.createStore_(
|
|
shaka.util.ContentDatabase.GROUP_STORE_, {keyPath: 'group_id'});
|
|
this.createStore_(
|
|
shaka.util.ContentDatabase.INDEX_STORE_, {keyPath: 'stream_id'});
|
|
var contentStore = this.createStore_(
|
|
shaka.util.ContentDatabase.CONTENT_STORE_, {autoIncrement: 'true'});
|
|
|
|
contentStore.createIndex('segment',
|
|
['stream_id', 'segment_id'],
|
|
{unique: true});
|
|
contentStore.createIndex('stream',
|
|
'stream_id',
|
|
{unique: false});
|
|
});
|
|
|
|
request.onsuccess = shaka.util.TypedBind(this,
|
|
/** @param {!Event} e */
|
|
function(e) {
|
|
this.db_ = e.target.result;
|
|
p.resolve();
|
|
});
|
|
|
|
request.onerror = function(e) { p.reject(request.error); };
|
|
return p;
|
|
};
|
|
|
|
|
|
/**
|
|
* Closes the connection to the database.
|
|
*/
|
|
shaka.util.ContentDatabase.prototype.closeDatabaseConnection = function() {
|
|
if (this.db_) {
|
|
this.db_.close();
|
|
this.db_ = null;
|
|
}
|
|
};
|
|
|
|
|
|
/**
|
|
* Closes the connection to the database if required and then deletes the
|
|
* database. The database can only be deleted if there are no other connections
|
|
* to the database.
|
|
* @return {!Promise}
|
|
*/
|
|
shaka.util.ContentDatabase.prototype.deleteDatabase = function() {
|
|
var p = new shaka.util.PublicPromise();
|
|
this.closeDatabaseConnection();
|
|
var deleteRequest = window.indexedDB.deleteDatabase(
|
|
shaka.util.ContentDatabase.DB_NAME);
|
|
|
|
deleteRequest.onsuccess = function(e) {
|
|
shaka.asserts.assert(e.newVersion == null);
|
|
p.resolve();
|
|
};
|
|
deleteRequest.onerror = function(e) { p.reject(deleteRequest.error); };
|
|
return p;
|
|
};
|
|
|
|
|
|
/**
|
|
* Creates an object store in the database. It will replace any previous object
|
|
* store with the same name in this database.
|
|
* @param {string} name The unique name of the object store.
|
|
* @param {Object} options The options for this object store including
|
|
* keyPath and autoIncrement, other options will be ignored.
|
|
* @return {!IDBObjectStore}
|
|
* @private
|
|
*/
|
|
shaka.util.ContentDatabase.prototype.createStore_ = function(name, options) {
|
|
if (this.db_.objectStoreNames.contains(name)) {
|
|
this.db_.deleteObjectStore(name);
|
|
}
|
|
return this.db_.createObjectStore(name, options);
|
|
};
|
|
|
|
|
|
/**
|
|
* Opens a reference to the content store.
|
|
* @return {!IDBObjectStore} A reference to the content store.
|
|
* @protected
|
|
*/
|
|
shaka.util.ContentDatabase.prototype.getContentStore = function() {
|
|
return this.getStore_(shaka.util.ContentDatabase.CONTENT_STORE_);
|
|
};
|
|
|
|
|
|
/**
|
|
* Opens a reference to the index store.
|
|
* @return {!IDBObjectStore} A reference to the index store.
|
|
* @protected
|
|
*/
|
|
shaka.util.ContentDatabase.prototype.getIndexStore = function() {
|
|
return this.getStore_(shaka.util.ContentDatabase.INDEX_STORE_);
|
|
};
|
|
|
|
|
|
/**
|
|
* Opens a reference to the group store.
|
|
* @return {!IDBObjectStore} A reference to the group store.
|
|
* @protected
|
|
*/
|
|
shaka.util.ContentDatabase.prototype.getGroupStore = function() {
|
|
return this.getStore_(shaka.util.ContentDatabase.GROUP_STORE_);
|
|
};
|
|
|
|
|
|
/**
|
|
* Opens a reference to a store.
|
|
* @param {string} storeName The name of a store in the database.
|
|
* @return {!IDBObjectStore} A reference to a store.
|
|
* @private
|
|
*/
|
|
shaka.util.ContentDatabase.prototype.getStore_ = function(storeName) {
|
|
shaka.asserts.assert(this.db_, 'A database connection should be open.');
|
|
var trans = this.db_.transaction([storeName], this.mode_);
|
|
return trans.objectStore(storeName);
|
|
};
|
|
|
|
|
|
/**
|
|
* Retrieves an item from a store in the database.
|
|
* @param {!IDBObjectStore|!IDBIndex} store The store to request an item from.
|
|
* @param {number|!Array} id The unique id(s) of item in the store.
|
|
* @return {!Promise}
|
|
* @protected
|
|
*/
|
|
shaka.util.ContentDatabase.prototype.retrieveItem = function(
|
|
store, id) {
|
|
var p = new shaka.util.PublicPromise();
|
|
|
|
var request = store.get(id);
|
|
|
|
request.onerror = function(e) { p.reject(request.error); };
|
|
request.onsuccess = function() {
|
|
if (request.result) {
|
|
p.resolve(request.result);
|
|
} else {
|
|
var error = new Error('Item not found.');
|
|
error.type = 'storage';
|
|
p.reject(error);
|
|
}
|
|
};
|
|
|
|
return p;
|
|
};
|
|
|