node-datachannel
Version:
WebRTC For Node.js and Electron. libdatachannel node bindings.
461 lines (371 loc) • 13.9 kB
Plain Text
#include "media-audio-wrapper.h"
#include "media-direction.h"
Napi::FunctionReference AudioWrapper::constructor = Napi::FunctionReference();
std::unordered_set<AudioWrapper *> AudioWrapper::instances;
Napi::Object AudioWrapper::Init(Napi::Env env, Napi::Object exports)
{
Napi::HandleScope scope(env);
Napi::Function func = DefineClass(
env,
"Audio",
{
InstanceValue("media-type-audio", Napi::Boolean::New(env, true)),
InstanceMethod("addAudioCodec", &AudioWrapper::addAudioCodec),
InstanceMethod("addOpusCodec", &AudioWrapper::addOpusCodec),
InstanceMethod("direction", &AudioWrapper::direction),
InstanceMethod("generateSdp", &AudioWrapper::generateSdp),
InstanceMethod("mid", &AudioWrapper::mid),
InstanceMethod("setDirection", &AudioWrapper::setDirection),
InstanceMethod("description", &AudioWrapper::description),
InstanceMethod("removeFormat", &AudioWrapper::removeFormat),
InstanceMethod("addSSRC", &AudioWrapper::addSSRC),
InstanceMethod("removeSSRC", &AudioWrapper::removeSSRC),
InstanceMethod("replaceSSRC", &AudioWrapper::replaceSSRC),
InstanceMethod("hasSSRC", &AudioWrapper::hasSSRC),
InstanceMethod("getSSRCs", &AudioWrapper::getSSRCs),
InstanceMethod("getCNameForSsrc", &AudioWrapper::getCNameForSsrc),
InstanceMethod("setBitrate", &AudioWrapper::setBitrate),
InstanceMethod("getBitrate", &AudioWrapper::getBitrate),
InstanceMethod("hasPayloadType", &AudioWrapper::hasPayloadType),
InstanceMethod("addRTXCodec", &AudioWrapper::addRTXCodec),
InstanceMethod("addRTPMap", &AudioWrapper::addRTPMap),
InstanceMethod("parseSdpLine", &AudioWrapper::parseSdpLine),
});
// If this is not the first call, we don't want to reassign the constructor (hot-reload problem)
if(constructor.IsEmpty())
{
constructor = Napi::Persistent(func);
constructor.SuppressDestruct();
}
exports.Set("Audio", func);
return exports;
}
AudioWrapper::AudioWrapper(const Napi::CallbackInfo &info) : Napi::ObjectWrap<AudioWrapper>(info)
{
Napi::Env env = info.Env();
int length = info.Length();
std::string mid = "audio";
rtc::Description::Direction dir = rtc::Description::Direction::SendOnly;
// optional
if (length > 0)
{
if (!info[0].IsString())
{
Napi::TypeError::New(env, "mid (String) expected").ThrowAsJavaScriptException();
return;
}
mid = info[0].As<Napi::String>().ToString();
}
// ootional
if (length > 1)
{
if (!info[1].IsString())
{
Napi::TypeError::New(env, "direction (String) expected").ThrowAsJavaScriptException();
return;
}
std::string dirAsStr = info[1].As<Napi::String>().ToString();
dir = strToDirection(dirAsStr);
}
mAudioPtr = std::make_unique<rtc::Description::Audio>(mid, dir);
instances.insert(this);
}
AudioWrapper::~AudioWrapper()
{
mAudioPtr.reset();
instances.erase(this);
}
rtc::Description::Audio AudioWrapper::getAudioInstance()
{
return *(mAudioPtr.get());
}
void AudioWrapper::addAudioCodec(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 2 || !info[0].IsNumber() || !info[1].IsString())
{
Napi::TypeError::New(env, "We expect (Number, String, String[optional]) as param").ThrowAsJavaScriptException();
return;
}
int payloadType = info[0].As<Napi::Number>().ToNumber();
std::string codec = info[1].As<Napi::String>().ToString();
std::optional<std::string> profile = std::nullopt;
if (length > 2)
{
if (!info[2].IsString())
{
Napi::TypeError::New(env, "profile (String) expected").ThrowAsJavaScriptException();
return;
}
profile = info[2].As<Napi::String>().ToString();
}
mAudioPtr->addAudioCodec(payloadType, codec, profile);
}
void AudioWrapper::addOpusCodec(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 1 || !info[0].IsNumber())
{
Napi::TypeError::New(env, "We expect (Number) as param").ThrowAsJavaScriptException();
return;
}
int payloadType = info[0].As<Napi::Number>().ToNumber();
std::optional<std::string> profile = rtc::DEFAULT_OPUS_AUDIO_PROFILE;
if (length > 1)
{
if (!info[1].IsString())
{
Napi::TypeError::New(env, "profile (String) expected").ThrowAsJavaScriptException();
return;
}
profile = info[1].As<Napi::String>().ToString();
}
mAudioPtr->addOpusCodec(payloadType, profile);
}
Napi::Value AudioWrapper::direction(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
return Napi::String::New(env, directionToStr(mAudioPtr->direction()));
}
Napi::Value AudioWrapper::generateSdp(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 3 || !info[0].IsString() || !info[1].IsString() || !info[2].IsNumber())
{
Napi::TypeError::New(env, "We expect (String, String, Number) as param").ThrowAsJavaScriptException();
return Napi::String::New(env, "");
}
std::string eol = info[0].As<Napi::String>().ToString();
std::string addr = info[1].As<Napi::String>().ToString();
uint16_t port = info[2].As<Napi::Number>().Uint32Value();
return Napi::String::New(env, mAudioPtr->generateSdp(eol, addr, port));
}
Napi::Value AudioWrapper::mid(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
return Napi::String::New(env, mAudioPtr->mid());
}
void AudioWrapper::setDirection(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 1 || !info[0].IsString())
{
Napi::TypeError::New(env, "We expect (String) as param").ThrowAsJavaScriptException();
return;
}
std::string dirAsStr = info[0].As<Napi::String>().ToString();
rtc::Description::Direction dir = strToDirection(dirAsStr);
mAudioPtr->setDirection(dir);
}
Napi::Value AudioWrapper::description(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
return Napi::String::New(env, mAudioPtr->description());
}
void AudioWrapper::removeFormat(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 1 || !info[0].IsString())
{
Napi::TypeError::New(env, "We expect (String) as param").ThrowAsJavaScriptException();
return;
}
std::string fmt = info[0].As<Napi::String>().ToString();
mAudioPtr->removeFormat(fmt);
}
void AudioWrapper::addSSRC(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 1 || !info[0].IsNumber())
{
Napi::TypeError::New(env, "We expect (Number, String[optional], String[optional], String[optional]) as param").ThrowAsJavaScriptException();
return;
}
uint32_t ssrc = static_cast<uint32_t>(info[0].As<Napi::Number>().ToNumber());
std::optional<std::string> name;
std::optional<std::string> msid = std::nullopt;
std::optional<std::string> trackID = std::nullopt;
if (length > 1)
{
if (!info[1].IsString())
{
Napi::TypeError::New(env, "name as String expected").ThrowAsJavaScriptException();
return;
}
name = info[1].As<Napi::String>().ToString();
}
if (length > 2)
{
if (!info[2].IsString())
{
Napi::TypeError::New(env, "msid as String expected").ThrowAsJavaScriptException();
return;
}
msid = info[2].As<Napi::String>().ToString();
}
if (length > 3)
{
if (!info[3].IsString())
{
Napi::TypeError::New(env, "trackID as String expected").ThrowAsJavaScriptException();
return;
}
trackID = info[3].As<Napi::String>().ToString();
}
mAudioPtr->addSSRC(ssrc, name, msid, trackID);
}
void AudioWrapper::removeSSRC(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 1 || !info[0].IsNumber())
{
Napi::TypeError::New(env, "We expect (Number) as param").ThrowAsJavaScriptException();
return;
}
uint32_t ssrc = static_cast<uint32_t>(info[0].As<Napi::Number>().ToNumber());
mAudioPtr->removeSSRC(ssrc);
}
void AudioWrapper::replaceSSRC(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 2 || !info[0].IsNumber() || !info[1].IsNumber())
{
Napi::TypeError::New(env, "We expect (Number, Number, String[optional], String[optional], String[optional]) as param").ThrowAsJavaScriptException();
return;
}
uint32_t ssrc = static_cast<uint32_t>(info[0].As<Napi::Number>().ToNumber());
uint32_t oldSsrc = static_cast<uint32_t>(info[1].As<Napi::Number>().ToNumber());
std::optional<std::string> name;
std::optional<std::string> msid = std::nullopt;
std::optional<std::string> trackID = std::nullopt;
if (length > 2)
{
if (!info[2].IsString())
{
Napi::TypeError::New(env, "name as String expected").ThrowAsJavaScriptException();
return;
}
name = info[2].As<Napi::String>().ToString();
}
if (length > 3)
{
if (!info[3].IsString())
{
Napi::TypeError::New(env, "msid as String expected").ThrowAsJavaScriptException();
return;
}
msid = info[3].As<Napi::String>().ToString();
}
if (length > 4)
{
if (!info[4].IsString())
{
Napi::TypeError::New(env, "trackID as String expected").ThrowAsJavaScriptException();
return;
}
trackID = info[4].As<Napi::String>().ToString();
}
mAudioPtr->replaceSSRC(oldSsrc, ssrc, name, msid, trackID);
}
Napi::Value AudioWrapper::hasSSRC(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 1 || !info[0].IsNumber())
{
Napi::TypeError::New(env, "We expect (Number) as param").ThrowAsJavaScriptException();
return env.Null();
}
uint32_t ssrc = static_cast<uint32_t>(info[0].As<Napi::Number>().ToNumber());
return Napi::Boolean::New(env, mAudioPtr->hasSSRC(ssrc));
}
Napi::Value AudioWrapper::getSSRCs(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
auto list = mAudioPtr->getSSRCs();
Napi::Uint32Array napiArr = Napi::Uint32Array::New(env, list.size());
for (size_t i = 0; i < list.size(); i++)
napiArr[i] = list[i];
return napiArr;
}
Napi::Value AudioWrapper::getCNameForSsrc(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 1 || !info[0].IsNumber())
{
Napi::TypeError::New(env, "We expect (Number) as param").ThrowAsJavaScriptException();
return env.Null();
}
uint32_t ssrc = static_cast<uint32_t>(info[0].As<Napi::Number>().ToNumber());
std::optional<std::string> name = mAudioPtr->getCNameForSsrc(ssrc);
if (!name.has_value())
return env.Null();
return Napi::String::New(env, name.value());
}
void AudioWrapper::setBitrate(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 1 || !info[0].IsNumber())
{
Napi::TypeError::New(env, "We expect (Number) as param").ThrowAsJavaScriptException();
return;
}
unsigned int bitrate = static_cast<uint32_t>(info[0].As<Napi::Number>().ToNumber());
mAudioPtr->setBitrate(bitrate);
}
Napi::Value AudioWrapper::getBitrate(const Napi::CallbackInfo &info)
{
return Napi::Number::New(info.Env(), mAudioPtr->bitrate());
}
Napi::Value AudioWrapper::hasPayloadType(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 1 || !info[0].IsNumber())
{
Napi::TypeError::New(env, "We expect (Number) as param").ThrowAsJavaScriptException();
return env.Null();
}
int payloadType = static_cast<int>(info[0].As<Napi::Number>().ToNumber());
return Napi::Boolean::New(env, mAudioPtr->hasPayloadType(payloadType));
}
void AudioWrapper::addRTXCodec(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 3 || !info[0].IsNumber() || !info[1].IsNumber() || !info[2].IsNumber())
{
Napi::TypeError::New(env, "We expect (Number,Number,Number) as param").ThrowAsJavaScriptException();
return;
}
int payloadType = static_cast<int32_t>(info[0].As<Napi::Number>().ToNumber());
int originalPayloadType = static_cast<int32_t>(info[1].As<Napi::Number>().ToNumber());
unsigned int clockRate = static_cast<uint32_t>(info[2].As<Napi::Number>().ToNumber());
mAudioPtr->addRtxCodec(payloadType, originalPayloadType, clockRate);
}
void AudioWrapper::addRTPMap(const Napi::CallbackInfo &info)
{
// mAudioPtr->addRTPMap()
}
void AudioWrapper::parseSdpLine(const Napi::CallbackInfo &info)
{
Napi::Env env = info.Env();
int length = info.Length();
if (length < 1 || !info[0].IsString())
{
Napi::TypeError::New(env, "We expect (String) as param").ThrowAsJavaScriptException();
return;
}
std::string line = info[0].As<Napi::String>().ToString();
mAudioPtr->parseSdpLine(line);
}