- ongoing work to ease jitter & RTT calculation

This commit is contained in:
Dmytro Bogovych 2023-04-11 13:43:38 +03:00
parent d90940c907
commit 0607bd1c47
14 changed files with 1071 additions and 1037 deletions

View File

@ -1,4 +1,4 @@
/* Copyright(C) 2007-2016 VoIP objects (voipobjects.com) /* Copyright(C) 2007-2023 VoIP objects (voipobjects.com)
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
@ -10,13 +10,13 @@
enum class StreamState enum class StreamState
{ {
Sending = 1, // Transmitting RTP. Set this flag to allow outgoing media stream. Sending = 1, // Transmitting RTP. Set this flag to allow outgoing media stream.
Receiving = 2, // Receiving RTP. Set this flag to allow receiving media stream. Receiving = 2, // Receiving RTP. Set this flag to allow receiving media stream.
Playing = 4, // Play to audio. Unmutes the audio from specified stream. Playing = 4, // Play to audio. Unmutes the audio from specified stream.
Grabbing = 8, // Capture audio. Unmutes the audio to specified stream. Grabbing = 8, // Capture audio. Unmutes the audio to specified stream.
Srtp = 16, // Use SRTP. Make attempt Srtp = 16, // Use SRTP. Make attempt
SipSend = 32, // Declare send capability in SDP SipSend = 32, // Declare send capability in SDP
SipRecv = 64 // Declare recv capability in SDP SipRecv = 64 // Declare recv capability in SDP
}; };

View File

@ -22,413 +22,412 @@
using namespace MT; using namespace MT;
AudioStream::AudioStream(const CodecList::Settings& settings) AudioStream::AudioStream(const CodecList::Settings& settings)
:mPacketTime(0), mEncodedTime(0), mCodecSettings(settings), :mPacketTime(0), mEncodedTime(0), mCodecSettings(settings),
mRemoteTelephoneCodec(0), mRtpSession(), mTransmittingPayloadType(-1), mRemoteTelephoneCodec(0), mRtpSession(), mTransmittingPayloadType(-1),
mRtpSender(mStat) mRtpSender(mStat)
{ {
mOutputBuffer.setCapacity(16384); mOutputBuffer.setCapacity(16384);
mCapturedAudio.setCapacity(16384); mCapturedAudio.setCapacity(16384);
mCaptureResampler8.start(AUDIO_CHANNELS, AUDIO_SAMPLERATE, 8000); mCaptureResampler8.start(AUDIO_CHANNELS, AUDIO_SAMPLERATE, 8000);
mCaptureResampler16.start(AUDIO_CHANNELS, AUDIO_SAMPLERATE, 16000); mCaptureResampler16.start(AUDIO_CHANNELS, AUDIO_SAMPLERATE, 16000);
mCaptureResampler32.start(AUDIO_CHANNELS, AUDIO_SAMPLERATE, 32000); mCaptureResampler32.start(AUDIO_CHANNELS, AUDIO_SAMPLERATE, 32000);
mCaptureResampler48.start(AUDIO_CHANNELS, AUDIO_SAMPLERATE, 48000); mCaptureResampler48.start(AUDIO_CHANNELS, AUDIO_SAMPLERATE, 48000);
// Configure transmitter // Configure transmitter
jrtplib::RTPExternalTransmissionParams params(&mRtpSender, 0); jrtplib::RTPExternalTransmissionParams params(&mRtpSender, 0);
jrtplib::RTPSessionParams sessionParams; jrtplib::RTPSessionParams sessionParams;
sessionParams.SetAcceptOwnPackets(true); sessionParams.SetAcceptOwnPackets(true);
sessionParams.SetMaximumPacketSize(MT_MAXRTPPACKET); sessionParams.SetMaximumPacketSize(MT_MAXRTPPACKET);
sessionParams.SetResolveLocalHostname(false); sessionParams.SetResolveLocalHostname(false);
sessionParams.SetUsePollThread(false); sessionParams.SetUsePollThread(false);
sessionParams.SetOwnTimestampUnit(1/8000.0); sessionParams.SetOwnTimestampUnit(1/8000.0);
mRtpSession.Create(sessionParams, &params, jrtplib::RTPTransmitter::ExternalProto); mRtpSession.Create(sessionParams, &params, jrtplib::RTPTransmitter::ExternalProto);
mRtpDtmfSession.Create(sessionParams, &params, jrtplib::RTPTransmitter::ExternalProto); mRtpDtmfSession.Create(sessionParams, &params, jrtplib::RTPTransmitter::ExternalProto);
// Attach srtp session to sender // Attach srtp session to sender
mRtpSender.setSrtpSession(&mSrtpSession); mRtpSender.setSrtpSession(&mSrtpSession);
//mRtpDump = new RtpDump("d:\\outgoing.rtp"); //mRtpDump = new RtpDump("d:\\outgoing.rtp");
//mRtpSender.setDumpWriter(mRtpDump); //mRtpSender.setDumpWriter(mRtpDump);
#if defined(DUMP_SENDING_AUDIO) #if defined(DUMP_SENDING_AUDIO)
mSendingDump = std::make_shared<WavFileWriter>(); mSendingDump = std::make_shared<WavFileWriter>();
mSendingDump->open("sending_audio.wav", 8000, 1); mSendingDump->open("sending_audio.wav", 8000, 1);
#endif #endif
} }
AudioStream::~AudioStream() AudioStream::~AudioStream()
{ {
ICELogInfo(<< "Delete AudioStream instance"); ICELogInfo(<< "Delete AudioStream instance");
if (mSendingDump) if (mSendingDump)
{ {
mSendingDump->close(); mSendingDump->close();
mSendingDump.reset(); mSendingDump.reset();
} }
// Delete used rtp streams // Delete used rtp streams
for (AudioStreamMap::iterator streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter) for (AudioStreamMap::iterator streamIter = mStreamMap.begin(); streamIter != mStreamMap.end(); ++streamIter)
delete streamIter->second; delete streamIter->second;
mStreamMap.clear(); mStreamMap.clear();
if (mRtpDtmfSession.IsActive()) if (mRtpDtmfSession.IsActive())
mRtpDtmfSession.Destroy(); mRtpDtmfSession.Destroy();
if (mRtpSession.IsActive()) if (mRtpSession.IsActive())
mRtpSession.Destroy(); mRtpSession.Destroy();
#if defined(USE_RTPDUMP) #if defined(USE_RTPDUMP)
if (mRtpDump) if (mRtpDump)
{ {
mRtpDump->flush(); mRtpDump->flush();
delete mRtpDump; delete mRtpDump;
} }
#endif #endif
mCaptureResampler8.stop(); mCaptureResampler8.stop();
mCaptureResampler16.stop(); mCaptureResampler16.stop();
mCaptureResampler32.stop(); mCaptureResampler32.stop();
mCaptureResampler48.stop(); mCaptureResampler48.stop();
ICELogInfo(<< "Encoded " << mEncodedTime << " milliseconds of audio"); ICELogInfo(<< "Encoded " << mEncodedTime << " milliseconds of audio");
if (mDumpStreams.mStreamForRecordingIncoming) if (mDumpStreams.mStreamForRecordingIncoming)
mDumpStreams.mStreamForRecordingIncoming->close(); mDumpStreams.mStreamForRecordingIncoming->close();
if (mDumpStreams.mStreamForReadingOutgoing) if (mDumpStreams.mStreamForReadingOutgoing)
mDumpStreams.mStreamForReadingOutgoing->close(); mDumpStreams.mStreamForReadingOutgoing->close();
if (mFinalStatistics) if (mFinalStatistics)
*mFinalStatistics = mStat; *mFinalStatistics = mStat;
ICELogInfo(<< mStat.toString()); ICELogInfo(<< mStat.toString());
} }
void AudioStream::setDestination(const RtpPair<InternetAddress>& dest) void AudioStream::setDestination(const RtpPair<InternetAddress>& dest)
{ {
Lock l(mMutex); Lock l(mMutex);
Stream::setDestination(dest); Stream::setDestination(dest);
mRtpSender.setDestination(dest); mRtpSender.setDestination(dest);
} }
void AudioStream::setTransmittingCodec(Codec::Factory& factory, int payloadType) void AudioStream::setTransmittingCodec(Codec::Factory& factory, int payloadType)
{ {
ICELogInfo(<< "Selected codec " << factory.name() << "/" << factory.samplerate() << " for transmitting"); ICELogInfo(<< "Selected codec " << factory.name() << "/" << factory.samplerate() << " for transmitting");
Lock l(mMutex); Lock l(mMutex);
mTransmittingCodec = factory.create(); mTransmittingCodec = factory.create();
mTransmittingPayloadType = payloadType; mTransmittingPayloadType = payloadType;
if (mRtpSession.IsActive()) if (mRtpSession.IsActive())
mRtpSession.SetTimestampUnit(1.0 / mTransmittingCodec->samplerate()); mRtpSession.SetTimestampUnit(1.0 / mTransmittingCodec->samplerate());
} }
PCodec AudioStream::transmittingCodec() PCodec AudioStream::transmittingCodec()
{ {
Lock l(mMutex); Lock l(mMutex);
return mTransmittingCodec; return mTransmittingCodec;
} }
void AudioStream::addData(const void* buffer, int bytes) void AudioStream::addData(const void* buffer, int bytes)
{ {
assert(bytes == AUDIO_MIC_BUFFER_SIZE); assert(bytes == AUDIO_MIC_BUFFER_SIZE);
// Read predefined audio if configured // Read predefined audio if configured
if (mDumpStreams.mStreamForReadingOutgoing) if (mDumpStreams.mStreamForReadingOutgoing)
{ {
if (mDumpStreams.mStreamForReadingOutgoing->isOpened()) if (mDumpStreams.mStreamForReadingOutgoing->isOpened())
mDumpStreams.mStreamForReadingOutgoing->read(const_cast<void*>(buffer), bytes); mDumpStreams.mStreamForReadingOutgoing->read(const_cast<void*>(buffer), bytes);
}
// Read mirrored audio if needed
if (mMirror && mMirrorPrebuffered)
mMirrorBuffer.read(const_cast<void*>(buffer), bytes);
if (mMediaObserver)
mMediaObserver->onMedia(buffer, bytes, MT::Stream::MediaDirection::Outgoing, this, mMediaObserverTag);
Codec* codec = nullptr;
{
Lock l(mMutex);
codec = mTransmittingCodec.get();
if (nullptr == codec) {
// ICELogDebug(<< "No transmitting codec selected.");
return;
} }
}
// Resample // Read mirrored audio if needed
unsigned dstlen = unsigned(float(codec->samplerate() / float(AUDIO_SAMPLERATE)) * bytes); if (mMirror && mMirrorPrebuffered)
Audio::Resampler* r = nullptr; mMirrorBuffer.read(const_cast<void*>(buffer), bytes);
switch (codec->samplerate())
{
case 8000: r = &mCaptureResampler8; break;
case 16000: r = &mCaptureResampler16; break;
case 32000: r = &mCaptureResampler32; break;
case 48000: r = &mCaptureResampler48; break;
default:
assert(0);
}
size_t processedInput = 0; if (mMediaObserver)
dstlen = r->processBuffer(buffer, bytes, processedInput, mResampleBuffer, dstlen); mMediaObserver->onMedia(buffer, bytes, MT::Stream::MediaDirection::Outgoing, this, mMediaObserverTag);
// ProcessedInput output value is ignored - because sample rate of input is always 8/16/32/48K - so all buffer is processed
// See if we need stereo <-> mono conversions Codec* codec = nullptr;
unsigned stereolen = 0; {
if (codec->channels() != AUDIO_CHANNELS) Lock l(mMutex);
{ codec = mTransmittingCodec.get();
if (codec->channels() == 2) if (nullptr == codec) {
stereolen = Audio::ChannelConverter::monoToStereo(mResampleBuffer, dstlen, mStereoBuffer, dstlen * 2); // ICELogDebug(<< "No transmitting codec selected.");
return;
}
}
// Resample
unsigned dstlen = unsigned(float(codec->samplerate() / float(AUDIO_SAMPLERATE)) * bytes);
Audio::Resampler* r = nullptr;
switch (codec->samplerate())
{
case 8000: r = &mCaptureResampler8; break;
case 16000: r = &mCaptureResampler16; break;
case 32000: r = &mCaptureResampler32; break;
case 48000: r = &mCaptureResampler48; break;
default:
assert(0);
}
size_t processedInput = 0;
dstlen = r->processBuffer(buffer, bytes, processedInput, mResampleBuffer, dstlen);
// ProcessedInput output value is ignored - because sample rate of input is always 8/16/32/48K - so all buffer is processed
// See if we need stereo <-> mono conversions
unsigned stereolen = 0;
if (codec->channels() != AUDIO_CHANNELS)
{
if (codec->channels() == 2)
stereolen = Audio::ChannelConverter::monoToStereo(mResampleBuffer, dstlen, mStereoBuffer, dstlen * 2);
else
dstlen = Audio::ChannelConverter::stereoToMono(mResampleBuffer, dstlen, mResampleBuffer, dstlen / 2);
}
// See if inband dtmf audio should be sent instead
ByteBuffer dtmf;
if (mDtmfContext.type() == DtmfContext::Dtmf_Inband && mDtmfContext.getInband(AUDIO_MIC_BUFFER_LENGTH, codec->samplerate(), dtmf))
mCapturedAudio.add(dtmf.data(), dtmf.size());
else else
dstlen = Audio::ChannelConverter::stereoToMono(mResampleBuffer, dstlen, mResampleBuffer, dstlen / 2); mCapturedAudio.add(stereolen ? mStereoBuffer : mResampleBuffer, stereolen ? stereolen : dstlen);
}
// See if inband dtmf audio should be sent instead // See if it is time to send RFC2833 tone
ByteBuffer dtmf; ByteBuffer rfc2833, stopPacket;
if (mDtmfContext.type() == DtmfContext::Dtmf_Inband && mDtmfContext.getInband(AUDIO_MIC_BUFFER_LENGTH, codec->samplerate(), dtmf)) if (mDtmfContext.type() == DtmfContext::Dtmf_Rfc2833 && mDtmfContext.getRfc2833(AUDIO_MIC_BUFFER_LENGTH, rfc2833, stopPacket))
mCapturedAudio.add(dtmf.data(), dtmf.size());
else
mCapturedAudio.add(stereolen ? mStereoBuffer : mResampleBuffer, stereolen ? stereolen : dstlen);
// See if it is time to send RFC2833 tone
ByteBuffer rfc2833, stopPacket;
if (mDtmfContext.type() == DtmfContext::Dtmf_Rfc2833 && mDtmfContext.getRfc2833(AUDIO_MIC_BUFFER_LENGTH, rfc2833, stopPacket))
{
if (rfc2833.size())
mRtpDtmfSession.SendPacket(rfc2833.data(), rfc2833.size(), mRemoteTelephoneCodec, true, AUDIO_MIC_BUFFER_LENGTH * 8);
if (stopPacket.size())
{ {
for (int i=0; i<3; i++) if (rfc2833.size())
mRtpDtmfSession.SendPacket(stopPacket.data(), stopPacket.size(), mRemoteTelephoneCodec, true, AUDIO_MIC_BUFFER_LENGTH * 8); mRtpDtmfSession.SendPacket(rfc2833.data(), rfc2833.size(), mRemoteTelephoneCodec, true, AUDIO_MIC_BUFFER_LENGTH * 8);
if (stopPacket.size())
{
for (int i=0; i<3; i++)
mRtpDtmfSession.SendPacket(stopPacket.data(), stopPacket.size(), mRemoteTelephoneCodec, true, AUDIO_MIC_BUFFER_LENGTH * 8);
}
} }
}
int processed = 0; int processed = 0;
int encodedTime = 0; int encodedTime = 0;
int packetTime = mPacketTime ? mPacketTime : codec->frameTime(); int packetTime = mPacketTime ? mPacketTime : codec->frameTime();
// Make stereo version if required // Make stereo version if required
for (int i=0; i<mCapturedAudio.filled() / codec->pcmLength(); i++) for (int i=0; i<mCapturedAudio.filled() / codec->pcmLength(); i++)
{
if (mSendingDump)
mSendingDump->write((const char*)mCapturedAudio.data() + codec->pcmLength() * i, codec->pcmLength());
int produced;
produced = codec->encode((const char*)mCapturedAudio.data() + codec->pcmLength()*i,
codec->pcmLength(), mFrameBuffer, MT_MAXAUDIOFRAME);
// Counter of processed input bytes of raw pcm data from microphone
processed += codec->pcmLength();
encodedTime += codec->frameTime();
mEncodedTime += codec->frameTime();
if (produced)
{ {
mEncodedAudio.appendBuffer(mFrameBuffer, produced); if (mSendingDump)
if (packetTime <= encodedTime) mSendingDump->write((const char*)mCapturedAudio.data() + codec->pcmLength() * i, codec->pcmLength());
{
// Time to send packet int produced;
ICELogMedia(<< "Sending RTP packet pt = " << mTransmittingPayloadType << ", plength = " << (int)mEncodedAudio.size()); produced = codec->encode((const char*)mCapturedAudio.data() + codec->pcmLength()*i,
mRtpSession.SendPacketEx(mEncodedAudio.data(), mEncodedAudio.size(), mTransmittingPayloadType, false, codec->pcmLength(), mFrameBuffer, MT_MAXAUDIOFRAME);
packetTime * codec->samplerate()/1000, 0, NULL, 0);
mEncodedAudio.clear(); // Counter of processed input bytes of raw pcm data from microphone
encodedTime = 0; processed += codec->pcmLength();
} encodedTime += codec->frameTime();
mEncodedTime += codec->frameTime();
if (produced)
{
mEncodedAudio.appendBuffer(mFrameBuffer, produced);
if (packetTime <= encodedTime)
{
// Time to send packet
ICELogMedia(<< "Sending RTP packet pt = " << mTransmittingPayloadType << ", plength = " << (int)mEncodedAudio.size());
mRtpSession.SendPacketEx(mEncodedAudio.data(), mEncodedAudio.size(), mTransmittingPayloadType, false,
packetTime * codec->samplerate()/1000, 0, NULL, 0);
mEncodedAudio.clear();
encodedTime = 0;
}
}
} }
} if (processed > 0)
if (processed > 0) mCapturedAudio.erase(processed);
mCapturedAudio.erase(processed);
} }
void AudioStream::copyDataTo(Audio::Mixer& mixer, int needed) void AudioStream::copyDataTo(Audio::Mixer& mixer, int needed)
{ {
// Local audio mixer - used to send audio to media observer // Local audio mixer - used to send audio to media observer
Audio::Mixer localMixer; Audio::Mixer localMixer;
Audio::DataWindow forObserver; Audio::DataWindow forObserver;
// Iterate // Iterate
for (auto& streamIter: mStreamMap) for (auto& streamIter: mStreamMap)
{
Audio::DataWindow w;
w.setCapacity(32768);
SingleAudioStream* sas = streamIter.second;
if (sas)
{ {
sas->copyPcmTo(w, needed); Audio::DataWindow w;
w.setCapacity(32768);
// Provide mirroring if needed SingleAudioStream* sas = streamIter.second;
if (mMirror) if (sas)
{
mMirrorBuffer.add(w.data(), w.filled());
if (!mMirrorPrebuffered)
mMirrorPrebuffered = mMirrorBuffer.filled() >= MT_MIRROR_PREBUFFER;
}
if (!(state() & (int)StreamState::Receiving))
w.zero(needed);
// Check if we do not need input from this stream
if (w.filled())
{
if (mDumpStreams.mStreamForRecordingIncoming)
{ {
if (mDumpStreams.mStreamForRecordingIncoming->isOpened()) sas->copyPcmTo(w, needed);
mDumpStreams.mStreamForRecordingIncoming->write(w.data(), w.filled());
// Provide mirroring if needed
if (mMirror)
{
mMirrorBuffer.add(w.data(), w.filled());
if (!mMirrorPrebuffered)
mMirrorPrebuffered = mMirrorBuffer.filled() >= MT_MIRROR_PREBUFFER;
}
if (!(state() & (int)StreamState::Receiving))
w.zero(needed);
// Check if we do not need input from this stream
if (w.filled())
{
if (mDumpStreams.mStreamForRecordingIncoming)
{
if (mDumpStreams.mStreamForRecordingIncoming->isOpened())
mDumpStreams.mStreamForRecordingIncoming->write(w.data(), w.filled());
}
mixer.addPcm(this, streamIter.first, w, AUDIO_SAMPLERATE, false);
if (mMediaObserver)
localMixer.addPcm(this, streamIter.first, w, AUDIO_SAMPLERATE, false);
}
} }
mixer.addPcm(this, streamIter.first, w, AUDIO_SAMPLERATE, false);
if (mMediaObserver)
localMixer.addPcm(this, streamIter.first, w, AUDIO_SAMPLERATE, false);
}
} }
}
if (mMediaObserver) if (mMediaObserver)
{ {
localMixer.mixAndGetPcm(forObserver); localMixer.mixAndGetPcm(forObserver);
mMediaObserver->onMedia(forObserver.data(), forObserver.capacity(), MT::Stream::MediaDirection::Incoming, this, mMediaObserverTag); mMediaObserver->onMedia(forObserver.data(), forObserver.capacity(), MT::Stream::MediaDirection::Incoming, this, mMediaObserverTag);
} }
} }
void AudioStream::dataArrived(PDatagramSocket s, const void* buffer, int length, InternetAddress& source) void AudioStream::dataArrived(PDatagramSocket s, const void* buffer, int length, InternetAddress& source)
{ {
jrtplib::RTPIPv6Address addr6; jrtplib::RTPIPv6Address addr6;
jrtplib::RTPIPv4Address addr4; jrtplib::RTPIPv4Address addr4;
jrtplib::RTPExternalTransmissionInfo* info = dynamic_cast<jrtplib::RTPExternalTransmissionInfo*>(mRtpSession.GetTransmissionInfo()); jrtplib::RTPExternalTransmissionInfo* info = dynamic_cast<jrtplib::RTPExternalTransmissionInfo*>(mRtpSession.GetTransmissionInfo());
assert(info); assert(info);
// Drop RTP packets if stream is not receiving now; let RTCP go // Drop RTP packets if stream is not receiving now; let RTCP go
if (!(state() & (int)StreamState::Receiving) && RtpHelper::isRtp(buffer, length)) if (!(state() & (int)StreamState::Receiving) && RtpHelper::isRtpOrRtcp(buffer, length))
{
ICELogMedia(<< "Stream is not allowed to receive RTP stream. Ignore the packet");
return;
}
// Copy incoming data to temp buffer to perform possible srtp unprotect
int receiveLength = length;
memcpy(mReceiveBuffer, buffer, length);
bool srtpResult;
if (mSrtpSession.active())
{
if (RtpHelper::isRtp(mReceiveBuffer, receiveLength))
srtpResult = mSrtpSession.unprotectRtp(mReceiveBuffer, &receiveLength);
else
srtpResult = mSrtpSession.unprotectRtcp(mReceiveBuffer, &receiveLength);
if (!srtpResult)
{ {
ICELogError(<<"Cannot decrypt SRTP packet."); ICELogMedia(<< "Stream is not allowed to receive RTP stream. Ignore the RT(C)P packet");
return; return;
} }
}
//ICELogDebug(<< "Packet no: " << RtpHelper::findPacketNo(mReceiveBuffer, receiveLength)); // Copy incoming data to temp buffer to perform possible srtp unprotect
int receiveLength = length;
memcpy(mReceiveBuffer, buffer, length);
switch (source.family()) bool srtpResult;
{ if (mSrtpSession.active())
case AF_INET:
addr4.SetIP(source.sockaddr4()->sin_addr.s_addr);
addr4.SetPort(source.port());
ICELogMedia(<< "Injecting RTP/RTCP packet into jrtplib");
info->GetPacketInjector()->InjectRTPorRTCP(mReceiveBuffer, receiveLength, addr4);
break;
case AF_INET6:
addr6.SetIP(source.sockaddr6()->sin6_addr);
addr6.SetPort(source.port());
ICELogMedia(<< "Injecting RTP/RTCP packet into jrtplib");
info->GetPacketInjector()->InjectRTPorRTCP(mReceiveBuffer, receiveLength, addr6);
break;
default:
assert(0);
}
mStat.mReceived += length;
if (RtpHelper::isRtp(mReceiveBuffer, receiveLength))
{
if (!mStat.mFirstRtpTime.is_initialized())
mStat.mFirstRtpTime = std::chrono::system_clock::now();
mStat.mReceivedRtp++;
}
else
mStat.mReceivedRtcp++;
mRtpSession.Poll(); // maybe it is extra with external transmitter
bool hasData = mRtpSession.GotoFirstSourceWithData();
while (hasData)
{
std::shared_ptr<jrtplib::RTPPacket> packet(mRtpSession.GetNextPacket());
if (packet)
{ {
ICELogMedia(<< "jrtplib returned packet"); if (RtpHelper::isRtp(mReceiveBuffer, receiveLength))
// Find right handler for rtp stream srtpResult = mSrtpSession.unprotectRtp(mReceiveBuffer, &receiveLength);
SingleAudioStream* rtpStream = nullptr;
AudioStreamMap::iterator streamIter = mStreamMap.find(packet->GetSSRC());
if (streamIter == mStreamMap.end())
mStreamMap[packet->GetSSRC()] = rtpStream = new SingleAudioStream(mCodecSettings, mStat);
else else
rtpStream = streamIter->second; srtpResult = mSrtpSession.unprotectRtcp(mReceiveBuffer, &receiveLength);
if (!srtpResult)
// Process incoming data packet {
rtpStream->process(packet); ICELogError(<<"Cannot decrypt SRTP packet.");
return;
double rtt = mRtpSession.GetCurrentSourceInfo()->INF_GetRoundtripTime().GetDouble(); }
if (rtt > 0) }
mStat.mRttDelay.process(rtt);
switch (source.family())
{
case AF_INET:
addr4.SetIP(source.sockaddr4()->sin_addr.s_addr);
addr4.SetPort(source.port());
ICELogMedia(<< "Injecting RTP/RTCP packet into jrtplib");
info->GetPacketInjector()->InjectRTPorRTCP(mReceiveBuffer, receiveLength, addr4);
break;
case AF_INET6:
addr6.SetIP(source.sockaddr6()->sin6_addr);
addr6.SetPort(source.port());
ICELogMedia(<< "Injecting RTP/RTCP packet into jrtplib");
info->GetPacketInjector()->InjectRTPorRTCP(mReceiveBuffer, receiveLength, addr6);
break;
default:
assert(0);
}
mStat.mReceived += length;
if (RtpHelper::isRtp(mReceiveBuffer, receiveLength))
{
if (!mStat.mFirstRtpTime.is_initialized())
mStat.mFirstRtpTime = std::chrono::system_clock::now();
mStat.mReceivedRtp++;
}
else
mStat.mReceivedRtcp++;
mRtpSession.Poll(); // maybe it is extra with external transmitter
bool hasData = mRtpSession.GotoFirstSourceWithData();
while (hasData)
{
std::shared_ptr<jrtplib::RTPPacket> packet(mRtpSession.GetNextPacket());
if (packet)
{
ICELogMedia(<< "jrtplib returned packet");
// Find right handler for rtp stream
SingleAudioStream* rtpStream = nullptr;
AudioStreamMap::iterator streamIter = mStreamMap.find(packet->GetSSRC());
if (streamIter == mStreamMap.end())
mStreamMap[packet->GetSSRC()] = rtpStream = new SingleAudioStream(mCodecSettings, mStat);
else
rtpStream = streamIter->second;
// Process incoming data packet
rtpStream->process(packet);
double rtt = mRtpSession.GetCurrentSourceInfo()->INF_GetRoundtripTime().GetDouble();
if (rtt > 0)
mStat.mRttDelay.process(rtt);
}
hasData = mRtpSession.GotoNextSourceWithData();
} }
hasData = mRtpSession.GotoNextSourceWithData();
}
} }
void AudioStream::setState(unsigned state) void AudioStream::setState(unsigned state)
{ {
Stream::setState(state); Stream::setState(state);
} }
void AudioStream::setTelephoneCodec(int payloadType) void AudioStream::setTelephoneCodec(int payloadType)
{ {
mRemoteTelephoneCodec = payloadType; mRemoteTelephoneCodec = payloadType;
} }
void AudioStream::setSocket(const RtpPair<PDatagramSocket>& socket) void AudioStream::setSocket(const RtpPair<PDatagramSocket>& socket)
{ {
Stream::setSocket(socket); Stream::setSocket(socket);
mRtpSender.setSocket(socket); mRtpSender.setSocket(socket);
} }
DtmfContext& AudioStream::queueOfDtmf() DtmfContext& AudioStream::queueOfDtmf()
{ {
return mDtmfContext; return mDtmfContext;
} }
void AudioStream::readFile(const Audio::PWavFileReader& stream, MediaDirection direction) void AudioStream::readFile(const Audio::PWavFileReader& stream, MediaDirection direction)
{ {
switch (direction) switch (direction)
{ {
case MediaDirection::Outgoing: mDumpStreams.mStreamForReadingOutgoing = stream; break; case MediaDirection::Outgoing: mDumpStreams.mStreamForReadingOutgoing = stream; break;
case MediaDirection::Incoming: mDumpStreams.mStreamForReadingIncoming = stream; break; case MediaDirection::Incoming: mDumpStreams.mStreamForReadingIncoming = stream; break;
} }
} }
void AudioStream::writeFile(const Audio::PWavFileWriter& writer, MediaDirection direction) void AudioStream::writeFile(const Audio::PWavFileWriter& writer, MediaDirection direction)
{ {
switch (direction) switch (direction)
{ {
case MediaDirection::Outgoing: mDumpStreams.mStreamForRecordingOutgoing = writer; break; case MediaDirection::Outgoing: mDumpStreams.mStreamForRecordingOutgoing = writer; break;
case MediaDirection::Incoming: mDumpStreams.mStreamForRecordingIncoming = writer; break; case MediaDirection::Incoming: mDumpStreams.mStreamForRecordingIncoming = writer; break;
} }
} }
void AudioStream::setupMirror(bool enable) void AudioStream::setupMirror(bool enable)
{ {
if (!mMirror && enable) if (!mMirror && enable)
{ {
mMirrorBuffer.setCapacity(MT_MIRROR_CAPACITY); mMirrorBuffer.setCapacity(MT_MIRROR_CAPACITY);
mMirrorPrebuffered = false; mMirrorPrebuffered = false;
} }
mMirror = enable; mMirror = enable;
} }
void AudioStream::setFinalStatisticsOutput(Statistics* stats) void AudioStream::setFinalStatisticsOutput(Statistics* stats)
{ {
mFinalStatistics = stats; mFinalStatistics = stats;
} }

View File

@ -26,9 +26,9 @@
namespace MT namespace MT
{ {
class AudioStream: public Stream class AudioStream: public Stream
{ {
public: public:
AudioStream(const CodecList::Settings& codecSettings); AudioStream(const CodecList::Settings& codecSettings);
~AudioStream(); ~AudioStream();
@ -59,7 +59,7 @@ namespace MT
void setFinalStatisticsOutput(Statistics* stats); void setFinalStatisticsOutput(Statistics* stats);
protected: protected:
Audio::DataWindow mCapturedAudio; // Data from microphone Audio::DataWindow mCapturedAudio; // Data from microphone
Audio::DataWindow mStereoCapturedAudio; Audio::DataWindow mStereoCapturedAudio;
char mIncomingPcmBuffer[AUDIO_MIC_BUFFER_SIZE]; // Temporary buffer to allow reading from file char mIncomingPcmBuffer[AUDIO_MIC_BUFFER_SIZE]; // Temporary buffer to allow reading from file
@ -83,18 +83,18 @@ namespace MT
RtpDump* mRtpDump = nullptr; RtpDump* mRtpDump = nullptr;
#endif #endif
Audio::Resampler mCaptureResampler8, Audio::Resampler mCaptureResampler8,
mCaptureResampler16, mCaptureResampler16,
mCaptureResampler32, mCaptureResampler32,
mCaptureResampler48; mCaptureResampler48;
DtmfContext mDtmfContext; DtmfContext mDtmfContext;
char mReceiveBuffer[MAX_VALID_UDPPACKET_SIZE]; char mReceiveBuffer[MAX_VALID_UDPPACKET_SIZE];
struct struct
{ {
Audio::PWavFileWriter mStreamForRecordingIncoming, Audio::PWavFileWriter mStreamForRecordingIncoming,
mStreamForRecordingOutgoing; mStreamForRecordingOutgoing;
Audio::PWavFileReader mStreamForReadingIncoming, Audio::PWavFileReader mStreamForReadingIncoming,
mStreamForReadingOutgoing; mStreamForReadingOutgoing;
} mDumpStreams; } mDumpStreams;
Audio::PWavFileWriter mSendingDump; Audio::PWavFileWriter mSendingDump;
@ -106,7 +106,7 @@ namespace MT
Statistics* mFinalStatistics = nullptr; Statistics* mFinalStatistics = nullptr;
bool decryptSrtp(void* data, int* len); bool decryptSrtp(void* data, int* len);
}; };
}; };
#endif #endif

View File

@ -40,7 +40,7 @@ PStream Terminal::createStream(int type, VariantMap& /*config*/)
switch (type) switch (type)
{ {
case Stream::Audio: case Stream::Audio:
result = PStream(new AudioStream(MT::CodecList::Settings::DefaultSettings)); result = std::make_shared<AudioStream>(MT::CodecList::Settings::DefaultSettings);
mAudioList.add(result); mAudioList.add(result);
break; break;

View File

@ -100,6 +100,7 @@ RTCPScheduler::~RTCPScheduler()
void RTCPScheduler::Reset() void RTCPScheduler::Reset()
{ {
pmembers = 0;
headeroverhead = 0; // user has to set this to an appropriate value headeroverhead = 0; // user has to set this to an appropriate value
hassentrtcp = false; hassentrtcp = false;
firstcall = true; firstcall = true;

View File

@ -900,9 +900,26 @@ void RTPExternalTransmitter::InjectRTPorRTCP(const void *data, size_t len, const
AbortWaitInternal(); AbortWaitInternal();
MAINMUTEX_UNLOCK MAINMUTEX_UNLOCK
} }
void RTPExternalTransmitter::InjectRaw(RTPRawPacket* packet)
{
if (!init)
return;
MAINMUTEX_LOCK
if (!created)
{
MAINMUTEX_UNLOCK
return;
}
rawpacketlist.push_back(packet);
AbortWaitInternal();
MAINMUTEX_UNLOCK
}
#ifdef RTPDEBUG #ifdef RTPDEBUG
void RTPExternalTransmitter::Dump() void RTPExternalTransmitter::Dump()
{ {

View File

@ -96,6 +96,8 @@ public:
/** Use this function to inject an RTP or RTCP packet and the transmitter will try to figure out which type of packet it is. */ /** Use this function to inject an RTP or RTCP packet and the transmitter will try to figure out which type of packet it is. */
void InjectRTPorRTCP(const void *data, size_t len, const RTPAddress &a); void InjectRTPorRTCP(const void *data, size_t len, const RTPAddress &a);
void InjectRaw(RTPRawPacket* packet);
private: private:
RTPExternalTransmitter *transmitter; RTPExternalTransmitter *transmitter;
}; };
@ -186,6 +188,8 @@ public:
void InjectRTP(const void *data, size_t len, const RTPAddress &a); void InjectRTP(const void *data, size_t len, const RTPAddress &a);
void InjectRTCP(const void *data, size_t len, const RTPAddress &a); void InjectRTCP(const void *data, size_t len, const RTPAddress &a);
void InjectRTPorRTCP(const void *data, size_t len, const RTPAddress &a); void InjectRTPorRTCP(const void *data, size_t len, const RTPAddress &a);
void InjectRaw(RTPRawPacket* packet);
private: private:
void FlushPackets(); void FlushPackets();
@ -233,6 +237,11 @@ inline void RTPExternalPacketInjecter::InjectRTPorRTCP(const void *data, size_t
transmitter->InjectRTPorRTCP(data, len, a); transmitter->InjectRTPorRTCP(data, len, a);
} }
inline void RTPExternalPacketInjecter::InjectRaw(RTPRawPacket* packet)
{
transmitter->InjectRaw(packet);
}
} // end namespace } // end namespace
#endif // RTPTCPSOCKETTRANSMITTER_H #endif // RTPTCPSOCKETTRANSMITTER_H

View File

@ -54,13 +54,13 @@ class RTPKeyHashTable : public RTPMemoryObject
{ {
public: public:
RTPKeyHashTable(RTPMemoryManager *mgr = 0,int memtype = RTPMEM_TYPE_OTHER); RTPKeyHashTable(RTPMemoryManager *mgr = 0,int memtype = RTPMEM_TYPE_OTHER);
~RTPKeyHashTable() { Clear(); } ~RTPKeyHashTable() { Clear(); }
void GotoFirstElement() { curhashelem = firsthashelem; } void GotoFirstElement() { curhashelem = firsthashelem; }
void GotoLastElement() { curhashelem = lasthashelem; } void GotoLastElement() { curhashelem = lasthashelem; }
bool HasCurrentElement() { return (curhashelem == 0)?false:true; } bool HasCurrentElement() { return (curhashelem == 0)?false:true; }
int DeleteCurrentElement(); int DeleteCurrentElement();
Element &GetCurrentElement() { return curhashelem->GetElement(); } Element &GetCurrentElement() { return curhashelem->GetElement(); }
Key &GetCurrentKey() { return curhashelem->GetKey(); } Key &GetCurrentKey() { return curhashelem->GetKey(); }
int GotoElement(const Key &k); int GotoElement(const Key &k);
bool HasElement(const Key &k); bool HasElement(const Key &k);

View File

@ -80,7 +80,7 @@ public:
bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void *extensiondata, bool gotextension,uint16_t extensionid,uint16_t extensionlen_numwords,const void *extensiondata,
void *buffer,size_t buffersize,RTPMemoryManager *mgr = 0); void *buffer,size_t buffersize,RTPMemoryManager *mgr = 0);
virtual ~RTPPacket(); virtual ~RTPPacket();
/** If an error occurred in one of the constructors, this function returns the error code. */ /** If an error occurred in one of the constructors, this function returns the error code. */
int GetCreationError() const { return error; } int GetCreationError() const { return error; }

View File

@ -1444,8 +1444,8 @@ int RTPSession::ProcessPolledData()
RTPTime colltimeout = RTPTime(Td*collisionmultiplier); RTPTime colltimeout = RTPTime(Td*collisionmultiplier);
RTPTime notetimeout = RTPTime(Td*notemultiplier); RTPTime notetimeout = RTPTime(Td*notemultiplier);
sources.MultipleTimeouts(t,sendertimeout,byetimeout,generaltimeout,notetimeout); // sources.MultipleTimeouts(t,sendertimeout,byetimeout,generaltimeout,notetimeout);
collisionlist.Timeout(t,colltimeout); // collisionlist.Timeout(t,colltimeout);
// We'll check if it's time for RTCP stuff // We'll check if it's time for RTCP stuff

View File

@ -55,6 +55,8 @@
#include <jthread/jmutex.h> #include <jthread/jmutex.h>
#endif // RTP_SUPPORT_THREAD #endif // RTP_SUPPORT_THREAD
#include <iostream>
namespace jrtplib namespace jrtplib
{ {
@ -474,7 +476,11 @@ protected:
const uint8_t *cname,size_t cnamelength) { } const uint8_t *cname,size_t cnamelength) { }
/** Is called when a new entry \c srcdat is added to the source table. */ /** Is called when a new entry \c srcdat is added to the source table. */
virtual void OnNewSource(RTPSourceData *srcdat) { } virtual void OnNewSource(RTPSourceData *srcdat)
{
// Sync timestamp unit
srcdat->SetTimestampUnit(timestampunit);
}
/** Is called when the entry \c srcdat is about to be deleted from the source table. */ /** Is called when the entry \c srcdat is about to be deleted from the source table. */
virtual void OnRemoveSource(RTPSourceData *srcdat) { } virtual void OnRemoveSource(RTPSourceData *srcdat) { }

View File

@ -35,462 +35,462 @@
#include "rtpaddress.h" #include "rtpaddress.h"
#include "rtpmemorymanager.h" #include "rtpmemorymanager.h"
#if ! (defined(WIN32) || defined(_WIN32_WCE)) #if ! (defined(WIN32) || defined(_WIN32_WCE))
#include <netinet/in.h> #include <netinet/in.h>
#endif // WIN32 #endif // WIN32
#ifdef RTPDEBUG #ifdef RTPDEBUG
#include <iostream> #include <iostream>
#include <string> #include <string>
#endif // RTPDEBUG #endif // RTPDEBUG
#include "rtpdebug.h" #include "rtpdebug.h"
#define ACCEPTPACKETCODE \ #define ACCEPTPACKETCODE \
*accept = true; \ *accept = true; \
\ \
sentdata = true; \ sentdata = true; \
packetsreceived++; \ packetsreceived++; \
numnewpackets++; \ numnewpackets++; \
\ \
if (pack->GetExtendedSequenceNumber() == 0) \ if (pack->GetExtendedSequenceNumber() == 0) \
{ \ { \
baseseqnr = 0x0000FFFF; \ baseseqnr = 0x0000FFFF; \
numcycles = 0x00010000; \ numcycles = 0x00010000; \
} \ } \
else \ else \
baseseqnr = pack->GetExtendedSequenceNumber() - 1; \ baseseqnr = pack->GetExtendedSequenceNumber() - 1; \
\ \
exthighseqnr = baseseqnr + 1; \ exthighseqnr = baseseqnr + 1; \
prevpacktime = receivetime; \ prevpacktime = receivetime; \
prevexthighseqnr = baseseqnr; \ prevexthighseqnr = baseseqnr; \
savedextseqnr = baseseqnr; \ savedextseqnr = baseseqnr; \
\ \
pack->SetExtendedSequenceNumber(exthighseqnr); \ pack->SetExtendedSequenceNumber(exthighseqnr); \
\ \
prevtimestamp = pack->GetTimestamp(); \ prevtimestamp = pack->GetTimestamp(); \
lastmsgtime = prevpacktime; \ lastmsgtime = prevpacktime; \
if (!ownpacket) /* for own packet, this value is set on an outgoing packet */ \ if (!ownpacket) /* for own packet, this value is set on an outgoing packet */ \
lastrtptime = prevpacktime; lastrtptime = prevpacktime;
namespace jrtplib namespace jrtplib
{ {
void RTPSourceStats::ProcessPacket(RTPPacket *pack,const RTPTime &receivetime,double tsunit, void RTPSourceStats::ProcessPacket(RTPPacket *pack,const RTPTime &receivetime,double tsunit,
bool ownpacket,bool *accept,bool applyprobation,bool *onprobation) bool ownpacket, bool *accept, bool applyprobation, bool *onprobation)
{ {
// Note that the sequence number in the RTP packet is still just the // Note that the sequence number in the RTP packet is still just the
// 16 bit number contained in the RTP header // 16 bit number contained in the RTP header
*onprobation = false; *onprobation = false;
if (!sentdata) // no valid packets received yet if (!sentdata) // no valid packets received yet
{ {
#ifdef RTP_SUPPORT_PROBATION #ifdef RTP_SUPPORT_PROBATION
if (applyprobation) if (applyprobation)
{ {
bool acceptpack = false; bool acceptpack = false;
if (probation) if (probation)
{ {
uint16_t pseq; uint16_t pseq;
uint32_t pseq2; uint32_t pseq2;
pseq = prevseqnr; pseq = prevseqnr;
pseq++; pseq++;
pseq2 = (uint32_t)pseq; pseq2 = (uint32_t)pseq;
if (pseq2 == pack->GetExtendedSequenceNumber()) // ok, its the next expected packet if (pseq2 == pack->GetExtendedSequenceNumber()) // ok, its the next expected packet
{ {
prevseqnr = (uint16_t)pack->GetExtendedSequenceNumber(); prevseqnr = (uint16_t)pack->GetExtendedSequenceNumber();
probation--; probation--;
if (probation == 0) // probation over if (probation == 0) // probation over
acceptpack = true; acceptpack = true;
else else
*onprobation = true; *onprobation = true;
} }
else // not next packet else // not next packet
{ {
probation = RTP_PROBATIONCOUNT; probation = RTP_PROBATIONCOUNT;
prevseqnr = (uint16_t)pack->GetExtendedSequenceNumber(); prevseqnr = (uint16_t)pack->GetExtendedSequenceNumber();
*onprobation = true; *onprobation = true;
} }
} }
else // first packet received with this SSRC ID, start probation else // first packet received with this SSRC ID, start probation
{ {
probation = RTP_PROBATIONCOUNT; probation = RTP_PROBATIONCOUNT;
prevseqnr = (uint16_t)pack->GetExtendedSequenceNumber(); prevseqnr = (uint16_t)pack->GetExtendedSequenceNumber();
*onprobation = true; *onprobation = true;
} }
if (acceptpack) if (acceptpack)
{ {
ACCEPTPACKETCODE ACCEPTPACKETCODE
} }
else else
{ {
*accept = false; *accept = false;
lastmsgtime = receivetime; lastmsgtime = receivetime;
} }
} }
else // No probation else // No probation
{ {
ACCEPTPACKETCODE ACCEPTPACKETCODE
} }
#else // No compiled-in probation support #else // No compiled-in probation support
ACCEPTPACKETCODE ACCEPTPACKETCODE
#endif // RTP_SUPPORT_PROBATION #endif // RTP_SUPPORT_PROBATION
} }
else // already got packets else // already got packets
{ {
uint16_t maxseq16; uint16_t maxseq16;
uint32_t extseqnr; uint32_t extseqnr;
// Adjust max extended sequence number and set extende seq nr of packet // Adjust max extended sequence number and set extende seq nr of packet
*accept = true; *accept = true;
packetsreceived++; packetsreceived++;
numnewpackets++; numnewpackets++;
maxseq16 = (uint16_t)(exthighseqnr&0x0000FFFF); maxseq16 = (uint16_t)(exthighseqnr&0x0000FFFF);
if (pack->GetExtendedSequenceNumber() >= maxseq16) if (pack->GetExtendedSequenceNumber() >= maxseq16)
{ {
extseqnr = numcycles+pack->GetExtendedSequenceNumber(); extseqnr = numcycles+pack->GetExtendedSequenceNumber();
exthighseqnr = extseqnr; exthighseqnr = extseqnr;
} }
else else
{ {
uint16_t dif1,dif2; uint16_t dif1,dif2;
dif1 = ((uint16_t)pack->GetExtendedSequenceNumber()); dif1 = ((uint16_t)pack->GetExtendedSequenceNumber());
dif1 -= maxseq16; dif1 -= maxseq16;
dif2 = maxseq16; dif2 = maxseq16;
dif2 -= ((uint16_t)pack->GetExtendedSequenceNumber()); dif2 -= ((uint16_t)pack->GetExtendedSequenceNumber());
if (dif1 < dif2) if (dif1 < dif2)
{ {
numcycles += 0x00010000; numcycles += 0x00010000;
extseqnr = numcycles+pack->GetExtendedSequenceNumber(); extseqnr = numcycles+pack->GetExtendedSequenceNumber();
exthighseqnr = extseqnr; exthighseqnr = extseqnr;
} }
else else
extseqnr = numcycles+pack->GetExtendedSequenceNumber(); extseqnr = numcycles+pack->GetExtendedSequenceNumber();
} }
pack->SetExtendedSequenceNumber(extseqnr); pack->SetExtendedSequenceNumber(extseqnr);
// Calculate jitter // Calculate jitter
if (tsunit > 0) if (tsunit > 0)
{ {
#if 0 #if 0
RTPTime curtime = receivetime; RTPTime curtime = receivetime;
double diffts1,diffts2,diff; double diffts1,diffts2,diff;
curtime -= prevpacktime; curtime -= prevpacktime;
diffts1 = curtime.GetDouble()/tsunit; diffts1 = curtime.GetDouble()/tsunit;
diffts2 = (double)pack->GetTimestamp() - (double)prevtimestamp; diffts2 = (double)pack->GetTimestamp() - (double)prevtimestamp;
diff = diffts1 - diffts2; diff = diffts1 - diffts2;
if (diff < 0) if (diff < 0)
diff = -diff; diff = -diff;
diff -= djitter; diff -= djitter;
diff /= 16.0; diff /= 16.0;
djitter += diff; djitter += diff;
jitter = (uint32_t)djitter; jitter = (uint32_t)djitter;
#else #else
RTPTime curtime = receivetime; RTPTime curtime = receivetime;
double diffts1,diffts2,diff; double diffts1,diffts2,diff;
uint32_t curts = pack->GetTimestamp(); uint32_t curts = pack->GetTimestamp();
curtime -= prevpacktime; curtime -= prevpacktime;
diffts1 = curtime.GetDouble()/tsunit; diffts1 = curtime.GetDouble() / tsunit;
if (curts > prevtimestamp) if (curts > prevtimestamp)
{ {
uint32_t unsigneddiff = curts - prevtimestamp; uint32_t unsigneddiff = curts - prevtimestamp;
if (unsigneddiff < 0x10000000) // okay, curts realy is larger than prevtimestamp if (unsigneddiff < 0x10000000) // okay, curts realy is larger than prevtimestamp
diffts2 = (double)unsigneddiff; diffts2 = (double)unsigneddiff;
else else
{ {
// wraparound occurred and curts is actually smaller than prevtimestamp // wraparound occurred and curts is actually smaller than prevtimestamp
unsigneddiff = -unsigneddiff; // to get the actual difference (in absolute value) unsigneddiff = -unsigneddiff; // to get the actual difference (in absolute value)
diffts2 = -((double)unsigneddiff); diffts2 = -((double)unsigneddiff);
} }
} }
else if (curts < prevtimestamp) else if (curts < prevtimestamp)
{ {
uint32_t unsigneddiff = prevtimestamp - curts; uint32_t unsigneddiff = prevtimestamp - curts;
if (unsigneddiff < 0x10000000) // okay, curts really is smaller than prevtimestamp if (unsigneddiff < 0x10000000) // okay, curts really is smaller than prevtimestamp
diffts2 = -((double)unsigneddiff); // negative since we actually need curts-prevtimestamp diffts2 = -((double)unsigneddiff); // negative since we actually need curts-prevtimestamp
else else
{ {
// wraparound occurred and curts is actually larger than prevtimestamp // wraparound occurred and curts is actually larger than prevtimestamp
unsigneddiff = -unsigneddiff; // to get the actual difference (in absolute value) unsigneddiff = -unsigneddiff; // to get the actual difference (in absolute value)
diffts2 = (double)unsigneddiff; diffts2 = (double)unsigneddiff;
} }
} }
else else
diffts2 = 0; diffts2 = 0;
diff = diffts1 - diffts2; diff = diffts1 - diffts2;
if (diff < 0) if (diff < 0)
diff = -diff; diff = -diff;
diff -= djitter; diff -= djitter;
diff /= 16.0; diff /= 16.0;
djitter += diff; djitter += diff;
jitter = (uint32_t)djitter; jitter = (uint32_t)djitter;
#endif #endif
} }
else else
{ {
djitter = 0; djitter = 0;
jitter = 0; jitter = 0;
} }
prevpacktime = receivetime; prevpacktime = receivetime;
prevtimestamp = pack->GetTimestamp(); prevtimestamp = pack->GetTimestamp();
lastmsgtime = prevpacktime; lastmsgtime = prevpacktime;
if (!ownpacket) // for own packet, this value is set on an outgoing packet if (!ownpacket) // for own packet, this value is set on an outgoing packet
lastrtptime = prevpacktime; lastrtptime = prevpacktime;
} }
} }
RTPSourceData::RTPSourceData(uint32_t s, RTPMemoryManager *mgr) : RTPMemoryObject(mgr),SDESinf(mgr),byetime(0,0) RTPSourceData::RTPSourceData(uint32_t s, RTPMemoryManager *mgr) : RTPMemoryObject(mgr),SDESinf(mgr),byetime(0,0)
{ {
ssrc = s; ssrc = s;
issender = false; issender = false;
iscsrc = false; iscsrc = false;
timestampunit = -1; timestampunit = -1;
receivedbye = false; receivedbye = false;
byereason = 0; byereason = 0;
byereasonlen = 0; byereasonlen = 0;
rtpaddr = 0; rtpaddr = 0;
rtcpaddr = 0; rtcpaddr = 0;
ownssrc = false; ownssrc = false;
validated = false; validated = false;
processedinrtcp = false; processedinrtcp = false;
isrtpaddrset = false; isrtpaddrset = false;
isrtcpaddrset = false; isrtcpaddrset = false;
} }
RTPSourceData::~RTPSourceData() RTPSourceData::~RTPSourceData()
{ {
FlushPackets(); FlushPackets();
if (byereason) if (byereason)
RTPDeleteByteArray(byereason,GetMemoryManager()); RTPDeleteByteArray(byereason,GetMemoryManager());
if (rtpaddr) if (rtpaddr)
RTPDelete(rtpaddr,GetMemoryManager()); RTPDelete(rtpaddr,GetMemoryManager());
if (rtcpaddr) if (rtcpaddr)
RTPDelete(rtcpaddr,GetMemoryManager()); RTPDelete(rtcpaddr,GetMemoryManager());
} }
double RTPSourceData::INF_GetEstimatedTimestampUnit() const double RTPSourceData::INF_GetEstimatedTimestampUnit() const
{ {
if (!SRprevinf.HasInfo()) if (!SRprevinf.HasInfo())
return -1.0; return -1.0;
RTPTime t1 = RTPTime(SRinf.GetNTPTimestamp()); RTPTime t1 = RTPTime(SRinf.GetNTPTimestamp());
RTPTime t2 = RTPTime(SRprevinf.GetNTPTimestamp()); RTPTime t2 = RTPTime(SRprevinf.GetNTPTimestamp());
if ((t1.GetSeconds() == 0 && t1.GetMicroSeconds() == 0) || if ((t1.GetSeconds() == 0 && t1.GetMicroSeconds() == 0) ||
(t2.GetSeconds() == 0 && t2.GetMicroSeconds() == 0)) // one of the times couldn't be calculated (t2.GetSeconds() == 0 && t2.GetMicroSeconds() == 0)) // one of the times couldn't be calculated
return -1.0; return -1.0;
if (t1 <= t2) if (t1 <= t2)
return -1.0; return -1.0;
t1 -= t2; // get the time difference t1 -= t2; // get the time difference
uint32_t tsdiff = SRinf.GetRTPTimestamp()-SRprevinf.GetRTPTimestamp(); uint32_t tsdiff = SRinf.GetRTPTimestamp()-SRprevinf.GetRTPTimestamp();
return (t1.GetDouble()/((double)tsdiff)); return (t1.GetDouble()/((double)tsdiff));
} }
RTPTime RTPSourceData::INF_GetRoundtripTime() const RTPTime RTPSourceData::INF_GetRoundtripTime() const
{ {
if (!RRinf.HasInfo()) if (!RRinf.HasInfo())
return RTPTime(0,0); return RTPTime(0,0);
if (RRinf.GetDelaySinceLastSR() == 0 && RRinf.GetLastSRTimestamp() == 0) if (RRinf.GetDelaySinceLastSR() == 0 && RRinf.GetLastSRTimestamp() == 0)
return RTPTime(0,0); return RTPTime(0,0);
RTPNTPTime recvtime = RRinf.GetReceiveTime().GetNTPTime(); RTPNTPTime recvtime = RRinf.GetReceiveTime().GetNTPTime();
uint32_t rtt = ((recvtime.GetMSW()&0xFFFF)<<16)|((recvtime.GetLSW()>>16)&0xFFFF); uint32_t rtt = ((recvtime.GetMSW()&0xFFFF)<<16)|((recvtime.GetLSW()>>16)&0xFFFF);
rtt -= RRinf.GetLastSRTimestamp(); rtt -= RRinf.GetLastSRTimestamp();
rtt -= RRinf.GetDelaySinceLastSR(); rtt -= RRinf.GetDelaySinceLastSR();
double drtt = (((double)rtt)/65536.0); double drtt = (((double)rtt)/65536.0);
return RTPTime(drtt); return RTPTime(drtt);
} }
#ifdef RTPDEBUG #ifdef RTPDEBUG
void RTPSourceData::Dump() void RTPSourceData::Dump()
{ {
std::cout << "Source data for SSRC: " << ssrc << std::endl; std::cout << "Source data for SSRC: " << ssrc << std::endl;
std::cout << " Active: " << ((IsActive())?"Yes":"No") << std::endl; std::cout << " Active: " << ((IsActive())?"Yes":"No") << std::endl;
std::cout << " Sender: " << ((issender)?"Yes":"No") << std::endl; std::cout << " Sender: " << ((issender)?"Yes":"No") << std::endl;
std::cout << " CSRC: " << ((iscsrc)?"Yes":"No") << std::endl; std::cout << " CSRC: " << ((iscsrc)?"Yes":"No") << std::endl;
std::cout << " Received bye: " << ((receivedbye)?"Yes":"No") << std::endl; std::cout << " Received bye: " << ((receivedbye)?"Yes":"No") << std::endl;
std::cout << " ProcessedInRTCP: " << ((processedinrtcp)?"Yes":"No") << std::endl; std::cout << " ProcessedInRTCP: " << ((processedinrtcp)?"Yes":"No") << std::endl;
std::cout << " Timestamp unit: " << timestampunit << std::endl; std::cout << " Timestamp unit: " << timestampunit << std::endl;
std::cout << " RTP address: "; std::cout << " RTP address: ";
if (!isrtpaddrset) if (!isrtpaddrset)
std::cout << "Not set" << std::endl; std::cout << "Not set" << std::endl;
else else
{ {
if (rtpaddr == 0) if (rtpaddr == 0)
std::cout << "Own session" << std::endl; std::cout << "Own session" << std::endl;
else else
std::cout << rtpaddr->GetAddressString() << std::endl; std::cout << rtpaddr->GetAddressString() << std::endl;
} }
std::cout << " RTCP address: "; std::cout << " RTCP address: ";
if (!isrtcpaddrset) if (!isrtcpaddrset)
std::cout << "Not set" << std::endl; std::cout << "Not set" << std::endl;
else else
{ {
if (rtcpaddr == 0) if (rtcpaddr == 0)
std::cout << "Own session" << std::endl; std::cout << "Own session" << std::endl;
else else
std::cout << rtcpaddr->GetAddressString() << std::endl; std::cout << rtcpaddr->GetAddressString() << std::endl;
} }
if (SRinf.HasInfo()) if (SRinf.HasInfo())
{ {
if (!SRprevinf.HasInfo()) if (!SRprevinf.HasInfo())
{ {
std::cout << " SR Info:" << std::endl; std::cout << " SR Info:" << std::endl;
std::cout << " NTP timestamp: " << SRinf.GetNTPTimestamp().GetMSW() << ":" << SRinf.GetNTPTimestamp().GetLSW() << std::endl; std::cout << " NTP timestamp: " << SRinf.GetNTPTimestamp().GetMSW() << ":" << SRinf.GetNTPTimestamp().GetLSW() << std::endl;
std::cout << " RTP timestamp: " << SRinf.GetRTPTimestamp() << std::endl; std::cout << " RTP timestamp: " << SRinf.GetRTPTimestamp() << std::endl;
std::cout << " Packet count: " << SRinf.GetPacketCount() << std::endl; std::cout << " Packet count: " << SRinf.GetPacketCount() << std::endl;
std::cout << " Octet count: " << SRinf.GetByteCount() << std::endl; std::cout << " Octet count: " << SRinf.GetByteCount() << std::endl;
std::cout << " Receive time: " << SRinf.GetReceiveTime().GetSeconds() << std::endl; std::cout << " Receive time: " << SRinf.GetReceiveTime().GetSeconds() << std::endl;
} }
else else
{ {
std::cout << " SR Info:" << std::endl; std::cout << " SR Info:" << std::endl;
std::cout << " NTP timestamp: " << SRinf.GetNTPTimestamp().GetMSW() << ":" << SRinf.GetNTPTimestamp().GetLSW() std::cout << " NTP timestamp: " << SRinf.GetNTPTimestamp().GetMSW() << ":" << SRinf.GetNTPTimestamp().GetLSW()
<< " (" << SRprevinf.GetNTPTimestamp().GetMSW() << ":" << SRprevinf.GetNTPTimestamp().GetLSW() << ")" << std::endl; << " (" << SRprevinf.GetNTPTimestamp().GetMSW() << ":" << SRprevinf.GetNTPTimestamp().GetLSW() << ")" << std::endl;
std::cout << " RTP timestamp: " << SRinf.GetRTPTimestamp() std::cout << " RTP timestamp: " << SRinf.GetRTPTimestamp()
<< " (" << SRprevinf.GetRTPTimestamp() << ")" << std::endl; << " (" << SRprevinf.GetRTPTimestamp() << ")" << std::endl;
std::cout << " Packet count: " << SRinf.GetPacketCount() std::cout << " Packet count: " << SRinf.GetPacketCount()
<< " (" << SRprevinf.GetPacketCount() << ")" << std::endl; << " (" << SRprevinf.GetPacketCount() << ")" << std::endl;
std::cout << " Octet count: " << SRinf.GetByteCount() std::cout << " Octet count: " << SRinf.GetByteCount()
<< " (" << SRprevinf.GetByteCount() <<")" << std::endl; << " (" << SRprevinf.GetByteCount() <<")" << std::endl;
std::cout << " Receive time: " << SRinf.GetReceiveTime().GetSeconds() std::cout << " Receive time: " << SRinf.GetReceiveTime().GetSeconds()
<< " (" << SRprevinf.GetReceiveTime().GetSeconds() << ")" << std::endl; << " (" << SRprevinf.GetReceiveTime().GetSeconds() << ")" << std::endl;
} }
} }
if (RRinf.HasInfo()) if (RRinf.HasInfo())
{ {
if (!RRprevinf.HasInfo()) if (!RRprevinf.HasInfo())
{ {
std::cout << " RR Info:" << std::endl; std::cout << " RR Info:" << std::endl;
std::cout << " Fraction lost: " << RRinf.GetFractionLost() << std::endl; std::cout << " Fraction lost: " << RRinf.GetFractionLost() << std::endl;
std::cout << " Packets lost: " << RRinf.GetPacketsLost() << std::endl; std::cout << " Packets lost: " << RRinf.GetPacketsLost() << std::endl;
std::cout << " Ext.High.Seq: " << RRinf.GetExtendedHighestSequenceNumber() << std::endl; std::cout << " Ext.High.Seq: " << RRinf.GetExtendedHighestSequenceNumber() << std::endl;
std::cout << " Jitter: " << RRinf.GetJitter() << std::endl; std::cout << " Jitter: " << RRinf.GetJitter() << std::endl;
std::cout << " LSR: " << RRinf.GetLastSRTimestamp() << std::endl; std::cout << " LSR: " << RRinf.GetLastSRTimestamp() << std::endl;
std::cout << " DLSR: " << RRinf.GetDelaySinceLastSR() << std::endl; std::cout << " DLSR: " << RRinf.GetDelaySinceLastSR() << std::endl;
std::cout << " Receive time: " << RRinf.GetReceiveTime().GetSeconds() << std::endl; std::cout << " Receive time: " << RRinf.GetReceiveTime().GetSeconds() << std::endl;
} }
else else
{ {
std::cout << " RR Info:" << std::endl; std::cout << " RR Info:" << std::endl;
std::cout << " Fraction lost: " << RRinf.GetFractionLost() std::cout << " Fraction lost: " << RRinf.GetFractionLost()
<< " (" << RRprevinf.GetFractionLost() << ")" << std::endl; << " (" << RRprevinf.GetFractionLost() << ")" << std::endl;
std::cout << " Packets lost: " << RRinf.GetPacketsLost() std::cout << " Packets lost: " << RRinf.GetPacketsLost()
<< " (" << RRprevinf.GetPacketsLost() << ")" << std::endl; << " (" << RRprevinf.GetPacketsLost() << ")" << std::endl;
std::cout << " Ext.High.Seq: " << RRinf.GetExtendedHighestSequenceNumber() std::cout << " Ext.High.Seq: " << RRinf.GetExtendedHighestSequenceNumber()
<< " (" << RRprevinf.GetExtendedHighestSequenceNumber() << ")" << std::endl; << " (" << RRprevinf.GetExtendedHighestSequenceNumber() << ")" << std::endl;
std::cout << " Jitter: " << RRinf.GetJitter() std::cout << " Jitter: " << RRinf.GetJitter()
<< " (" << RRprevinf.GetJitter() << ")" << std::endl; << " (" << RRprevinf.GetJitter() << ")" << std::endl;
std::cout << " LSR: " << RRinf.GetLastSRTimestamp() std::cout << " LSR: " << RRinf.GetLastSRTimestamp()
<< " (" << RRprevinf.GetLastSRTimestamp() << ")" << std::endl; << " (" << RRprevinf.GetLastSRTimestamp() << ")" << std::endl;
std::cout << " DLSR: " << RRinf.GetDelaySinceLastSR() std::cout << " DLSR: " << RRinf.GetDelaySinceLastSR()
<< " (" << RRprevinf.GetDelaySinceLastSR() << ")" << std::endl; << " (" << RRprevinf.GetDelaySinceLastSR() << ")" << std::endl;
std::cout << " Receive time: " << RRinf.GetReceiveTime().GetSeconds() std::cout << " Receive time: " << RRinf.GetReceiveTime().GetSeconds()
<< " (" << RRprevinf.GetReceiveTime().GetSeconds() <<")" << std::endl; << " (" << RRprevinf.GetReceiveTime().GetSeconds() <<")" << std::endl;
} }
} }
std::cout << " Stats:" << std::endl; std::cout << " Stats:" << std::endl;
std::cout << " Sent data: " << ((stats.HasSentData())?"Yes":"No") << std::endl; std::cout << " Sent data: " << ((stats.HasSentData())?"Yes":"No") << std::endl;
std::cout << " Packets received: " << stats.GetNumPacketsReceived() << std::endl; std::cout << " Packets received: " << stats.GetNumPacketsReceived() << std::endl;
std::cout << " Seq. base: " << stats.GetBaseSequenceNumber() << std::endl; std::cout << " Seq. base: " << stats.GetBaseSequenceNumber() << std::endl;
std::cout << " Ext.High.Seq: " << stats.GetExtendedHighestSequenceNumber() << std::endl; std::cout << " Ext.High.Seq: " << stats.GetExtendedHighestSequenceNumber() << std::endl;
std::cout << " Jitter: " << stats.GetJitter() << std::endl; std::cout << " Jitter: " << stats.GetJitter() << std::endl;
std::cout << " New packets: " << stats.GetNumPacketsReceivedInInterval() << std::endl; std::cout << " New packets: " << stats.GetNumPacketsReceivedInInterval() << std::endl;
std::cout << " Saved seq. nr.: " << stats.GetSavedExtendedSequenceNumber() << std::endl; std::cout << " Saved seq. nr.: " << stats.GetSavedExtendedSequenceNumber() << std::endl;
std::cout << " RTT: " << INF_GetRoundtripTime().GetDouble() << " seconds" << std::endl; std::cout << " RTT: " << INF_GetRoundtripTime().GetDouble() << " seconds" << std::endl;
if (INF_GetEstimatedTimestampUnit() > 0) if (INF_GetEstimatedTimestampUnit() > 0)
std::cout << " Estimated: " << (1.0/INF_GetEstimatedTimestampUnit()) << " samples per second" << std::endl; std::cout << " Estimated: " << (1.0/INF_GetEstimatedTimestampUnit()) << " samples per second" << std::endl;
std::cout << " SDES Info:" << std::endl; std::cout << " SDES Info:" << std::endl;
size_t len; size_t len;
char str[1024]; char str[1024];
uint8_t *val; uint8_t *val;
if ((val = SDESinf.GetCNAME(&len)) != 0) if ((val = SDESinf.GetCNAME(&len)) != 0)
{ {
memcpy(str,val,len); memcpy(str,val,len);
str[len] = 0; str[len] = 0;
std::cout << " CNAME: " << std::string(str) << std::endl; std::cout << " CNAME: " << std::string(str) << std::endl;
} }
if ((val = SDESinf.GetName(&len)) != 0) if ((val = SDESinf.GetName(&len)) != 0)
{ {
memcpy(str,val,len); memcpy(str,val,len);
str[len] = 0; str[len] = 0;
std::cout << " Name: " << std::string(str) << std::endl; std::cout << " Name: " << std::string(str) << std::endl;
} }
if ((val = SDESinf.GetEMail(&len)) != 0) if ((val = SDESinf.GetEMail(&len)) != 0)
{ {
memcpy(str,val,len); memcpy(str,val,len);
str[len] = 0; str[len] = 0;
std::cout << " EMail: " << std::string(str) << std::endl; std::cout << " EMail: " << std::string(str) << std::endl;
} }
if ((val = SDESinf.GetPhone(&len)) != 0) if ((val = SDESinf.GetPhone(&len)) != 0)
{ {
memcpy(str,val,len); memcpy(str,val,len);
str[len] = 0; str[len] = 0;
std::cout << " phone: " << std::string(str) << std::endl; std::cout << " phone: " << std::string(str) << std::endl;
} }
if ((val = SDESinf.GetLocation(&len)) != 0) if ((val = SDESinf.GetLocation(&len)) != 0)
{ {
memcpy(str,val,len); memcpy(str,val,len);
str[len] = 0; str[len] = 0;
std::cout << " Location: " << std::string(str) << std::endl; std::cout << " Location: " << std::string(str) << std::endl;
} }
if ((val = SDESinf.GetTool(&len)) != 0) if ((val = SDESinf.GetTool(&len)) != 0)
{ {
memcpy(str,val,len); memcpy(str,val,len);
str[len] = 0; str[len] = 0;
std::cout << " Tool: " << std::string(str) << std::endl; std::cout << " Tool: " << std::string(str) << std::endl;
} }
if ((val = SDESinf.GetNote(&len)) != 0) if ((val = SDESinf.GetNote(&len)) != 0)
{ {
memcpy(str,val,len); memcpy(str,val,len);
str[len] = 0; str[len] = 0;
std::cout << " Note: " << std::string(str) << std::endl; std::cout << " Note: " << std::string(str) << std::endl;
} }
#ifdef RTP_SUPPORT_SDESPRIV #ifdef RTP_SUPPORT_SDESPRIV
SDESinf.GotoFirstPrivateValue(); SDESinf.GotoFirstPrivateValue();
uint8_t *pref; uint8_t *pref;
size_t preflen; size_t preflen;
while (SDESinf.GetNextPrivateValue(&pref,&preflen,&val,&len)) while (SDESinf.GetNextPrivateValue(&pref,&preflen,&val,&len))
{ {
char prefstr[1024]; char prefstr[1024];
memcpy(prefstr,pref,preflen); memcpy(prefstr,pref,preflen);
memcpy(str,val,len); memcpy(str,val,len);
prefstr[preflen] = 0; prefstr[preflen] = 0;
str[len] = 0; str[len] = 0;
std::cout << " Private: " << std::string(prefstr) << ":" << std::string(str) << std::endl; std::cout << " Private: " << std::string(prefstr) << ":" << std::string(str) << std::endl;
} }
#endif // RTP_SUPPORT_SDESPRIV #endif // RTP_SUPPORT_SDESPRIV
if (byereason) if (byereason)
{ {
memcpy(str,byereason,byereasonlen); memcpy(str,byereason,byereasonlen);
str[byereasonlen] = 0; str[byereasonlen] = 0;
std::cout << " BYE Reason: " << std::string(str) << std::endl; std::cout << " BYE Reason: " << std::string(str) << std::endl;
} }
} }
#endif // RTPDEBUG #endif // RTPDEBUG

View File

@ -55,111 +55,111 @@ class RTPAddress;
class JRTPLIB_IMPORTEXPORT RTCPSenderReportInfo class JRTPLIB_IMPORTEXPORT RTCPSenderReportInfo
{ {
public: public:
RTCPSenderReportInfo():ntptimestamp(0,0),receivetime(0,0) { hasinfo = false; rtptimestamp = 0; packetcount = 0; bytecount = 0; } RTCPSenderReportInfo():ntptimestamp(0,0),receivetime(0,0) { hasinfo = false; rtptimestamp = 0; packetcount = 0; bytecount = 0; }
void Set(const RTPNTPTime &ntptime,uint32_t rtptime,uint32_t pcount, void Set(const RTPNTPTime &ntptime,uint32_t rtptime,uint32_t pcount,
uint32_t bcount,const RTPTime &rcvtime) { ntptimestamp = ntptime; rtptimestamp = rtptime; packetcount = pcount; bytecount = bcount; receivetime = rcvtime; hasinfo = true; } uint32_t bcount,const RTPTime &rcvtime) { ntptimestamp = ntptime; rtptimestamp = rtptime; packetcount = pcount; bytecount = bcount; receivetime = rcvtime; hasinfo = true; }
bool HasInfo() const { return hasinfo; } bool HasInfo() const { return hasinfo; }
RTPNTPTime GetNTPTimestamp() const { return ntptimestamp; } RTPNTPTime GetNTPTimestamp() const { return ntptimestamp; }
uint32_t GetRTPTimestamp() const { return rtptimestamp; } uint32_t GetRTPTimestamp() const { return rtptimestamp; }
uint32_t GetPacketCount() const { return packetcount; } uint32_t GetPacketCount() const { return packetcount; }
uint32_t GetByteCount() const { return bytecount; } uint32_t GetByteCount() const { return bytecount; }
RTPTime GetReceiveTime() const { return receivetime; } RTPTime GetReceiveTime() const { return receivetime; }
private: private:
bool hasinfo; bool hasinfo;
RTPNTPTime ntptimestamp; RTPNTPTime ntptimestamp;
uint32_t rtptimestamp; uint32_t rtptimestamp;
uint32_t packetcount; uint32_t packetcount;
uint32_t bytecount; uint32_t bytecount;
RTPTime receivetime; RTPTime receivetime;
}; };
class JRTPLIB_IMPORTEXPORT RTCPReceiverReportInfo class JRTPLIB_IMPORTEXPORT RTCPReceiverReportInfo
{ {
public: public:
RTCPReceiverReportInfo():receivetime(0,0) { hasinfo = false; fractionlost = 0; packetslost = 0; exthighseqnr = 0; jitter = 0; lsr = 0; dlsr = 0; } RTCPReceiverReportInfo():receivetime(0,0) { hasinfo = false; fractionlost = 0; packetslost = 0; exthighseqnr = 0; jitter = 0; lsr = 0; dlsr = 0; }
void Set(uint8_t fraclost,int32_t plost,uint32_t exthigh, void Set(uint8_t fraclost,int32_t plost,uint32_t exthigh,
uint32_t jit,uint32_t l,uint32_t dl,const RTPTime &rcvtime) { fractionlost = ((double)fraclost)/256.0; packetslost = plost; exthighseqnr = exthigh; jitter = jit; lsr = l; dlsr = dl; receivetime = rcvtime; hasinfo = true; } uint32_t jit,uint32_t l,uint32_t dl,const RTPTime &rcvtime) { fractionlost = ((double)fraclost)/256.0; packetslost = plost; exthighseqnr = exthigh; jitter = jit; lsr = l; dlsr = dl; receivetime = rcvtime; hasinfo = true; }
bool HasInfo() const { return hasinfo; } bool HasInfo() const { return hasinfo; }
double GetFractionLost() const { return fractionlost; } double GetFractionLost() const { return fractionlost; }
int32_t GetPacketsLost() const { return packetslost; } int32_t GetPacketsLost() const { return packetslost; }
uint32_t GetExtendedHighestSequenceNumber() const { return exthighseqnr; } uint32_t GetExtendedHighestSequenceNumber() const { return exthighseqnr; }
uint32_t GetJitter() const { return jitter; } uint32_t GetJitter() const { return jitter; }
uint32_t GetLastSRTimestamp() const { return lsr; } uint32_t GetLastSRTimestamp() const { return lsr; }
uint32_t GetDelaySinceLastSR() const { return dlsr; } uint32_t GetDelaySinceLastSR() const { return dlsr; }
RTPTime GetReceiveTime() const { return receivetime; } RTPTime GetReceiveTime() const { return receivetime; }
private: private:
bool hasinfo; bool hasinfo;
double fractionlost; double fractionlost;
int32_t packetslost; int32_t packetslost;
uint32_t exthighseqnr; uint32_t exthighseqnr;
uint32_t jitter; uint32_t jitter;
uint32_t lsr; uint32_t lsr;
uint32_t dlsr; uint32_t dlsr;
RTPTime receivetime; RTPTime receivetime;
}; };
class JRTPLIB_IMPORTEXPORT RTPSourceStats class JRTPLIB_IMPORTEXPORT RTPSourceStats
{ {
public: public:
RTPSourceStats(); RTPSourceStats();
void ProcessPacket(RTPPacket *pack,const RTPTime &receivetime,double tsunit,bool ownpacket,bool *accept,bool applyprobation,bool *onprobation); void ProcessPacket(RTPPacket *pack,const RTPTime &receivetime,double tsunit,bool ownpacket,bool *accept,bool applyprobation,bool *onprobation);
bool HasSentData() const { return sentdata; } bool HasSentData() const { return sentdata; }
uint32_t GetNumPacketsReceived() const { return packetsreceived; } uint32_t GetNumPacketsReceived() const { return packetsreceived; }
uint32_t GetBaseSequenceNumber() const { return baseseqnr; } uint32_t GetBaseSequenceNumber() const { return baseseqnr; }
uint32_t GetExtendedHighestSequenceNumber() const { return exthighseqnr; } uint32_t GetExtendedHighestSequenceNumber() const { return exthighseqnr; }
uint32_t GetJitter() const { return jitter; } uint32_t GetJitter() const { return jitter; }
void ResetJitter() { jitter = 0; } void ResetJitter() { jitter = 0; }
int32_t GetNumPacketsReceivedInInterval() const { return numnewpackets; } int32_t GetNumPacketsReceivedInInterval() const { return numnewpackets; }
uint32_t GetSavedExtendedSequenceNumber() const { return savedextseqnr; } uint32_t GetSavedExtendedSequenceNumber() const { return savedextseqnr; }
void StartNewInterval() { numnewpackets = 0; savedextseqnr = exthighseqnr; } void StartNewInterval() { numnewpackets = 0; savedextseqnr = exthighseqnr; }
void SetLastMessageTime(const RTPTime &t) { lastmsgtime = t; } void SetLastMessageTime(const RTPTime &t) { lastmsgtime = t; }
RTPTime GetLastMessageTime() const { return lastmsgtime; } RTPTime GetLastMessageTime() const { return lastmsgtime; }
void SetLastRTPPacketTime(const RTPTime &t) { lastrtptime = t; } void SetLastRTPPacketTime(const RTPTime &t) { lastrtptime = t; }
RTPTime GetLastRTPPacketTime() const { return lastrtptime; } RTPTime GetLastRTPPacketTime() const { return lastrtptime; }
void SetLastNoteTime(const RTPTime &t) { lastnotetime = t; } void SetLastNoteTime(const RTPTime &t) { lastnotetime = t; }
RTPTime GetLastNoteTime() const { return lastnotetime; } RTPTime GetLastNoteTime() const { return lastnotetime; }
private: private:
bool sentdata; bool sentdata;
uint32_t packetsreceived; uint32_t packetsreceived;
uint32_t numcycles; // shifted left 16 bits uint32_t numcycles; // shifted left 16 bits
uint32_t baseseqnr; uint32_t baseseqnr;
uint32_t exthighseqnr,prevexthighseqnr; uint32_t exthighseqnr,prevexthighseqnr;
uint32_t jitter,prevtimestamp; uint32_t jitter,prevtimestamp;
double djitter; double djitter;
RTPTime prevpacktime; RTPTime prevpacktime;
RTPTime lastmsgtime; RTPTime lastmsgtime;
RTPTime lastrtptime; RTPTime lastrtptime;
RTPTime lastnotetime; RTPTime lastnotetime;
uint32_t numnewpackets; uint32_t numnewpackets;
uint32_t savedextseqnr; uint32_t savedextseqnr;
#ifdef RTP_SUPPORT_PROBATION #ifdef RTP_SUPPORT_PROBATION
uint16_t prevseqnr; uint16_t prevseqnr;
int probation; int probation;
RTPSources::ProbationType probationtype; RTPSources::ProbationType probationtype;
#endif // RTP_SUPPORT_PROBATION #endif // RTP_SUPPORT_PROBATION
}; };
inline RTPSourceStats::RTPSourceStats():prevpacktime(0,0),lastmsgtime(0,0),lastrtptime(0,0),lastnotetime(0,0) inline RTPSourceStats::RTPSourceStats():prevpacktime(0,0),lastmsgtime(0,0),lastrtptime(0,0),lastnotetime(0,0)
{ {
sentdata = false; sentdata = false;
packetsreceived = 0; packetsreceived = 0;
baseseqnr = 0; baseseqnr = 0;
exthighseqnr = 0; exthighseqnr = 0;
prevexthighseqnr = 0; prevexthighseqnr = 0;
jitter = 0; jitter = 0;
numcycles = 0; numcycles = 0;
numnewpackets = 0; numnewpackets = 0;
prevtimestamp = 0; prevtimestamp = 0;
djitter = 0; djitter = 0;
savedextseqnr = 0; savedextseqnr = 0;
#ifdef RTP_SUPPORT_PROBATION #ifdef RTP_SUPPORT_PROBATION
probation = 0; probation = 0;
prevseqnr = 0; prevseqnr = 0;
#endif // RTP_SUPPORT_PROBATION #endif // RTP_SUPPORT_PROBATION
} }
@ -167,311 +167,311 @@ inline RTPSourceStats::RTPSourceStats():prevpacktime(0,0),lastmsgtime(0,0),lastr
class JRTPLIB_IMPORTEXPORT RTPSourceData : public RTPMemoryObject class JRTPLIB_IMPORTEXPORT RTPSourceData : public RTPMemoryObject
{ {
protected: protected:
RTPSourceData(uint32_t ssrc, RTPMemoryManager *mgr = 0); RTPSourceData(uint32_t ssrc, RTPMemoryManager *mgr = 0);
virtual ~RTPSourceData(); virtual ~RTPSourceData();
public: public:
/** Extracts the first packet of this participants RTP packet queue. */ /** Extracts the first packet of this participants RTP packet queue. */
RTPPacket *GetNextPacket(); RTPPacket *GetNextPacket();
/** Clears the participant's RTP packet list. */ /** Clears the participant's RTP packet list. */
void FlushPackets(); void FlushPackets();
/** Returns \c true if there are RTP packets which can be extracted. */ /** Returns \c true if there are RTP packets which can be extracted. */
bool HasData() const { if (!validated) return false; return packetlist.empty()?false:true; } bool HasData() const { if (!validated) return false; return packetlist.empty()?false:true; }
/** Returns the SSRC identifier for this member. */ /** Returns the SSRC identifier for this member. */
uint32_t GetSSRC() const { return ssrc; } uint32_t GetSSRC() const { return ssrc; }
/** Returns \c true if the participant was added using the RTPSources member function CreateOwnSSRC and /** Returns \c true if the participant was added using the RTPSources member function CreateOwnSSRC and
* returns \c false otherwise. * returns \c false otherwise.
*/ */
bool IsOwnSSRC() const { return ownssrc; } bool IsOwnSSRC() const { return ownssrc; }
/** Returns \c true if the source identifier is actually a CSRC from an RTP packet. */ /** Returns \c true if the source identifier is actually a CSRC from an RTP packet. */
bool IsCSRC() const { return iscsrc; } bool IsCSRC() const { return iscsrc; }
/** Returns \c true if this member is marked as a sender and \c false if not. */ /** Returns \c true if this member is marked as a sender and \c false if not. */
bool IsSender() const { return issender; } bool IsSender() const { return issender; }
/** Returns \c true if the participant is validated, which is the case if a number of /** Returns \c true if the participant is validated, which is the case if a number of
* consecutive RTP packets have been received or if a CNAME item has been received for * consecutive RTP packets have been received or if a CNAME item has been received for
* this participant. * this participant.
*/ */
bool IsValidated() const { return validated; } bool IsValidated() const { return validated; }
/** Returns \c true if the source was validated and had not yet sent a BYE packet. */ /** Returns \c true if the source was validated and had not yet sent a BYE packet. */
bool IsActive() const { if (!validated) return false; if (receivedbye) return false; return true; } bool IsActive() const { if (!validated) return false; if (receivedbye) return false; return true; }
/** This function is used by the RTCPPacketBuilder class to mark whether this participant's /** This function is used by the RTCPPacketBuilder class to mark whether this participant's
* information has been processed in a report block or not. * information has been processed in a report block or not.
*/ */
void SetProcessedInRTCP(bool v) { processedinrtcp = v; } void SetProcessedInRTCP(bool v) { processedinrtcp = v; }
/** This function is used by the RTCPPacketBuilder class and returns whether this participant /** This function is used by the RTCPPacketBuilder class and returns whether this participant
* has been processed in a report block or not. * has been processed in a report block or not.
*/ */
bool IsProcessedInRTCP() const { return processedinrtcp; } bool IsProcessedInRTCP() const { return processedinrtcp; }
/** Returns \c true if the address from which this participant's RTP packets originate has /** Returns \c true if the address from which this participant's RTP packets originate has
* already been set. * already been set.
*/ */
bool IsRTPAddressSet() const { return isrtpaddrset; } bool IsRTPAddressSet() const { return isrtpaddrset; }
/** Returns \c true if the address from which this participant's RTCP packets originate has /** Returns \c true if the address from which this participant's RTCP packets originate has
* already been set. * already been set.
*/ */
bool IsRTCPAddressSet() const { return isrtcpaddrset; } bool IsRTCPAddressSet() const { return isrtcpaddrset; }
/** Returns the address from which this participant's RTP packets originate. /** Returns the address from which this participant's RTP packets originate.
* Returns the address from which this participant's RTP packets originate. If the address has * Returns the address from which this participant's RTP packets originate. If the address has
* been set and the returned value is NULL, this indicates that it originated from the local * been set and the returned value is NULL, this indicates that it originated from the local
* participant. * participant.
*/ */
const RTPAddress *GetRTPDataAddress() const { return rtpaddr; } const RTPAddress *GetRTPDataAddress() const { return rtpaddr; }
/** Returns the address from which this participant's RTCP packets originate. /** Returns the address from which this participant's RTCP packets originate.
* Returns the address from which this participant's RTCP packets originate. If the address has * Returns the address from which this participant's RTCP packets originate. If the address has
* been set and the returned value is NULL, this indicates that it originated from the local * been set and the returned value is NULL, this indicates that it originated from the local
* participant. * participant.
*/ */
const RTPAddress *GetRTCPDataAddress() const { return rtcpaddr; } const RTPAddress *GetRTCPDataAddress() const { return rtcpaddr; }
/** Returns \c true if we received a BYE message for this participant and \c false otherwise. */ /** Returns \c true if we received a BYE message for this participant and \c false otherwise. */
bool ReceivedBYE() const { return receivedbye; } bool ReceivedBYE() const { return receivedbye; }
/** Returns the reason for leaving contained in the BYE packet of this participant. /** Returns the reason for leaving contained in the BYE packet of this participant.
* Returns the reason for leaving contained in the BYE packet of this participant. The length of * Returns the reason for leaving contained in the BYE packet of this participant. The length of
* the reason is stored in \c len. * the reason is stored in \c len.
*/ */
uint8_t *GetBYEReason(size_t *len) const { *len = byereasonlen; return byereason; } uint8_t *GetBYEReason(size_t *len) const { *len = byereasonlen; return byereason; }
/** Returns the time at which the BYE packet was received. */ /** Returns the time at which the BYE packet was received. */
RTPTime GetBYETime() const { return byetime; } RTPTime GetBYETime() const { return byetime; }
/** Sets the value for the timestamp unit to be used in jitter calculations for data received from this participant. /** Sets the value for the timestamp unit to be used in jitter calculations for data received from this participant.
* Sets the value for the timestamp unit to be used in jitter calculations for data received from this participant. * Sets the value for the timestamp unit to be used in jitter calculations for data received from this participant.
* If not set, the library uses an approximation for the timestamp unit which is calculated from two consecutive * If not set, the library uses an approximation for the timestamp unit which is calculated from two consecutive
* RTCP sender reports. The timestamp unit is defined as a time interval divided by the corresponding timestamp * RTCP sender reports. The timestamp unit is defined as a time interval divided by the corresponding timestamp
* interval. For 8000 Hz audio this would be 1/8000. For video, often a timestamp unit of 1/90000 is used. * interval. For 8000 Hz audio this would be 1/8000. For video, often a timestamp unit of 1/90000 is used.
*/ */
void SetTimestampUnit(double tsu) { timestampunit = tsu; } void SetTimestampUnit(double tsu) { timestampunit = tsu; }
/** Returns the timestamp unit used for this participant. */ /** Returns the timestamp unit used for this participant. */
double GetTimestampUnit() const { return timestampunit; } double GetTimestampUnit() const { return timestampunit; }
/** Returns \c true if an RTCP sender report has been received from this participant. */ /** Returns \c true if an RTCP sender report has been received from this participant. */
bool SR_HasInfo() const { return SRinf.HasInfo(); } bool SR_HasInfo() const { return SRinf.HasInfo(); }
/** Returns the NTP timestamp contained in the last sender report. */ /** Returns the NTP timestamp contained in the last sender report. */
RTPNTPTime SR_GetNTPTimestamp() const { return SRinf.GetNTPTimestamp(); } RTPNTPTime SR_GetNTPTimestamp() const { return SRinf.GetNTPTimestamp(); }
/** Returns the RTP timestamp contained in the last sender report. */ /** Returns the RTP timestamp contained in the last sender report. */
uint32_t SR_GetRTPTimestamp() const { return SRinf.GetRTPTimestamp(); } uint32_t SR_GetRTPTimestamp() const { return SRinf.GetRTPTimestamp(); }
/** Returns the packet count contained in the last sender report. */ /** Returns the packet count contained in the last sender report. */
uint32_t SR_GetPacketCount() const { return SRinf.GetPacketCount(); } uint32_t SR_GetPacketCount() const { return SRinf.GetPacketCount(); }
/** Returns the octet count contained in the last sender report. */ /** Returns the octet count contained in the last sender report. */
uint32_t SR_GetByteCount() const { return SRinf.GetByteCount(); } uint32_t SR_GetByteCount() const { return SRinf.GetByteCount(); }
/** Returns the time at which the last sender report was received. */ /** Returns the time at which the last sender report was received. */
RTPTime SR_GetReceiveTime() const { return SRinf.GetReceiveTime(); } RTPTime SR_GetReceiveTime() const { return SRinf.GetReceiveTime(); }
/** Returns \c true if more than one RTCP sender report has been received. */ /** Returns \c true if more than one RTCP sender report has been received. */
bool SR_Prev_HasInfo() const { return SRprevinf.HasInfo(); } bool SR_Prev_HasInfo() const { return SRprevinf.HasInfo(); }
/** Returns the NTP timestamp contained in the second to last sender report. */ /** Returns the NTP timestamp contained in the second to last sender report. */
RTPNTPTime SR_Prev_GetNTPTimestamp() const { return SRprevinf.GetNTPTimestamp(); } RTPNTPTime SR_Prev_GetNTPTimestamp() const { return SRprevinf.GetNTPTimestamp(); }
/** Returns the RTP timestamp contained in the second to last sender report. */ /** Returns the RTP timestamp contained in the second to last sender report. */
uint32_t SR_Prev_GetRTPTimestamp() const { return SRprevinf.GetRTPTimestamp(); } uint32_t SR_Prev_GetRTPTimestamp() const { return SRprevinf.GetRTPTimestamp(); }
/** Returns the packet count contained in the second to last sender report. */ /** Returns the packet count contained in the second to last sender report. */
uint32_t SR_Prev_GetPacketCount() const { return SRprevinf.GetPacketCount(); } uint32_t SR_Prev_GetPacketCount() const { return SRprevinf.GetPacketCount(); }
/** Returns the octet count contained in the second to last sender report. */ /** Returns the octet count contained in the second to last sender report. */
uint32_t SR_Prev_GetByteCount() const { return SRprevinf.GetByteCount(); } uint32_t SR_Prev_GetByteCount() const { return SRprevinf.GetByteCount(); }
/** Returns the time at which the second to last sender report was received. */ /** Returns the time at which the second to last sender report was received. */
RTPTime SR_Prev_GetReceiveTime() const { return SRprevinf.GetReceiveTime(); } RTPTime SR_Prev_GetReceiveTime() const { return SRprevinf.GetReceiveTime(); }
/** Returns \c true if this participant sent a receiver report with information about the reception of our data. */ /** Returns \c true if this participant sent a receiver report with information about the reception of our data. */
bool RR_HasInfo() const { return RRinf.HasInfo(); } bool RR_HasInfo() const { return RRinf.HasInfo(); }
/** Returns the fraction lost value from the last report. */ /** Returns the fraction lost value from the last report. */
double RR_GetFractionLost() const { return RRinf.GetFractionLost(); } double RR_GetFractionLost() const { return RRinf.GetFractionLost(); }
/** Returns the number of lost packets contained in the last report. */ /** Returns the number of lost packets contained in the last report. */
int32_t RR_GetPacketsLost() const { return RRinf.GetPacketsLost(); } int32_t RR_GetPacketsLost() const { return RRinf.GetPacketsLost(); }
/** Returns the extended highest sequence number contained in the last report. */ /** Returns the extended highest sequence number contained in the last report. */
uint32_t RR_GetExtendedHighestSequenceNumber() const { return RRinf.GetExtendedHighestSequenceNumber(); } uint32_t RR_GetExtendedHighestSequenceNumber() const { return RRinf.GetExtendedHighestSequenceNumber(); }
/** Returns the jitter value from the last report. */ /** Returns the jitter value from the last report. */
uint32_t RR_GetJitter() const { return RRinf.GetJitter(); } uint32_t RR_GetJitter() const { return RRinf.GetJitter(); }
/** Returns the LSR value from the last report. */ /** Returns the LSR value from the last report. */
uint32_t RR_GetLastSRTimestamp() const { return RRinf.GetLastSRTimestamp(); } uint32_t RR_GetLastSRTimestamp() const { return RRinf.GetLastSRTimestamp(); }
/** Returns the DLSR value from the last report. */ /** Returns the DLSR value from the last report. */
uint32_t RR_GetDelaySinceLastSR() const { return RRinf.GetDelaySinceLastSR(); } uint32_t RR_GetDelaySinceLastSR() const { return RRinf.GetDelaySinceLastSR(); }
/** Returns the time at which the last report was received. */ /** Returns the time at which the last report was received. */
RTPTime RR_GetReceiveTime() const { return RRinf.GetReceiveTime(); } RTPTime RR_GetReceiveTime() const { return RRinf.GetReceiveTime(); }
/** Returns \c true if this participant sent more than one receiver report with information /** Returns \c true if this participant sent more than one receiver report with information
* about the reception of our data. * about the reception of our data.
*/ */
bool RR_Prev_HasInfo() const { return RRprevinf.HasInfo(); } bool RR_Prev_HasInfo() const { return RRprevinf.HasInfo(); }
/** Returns the fraction lost value from the second to last report. */ /** Returns the fraction lost value from the second to last report. */
double RR_Prev_GetFractionLost() const { return RRprevinf.GetFractionLost(); } double RR_Prev_GetFractionLost() const { return RRprevinf.GetFractionLost(); }
/** Returns the number of lost packets contained in the second to last report. */ /** Returns the number of lost packets contained in the second to last report. */
int32_t RR_Prev_GetPacketsLost() const { return RRprevinf.GetPacketsLost(); } int32_t RR_Prev_GetPacketsLost() const { return RRprevinf.GetPacketsLost(); }
/** Returns the extended highest sequence number contained in the second to last report. */ /** Returns the extended highest sequence number contained in the second to last report. */
uint32_t RR_Prev_GetExtendedHighestSequenceNumber() const { return RRprevinf.GetExtendedHighestSequenceNumber(); } uint32_t RR_Prev_GetExtendedHighestSequenceNumber() const { return RRprevinf.GetExtendedHighestSequenceNumber(); }
/** Returns the jitter value from the second to last report. */ /** Returns the jitter value from the second to last report. */
uint32_t RR_Prev_GetJitter() const { return RRprevinf.GetJitter(); } uint32_t RR_Prev_GetJitter() const { return RRprevinf.GetJitter(); }
/** Returns the LSR value from the second to last report. */ /** Returns the LSR value from the second to last report. */
uint32_t RR_Prev_GetLastSRTimestamp() const { return RRprevinf.GetLastSRTimestamp(); } uint32_t RR_Prev_GetLastSRTimestamp() const { return RRprevinf.GetLastSRTimestamp(); }
/** Returns the DLSR value from the second to last report. */ /** Returns the DLSR value from the second to last report. */
uint32_t RR_Prev_GetDelaySinceLastSR() const { return RRprevinf.GetDelaySinceLastSR(); } uint32_t RR_Prev_GetDelaySinceLastSR() const { return RRprevinf.GetDelaySinceLastSR(); }
/** Returns the time at which the second to last report was received. */ /** Returns the time at which the second to last report was received. */
RTPTime RR_Prev_GetReceiveTime() const { return RRprevinf.GetReceiveTime(); } RTPTime RR_Prev_GetReceiveTime() const { return RRprevinf.GetReceiveTime(); }
/** Returns \c true if validated RTP packets have been received from this participant. */ /** Returns \c true if validated RTP packets have been received from this participant. */
bool INF_HasSentData() const { return stats.HasSentData(); } bool INF_HasSentData() const { return stats.HasSentData(); }
/** Returns the total number of received packets from this participant. */ /** Returns the total number of received packets from this participant. */
int32_t INF_GetNumPacketsReceived() const { return stats.GetNumPacketsReceived(); } int32_t INF_GetNumPacketsReceived() const { return stats.GetNumPacketsReceived(); }
/** Returns the base sequence number of this participant. */ /** Returns the base sequence number of this participant. */
uint32_t INF_GetBaseSequenceNumber() const { return stats.GetBaseSequenceNumber(); } uint32_t INF_GetBaseSequenceNumber() const { return stats.GetBaseSequenceNumber(); }
/** Returns the extended highest sequence number received from this participant. */ /** Returns the extended highest sequence number received from this participant. */
uint32_t INF_GetExtendedHighestSequenceNumber() const { return stats.GetExtendedHighestSequenceNumber(); } uint32_t INF_GetExtendedHighestSequenceNumber() const { return stats.GetExtendedHighestSequenceNumber(); }
/** Returns the current jitter value for this participant. */ /** Returns the current jitter value for this participant. */
uint32_t INF_GetJitter() const { return stats.GetJitter(); } uint32_t INF_GetJitter() const { return stats.GetJitter(); }
/** Returns the time at which something was last heard from this member. */ /** Returns the time at which something was last heard from this member. */
RTPTime INF_GetLastMessageTime() const { return stats.GetLastMessageTime(); } RTPTime INF_GetLastMessageTime() const { return stats.GetLastMessageTime(); }
/** Returns the time at which the last RTP packet was received. */ /** Returns the time at which the last RTP packet was received. */
RTPTime INF_GetLastRTPPacketTime() const { return stats.GetLastRTPPacketTime(); } RTPTime INF_GetLastRTPPacketTime() const { return stats.GetLastRTPPacketTime(); }
/** Returns the estimated timestamp unit, calculated from two consecutive sender reports. */ /** Returns the estimated timestamp unit, calculated from two consecutive sender reports. */
double INF_GetEstimatedTimestampUnit() const; double INF_GetEstimatedTimestampUnit() const;
/** Returns the number of packets received since a new interval was started with INF_StartNewInterval. */ /** Returns the number of packets received since a new interval was started with INF_StartNewInterval. */
uint32_t INF_GetNumPacketsReceivedInInterval() const { return stats.GetNumPacketsReceivedInInterval(); } uint32_t INF_GetNumPacketsReceivedInInterval() const { return stats.GetNumPacketsReceivedInInterval(); }
/** Returns the extended sequence number which was stored by the INF_StartNewInterval call. */ /** Returns the extended sequence number which was stored by the INF_StartNewInterval call. */
uint32_t INF_GetSavedExtendedSequenceNumber() const { return stats.GetSavedExtendedSequenceNumber(); } uint32_t INF_GetSavedExtendedSequenceNumber() const { return stats.GetSavedExtendedSequenceNumber(); }
/** Starts a new interval to count received packets in; this also stores the current extended highest sequence /** Starts a new interval to count received packets in; this also stores the current extended highest sequence
* number to be able to calculate the packet loss during the interval. * number to be able to calculate the packet loss during the interval.
*/ */
void INF_StartNewInterval() { stats.StartNewInterval(); } void INF_StartNewInterval() { stats.StartNewInterval(); }
/** Estimates the round trip time by using the LSR and DLSR info from the last receiver report. */ /** Estimates the round trip time by using the LSR and DLSR info from the last receiver report. */
RTPTime INF_GetRoundtripTime() const; RTPTime INF_GetRoundtripTime() const;
/** Returns the time at which the last SDES NOTE item was received. */ /** Returns the time at which the last SDES NOTE item was received. */
RTPTime INF_GetLastSDESNoteTime() const { return stats.GetLastNoteTime(); } RTPTime INF_GetLastSDESNoteTime() const { return stats.GetLastNoteTime(); }
/** Returns a pointer to the SDES CNAME item of this participant and stores its length in \c len. */ /** Returns a pointer to the SDES CNAME item of this participant and stores its length in \c len. */
uint8_t *SDES_GetCNAME(size_t *len) const { return SDESinf.GetCNAME(len); } uint8_t *SDES_GetCNAME(size_t *len) const { return SDESinf.GetCNAME(len); }
/** Returns a pointer to the SDES name item of this participant and stores its length in \c len. */ /** Returns a pointer to the SDES name item of this participant and stores its length in \c len. */
uint8_t *SDES_GetName(size_t *len) const { return SDESinf.GetName(len); } uint8_t *SDES_GetName(size_t *len) const { return SDESinf.GetName(len); }
/** Returns a pointer to the SDES e-mail item of this participant and stores its length in \c len. */ /** Returns a pointer to the SDES e-mail item of this participant and stores its length in \c len. */
uint8_t *SDES_GetEMail(size_t *len) const { return SDESinf.GetEMail(len); } uint8_t *SDES_GetEMail(size_t *len) const { return SDESinf.GetEMail(len); }
/** Returns a pointer to the SDES phone item of this participant and stores its length in \c len. */ /** Returns a pointer to the SDES phone item of this participant and stores its length in \c len. */
uint8_t *SDES_GetPhone(size_t *len) const { return SDESinf.GetPhone(len); } uint8_t *SDES_GetPhone(size_t *len) const { return SDESinf.GetPhone(len); }
/** Returns a pointer to the SDES location item of this participant and stores its length in \c len. */ /** Returns a pointer to the SDES location item of this participant and stores its length in \c len. */
uint8_t *SDES_GetLocation(size_t *len) const { return SDESinf.GetLocation(len); } uint8_t *SDES_GetLocation(size_t *len) const { return SDESinf.GetLocation(len); }
/** Returns a pointer to the SDES tool item of this participant and stores its length in \c len. */ /** Returns a pointer to the SDES tool item of this participant and stores its length in \c len. */
uint8_t *SDES_GetTool(size_t *len) const { return SDESinf.GetTool(len); } uint8_t *SDES_GetTool(size_t *len) const { return SDESinf.GetTool(len); }
/** Returns a pointer to the SDES note item of this participant and stores its length in \c len. */ /** Returns a pointer to the SDES note item of this participant and stores its length in \c len. */
uint8_t *SDES_GetNote(size_t *len) const { return SDESinf.GetNote(len); } uint8_t *SDES_GetNote(size_t *len) const { return SDESinf.GetNote(len); }
#ifdef RTP_SUPPORT_SDESPRIV #ifdef RTP_SUPPORT_SDESPRIV
/** Starts the iteration over the stored SDES private item prefixes and their associated values. */ /** Starts the iteration over the stored SDES private item prefixes and their associated values. */
void SDES_GotoFirstPrivateValue() { SDESinf.GotoFirstPrivateValue(); } void SDES_GotoFirstPrivateValue() { SDESinf.GotoFirstPrivateValue(); }
/** If available, returns \c true and stores the next SDES private item prefix in \c prefix and its length in /** If available, returns \c true and stores the next SDES private item prefix in \c prefix and its length in
* \c prefixlen; the associated value and its length are then stored in \c value and \c valuelen. * \c prefixlen; the associated value and its length are then stored in \c value and \c valuelen.
*/ */
bool SDES_GetNextPrivateValue(uint8_t **prefix,size_t *prefixlen,uint8_t **value,size_t *valuelen) { return SDESinf.GetNextPrivateValue(prefix,prefixlen,value,valuelen); } bool SDES_GetNextPrivateValue(uint8_t **prefix,size_t *prefixlen,uint8_t **value,size_t *valuelen) { return SDESinf.GetNextPrivateValue(prefix,prefixlen,value,valuelen); }
/** Looks for the entry which corresponds to the SDES private item prefix \c prefix with length /** Looks for the entry which corresponds to the SDES private item prefix \c prefix with length
* \c prefixlen; if found, the function returns \c true and stores the associated value and * \c prefixlen; if found, the function returns \c true and stores the associated value and
* its length in \c value and \c valuelen respectively. * its length in \c value and \c valuelen respectively.
*/ */
bool SDES_GetPrivateValue(uint8_t *prefix,size_t prefixlen,uint8_t **value,size_t *valuelen) const { return SDESinf.GetPrivateValue(prefix,prefixlen,value,valuelen); } bool SDES_GetPrivateValue(uint8_t *prefix,size_t prefixlen,uint8_t **value,size_t *valuelen) const { return SDESinf.GetPrivateValue(prefix,prefixlen,value,valuelen); }
#endif // RTP_SUPPORT_SDESPRIV #endif // RTP_SUPPORT_SDESPRIV
#ifdef RTPDEBUG #ifdef RTPDEBUG
virtual void Dump(); virtual void Dump();
#endif // RTPDEBUG #endif // RTPDEBUG
protected: protected:
std::list<RTPPacket *> packetlist; std::list<RTPPacket *> packetlist;
uint32_t ssrc; uint32_t ssrc;
bool ownssrc; bool ownssrc;
bool iscsrc; bool iscsrc;
double timestampunit; double timestampunit;
bool receivedbye; bool receivedbye;
bool validated; bool validated;
bool processedinrtcp; bool processedinrtcp;
bool issender; bool issender;
RTCPSenderReportInfo SRinf,SRprevinf; RTCPSenderReportInfo SRinf,SRprevinf;
RTCPReceiverReportInfo RRinf,RRprevinf; RTCPReceiverReportInfo RRinf,RRprevinf;
RTPSourceStats stats; RTPSourceStats stats;
RTCPSDESInfo SDESinf; RTCPSDESInfo SDESinf;
bool isrtpaddrset,isrtcpaddrset; bool isrtpaddrset,isrtcpaddrset;
RTPAddress *rtpaddr,*rtcpaddr; RTPAddress *rtpaddr,*rtcpaddr;
RTPTime byetime; RTPTime byetime;
uint8_t *byereason; uint8_t *byereason;
size_t byereasonlen; size_t byereasonlen;
}; };
inline RTPPacket *RTPSourceData::GetNextPacket() inline RTPPacket *RTPSourceData::GetNextPacket()
{ {
if (!validated) if (!validated)
return 0; return 0;
RTPPacket *p; RTPPacket *p;
if (packetlist.empty()) if (packetlist.empty())
return 0; return 0;
p = *(packetlist.begin()); p = *(packetlist.begin());
packetlist.pop_front(); packetlist.pop_front();
return p; return p;
} }
inline void RTPSourceData::FlushPackets() inline void RTPSourceData::FlushPackets()
{ {
std::list<RTPPacket *>::const_iterator it; std::list<RTPPacket *>::const_iterator it;
for (it = packetlist.begin() ; it != packetlist.end() ; ++it) for (it = packetlist.begin() ; it != packetlist.end() ; ++it)
RTPDelete(*it,GetMemoryManager()); RTPDelete(*it,GetMemoryManager());
packetlist.clear(); packetlist.clear();
} }
} // end namespace } // end namespace

View File

@ -809,7 +809,9 @@ int RTPSources::ObtainSourceDataInstance(uint32_t ssrc,RTPInternalSourceData **s
#endif // RTP_SUPPORT_PROBATION #endif // RTP_SUPPORT_PROBATION
if (srcdat2 == 0) if (srcdat2 == 0)
return ERR_RTP_OUTOFMEM; return ERR_RTP_OUTOFMEM;
if ((status = sourcelist.AddElement(ssrc,srcdat2)) < 0)
// Add new source item
if ((status = sourcelist.AddElement(ssrc,srcdat2)) < 0)
{ {
RTPDelete(srcdat2,GetMemoryManager()); RTPDelete(srcdat2,GetMemoryManager());
return status; return status;