Sfoglia il codice sorgente

add some style using eslint

Gil Pedersen 11 anni fa
parent
commit
f3c0710e95
8 ha cambiato i file con 200 aggiunte e 193 eliminazioni
  1. 15 0
      .eslintrc
  2. 34 34
      bin/hlsdump
  3. 2 2
      bin/hlsmon
  4. 10 6
      bin/hlsrecord
  5. 55 59
      lib/reader.js
  6. 13 13
      lib/recorder.js
  7. 9 14
      lib/tsblast.js
  8. 62 65
      lib/tssmooth.js

+ 15 - 0
.eslintrc

@@ -0,0 +1,15 @@
+{
+    "env": {
+        "node": true
+    },
+    "rules": {
+        "quotes": 0,
+        "no-comma-dangle": 0,
+        "no-mixed-requires": [0, true],
+        "curly": [0, "multi"],
+        "no-unused-vars": 1,
+        "camelcase": 1,
+        "no-use-before-define": 1,
+        "no-underscore-dangle": 0
+    }
+}

+ 34 - 34
bin/hlsdump

@@ -1,5 +1,8 @@
 #!/usr/bin/env node
 
+/* eslint-disable no-process-exit */
+"use strict";
+
 var hlsdump = require('commander');
 hlsdump.version('0.0.0')
    .usage('[options] <url>')
@@ -18,7 +21,7 @@ hlsdump.version('0.0.0')
      return r;
    })
    .option('-b, --buffer-size <bytes>|full', 'try to buffer <bytes> of input data (implies -s)', function(val) {
-     if (val === 'full') return 0x80000000-1;
+     if (val === 'full') return 0x80000000 - 1;
      return parseInt(val, 0);
    })
    .option('-s, --sync', 'clock sync using stream PCR')
@@ -43,24 +46,22 @@ var reader = require('../lib/reader'),
     tssmooth = require('../lib/tssmooth'),
     tsblast = require('../lib/tsblast');
 
-try {
-  var Passthrough = require('stream').Passthrough;
-  assert(Passthrough);
-} catch (e) {
-  var Passthrough = require('readable-stream/passthrough');
-}
+var Passthrough = require('readable-stream/passthrough');
 
 var stats = require('measured').createCollection();
 
 var src = hlsdump.args[0];
-if (!src) return hlsdump.help();
+if (!src) {
+  hlsdump.help();
+  process.exit(-1);
+}
 
 if (hlsdump.bufferSize) hlsdump.sync = true;
 
 var r = reader(src, {highWaterMark:(hlsdump.concurrent || 1) - 1, fullStream:hlsdump.fullStream});
 
 var totalDuration = 0, currentSegment = -1;
