Skip to content

Commit 6058429

Browse files
committed
Fix an error when no buffer sink is available due to media segments have been preloaded
1 parent 612a36e commit 6058429

File tree

4 files changed

+79
-49
lines changed

4 files changed

+79
-49
lines changed

src/streaming/SourceBufferSink.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ function SourceBufferSink(config) {
264264

265265
function getAllBufferRanges() {
266266
try {
267-
return buffer.buffered;
267+
return buffer?.buffered;
268268
} catch (e) {
269269
logger.error('getAllBufferRanges exception: ' + e.message);
270270
return null;
@@ -458,7 +458,7 @@ function SourceBufferSink(config) {
458458
try {
459459
callbacks.push(callback);
460460

461-
if (!buffer.updating) {
461+
if (buffer && !buffer.updating) {
462462
_executeCallback();
463463
}
464464
} catch (e) {

src/streaming/Stream.js

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -189,14 +189,14 @@ function Stream(config) {
189189
/**
190190
* Activates Stream by re-initializing some of its components
191191
* @param {MediaSource} mediaSource
192-
* @param {array} previousBufferSinks
192+
* @param {array} previousSourceBufferSinks
193193
* @param representationsFromPreviousPeriod
194194
* @memberof Stream#
195195
*/
196-
function activate(mediaSource, previousBufferSinks, representationsFromPreviousPeriod = []) {
196+
function activate(mediaSource, previousSourceBufferSinks, representationsFromPreviousPeriod = []) {
197197
return new Promise((resolve, reject) => {
198198
if (isActive) {
199-
resolve(previousBufferSinks);
199+
resolve();
200200
return;
201201
}
202202

@@ -205,21 +205,21 @@ function Stream(config) {
205205
eventBus.trigger(Events.STREAM_ACTIVATED, {
206206
streamInfo
207207
});
208-
resolve(previousBufferSinks);
208+
resolve();
209209
return;
210210
}
211211

212212

213-
_initializeMedia(mediaSource, previousBufferSinks, representationsFromPreviousPeriod)
214-
.then((bufferSinks) => {
213+
_initializeMedia(mediaSource, previousSourceBufferSinks, representationsFromPreviousPeriod)
214+
.then(() => {
215215
isActive = true;
216216
if (representationsFromPreviousPeriod && representationsFromPreviousPeriod.length > 0) {
217217
startScheduleControllers();
218218
}
219219
eventBus.trigger(Events.STREAM_ACTIVATED, {
220220
streamInfo
221221
});
222-
resolve(bufferSinks);
222+
resolve();
223223
})
224224
.catch((e) => {
225225
reject(e);
@@ -256,23 +256,23 @@ function Stream(config) {
256256
/**
257257
*
258258
* @param {object} mediaSource
259-
* @param {array} previousBufferSinks
259+
* @param {array} previousSourceBufferSinks
260260
* @param representationsFromPreviousPeriod
261261
* @return {Promise<Array>}
262262
* @private
263263
*/
264-
function _initializeMedia(mediaSource, previousBufferSinks, representationsFromPreviousPeriod = []) {
265-
return _commonMediaInitialization(mediaSource, previousBufferSinks, representationsFromPreviousPeriod);
264+
function _initializeMedia(mediaSource, previousSourceBufferSinks, representationsFromPreviousPeriod = []) {
265+
return _commonMediaInitialization(mediaSource, previousSourceBufferSinks, representationsFromPreviousPeriod);
266266
}
267267

268268
/**
269269
*
270270
* @param {object} mediaSource
271-
* @param {array} previousBufferSinks
271+
* @param {array} previousSourceBufferSinks
272272
* @return {Promise<array>}
273273
* @private
274274
*/
275-
function _commonMediaInitialization(mediaSource, previousBufferSinks, representationsFromPreviousPeriod) {
275+
function _commonMediaInitialization(mediaSource, previousSourceBufferSinks, representationsFromPreviousPeriod) {
276276
return new Promise((resolve, reject) => {
277277
checkConfig();
278278

@@ -293,7 +293,7 @@ function Stream(config) {
293293

294294
Promise.all(promises)
295295
.then(() => {
296-
return _createBufferSinks(previousBufferSinks)
296+
return _createBufferSinks(previousSourceBufferSinks)
297297
})
298298
.then((bufferSinks) => {
299299
if (streamProcessors.length === 0) {
@@ -504,16 +504,16 @@ function Stream(config) {
504504

505505
/**
506506
* Creates the SourceBufferSink objects for all StreamProcessors
507-
* @param {array} previousBuffersSinks
507+
* @param {array} previousSourceBufferSinks
508508
* @return {Promise<object>}
509509
* @private
510510
*/
511-
function _createBufferSinks(previousBuffersSinks) {
511+
function _createBufferSinks(previousSourceBufferSinks) {
512512
return new Promise((resolve) => {
513513
const buffers = {};
514514
const promises = streamProcessors.map((sp) => {
515515
const oldRepresentation = sp.getRepresentation();
516-
return sp.createBufferSinks(previousBuffersSinks, oldRepresentation);
516+
return sp.createBufferSinks(previousSourceBufferSinks, oldRepresentation);
517517
});
518518

519519
Promise.all(promises)

src/streaming/controllers/BufferController.js

Lines changed: 15 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -161,18 +161,18 @@ function BufferController(config) {
161161
/**
162162
* Creates a SourceBufferSink object
163163
* @param {object} mediaInfo
164-
* @param {array} oldBufferSinks
164+
* @param {Map<any, any>} previousBufferSinks
165165
* @return {Promise<Object>} SourceBufferSink
166166
*/
167-
function createBufferSink(mediaInfo, oldBufferSinks = [], oldRepresentation) {
167+
function createBufferSink(mediaInfo, previousBufferSinks = new Map(), oldRepresentation) {
168168
return new Promise((resolve, reject) => {
169169
if (!initCache || !mediaInfo) {
170170
resolve(null);
171171
return;
172172
}
173173
if (mediaSource) {
174174
isPrebuffering = false;
175-
_initializeSinkForMseBuffering(mediaInfo, oldBufferSinks, oldRepresentation)
175+
_initializeSinkForMseBuffering(mediaInfo, previousBufferSinks, oldRepresentation)
176176
.then((sink) => {
177177
resolve(sink);
178178
})
@@ -205,14 +205,14 @@ function BufferController(config) {
205205
})
206206
}
207207

208-
function _initializeSinkForMseBuffering(mediaInfo, oldBufferSinks, oldRepresentation) {
208+
function _initializeSinkForMseBuffering(mediaInfo, previousBufferSinks, oldRepresentation) {
209209
return new Promise((resolve) => {
210210
sourceBufferSink = SourceBufferSink(context).create({
211211
mediaSource,
212212
textController,
213213
eventBus
214214
});
215-
_initializeSink(mediaInfo, oldBufferSinks, oldRepresentation)
215+
_initializeSink(mediaInfo, previousBufferSinks, oldRepresentation)
216216
.then(() => {
217217
return updateBufferTimestampOffset(representationController.getCurrentRepresentation());
218218
})
@@ -226,18 +226,23 @@ function BufferController(config) {
226226
})
227227
}
228228

229-
function _initializeSink(mediaInfo, oldBufferSinks, oldRepresentation) {
229+
function _initializeSink(mediaInfo, previousBufferSinks, oldRepresentation) {
230230
const newRepresentation = representationController.getCurrentRepresentation();
231+
let previousBufferSink = null;
231232

232-
if (oldBufferSinks && oldBufferSinks[type] && (type === Constants.VIDEO || type === Constants.AUDIO)) {
233-
return _initializeSinkForStreamSwitch(mediaInfo, newRepresentation, oldBufferSinks, oldRepresentation)
233+
if (type === Constants.VIDEO || type === Constants.AUDIO) {
234+
previousBufferSink = previousBufferSinks.get(type);
235+
}
236+
237+
if (previousBufferSink) {
238+
return _initializeSinkForBufferReuse(mediaInfo, newRepresentation, previousBufferSink, oldRepresentation)
234239
} else {
235240
return _initializeSinkForFirstUse(mediaInfo, newRepresentation);
236241
}
237242
}
238243

239-
function _initializeSinkForStreamSwitch(mediaInfo, newRepresentation, oldBufferSinks, oldRepresentation) {
240-
sourceBufferSink.initializeForStreamSwitch(mediaInfo, newRepresentation, oldBufferSinks[type]);
244+
function _initializeSinkForBufferReuse(mediaInfo, newRepresentation, previousBufferSink, oldRepresentation) {
245+
sourceBufferSink.initializeForStreamSwitch(mediaInfo, newRepresentation, previousBufferSink);
241246

242247
const promises = [];
243248
promises.push(sourceBufferSink.abortBeforeAppend());

src/streaming/controllers/StreamController.js

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ function StreamController() {
6464
protectionData, extUrlQueryInfoController,
6565
autoPlay, isStreamSwitchingInProgress, hasMediaError, hasInitialisationError, mediaSource, videoModel,
6666
playbackController, serviceDescriptionController, mediaPlayerModel, customParametersModel, isPaused,
67-
initialPlayback, initialSteeringRequest, playbackEndedTimerInterval, bufferSinks, preloadingStreams, settings,
67+
initialPlayback, initialSteeringRequest, playbackEndedTimerInterval, preloadingStreams, settings,
6868
firstLicenseIsFetched, waitForPlaybackStartTimeout, providedStartTime, errorInformation;
6969

7070
function setup() {
@@ -430,6 +430,7 @@ function StreamController() {
430430

431431
let keepBuffers = false;
432432
let representationsFromPreviousPeriod = [];
433+
let sourceBufferSinksFromPreviousPeriod = _getSourceBufferSinksFromPreviousPeriod(previousStream);
433434
activeStream = stream;
434435

435436
if (previousStream) {
@@ -451,9 +452,15 @@ function StreamController() {
451452

452453
// If we have a video element we are not preloading into a virtual buffer
453454
if (videoModel.getElement()) {
454-
_openMediaSource({ seekTime, keepBuffers, streamActivated: false, representationsFromPreviousPeriod });
455+
_openMediaSource({
456+
seekTime,
457+
keepBuffers,
458+
sourceBufferSinksFromPreviousPeriod,
459+
streamActivated: false,
460+
representationsFromPreviousPeriod
461+
});
455462
} else {
456-
_activateStream({ seekTime, keepBuffers });
463+
_activateStream({ seekTime, keepBuffers, sourceBufferSinksFromPreviousPeriod });
457464
}
458465
} catch (e) {
459466
isStreamSwitchingInProgress = false;
@@ -524,11 +531,8 @@ function StreamController() {
524531
*/
525532
function _activateStream(inputParameters) {
526533
const representationsFromPreviousPeriod = inputParameters.representationsFromPreviousPeriod || [];
527-
activeStream.activate(mediaSource, inputParameters.keepBuffers ? bufferSinks : undefined, representationsFromPreviousPeriod)
528-
.then((sinks) => {
529-
if (sinks) {
530-
bufferSinks = sinks;
531-
}
534+
activeStream.activate(mediaSource, inputParameters.sourceBufferSinksFromPreviousPeriod, representationsFromPreviousPeriod)
535+
.then(() => {
532536

533537
// Set the initial time for this stream in the StreamProcessor
534538
if (!isNaN(inputParameters.seekTime)) {
@@ -549,6 +553,25 @@ function StreamController() {
549553
})
550554
}
551555

556+
function _getSourceBufferSinksFromPreviousPeriod(previousStream) {
557+
const sourceBufferSinkMap = new Map();
558+
559+
if (!previousStream) {
560+
return sourceBufferSinkMap;
561+
}
562+
563+
const previousStreamProcessors = previousStream ? previousStream.getStreamProcessors() : [];
564+
565+
previousStreamProcessors.forEach((streamProcessor) => {
566+
const sourceBufferSink = streamProcessor.getBuffer();
567+
if (sourceBufferSink) {
568+
sourceBufferSinkMap.set(sourceBufferSink.getType(), sourceBufferSink);
569+
}
570+
})
571+
572+
return sourceBufferSinkMap
573+
}
574+
552575
/**
553576
* A playback seeking event was triggered. We need to disable the preloading streams and call the respective seeking handler.
554577
* We distinguish between inner period seeks and outer period seeks
@@ -693,17 +716,22 @@ function StreamController() {
693716
*/
694717
function _onStreamCanLoadNext(nextStream, previousStream = null) {
695718

696-
if (mediaSource && !nextStream.getPreloaded()) {
697-
let seamlessPeriodSwitch = _canSourceBuffersBeKept(nextStream, previousStream);
719+
if (!mediaSource || nextStream.getPreloaded()) {
720+
return;
721+
}
698722

699-
if (seamlessPeriodSwitch) {
700-
const representationsFromPreviousPeriod = _getRepresentationsFromPreviousPeriod(previousStream);
701-
nextStream.startPreloading(mediaSource, bufferSinks, representationsFromPreviousPeriod)
702-
.then(() => {
703-
preloadingStreams.push(nextStream);
704-
});
705-
}
723+
let seamlessPeriodSwitch = _canSourceBuffersBeKept(nextStream, previousStream);
724+
725+
if (!seamlessPeriodSwitch) {
726+
return;
706727
}
728+
729+
const representationsFromPreviousPeriod = _getRepresentationsFromPreviousPeriod(previousStream);
730+
const previousSourceBufferSinks = _getSourceBufferSinksFromPreviousPeriod(previousStream);
731+
nextStream.startPreloading(mediaSource, previousSourceBufferSinks, representationsFromPreviousPeriod)
732+
.then(() => {
733+
preloadingStreams.push(nextStream);
734+
});
707735
}
708736

709737
/**
@@ -904,9 +932,7 @@ function StreamController() {
904932

905933
// If the preloading for the current stream is not scheduled, but its predecessor has finished buffering we can start prebuffering this stream
906934
if (!stream.getPreloaded() && previousStream.getHasFinishedBuffering()) {
907-
if (mediaSource) {
908-
_onStreamCanLoadNext(stream, previousStream);
909-
}
935+
_onStreamCanLoadNext(stream, previousStream);
910936
}
911937
i += 1;
912938
}
@@ -1307,7 +1333,6 @@ function StreamController() {
13071333

13081334
let allUTCTimingSources = (!adapter.getIsDynamic()) ? manifestUTCTimingSources : manifestUTCTimingSources.concat(customParametersModel.getUTCTimingSources());
13091335
timeSyncController.attemptSync(allUTCTimingSources, adapter.getIsDynamic());
1310-
13111336
extUrlQueryInfoController.createFinalQueryStrings(manifest);
13121337
});
13131338
} else {

0 commit comments

Comments
 (0)