- adopt RFC2833 decoder for pcap analyzer
This commit is contained in:
@@ -201,7 +201,7 @@ RtpBuffer::FetchResult RtpBuffer::fetch()
|
||||
// See if there is enough information in buffer
|
||||
auto total = findTimelength();
|
||||
|
||||
while (total > mHigh && mPacketList.size() && 0ms != mHigh)
|
||||
while (total > mHigh && mPacketList.size() > 1 && 0ms != mHigh)
|
||||
{
|
||||
ICELogMedia( << "Dropping RTP packets from jitter buffer");
|
||||
total -= mPacketList.front()->timelength();
|
||||
@@ -337,7 +337,7 @@ Receiver::~Receiver()
|
||||
|
||||
//-------------- AudioReceiver ----------------
|
||||
AudioReceiver::AudioReceiver(const CodecList::Settings& settings, MT::Statistics &stat)
|
||||
:Receiver(stat), mBuffer(stat), mCodecSettings(settings), mCodecList(settings)
|
||||
:Receiver(stat), mBuffer(stat), mDtmfBuffer(stat), mCodecSettings(settings), mCodecList(settings), mDtmfReceiver(stat)
|
||||
{
|
||||
// Init resamplers
|
||||
mResampler8.start(AUDIO_CHANNELS, 8000, AUDIO_SAMPLERATE);
|
||||
@@ -351,6 +351,10 @@ AudioReceiver::AudioReceiver(const CodecList::Settings& settings, MT::Statistics
|
||||
|
||||
mAvailable.setCapacity(AUDIO_SAMPLERATE * sizeof(short));
|
||||
|
||||
mDtmfBuffer.setPrebuffer(0ms);
|
||||
mDtmfBuffer.setLow(0ms);
|
||||
mDtmfBuffer.setHigh(1ms);
|
||||
|
||||
#if defined(DUMP_DECODED)
|
||||
mDecodedDump = std::make_shared<Audio::WavFileWriter>();
|
||||
mDecodedDump->open("decoded.wav", 8000 /*G711*/, AUDIO_CHANNELS);
|
||||
@@ -431,14 +435,19 @@ bool AudioReceiver::add(const std::shared_ptr<jrtplib::RTPPacket>& p, Codec** de
|
||||
// Increase codec counter
|
||||
mStat.mCodecCount[ptype]++;
|
||||
|
||||
// Check if we deal with telephone-event
|
||||
if (p->GetPayloadType() == mCodecSettings.mTelephoneEvent)
|
||||
{
|
||||
*detectedCodec = nullptr;
|
||||
mDtmfBuffer.add(p, 10ms, 8000);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Look for codec
|
||||
// Check if codec can be handled
|
||||
Codec* codec = nullptr;
|
||||
auto codecIter = mCodecMap.find(ptype);
|
||||
if (codecIter == mCodecMap.end())
|
||||
{
|
||||
// Well, there is no information about the codec; skip this packet
|
||||
}
|
||||
else
|
||||
if (codecIter != mCodecMap.end())
|
||||
{
|
||||
// Check if codec is creating lazily
|
||||
if (!codecIter->second)
|
||||
@@ -467,7 +476,7 @@ bool AudioReceiver::add(const std::shared_ptr<jrtplib::RTPPacket>& p, Codec** de
|
||||
samplerate = codec->samplerate();
|
||||
}
|
||||
|
||||
// Process jitter
|
||||
// Process jitter anyway - can we decode payload or not
|
||||
mJitterStats.process(p.get(), samplerate);
|
||||
mStat.mJitter = static_cast<float>(mJitterStats.get());
|
||||
|
||||
@@ -489,8 +498,9 @@ bool AudioReceiver::add(const std::shared_ptr<jrtplib::RTPPacket>& p, Codec** de
|
||||
|
||||
// Queue packet to buffer
|
||||
auto packet = mBuffer.add(p, std::chrono::milliseconds(time_length), samplerate).get();
|
||||
|
||||
return packet;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
void AudioReceiver::processDecoded(Audio::DataWindow& output, DecodeOptions options)
|
||||
@@ -764,6 +774,12 @@ AudioReceiver::DecodeResult AudioReceiver::getAudioTo(Audio::DataWindow& output,
|
||||
{
|
||||
DecodeResult result = {.mStatus = DecodeResult::Status::Skip};
|
||||
|
||||
// Process RFC2833 here; it doesn't result in any audio - only callbacks and statistics
|
||||
auto fr = mDtmfBuffer.fetch();
|
||||
if (fr.mPacket && fr.mStatus == RtpBuffer::FetchResult::Status::RegularPacket)
|
||||
mDtmfReceiver.add(fr.mPacket->rtp());
|
||||
|
||||
|
||||
auto produced = 0ms;
|
||||
if (mAvailable.filled() && mCodec && options.mElapsed != 0ms)
|
||||
{
|
||||
@@ -968,12 +984,10 @@ DtmfReceiver::~DtmfReceiver()
|
||||
|
||||
void DtmfReceiver::add(const std::shared_ptr<RTPPacket>& p)
|
||||
{
|
||||
// This receiver always work in context of single RTP stream; so there is no need to put SSRC map and so on
|
||||
if (p->GetPayloadType() != 101)
|
||||
return;
|
||||
|
||||
auto ev = DtmfBuilder::parseRfc2833({p->GetPayloadData(), p->GetPayloadLength()});
|
||||
if (ev.mTone != mEvent || ev.mEnd != mEventEnded)
|
||||
{
|
||||
if (!(mEvent == ev.mTone && !mEventEnded && ev.mEnd))
|
||||
{
|
||||
// New tone is here
|
||||
if (mCallback)
|
||||
@@ -987,4 +1001,5 @@ void DtmfReceiver::add(const std::shared_ptr<RTPPacket>& p)
|
||||
mEvent = ev.mTone;
|
||||
mEventEnded = ev.mEnd;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -136,6 +136,23 @@ protected:
|
||||
Statistics& mStat;
|
||||
};
|
||||
|
||||
class DtmfReceiver: public Receiver
|
||||
{
|
||||
private:
|
||||
char mEvent = 0;
|
||||
bool mEventEnded = false;
|
||||
std::chrono::milliseconds mEventStart = 0ms;
|
||||
std::function<void(char)> mCallback;
|
||||
|
||||
public:
|
||||
DtmfReceiver(Statistics& stat);
|
||||
~DtmfReceiver();
|
||||
|
||||
void add(const std::shared_ptr<RTPPacket>& p);
|
||||
void setCallback(std::function<void(char tone)> callback);
|
||||
};
|
||||
|
||||
|
||||
class AudioReceiver: public Receiver
|
||||
{
|
||||
public:
|
||||
@@ -189,6 +206,9 @@ public:
|
||||
|
||||
protected:
|
||||
RtpBuffer mBuffer; // Jitter buffer itself
|
||||
RtpBuffer mDtmfBuffer; // These two (mDtmfBuffer / mDtmfReceiver) are for our analyzer stack only; in normal softphone logic DTMF packets goes via SingleAudioStream::mDtmfReceiver
|
||||
DtmfReceiver mDtmfReceiver;
|
||||
|
||||
CodecMap mCodecMap;
|
||||
PCodec mCodec;
|
||||
int mFrameCount = 0;
|
||||
@@ -247,21 +267,6 @@ protected:
|
||||
DecodeResult decodeEmptyTo(Audio::DataWindow& output, DecodeOptions options);
|
||||
};
|
||||
|
||||
class DtmfReceiver: public Receiver
|
||||
{
|
||||
private:
|
||||
char mEvent = 0;
|
||||
bool mEventEnded = false;
|
||||
std::chrono::milliseconds mEventStart = 0ms;
|
||||
std::function<void(char)> mCallback;
|
||||
|
||||
public:
|
||||
DtmfReceiver(Statistics& stat);
|
||||
~DtmfReceiver();
|
||||
|
||||
void add(const std::shared_ptr<RTPPacket>& p);
|
||||
void setCallback(std::function<void(char tone)> callback);
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -65,6 +65,8 @@ bool CodecList::Settings::contains(int ptype) const
|
||||
|
||||
if (mGsmEfrPayloadType == ptype || mGsmFrPayloadType == ptype || mGsmHrPayloadType == ptype)
|
||||
return true;
|
||||
if (mTelephoneEvent == ptype)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
@@ -122,6 +124,9 @@ std::string CodecList::Settings::toString() const
|
||||
if (mGsmEfrPayloadType != -1)
|
||||
oss << "GSM EFR ptype: " << mGsmEfrPayloadType << " ";
|
||||
|
||||
if (mTelephoneEvent != -1)
|
||||
oss << "RFC2833 DTMF ptype: " << mTelephoneEvent;
|
||||
|
||||
for (auto& spec: mEvsSpec)
|
||||
{
|
||||
oss << "EVS ptype: " << spec.mPayloadType << ", bw: " << spec.mBandwidth << ", enc: " << (spec.mEncodingType == EvsSpec::Encoding_MIME ? "mime" : "g192") << " ";
|
||||
@@ -132,6 +137,7 @@ std::string CodecList::Settings::toString() const
|
||||
oss << "OPUS ptype: " << spec.mPayloadType << ", rate: " << spec.mRate << ", channels: " << spec.mChannels << std::endl;
|
||||
}
|
||||
|
||||
|
||||
return oss.str();
|
||||
}
|
||||
|
||||
@@ -151,6 +157,7 @@ void CodecList::Settings::clear()
|
||||
mGsmEfrPayloadType = -1;
|
||||
mGsmFrPayloadType = -1;
|
||||
mGsmHrPayloadType = -1;
|
||||
mTelephoneEvent = -1;
|
||||
}
|
||||
|
||||
bool CodecList::Settings::EvsSpec::isValid() const
|
||||
@@ -268,15 +275,16 @@ CodecList::Settings CodecList::Settings::parseSdp(const std::list<resip::Codec>&
|
||||
}
|
||||
} else if (codec_name == "EVS") {
|
||||
r.mEvsSpec.push_back({ptype});
|
||||
}
|
||||
} else if (codec_name == "TELEPHONE-EVENT")
|
||||
r.mTelephoneEvent = ptype;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
bool CodecList::Settings::operator == (const Settings& rhs) const
|
||||
{
|
||||
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))
|
||||
if (std::tie(mWrapIuUP, mSkipDecode, mIsac16KPayloadType, mIsac32KPayloadType, mIlbc20PayloadType, mIlbc30PayloadType, mGsmFrPayloadType, mGsmFrPayloadLength, mGsmEfrPayloadType, mGsmHrPayloadType, mTelephoneEvent) !=
|
||||
std::tie(rhs.mWrapIuUP, rhs.mSkipDecode, rhs.mIsac16KPayloadType, rhs.mIsac32KPayloadType, rhs.mIlbc20PayloadType, rhs.mIlbc30PayloadType, rhs.mGsmFrPayloadType, rhs.mGsmFrPayloadLength, rhs.mGsmEfrPayloadType, rhs.mGsmHrPayloadType, rhs.mTelephoneEvent))
|
||||
return false;
|
||||
|
||||
if (mAmrNbOctetPayloadType != rhs.mAmrNbOctetPayloadType)
|
||||
@@ -306,6 +314,9 @@ bool CodecList::Settings::operator == (const Settings& rhs) const
|
||||
if (mOpusSpec[i] != rhs.mOpusSpec[i])
|
||||
return false;
|
||||
|
||||
if (mTelephoneEvent != rhs.mTelephoneEvent)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
@@ -28,6 +28,9 @@ public:
|
||||
bool mWrapIuUP = false;
|
||||
bool mSkipDecode = false;
|
||||
|
||||
// RFC2833 DTMF
|
||||
int mTelephoneEvent = -1;
|
||||
|
||||
// AMR payload types
|
||||
std::set<int64_t> mAmrWbPayloadType = { };
|
||||
std::set<int64_t> mAmrNbPayloadType = { };
|
||||
|
||||
@@ -23,7 +23,7 @@ SingleAudioStream::~SingleAudioStream()
|
||||
void SingleAudioStream::process(const std::shared_ptr<jrtplib::RTPPacket>& packet)
|
||||
{
|
||||
ICELogMedia(<< "Processing incoming RTP/RTCP packet");
|
||||
if (packet->GetPayloadType() == 101/*resip::Codec::TelephoneEvent.payloadType()*/)
|
||||
if (packet->GetPayloadType() == mReceiver.getCodecSettings().mTelephoneEvent)
|
||||
mDtmfReceiver.add(packet);
|
||||
else
|
||||
mReceiver.add(packet);
|
||||
|
||||
Reference in New Issue
Block a user