-var reading = false;
+var reading = false, hooked = false;
 var keyCache = {};
 
 streamprocess(r, function (obj, done) {
@@ -73,7 +74,7 @@ streamprocess(r, function (obj, done) {
   console.error('piping segment', meta.url);
 
   var stopwatch = stats.timer('fetchTime').start();
-  stream.once('close', 'end', 'error', function(err) {
+  stream.once('close', 'end', 'error', function() {
     stopwatch.end();
   });
 
@@ -108,37 +109,37 @@ streamprocess(r, function (obj, done) {
       });
       pushBuffer(oncemore(stream.pipe(decrypt)));
     });
-
-    function fetchKey(cb) {
-      if (hlsdump.key) return cb(null, hlsdump.key);
-
-      var uri = url.resolve(r.url, keyData.uri.slice(1,-1));
-      var entry = keyCache[uri];
-      if (entry && entry.length) return cb(null, keyCache[uri]);
-
-      var key = new Buffer(0);
-      var headers = {};
-      if (hlsdump.cookie)
-        headers['Cookie'] = hlsdump.cookie;
-      
-      oncemore(uristream(uri, { headers:headers, whitelist:['http', 'https', 'data'], timeout: 10*1000 }))
-        .on('data', function(chunk) {
-          key = Buffer.concat([key, chunk]);
-        })
-        .once('error', 'end', function(err) {
-          keyCache[uri] = key;
-          return cb(err, key);
-        });
-    }
   } else {
     pushBuffer(stream);
   }
 
+  function fetchKey(cb) {
+    if (hlsdump.key) return cb(null, hlsdump.key);
+
+    var uri = url.resolve(r.url, keyData.uri.slice(1,-1));
+    var entry = keyCache[uri];
+    if (entry && entry.length) return cb(null, keyCache[uri]);
+
+    var key = new Buffer(0);
+    var headers = {};
+    if (hlsdump.cookie)
+      headers.Cookie = hlsdump.cookie;
+
+    oncemore(uristream(uri, { headers:headers, whitelist:['http', 'https', 'data'], timeout: 10 * 1000 }))
+      .on('data', function(chunk) {
+        key = Buffer.concat([key, chunk]);
+      })
+      .once('error', 'end', function(err) {
+        keyCache[uri] = key;
+        return cb(err, key);
+      });
+  }
+
   function pushBuffer(stream) {
     stream.pipe(buffer, { end: false });
     stream.once('end', 'error', function(err) {
       reading = false;
-      console.error('segment done at '+totalDuration.toFixed(0)+' seconds, avg bitrate (kbps):', (size / (duration * 1024/8)).toFixed(1));
+      console.error('segment done at ' + totalDuration.toFixed(0) + ' seconds, avg bitrate (kbps):', (size / (duration * 1024 / 8)).toFixed(1));
       if (err) {
         stats.meter('streamErrors').mark();
         console.error('stream error', err.stack || err);
@@ -175,7 +176,6 @@ if (hlsdump.output) {
 }
 
 // the hook is used to prebuffer
-var hooked = false;
 function hook(stream) {
   if (hooked) return;
 

+ 2 - 2
bin/hlsmon

@@ -25,7 +25,7 @@ function monitor(srcUrl) {
     while (null !== (obj = r.read())) {
       var meta = obj.meta;
       var duration = obj.segment.duration;
-      console.log(meta.modified.toJSON() + sep + meta.size + sep + duration.toFixed(3) + sep + (meta.size / (duration * 1024/8)).toFixed(3));
+      console.log(meta.modified.toJSON() + sep + meta.size + sep + duration.toFixed(3) + sep + (meta.size / (duration * 1024 / 8)).toFixed(3));
       time += duration;
     }
   });
@@ -41,7 +41,7 @@ function monitor(srcUrl) {
   r.on('end', function() {
     if (r.index && r.index.variant) {
       var newUrl = url.resolve(r.baseUrl, r.index.programs['1'][0].uri);
-      console.error('found variant index, using: ', newUrl)
+      console.error('found variant index, using: ', newUrl);
       return monitor(newUrl);
     }
     console.error('done');

+ 10 - 6
bin/hlsrecord

@@ -1,5 +1,6 @@
 #!/usr/bin/env node
 
+/* eslint-disable no-process-exit */
 "use strict";
 
 // record a live hls-stream storing an on-demand ready version
@@ -19,9 +20,9 @@ function dateValue(val) {
   // FIXME: negative values doesn't work with commander, as
   if (val === 'now') return new Date();
   if (val.length && (val[0] === '+' || val[0] === '-'))
-    return new Date(Math.round(new Date().getTime()/1000 + parseInt(val, 10))*1000);
+    return new Date(Math.round(new Date().getTime() / 1000 + parseInt(val, 10)) * 1000);
   if (parseInt(val, 10) == val)
-    return new Date(parseInt(val, 10)*1000);
+    return new Date(parseInt(val, 10) * 1000);
   return new Date(val);
 }
 
@@ -42,7 +43,10 @@ mime.define({
 });
 
 var src = hlsrecord.args[0];
-if (!src) return hlsrecord.help();
+if (!src) {
+  hlsrecord.help();
+  process.exit(-1);
+}
 
 var outDir = hlsrecord.output || 'stream';
 if (hlsrecord.createDir)
@@ -56,7 +60,7 @@ if (hlsrecord.endDate)
 var options = {
   startDate: hlsrecord.beginDate,
   stopDate: hlsrecord.endDate,
-  maxStallTime: 5*60*1000,
+  maxStallTime: 5 * 60 * 1000,
   fullStream:true,
   highWaterMark:0,
 };
@@ -69,5 +73,5 @@ function createReader(src) {
   return r;
 }
 
-var r = createReader(src);
-recorder(r, outDir, { subreader:createReader }).start();
+var rdr = createReader(src);
+recorder(rdr, outDir, { subreader:createReader }).start();

+ 55 - 59
lib/reader.js

@@ -13,18 +13,9 @@ var extend = require('xtend'),
     uristream = require('uristream'),
     debug = require('debug')('hls:reader');
 
-try {
-  var Readable = require('stream').Readable;
-  assert(Readable);
-} catch (e) {
-  var Readable = require('readable-stream');
-}
+var Readable = require('readable-stream');
 
-function noop() {};
-
-module.exports = hlsreader;
-hlsreader.HlsSegmentObject = HlsSegmentObject;
-hlsreader.HlsStreamReader = HlsStreamReader;
+var noop = function noop() {};
 
 function HlsSegmentObject(seq, segment, meta, stream) {
   this.seq = seq;
@@ -33,11 +24,48 @@ function HlsSegmentObject(seq, segment, meta, stream) {
   this.stream = stream;
 }
 
+function fetchfrom(reader, seqNo, segment, cb) {
+  var segmentUrl = url.resolve(reader.baseUrl, segment.uri);
+  var probe = !!reader.noData;
+
+  debug('fetching segment', segmentUrl);
+  var stream = uristream(segmentUrl, { probe:probe, highWaterMark:100 * 1000 * 1000 });
+
+  function finish(err, res) {
+    stream.removeListener('meta', onmeta);
+    stream.removeListener('end', onfail);
+    stream.removeListener('error', onfail);
+    cb(err, res);
+  }
+
+  function onmeta(meta) {
+    debug('got segment meta', meta);
+
+    if (reader.segmentMimeTypes.indexOf(meta.mime.toLowerCase()) === -1) {
+      if (stream.abort) stream.abort();
+      return stream.emit(new Error('Unsupported segment MIME type: ' + meta.mime));
+    }
+
+    finish(null, new HlsSegmentObject(seqNo, segment, meta, stream));
+  }
+
+  function onfail(err) {
+    if (!err) err = new Error('No metadata');
+    finish(err);
+  }
+
+  stream.on('meta', onmeta);
+  stream.on('end', onfail);
+  stream.on('error', onfail);
+
+  return stream;
+}
+
 function checknext(reader) {
   var state = reader.readState;
   var index = reader.index;
   if (!state.active || state.fetching || state.nextSeq === -1 || !index)
-    return;
+    return null;
 
   var seq = state.nextSeq;
   var segment = index.getSegment(seq);
@@ -70,49 +98,13 @@ function checknext(reader) {
     });
   } else if (index.ended) {
     reader.push(null);
-  } else if (!index.type && (index.lastSeqNo() < state.nextSeq-1)) {
+  } else if (!index.type && (index.lastSeqNo() < state.nextSeq - 1)) {
     // handle live stream restart
     state.nextSeq = index.startSeqNo(true);
     checknext(reader);
   }
 }
 
-function fetchfrom(reader, seqNo, segment, cb) {
-  var segmentUrl = url.resolve(reader.baseUrl, segment.uri)
-  var probe = !!reader.noData;
-
-  debug('fetching segment', segmentUrl);
-  var stream = uristream(segmentUrl, { probe:probe, highWaterMark:100*1000*1000 });
-  stream.on('meta', onmeta);
-  stream.on('end', onfail);
-  stream.on('error', onfail);
-
-  function finish(err, res) {
-    stream.removeListener('meta', onmeta);
-    stream.removeListener('end', onfail);
-    stream.removeListener('error', onfail);
-    cb(err, res);
-  }
-
-  function onmeta(meta) {
-    debug('got segment meta', meta);
-
-    if (reader.segmentMimeTypes.indexOf(meta.mime.toLowerCase()) === -1) {
-      if (stream.abort) stream.abort();
-      return stream.emit(new Error('Unsupported segment MIME type: '+meta.mime));
-    }
-
-    finish(null, new HlsSegmentObject(seqNo, segment, meta, stream));
-  }
-
-  function onfail(err) {
-    if (!err) err = new Error('No metadata');
-    finish(err);
-  }
-
-  return stream;
-}
-
 function HlsStreamReader(src, options) {
   var self = this;
 
@@ -145,7 +137,7 @@ function HlsStreamReader(src, options) {
   function getUpdateInterval(updated) {
     if (updated && self.index.segments.length) {
       self.indexStallSince = null;
-      return Math.min(self.index.target_duration, self.index.segments[self.index.segments.length-1].duration);
+      return Math.min(self.index.target_duration, self.index.segments[self.index.segments.length - 1].duration);
     } else {
       if (self.indexStallSince) {
         if ((Date.now() - +self.indexStallSince) > self.maxStallTime)
@@ -164,7 +156,7 @@ function HlsStreamReader(src, options) {
       var count = index.segments.length;
       var time = 0, startTime = self.startDate.getTime();
 
-      for (var i=0; i<count; i++) {
+      for (var i = 0; i < count; i++) {
         var segment = index.segments[i];
         if (segment.program_time) {
           time = segment.program_time.getTime();
@@ -183,10 +175,10 @@ function HlsStreamReader(src, options) {
 
   function updatecheck(updated) {
     if (updated) {
-      if (self.readState.nextSeq===-1)
+      if (self.readState.nextSeq === -1)
         self.readState.nextSeq = initialSeqNo();
       else if (self.readState.nextSeq < self.index.startSeqNo(true)) {
-        debug('skipping '+(self.index.startSeqNo(true)-self.readState.nextSeq)+' invalidated segments');
+        debug('skipping ' + (self.index.startSeqNo(true) - self.readState.nextSeq) + ' invalidated segments');
         self.readState.nextSeq = self.index.startSeqNo(true);
       }
 
@@ -215,20 +207,20 @@ function HlsStreamReader(src, options) {
       if (updateInterval <= 0)
         return self.emit('error', new Error('index stall'));
       debug('scheduling index refresh', updateInterval);
-      setTimeout(updateindex, Math.max(1, updateInterval)*1000);
+      setTimeout(updateindex, Math.max(1, updateInterval) * 1000);
     }
   }
 
   function updateindex() {
     if (!self.readable) return;
-    var stream = uristream(url.format(self.url), { timeout:30*1000 });
+    var stream = uristream(url.format(self.url), { timeout:30 * 1000 });
     stream.on('meta', function(meta) {
       debug('got index meta', meta);
 
       if (self.indexMimeTypes.indexOf(meta.mime.toLowerCase()) === -1) {
         // FIXME: correctly handle .m3u us-ascii encoding
         if (stream.abort) stream.abort();
-        return stream.emit('error', new Error('Invalid MIME type: '+meta.mime));
+        return stream.emit('error', new Error('Invalid MIME type: ' + meta.mime));
       }
 
       self.baseUrl = meta.url;
@@ -270,11 +262,15 @@ HlsStreamReader.prototype.segmentMimeTypes = [
   'audio/ac3',
 ];
 
-HlsStreamReader.prototype._read = function(n) {
+HlsStreamReader.prototype._read = function(/*n*/) {
   this.readState.active = true;
   checknext(this);
 };
 
-function hlsreader(url, options) {
+
+var hlsreader = module.exports = function hlsreader(url, options) {
   return new HlsStreamReader(url, options);
-}
+};
+
+hlsreader.HlsSegmentObject = HlsSegmentObject;
+hlsreader.HlsStreamReader = HlsStreamReader;

+ 13 - 13
lib/recorder.js

@@ -1,3 +1,5 @@
+"use strict";
+
 var fs = require('fs'),
     path = require('path'),
     url = require('url'),
@@ -9,9 +11,6 @@ var mime = require('mime'),
     m3u8parse = require('m3u8parse'),
     debug = require('debug')('hls:recorder');
 
-module.exports = hlsrecorder;
-hlsrecorder.HlsStreamRecorder = HlsStreamRecorder;
-
 function HlsStreamRecorder(reader, dst, options) {
   options = options || {};
 
@@ -26,8 +25,6 @@ function HlsStreamRecorder(reader, dst, options) {
 }
 
 HlsStreamRecorder.prototype.start = function() {
-  var self = this;
-
   // TODO: make async?
   if (!fs.existsSync(this.dst))
     fs.mkdirSync(this.dst);
@@ -71,7 +68,7 @@ HlsStreamRecorder.prototype.updateIndex = function(update) {
           debug('url', programUrl);
           var dir = self.variantName(program.info, index);
           program.uri = path.join(dir, 'index.m3u8');
-          program.recorder = hlsrecorder(self.subreader(programUrl), path.join(self.dst, dir)).start();
+          program.recorder = new HlsStreamRecorder(self.subreader(programUrl), path.join(self.dst, dir)).start();
         });
       }
 
@@ -87,7 +84,7 @@ HlsStreamRecorder.prototype.updateIndex = function(update) {
     // hook end listener
     this.reader.on('end', function() {
       self.index.ended = true;
-      self.flushIndex(function(err) {
+      self.flushIndex(function(/*err*/) {
         debug('done');
       });
     });
@@ -108,7 +105,7 @@ HlsStreamRecorder.prototype.process = function(obj, next) {
   if (this.nextSegmentSeq !== -1 &&
       this.nextSegmentSeq !== obj.seq)
     segment.discontinuity = true;
-  this.nextSegmentSeq = obj.seq+1;
+  this.nextSegmentSeq = obj.seq + 1;
 
   // create our own uri
   segment.uri = util.format('%s.%s', this.segmentName(this.seq), mime.extension(meta.mime));
@@ -144,9 +141,9 @@ HlsStreamRecorder.prototype.variantName = function(info, index) {
 
 HlsStreamRecorder.prototype.segmentName = function(seqNo) {
   function name(n) {
-    var next = ~~(n/26);
-    var chr = String.fromCharCode(97 + n%26); // 'a' + n
-    if (next) return name(next-1) + chr;
+    var next = ~~(n / 26);
+    var chr = String.fromCharCode(97 + n % 26); // 'a' + n
+    if (next) return name(next - 1) + chr;
     return chr;
   }
   return name(seqNo);
@@ -157,6 +154,9 @@ HlsStreamRecorder.prototype.flushIndex = function(cb) {
   fs.writeFile(path.join(this.dst, 'index.m3u8'), this.index, cb);
 };
 
-function hlsrecorder(reader, dst, options) {
+
+var hlsrecorder = module.exports = function hlsrecorder(reader, dst, options) {
   return new HlsStreamRecorder(reader, dst, options);
-}
+};
+
+hlsrecorder.HlsStreamRecorder = HlsStreamRecorder;

+ 9 - 14
lib/tsblast.js

@@ -4,18 +4,9 @@ var dgram = require('dgram'),
     util = require('util'),
     assert = require('assert');
 
-try {
-  var Writable = require('stream').Writable;
-  assert(Writable);
-} catch (e) {
-  var Writable = require('readable-stream/writable');
-}
-
-module.exports = tsblast;
-exports.TsBlast = TsBlast;
+var Writable = require('readable-stream/writable');
 
 function TsBlast(dst, options) {
-  var self = this;
   Writable.call(this, options);
 
   if (typeof dst === 'number')
@@ -46,11 +37,12 @@ TsBlast.prototype._write = function(chunk, encoding, cb) {
       this.buffer = chunk;
   }
 
-  var index = 0, psize = 188*7;
+  var index = 0, psize = 188 * 7;
 
   function sendnext() {
     if ((self.buffer.length - index) >= psize) {
-      self.client.send(self.buffer, index, psize, self.dst.port, self.dst.host, function(err, bytes) {
+      self.client.send(self.buffer, index, psize, self.dst.port, self.dst.host, function(/*err, bytes*/) {
+        // TODO: handle errors?
         index += psize;
         sendnext();
       });
@@ -67,6 +59,9 @@ TsBlast.prototype._write = function(chunk, encoding, cb) {
   sendnext();
 };
 
-function tsblast(dst, options) {
+
+var tsblast = module.exports = function tsblast(dst, options) {
   return new TsBlast(dst, options);
-}
+};
+
+tsblast.TsBlast = TsBlast;

+ 62 - 65
lib/tssmooth.js

@@ -4,18 +4,10 @@ var util = require('util'),
     assert = require('assert'),
     debug = require('debug')('hls:tssmooth');
 
-try {
-  var Transform = require('stream').Transform;
-  assert(Transform);
-} catch (e) {
-  var Transform = require('readable-stream/transform');
-}
+var Transform = require('readable-stream/transform');
 
 // In Transport Streams the intended rate is determined by the values of the PCR fields and the number of Transport Stream bytes between them. (ISO-13818-1 D.0.9)
 
-module.exports = tssmooth;
-exports.TsSmooth = TsSmooth;
-
 function RateError(msg) {
   Error.call(this);
 
@@ -30,14 +22,14 @@ function parsePCR(buffer, index, pcr_pid) {
   if (((head >> 5) & 1) !== 1) return -1;
   if (pcr_pid && pcr_pid != pid) return -1;
 
-  var s = buffer.readUInt8(index+4, true);
+  var s = buffer.readUInt8(index + 4, true);
   if (s < 7) return -1;
 
-  var f = buffer.readUInt8(index+5, true);
+  var f = buffer.readUInt8(index + 5, true);
   if (((f >> 4) & 1) !== 1) return -1;
 
-  var base = buffer.readUInt32BE(index+6, true) * 2;
-  var ext = buffer.readUInt32BE(index+10, true);
+  var base = buffer.readUInt32BE(index + 6, true) * 2;
+  var ext = buffer.readUInt32BE(index + 10, true);
 
   base += (ext >> 31);
   ext = ext & 0x1ff;
@@ -45,26 +37,39 @@ function parsePCR(buffer, index, pcr_pid) {
   return base / 0.09 + ext / 27; // return usecs
 }
 
+function utime() {
+  var t = process.hrtime(); // based on CLOCK_MONOTONIC, and thus accommodates local drift (but apparently not suspend)
+//  console.error(t);
+  return t[0] * 1E6 + t[1] / 1E3;
+}
+
+function wait(waitMs, fn) {
+  if (waitMs > 0)
+    setTimeout(fn, waitMs);
+  else
+    fn();
+}
+
 function TsSmooth(options) {
   var self = this;
   options = options || {};
 
-  this.packetSize = options.packetSize || 7*188; // size of output packets
+  this.packetSize = options.packetSize || 7 * 188; // size of output packets
 
   this.buffer = new Buffer(0);
 
   this.pcr = -1;
   this.last = null;
 
-  this.error_limit = 80000; /* 80 ms */
+  this.errorLimit = 80000; /* 80 ms */
   this.bitrate = 10E06;
-  this.pcrtime = -1;
+  this.pcrTime = -1;
 
-  this.pcrdelta = function(pcr, pcr_old) {
-    var pcr_delta = pcr - pcr_old;
-    if (pcr_delta < 0) pcr_delta += (0x200000000 * 300) / 27;
-    return pcr_delta;
-  }
+  this.pcrDelta = function(pcr, lastPcr) {
+    var pcrDelta = pcr - lastPcr;
+    if (pcrDelta < 0) pcrDelta += (0x200000000 * 300) / 27;
+    return pcrDelta;
+  };
 
   this.pcr2time = function(pcr) {
     if (self.pcr === -1) {
@@ -72,31 +77,31 @@ function TsSmooth(options) {
       self.last = utime();
     }
 
-    var pcr_delta = self.pcrdelta(pcr, self.pcr);
-    var ret = self.last + pcr_delta;
-    if (pcr_delta > 3600E6) {
+    var pcrDelta = self.pcrDelta(pcr, self.pcr);
+    var ret = self.last + pcrDelta;
+    if (pcrDelta > 3600E6) {
       // update pcr reference every hour to handle wrap-around
       self.pcr = pcr;
       self.last = ret;
     }
     return ret;
-  }
+  };
 
-  this.output_time = function(newPCR) {
+  this.outputTime = function(newPCR) {
     // when this is called normally, now ~= self.pcrtime
-    if (newPCR === -1) return;
+    if (newPCR === -1) return undefined;
 
     var pcrtime = self.pcr2time(newPCR);
-    if (self.pcrtime === -1) {
-      self.pcrtime = pcrtime;
-      return;
+    if (self.pcrTime === -1) {
+      self.pcrTime = pcrtime;
+      return undefined;
     }
 
-    var delta = pcrtime - self.pcrtime;
-    self.pcrtime = pcrtime;
+    var delta = pcrtime - self.pcrTime;
+    self.pcrTime = pcrtime;
 
     return { time:pcrtime, delta: delta };
-  }
+  };
 
   Transform.call(this, {highWaterMark:this.packetSize});
 }
@@ -105,22 +110,9 @@ util.inherits(TsSmooth, Transform);
 TsSmooth.prototype.reset = function(currentPCR) {
   this.pcr = -1;
   if (typeof currentPCR !== 'undefined')
-    this.pcrtime = this.pcr2time(currentPCR);
+    this.pcrTime = this.pcr2time(currentPCR);
 };
 
-function utime() {
-  var t = process.hrtime(); // based on CLOCK_MONOTONIC, and thus accommodates local drift (but apparently not suspend)
-//  console.error(t);
-  return t[0] * 1E6 + t[1] / 1E3;
-}
-
-function wait(waitMs, fn) {
-  if (waitMs > 0)
-    setTimeout(fn, waitMs);
-  else
-    fn();
-}
-
 // smoothly outputs given buffer before endTime
 function outputBefore(stream, buffer, endTime, packetSize, cb) {
   var index = 0;
@@ -129,11 +121,11 @@ function outputBefore(stream, buffer, endTime, packetSize, cb) {
     var now = utime();
     var packetTime = (endTime - now) * (packetSize / (buffer.length - index));
 
-    stream.push(buffer.slice(index, Math.min(buffer.length, index+packetSize)));
+    stream.push(buffer.slice(index, Math.min(buffer.length, index + packetSize)));
     index += packetSize;
 
-    var done = (index < buffer.length) ? outputPacket: cb;
-    var delay = Math.min(Math.max((0.8*packetTime/1000)-1, 1), 50);
+    var done = (index < buffer.length) ? outputPacket : cb;
+    var delay = Math.min(Math.max((0.8 * packetTime / 1000) - 1, 1), 50);
     if (delay === 1)
       process.nextTick(done);
     else
@@ -145,20 +137,20 @@ function outputBefore(stream, buffer, endTime, packetSize, cb) {
 TsSmooth.prototype._transform = function(chunk, encoding, cb) {
   var self = this;
 
-  var index = Math.floor(this.buffer.length/188)*188;
+  var index = Math.floor(this.buffer.length / 188) * 188;
   this.buffer = Buffer.concat([this.buffer, chunk]);
 
   var buf = self.buffer;
-  var end = buf.length-188;
+  var end = buf.length - 188;
 
   var startIndex = 0;
   function processNext() {
     while (index < end) {
       // check sync
-      if (buf.readUInt8(index+188, true) !== 0x47) {
+      if (buf.readUInt8(index + 188, true) !== 0x47) {
         // find next potential sync point
         debug('ts sync lost');
-        var sync = index+1;
+        var sync = index + 1;
         for (; sync < end; sync++) {
           if (buf.readUInt8(sync, true) === 0x47)
             break;
@@ -166,36 +158,38 @@ TsSmooth.prototype._transform = function(chunk, encoding, cb) {
         // remove bad data
         debug('slice', sync, end);
         buf = Buffer.concat([buf.slice(0, index), buf.slice(sync)]);
-        end -= sync-index;
+        end -= sync - index;
         continue;
       }
 
       var pcr = parsePCR(buf, index);
-      var out = self.output_time(pcr);
+      var out = self.outputTime(pcr);
       if (out !== undefined && index !== startIndex) {
         if (out.delta > 100E3 || out.delta < 0)
-          self.emit('warning', new Error('PCR_error: '+(out.delta/1E6).toFixed(2)+'s missing'));
+          self.emit('warning', new Error('PCR_error: ' + (out.delta / 1E6).toFixed(2) + 's missing'));
 
         var now = utime();
         var error = (out.time - now) - out.delta;
-        var waittime = (error > self.error_limit) ? (error/1000 - 5) : 0;
+        var waittime = (error > self.errorLimit) ? (error / 1000 - 5) : 0;
 
-        if (error < -2*1E6 || error > 300*1E6) {
+        if (error < -2 * 1E6 || error > 300 * 1E6) {
           // negative == buffer too late
           // positive == buffer too early
-          self.emit('warning', new RateError('PCR sync offset '+(error/1E6).toFixed(2)+'s error'));
+          self.emit('warning', new RateError('PCR sync offset ' + (error / 1E6).toFixed(2) + 's error'));
           self.reset(pcr);
           waittime = 0;
-        } else if (error < -self.error_limit) {
+        } else if (error < -self.errorLimit) {
           // ignore the data since it is too late
           return setImmediate(processNext);
         }
 
+        var slice = buf.slice(startIndex, index);
+        startIndex = index;
+        /* eslint-disable no-loop-func */
         return wait(waittime, function output() {
-          var slice = buf.slice(startIndex, index);
-          startIndex = index;
           return outputBefore(self, slice, out.time, self.packetSize, processNext);
         });
+        /* eslint-enable */
       }
       index += 188;
     }
@@ -212,6 +206,9 @@ TsSmooth.prototype._flush = function(cb) {
   cb();
 };
 
-function tssmooth(options) {
+
+var tssmooth = module.exports = function tssmooth(options) {
   return new TsSmooth(options);
-}
+};
+
+tssmooth.TsSmooth = TsSmooth;