- 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

@ -50,9 +50,13 @@
#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

@ -66,6 +66,13 @@ namespace MT
int getSwitchCounter() const; int getSwitchCounter() const;
}; };
struct AmrWbStatistics
{
int mDiscarded = 0;
int mNonParsed = 0;
};
extern AmrWbStatistics GAmrWbStatistics;
class AmrWbCodec : public Codec class AmrWbCodec : public Codec
{ {
protected: protected:

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,9 +469,12 @@ 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);
if (available > 0)
{
packet->pcm().resize(available / 2); packet->pcm().resize(available / 2);
memcpy(packet->pcm().data(), mDecodedFrame, available / 2); memcpy(packet->pcm().data(), mDecodedFrame, available / 2);
} }
}
return true; return true;
} }
else else

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)
@ -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;
} }
@ -218,21 +324,12 @@ CodecList::CodecList(const Settings& settings)
void CodecList::init(const Settings& settings) void CodecList::init(const Settings& settings)
{ {
for (auto f: mFactoryList)
delete f;
mFactoryList.clear(); mFactoryList.clear();
mSettings = settings;
#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
@ -240,28 +337,29 @@ void CodecList::init(const Settings& settings)
#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)
@ -273,15 +371,14 @@ void CodecList::init(const Settings& settings)
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

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;