Class: Discordrb::Voice::Encoder
- Inherits:
-
Object
- Object
- Discordrb::Voice::Encoder
- Defined in:
- lib/discordrb/voice/encoder.rb
Overview
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.
Constant Summary collapse
- OPUS_SILENCE =
One frame of complete silence Opus encoded
[0xF8, 0xFF, 0xFE].pack('C*').freeze
Instance Attribute Summary collapse
-
#filter_volume ⇒ Integer
The volume used as a filter to ffmpeg/avconv.
-
#use_avconv ⇒ true, false
Whether or not avconv should be used instead of ffmpeg.
Instance Method Summary collapse
-
#adjust_volume(buf, mult) ⇒ String
Adjusts the volume of a given buffer of s16le PCM data.
-
#bitrate=(value) ⇒ Object
Set the opus encoding bitrate.
-
#encode(buffer) ⇒ String
Encodes the given buffer using opus.
-
#encode_file(file, options = '') ⇒ IO
Encodes a given file (or rather, decodes it) using ffmpeg.
-
#encode_io(io, options = '') ⇒ IO
Encodes an arbitrary IO audio stream using ffmpeg.
-
#initialize ⇒ Encoder
constructor
Create a new encoder.
Constructor Details
#initialize ⇒ Encoder
Create a new encoder
26 27 28 29 30 31 32 33 34 35 |
# 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 |
Instance Attribute Details
#filter_volume ⇒ Integer
Returns the volume used as a filter to ffmpeg/avconv.
23 24 25 |
# File 'lib/discordrb/voice/encoder.rb', line 23 def filter_volume @filter_volume end |
#use_avconv ⇒ true, false
Whether or not avconv should be used instead of ffmpeg. If possible, it is recommended to use ffmpeg instead, as it is better supported.
19 20 21 |
# File 'lib/discordrb/voice/encoder.rb', line 19 def use_avconv @use_avconv end |
Instance Method Details
#adjust_volume(buf, mult) ⇒ String
Adjusts the volume of a given buffer of s16le PCM data.
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# 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 |
#bitrate=(value) ⇒ Object
Set the opus encoding bitrate
39 40 41 |
# File 'lib/discordrb/voice/encoder.rb', line 39 def bitrate=(value) @opus.bitrate = value end |
#encode(buffer) ⇒ String
Encodes the given buffer using opus.
46 47 48 |
# File 'lib/discordrb/voice/encoder.rb', line 46 def encode(buffer) @opus.encode(buffer, 1920) end |
#encode_file(file, options = '') ⇒ IO
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 https://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.
79 80 81 82 |
# File 'lib/discordrb/voice/encoder.rb', line 79 def encode_file(file, = '') command = "#{ffmpeg_command} -loglevel 0 -i \"#{file}\" #{} -f s16le -ar 48000 -ac 2 #{filter_volume_argument} pipe:1" IO.popen(command) end |
#encode_io(io, options = '') ⇒ IO
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 https://ffmpeg.org/general.html#Audio-Codecs.
89 90 91 92 93 94 |
# File 'lib/discordrb/voice/encoder.rb', line 89 def encode_io(io, = '') ret_io, writer = IO.pipe command = "#{ffmpeg_command} -loglevel 0 -i - #{} -f s16le -ar 48000 -ac 2 #{filter_volume_argument} pipe:1" spawn(command, in: io, out: writer) ret_io end |