buddy

node MVC discord bot
Log | Files | Refs | README

BasePlayer.js (2752B)


      1 'use strict';
      2 
      3 const EventEmitter = require('events');
      4 const { Readable: ReadableStream } = require('stream');
      5 const prism = require('prism-media');
      6 const StreamDispatcher = require('../dispatcher/StreamDispatcher');
      7 
      8 const FFMPEG_ARGUMENTS = ['-analyzeduration', '0', '-loglevel', '0', '-f', 's16le', '-ar', '48000', '-ac', '2'];
      9 
     10 /**
     11  * An Audio Player for a Voice Connection.
     12  * @private
     13  * @extends {EventEmitter}
     14  */
     15 class BasePlayer extends EventEmitter {
     16   constructor() {
     17     super();
     18 
     19     this.dispatcher = null;
     20 
     21     this.streamingData = {
     22       channels: 2,
     23       sequence: 0,
     24       timestamp: 0,
     25     };
     26   }
     27 
     28   destroy() {
     29     this.destroyDispatcher();
     30   }
     31 
     32   destroyDispatcher() {
     33     if (this.dispatcher) {
     34       this.dispatcher.destroy();
     35       this.dispatcher = null;
     36     }
     37   }
     38 
     39   playUnknown(input, options) {
     40     this.destroyDispatcher();
     41 
     42     const isStream = input instanceof ReadableStream;
     43 
     44     const args = isStream ? FFMPEG_ARGUMENTS.slice() : ['-i', input, ...FFMPEG_ARGUMENTS];
     45     if (options.seek) args.unshift('-ss', String(options.seek));
     46 
     47     const ffmpeg = new prism.FFmpeg({ args });
     48     const streams = { ffmpeg };
     49     if (isStream) {
     50       streams.input = input;
     51       input.pipe(ffmpeg);
     52     }
     53     return this.playPCMStream(ffmpeg, options, streams);
     54   }
     55 
     56   playPCMStream(stream, options, streams = {}) {
     57     this.destroyDispatcher();
     58     const opus = (streams.opus = new prism.opus.Encoder({ channels: 2, rate: 48000, frameSize: 960 }));
     59     if (options && options.volume === false) {
     60       stream.pipe(opus);
     61       return this.playOpusStream(opus, options, streams);
     62     }
     63     streams.volume = new prism.VolumeTransformer({ type: 's16le', volume: options ? options.volume : 1 });
     64     stream.pipe(streams.volume).pipe(opus);
     65     return this.playOpusStream(opus, options, streams);
     66   }
     67 
     68   playOpusStream(stream, options, streams = {}) {
     69     this.destroyDispatcher();
     70     streams.opus = stream;
     71     if (options.volume !== false && !streams.input) {
     72       streams.input = stream;
     73       const decoder = new prism.opus.Decoder({ channels: 2, rate: 48000, frameSize: 960 });
     74       streams.volume = new prism.VolumeTransformer({ type: 's16le', volume: options ? options.volume : 1 });
     75       streams.opus = stream
     76         .pipe(decoder)
     77         .pipe(streams.volume)
     78         .pipe(new prism.opus.Encoder({ channels: 2, rate: 48000, frameSize: 960 }));
     79     }
     80     const dispatcher = this.createDispatcher(options, streams);
     81     streams.opus.pipe(dispatcher);
     82     return dispatcher;
     83   }
     84 
     85   createDispatcher(options, streams, broadcast) {
     86     this.destroyDispatcher();
     87     const dispatcher = (this.dispatcher = new StreamDispatcher(this, options, streams, broadcast));
     88     return dispatcher;
     89   }
     90 }
     91 
     92 module.exports = BasePlayer;