Skip to content

Commit a34b4da

Browse files
fix: store transmuxQueue and currentTransmux on transmuxer instead of globally (#1045)
Prevents separate videos on the page or separate transmuxers from bottlenecking one another.
1 parent f0732af commit a34b4da

File tree

6 files changed

+83
-115
lines changed

6 files changed

+83
-115
lines changed

src/segment-loader.js

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import Config from './config';
77
import window from 'global/window';
88
import { initSegmentId, segmentKeyId } from './bin-utils';
99
import { mediaSegmentRequest, REQUEST_ERRORS } from './media-segment-request';
10-
import TransmuxWorker from 'worker!./transmuxer-worker.js';
1110
import segmentTransmuxer from './segment-transmuxer';
1211
import { TIME_FUDGE_FACTOR, timeUntilRebuffer as timeUntilRebuffer_ } from './ranges';
1312
import { minRebufferMaxBandwidthSelector } from './playlist-selectors';
@@ -530,7 +529,6 @@ export default class SegmentLoader extends videojs.EventTarget {
530529
};
531530

532531
this.transmuxer_ = this.createTransmuxer_();
533-
534532
this.triggerSyncInfoUpdate_ = () => this.trigger('syncinfoupdate');
535533
this.syncController_.on('syncinfoupdate', this.triggerSyncInfoUpdate_);
536534

@@ -591,20 +589,13 @@ export default class SegmentLoader extends videojs.EventTarget {
591589
}
592590

593591
createTransmuxer_() {
594-
const transmuxer = new TransmuxWorker();
595-
596-
transmuxer.postMessage({
597-
action: 'init',
598-
options: {
599-
parse708captions: this.parse708captions_,
600-
remux: false,
601-
alignGopsAtEnd: this.safeAppend_,
602-
keepOriginalTimestamps: true,
603-
handlePartialData: this.handlePartialData_
604-
}
592+
return segmentTransmuxer.createTransmuxer({
593+
remux: false,
594+
alignGopsAtEnd: this.safeAppend_,
595+
keepOriginalTimestamps: true,
596+
handlePartialData: this.handlePartialData_,
597+
parse708captions: this.parse708captions_
605598
});
606-
607-
return transmuxer;
608599
}
609600

610601
/**
@@ -632,9 +623,6 @@ export default class SegmentLoader extends videojs.EventTarget {
632623
this.abort_();
633624
if (this.transmuxer_) {
634625
this.transmuxer_.terminate();
635-
// Although it isn't an instance of a class, the segment transmuxer must still be
636-
// cleaned up.
637-
segmentTransmuxer.dispose();
638626
}
639627
this.resetStats_();
640628

src/segment-transmuxer.js

Lines changed: 53 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
1-
const transmuxQueue = [];
2-
let currentTransmux;
1+
import TransmuxWorker from 'worker!./transmuxer-worker.js';
32

43
export const handleData_ = (event, transmuxedData, callback) => {
54
const {
@@ -66,30 +65,31 @@ export const handleGopInfo_ = (event, transmuxedData) => {
6665
transmuxedData.gopInfo = event.data.gopInfo;
6766
};
6867

69-
export const processTransmux = ({
70-
transmuxer,
71-
bytes,
72-
audioAppendStart,
73-
gopsToAlignWith,
74-
isPartial,
75-
remux,
76-
onData,
77-
onTrackInfo,
78-
onAudioTimingInfo,
79-
onVideoTimingInfo,
80-
onVideoSegmentTimingInfo,
81-
onAudioSegmentTimingInfo,
82-
onId3,
83-
onCaptions,
84-
onDone
85-
}) => {
68+
export const processTransmux = (options) => {
69+
const {
70+
transmuxer,
71+
bytes,
72+
audioAppendStart,
73+
gopsToAlignWith,
74+
isPartial,
75+
remux,
76+
onData,
77+
onTrackInfo,
78+
onAudioTimingInfo,
79+
onVideoTimingInfo,
80+
onVideoSegmentTimingInfo,
81+
onAudioSegmentTimingInfo,
82+
onId3,
83+
onCaptions,
84+
onDone
85+
} = options;
8686
const transmuxedData = {
8787
isPartial,
8888
buffer: []
8989
};
9090

9191
const handleMessage = (event) => {
92-
if (!currentTransmux) {
92+
if (transmuxer.currentTransmux !== options) {
9393
// disposed
9494
return;
9595
}
@@ -134,7 +134,7 @@ export const processTransmux = ({
134134
});
135135

136136
/* eslint-disable no-use-before-define */
137-
dequeue();
137+
dequeue(transmuxer);
138138
/* eslint-enable */
139139
};
140140

@@ -187,30 +187,30 @@ export const processTransmux = ({
187187
transmuxer.postMessage({ action: isPartial ? 'partialFlush' : 'flush' });
188188
};
189189

190-
export const dequeue = () => {
191-
currentTransmux = null;
192-
if (transmuxQueue.length) {
193-
currentTransmux = transmuxQueue.shift();
194-
if (typeof currentTransmux === 'function') {
195-
currentTransmux();
190+
export const dequeue = (transmuxer) => {
191+
transmuxer.currentTransmux = null;
192+
if (transmuxer.transmuxQueue.length) {
193+
transmuxer.currentTransmux = transmuxer.transmuxQueue.shift();
194+
if (typeof transmuxer.currentTransmux === 'function') {
195+
transmuxer.currentTransmux();
196196
} else {
197-
processTransmux(currentTransmux);
197+
processTransmux(transmuxer.currentTransmux);
198198
}
199199
}
200200
};
201201

202202
export const processAction = (transmuxer, action) => {
203203
transmuxer.postMessage({ action });
204-
dequeue();
204+
dequeue(transmuxer);
205205
};
206206

207207
export const enqueueAction = (action, transmuxer) => {
208-
if (!currentTransmux) {
209-
currentTransmux = action;
208+
if (!transmuxer.currentTransmux) {
209+
transmuxer.currentTransmux = action;
210210
processAction(transmuxer, action);
211211
return;
212212
}
213-
transmuxQueue.push(processAction.bind(null, transmuxer, action));
213+
transmuxer.transmuxQueue.push(processAction.bind(null, transmuxer, action));
214214
};
215215

216216
export const reset = (transmuxer) => {
@@ -222,23 +222,35 @@ export const endTimeline = (transmuxer) => {
222222
};
223223

224224
export const transmux = (options) => {
225-
if (!currentTransmux) {
226-
currentTransmux = options;
225+
if (!options.transmuxer.currentTransmux) {
226+
options.transmuxer.currentTransmux = options;
227227
processTransmux(options);
228228
return;
229229
}
230-
transmuxQueue.push(options);
230+
options.transmuxer.transmuxQueue.push(options);
231231
};
232232

233-
export const dispose = () => {
234-
// clear out module-level references
235-
currentTransmux = null;
236-
transmuxQueue.length = 0;
233+
export const createTransmuxer = (options) => {
234+
const transmuxer = new TransmuxWorker();
235+
236+
transmuxer.currentTransmux = null;
237+
transmuxer.transmuxQueue = [];
238+
const term = transmuxer.terminate;
239+
240+
transmuxer.terminate = () => {
241+
transmuxer.currentTransmux = null;
242+
transmuxer.transmuxQueue.length = 0;
243+
return term.call(transmuxer);
244+
};
245+
246+
transmuxer.postMessage({action: 'init', options});
247+
248+
return transmuxer;
237249
};
238250

239251
export default {
240252
reset,
241-
dispose,
242253
endTimeline,
243-
transmux
254+
transmux,
255+
createTransmuxer
244256
};

test/media-segment-request.test.js

Lines changed: 5 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,8 @@ import {
88
standardXHRResponse,
99
downloadProgress
1010
} from './test-helpers';
11-
import TransmuxWorker from 'worker!../src/transmuxer-worker.js';
11+
import {createTransmuxer as createTransmuxer_} from '../src/segment-transmuxer.js';
1212
import Decrypter from 'worker!../src/decrypter-worker.js';
13-
import {dispose as segmentTransmuxerDispose} from '../src/segment-transmuxer.js';
1413
import {
1514
aacWithoutId3 as aacWithoutId3Segment,
1615
aacWithId3 as aacWithId3Segment,
@@ -71,18 +70,11 @@ const sharedHooks = {
7170
};
7271

7372
this.createTransmuxer = (isPartial) => {
74-
const transmuxer = new TransmuxWorker();
75-
76-
transmuxer.postMessage({
77-
action: 'init',
78-
options: {
79-
remux: false,
80-
keepOriginalTimestamps: true,
81-
handlePartialData: isPartial
82-
}
73+
return createTransmuxer_({
74+
remux: false,
75+
keepOriginalTimestamps: true,
76+
handlePartialData: isPartial
8377
});
84-
85-
return transmuxer;
8678
};
8779
},
8880
afterEach(assert) {
@@ -92,9 +84,6 @@ const sharedHooks = {
9284
if (this.transmuxer) {
9385
this.transmuxer.terminate();
9486
}
95-
96-
// clear current transmux on segment transmuxer
97-
segmentTransmuxerDispose();
9887
}
9988

10089
};

test/segment-loader.test.js

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ import {
99
mediaDuration,
1010
getTroublesomeSegmentDurationMessage
1111
} from '../src/segment-loader';
12-
import segmentTransmuxer from '../src/segment-transmuxer';
1312
import videojs from 'video.js';
1413
import mp4probe from 'mux.js/lib/mp4/probe';
1514
import {
@@ -2381,29 +2380,23 @@ QUnit.module('SegmentLoader', function(hooks) {
23812380
QUnit.test('dispose cleans up transmuxer', function(assert) {
23822381
return setupMediaSource(loader.mediaSource_, loader.sourceUpdater_).then(() => {
23832382
loader.playlist(playlistWithDuration(20));
2383+
const transmuxer = loader.transmuxer_;
23842384

2385-
const origTransmuxerTerminate =
2386-
loader.transmuxer_.terminate.bind(loader.transmuxer_);
2385+
const origTransmuxerTerminate = transmuxer.terminate.bind(transmuxer);
23872386
let transmuxerTerminateCount = 0;
2388-
const origSegmentTransmuxerDispose =
2389-
segmentTransmuxer.dispose.bind(segmentTransmuxer);
2390-
let segmentTransmuxerDisposeCalls = 0;
23912387

2392-
loader.transmuxer_.terminate = () => {
2388+
transmuxer.terminate = () => {
23932389
transmuxerTerminateCount++;
23942390
origTransmuxerTerminate();
23952391
};
2396-
segmentTransmuxer.dispose = () => {
2397-
origSegmentTransmuxerDispose();
2398-
segmentTransmuxerDisposeCalls++;
2399-
};
24002392

24012393
loader.load();
24022394
this.clock.tick(1);
24032395
loader.dispose();
24042396

24052397
assert.equal(transmuxerTerminateCount, 1, 'terminated transmuxer');
2406-
assert.equal(segmentTransmuxerDisposeCalls, 1, 'disposed segment transmuxer');
2398+
assert.ok(!transmuxer.currentTransmux, 'no current transmux');
2399+
assert.equal(transmuxer.transmuxQueue.length, 0, 'no queue');
24072400
});
24082401
});
24092402

test/segment-transmuxer.test.js

Lines changed: 9 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import QUnit from 'qunit';
22
import sinon from 'sinon';
3-
import TransmuxWorker from 'worker!../src/transmuxer-worker.js';
43
import {
54
muxed as muxedSegment,
65
caption as captionSegment,
@@ -17,32 +16,27 @@ import {
1716
handleGopInfo_,
1817
handleDone_,
1918
handleData_,
20-
dispose
19+
createTransmuxer as createTransmuxer_
2120
} from '../src/segment-transmuxer';
2221
// needed for plugin registration
2322
import '../src/videojs-http-streaming';
2423

2524
const noop = () => {};
2625

2726
const createTransmuxer = (isPartial) => {
28-
const transmuxer = new TransmuxWorker();
29-
30-
transmuxer.postMessage({
31-
action: 'init',
32-
options: {
33-
remux: false,
34-
keepOriginalTimestamps: true,
35-
handlePartialData: isPartial
36-
}
27+
return createTransmuxer_({
28+
remux: false,
29+
keepOriginalTimestamps: true,
30+
handlePartialData: isPartial
3731
});
38-
39-
return transmuxer;
4032
};
4133

4234
const mockTransmuxer = (isPartial) => {
4335
const transmuxer = {
4436
postMessage(event) {},
45-
terminate() {}
37+
terminate() {},
38+
currentTransmux: null,
39+
transmuxQueue: []
4640
};
4741

4842
return transmuxer;
@@ -54,7 +48,6 @@ QUnit.module('Segment Transmuxer', {
5448
assert.timeout(5000);
5549
},
5650
afterEach(assert) {
57-
dispose();
5851
if (this.transmuxer) {
5952
this.transmuxer.terminate();
6053
}
@@ -240,7 +233,7 @@ QUnit.test('dequeues and processes action on dequeue()', function(assert) {
240233
'the transmux() posted `flush` to the transmuxer'
241234
);
242235

243-
dequeue();
236+
dequeue(this.transmuxer);
244237
assert.deepEqual(this.transmuxer.postMessage.callCount, 2, 'two actions processed');
245238
assert.deepEqual(
246239
this.transmuxer.postMessage.args[1][0],

test/transmuxer-worker.test.js

Lines changed: 5 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import QUnit from 'qunit';
2-
import TransmuxWorker from 'worker!../src/transmuxer-worker.js';
2+
import {createTransmuxer as createTransmuxer_} from '../src/segment-transmuxer.js';
33
import {
44
mp4Captions as mp4CaptionsSegment,
55
muxed as muxedSegment,
@@ -10,18 +10,11 @@ import {
1010
import '../src/videojs-http-streaming';
1111

1212
const createTransmuxer = (isPartial) => {
13-
const transmuxer = new TransmuxWorker();
14-
15-
transmuxer.postMessage({
16-
action: 'init',
17-
options: {
18-
remux: false,
19-
keepOriginalTimestamps: true,
20-
handlePartialData: isPartial
21-
}
13+
return createTransmuxer_({
14+
remux: false,
15+
keepOriginalTimestamps: true,
16+
handlePartialData: isPartial
2217
});
23-
24-
return transmuxer;
2518
};
2619

2720
// The final done message from the Transmux worker

0 commit comments

Comments
 (0)