diff --git a/package-lock.json b/package-lock.json index e7cf7003c..d5f1677d8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6563,9 +6563,9 @@ "dev": true }, "mux.js": { - "version": "5.11.3", - "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.11.3.tgz", - "integrity": "sha512-wL7zb7CMthrTVhVFOKiU/HrWeNA9vbPNIIebhkFRz5g2nTDgBsQPsDoHYW8pk4sgHgY9wvuzrqlDvLkhdPPgrw==", + "version": "5.12.1", + "resolved": "https://registry.npmjs.org/mux.js/-/mux.js-5.12.1.tgz", + "integrity": "sha512-bUZmpGr9fdyAsCc8UO761x8VKIxRuSIJ4yFX7F5bDer6bz5nCFcb3hbgFNc0bA3/v/Tp96Rftftexnx6BZAbVg==", "requires": { "@babel/runtime": "^7.11.2" } @@ -7715,9 +7715,9 @@ } }, "rollup-plugin-worker-factory": { - "version": "0.5.5", - "resolved": "https://registry.npmjs.org/rollup-plugin-worker-factory/-/rollup-plugin-worker-factory-0.5.5.tgz", - "integrity": "sha512-kbsvueLjSntAFjBnnD7UOWTdc1zcufshG97M+Muu2s1mugtiviYpz/jR1WQyZK1u5ZA2tbSCCqRzHHe6FmpoIg==", + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/rollup-plugin-worker-factory/-/rollup-plugin-worker-factory-0.5.7.tgz", + "integrity": "sha512-DZ9HOy8FFVnx9in/x2DFrbH2Dj3iBMUm5zuisBnfQst2WcDbNicJLveiytgnoKqXQnBm7TPnlEklp4ce1eT1aw==", "dev": true, "requires": { "rollup": "^2.34.2" diff --git a/package.json b/package.json index 27db21353..d1ede88f1 100644 --- a/package.json +++ b/package.json @@ -62,7 +62,7 @@ "global": "^4.4.0", "m3u8-parser": "4.7.0", "mpd-parser": "0.17.0", - "mux.js": "5.11.3", + "mux.js": "5.12.1", "video.js": "^6 || ^7" }, "peerDependencies": { @@ -81,7 +81,7 @@ "lodash-compat": "^3.10.0", "nomnoml": "^0.3.0", "rollup": "^2.36.1", - "rollup-plugin-worker-factory": "0.5.5", + "rollup-plugin-worker-factory": "0.5.7", "shelljs": "^0.8.4", "sinon": "^8.1.1", "url-toolkit": "^2.2.1", diff --git a/src/media-segment-request.js b/src/media-segment-request.js index 1f7113215..d6c91051e 100644 --- a/src/media-segment-request.js +++ b/src/media-segment-request.js @@ -289,7 +289,8 @@ const transmuxAndNotify = ({ isEndOfTimeline, endedTimelineFn, dataFn, - doneFn + doneFn, + onTransmuxerLog }) => { const fmp4Tracks = segment.map && segment.map.tracks || {}; const isMuxed = Boolean(fmp4Tracks.audio && fmp4Tracks.video); @@ -358,6 +359,7 @@ const transmuxAndNotify = ({ onEndedTimeline: () => { endedTimelineFn(); }, + onTransmuxerLog, onDone: (result) => { if (!doneFn) { return; @@ -415,7 +417,8 @@ const handleSegmentBytes = ({ isEndOfTimeline, endedTimelineFn, dataFn, - doneFn + doneFn, + onTransmuxerLog }) => { let bytesAsUint8Array = new Uint8Array(bytes); @@ -510,6 +513,9 @@ const handleSegmentBytes = ({ // transfer bytes back to us bytes = message.data.buffer; segment.bytes = bytesAsUint8Array = message.data; + message.logs.forEach(function(log) { + onTransmuxerLog(videojs.mergeOptions(log, {stream: 'mp4CaptionParser'})); + }); finishLoading(message.captions); } }); @@ -547,7 +553,8 @@ const handleSegmentBytes = ({ isEndOfTimeline, endedTimelineFn, dataFn, - doneFn + doneFn, + onTransmuxerLog }); }; @@ -623,7 +630,8 @@ const decryptSegment = ({ isEndOfTimeline, endedTimelineFn, dataFn, - doneFn + doneFn, + onTransmuxerLog }) => { decrypt({ id: segment.requestId, @@ -645,7 +653,8 @@ const decryptSegment = ({ isEndOfTimeline, endedTimelineFn, dataFn, - doneFn + doneFn, + onTransmuxerLog }); }); }; @@ -691,7 +700,8 @@ const waitForCompletion = ({ isEndOfTimeline, endedTimelineFn, dataFn, - doneFn + doneFn, + onTransmuxerLog }) => { let count = 0; let didError = false; @@ -737,7 +747,8 @@ const waitForCompletion = ({ isEndOfTimeline, endedTimelineFn, dataFn, - doneFn + doneFn, + onTransmuxerLog }); } // Otherwise, everything is ready just continue @@ -753,7 +764,8 @@ const waitForCompletion = ({ isEndOfTimeline, endedTimelineFn, dataFn, - doneFn + doneFn, + onTransmuxerLog }); }; @@ -942,7 +954,8 @@ export const mediaSegmentRequest = ({ isEndOfTimeline, endedTimelineFn, dataFn, - doneFn + doneFn, + onTransmuxerLog }) => { const activeXhrs = []; const finishProcessingFn = waitForCompletion({ @@ -957,7 +970,8 @@ export const mediaSegmentRequest = ({ isEndOfTimeline, endedTimelineFn, dataFn, - doneFn + doneFn, + onTransmuxerLog }); // optionally, request the decryption key diff --git a/src/segment-loader.js b/src/segment-loader.js index b5c8c8caf..4b3598f15 100644 --- a/src/segment-loader.js +++ b/src/segment-loader.js @@ -2427,7 +2427,10 @@ export default class SegmentLoader extends videojs.EventTarget { id3Fn: this.handleId3_.bind(this), dataFn: this.handleData_.bind(this), - doneFn: this.segmentRequestFinished_.bind(this) + doneFn: this.segmentRequestFinished_.bind(this), + onTransmuxerLog: ({message, level, stream}) => { + this.logger_(`${segmentInfoString(segmentInfo)} logged from transmuxer stream ${stream} as a ${level}: ${message}`); + } }); } diff --git a/src/segment-transmuxer.js b/src/segment-transmuxer.js index d3511308f..6d1bb789e 100644 --- a/src/segment-transmuxer.js +++ b/src/segment-transmuxer.js @@ -81,6 +81,7 @@ export const processTransmux = (options) => { onCaptions, onDone, onEndedTimeline, + onTransmuxerLog, isEndOfTimeline } = options; const transmuxedData = { @@ -125,6 +126,9 @@ export const processTransmux = (options) => { waitForEndedTimelineEvent = false; onEndedTimeline(); } + if (event.data.action === 'log') { + onTransmuxerLog(event.data.log); + } // wait for the transmuxed event since we may have audio and video if (event.data.type !== 'transmuxed') { diff --git a/src/transmuxer-worker.js b/src/transmuxer-worker.js index 7d8e5d764..d8f9e7e3f 100644 --- a/src/transmuxer-worker.js +++ b/src/transmuxer-worker.js @@ -155,6 +155,10 @@ const wireTransmuxerEvents = function(self, transmuxer) { }); }); + transmuxer.on('log', function(log) { + self.postMessage({action: 'log', log}); + }); + }; /** @@ -198,6 +202,7 @@ class MessageHandlers { this.self.postMessage({ action: 'mp4Captions', captions: parsed && parsed.captions || [], + logs: parsed && parsed.logs || [], data: segment.buffer }, [segment.buffer]); } diff --git a/test/media-segment-request.test.js b/test/media-segment-request.test.js index 7a1c5164d..92f6344a7 100644 --- a/test/media-segment-request.test.js +++ b/test/media-segment-request.test.js @@ -89,7 +89,8 @@ QUnit.module('Media Segment Request - make it to transmuxer', { xhr: this.xhr, xhrOptions: this.xhrOptions, decryptionWorker: this.mockDecrypter, - segment: {} + segment: {}, + onTransmuxerLog: () => {} }; [ @@ -1335,7 +1336,8 @@ QUnit.test('non-TS segment will get parsed for captions', function(assert) { data: { action: 'mp4Captions', data: event.data, - captions + captions, + logs: [] } }); } @@ -1475,7 +1477,8 @@ QUnit.test('non-TS segment will get parsed for captions on next segment request data: { action: 'mp4Captions', data: event.data, - captions + captions, + logs: [] } }); } diff --git a/test/segment-loader.test.js b/test/segment-loader.test.js index d4f049d7e..4f196f18c 100644 --- a/test/segment-loader.test.js +++ b/test/segment-loader.test.js @@ -902,6 +902,55 @@ QUnit.module('SegmentLoader', function(hooks) { }); }); + QUnit.test('uses the log event from the transmuxer', function(assert) { + const playlist = playlistWithDuration(10); + const ogPost = loader.transmuxer_.postMessage; + const messages = []; + + loader.logger_ = (message) => { + messages.push(message); + }; + + loader.transmuxer_.postMessage = (message) => { + const retval = ogPost.call(loader.transmuxer_, message); + + if (message.action === 'push') { + const log = newEvent('message'); + + log.data = {action: 'log', log: {message: 'debug foo', stream: 'something', level: 'warn'}}; + + loader.transmuxer_.dispatchEvent(log); + return; + } + + return retval; + }; + + return setupMediaSource(loader.mediaSource_, loader.sourceUpdater_, {isVideoOnly: true}).then(() => { + return new Promise((resolve, reject) => { + loader.one('appended', resolve); + loader.one('error', reject); + + loader.playlist(playlist); + loader.load(); + + this.clock.tick(100); + // segment + standardXHRResponse(this.requests.shift(), videoOneSecondSegment()); + }); + }).then(() => { + let messageFound = false; + + messages.forEach(function(message) { + if ((/debug foo/).test(message) && (/warn/).test(message) && (/something/).test(message)) { + messageFound = true; + } + }); + + assert.ok(messageFound, 'message was logged'); + }); + }); + QUnit.test('segmentKey will cache new encrypted keys with cacheEncryptionKeys true', function(assert) { loader.cacheEncryptionKeys_ = true; diff --git a/test/transmuxer-worker.test.js b/test/transmuxer-worker.test.js index abad1c584..5730e11eb 100644 --- a/test/transmuxer-worker.test.js +++ b/test/transmuxer-worker.test.js @@ -328,6 +328,7 @@ QUnit.test('can parse mp4 captions', function(assert) { assert.equal(message.action, 'mp4Captions', 'returned mp4Captions event'); assert.deepEqual(message.captions.length, 2, 'two captions'); + assert.deepEqual(message.logs.length, 0, 'no logs returned'); assert.deepEqual( new Uint8Array(message.data), data,