Implements selective retransmissions.

Default is set to not retransmit VP8 non-base layer packets or FEC packets.

BUG=
TEST=

Review URL: http://webrtc-codereview.appspot.com/323010

git-svn-id: http://webrtc.googlecode.com/svn/trunk@1290 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
stefan@webrtc.org 2011-12-22 12:52:41 +00:00
parent 51faeed6be
commit 6a4bef4e65
10 changed files with 199 additions and 63 deletions

View File

@ -810,13 +810,33 @@ public:
*/ */
virtual WebRtc_Word32 SetNACKStatus(const NACKMethod method) = 0; virtual WebRtc_Word32 SetNACKStatus(const NACKMethod method) = 0;
/*
* TODO(holmer): Propagate this API to VideoEngine.
* Returns the currently configured selective retransmission settings.
*/
virtual int SelectiveRetransmissions() const = 0;
/*
* TODO(holmer): Propagate this API to VideoEngine.
* Sets the selective retransmission settings, which will decide which
* packets will be retransmitted if NACKed. Settings are constructed by
* combining the constants in enum RetransmissionMode with bitwise OR.
* All packets are retransmitted if kRetransmitAllPackets is set, while no
* packets are retransmitted if kRetransmitOff is set.
* By default all packets except FEC packets are retransmitted. For VP8
* with temporal scalability only base layer packets are retransmitted.
*
* Returns -1 on failure, otherwise 0.
*/
virtual int SetSelectiveRetransmissions(uint8_t settings) = 0;
/* /*
* Send a Negative acknowledgement packet * Send a Negative acknowledgement packet
* *
* return -1 on failure else 0 * return -1 on failure else 0
*/ */
virtual WebRtc_Word32 SendNACK(const WebRtc_UWord16* nackList, virtual WebRtc_Word32 SendNACK(const WebRtc_UWord16* nackList,
const WebRtc_UWord16 size) = 0; const WebRtc_UWord16 size) = 0;
/* /*
* Store the sent packets, needed to answer to a Negative acknowledgement requests * Store the sent packets, needed to answer to a Negative acknowledgement requests

View File

@ -89,6 +89,14 @@ enum NACKMethod
kNackRtcp = 2 kNackRtcp = 2
}; };
enum RetransmissionMode {
kRetransmitOff = 0x0,
kRetransmitFECPackets = 0x1,
kRetransmitBaseLayer = 0x2,
kRetransmitHigherLayers = 0x4,
kRetransmitAllPackets = 0xFF
};
struct RTCPSenderInfo struct RTCPSenderInfo
{ {
WebRtc_UWord32 NTPseconds; WebRtc_UWord32 NTPseconds;

View File

@ -194,6 +194,10 @@ class MockRtpRtcp : public RtpRtcp {
NACKMethod()); NACKMethod());
MOCK_METHOD1(SetNACKStatus, MOCK_METHOD1(SetNACKStatus,
WebRtc_Word32(const NACKMethod method)); WebRtc_Word32(const NACKMethod method));
MOCK_CONST_METHOD0(SelectiveRetransmissions,
int());
MOCK_METHOD1(SetSelectiveRetransmissions,
int(uint8_t settings));
MOCK_METHOD2(SendNACK, MOCK_METHOD2(SendNACK,
WebRtc_Word32(const WebRtc_UWord16* nackList, const WebRtc_UWord16 size)); WebRtc_Word32(const WebRtc_UWord16* nackList, const WebRtc_UWord16 size));
MOCK_METHOD2(SetStorePacketsStatus, MOCK_METHOD2(SetStorePacketsStatus,

View File

@ -1963,6 +1963,26 @@ WebRtc_Word32 ModuleRtpRtcpImpl::SetNACKStatus(NACKMethod method)
return 0; return 0;
} }
// Returns the currently configured retransmission mode.
int ModuleRtpRtcpImpl::SelectiveRetransmissions() const {
WEBRTC_TRACE(kTraceModuleCall,
kTraceRtpRtcp,
_id,
"SelectiveRetransmissions()");
return _rtpSender.SelectiveRetransmissions();
}
// Enable or disable a retransmission mode, which decides which packets will
// be retransmitted if NACKed.
int ModuleRtpRtcpImpl::SetSelectiveRetransmissions(uint8_t settings) {
WEBRTC_TRACE(kTraceModuleCall,
kTraceRtpRtcp,
_id,
"SetSelectiveRetransmissions(%u)",
settings);
return _rtpSender.SetSelectiveRetransmissions(settings);
}
// Send a Negative acknowledgement packet // Send a Negative acknowledgement packet
WebRtc_Word32 WebRtc_Word32
ModuleRtpRtcpImpl::SendNACK(const WebRtc_UWord16* nackList, ModuleRtpRtcpImpl::SendNACK(const WebRtc_UWord16* nackList,

View File

@ -381,6 +381,10 @@ public:
// Turn negative acknowledgement requests on/off // Turn negative acknowledgement requests on/off
virtual WebRtc_Word32 SetNACKStatus(const NACKMethod method); virtual WebRtc_Word32 SetNACKStatus(const NACKMethod method);
virtual int SelectiveRetransmissions() const;
virtual int SetSelectiveRetransmissions(uint8_t settings);
// Send a Negative acknowledgement packet // Send a Negative acknowledgement packet
virtual WebRtc_Word32 SendNACK(const WebRtc_UWord16* nackList, virtual WebRtc_Word32 SendNACK(const WebRtc_UWord16* nackList,
const WebRtc_UWord16 size); const WebRtc_UWord16 size);

View File

@ -554,7 +554,7 @@ RTPSender::SendRTPKeepalivePacket()
BuildRTPheader(dataBuffer, _keepAlivePayloadType, false, 0, false); BuildRTPheader(dataBuffer, _keepAlivePayloadType, false, 0, false);
} }
return SendToNetwork(dataBuffer, 0, rtpHeaderLength); return SendToNetwork(dataBuffer, 0, rtpHeaderLength, kAllowRetransmission);
} }
WebRtc_Word32 WebRtc_Word32
@ -899,11 +899,11 @@ RTPSender::ReSendToNetwork(WebRtc_UWord16 packetID,
return -1; return -1;
} }
} }
if(length ==0) if (length == 0)
{ {
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, // This is a valid case since packets which we decide not to
"Resend packet length == 0 for seqNum %u", seqNum); // retransmit are stored but with length zero.
return -1; return 0;
} }
// copy to local buffer for callback // copy to local buffer for callback
@ -942,6 +942,16 @@ RTPSender::ReSendToNetwork(WebRtc_UWord16 packetID,
return -1; return -1;
} }
int RTPSender::SelectiveRetransmissions() const {
if (!_video) return -1;
return _video->SelectiveRetransmissions();
}
int RTPSender::SetSelectiveRetransmissions(uint8_t settings) {
if (!_video) return -1;
return _video->SetSelectiveRetransmissions(settings);
}
void void
RTPSender::OnReceivedNACK(const WebRtc_UWord16 nackSequenceNumbersLength, RTPSender::OnReceivedNACK(const WebRtc_UWord16 nackSequenceNumbersLength,
const WebRtc_UWord16* nackSequenceNumbers, const WebRtc_UWord16* nackSequenceNumbers,
@ -1069,7 +1079,7 @@ WebRtc_Word32
RTPSender::SendToNetwork(const WebRtc_UWord8* buffer, RTPSender::SendToNetwork(const WebRtc_UWord8* buffer,
const WebRtc_UWord16 length, const WebRtc_UWord16 length,
const WebRtc_UWord16 rtpLength, const WebRtc_UWord16 rtpLength,
const bool dontStore) const StorageType storage)
{ {
WebRtc_Word32 retVal = -1; WebRtc_Word32 retVal = -1;
// sanity // sanity
@ -1078,34 +1088,22 @@ RTPSender::SendToNetwork(const WebRtc_UWord8* buffer,
return -1; return -1;
} }
if(!dontStore) // Make sure the packet is big enough for us to parse the sequence number.
{ assert(length + rtpLength > 3);
// Store my packets // Parse the sequence number from the RTP header.
// Used for NACK WebRtc_UWord16 sequenceNumber = (buffer[2] << 8) + buffer[3];
CriticalSectionScoped lock(_prevSentPacketsCritsect); switch (storage) {
if(_storeSentPackets && length > 0) case kAllowRetransmission:
{ StorePacket(buffer, length + rtpLength, sequenceNumber);
if(_ptrPrevSentPackets[0] == NULL) break;
{ case kDontRetransmit:
for(WebRtc_Word32 i=0; i< _storeSentPacketsNumber; i++) // Store an empty packet. Won't be retransmitted if NACKed.
{ StorePacket(NULL, 0, sequenceNumber);
_ptrPrevSentPackets[i] = new char[_maxPayloadLength]; break;
memset(_ptrPrevSentPackets[i],0, _maxPayloadLength); case kDontStore:
} break;
} default:
assert(false);
const WebRtc_UWord16 sequenceNumber = (buffer[2] << 8) + buffer[3];
memcpy(_ptrPrevSentPackets[_prevSentPacketsIndex], buffer, length + rtpLength);
_prevSentPacketsSeqNum[_prevSentPacketsIndex] = sequenceNumber;
_prevSentPacketsLength[_prevSentPacketsIndex]= length + rtpLength;
_prevSentPacketsResendTime[_prevSentPacketsIndex]=0; // Packet has not been re-sent.
_prevSentPacketsIndex++;
if(_prevSentPacketsIndex >= _storeSentPacketsNumber)
{
_prevSentPacketsIndex = 0;
}
}
} }
// Send packet // Send packet
{ {
@ -1133,6 +1131,32 @@ RTPSender::SendToNetwork(const WebRtc_UWord8* buffer,
return -1; return -1;
} }
void RTPSender::StorePacket(const uint8_t* buffer, uint16_t length,
uint16_t sequence_number) {
// Store packet to be used for NACK.
CriticalSectionScoped lock(_prevSentPacketsCritsect);
if(_storeSentPackets) {
if(_ptrPrevSentPackets[0] == NULL) {
for(WebRtc_Word32 i = 0; i < _storeSentPacketsNumber; i++) {
_ptrPrevSentPackets[i] = new char[_maxPayloadLength];
memset(_ptrPrevSentPackets[i], 0, _maxPayloadLength);
}
}
if (buffer != NULL && length > 0) {
memcpy(_ptrPrevSentPackets[_prevSentPacketsIndex], buffer, length);
}
_prevSentPacketsSeqNum[_prevSentPacketsIndex] = sequence_number;
_prevSentPacketsLength[_prevSentPacketsIndex] = length;
// Packet has not been re-sent.
_prevSentPacketsResendTime[_prevSentPacketsIndex] = 0;
_prevSentPacketsIndex++;
if(_prevSentPacketsIndex >= _storeSentPacketsNumber) {
_prevSentPacketsIndex = 0;
}
}
}
void void
RTPSender::ProcessBitrate() RTPSender::ProcessBitrate()
{ {

View File

@ -31,6 +31,12 @@ class CriticalSectionWrapper;
class RTPSenderAudio; class RTPSenderAudio;
class RTPSenderVideo; class RTPSenderVideo;
enum StorageType {
kDontStore,
kDontRetransmit,
kAllowRetransmission
};
class RTPSenderInterface class RTPSenderInterface
{ {
public: public:
@ -57,9 +63,9 @@ public:
virtual WebRtc_UWord16 ActualSendBitrateKbit() const = 0; virtual WebRtc_UWord16 ActualSendBitrateKbit() const = 0;
virtual WebRtc_Word32 SendToNetwork(const WebRtc_UWord8* dataBuffer, virtual WebRtc_Word32 SendToNetwork(const WebRtc_UWord8* dataBuffer,
const WebRtc_UWord16 payloadLength, const WebRtc_UWord16 payloadLength,
const WebRtc_UWord16 rtpHeaderLength, const WebRtc_UWord16 rtpHeaderLength,
const bool dontStore = false) = 0; const StorageType storage) = 0;
}; };
class RTPSender : public Bitrate, public RTPSenderInterface class RTPSender : public Bitrate, public RTPSenderInterface
@ -162,6 +168,8 @@ public:
/* /*
* NACK * NACK
*/ */
int SelectiveRetransmissions() const;
int SetSelectiveRetransmissions(uint8_t settings);
void OnReceivedNACK(const WebRtc_UWord16 nackSequenceNumbersLength, void OnReceivedNACK(const WebRtc_UWord16 nackSequenceNumbersLength,
const WebRtc_UWord16* nackSequenceNumbers, const WebRtc_UWord16* nackSequenceNumbers,
const WebRtc_UWord16 avgRTT); const WebRtc_UWord16 avgRTT);
@ -216,9 +224,9 @@ public:
virtual WebRtc_UWord32 SSRC() const; virtual WebRtc_UWord32 SSRC() const;
virtual WebRtc_Word32 SendToNetwork(const WebRtc_UWord8* dataBuffer, virtual WebRtc_Word32 SendToNetwork(const WebRtc_UWord8* dataBuffer,
const WebRtc_UWord16 payloadLength, const WebRtc_UWord16 payloadLength,
const WebRtc_UWord16 rtpHeaderLength, const WebRtc_UWord16 rtpHeaderLength,
const bool dontStore = false); const StorageType storage);
/* /*
* Audio * Audio
@ -282,6 +290,9 @@ protected:
WebRtc_Word32 CheckPayloadType(const WebRtc_Word8 payloadType, RtpVideoCodecTypes& videoType); WebRtc_Word32 CheckPayloadType(const WebRtc_Word8 payloadType, RtpVideoCodecTypes& videoType);
private: private:
void StorePacket(const uint8_t* buffer, uint16_t length,
uint16_t sequence_number);
WebRtc_Word32 _id; WebRtc_Word32 _id;
const bool _audioConfigured; const bool _audioConfigured;
RTPSenderAudio* _audio; RTPSenderAudio* _audio;

View File

@ -527,7 +527,11 @@ RTPSenderAudio::SendAudio(const FrameType frameType,
} // end critical section } // end critical section
return _rtpSender->SendToNetwork(dataBuffer, payloadSize, (WebRtc_UWord16)rtpHeaderLength); return _rtpSender->SendToNetwork(
dataBuffer,
payloadSize,
static_cast<WebRtc_UWord16>(rtpHeaderLength),
kAllowRetransmission);
} }
@ -662,7 +666,8 @@ RTPSenderAudio::SendTelephoneEventPacket(const bool ended,
ModuleRTPUtility::AssignUWord16ToBuffer(dtmfbuffer+14, duration); ModuleRTPUtility::AssignUWord16ToBuffer(dtmfbuffer+14, duration);
_sendAudioCritsect->Leave(); _sendAudioCritsect->Leave();
retVal = _rtpSender->SendToNetwork(dtmfbuffer, 4, 12); retVal = _rtpSender->SendToNetwork(dtmfbuffer, 4, 12,
kAllowRetransmission);
sendCount--; sendCount--;
}while (sendCount > 0 && retVal == 0); }while (sendCount > 0 && retVal == 0);

View File

@ -35,6 +35,7 @@ RTPSenderVideo::RTPSenderVideo(const WebRtc_Word32 id,
_videoType(kRtpNoVideo), _videoType(kRtpNoVideo),
_videoCodecInformation(NULL), _videoCodecInformation(NULL),
_maxBitrate(0), _maxBitrate(0),
_retransmissionSettings(kRetransmitBaseLayer),
// Generic FEC // Generic FEC
_fec(id), _fec(id),
@ -71,6 +72,7 @@ RTPSenderVideo::Init()
{ {
CriticalSectionScoped cs(_sendVideoCritsect); CriticalSectionScoped cs(_sendVideoCritsect);
_retransmissionSettings = kRetransmitBaseLayer;
_fecEnabled = false; _fecEnabled = false;
_payloadTypeRED = -1; _payloadTypeRED = -1;
_payloadTypeFEC = -1; _payloadTypeFEC = -1;
@ -157,7 +159,8 @@ WebRtc_Word32
RTPSenderVideo::SendVideoPacket(const FrameType frameType, RTPSenderVideo::SendVideoPacket(const FrameType frameType,
const WebRtc_UWord8* dataBuffer, const WebRtc_UWord8* dataBuffer,
const WebRtc_UWord16 payloadLength, const WebRtc_UWord16 payloadLength,
const WebRtc_UWord16 rtpHeaderLength) const WebRtc_UWord16 rtpHeaderLength,
StorageType storage)
{ {
if(_fecEnabled) if(_fecEnabled)
{ {
@ -254,11 +257,11 @@ RTPSenderVideo::SendVideoPacket(const FrameType frameType,
// Send normal packet with RED header // Send normal packet with RED header
int packetSuccess = _rtpSender.SendToNetwork( int packetSuccess = _rtpSender.SendToNetwork(
newDataBuffer, newDataBuffer,
packetToSend->pkt->length - packetToSend->pkt->length - packetToSend->rtpHeaderLength +
packetToSend->rtpHeaderLength + REDForFECHeaderLength,
REDForFECHeaderLength, packetToSend->rtpHeaderLength,
packetToSend->rtpHeaderLength); storage);
retVal |= packetSuccess; retVal |= packetSuccess;
@ -313,12 +316,18 @@ RTPSenderVideo::SendVideoPacket(const FrameType frameType,
// Invalid FEC packet // Invalid FEC packet
assert(packetToSend->length != 0); assert(packetToSend->length != 0);
StorageType storage = kDontRetransmit;
if (_retransmissionSettings & kRetransmitFECPackets) {
storage = kAllowRetransmission;
}
// No marker bit on FEC packets, last media packet have the // No marker bit on FEC packets, last media packet have the
// marker send FEC packet with RED header // marker send FEC packet with RED header
int packetSuccess = _rtpSender.SendToNetwork( int packetSuccess = _rtpSender.SendToNetwork(
newDataBuffer, newDataBuffer,
packetToSend->length + REDForFECHeaderLength, packetToSend->length + REDForFECHeaderLength,
lastMediaRtpHeader.length); lastMediaRtpHeader.length,
storage);
retVal |= packetSuccess; retVal |= packetSuccess;
@ -335,7 +344,8 @@ RTPSenderVideo::SendVideoPacket(const FrameType frameType,
} }
int retVal = _rtpSender.SendToNetwork(dataBuffer, int retVal = _rtpSender.SendToNetwork(dataBuffer,
payloadLength, payloadLength,
rtpHeaderLength); rtpHeaderLength,
storage);
if (retVal == 0) if (retVal == 0)
{ {
_videoBitrate.Update(payloadLength + rtpHeaderLength); _videoBitrate.Update(payloadLength + rtpHeaderLength);
@ -358,7 +368,7 @@ RTPSenderVideo::SendRTPIntraRequest()
ModuleRTPUtility::AssignUWord32ToBuffer(data+4, _rtpSender.SSRC()); ModuleRTPUtility::AssignUWord32ToBuffer(data+4, _rtpSender.SSRC());
return _rtpSender.SendToNetwork(data, 0, length); return _rtpSender.SendToNetwork(data, 0, length, kAllowRetransmission);
} }
WebRtc_Word32 WebRtc_Word32
@ -537,7 +547,8 @@ RTPSenderVideo::SendGeneric(const WebRtc_Word8 payloadType,
if(-1 == SendVideoPacket(kVideoFrameKey, if(-1 == SendVideoPacket(kVideoFrameKey,
dataBuffer, dataBuffer,
payloadBytesInPacket, payloadBytesInPacket,
rtpHeaderLength)) rtpHeaderLength,
kAllowRetransmission))
{ {
return -1; return -1;
} }
@ -589,7 +600,8 @@ void RTPSenderVideo::SendPadData(WebRtc_Word8 payload_type,
// Send the packet // Send the packet
_rtpSender.SendToNetwork(data_buffer, _rtpSender.SendToNetwork(data_buffer,
padding_bytes_in_packet, padding_bytes_in_packet,
header_length); header_length,
kDontRetransmit);
} }
} }
@ -666,7 +678,7 @@ RTPSenderVideo::SendMPEG4(const FrameType frameType,
}while(payloadBytesToSend); }while(payloadBytesToSend);
if (-1 == SendVideoPacket(frameType, dataBuffer, payloadBytes, if (-1 == SendVideoPacket(frameType, dataBuffer, payloadBytes,
rtpHeaderLength)) rtpHeaderLength, kAllowRetransmission))
{ {
return -1; return -1;
} }
@ -934,7 +946,7 @@ RTPSenderVideo::SendH263(const FrameType frameType,
if (-1 == SendVideoPacket(frameType, if (-1 == SendVideoPacket(frameType,
dataBuffer, dataBuffer,
payloadBytesInPacket + h263HeaderLength, payloadBytesInPacket + h263HeaderLength,
rtpHeaderLength)) rtpHeaderLength, kAllowRetransmission))
{ {
return -1; return -1;
} }
@ -1072,8 +1084,11 @@ RTPSenderVideo::SendH2631998(const FrameType frameType,
memcpy(&dataBuffer[rtpHeaderLength + h2631998HeaderLength], memcpy(&dataBuffer[rtpHeaderLength + h2631998HeaderLength],
data, payloadBytesInPacket); data, payloadBytesInPacket);
if(-1 == SendVideoPacket(frameType, dataBuffer, payloadBytesInPacket + if(-1 == SendVideoPacket(frameType,
h2631998HeaderLength, rtpHeaderLength)) dataBuffer,
payloadBytesInPacket + h2631998HeaderLength,
rtpHeaderLength,
kAllowRetransmission))
{ {
return -1; return -1;
} }
@ -1250,7 +1265,8 @@ RTPSenderVideo::SendH263MBs(const FrameType frameType,
if (-1 == SendVideoPacket(frameType, if (-1 == SendVideoPacket(frameType,
dataBuffer, dataBuffer,
payloadBytesInPacket + h263HeaderLength, payloadBytesInPacket + h263HeaderLength,
rtpHeaderLength)) rtpHeaderLength,
kAllowRetransmission))
{ {
return -1; return -1;
} }
@ -1281,6 +1297,16 @@ RTPSenderVideo::SendVP8(const FrameType frameType,
RtpFormatVp8 packetizer(data, payloadBytesToSend, rtpTypeHdr->VP8, RtpFormatVp8 packetizer(data, payloadBytesToSend, rtpTypeHdr->VP8,
maxPayloadLengthVP8, *fragmentation, kAggregate); maxPayloadLengthVP8, *fragmentation, kAggregate);
StorageType storage = kAllowRetransmission;
if (rtpTypeHdr->VP8.temporalIdx == 0 &&
!(_retransmissionSettings & kRetransmitBaseLayer)) {
storage = kDontRetransmit;
}
if (rtpTypeHdr->VP8.temporalIdx > 0 &&
!(_retransmissionSettings & kRetransmitHigherLayers)) {
storage = kDontRetransmit;
}
bool last = false; bool last = false;
_numberFirstPartition = 0; _numberFirstPartition = 0;
while (!last) while (!last)
@ -1305,7 +1331,7 @@ RTPSenderVideo::SendVP8(const FrameType frameType,
_rtpSender.BuildRTPheader(dataBuffer, payloadType, last, _rtpSender.BuildRTPheader(dataBuffer, payloadType, last,
captureTimeStamp); captureTimeStamp);
if (-1 == SendVideoPacket(frameType, dataBuffer, payloadBytesInPacket, if (-1 == SendVideoPacket(frameType, dataBuffer, payloadBytesInPacket,
rtpHeaderLength)) rtpHeaderLength, storage))
{ {
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
"RTPSenderVideo::SendVP8 failed to send packet number" "RTPSenderVideo::SendVP8 failed to send packet number"
@ -1328,4 +1354,13 @@ WebRtc_UWord32 RTPSenderVideo::FecOverheadRate() const {
return _fecOverheadRate.BitrateLast(); return _fecOverheadRate.BitrateLast();
} }
int RTPSenderVideo::SelectiveRetransmissions() const {
return _retransmissionSettings;
}
int RTPSenderVideo::SetSelectiveRetransmissions(uint8_t settings) {
_retransmissionSettings = settings;
return 0;
}
} // namespace webrtc } // namespace webrtc

View File

@ -92,11 +92,15 @@ public:
WebRtc_UWord32 VideoBitrateSent() const; WebRtc_UWord32 VideoBitrateSent() const;
WebRtc_UWord32 FecOverheadRate() const; WebRtc_UWord32 FecOverheadRate() const;
int SelectiveRetransmissions() const;
int SetSelectiveRetransmissions(uint8_t settings);
protected: protected:
virtual WebRtc_Word32 SendVideoPacket(const FrameType frameType, virtual WebRtc_Word32 SendVideoPacket(const FrameType frameType,
const WebRtc_UWord8* dataBuffer, const WebRtc_UWord8* dataBuffer,
const WebRtc_UWord16 payloadLength, const WebRtc_UWord16 payloadLength,
const WebRtc_UWord16 rtpHeaderLength); const WebRtc_UWord16 rtpHeaderLength,
StorageType storage);
private: private:
WebRtc_Word32 SendGeneric(const WebRtc_Word8 payloadType, WebRtc_Word32 SendGeneric(const WebRtc_Word8 payloadType,
@ -155,6 +159,7 @@ private:
RtpVideoCodecTypes _videoType; RtpVideoCodecTypes _videoType;
VideoCodecInformation* _videoCodecInformation; VideoCodecInformation* _videoCodecInformation;
WebRtc_UWord32 _maxBitrate; WebRtc_UWord32 _maxBitrate;
WebRtc_Word32 _retransmissionSettings;
// FEC // FEC
ForwardErrorCorrection _fec; ForwardErrorCorrection _fec;