Home Reference Source

src/demux/transmuxer-worker.ts

  1. import Transmuxer, { isPromise } from '../demux/transmuxer';
  2. import { Events } from '../events';
  3. import { enableLogs } from '../utils/logger';
  4. import { EventEmitter } from 'eventemitter3';
  5. import type { RemuxedTrack, RemuxerResult } from '../types/remuxer';
  6. import type { TransmuxerResult, ChunkMetadata } from '../types/transmuxer';
  7.  
  8. export default function TransmuxerWorker(self) {
  9. const observer = new EventEmitter();
  10. const forwardMessage = (ev, data) => {
  11. self.postMessage({ event: ev, data: data });
  12. };
  13.  
  14. // forward events to main thread
  15. observer.on(Events.FRAG_DECRYPTED, forwardMessage);
  16. observer.on(Events.ERROR, forwardMessage);
  17.  
  18. self.addEventListener('message', (ev) => {
  19. const data = ev.data;
  20. switch (data.cmd) {
  21. case 'init': {
  22. const config = JSON.parse(data.config);
  23. self.transmuxer = new Transmuxer(
  24. observer,
  25. data.typeSupported,
  26. config,
  27. data.vendor
  28. );
  29. enableLogs(config.debug);
  30. forwardMessage('init', null);
  31. break;
  32. }
  33. case 'configure': {
  34. self.transmuxer.configure(data.config);
  35. break;
  36. }
  37. case 'demux': {
  38. const transmuxResult:
  39. | TransmuxerResult
  40. | Promise<TransmuxerResult> = self.transmuxer.push(
  41. data.data,
  42. data.decryptdata,
  43. data.chunkMeta,
  44. data.state
  45. );
  46. if (isPromise(transmuxResult)) {
  47. transmuxResult.then((data) => {
  48. emitTransmuxComplete(self, data);
  49. });
  50. } else {
  51. emitTransmuxComplete(self, transmuxResult);
  52. }
  53. break;
  54. }
  55. case 'flush': {
  56. const id = data.chunkMeta;
  57. const transmuxResult = self.transmuxer.flush(id);
  58. if (isPromise(transmuxResult)) {
  59. transmuxResult.then((results: Array<TransmuxerResult>) => {
  60. handleFlushResult(self, results as Array<TransmuxerResult>, id);
  61. });
  62. } else {
  63. handleFlushResult(
  64. self,
  65. transmuxResult as Array<TransmuxerResult>,
  66. id
  67. );
  68. }
  69. break;
  70. }
  71. default:
  72. break;
  73. }
  74. });
  75. }
  76.  
  77. function emitTransmuxComplete(self: any, transmuxResult: TransmuxerResult) {
  78. if (isEmptyResult(transmuxResult.remuxResult)) {
  79. return;
  80. }
  81. const transferable: Array<ArrayBuffer> = [];
  82. const { audio, video } = transmuxResult.remuxResult;
  83. if (audio) {
  84. addToTransferable(transferable, audio);
  85. }
  86. if (video) {
  87. addToTransferable(transferable, video);
  88. }
  89. self.postMessage(
  90. { event: 'transmuxComplete', data: transmuxResult },
  91. transferable
  92. );
  93. }
  94.  
  95. // Converts data to a transferable object https://developers.google.com/web/updates/2011/12/Transferable-Objects-Lightning-Fast)
  96. // in order to minimize message passing overhead
  97. function addToTransferable(
  98. transferable: Array<ArrayBuffer>,
  99. track: RemuxedTrack
  100. ) {
  101. if (track.data1) {
  102. transferable.push(track.data1.buffer);
  103. }
  104. if (track.data2) {
  105. transferable.push(track.data2.buffer);
  106. }
  107. }
  108.  
  109. function handleFlushResult(
  110. self: any,
  111. results: Array<TransmuxerResult>,
  112. chunkMeta: ChunkMetadata
  113. ) {
  114. results.forEach((result) => {
  115. emitTransmuxComplete(self, result);
  116. });
  117. self.postMessage({ event: 'flush', data: chunkMeta });
  118. }
  119.  
  120. function isEmptyResult(remuxResult: RemuxerResult) {
  121. return (
  122. !remuxResult.audio &&
  123. !remuxResult.video &&
  124. !remuxResult.text &&
  125. !remuxResult.id3 &&
  126. !remuxResult.initSegment
  127. );
  128. }