Skip to content

Commit

Permalink
Fix regression for non-embedded text tracks (displayed twice) (#3290)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bertrand Berthelot committed Jun 15, 2020
1 parent 144e488 commit a208746
Show file tree
Hide file tree
Showing 5 changed files with 52 additions and 94 deletions.
1 change: 0 additions & 1 deletion src/core/events/CoreEvents.js
Expand Up @@ -74,7 +74,6 @@ class CoreEvents extends EventsBase {
this.STREAM_BUFFERING_COMPLETED = 'streamBufferingCompleted';
this.STREAM_COMPLETED = 'streamCompleted';
this.TEXT_TRACKS_QUEUE_INITIALIZED = 'textTracksQueueInitialized';
this.TIMED_TEXT_REQUESTED = 'timedTextRequested';
this.TIME_SYNCHRONIZATION_COMPLETED = 'timeSynchronizationComplete';
this.URL_RESOLUTION_FAILED = 'urlResolutionFailed';
this.VIDEO_CHUNK_RECEIVED = 'videoChunkReceived';
Expand Down
25 changes: 4 additions & 21 deletions src/streaming/StreamProcessor.js
Expand Up @@ -169,10 +169,6 @@ function StreamProcessor(config) {
settings: settings
});

if (adapter && adapter.getIsTextTrack(mimeType)) {
eventBus.on(Events.TIMED_TEXT_REQUESTED, onTimedTextRequested, this);
}

scheduleController.initialize(hasVideoTrack);

streamInitialized = false;
Expand Down Expand Up @@ -223,10 +219,6 @@ function StreamProcessor(config) {
eventBus.off(Events.BUFFER_CLEARED, onBufferCleared, instance);
eventBus.off(Events.SEEK_TARGET, onSeekTarget, instance);

if (adapter && adapter.getIsTextTrack(mimeType)) {
eventBus.off(Events.TIMED_TEXT_REQUESTED, onTimedTextRequested, this);
}

resetInitialSettings();
type = null;
streamInfo = null;
Expand Down Expand Up @@ -442,7 +434,9 @@ function StreamProcessor(config) {
}

function onInitFragmentNeeded(e) {
if (!e.sender || e.sender.getType() !== type || e.sender.getStreamId() !== streamInfo.id) return;
if (!e.sender || e.mediaType !== type || e.streamId !== streamInfo.id) return;

if (adapter.getIsTextTrack(mimeType) && !textController.isTextEnabled()) return;

if (bufferController && e.representationId) {
if (!bufferController.appendInitSegment(e.representationId)) {
Expand All @@ -454,7 +448,7 @@ function StreamProcessor(config) {
}

function onMediaFragmentNeeded(e) {
if (e.sender.getType() !== type || e.sender.getStreamId() !== streamInfo.id) return;
if (!e.sender || e.mediaType !== type || e.streamId !== streamInfo.id) return;

let request;

Expand Down Expand Up @@ -525,17 +519,6 @@ function StreamProcessor(config) {
return request;
}

function onTimedTextRequested(e) {
if (e.streamId !== streamInfo.id) return;

//if subtitles are disabled, do not download subtitles file.
if (textController.isTextEnabled()) {
const representation = representationController ? representationController.getRepresentationForQuality(e.index) : null;
const request = indexHandler ? indexHandler.getInitRequest(getMediaInfo(), representation) : null;
scheduleController.processInitRequest(request);
}
}

function onMediaFragmentLoaded(e) {
const chunk = e.chunk;
if (chunk.streamId !== streamInfo.id || chunk.mediaInfo.type != type) return;
Expand Down
32 changes: 22 additions & 10 deletions src/streaming/controllers/ScheduleController.js
Expand Up @@ -157,13 +157,9 @@ function ScheduleController(config) {
function schedule() {
if (isStopped || isFragmentProcessingInProgress ||
(playbackController.isPaused() && !settings.get().streaming.scheduleWhilePaused) ||
((type === Constants.FRAGMENTED_TEXT || type === Constants.TEXT) && !textController.isTextEnabled())) {
logger.debug('Schedule stop!');
return;
}

if (bufferController.getIsBufferingCompleted()) {
logger.debug('Schedule stop because buffering is completed!');
((type === Constants.FRAGMENTED_TEXT || type === Constants.TEXT) && !textController.isTextEnabled()) ||
bufferController.getIsBufferingCompleted()) {
stop();
return;
}

Expand All @@ -186,18 +182,34 @@ function ScheduleController(config) {
} else {
logger.debug('Quality has changed, get init request for representationid = ' + currentRepresentationInfo.id);
}
eventBus.trigger(Events.INIT_FRAGMENT_NEEDED, { sender: instance, representationId: currentRepresentationInfo.id });
eventBus.trigger(Events.INIT_FRAGMENT_NEEDED, {
sender: instance,
streamId: streamId,
mediaType: type,
representationId: currentRepresentationInfo.id
});
lastInitQuality = currentRepresentationInfo.quality;
checkPlaybackQuality = false;
} else {
const replacement = replaceRequestArray.shift();

if (replacement && replacement.isInitializationRequest()) {
// To be sure the specific init segment had not already been loaded
eventBus.trigger(Events.INIT_FRAGMENT_NEEDED, { sender: instance, representationId: replacement.representationId });
eventBus.trigger(Events.INIT_FRAGMENT_NEEDED, {
sender: instance,
streamId: streamId,
mediaType: type,
representationId: replacement.representationId
});
checkPlaybackQuality = false;
} else {
eventBus.trigger(Events.MEDIA_FRAGMENT_NEEDED, { sender: instance, seekTarget: seekTarget, replacement: replacement });
eventBus.trigger(Events.MEDIA_FRAGMENT_NEEDED, {
sender: instance,
streamId: streamId,
mediaType: type,
seekTarget: seekTarget,
replacement: replacement
});
checkPlaybackQuality = true;
}
}
Expand Down
41 changes: 19 additions & 22 deletions src/streaming/text/NotFragmentedTextBufferController.js
Expand Up @@ -150,17 +150,25 @@ function NotFragmentedTextBufferController(config) {
function onDataUpdateCompleted(e) {
if (e.sender.getStreamId() !== streamInfo.id || e.sender.getType() !== type || e.error) return;

const currentRepresentation = e.sender.getCurrentRepresentation();
if (initCache.extract(streamInfo.id, e.currentRepresentation.id) !== null) {
return;
}

const chunk = initCache.extract(streamInfo.id, currentRepresentation ? currentRepresentation.id : null);
// Representation has changed, clear buffer
isBufferingCompleted = false;

if (!chunk) {
eventBus.trigger(Events.TIMED_TEXT_REQUESTED, {
index: 0,
streamId: streamInfo.id,
sender: e.sender
}); //TODO make index dynamic if referring to MP?
}
// // Text data file is contained in initialization segment
eventBus.trigger(Events.INIT_FRAGMENT_NEEDED, {
sender: instance,
streamId: streamInfo.id,
mediaType: type,
representationId: e.currentRepresentation.id
});
}

function appendInitSegment(representationId) {
// If text data file already in cache then no need to append it again
return initCache.extract(streamInfo.id, representationId) !== null;
}

function onInitFragmentLoaded(e) {
Expand All @@ -169,24 +177,13 @@ function NotFragmentedTextBufferController(config) {
initCache.save(e.chunk);
buffer.append(e.chunk);

isBufferingCompleted = true;

eventBus.trigger(Events.STREAM_COMPLETED, {
request: e.request
});
}

function appendInitSegment(representationId) {
const chunk = initCache.extract(streamInfo.id, representationId);

if (!chunk) {
console.log('trigger TIMED_TEXT_REQUESTED');
eventBus.trigger(Events.TIMED_TEXT_REQUESTED, {
index: 0,
streamId: streamInfo.id,
sender: instance
});
}
}

function getRangeAt() {
return null;
}
Expand Down
47 changes: 7 additions & 40 deletions test/unit/streaming.text.NotFragmentedTextBufferController.js
Expand Up @@ -2,7 +2,6 @@ import NotFragmentedTextBufferController from '../../src/streaming/text/NotFragm
import ObjectUtils from '../../src/streaming/utils/ObjectUtils';
import EventBus from '../../src/core/EventBus';
import Events from '../../src/core/events/Events';
import InitCache from '../../src/streaming/utils/InitCache';

import ErrorHandlerMock from './mocks/ErrorHandlerMock';
import StreamProcessorMock from './mocks/StreamProcessorMock';
Expand All @@ -18,7 +17,6 @@ const streamInfo = {
};
const eventBus = EventBus(context).getInstance();
const objectUtils = ObjectUtils(context).getInstance();
const initCache = InitCache(context).getInstance();

describe('NotFragmentedTextBufferController', function () {

Expand Down Expand Up @@ -127,57 +125,26 @@ describe('NotFragmentedTextBufferController', function () {
});
});

describe('Method appendInitSegment', function () {
// it('should not append init data to source buffer if data have already been cached', function () {
// let chunk = {
// bytes: 'initData',
// quality: 2,
// mediaInfo: {
// type: testType
// },
// streamId: 'streamId',
// representationId: 'representationId'
// };

// initCache.save(chunk);
// notFragmentedTextBufferController.createBuffer(mockMediaInfoArr);
// const buffer = notFragmentedTextBufferController.getBuffer().getBuffer();
// notFragmentedTextBufferController.appendInitSegment(chunk.representationId);
// expect(buffer.chunk).to.equal(null);
// });

it('should trigger TIMED_TEXT_REQUESTED if no init data is cached', function (done) {

// reset cache
initCache.reset();

let onInitRequest = function () {
eventBus.off(Events.TIMED_TEXT_REQUESTED, onInitRequest);
done();
};
eventBus.on(Events.TIMED_TEXT_REQUESTED, onInitRequest, this);

notFragmentedTextBufferController.appendInitSegment('representationId');
});
});

describe('Event DATA_UPDATE_COMPLETED Handler', function () {

it('should trigger TIMED_TEXT_REQUESTED', function (done) {
it('should trigger INIT_FRAGMENT_NEEDED', function (done) {

let event = {
sender: {
getType: function () { return testType; },
getStreamId: function () { return streamInfo.id; },
getCurrentRepresentation: function () { return { id: 0}; }
}
},
streamId: streamInfo.id,
mediaType: testType,
currentRepresentation: { id: 0}
};

let onEvent = function () {
eventBus.off(Events.TIMED_TEXT_REQUESTED, onEvent);
eventBus.off(Events.INIT_FRAGMENT_NEEDED, onEvent);
done();
};
eventBus.on(Events.TIMED_TEXT_REQUESTED, onEvent, this);
eventBus.on(Events.INIT_FRAGMENT_NEEDED, onEvent, this);
eventBus.trigger(Events.DATA_UPDATE_COMPLETED, event);
});
});
Expand Down

0 comments on commit a208746

Please sign in to comment.