stream.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141
  1. /**
  2. * mux.js
  3. *
  4. * Copyright (c) Brightcove
  5. * Licensed Apache-2.0 https://github.com/videojs/mux.js/blob/master/LICENSE
  6. *
  7. * A lightweight readable stream implemention that handles event dispatching.
  8. * Objects that inherit from streams should call init in their constructors.
  9. */
  10. 'use strict';
  11. var Stream = function() {
  12. this.init = function() {
  13. var listeners = {};
  14. /**
  15. * Add a listener for a specified event type.
  16. * @param type {string} the event name
  17. * @param listener {function} the callback to be invoked when an event of
  18. * the specified type occurs
  19. */
  20. this.on = function(type, listener) {
  21. if (!listeners[type]) {
  22. listeners[type] = [];
  23. }
  24. listeners[type] = listeners[type].concat(listener);
  25. };
  26. /**
  27. * Remove a listener for a specified event type.
  28. * @param type {string} the event name
  29. * @param listener {function} a function previously registered for this
  30. * type of event through `on`
  31. */
  32. this.off = function(type, listener) {
  33. var index;
  34. if (!listeners[type]) {
  35. return false;
  36. }
  37. index = listeners[type].indexOf(listener);
  38. listeners[type] = listeners[type].slice();
  39. listeners[type].splice(index, 1);
  40. return index > -1;
  41. };
  42. /**
  43. * Trigger an event of the specified type on this stream. Any additional
  44. * arguments to this function are passed as parameters to event listeners.
  45. * @param type {string} the event name
  46. */
  47. this.trigger = function(type) {
  48. var callbacks, i, length, args;
  49. callbacks = listeners[type];
  50. if (!callbacks) {
  51. return;
  52. }
  53. // Slicing the arguments on every invocation of this method
  54. // can add a significant amount of overhead. Avoid the
  55. // intermediate object creation for the common case of a
  56. // single callback argument
  57. if (arguments.length === 2) {
  58. length = callbacks.length;
  59. for (i = 0; i < length; ++i) {
  60. callbacks[i].call(this, arguments[1]);
  61. }
  62. } else {
  63. args = [];
  64. i = arguments.length;
  65. for (i = 1; i < arguments.length; ++i) {
  66. args.push(arguments[i]);
  67. }
  68. length = callbacks.length;
  69. for (i = 0; i < length; ++i) {
  70. callbacks[i].apply(this, args);
  71. }
  72. }
  73. };
  74. /**
  75. * Destroys the stream and cleans up.
  76. */
  77. this.dispose = function() {
  78. listeners = {};
  79. };
  80. };
  81. };
  82. /**
  83. * Forwards all `data` events on this stream to the destination stream. The
  84. * destination stream should provide a method `push` to receive the data
  85. * events as they arrive.
  86. * @param destination {stream} the stream that will receive all `data` events
  87. * @param autoFlush {boolean} if false, we will not call `flush` on the destination
  88. * when the current stream emits a 'done' event
  89. * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
  90. */
  91. Stream.prototype.pipe = function(destination) {
  92. this.on('data', function(data) {
  93. destination.push(data);
  94. });
  95. this.on('done', function(flushSource) {
  96. destination.flush(flushSource);
  97. });
  98. this.on('partialdone', function(flushSource) {
  99. destination.partialFlush(flushSource);
  100. });
  101. this.on('endedtimeline', function(flushSource) {
  102. destination.endTimeline(flushSource);
  103. });
  104. this.on('reset', function(flushSource) {
  105. destination.reset(flushSource);
  106. });
  107. return destination;
  108. };
  109. // Default stream functions that are expected to be overridden to perform
  110. // actual work. These are provided by the prototype as a sort of no-op
  111. // implementation so that we don't have to check for their existence in the
  112. // `pipe` function above.
  113. Stream.prototype.push = function(data) {
  114. this.trigger('data', data);
  115. };
  116. Stream.prototype.flush = function(flushSource) {
  117. this.trigger('done', flushSource);
  118. };
  119. Stream.prototype.partialFlush = function(flushSource) {
  120. this.trigger('partialdone', flushSource);
  121. };
  122. Stream.prototype.endTimeline = function(flushSource) {
  123. this.trigger('endedtimeline', flushSource);
  124. };
  125. Stream.prototype.reset = function(flushSource) {
  126. this.trigger('reset', flushSource);
  127. };
  128. module.exports = Stream;