PlayInterface.js (4246B)
1 'use strict'; 2 3 const { Readable } = require('stream'); 4 const prism = require('prism-media'); 5 const { Error } = require('../../../errors'); 6 7 /** 8 * Options that can be passed to stream-playing methods: 9 * @typedef {Object} StreamOptions 10 * @property {StreamType} [type='unknown'] The type of stream. 11 * @property {number} [seek=0] The time to seek to, will be ignored when playing `ogg/opus` or `webm/opus` streams 12 * @property {number|boolean} [volume=1] The volume to play at. Set this to false to disable volume transforms for 13 * this stream to improve performance. 14 * @property {number} [plp] Expected packet loss percentage 15 * @property {boolean} [fec] Enabled forward error correction 16 * @property {number|string} [bitrate=96] The bitrate (quality) of the audio in kbps. 17 * If set to 'auto', the voice channel's bitrate will be used 18 * @property {number} [highWaterMark=12] The maximum number of opus packets to make and store before they are 19 * actually needed. See https://nodejs.org/en/docs/guides/backpressuring-in-streams/. Setting this value to 20 * 1 means that changes in volume will be more instant. 21 */ 22 23 /** 24 * An option passed as part of `StreamOptions` specifying the type of the stream. 25 * * `unknown`: The default type, streams/input will be passed through to ffmpeg before encoding. 26 * Will play most streams. 27 * * `converted`: Play a stream of 16bit signed stereo PCM data, skipping ffmpeg. 28 * * `opus`: Play a stream of opus packets, skipping ffmpeg. You lose the ability to alter volume. 29 * * `ogg/opus`: Play an ogg file with the opus encoding, skipping ffmpeg. You lose the ability to alter volume. 30 * * `webm/opus`: Play a webm file with opus audio, skipping ffmpeg. You lose the ability to alter volume. 31 * @typedef {string} StreamType 32 */ 33 34 /** 35 * An interface class to allow you to play audio over VoiceConnections and VoiceBroadcasts. 36 */ 37 class PlayInterface { 38 constructor(player) { 39 this.player = player; 40 } 41 42 /** 43 * Play an audio resource. 44 * @param {VoiceBroadcast|ReadableStream|string} resource The resource to play. 45 * @param {StreamOptions} [options] The options to play. 46 * @example 47 * // Play a local audio file 48 * connection.play('/home/hydrabolt/audio.mp3', { volume: 0.5 }); 49 * @example 50 * // Play a ReadableStream 51 * connection.play(ytdl('https://www.youtube.com/watch?v=ZlAU_w7-Xp8', { quality: 'highestaudio' })); 52 * @example 53 * // Play a voice broadcast 54 * const broadcast = client.voice.createBroadcast(); 55 * broadcast.play('/home/hydrabolt/audio.mp3'); 56 * connection.play(broadcast); 57 * @example 58 * // Using different protocols: https://ffmpeg.org/ffmpeg-protocols.html 59 * connection.play('http://www.sample-videos.com/audio/mp3/wave.mp3'); 60 * @returns {StreamDispatcher} 61 */ 62 play(resource, options = {}) { 63 const VoiceBroadcast = require('../VoiceBroadcast'); 64 if (resource instanceof VoiceBroadcast) { 65 if (!this.player.playBroadcast) throw new Error('VOICE_PLAY_INTERFACE_NO_BROADCAST'); 66 return this.player.playBroadcast(resource, options); 67 } 68 if (resource instanceof Readable || typeof resource === 'string') { 69 const type = options.type || 'unknown'; 70 if (type === 'unknown') { 71 return this.player.playUnknown(resource, options); 72 } else if (type === 'converted') { 73 return this.player.playPCMStream(resource, options); 74 } else if (type === 'opus') { 75 return this.player.playOpusStream(resource, options); 76 } else if (type === 'ogg/opus') { 77 if (!(resource instanceof Readable)) throw new Error('VOICE_PRISM_DEMUXERS_NEED_STREAM'); 78 return this.player.playOpusStream(resource.pipe(new prism.opus.OggDemuxer()), options); 79 } else if (type === 'webm/opus') { 80 if (!(resource instanceof Readable)) throw new Error('VOICE_PRISM_DEMUXERS_NEED_STREAM'); 81 return this.player.playOpusStream(resource.pipe(new prism.opus.WebmDemuxer()), options); 82 } 83 } 84 throw new Error('VOICE_PLAY_INTERFACE_BAD_TYPE'); 85 } 86 87 static applyToClass(structure) { 88 for (const prop of ['play']) { 89 Object.defineProperty(structure.prototype, prop, Object.getOwnPropertyDescriptor(PlayInterface.prototype, prop)); 90 } 91 } 92 } 93 94 module.exports = PlayInterface;