summaryrefslogtreecommitdiff
path: root/node_modules/@discordjs/opus/src/node-opus.cc
diff options
context:
space:
mode:
author8cy <[email protected]>2020-04-03 02:37:42 -0700
committer8cy <[email protected]>2020-04-03 02:37:42 -0700
commit60867fb030bae582082340ead7dbc7efdc2f5398 (patch)
tree4c6a7356351be2e4914e15c4703172597c45656e /node_modules/@discordjs/opus/src/node-opus.cc
parentcommenting (diff)
downloads5nical-60867fb030bae582082340ead7dbc7efdc2f5398.tar.xz
s5nical-60867fb030bae582082340ead7dbc7efdc2f5398.zip
2020/04/03, 02:34, v1.2.0
Diffstat (limited to 'node_modules/@discordjs/opus/src/node-opus.cc')
-rw-r--r--node_modules/@discordjs/opus/src/node-opus.cc197
1 files changed, 197 insertions, 0 deletions
diff --git a/node_modules/@discordjs/opus/src/node-opus.cc b/node_modules/@discordjs/opus/src/node-opus.cc
new file mode 100644
index 0000000..c63321a
--- /dev/null
+++ b/node_modules/@discordjs/opus/src/node-opus.cc
@@ -0,0 +1,197 @@
+#include "napi.h"
+#include "../deps/opus/include/opus.h"
+#include "node-opus.h"
+
+using namespace Napi;
+
+const char* getDecodeError(int decodedSamples) {
+ switch(decodedSamples) {
+ case OPUS_BAD_ARG:
+ return "One or more invalid/out of range arguments";
+ case OPUS_BUFFER_TOO_SMALL:
+ return "The mode struct passed is invalid";
+ case OPUS_INTERNAL_ERROR:
+ return "An internal error was detected";
+ case OPUS_INVALID_PACKET:
+ return "The compressed data passed is corrupted";
+ case OPUS_UNIMPLEMENTED:
+ return "Invalid/unsupported request number";
+ case OPUS_INVALID_STATE:
+ return "An encoder or decoder structure is invalid or already freed.";
+ case OPUS_ALLOC_FAIL:
+ return "Memory allocation has failed";
+ default:
+ return "Unknown OPUS error";
+ }
+}
+
+Object OpusEncoder::Init(Napi::Env env, Object exports) {
+ HandleScope scope(env);
+
+ Function func = DefineClass(env, "OpusEncoder", {
+ InstanceMethod("encode", &OpusEncoder::Encode),
+ InstanceMethod("decode", &OpusEncoder::Decode),
+ InstanceMethod("applyEncoderCTL", &OpusEncoder::ApplyEncoderCTL),
+ InstanceMethod("applyDecoderCTL", &OpusEncoder::ApplyDecoderCTL),
+ InstanceMethod("setBitrate", &OpusEncoder::SetBitrate),
+ InstanceMethod("getBitrate", &OpusEncoder::GetBitrate),
+ });
+
+ exports.Set("OpusEncoder", func);
+ return exports;
+}
+
+OpusEncoder::OpusEncoder(const CallbackInfo& args): ObjectWrap<OpusEncoder>(args) {
+ this->encoder = nullptr;
+ this->decoder = nullptr;
+ this->rate = args[0].ToNumber().Int32Value();
+ this->channels = args[1].ToNumber().Int32Value();
+ this->application = OPUS_APPLICATION_AUDIO;
+ this->outPcm = new opus_int16[channels * MAX_FRAME_SIZE];
+}
+
+OpusEncoder::~OpusEncoder() {
+ if (this->encoder) opus_encoder_destroy(this->encoder);
+ if (this->decoder) opus_decoder_destroy(this->decoder);
+
+ this->encoder = nullptr;
+ this->decoder = nullptr;
+
+ delete this->outPcm;
+ this->outPcm = nullptr;
+}
+
+int OpusEncoder::EnsureEncoder() {
+ if (this->encoder) return 0;
+
+ int error;
+ this->encoder = opus_encoder_create(rate, channels, application, &error);
+
+ return error;
+}
+
+int OpusEncoder::EnsureDecoder() {
+ if (this->decoder) return 0;
+
+ int error;
+ this->decoder = opus_decoder_create(rate, channels, &error);
+
+ return error;
+}
+
+Napi::Value OpusEncoder::Encode(const CallbackInfo& args) {
+ Napi::Env env = args.Env();
+
+ if (this->EnsureEncoder() != OPUS_OK) {
+ Napi::Error::New(env, "Could not create encoder. Check the encoder parameters").ThrowAsJavaScriptException();
+ }
+
+ if (!args[0].IsBuffer()) {
+ Napi::TypeError::New(env, "This needs to be a buffer").ThrowAsJavaScriptException();
+ }
+
+ Buffer<char> buf = args[0].As<Buffer<char>>();
+ char* pcmData = buf.Data();
+ opus_int16* pcm = reinterpret_cast<opus_int16*>(pcmData);
+ int frameSize = buf.Length() / 2 / this->channels;
+
+ int compressedLength = opus_encode(this->encoder, pcm, frameSize, &(this->outOpus[0]), MAX_PACKET_SIZE);
+
+ Buffer<char> actualBuf = Buffer<char>::Copy(env, reinterpret_cast<char*>(this->outOpus), compressedLength);
+
+ if (!actualBuf.IsEmpty()) return actualBuf;
+}
+
+Napi::Value OpusEncoder::Decode(const CallbackInfo& args) {
+ Napi::Env env = args.Env();
+
+ Buffer<unsigned char> buf = args[0].As<Buffer<unsigned char>>();
+ unsigned char* compressedData = buf.Data();
+ size_t compressedDataLength = buf.Length();
+
+ if (this->EnsureDecoder() != OPUS_OK) {
+ Napi::Error::New(env, "Could not create decoder. Check the decoder parameters").ThrowAsJavaScriptException();
+ }
+
+ int decodedSamples = opus_decode(
+ this->decoder,
+ compressedData,
+ compressedDataLength,
+ &(this->outPcm[0]),
+ MAX_FRAME_SIZE,
+ /* decode_fec */ 0
+ );
+
+ if (decodedSamples < 0) {
+ Napi::TypeError::New(env, getDecodeError(decodedSamples)).ThrowAsJavaScriptException();
+ }
+
+ int decodedLength = decodedSamples * 2 * this->channels;
+
+ Buffer<char> actualBuf = Buffer<char>::Copy(env, reinterpret_cast<char*>(this->outPcm), decodedLength);
+
+ if (!actualBuf.IsEmpty()) return actualBuf;
+}
+
+void OpusEncoder::ApplyEncoderCTL(const CallbackInfo& args) {
+ Napi::Env env = args.Env();
+
+ int ctl = args[0].ToNumber().Int32Value();
+ int value = args[1].ToNumber().Int32Value();
+
+ if (this->EnsureEncoder() != OPUS_OK) {
+ Napi::Error::New(env, "Could not create encoder. Check the encoder parameters").ThrowAsJavaScriptException();
+ }
+
+ if (opus_encoder_ctl(this->encoder, ctl, value) != OPUS_OK) {
+ Napi::TypeError::New(env, "Invalid ctl / value").ThrowAsJavaScriptException();
+ }
+}
+
+void OpusEncoder::ApplyDecoderCTL(const CallbackInfo& args) {
+ Napi::Env env = args.Env();
+
+ int ctl = args[0].ToNumber().Int32Value();
+ int value = args[1].ToNumber().Int32Value();
+
+ if (this->EnsureDecoder() != OPUS_OK) {
+ Napi::Error::New(env, "Could not create decoder. Check the decoder parameters").ThrowAsJavaScriptException();
+ }
+
+ if (opus_decoder_ctl(this->decoder, ctl, value) != OPUS_OK) {
+ Napi::TypeError::New(env, "Invalid ctl / value").ThrowAsJavaScriptException();
+ }
+}
+
+void OpusEncoder::SetBitrate(const CallbackInfo& args) {
+ Napi::Env env = args.Env();
+
+ int bitrate = args[0].ToNumber().Int32Value();
+
+ if (this->EnsureEncoder() != OPUS_OK) {
+ Napi::Error::New(env, "Could not create encoder. Check the encoder parameters").ThrowAsJavaScriptException();
+ }
+
+ if (opus_encoder_ctl(this->encoder, OPUS_SET_BITRATE(bitrate)) != OPUS_OK) {
+ Napi::TypeError::New(env, "Invalid bitrate").ThrowAsJavaScriptException();
+ }
+}
+
+Napi::Value OpusEncoder::GetBitrate(const CallbackInfo& args) {
+ Napi::Env env = args.Env();
+
+ if (this->EnsureEncoder() != OPUS_OK) {
+ Napi::Error::New(env, "Could not create encoder. Check the encoder parameters").ThrowAsJavaScriptException();
+ }
+
+ opus_int32 bitrate;
+ opus_encoder_ctl(this->encoder, OPUS_GET_BITRATE(&bitrate));
+
+ return Napi::Number::New(env, bitrate);
+}
+
+Object Init(Napi::Env env, Object exports) {
+ return OpusEncoder::Init(env, exports);
+}
+
+NODE_API_MODULE(opus, Init)