stream.js 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  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 Stream() {
  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. } // Slicing the arguments on every invocation of this method
  53. // can add a significant amount of overhead. Avoid the
  54. // intermediate object creation for the common case of a
  55. // single callback argument
  56. if (arguments.length === 2) {
  57. length = callbacks.length;
  58. for (i = 0; i < length; ++i) {
  59. callbacks[i].call(this, arguments[1]);
  60. }
  61. } else {
  62. args = [];
  63. i = arguments.length;
  64. for (i = 1; i < arguments.length; ++i) {
  65. args.push(arguments[i]);
  66. }
  67. length = callbacks.length;
  68. for (i = 0; i < length; ++i) {
  69. callbacks[i].apply(this, args);
  70. }
  71. }
  72. };
  73. /**
  74. * Destroys the stream and cleans up.
  75. */
  76. this.dispose = function () {
  77. listeners = {};
  78. };
  79. };
  80. };
  81. /**
  82. * Forwards all `data` events on this stream to the destination stream. The
  83. * destination stream should provide a method `push` to receive the data
  84. * events as they arrive.
  85. * @param destination {stream} the stream that will receive all `data` events
  86. * @param autoFlush {boolean} if false, we will not call `flush` on the destination
  87. * when the current stream emits a 'done' event
  88. * @see http://nodejs.org/api/stream.html#stream_readable_pipe_destination_options
  89. */
  90. Stream.prototype.pipe = function (destination) {
  91. this.on('data', function (data) {
  92. destination.push(data);
  93. });
  94. this.on('done', function (flushSource) {
  95. destination.flush(flushSource);
  96. });
  97. this.on('partialdone', function (flushSource) {
  98. destination.partialFlush(flushSource);
  99. });
  100. this.on('endedtimeline', function (flushSource) {
  101. destination.endTimeline(flushSource);
  102. });
  103. this.on('reset', function (flushSource) {
  104. destination.reset(flushSource);
  105. });
  106. return destination;
  107. }; // Default stream functions that are expected to be overridden to perform
  108. // actual work. These are provided by the prototype as a sort of no-op
  109. // implementation so that we don't have to check for their existence in the
  110. // `pipe` function above.
  111. Stream.prototype.push = function (data) {
  112. this.trigger('data', data);
  113. };
  114. Stream.prototype.flush = function (flushSource) {
  115. this.trigger('done', flushSource);
  116. };
  117. Stream.prototype.partialFlush = function (flushSource) {
  118. this.trigger('partialdone', flushSource);
  119. };
  120. Stream.prototype.endTimeline = function (flushSource) {
  121. this.trigger('endedtimeline', flushSource);
  122. };
  123. Stream.prototype.reset = function (flushSource) {
  124. this.trigger('reset', flushSource);
  125. };
  126. module.exports = Stream;