- fixes from pvqa_pcap

This commit is contained in:
Dmytro Bogovych 2024-12-23 17:39:45 +03:00
parent bf2d513080
commit 4ba1ea7fa2
7 changed files with 313 additions and 186 deletions

View File

@ -46,13 +46,17 @@
#define MT_SAMPLERATE AUDIO_SAMPLERATE #define MT_SAMPLERATE AUDIO_SAMPLERATE
#define MT_MAXAUDIOFRAME 1440 #define MT_MAXAUDIOFRAME 1440
#define MT_MAXRTPPACKET 1500 #define MT_MAXRTPPACKET 1500
#define MT_DTMF_END_PACKETS 3 #define MT_DTMF_END_PACKETS 3
#define RTP_BUFFER_HIGH 480 #define RTP_BUFFER_HIGH 0
#define RTP_BUFFER_LOW 10 #define RTP_BUFFER_LOW 0
#define RTP_BUFFER_PREBUFFER 320 #define RTP_BUFFER_PREBUFFER 0
// #define RTP_BUFFER_HIGH 160
// #define RTP_BUFFER_LOW 10
// #define RTP_BUFFER_PREBUFFER 160
#define RTP_DECODED_CAPACITY 2048 #define RTP_DECODED_CAPACITY 2048
#define DEFAULT_SUBSCRIPTION_TIME 1200 #define DEFAULT_SUBSCRIPTION_TIME 1200

View File

