class Discordrb::Voice::Encoder
This class conveniently abstracts opus and ffmpeg/avconv, for easy implementation of voice sending. It’s not very useful for most users, but I guess it can be useful sometimes.
Constants
- OPUS_SILENCE
One frame of complete silence Opus encoded
Attributes
@see VoiceBot#filter_volume=
@return [Integer] the volume used as a filter to ffmpeg/avconv.
Whether or not avconv should be used instead of ffmpeg. If possible, it is recommended to use ffmpeg instead, as it is better supported. @return [true, false] whether avconv should be used instead of ffmpeg.
Public Class Methods
Create a new encoder
# File lib/discordrb/voice/encoder.rb, line 26 def initialize sample_rate = 48_000 frame_size = 960 channels = 2 @filter_volume = 1 raise LoadError, 'Opus unavailable - voice not supported! Please install opus for voice support to work.' unless OPUS_AVAILABLE @opus = Opus::Encoder.new(sample_rate, frame_size, channels) end
Public Instance Methods
Adjusts the volume of a given buffer of s16le PCM data. @param buf [String] An unencoded PCM (s16le) buffer. @param mult [Float] The volume multiplier, 1 for same volume. @return [String] The buffer with adjusted volume, s16le again
# File lib/discordrb/voice/encoder.rb, line 57 def adjust_volume(buf, mult) # We don't need to adjust anything if the buf is nil so just return in that case return unless buf # buf is s16le so use 's<' for signed, 16 bit, LE result = buf.unpack('s<*').map do |sample| sample *= mult # clamp to s16 range [32_767, [-32_768, sample].max].min end # After modification, make it s16le again result.pack('s<*') end
Set the opus encoding bitrate @param value [Integer] The new bitrate to use, in bits per second (so 64000 if you want 64 kbps)
# File lib/discordrb/voice/encoder.rb, line 39 def bitrate=(value) @opus.bitrate = value end
Encodes the given buffer using opus. @param buffer [String] An unencoded PCM (s16le) buffer. @return [String] A buffer encoded using opus.
# File lib/discordrb/voice/encoder.rb, line 46 def encode(buffer) @opus.encode(buffer, 1920) end
Encodes a given file (or rather, decodes it) using ffmpeg. This accepts pretty much any format, even videos with an audio track. For a list of supported formats, see ffmpeg.org/general.html#Audio-Codecs. It even accepts URLs, though encoding them is pretty slow - I recommend to make a stream of it and then use {#encode_io} instead. @param file [String] The path or URL to encode. @param options [String] ffmpeg options to pass after the -i flag @return [IO] the audio, encoded as s16le PCM
# File lib/discordrb/voice/encoder.rb, line 79 def encode_file(file, options = '') command = ffmpeg_command(input: file, options: options) IO.popen(command) end
Encodes an arbitrary IO audio stream using ffmpeg. Accepts pretty much any media format, even videos with audio tracks. For a list of supported audio formats, see ffmpeg.org/general.html#Audio-Codecs. @param io [IO] The stream to encode. @param options [String] ffmpeg options to pass after the -i flag @return [IO] the audio, encoded as s16le PCM
# File lib/discordrb/voice/encoder.rb, line 89 def encode_io(io, options = '') command = ffmpeg_command(options: options) IO.popen(command, in: io) end
Private Instance Methods
# File lib/discordrb/voice/encoder.rb, line 96 def ffmpeg_command(input: '-', options: null) [ @use_avconv ? 'avconv' : 'ffmpeg', '-loglevel', '0', '-i', input, '-f', 's16le', '-ar', '48000', '-ac', '2', 'pipe:1', filter_volume_argument ].concat(options.split).reject { |segment| segment.nil? || segment == '' } end
# File lib/discordrb/voice/encoder.rb, line 109 def filter_volume_argument return '' if @filter_volume == 1 @use_avconv ? "-vol #{(@filter_volume * 256).ceil}" : "-af volume=#{@filter_volume}" end