Changed RTP reveivers to use stl map and list.
Review URL: https://webrtc-codereview.appspot.com/349010 git-svn-id: http://webrtc.googlecode.com/svn/trunk@1475 4adac7df-926f-26a2-2b94-8c16560cd09d
This commit is contained in:
parent
38f4816737
commit
af6f15c1bf
@ -21,6 +21,14 @@
|
||||
#include <stdlib.h> // abs
|
||||
|
||||
namespace webrtc {
|
||||
|
||||
using ModuleRTPUtility::AudioPayload;
|
||||
using ModuleRTPUtility::GetCurrentRTP;
|
||||
using ModuleRTPUtility::Payload;
|
||||
using ModuleRTPUtility::RTPPayloadParser;
|
||||
using ModuleRTPUtility::StringCompare;
|
||||
using ModuleRTPUtility::VideoPayload;
|
||||
|
||||
RTPReceiver::RTPReceiver(const WebRtc_Word32 id,
|
||||
const bool audio,
|
||||
RtpRtcpClock* clock,
|
||||
@ -98,43 +106,24 @@ RTPReceiver::RTPReceiver(const WebRtc_Word32 id,
|
||||
WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, id, "%s created", __FUNCTION__);
|
||||
}
|
||||
|
||||
RTPReceiver::~RTPReceiver()
|
||||
{
|
||||
if(_cbRtpFeedback)
|
||||
{
|
||||
for(int i = 0; i < _numCSRCs; i++)
|
||||
{
|
||||
RTPReceiver::~RTPReceiver() {
|
||||
if (_cbRtpFeedback) {
|
||||
for (int i = 0; i < _numCSRCs; i++) {
|
||||
_cbRtpFeedback->OnIncomingCSRCChanged(_id,_currentRemoteCSRC[i], false);
|
||||
}
|
||||
}
|
||||
delete _criticalSectionCbs;
|
||||
delete _criticalSectionRTPReceiver;
|
||||
|
||||
// empty map
|
||||
bool loop = true;
|
||||
do
|
||||
{
|
||||
MapItem* item = _payloadTypeMap.First();
|
||||
if(item)
|
||||
{
|
||||
// delete
|
||||
ModuleRTPUtility::Payload* payload= ((ModuleRTPUtility::Payload*)item->GetItem());
|
||||
delete payload;
|
||||
|
||||
// remove from map and delete Item
|
||||
_payloadTypeMap.Erase(item);
|
||||
} else
|
||||
{
|
||||
loop = false;
|
||||
while (!_payloadTypeMap.empty()) {
|
||||
std::map<WebRtc_Word8, Payload*>::iterator it = _payloadTypeMap.begin();
|
||||
delete it->second;
|
||||
_payloadTypeMap.erase(it);
|
||||
}
|
||||
} while (loop);
|
||||
|
||||
WEBRTC_TRACE(kTraceMemory, kTraceRtpRtcp, _id, "%s deleted", __FUNCTION__);
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
RTPReceiver::Init()
|
||||
{
|
||||
WebRtc_Word32 RTPReceiver::Init() {
|
||||
CriticalSectionScoped lock(_criticalSectionRTPReceiver);
|
||||
|
||||
_lastReceiveTime = 0;
|
||||
@ -184,22 +173,11 @@ RTPReceiver::Init()
|
||||
|
||||
_rtpHeaderExtensionMap.Erase();
|
||||
|
||||
// clear db
|
||||
bool loop = true;
|
||||
do
|
||||
{
|
||||
MapItem* item = _payloadTypeMap.First();
|
||||
if(item)
|
||||
{
|
||||
ModuleRTPUtility::Payload* payload= ((ModuleRTPUtility::Payload*)item->GetItem());
|
||||
delete payload;
|
||||
// remove from map
|
||||
_payloadTypeMap.Erase(item);
|
||||
} else
|
||||
{
|
||||
loop = false;
|
||||
while (!_payloadTypeMap.empty()) {
|
||||
std::map<WebRtc_Word8, Payload*>::iterator it = _payloadTypeMap.begin();
|
||||
delete it->second;
|
||||
_payloadTypeMap.erase(it);
|
||||
}
|
||||
} while (loop);
|
||||
|
||||
Bitrate::Init();
|
||||
RTPReceiverAudio::Init();
|
||||
@ -369,24 +347,17 @@ RTPReceiver::RegisterIncomingDataCallback(RtpData* incomingDataCallback)
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
RTPReceiver::RegisterReceivePayload( const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
|
||||
WebRtc_Word32 RTPReceiver::RegisterReceivePayload(
|
||||
const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
|
||||
const WebRtc_Word8 payloadType,
|
||||
const WebRtc_UWord32 frequency,
|
||||
const WebRtc_UWord8 channels,
|
||||
const WebRtc_UWord32 rate)
|
||||
{
|
||||
if(payloadName == NULL)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
const WebRtc_UWord32 rate) {
|
||||
assert(payloadName);
|
||||
CriticalSectionScoped lock(_criticalSectionRTPReceiver);
|
||||
|
||||
// sanity
|
||||
switch(payloadType)
|
||||
{
|
||||
switch (payloadType) {
|
||||
// reserved payload types to avoid RTCP conflicts when marker bit is set
|
||||
case 64: // 192 Full INTRA-frame request
|
||||
case 72: // 200 Sender report
|
||||
@ -397,301 +368,269 @@ RTPReceiver::RegisterReceivePayload( const WebRtc_Word8 payloadName[RTP_PAYLOAD_
|
||||
case 77: // 205 Transport layer FB message
|
||||
case 78: // 206 Payload-specific FB message
|
||||
case 79: // 207 Extended report
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid payloadtype:%d", __FUNCTION__, payloadType);
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
|
||||
"%s invalid payloadtype:%d",
|
||||
__FUNCTION__, payloadType);
|
||||
return -1;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
WebRtc_Word32 payloadNameLength = (WebRtc_Word32)strlen(payloadName);
|
||||
size_t payloadNameLength = strlen(payloadName);
|
||||
|
||||
MapItem* item = NULL;
|
||||
item = _payloadTypeMap.Find(payloadType);
|
||||
if( NULL != item)
|
||||
{
|
||||
std::map<WebRtc_Word8, Payload*>::iterator it =
|
||||
_payloadTypeMap.find(payloadType);
|
||||
if (it != _payloadTypeMap.end()) {
|
||||
// we already use this payload type
|
||||
|
||||
ModuleRTPUtility::Payload* payload = (ModuleRTPUtility::Payload*)item->GetItem();
|
||||
Payload* payload = it->second;
|
||||
assert(payload);
|
||||
|
||||
WebRtc_Word32 nameLength = (WebRtc_Word32)strlen(payload->name);
|
||||
size_t nameLength = strlen(payload->name);
|
||||
|
||||
// check if it's the same as we already have
|
||||
// if same ignore sending an error
|
||||
if(payloadNameLength == nameLength && ModuleRTPUtility::StringCompare(payload->name, payloadName, payloadNameLength))
|
||||
{
|
||||
if (payloadNameLength == nameLength &&
|
||||
StringCompare(payload->name, payloadName, payloadNameLength)) {
|
||||
if (_audio &&
|
||||
payload->audio &&
|
||||
payload->typeSpecific.Audio.frequency == frequency &&
|
||||
payload->typeSpecific.Audio.channels == channels &&
|
||||
(payload->typeSpecific.Audio.rate == rate || payload->typeSpecific.Audio.rate == 0 || rate == 0))
|
||||
{
|
||||
payload->typeSpecific.Audio.rate = rate; // Ensure that we update the rate if new or old is zero
|
||||
(payload->typeSpecific.Audio.rate == rate ||
|
||||
payload->typeSpecific.Audio.rate == 0 || rate == 0)) {
|
||||
payload->typeSpecific.Audio.rate = rate;
|
||||
// Ensure that we update the rate if new or old is zero
|
||||
return 0;
|
||||
}
|
||||
if(!_audio && !payload->audio)
|
||||
{
|
||||
if (!_audio && !payload->audio) {
|
||||
// update maxBitrate for video
|
||||
payload->typeSpecific.Video.maxRate = rate;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument payloadType:%d already registered", __FUNCTION__, payloadType);
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
|
||||
"%s invalid argument payloadType:%d already registered",
|
||||
__FUNCTION__, payloadType);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(_audio)
|
||||
{
|
||||
if (_audio) {
|
||||
// remove existing item, hence search for the name
|
||||
// only for audio, for video we allow a codecs to use multiple pltypes
|
||||
item = _payloadTypeMap.First();
|
||||
while(item)
|
||||
{
|
||||
ModuleRTPUtility::Payload* payload = (ModuleRTPUtility::Payload*)item->GetItem();
|
||||
WebRtc_Word32 nameLength = (WebRtc_Word32)strlen(payload->name);
|
||||
std::map<WebRtc_Word8, Payload*>::iterator audio_it =
|
||||
_payloadTypeMap.begin();
|
||||
while (audio_it != _payloadTypeMap.end()) {
|
||||
Payload* payload = audio_it->second;
|
||||
size_t nameLength = strlen(payload->name);
|
||||
|
||||
if(payloadNameLength == nameLength && ModuleRTPUtility::StringCompare(payload->name, payloadName, payloadNameLength))
|
||||
{
|
||||
if (payloadNameLength == nameLength &&
|
||||
StringCompare(payload->name, payloadName, payloadNameLength)) {
|
||||
// we found the payload name in the list
|
||||
// if audio check frequency and rate
|
||||
if( payload->audio)
|
||||
{
|
||||
if (payload->audio) {
|
||||
if (payload->typeSpecific.Audio.frequency == frequency &&
|
||||
(payload->typeSpecific.Audio.rate == rate || payload->typeSpecific.Audio.rate == 0 || rate == 0))
|
||||
{
|
||||
(payload->typeSpecific.Audio.rate == rate ||
|
||||
payload->typeSpecific.Audio.rate == 0 || rate == 0)) {
|
||||
// remove old setting
|
||||
delete payload;
|
||||
_payloadTypeMap.Erase(item);
|
||||
_payloadTypeMap.erase(audio_it);
|
||||
break;
|
||||
}
|
||||
} else if(ModuleRTPUtility::StringCompare(payloadName,"red",3))
|
||||
{
|
||||
} else if(StringCompare(payloadName,"red",3)) {
|
||||
delete payload;
|
||||
_payloadTypeMap.Erase(item);
|
||||
_payloadTypeMap.erase(audio_it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
item = _payloadTypeMap.Next(item);
|
||||
audio_it++;
|
||||
}
|
||||
}
|
||||
|
||||
ModuleRTPUtility::Payload* payload = NULL;
|
||||
Payload* payload = NULL;
|
||||
|
||||
// save the RED payload type
|
||||
// used in both audio and video
|
||||
if(ModuleRTPUtility::StringCompare(payloadName,"red",3))
|
||||
{
|
||||
if (StringCompare(payloadName,"red",3)) {
|
||||
_redPayloadType = payloadType;
|
||||
payload = new ModuleRTPUtility::Payload;
|
||||
payload = new Payload;
|
||||
payload->audio = false;
|
||||
memcpy(payload->name, payloadName, RTP_PAYLOAD_NAME_SIZE);
|
||||
} else
|
||||
{
|
||||
if(_audio)
|
||||
{
|
||||
payload = RegisterReceiveAudioPayload(payloadName, payloadType, frequency, channels, rate);
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
if (_audio) {
|
||||
payload = RegisterReceiveAudioPayload(payloadName, payloadType,
|
||||
frequency, channels, rate);
|
||||
} else {
|
||||
payload = RegisterReceiveVideoPayload(payloadName, payloadType, rate);
|
||||
}
|
||||
if(payload == NULL)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s filed to register payload", __FUNCTION__);
|
||||
}
|
||||
if (payload == NULL) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
|
||||
"%s filed to register payload",
|
||||
__FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
_payloadTypeMap.Insert(payloadType, payload);
|
||||
_payloadTypeMap[payloadType] = payload;
|
||||
|
||||
// Successful set of payload type, clear the value of last receivedPT, since it might mean something else
|
||||
// Successful set of payload type, clear the value of last receivedPT,
|
||||
// since it might mean something else
|
||||
_lastReceivedPayloadType = -1;
|
||||
_lastReceivedMediaPayloadType = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
RTPReceiver::DeRegisterReceivePayload(const WebRtc_Word8 payloadType)
|
||||
{
|
||||
WebRtc_Word32 RTPReceiver::DeRegisterReceivePayload(
|
||||
const WebRtc_Word8 payloadType) {
|
||||
CriticalSectionScoped lock(_criticalSectionRTPReceiver);
|
||||
|
||||
MapItem* item = _payloadTypeMap.Find(payloadType);
|
||||
if( NULL != item)
|
||||
{
|
||||
ModuleRTPUtility::Payload* payload = (ModuleRTPUtility::Payload*)item->GetItem();
|
||||
delete payload;
|
||||
std::map<WebRtc_Word8, Payload*>::iterator it =
|
||||
_payloadTypeMap.find(payloadType);
|
||||
|
||||
_payloadTypeMap.Erase(item);
|
||||
return 0;
|
||||
}
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s failed to find payloadType:%d", __FUNCTION__, payloadType);
|
||||
if (it == _payloadTypeMap.end()) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
|
||||
"%s failed to find payloadType:%d",
|
||||
__FUNCTION__, payloadType);
|
||||
return -1;
|
||||
}
|
||||
delete it->second;
|
||||
_payloadTypeMap.erase(it);
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32 RTPReceiver::ReceivePayloadType(
|
||||
const WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
|
||||
const WebRtc_UWord32 frequency,
|
||||
const WebRtc_UWord8 channels,
|
||||
const WebRtc_UWord32 rate,
|
||||
WebRtc_Word8* payloadType) const
|
||||
{
|
||||
if(payloadType == NULL)
|
||||
{
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "%s invalid argument", __FUNCTION__);
|
||||
WebRtc_Word8* payloadType) const {
|
||||
if (payloadType == NULL) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
|
||||
"%s invalid argument", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtc_Word32 payloadNameLength = (WebRtc_Word32)strlen(payloadName);
|
||||
size_t payloadNameLength = strlen(payloadName);
|
||||
|
||||
CriticalSectionScoped lock(_criticalSectionRTPReceiver);
|
||||
|
||||
MapItem* item = _payloadTypeMap.First();
|
||||
while( NULL != item)
|
||||
{
|
||||
ModuleRTPUtility::Payload* payload = (ModuleRTPUtility::Payload*)item->GetItem();
|
||||
std::map<WebRtc_Word8, Payload*>::const_iterator it =
|
||||
_payloadTypeMap.begin();
|
||||
|
||||
while (it != _payloadTypeMap.end()) {
|
||||
Payload* payload = it->second;
|
||||
assert(payload);
|
||||
|
||||
WebRtc_Word32 nameLength = (WebRtc_Word32)strlen(payload->name);
|
||||
if(payloadNameLength == nameLength && ModuleRTPUtility::StringCompare(payload->name, payloadName, payloadNameLength))
|
||||
{
|
||||
size_t nameLength = strlen(payload->name);
|
||||
if (payloadNameLength == nameLength &&
|
||||
StringCompare(payload->name, payloadName, payloadNameLength)) {
|
||||
// name match
|
||||
if(payload->audio)
|
||||
{
|
||||
if (rate == 0)
|
||||
{
|
||||
if( payload->audio) {
|
||||
if (rate == 0) {
|
||||
// [default] audio, check freq and channels
|
||||
if (payload->typeSpecific.Audio.frequency == frequency &&
|
||||
payload->typeSpecific.Audio.channels == channels)
|
||||
{
|
||||
*payloadType = item->GetId();
|
||||
payload->typeSpecific.Audio.channels == channels) {
|
||||
*payloadType = it->first;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
// audio, check freq, channels and rate
|
||||
if( payload->typeSpecific.Audio.frequency == frequency &&
|
||||
payload->typeSpecific.Audio.channels == channels &&
|
||||
payload->typeSpecific.Audio.rate == rate) // extra rate condition added
|
||||
{
|
||||
*payloadType = item->GetId();
|
||||
payload->typeSpecific.Audio.rate == rate) {
|
||||
// extra rate condition added
|
||||
*payloadType = it->first;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
// video
|
||||
*payloadType = item->GetId();
|
||||
*payloadType = it->first;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
item = _payloadTypeMap.Next(item);
|
||||
it++;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
RTPReceiver::ReceivePayload(const WebRtc_Word8 payloadType,
|
||||
WebRtc_Word32 RTPReceiver::ReceivePayload(
|
||||
const WebRtc_Word8 payloadType,
|
||||
WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
|
||||
WebRtc_UWord32* frequency,
|
||||
WebRtc_UWord8* channels,
|
||||
WebRtc_UWord32* rate) const
|
||||
{
|
||||
WebRtc_UWord32* rate) const {
|
||||
CriticalSectionScoped lock(_criticalSectionRTPReceiver);
|
||||
|
||||
MapItem* item = _payloadTypeMap.Find(payloadType);
|
||||
if( NULL == item)
|
||||
{
|
||||
std::map<WebRtc_Word8, Payload*>::const_iterator it =
|
||||
_payloadTypeMap.find(payloadType);
|
||||
|
||||
if (it == _payloadTypeMap.end()) {
|
||||
return -1;
|
||||
}
|
||||
ModuleRTPUtility::Payload* payload = (ModuleRTPUtility::Payload*)item->GetItem();
|
||||
Payload* payload = it->second;
|
||||
assert(payload);
|
||||
|
||||
if(frequency)
|
||||
{
|
||||
if(payload->audio)
|
||||
{
|
||||
if(frequency) {
|
||||
if(payload->audio) {
|
||||
*frequency = payload->typeSpecific.Audio.frequency;
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
*frequency = 90000;
|
||||
}
|
||||
}
|
||||
if(channels)
|
||||
{
|
||||
if(payload->audio)
|
||||
{
|
||||
if (channels) {
|
||||
if(payload->audio) {
|
||||
*channels = payload->typeSpecific.Audio.channels;
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
*channels = 1;
|
||||
}
|
||||
}
|
||||
if (rate)
|
||||
{
|
||||
if(payload->audio)
|
||||
{
|
||||
if (rate) {
|
||||
if(payload->audio) {
|
||||
*rate = payload->typeSpecific.Audio.rate;
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
assert(false);
|
||||
*rate = 0;
|
||||
}
|
||||
}
|
||||
if(payloadName)
|
||||
{
|
||||
if (payloadName) {
|
||||
memcpy(payloadName, payload->name, RTP_PAYLOAD_NAME_SIZE);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
RTPReceiver::RemotePayload(WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
|
||||
WebRtc_Word32 RTPReceiver::RemotePayload(
|
||||
WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE],
|
||||
WebRtc_Word8* payloadType,
|
||||
WebRtc_UWord32* frequency,
|
||||
WebRtc_UWord8* channels) const
|
||||
{
|
||||
if(_lastReceivedPayloadType == -1)
|
||||
{
|
||||
WebRtc_UWord8* channels) const {
|
||||
if(_lastReceivedPayloadType == -1) {
|
||||
WEBRTC_TRACE(kTraceWarning, kTraceRtpRtcp, _id, "%s invalid state", __FUNCTION__);
|
||||
return -1;
|
||||
}
|
||||
memset(payloadName, 0, RTP_PAYLOAD_NAME_SIZE);
|
||||
std::map<WebRtc_Word8, Payload*>::const_iterator it =
|
||||
_payloadTypeMap.find(_lastReceivedPayloadType);
|
||||
|
||||
MapItem* item = _payloadTypeMap.Find(_lastReceivedPayloadType);
|
||||
if( NULL != item)
|
||||
{
|
||||
ModuleRTPUtility::Payload* payload = (ModuleRTPUtility::Payload*)item->GetItem();
|
||||
if(payload)
|
||||
{
|
||||
if (it == _payloadTypeMap.end()) {
|
||||
return -1;
|
||||
}
|
||||
Payload* payload = it->second;
|
||||
assert(payload);
|
||||
payloadName[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
|
||||
memcpy(payloadName, payload->name, RTP_PAYLOAD_NAME_SIZE - 1);
|
||||
|
||||
if(payloadType )
|
||||
{
|
||||
if (payloadType) {
|
||||
*payloadType = _lastReceivedPayloadType;
|
||||
}
|
||||
if(frequency)
|
||||
{
|
||||
if(payload->audio)
|
||||
{
|
||||
if (frequency) {
|
||||
if (payload->audio) {
|
||||
*frequency = payload->typeSpecific.Audio.frequency;
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
*frequency = 90000;
|
||||
}
|
||||
}
|
||||
if(channels)
|
||||
{
|
||||
if(payload->audio)
|
||||
{
|
||||
if (channels) {
|
||||
if (payload->audio) {
|
||||
*channels = payload->typeSpecific.Audio.channels;
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
*channels = 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
RTPReceiver::RegisterRtpHeaderExtension(const RTPExtensionType type,
|
||||
@ -836,11 +775,11 @@ WebRtc_Word32 RTPReceiver::IncomingRTPPacket(
|
||||
CheckSSRCChanged(rtp_header);
|
||||
|
||||
bool is_red = false;
|
||||
ModuleRTPUtility::VideoPayload video_specific;
|
||||
VideoPayload video_specific;
|
||||
video_specific.maxRate = 0;
|
||||
video_specific.videoCodecType = kRtpNoVideo;
|
||||
|
||||
ModuleRTPUtility::AudioPayload audio_specific;
|
||||
AudioPayload audio_specific;
|
||||
audio_specific.bitsPerSample = 0;
|
||||
audio_specific.channels = 0;
|
||||
audio_specific.frequency = 0;
|
||||
@ -955,7 +894,7 @@ RTPReceiver::UpdateStatistics(const WebRtcRTPHeader* rtpHeader,
|
||||
_receivedSeqMax = rtpHeader->header.sequenceNumber;
|
||||
_receivedInorderPacketCount = 1;
|
||||
_localTimeLastReceivedTimestamp =
|
||||
ModuleRTPUtility::GetCurrentRTP(&_clock, freq); //time in samples
|
||||
GetCurrentRTP(&_clock, freq); //time in samples
|
||||
return;
|
||||
}
|
||||
|
||||
@ -963,7 +902,7 @@ RTPReceiver::UpdateStatistics(const WebRtcRTPHeader* rtpHeader,
|
||||
if(InOrderPacket(rtpHeader->header.sequenceNumber))
|
||||
{
|
||||
const WebRtc_UWord32 RTPtime =
|
||||
ModuleRTPUtility::GetCurrentRTP(&_clock, freq); //time in samples
|
||||
GetCurrentRTP(&_clock, freq); //time in samples
|
||||
_receivedInorderPacketCount++;
|
||||
|
||||
// wrong if we use RetransmitOfOldPacket
|
||||
@ -1110,28 +1049,21 @@ RTPReceiver::TimeStamp() const
|
||||
return _lastReceivedTimestamp;
|
||||
}
|
||||
|
||||
WebRtc_UWord32
|
||||
RTPReceiver::PayloadTypeToPayload(const WebRtc_UWord8 payloadType,
|
||||
ModuleRTPUtility::Payload*& payload) const
|
||||
{
|
||||
MapItem* item = _payloadTypeMap.Find(payloadType);
|
||||
WebRtc_UWord32 RTPReceiver::PayloadTypeToPayload(
|
||||
const WebRtc_UWord8 payloadType,
|
||||
Payload*& payload) const {
|
||||
|
||||
std::map<WebRtc_Word8, Payload*>::const_iterator it =
|
||||
_payloadTypeMap.find(payloadType);
|
||||
|
||||
// check that this is a registered payload type
|
||||
if(item == NULL)
|
||||
{
|
||||
if (it == _payloadTypeMap.end()) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
payload = (ModuleRTPUtility::Payload*)item->GetItem();
|
||||
if(payload == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
payload = it->second;
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
// timeStamp of the last incoming packet that is the first packet of its frame
|
||||
WebRtc_Word32
|
||||
RTPReceiver::EstimatedRemoteTimeStamp(WebRtc_UWord32& timestamp) const
|
||||
@ -1148,7 +1080,7 @@ RTPReceiver::EstimatedRemoteTimeStamp(WebRtc_UWord32& timestamp) const
|
||||
return -1;
|
||||
}
|
||||
//time in samples
|
||||
WebRtc_UWord32 diff = ModuleRTPUtility::GetCurrentRTP(&_clock, freq)
|
||||
WebRtc_UWord32 diff = GetCurrentRTP(&_clock, freq)
|
||||
- _localTimeLastReceivedTimestamp;
|
||||
|
||||
timestamp = _lastReceivedTimestamp + diff;
|
||||
@ -1187,9 +1119,7 @@ RTPReceiver::SetSSRCFilter(const bool enable, const WebRtc_UWord32 allowedSSRC)
|
||||
}
|
||||
|
||||
// no criticalsection when called
|
||||
void
|
||||
RTPReceiver::CheckSSRCChanged(const WebRtcRTPHeader* rtpHeader)
|
||||
{
|
||||
void RTPReceiver::CheckSSRCChanged(const WebRtcRTPHeader* rtpHeader) {
|
||||
bool newSSRC = false;
|
||||
bool reInitializeDecoder = false;
|
||||
WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE];
|
||||
@ -1201,8 +1131,9 @@ RTPReceiver::CheckSSRCChanged(const WebRtcRTPHeader* rtpHeader)
|
||||
{
|
||||
CriticalSectionScoped lock(_criticalSectionRTPReceiver);
|
||||
|
||||
if (_SSRC != rtpHeader->header.ssrc || (_lastReceivedPayloadType == -1 && _SSRC == 0)) // we need the _payloadType to make the call if the remote SSRC is 0
|
||||
{
|
||||
if (_SSRC != rtpHeader->header.ssrc ||
|
||||
(_lastReceivedPayloadType == -1 && _SSRC == 0)) {
|
||||
// we need the _payloadType to make the call if the remote SSRC is 0
|
||||
newSSRC = true;
|
||||
|
||||
// reset last report
|
||||
@ -1213,68 +1144,62 @@ RTPReceiver::CheckSSRCChanged(const WebRtcRTPHeader* rtpHeader)
|
||||
_lastReceivedSequenceNumber = 0;
|
||||
_lastReceivedTransmissionTimeOffset = 0;
|
||||
|
||||
if (_SSRC) // do we have a SSRC? then the stream is restarted
|
||||
{
|
||||
if (_SSRC) { // do we have a SSRC? then the stream is restarted
|
||||
// if we have the same codec? reinit decoder
|
||||
if (rtpHeader->header.payloadType == _lastReceivedPayloadType)
|
||||
{
|
||||
if (rtpHeader->header.payloadType == _lastReceivedPayloadType) {
|
||||
reInitializeDecoder = true;
|
||||
|
||||
MapItem* item = _payloadTypeMap.Find(rtpHeader->header.payloadType);
|
||||
if( NULL != item)
|
||||
{
|
||||
ModuleRTPUtility::Payload* payload = (ModuleRTPUtility::Payload*)item->GetItem();
|
||||
if(payload)
|
||||
{
|
||||
std::map<WebRtc_Word8, Payload*>::iterator it =
|
||||
_payloadTypeMap.find(rtpHeader->header.payloadType);
|
||||
|
||||
if (it == _payloadTypeMap.end()) {
|
||||
return;
|
||||
}
|
||||
Payload* payload = it->second;
|
||||
assert(payload);
|
||||
payloadName[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
|
||||
memcpy(payloadName, payload->name, RTP_PAYLOAD_NAME_SIZE - 1);
|
||||
if(payload->audio)
|
||||
{
|
||||
if(payload->audio) {
|
||||
frequency = payload->typeSpecific.Audio.frequency;
|
||||
channels = payload->typeSpecific.Audio.channels;
|
||||
rate = payload->typeSpecific.Audio.rate;
|
||||
} else
|
||||
{
|
||||
} else {
|
||||
frequency = 90000;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_SSRC = rtpHeader->header.ssrc;
|
||||
}
|
||||
}
|
||||
if(newSSRC)
|
||||
{
|
||||
if(newSSRC) {
|
||||
// we need to get this to our RTCP sender and receiver
|
||||
// need to do this outside critical section
|
||||
_rtpRtcp.SetRemoteSSRC(rtpHeader->header.ssrc);
|
||||
}
|
||||
|
||||
CriticalSectionScoped lock(_criticalSectionCbs);
|
||||
if(_cbRtpFeedback)
|
||||
{
|
||||
if(newSSRC)
|
||||
{
|
||||
if(_cbRtpFeedback) {
|
||||
if(newSSRC) {
|
||||
_cbRtpFeedback->OnIncomingSSRCChanged(_id, rtpHeader->header.ssrc);
|
||||
}
|
||||
if(reInitializeDecoder)
|
||||
{
|
||||
if(-1 == _cbRtpFeedback->OnInitializeDecoder(_id, rtpHeader->header.payloadType, payloadName, frequency, channels, rate)) // new stream same codec
|
||||
{
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "Failed to create decoder for payload type:%d", rtpHeader->header.payloadType);
|
||||
if(reInitializeDecoder) {
|
||||
if (-1 == _cbRtpFeedback->OnInitializeDecoder(_id,
|
||||
rtpHeader->header.payloadType, payloadName, frequency, channels,
|
||||
rate)) { // new stream same codec
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
|
||||
"Failed to create decoder for payload type:%d",
|
||||
rtpHeader->header.payloadType);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// no criticalsection when called
|
||||
WebRtc_Word32
|
||||
RTPReceiver::CheckPayloadChanged(const WebRtcRTPHeader* rtpHeader,
|
||||
WebRtc_Word32 RTPReceiver::CheckPayloadChanged(
|
||||
const WebRtcRTPHeader* rtpHeader,
|
||||
const WebRtc_Word8 firstPayloadByte,
|
||||
bool& isRED,
|
||||
ModuleRTPUtility::AudioPayload& audioSpecificPayload,
|
||||
ModuleRTPUtility::VideoPayload& videoSpecificPayload)
|
||||
{
|
||||
AudioPayload& audioSpecificPayload,
|
||||
VideoPayload& videoSpecificPayload) {
|
||||
bool reInitializeDecoder = false;
|
||||
|
||||
WebRtc_Word8 payloadName[RTP_PAYLOAD_NAME_SIZE];
|
||||
@ -1283,123 +1208,112 @@ RTPReceiver::CheckPayloadChanged(const WebRtcRTPHeader* rtpHeader,
|
||||
{
|
||||
CriticalSectionScoped lock(_criticalSectionRTPReceiver);
|
||||
|
||||
if (payloadType != _lastReceivedPayloadType)
|
||||
{
|
||||
if (REDPayloadType(payloadType))
|
||||
{
|
||||
if (payloadType != _lastReceivedPayloadType) {
|
||||
if (REDPayloadType(payloadType)) {
|
||||
// get the real codec payload type
|
||||
payloadType = firstPayloadByte & 0x7f;
|
||||
isRED = true;
|
||||
|
||||
//when we receive RED we need to check the real payload type
|
||||
if (payloadType == _lastReceivedPayloadType)
|
||||
{
|
||||
if (payloadType == _lastReceivedPayloadType) {
|
||||
if(_audio)
|
||||
{
|
||||
memcpy(&audioSpecificPayload, &_lastReceivedAudioSpecific, sizeof(_lastReceivedAudioSpecific));
|
||||
} else
|
||||
{
|
||||
memcpy(&videoSpecificPayload, &_lastReceivedVideoSpecific, sizeof(_lastReceivedVideoSpecific));
|
||||
memcpy(&audioSpecificPayload, &_lastReceivedAudioSpecific,
|
||||
sizeof(_lastReceivedAudioSpecific));
|
||||
} else {
|
||||
memcpy(&videoSpecificPayload, &_lastReceivedVideoSpecific,
|
||||
sizeof(_lastReceivedVideoSpecific));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
if(_audio)
|
||||
{
|
||||
if(TelephoneEventPayloadType(payloadType))
|
||||
{
|
||||
if (_audio) {
|
||||
if (TelephoneEventPayloadType(payloadType)) {
|
||||
// don't do callbacks for DTMF packets
|
||||
isRED = false;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// frequency is updated for CNG
|
||||
if(CNGPayloadType(payloadType, audioSpecificPayload.frequency))
|
||||
{
|
||||
if (CNGPayloadType(payloadType, audioSpecificPayload.frequency)) {
|
||||
// don't do callbacks for DTMF packets
|
||||
isRED = false;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
MapItem* item = _payloadTypeMap.Find(payloadType);
|
||||
std::map<WebRtc_Word8, ModuleRTPUtility::Payload*>::iterator it =
|
||||
_payloadTypeMap.find(payloadType);
|
||||
|
||||
// check that this is a registered payload type
|
||||
if(item == NULL)
|
||||
{
|
||||
if (it == _payloadTypeMap.end()) {
|
||||
return -1;
|
||||
}
|
||||
memset(payloadName, 0, sizeof(payloadName));
|
||||
|
||||
ModuleRTPUtility::Payload* payload = (ModuleRTPUtility::Payload*)item->GetItem();
|
||||
if(payload == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
Payload* payload = it->second;
|
||||
assert(payload);
|
||||
payloadName[RTP_PAYLOAD_NAME_SIZE - 1] = 0;
|
||||
memcpy(payloadName, payload->name, RTP_PAYLOAD_NAME_SIZE - 1);
|
||||
_lastReceivedPayloadType = payloadType;
|
||||
|
||||
reInitializeDecoder = true;
|
||||
|
||||
if(payload->audio)
|
||||
{
|
||||
memcpy(&_lastReceivedAudioSpecific, &(payload->typeSpecific.Audio), sizeof(_lastReceivedAudioSpecific));
|
||||
memcpy(&audioSpecificPayload, &(payload->typeSpecific.Audio), sizeof(_lastReceivedAudioSpecific));
|
||||
}else
|
||||
{
|
||||
memcpy(&_lastReceivedVideoSpecific, &(payload->typeSpecific.Video), sizeof(_lastReceivedVideoSpecific));
|
||||
memcpy(&videoSpecificPayload, &(payload->typeSpecific.Video), sizeof(_lastReceivedVideoSpecific));
|
||||
if(payload->audio) {
|
||||
memcpy(&_lastReceivedAudioSpecific, &(payload->typeSpecific.Audio),
|
||||
sizeof(_lastReceivedAudioSpecific));
|
||||
memcpy(&audioSpecificPayload, &(payload->typeSpecific.Audio),
|
||||
sizeof(_lastReceivedAudioSpecific));
|
||||
} else {
|
||||
memcpy(&_lastReceivedVideoSpecific, &(payload->typeSpecific.Video),
|
||||
sizeof(_lastReceivedVideoSpecific));
|
||||
memcpy(&videoSpecificPayload, &(payload->typeSpecific.Video),
|
||||
sizeof(_lastReceivedVideoSpecific));
|
||||
|
||||
if (_lastReceivedVideoSpecific.videoCodecType == kRtpFecVideo)
|
||||
{
|
||||
// Only reset the decoder on media packets.
|
||||
reInitializeDecoder = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_lastReceivedMediaPayloadType == _lastReceivedPayloadType)
|
||||
{
|
||||
} else {
|
||||
if (_lastReceivedMediaPayloadType == _lastReceivedPayloadType) {
|
||||
// Only reset the decoder if the media codec type has changed.
|
||||
reInitializeDecoder = false;
|
||||
}
|
||||
_lastReceivedMediaPayloadType = _lastReceivedPayloadType;
|
||||
}
|
||||
}
|
||||
if(reInitializeDecoder)
|
||||
{
|
||||
if (reInitializeDecoder) {
|
||||
// reset statistics
|
||||
ResetStatistics();
|
||||
}
|
||||
}else
|
||||
{
|
||||
} else {
|
||||
if(_audio)
|
||||
{
|
||||
memcpy(&audioSpecificPayload, &_lastReceivedAudioSpecific, sizeof(_lastReceivedAudioSpecific));
|
||||
memcpy(&audioSpecificPayload, &_lastReceivedAudioSpecific,
|
||||
sizeof(_lastReceivedAudioSpecific));
|
||||
} else
|
||||
{
|
||||
memcpy(&videoSpecificPayload, &_lastReceivedVideoSpecific, sizeof(_lastReceivedVideoSpecific));
|
||||
memcpy(&videoSpecificPayload, &_lastReceivedVideoSpecific,
|
||||
sizeof(_lastReceivedVideoSpecific));
|
||||
}
|
||||
isRED = false;
|
||||
}
|
||||
} // end critsect
|
||||
if(reInitializeDecoder)
|
||||
{
|
||||
if (reInitializeDecoder) {
|
||||
CriticalSectionScoped lock(_criticalSectionCbs);
|
||||
if(_cbRtpFeedback)
|
||||
{
|
||||
if (_cbRtpFeedback) {
|
||||
// create new decoder instance
|
||||
if(_audio)
|
||||
{
|
||||
if (-1 == _cbRtpFeedback->OnInitializeDecoder(_id, payloadType, payloadName, audioSpecificPayload.frequency, audioSpecificPayload.channels, audioSpecificPayload.rate))
|
||||
{
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "Failed to create audio decoder for payload type:%d", payloadType);
|
||||
if(_audio) {
|
||||
if (-1 == _cbRtpFeedback->OnInitializeDecoder(_id, payloadType,
|
||||
payloadName, audioSpecificPayload.frequency,
|
||||
audioSpecificPayload.channels, audioSpecificPayload.rate)) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
|
||||
"Failed to create audio decoder for payload type:%d",
|
||||
payloadType);
|
||||
return -1; // Wrong payload type
|
||||
}
|
||||
} else
|
||||
{
|
||||
if (-1 == _cbRtpFeedback->OnInitializeDecoder(_id, payloadType, payloadName, 90000, 1, 0))
|
||||
{
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id, "Failed to create video decoder for payload type:%d", payloadType);
|
||||
} else {
|
||||
if (-1 == _cbRtpFeedback->OnInitializeDecoder(_id, payloadType,
|
||||
payloadName, 90000, 1, 0)) {
|
||||
WEBRTC_TRACE(kTraceError, kTraceRtpRtcp, _id,
|
||||
"Failed to create video decoder for payload type:%d",
|
||||
payloadType);
|
||||
return -1; // Wrong payload type
|
||||
}
|
||||
}
|
||||
|
@ -11,6 +11,8 @@
|
||||
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_H_
|
||||
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_H_
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "rtp_utility.h"
|
||||
|
||||
@ -208,8 +210,7 @@ private:
|
||||
|
||||
WebRtc_Word8 _redPayloadType;
|
||||
|
||||
//
|
||||
MapWrapper _payloadTypeMap;
|
||||
std::map<WebRtc_Word8, ModuleRTPUtility::Payload*> _payloadTypeMap;
|
||||
RtpHeaderExtensionMap _rtpHeaderExtensionMap;
|
||||
|
||||
// SSRCs
|
||||
|
@ -24,7 +24,6 @@ RTPReceiverAudio::RTPReceiverAudio(const WebRtc_Word32 id):
|
||||
_telephoneEventForwardToDecoder(false),
|
||||
_telephoneEventDetectEndOfTone(false),
|
||||
_telephoneEventPayloadType(-1),
|
||||
_telephoneEventReported(),
|
||||
_cngNBPayloadType(-1),
|
||||
_cngWBPayloadType(-1),
|
||||
_cngSWBPayloadType(-1),
|
||||
@ -41,19 +40,15 @@ RTPReceiverAudio::~RTPReceiverAudio()
|
||||
delete _criticalSectionFeedback;
|
||||
}
|
||||
|
||||
WebRtc_Word32
|
||||
RTPReceiverAudio::Init()
|
||||
{
|
||||
WebRtc_Word32 RTPReceiverAudio::Init() {
|
||||
_lastReceivedFrequency = 8000;
|
||||
_telephoneEvent = false;
|
||||
_telephoneEventForwardToDecoder = false;
|
||||
_telephoneEventDetectEndOfTone = false;
|
||||
_telephoneEventPayloadType = -1;
|
||||
|
||||
while(_telephoneEventReported.Size() > 0)
|
||||
{
|
||||
_telephoneEventReported.Erase(_telephoneEventReported.First());
|
||||
}
|
||||
_telephoneEventReported.clear();
|
||||
|
||||
_cngNBPayloadType = -1;
|
||||
_cngWBPayloadType = -1;
|
||||
_cngSWBPayloadType = -1;
|
||||
@ -342,14 +337,17 @@ RTPReceiverAudio::ParseAudioCodecSpecific(WebRtcRTPHeader* rtpHeader,
|
||||
{
|
||||
bool end = (payloadData[(4*n)+1] & 0x80)? true:false;
|
||||
|
||||
if(_telephoneEventReported.Find(payloadData[4*n]) != NULL)
|
||||
std::set<WebRtc_UWord8>::iterator event =
|
||||
_telephoneEventReported.find(payloadData[4*n]);
|
||||
|
||||
if(event != _telephoneEventReported.end())
|
||||
{
|
||||
// we have already seen this event
|
||||
if(end)
|
||||
{
|
||||
removedEvents[numberOfRemovedEvents]= payloadData[4*n];
|
||||
numberOfRemovedEvents++;
|
||||
_telephoneEventReported.Erase(payloadData[4*n]);
|
||||
_telephoneEventReported.erase(payloadData[4*n]);
|
||||
}
|
||||
}else
|
||||
{
|
||||
@ -360,7 +358,7 @@ RTPReceiverAudio::ParseAudioCodecSpecific(WebRtcRTPHeader* rtpHeader,
|
||||
{
|
||||
newEvents[numberOfNewEvents] = payloadData[4*n];
|
||||
numberOfNewEvents++;
|
||||
_telephoneEventReported.Insert(payloadData[4*n],NULL);
|
||||
_telephoneEventReported.insert(payloadData[4*n]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -411,8 +409,9 @@ RTPReceiverAudio::ParseAudioCodecSpecific(WebRtcRTPHeader* rtpHeader,
|
||||
// don't forward event to decoder
|
||||
return 0;
|
||||
}
|
||||
MapItem* first = _telephoneEventReported.First();
|
||||
if(first && first->GetId() > 15)
|
||||
std::set<WebRtc_UWord8>::iterator first =
|
||||
_telephoneEventReported.begin();
|
||||
if(first != _telephoneEventReported.end() && *first > 15)
|
||||
{
|
||||
// don't forward non DTMF events
|
||||
return 0;
|
||||
|
@ -11,11 +11,12 @@
|
||||
#ifndef WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_AUDIO_H_
|
||||
#define WEBRTC_MODULES_RTP_RTCP_SOURCE_RTP_RECEIVER_AUDIO_H_
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "rtp_rtcp_defines.h"
|
||||
#include "rtp_utility.h"
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "map_wrapper.h"
|
||||
|
||||
namespace webrtc {
|
||||
class CriticalSectionWrapper;
|
||||
@ -78,7 +79,7 @@ private:
|
||||
bool _telephoneEventForwardToDecoder;
|
||||
bool _telephoneEventDetectEndOfTone;
|
||||
WebRtc_Word8 _telephoneEventPayloadType;
|
||||
MapWrapper _telephoneEventReported;
|
||||
std::set<WebRtc_UWord8> _telephoneEventReported;
|
||||
|
||||
WebRtc_Word8 _cngNBPayloadType;
|
||||
WebRtc_Word8 _cngWBPayloadType;
|
||||
|
@ -15,8 +15,6 @@
|
||||
#include "rtp_utility.h"
|
||||
|
||||
#include "typedefs.h"
|
||||
#include "map_wrapper.h"
|
||||
#include "list_wrapper.h"
|
||||
|
||||
#include "overuse_detector.h"
|
||||
#include "remote_rate_control.h"
|
||||
@ -25,12 +23,12 @@
|
||||
namespace webrtc {
|
||||
class ReceiverFEC;
|
||||
class ModuleRtpRtcpImpl;
|
||||
class CriticalSectionWrapper;
|
||||
|
||||
class RTPReceiverVideo
|
||||
{
|
||||
public:
|
||||
RTPReceiverVideo(const WebRtc_Word32 id,
|
||||
ModuleRtpRtcpImpl* owner);
|
||||
RTPReceiverVideo(const WebRtc_Word32 id, ModuleRtpRtcpImpl* owner);
|
||||
|
||||
virtual ~RTPReceiverVideo();
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user