@ -543,6 +543,7 @@ PCodec AmrWbCodec::CodecFactory::create()
return PCodec(new AmrWbCodec(mConfig)); return PCodec(new AmrWbCodec(mConfig));
} }
AmrWbStatistics MT::GAmrWbStatistics;
AmrWbCodec::AmrWbCodec(const AmrCodecConfig& config) AmrWbCodec::AmrWbCodec(const AmrCodecConfig& config)
:mEncoderCtx(nullptr), mDecoderCtx(nullptr), mConfig(config), :mEncoderCtx(nullptr), mDecoderCtx(nullptr), mConfig(config),
@ -672,6 +673,7 @@ int AmrWbCodec::decode(const void* input, int inputBytes, void* output, int outp
} }
catch(...) catch(...)
{ {
GAmrWbStatistics.mNonParsed++;
ICELogDebug(<< "Failed to decode AMR payload"); ICELogDebug(<< "Failed to decode AMR payload");
return 0; return 0;
} }
@ -680,8 +682,10 @@ int AmrWbCodec::decode(const void* input, int inputBytes, void* output, int outp
// Check if packet is corrupted // Check if packet is corrupted
if (ap.mDiscardPacket) if (ap.mDiscardPacket)
{
GAmrWbStatistics.mDiscarded++;
return 0; return 0;
}
// Check for output buffer capacity // Check for output buffer capacity
if (outputCapacity < (int)ap.mFrames.size() * pcmLength()) if (outputCapacity < (int)ap.mFrames.size() * pcmLength())
return 0; return 0;

View File

@ -14,16 +14,16 @@
namespace MT namespace MT
{ {
struct AmrCodecConfig struct AmrCodecConfig
{ {
bool mIuUP; bool mIuUP;
bool mOctetAligned; bool mOctetAligned;
int mPayloadType; int mPayloadType;
}; };
class AmrNbCodec : public Codec class AmrNbCodec : public Codec
{ {
protected: protected:
void* mEncoderCtx; void* mEncoderCtx;
void* mDecoderCtx; void* mDecoderCtx;
AmrCodecConfig mConfig; AmrCodecConfig mConfig;
@ -31,25 +31,25 @@ namespace MT
int mSwitchCounter; int mSwitchCounter;
int mPreviousPacketLength; int mPreviousPacketLength;
public: public:
class CodecFactory: public Factory class CodecFactory: public Factory
{ {
public: public:
CodecFactory(const AmrCodecConfig& config); CodecFactory(const AmrCodecConfig& config);
const char* name() override; const char* name() override;
int samplerate() override; int samplerate() override;
int payloadType() override; int payloadType() override;
#ifdef USE_RESIP_INTEGRATION #ifdef USE_RESIP_INTEGRATION
void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override;
int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override;
void create(CodecMap& codecs) override; void create(CodecMap& codecs) override;
#endif #endif
PCodec create() override; PCodec create() override;
protected: protected:
AmrCodecConfig mConfig; AmrCodecConfig mConfig;
}; };
AmrNbCodec(const AmrCodecConfig& config); AmrNbCodec(const AmrCodecConfig& config);
@ -64,11 +64,18 @@ namespace MT
int decode(const void* input, int inputBytes, void* output, int outputCapacity) override; int decode(const void* input, int inputBytes, void* output, int outputCapacity) override;
int plc(int lostFrames, void* output, int outputCapacity) override; int plc(int lostFrames, void* output, int outputCapacity) override;
int getSwitchCounter() const; int getSwitchCounter() const;
}; };
class AmrWbCodec : public Codec struct AmrWbStatistics
{ {
protected: int mDiscarded = 0;
int mNonParsed = 0;
};
extern AmrWbStatistics GAmrWbStatistics;
class AmrWbCodec : public Codec
{
protected:
void* mEncoderCtx; void* mEncoderCtx;
void* mDecoderCtx; void* mDecoderCtx;
AmrCodecConfig mConfig; AmrCodecConfig mConfig;
@ -76,25 +83,25 @@ namespace MT
int mSwitchCounter; int mSwitchCounter;
int mPreviousPacketLength; int mPreviousPacketLength;
public: public:
class CodecFactory: public Factory class CodecFactory: public Factory
{ {
public: public:
CodecFactory(const AmrCodecConfig& config); CodecFactory(const AmrCodecConfig& config);
const char* name() override; const char* name() override;
int samplerate() override; int samplerate() override;
int payloadType() override; int payloadType() override;
#ifdef USE_RESIP_INTEGRATION #ifdef USE_RESIP_INTEGRATION
void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override;
int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override;
void create(CodecMap& codecs) override; void create(CodecMap& codecs) override;
#endif #endif
PCodec create() override; PCodec create() override;
protected: protected:
AmrCodecConfig mConfig; AmrCodecConfig mConfig;
}; };
AmrWbCodec(const AmrCodecConfig& config); AmrWbCodec(const AmrCodecConfig& config);
@ -109,35 +116,35 @@ namespace MT
int decode(const void* input, int inputBytes, void* output, int outputCapacity) override; int decode(const void* input, int inputBytes, void* output, int outputCapacity) override;
int plc(int lostFrames, void* output, int outputCapacity) override; int plc(int lostFrames, void* output, int outputCapacity) override;
int getSwitchCounter() const; int getSwitchCounter() const;
}; };
class GsmEfrCodec : public Codec class GsmEfrCodec : public Codec
{ {
protected: protected:
void* mEncoderCtx; void* mEncoderCtx;
void* mDecoderCtx; void* mDecoderCtx;
bool mIuUP; bool mIuUP;
public: public:
class GsmEfrFactory: public Factory class GsmEfrFactory: public Factory
{ {
public: public:
GsmEfrFactory(bool iuup, int ptype); GsmEfrFactory(bool iuup, int ptype);
const char* name() override; const char* name() override;
int samplerate() override; int samplerate() override;
int payloadType() override; int payloadType() override;
#ifdef USE_RESIP_INTEGRATION #ifdef USE_RESIP_INTEGRATION
void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; void updateSdp(resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override;
int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override; int processSdp(const resip::SdpContents::Session::Medium::CodecContainer& codecs, SdpDirection direction) override;
void create(CodecMap& codecs) override; void create(CodecMap& codecs) override;
#endif #endif
PCodec create() override; PCodec create() override;
protected: protected:
bool mIuUP; bool mIuUP;
int mPayloadType; int mPayloadType;
}; };
GsmEfrCodec(bool iuup = false); GsmEfrCodec(bool iuup = false);
@ -151,7 +158,7 @@ namespace MT
int encode(const void* input, int inputBytes, void* output, int outputCapacity) override; int encode(const void* input, int inputBytes, void* output, int outputCapacity) override;
int decode(const void* input, int inputBytes, void* output, int outputCapacity) override; int decode(const void* input, int inputBytes, void* output, int outputCapacity) override;
int plc(int lostFrames, void* output, int outputCapacity) override; int plc(int lostFrames, void* output, int outputCapacity) override;
}; };
} // End of MT namespace } // End of MT namespace

View File

@ -197,7 +197,7 @@ RtpBuffer::FetchResult RtpBuffer::fetch(ResultList& rl)
// See if there is enough information in buffer // See if there is enough information in buffer
int total = findTimelength(); int total = findTimelength();
while (total > mHigh && mPacketList.size()) while (total > mHigh && mPacketList.size() && 0 != mHigh)
{ {
ICELogMedia( << "Dropping RTP packets from jitter buffer"); ICELogMedia( << "Dropping RTP packets from jitter buffer");
total -= mPacketList.front()->timelength(); total -= mPacketList.front()->timelength();
@ -356,11 +356,17 @@ void AudioReceiver::setCodecSettings(const CodecList::Settings& codecSettings)
return; return;
mCodecSettings = codecSettings; mCodecSettings = codecSettings;
mCodecMap.clear(); mCodecList.setSettings(mCodecSettings); // This builds factory list with proper payload types according to payload types in settings
mCodecList.setSettings(mCodecSettings);
// Rebuild codec map from factory list
mCodecList.fillCodecMap(mCodecMap); mCodecList.fillCodecMap(mCodecMap);
} }
CodecList::Settings& AudioReceiver::getCodecSettings()
{
return mCodecSettings;
}
size_t decode_packet(Codec& codec, RTPPacket& p, void* output_buffer, size_t output_capacity) size_t decode_packet(Codec& codec, RTPPacket& p, void* output_buffer, size_t output_capacity)
{ {
// How much data was produced // How much data was produced
@ -399,12 +405,15 @@ size_t decode_packet(Codec& codec, RTPPacket& p, void* output_buffer, size_t out
bool AudioReceiver::add(const std::shared_ptr<jrtplib::RTPPacket>& p, Codec** codec) bool AudioReceiver::add(const std::shared_ptr<jrtplib::RTPPacket>& p, Codec** codec)
{ {
// Estimate time length
int time_length = 0, payloadLength = p->GetPayloadLength(), ptype = p->GetPayloadType();
// ICELogInfo(<< "Adding packet No " << p->GetSequenceNumber()); // ICELogInfo(<< "Adding packet No " << p->GetSequenceNumber());
// Increase codec counter // Increase codec counter
mStat.mCodecCount[p->GetPayloadType()]++; mStat.mCodecCount[ptype]++;
// Check if codec can be handled // Check if codec can be handled
CodecMap::iterator codecIter = mCodecMap.find(p->GetPayloadType()); CodecMap::iterator codecIter = mCodecMap.find(ptype);
if (codecIter == mCodecMap.end()) if (codecIter == mCodecMap.end())
{ {
ICELogMedia(<< "Cannot find codec in available codecs"); ICELogMedia(<< "Cannot find codec in available codecs");
@ -427,8 +436,6 @@ bool AudioReceiver::add(const std::shared_ptr<jrtplib::RTPPacket>& p, Codec** co
if (mStat.mCodecName.empty()) if (mStat.mCodecName.empty())
mStat.mCodecName = codecIter->second->name(); mStat.mCodecName = codecIter->second->name();
// Estimate time length
int time_length = 0, payloadLength = p->GetPayloadLength(), ptype = p->GetPayloadType();
if (!codecIter->second->rtpLength()) if (!codecIter->second->rtpLength())
time_length = codecIter->second->frameTime(); time_length = codecIter->second->frameTime();
@ -462,8 +469,11 @@ bool AudioReceiver::add(const std::shared_ptr<jrtplib::RTPPacket>& p, Codec** co
{ {
// Move data to packet buffer // Move data to packet buffer
size_t available = decode_packet(**codec, *p, mDecodedFrame, sizeof mDecodedFrame); size_t available = decode_packet(**codec, *p, mDecodedFrame, sizeof mDecodedFrame);
packet->pcm().resize(available / 2); if (available > 0)
memcpy(packet->pcm().data(), mDecodedFrame, available / 2); {
packet->pcm().resize(available / 2);
memcpy(packet->pcm().data(), mDecodedFrame, available / 2);
}
} }
return true; return true;
} }

View File

@ -124,7 +124,7 @@ namespace MT
// Update codec settings // Update codec settings
void setCodecSettings(const CodecList::Settings& codecSettings); void setCodecSettings(const CodecList::Settings& codecSettings);
CodecList::Settings& getCodecSettings();
// Returns false when packet is rejected as illegal. codec parameter will show codec which will be used for decoding. // Returns false when packet is rejected as illegal. codec parameter will show codec which will be used for decoding.
// Lifetime of pointer to codec is limited by lifetime of AudioReceiver (it is container). // Lifetime of pointer to codec is limited by lifetime of AudioReceiver (it is container).
bool add(const std::shared_ptr<jrtplib::RTPPacket>& p, Codec** codec = nullptr); bool add(const std::shared_ptr<jrtplib::RTPPacket>& p, Codec** codec = nullptr);

View File

@ -25,33 +25,95 @@ using namespace MT;
using strx = strx; using strx = strx;
// ---------------- EvsSpec ---------------
bool CodecList::Settings::contains(int ptype) const
{
if (ptype >= 0 && ptype < 96)
return true;
if (mAmrNbOctetPayloadType.contains(ptype))
return true;
if (mAmrNbPayloadType.contains(ptype))
return true;
if (mAmrWbOctetPayloadType.contains(ptype))
return true;
if (mAmrWbPayloadType.contains(ptype))
return true;
for (const auto& s: mOpusSpec)
if (s.mPayloadType == ptype)
return true;
for (const auto& s: mEvsSpec)
if (s.mPayloadType == ptype)
return true;
if (mIsac16KPayloadType == ptype || mIsac32KPayloadType == ptype)
return true;
if (mIlbc20PayloadType == ptype || mIlbc30PayloadType == ptype)
return true;
if (mGsmEfrPayloadType == ptype || mGsmFrPayloadType == ptype || mGsmHrPayloadType == ptype)
return true;
return false;
}
std::string CodecList::Settings::toString() const std::string CodecList::Settings::toString() const
{ {
std::ostringstream oss; std::ostringstream oss;
oss << "wrap IuUP: " << mWrapIuUP << std::endl // oss << "wrap IuUP: " << mWrapIuUP << std::endl
<< "skip decode: " << mSkipDecode << std::endl; // << "skip decode: " << mSkipDecode << std::endl;
for (int ptype: mAmrWbPayloadType)
oss << "AMR WB ptype: " << ptype << std::endl;
for (int ptype: mAmrWbOctetPayloadType)
oss << "AMR WB octet-aligned ptype: " << ptype << std::endl;
for (int ptype: mAmrNbPayloadType)
oss << "AMR NB ptype: " << ptype << std::endl;
for (int ptype: mAmrNbOctetPayloadType)
oss << "AMR NB octet-aligned ptype:" << ptype << std::endl;
oss << "ISAC 16Khz ptype: " << mIsac16KPayloadType << std::endl if (!mAmrWbPayloadType.empty())
<< "ISAC 32Khz ptype: " << mIsac32KPayloadType << std::endl {
<< "iLBC 20ms ptype: " << mIlbc20PayloadType << std::endl oss << "AMR WB ptype: ";
<< "iLBC 30ms ptype: " << mIlbc30PayloadType << std::endl for (int ptype: mAmrWbPayloadType)
<< "GSM FR ptype: " << mGsmFrPayloadType << ", GSM FR plength: " << mGsmFrPayloadLength << std::endl oss << ptype << " ";
<< "GSM HR ptype: " << mGsmHrPayloadType << std::endl }
<< "GSM EFR ptype: " << mGsmEfrPayloadType << std::endl; if (!mAmrWbOctetPayloadType.empty())
{
oss << "AMR WB octet ptype: ";
for (int ptype: mAmrWbOctetPayloadType)
oss << ptype << " ";
}
if (!mAmrNbPayloadType.empty())
{
oss << "AMR ptype: ";
for (int ptype: mAmrNbPayloadType)
oss << ptype << " ";
}
if (!mAmrNbOctetPayloadType.empty())
{
oss << "AMR octet ptype: ";
for (int ptype: mAmrNbOctetPayloadType)
oss << ptype << " ";
}
if (mIsac16KPayloadType != -1)
oss << "ISAC 16Khz ptype: " << mIsac16KPayloadType << " ";
if (mIsac32KPayloadType != -1)
oss << "ISAC 32Khz ptype: " << mIsac32KPayloadType << " ";
if (mIlbc20PayloadType != -1)
oss << "iLBC 20ms ptype: " << mIlbc20PayloadType << " ";
if (mIlbc30PayloadType != -1)
oss << "iLBC 30ms ptype: " << mIlbc30PayloadType << " ";
if (mGsmFrPayloadType != -1)
oss << "GSM FR ptype: " << mGsmFrPayloadType << ", GSM FR plength: " << mGsmFrPayloadLength << " ";
if (mGsmHrPayloadType != -1)
oss << "GSM HR ptype: " << mGsmHrPayloadType << " ";
if (mGsmEfrPayloadType != -1)
oss << "GSM EFR ptype: " << mGsmEfrPayloadType << " ";
for (auto& spec: mEvsSpec) for (auto& spec: mEvsSpec)
{ {
oss << "EVS ptype: " << spec.mPayloadType << ", bw: " << spec.mBandwidth << ", enc: " << (spec.mEncodingType == EvsSpec::Encoding_MIME ? "mime" : "g192") << std::endl; oss << "EVS ptype: " << spec.mPayloadType << ", bw: " << spec.mBandwidth << ", enc: " << (spec.mEncodingType == EvsSpec::Encoding_MIME ? "mime" : "g192") << " ";
} }
for (auto& spec: mOpusSpec) for (auto& spec: mOpusSpec)
@ -100,24 +162,24 @@ CodecList::Settings::EvsSpec CodecList::Settings::EvsSpec::parse(const std::stri
if (encoding_type == "mime") if (encoding_type == "mime")
result.mEncodingType = Encoding_MIME; result.mEncodingType = Encoding_MIME;
else else
if (encoding_type == "g192") if (encoding_type == "g192")
result.mEncodingType = Encoding_G192; result.mEncodingType = Encoding_G192;
else else
throw std::logic_error("Bad EVS codec encoding type"); throw std::logic_error("Bad EVS codec encoding type");
// Bandwidth // Bandwidth
std::string& bandwidth = parts.back(); std::string& bandwidth = parts.back();
if (bandwidth == "nb" || bandwidth == "NB") if (bandwidth == "nb" || bandwidth == "NB")
result.mBandwidth = Bandwidth_NB; result.mBandwidth = Bandwidth_NB;
else else
if (bandwidth == "wb" || bandwidth == "WB") if (bandwidth == "wb" || bandwidth == "WB")
result.mBandwidth = Bandwidth_WB; result.mBandwidth = Bandwidth_WB;
else else
if (bandwidth == "swb" || bandwidth == "SWB") if (bandwidth == "swb" || bandwidth == "SWB")
result.mBandwidth = Bandwidth_SWB; result.mBandwidth = Bandwidth_SWB;
else else
if (bandwidth == "fb" || bandwidth == "FB") if (bandwidth == "fb" || bandwidth == "FB")
result.mBandwidth = Bandwidth_FB; result.mBandwidth = Bandwidth_FB;
} }
return result; return result;
@ -145,6 +207,21 @@ CodecList::Settings::OpusSpec CodecList::Settings::OpusSpec::parse(const std::st
} }
#if defined(USE_RESIP_INTEGRATION) #if defined(USE_RESIP_INTEGRATION)
static int findOctetMode(const char* line)
{
const char* param_name = "octet-align=";
auto p = strstr(line, param_name);
if (!p)
return 0;
p += strlen(param_name);
char int_buf[8] = {0};
int int_buf_offset = 0;
while (*p && isdigit(*p) && int_buf_offset < sizeof(int_buf))
int_buf[int_buf_offset++] = *p++;
return atoi(int_buf);
}
CodecList::Settings CodecList::Settings::parseSdp(const std::list<resip::Codec>& codeclist) CodecList::Settings CodecList::Settings::parseSdp(const std::list<resip::Codec>& codeclist)
{ {
CodecList::Settings r{DefaultSettings}; CodecList::Settings r{DefaultSettings};
@ -155,15 +232,44 @@ CodecList::Settings CodecList::Settings::parseSdp(const std::list<resip::Codec>&
int samplerate = c.getRate(); int samplerate = c.getRate();
int ptype = c.payloadType(); int ptype = c.payloadType();
auto enc_params = c.encodingParameters(); // This must channels number for Opus codec
auto params = c.parameters();
// Dynamic payload type codecs only - ISAC / iLBC / Speex / etc. // Dynamic payload type codecs only - ISAC / iLBC / Speex / etc.
if (codec_name == "OPUS") if (codec_name == "OPUS")
{ {
// Check the parameters // Check the parameters
auto enc_params = c.encodingParameters(); // This must channels number for Opus codec
auto params = c.parameters();
int channels = strx::toInt(enc_params.c_str(), 1); int channels = strx::toInt(enc_params.c_str(), 1);
r.mOpusSpec.push_back({ptype, samplerate, channels}); r.mOpusSpec.push_back({ptype, samplerate, channels});
} }
else
if (codec_name == "AMR-WB")
{
int octet_mode = findOctetMode(params.c_str());
if (octet_mode != -1)
{
if (octet_mode == 0)
r.mAmrWbPayloadType.insert(ptype);
else
if (octet_mode == 1)
r.mAmrWbOctetPayloadType.insert(ptype);
}
// std::cout << "AMR-WB parameters: " << params.c_str() << ", found octet-mode: " << octet_mode << std::endl;
}
else
if (codec_name == "AMR")
{
int octet_mode = findOctetMode(params.c_str());
if (octet_mode != -1)
{
if (octet_mode == 0)
r.mAmrWbPayloadType.insert(ptype);
else
if (octet_mode == 1)
r.mAmrWbOctetPayloadType.insert(ptype);
}
// std::cout << "AMR parameters: " << params.c_str() << ", found octet-mode: " << octet_mode << std::endl;
}
} }
return r; return r;
} }
@ -173,7 +279,7 @@ CodecList::Settings CodecList::Settings::parseSdp(const std::list<resip::Codec>&
bool CodecList::Settings::operator == (const Settings& rhs) const bool CodecList::Settings::operator == (const Settings& rhs) const
{ {
if (std::tie(mWrapIuUP, mSkipDecode, mIsac16KPayloadType, mIsac32KPayloadType, mIlbc20PayloadType, mIlbc30PayloadType, mGsmFrPayloadType, mGsmFrPayloadLength, mGsmEfrPayloadType, mGsmHrPayloadType) != if (std::tie(mWrapIuUP, mSkipDecode, mIsac16KPayloadType, mIsac32KPayloadType, mIlbc20PayloadType, mIlbc30PayloadType, mGsmFrPayloadType, mGsmFrPayloadLength, mGsmEfrPayloadType, mGsmHrPayloadType) !=
std::tie(rhs.mWrapIuUP, rhs.mSkipDecode, rhs.mIsac16KPayloadType, rhs.mIsac32KPayloadType, rhs.mIlbc20PayloadType, rhs.mIlbc30PayloadType, rhs.mGsmFrPayloadType, rhs.mGsmFrPayloadLength, rhs.mGsmEfrPayloadType, rhs.mGsmHrPayloadType)) std::tie(rhs.mWrapIuUP, rhs.mSkipDecode, rhs.mIsac16KPayloadType, rhs.mIsac32KPayloadType, rhs.mIlbc20PayloadType, rhs.mIlbc30PayloadType, rhs.mGsmFrPayloadType, rhs.mGsmFrPayloadLength, rhs.mGsmEfrPayloadType, rhs.mGsmHrPayloadType))
return false; return false;
if (mAmrNbOctetPayloadType != rhs.mAmrNbOctetPayloadType) if (mAmrNbOctetPayloadType != rhs.mAmrNbOctetPayloadType)
@ -211,108 +317,99 @@ bool CodecList::Settings::operator == (const Settings& rhs) const
CodecList::Settings CodecList::Settings::DefaultSettings; CodecList::Settings CodecList::Settings::DefaultSettings;
CodecList::CodecList(const Settings& settings) CodecList::CodecList(const Settings& settings)
:mSettings(settings) :mSettings(settings)
{ {
init(mSettings); init(mSettings);
} }
void CodecList::init(const Settings& settings) void CodecList::init(const Settings& settings)
{ {
for (auto f: mFactoryList) mFactoryList.clear();
delete f; mSettings = settings;
mFactoryList.clear();
#if defined(USE_OPUS_CODEC) #if defined(USE_OPUS_CODEC)
if (settings.mOpusSpec.empty())
{
mFactoryList.push_back(new OpusCodec::OpusFactory(48000, 2, MT_OPUS_CODEC_PT));
}
else
{
for (auto spec: settings.mOpusSpec) for (auto spec: settings.mOpusSpec)
{ {
mFactoryList.push_back(new OpusCodec::OpusFactory(spec.mRate, spec.mChannels, spec.mPayloadType)); mFactoryList.push_back(std::make_shared<OpusCodec::OpusFactory>(spec.mRate, spec.mChannels, spec.mPayloadType));
} }
}
#endif #endif
#if !defined(TARGET_ANDROID) && !defined(TARGET_OPENWRT) && !defined(TARGET_RPI) #if !defined(TARGET_ANDROID) && !defined(TARGET_OPENWRT) && !defined(TARGET_RPI)
#if defined(USE_AMR_CODEC) #if defined(USE_AMR_CODEC)
for (int pt: mSettings.mAmrWbPayloadType) for (int pt: mSettings.mAmrWbPayloadType)
mFactoryList.push_back(new AmrWbCodec::CodecFactory({mSettings.mWrapIuUP, false, pt})); mFactoryList.push_back(std::make_shared<AmrWbCodec::CodecFactory>(AmrCodecConfig{mSettings.mWrapIuUP, false, pt}));
for (int pt: mSettings.mAmrWbOctetPayloadType) for (int pt: mSettings.mAmrWbOctetPayloadType)
mFactoryList.push_back(new AmrWbCodec::CodecFactory({mSettings.mWrapIuUP, true, pt})); mFactoryList.push_back(std::make_shared<AmrWbCodec::CodecFactory>(AmrCodecConfig{mSettings.mWrapIuUP, true, pt}));
for (int pt: mSettings.mAmrNbPayloadType) for (int pt: mSettings.mAmrNbPayloadType)
mFactoryList.push_back(new AmrNbCodec::CodecFactory({mSettings.mWrapIuUP, false, pt})); mFactoryList.push_back(std::make_shared<AmrNbCodec::CodecFactory>(AmrCodecConfig{mSettings.mWrapIuUP, false, pt}));
for (int pt: mSettings.mAmrNbOctetPayloadType) for (int pt: mSettings.mAmrNbOctetPayloadType)
mFactoryList.push_back(new AmrNbCodec::CodecFactory({mSettings.mWrapIuUP, true, pt})); mFactoryList.push_back(std::make_shared<AmrNbCodec::CodecFactory>(AmrCodecConfig{mSettings.mWrapIuUP, true, pt}));
mFactoryList.push_back(new GsmEfrCodec::GsmEfrFactory(mSettings.mWrapIuUP, mSettings.mGsmEfrPayloadType)); if (mSettings.mGsmEfrPayloadType != -1)
mFactoryList.push_back(std::make_shared<GsmEfrCodec::GsmEfrFactory>(mSettings.mWrapIuUP, mSettings.mGsmEfrPayloadType));
#endif #endif
#endif #endif
// mFactoryList.push_back(new IsacCodec::IsacFactory16K(mSettings.mIsac16KPayloadType)); mFactoryList.push_back(std::make_shared<G711Codec::AlawFactory>());
// mFactoryList.push_back(new IlbcCodec::IlbcFactory(mSettings.mIlbc20PayloadType, mSettings.mIlbc30PayloadType)); mFactoryList.push_back(std::make_shared<G711Codec::UlawFactory>());
mFactoryList.push_back(new G711Codec::AlawFactory());
mFactoryList.push_back(new G711Codec::UlawFactory());
mFactoryList.push_back(new GsmCodec::GsmFactory(mSettings.mGsmFrPayloadLength == 32 ? GsmCodec::Type::Bytes_32 : GsmCodec::Type::Bytes_33, mSettings.mGsmFrPayloadType)); if (mSettings.mGsmFrPayloadType != -1)
mFactoryList.push_back(new G722Codec::G722Factory()); mFactoryList.push_back(std::make_shared<GsmCodec::GsmFactory>(mSettings.mGsmFrPayloadLength == 32 ? GsmCodec::Type::Bytes_32 : GsmCodec::Type::Bytes_33, mSettings.mGsmFrPayloadType));
mFactoryList.push_back(new G729Codec::G729Factory()); mFactoryList.push_back(std::make_shared<G722Codec::G722Factory>());
mFactoryList.push_back(std::make_shared<G729Codec::G729Factory>());
#ifndef TARGET_ANDROID #ifndef TARGET_ANDROID
mFactoryList.push_back(new GsmHrCodec::GsmHrFactory(mSettings.mGsmHrPayloadType)); if (mSettings.mGsmHrPayloadType != -1)
mFactoryList.push_back(std::make_shared<GsmHrCodec::GsmHrFactory>(mSettings.mGsmHrPayloadType));
#endif #endif
#if !defined(TARGET_ANDROID) && defined(USE_EVS_CODEC) #if !defined(TARGET_ANDROID) && defined(USE_EVS_CODEC)
for (auto& spec: settings.mEvsSpec) for (auto& spec: settings.mEvsSpec)
{ {
EVSCodec::StreamParameters evs_params; EVSCodec::StreamParameters evs_params;
evs_params.mime = spec.mEncodingType == Settings::EvsSpec::Encoding_MIME; evs_params.mime = spec.mEncodingType == Settings::EvsSpec::Encoding_MIME;
evs_params.bw = (int)spec.mBandwidth; evs_params.bw = (int)spec.mBandwidth;
evs_params.ptime = 20; evs_params.ptime = 20;
evs_params.ptype = spec.mPayloadType; evs_params.ptype = spec.mPayloadType;
mFactoryList.push_back(new EVSCodec::EVSFactory(evs_params)); mFactoryList.push_back(std::make_shared<EVSCodec::EVSFactory>(evs_params));
} }
#endif #endif
} }
CodecList::~CodecList() CodecList::~CodecList()
{ {
for (auto f: mFactoryList) mFactoryList.clear();
delete f;
} }
int CodecList::count() const int CodecList::count() const
{ {
return static_cast<int>(mFactoryList.size()); return static_cast<int>(mFactoryList.size());
} }
Codec::Factory& CodecList::codecAt(int index) const Codec::Factory& CodecList::codecAt(int index) const
{ {
return *mFactoryList[static_cast<size_t>(index)]; return *mFactoryList[static_cast<size_t>(index)];
} }
int CodecList::findCodec(const std::string &name) const int CodecList::findCodec(const std::string &name) const
{ {
for (int i=0; i<count(); i++) for (int i=0; i<count(); i++)
{ {
if (codecAt(i).name() == name) if (codecAt(i).name() == name)
return i; return i;
} }
return -1; return -1;
} }
void CodecList::fillCodecMap(CodecMap& cm) void CodecList::fillCodecMap(CodecMap& cm)
{ {
cm.clear(); cm.clear();
for (auto& factory: mFactoryList) for (auto& factory: mFactoryList)
{ {
// Create codec here. Although they are not needed right now - they can be needed to find codec's info. // Create codec here. Although they are not needed right now - they can be needed to find codec's info.
PCodec c = factory->create(); PCodec c = factory->create();
cm.insert({factory->payloadType(), c}); cm.insert({factory->payloadType(), c});
} }
} }
CodecListPriority::CodecListPriority() CodecListPriority::CodecListPriority()
@ -327,55 +424,55 @@ CodecListPriority::~CodecListPriority()
bool CodecListPriority::isNegativePriority(const CodecListPriority::Item& item) bool CodecListPriority::isNegativePriority(const CodecListPriority::Item& item)
{ {
return item.mPriority < 0; return item.mPriority < 0;
} }
bool CodecListPriority::compare(const Item& item1, const Item& item2) bool CodecListPriority::compare(const Item& item1, const Item& item2)
{ {
return item1.mPriority < item2.mPriority; return item1.mPriority < item2.mPriority;
} }
void CodecListPriority::setupFrom(PVariantMap vmap) void CodecListPriority::setupFrom(PVariantMap vmap)
{ {
CodecList::Settings settings; CodecList::Settings settings;
CodecList cl(settings); CodecList cl(settings);
//mPriorityList.resize(cl.count()); //mPriorityList.resize(cl.count());
bool emptyVmap = vmap ? vmap->empty() : true; bool emptyVmap = vmap ? vmap->empty() : true;
if (emptyVmap) if (emptyVmap)
{
for (int i=0; i<cl.count(); i++)
{ {
Item item; for (int i=0; i<cl.count(); i++)
item.mCodecIndex = i; {
item.mPriority = i; Item item;
mPriorityList.push_back(item); item.mCodecIndex = i;
item.mPriority = i;
mPriorityList.push_back(item);
}
} }
} else
else
{
for (int i=0; i<cl.count(); i++)
{ {
Item item; for (int i=0; i<cl.count(); i++)
item.mCodecIndex = i; {
item.mPriority = vmap->exists(i) ? vmap->at(i).asInt() : 1000; // Non listed codecs will get lower priority Item item;
mPriorityList.push_back(item); item.mCodecIndex = i;
item.mPriority = vmap->exists(i) ? vmap->at(i).asInt() : 1000; // Non listed codecs will get lower priority
mPriorityList.push_back(item);
}
// Remove -1 records
mPriorityList.erase(std::remove_if(mPriorityList.begin(), mPriorityList.end(), isNegativePriority), mPriorityList.end());
// Sort by priority
std::sort(mPriorityList.begin(), mPriorityList.end(), compare);
} }
// Remove -1 records
mPriorityList.erase(std::remove_if(mPriorityList.begin(), mPriorityList.end(), isNegativePriority), mPriorityList.end());
// Sort by priority
std::sort(mPriorityList.begin(), mPriorityList.end(), compare);
}
} }
int CodecListPriority::count(const CodecList & /*cl*/) const int CodecListPriority::count(const CodecList & /*cl*/) const
{ {
return static_cast<int>(mPriorityList.size()); return static_cast<int>(mPriorityList.size());
} }
Codec::Factory& CodecListPriority::codecAt(const CodecList& cl, int index) const Codec::Factory& CodecListPriority::codecAt(const CodecList& cl, int index) const
{ {
return cl.codecAt(mPriorityList[static_cast<size_t>(index)].mCodecIndex); return cl.codecAt(mPriorityList[static_cast<size_t>(index)].mCodecIndex);
} }

View File

@ -43,7 +43,7 @@ public:
int mIsac32KPayloadType = -1; int mIsac32KPayloadType = -1;
int mIlbc20PayloadType = -1; int mIlbc20PayloadType = -1;
int mIlbc30PayloadType = -1; int mIlbc30PayloadType = -1;
int mGsmFrPayloadType = 3; // GSM is codec with fixed payload type. But sometimes it has to be overwritten. int mGsmFrPayloadType = -1; // GSM is codec with fixed payload type. But sometimes it has to be overwritten.
int mGsmFrPayloadLength = 33; // Expected GSM payload length int mGsmFrPayloadLength = 33; // Expected GSM payload length
int mGsmHrPayloadType = -1; int mGsmHrPayloadType = -1;
int mGsmEfrPayloadType = -1; int mGsmEfrPayloadType = -1;
@ -96,6 +96,9 @@ public:
}; };
std::vector<OpusSpec> mOpusSpec; std::vector<OpusSpec> mOpusSpec;
// Payload type
bool contains(int ptype) const;
// Textual representation - used in logging // Textual representation - used in logging
std::string toString() const; std::string toString() const;
void clear(); void clear();
@ -110,7 +113,9 @@ public:
CodecList(const Settings& settings); CodecList(const Settings& settings);
~CodecList(); ~CodecList();
void setSettings(const Settings& settings) { init(settings); } void setSettings(const Settings& settings) {
init(settings);
}
int count() const; int count() const;
Codec::Factory& codecAt(int index) const; Codec::Factory& codecAt(int index) const;
@ -119,7 +124,7 @@ public:
void clear(); void clear();
protected: protected:
typedef std::vector<Codec::Factory*> FactoryList; typedef std::vector<std::shared_ptr<Codec::Factory>> FactoryList;
FactoryList mFactoryList; FactoryList mFactoryList;
Settings mSettings; Settings mSettings;