- 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_DTMF_END_PACKETS 3
#define RTP_BUFFER_HIGH 480
#define RTP_BUFFER_LOW 10
#define RTP_BUFFER_PREBUFFER 320
#define RTP_BUFFER_HIGH 0
#define RTP_BUFFER_LOW 0
#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 DEFAULT_SUBSCRIPTION_TIME 1200

View File

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

View File

@ -14,16 +14,16 @@
namespace MT
{
struct AmrCodecConfig
{
struct AmrCodecConfig
{
bool mIuUP;
bool mOctetAligned;
int mPayloadType;
};
};
class AmrNbCodec : public Codec
{
protected:
class AmrNbCodec : public Codec
{
protected:
void* mEncoderCtx;
void* mDecoderCtx;
AmrCodecConfig mConfig;
@ -31,7 +31,7 @@ namespace MT
int mSwitchCounter;
int mPreviousPacketLength;
public:
public:
class CodecFactory: public Factory
{
public:
@ -64,11 +64,18 @@ namespace MT
int decode(const void* input, int inputBytes, void* output, int outputCapacity) override;
int plc(int lostFrames, void* output, int outputCapacity) override;
int getSwitchCounter() const;
};
};
class AmrWbCodec : public Codec
{
protected:
struct AmrWbStatistics
{
int mDiscarded = 0;
int mNonParsed = 0;
};
extern AmrWbStatistics GAmrWbStatistics;
class AmrWbCodec : public Codec
{
protected:
void* mEncoderCtx;
void* mDecoderCtx;
AmrCodecConfig mConfig;
@ -76,7 +83,7 @@ namespace MT
int mSwitchCounter;
int mPreviousPacketLength;
public:
public:
class CodecFactory: public Factory
{
public:
@ -109,16 +116,16 @@ namespace MT
int decode(const void* input, int inputBytes, void* output, int outputCapacity) override;
int plc(int lostFrames, void* output, int outputCapacity) override;
int getSwitchCounter() const;
};
};
class GsmEfrCodec : public Codec
{
protected:
class GsmEfrCodec : public Codec
{
protected:
void* mEncoderCtx;
void* mDecoderCtx;
bool mIuUP;
public:
public:
class GsmEfrFactory: public Factory
{
public:
@ -151,7 +158,7 @@ namespace MT
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 plc(int lostFrames, void* output, int outputCapacity) override;
};
};
} // End of MT namespace

View File

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

View File

@ -124,7 +124,7 @@ namespace MT
// Update codec settings
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.
// 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);

View File

@ -25,33 +25,95 @@ using namespace MT;
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::ostringstream oss;
oss << "wrap IuUP: " << mWrapIuUP << 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 << "wrap IuUP: " << mWrapIuUP << std::endl
// << "skip decode: " << mSkipDecode << std::endl;
oss << "ISAC 16Khz ptype: " << mIsac16KPayloadType << std::endl
<< "ISAC 32Khz ptype: " << mIsac32KPayloadType << std::endl
<< "iLBC 20ms ptype: " << mIlbc20PayloadType << std::endl
<< "iLBC 30ms ptype: " << mIlbc30PayloadType << std::endl
<< "GSM FR ptype: " << mGsmFrPayloadType << ", GSM FR plength: " << mGsmFrPayloadLength << std::endl
<< "GSM HR ptype: " << mGsmHrPayloadType << std::endl
<< "GSM EFR ptype: " << mGsmEfrPayloadType << std::endl;
if (!mAmrWbPayloadType.empty())
{
oss << "AMR WB ptype: ";
for (int ptype: mAmrWbPayloadType)
oss << ptype << " ";
}
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)
{
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)
@ -145,6 +207,21 @@ CodecList::Settings::OpusSpec CodecList::Settings::OpusSpec::parse(const std::st
}
#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 r{DefaultSettings};
@ -155,15 +232,44 @@ CodecList::Settings CodecList::Settings::parseSdp(const std::list<resip::Codec>&
int samplerate = c.getRate();
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.
if (codec_name == "OPUS")
{
// 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);
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;
}
@ -218,21 +324,12 @@ CodecList::CodecList(const Settings& settings)
void CodecList::init(const Settings& settings)
{
for (auto f: mFactoryList)
delete f;
mFactoryList.clear();
mSettings = settings;
#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)
{
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
@ -240,28 +337,29 @@ void CodecList::init(const Settings& settings)
#if !defined(TARGET_ANDROID) && !defined(TARGET_OPENWRT) && !defined(TARGET_RPI)
#if defined(USE_AMR_CODEC)
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)
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)
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)
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
// mFactoryList.push_back(new IsacCodec::IsacFactory16K(mSettings.mIsac16KPayloadType));
// mFactoryList.push_back(new IlbcCodec::IlbcFactory(mSettings.mIlbc20PayloadType, mSettings.mIlbc30PayloadType));
mFactoryList.push_back(new G711Codec::AlawFactory());
mFactoryList.push_back(new G711Codec::UlawFactory());
mFactoryList.push_back(std::make_shared<G711Codec::AlawFactory>());
mFactoryList.push_back(std::make_shared<G711Codec::UlawFactory>());
mFactoryList.push_back(new GsmCodec::GsmFactory(mSettings.mGsmFrPayloadLength == 32 ? GsmCodec::Type::Bytes_32 : GsmCodec::Type::Bytes_33, mSettings.mGsmFrPayloadType));
mFactoryList.push_back(new G722Codec::G722Factory());
mFactoryList.push_back(new G729Codec::G729Factory());
if (mSettings.mGsmFrPayloadType != -1)
mFactoryList.push_back(std::make_shared<GsmCodec::GsmFactory>(mSettings.mGsmFrPayloadLength == 32 ? GsmCodec::Type::Bytes_32 : GsmCodec::Type::Bytes_33, mSettings.mGsmFrPayloadType));
mFactoryList.push_back(std::make_shared<G722Codec::G722Factory>());
mFactoryList.push_back(std::make_shared<G729Codec::G729Factory>());
#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
#if !defined(TARGET_ANDROID) && defined(USE_EVS_CODEC)
@ -273,15 +371,14 @@ void CodecList::init(const Settings& settings)
evs_params.ptime = 20;
evs_params.ptype = spec.mPayloadType;
mFactoryList.push_back(new EVSCodec::EVSFactory(evs_params));
mFactoryList.push_back(std::make_shared<EVSCodec::EVSFactory>(evs_params));
}
#endif
}
CodecList::~CodecList()
{
for (auto f: mFactoryList)
delete f;
mFactoryList.clear();
}
int CodecList::count() const

View File

@ -43,7 +43,7 @@ public:
int mIsac32KPayloadType = -1;
int mIlbc20PayloadType = -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 mGsmHrPayloadType = -1;
int mGsmEfrPayloadType = -1;
@ -96,6 +96,9 @@ public:
};
std::vector<OpusSpec> mOpusSpec;
// Payload type
bool contains(int ptype) const;
// Textual representation - used in logging
std::string toString() const;
void clear();
@ -110,7 +113,9 @@ public:
CodecList(const Settings& settings);
~CodecList();
void setSettings(const Settings& settings) { init(settings); }
void setSettings(const Settings& settings) {
init(settings);
}
int count() const;
Codec::Factory& codecAt(int index) const;
@ -119,7 +124,7 @@ public:
void clear();
protected:
typedef std::vector<Codec::Factory*> FactoryList;
typedef std::vector<std::shared_ptr<Codec::Factory>> FactoryList;
FactoryList mFactoryList;
Settings mSettings;