- ongoing work to ease jitter & RTT calculation
This commit is contained in:
parent
d90940c907
commit
0607bd1c47
|
|
@ -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
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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, ¶ms, jrtplib::RTPTransmitter::ExternalProto);
|
mRtpSession.Create(sessionParams, ¶ms, jrtplib::RTPTransmitter::ExternalProto);
|
||||||
mRtpDtmfSession.Create(sessionParams, ¶ms, jrtplib::RTPTransmitter::ExternalProto);
|
mRtpDtmfSession.Create(sessionParams, ¶ms, 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;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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);
|
||||||
|
|
|
||||||
|
|
@ -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; }
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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) { }
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue