318 lines
8.5 KiB
C++
318 lines
8.5 KiB
C++
/*
|
|
* Copyright (c) 2011 The WebRTC project authors. All Rights Reserved.
|
|
*
|
|
* Use of this source code is governed by a BSD-style license
|
|
* that can be found in the LICENSE file in the root of the source
|
|
* tree. An additional intellectual property rights grant can be found
|
|
* in the file PATENTS. All contributing project authors may
|
|
* be found in the AUTHORS file in the root of the source tree.
|
|
*/
|
|
|
|
//
|
|
// tbExternalTransport.cpp
|
|
//
|
|
|
|
#include "tbExternalTransport.h"
|
|
|
|
#include "critical_section_wrapper.h"
|
|
#include "event_wrapper.h"
|
|
#include "thread_wrapper.h"
|
|
#include "tick_util.h"
|
|
#include "vie_network.h"
|
|
#include "tick_util.h"
|
|
|
|
using namespace webrtc;
|
|
|
|
tbExternalTransport::tbExternalTransport(ViENetwork& vieNetwork)
|
|
:
|
|
_vieNetwork(vieNetwork),
|
|
_thread(*ThreadWrapper::CreateThread(ViEExternalTransportRun, this, kHighPriority, "AutotestTransport")),
|
|
_event(*EventWrapper::Create()),
|
|
_crit(*CriticalSectionWrapper::CreateCriticalSection()),
|
|
_statCrit(*CriticalSectionWrapper::CreateCriticalSection()),
|
|
_lossRate(0),
|
|
_networkDelayMs(0),
|
|
_rtpCount(0),
|
|
_dropCount(0),
|
|
_rtcpCount(0),
|
|
_rtpPackets(),
|
|
_rtcpPackets(),
|
|
_checkSSRC(false),
|
|
_lastSSRC(0),
|
|
_checkSequenceNumber(0),
|
|
_firstSequenceNumber(0),
|
|
_lastSeq(0)
|
|
{
|
|
srand((int)TickTime::MicrosecondTimestamp());
|
|
unsigned int tId = 0;
|
|
_thread.Start(tId);
|
|
}
|
|
|
|
|
|
tbExternalTransport::~tbExternalTransport()
|
|
{
|
|
// TODO: stop thread
|
|
_thread.SetNotAlive();
|
|
_event.Set();
|
|
if (_thread.Stop())
|
|
{
|
|
delete &_thread;
|
|
delete &_event;
|
|
}
|
|
delete &_crit;
|
|
delete &_statCrit;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int tbExternalTransport::SendPacket(int channel, const void *data, int len)
|
|
{
|
|
_statCrit.Enter();
|
|
_rtpCount++;
|
|
_statCrit.Leave();
|
|
|
|
|
|
unsigned short sequenceNumber = (((unsigned char*) data)[2]) << 8;
|
|
sequenceNumber += (((unsigned char*) data)[3]);
|
|
|
|
|
|
int marker=((unsigned char*)data)[1] & 0x80;
|
|
unsigned int timestamp=((((unsigned char*)data)[4]) << 24) + ((((unsigned char*)data)[5])<<16) +((((unsigned char*)data)[6])<<8)+(((unsigned char*)data)[7]);
|
|
|
|
|
|
// Packet loss
|
|
int dropThis = rand() % 100;
|
|
bool nacked=false;
|
|
if(sequenceNumber<_lastSeq)
|
|
{
|
|
nacked=true;
|
|
}
|
|
else
|
|
{
|
|
_lastSeq=sequenceNumber;
|
|
}
|
|
|
|
if (dropThis < _lossRate)
|
|
{
|
|
_statCrit.Enter();
|
|
_dropCount++;
|
|
_statCrit.Leave();
|
|
|
|
|
|
/* char str[256];
|
|
sprintf(str,"Dropping seq %d length %d m %d, ts %u\n", sequenceNumber,len,marker,timestamp) ;
|
|
OutputDebugString(str);*/
|
|
|
|
return len;
|
|
}
|
|
else
|
|
{
|
|
if(nacked)
|
|
{
|
|
/*char str[256];
|
|
sprintf(str,"Resending seq %d length %d m %d, ts %u\n", sequenceNumber,len,marker,timestamp) ;
|
|
OutputDebugString(str);*/
|
|
}
|
|
else
|
|
{
|
|
/*char str[256];
|
|
sprintf(str,"Sending seq %d length %d m %d, ts %u\n", sequenceNumber,len,marker,timestamp) ;
|
|
OutputDebugString(str);*/
|
|
|
|
}
|
|
}
|
|
|
|
|
|
VideoPacket* newPacket = new VideoPacket();
|
|
memcpy(newPacket->packetBuffer, data, len);
|
|
newPacket->length = len;
|
|
newPacket->channel = channel;
|
|
|
|
_crit.Enter();
|
|
newPacket->receiveTime = NowMs() + _networkDelayMs;
|
|
_rtpPackets.push(newPacket);
|
|
_event.Set();
|
|
_crit.Leave();
|
|
return len;
|
|
}
|
|
|
|
int tbExternalTransport::SendRTCPPacket(int channel, const void *data, int len)
|
|
{
|
|
_statCrit.Enter();
|
|
_rtcpCount++;
|
|
_statCrit.Leave();
|
|
|
|
VideoPacket* newPacket = new VideoPacket();
|
|
memcpy(newPacket->packetBuffer, data, len);
|
|
newPacket->length = len;
|
|
newPacket->channel = channel;
|
|
|
|
_crit.Enter();
|
|
newPacket->receiveTime = NowMs() + _networkDelayMs;
|
|
_rtcpPackets.push(newPacket);
|
|
_event.Set();
|
|
_crit.Leave();
|
|
return len;
|
|
}
|
|
|
|
WebRtc_Word32 tbExternalTransport::SetPacketLoss(WebRtc_Word32 lossRate)
|
|
{
|
|
CriticalSectionScoped cs(_statCrit);
|
|
_lossRate = lossRate;
|
|
return 0;
|
|
}
|
|
|
|
void tbExternalTransport::SetNetworkDelay(WebRtc_Word64 delayMs)
|
|
{
|
|
CriticalSectionScoped cs(_crit);
|
|
_networkDelayMs = delayMs;
|
|
return;
|
|
}
|
|
|
|
void tbExternalTransport::ClearStats()
|
|
{
|
|
CriticalSectionScoped cs(_statCrit);
|
|
_rtpCount = 0;
|
|
_dropCount = 0;
|
|
_rtcpCount = 0;
|
|
return;
|
|
}
|
|
|
|
void tbExternalTransport::GetStats(WebRtc_Word32& numRtpPackets, WebRtc_Word32& numDroppedPackets, WebRtc_Word32& numRtcpPackets)
|
|
{
|
|
CriticalSectionScoped cs(_statCrit);
|
|
numRtpPackets = _rtpCount;
|
|
numDroppedPackets = _dropCount;
|
|
numRtcpPackets = _rtcpCount;
|
|
return;
|
|
}
|
|
|
|
void tbExternalTransport::EnableSSRCCheck()
|
|
{
|
|
CriticalSectionScoped cs(_statCrit);
|
|
_checkSSRC = true;
|
|
}
|
|
unsigned int tbExternalTransport::ReceivedSSRC()
|
|
{
|
|
CriticalSectionScoped cs(_statCrit);
|
|
return _lastSSRC;
|
|
}
|
|
|
|
void tbExternalTransport::EnableSequenceNumberCheck()
|
|
{
|
|
CriticalSectionScoped cs(_statCrit);
|
|
_checkSequenceNumber = true;
|
|
}
|
|
|
|
unsigned short tbExternalTransport::GetFirstSequenceNumber()
|
|
{
|
|
CriticalSectionScoped cs(_statCrit);
|
|
return _firstSequenceNumber;
|
|
}
|
|
|
|
|
|
bool tbExternalTransport::ViEExternalTransportRun(void* object)
|
|
{
|
|
return static_cast<tbExternalTransport*>(object)->ViEExternalTransportProcess();
|
|
}
|
|
bool tbExternalTransport::ViEExternalTransportProcess()
|
|
{
|
|
unsigned int waitTime = KMaxWaitTimeMs;
|
|
|
|
VideoPacket* packet = NULL;
|
|
|
|
while (!_rtpPackets.empty())
|
|
{
|
|
// Take first packet in queue
|
|
_crit.Enter();
|
|
packet = _rtpPackets.front();
|
|
WebRtc_Word64 timeToReceive = packet->receiveTime - NowMs();
|
|
if (timeToReceive > 0)
|
|
{
|
|
// No packets to receive yet
|
|
if (timeToReceive < waitTime &&
|
|
timeToReceive > 0)
|
|
{
|
|
waitTime = (unsigned int) timeToReceive;
|
|
}
|
|
_crit.Leave();
|
|
break;
|
|
}
|
|
_rtpPackets.pop();
|
|
_crit.Leave();
|
|
|
|
// Send to ViE
|
|
if (packet)
|
|
{
|
|
{
|
|
CriticalSectionScoped cs(_statCrit);
|
|
if (_checkSSRC)
|
|
{
|
|
_lastSSRC = ((packet->packetBuffer[8]) << 24);
|
|
_lastSSRC += (packet->packetBuffer[9] << 16);
|
|
_lastSSRC += (packet->packetBuffer[10] << 8);
|
|
_lastSSRC += packet->packetBuffer[11];
|
|
_checkSSRC = false;
|
|
}
|
|
if (_checkSequenceNumber)
|
|
{
|
|
_firstSequenceNumber = (unsigned char)packet->packetBuffer[2] << 8;
|
|
_firstSequenceNumber += (unsigned char)packet->packetBuffer[3];
|
|
_checkSequenceNumber = false;
|
|
}
|
|
}
|
|
/*
|
|
unsigned short sequenceNumber = (unsigned char)packet->packetBuffer[2] << 8;
|
|
sequenceNumber += (unsigned char)packet->packetBuffer[3];
|
|
|
|
int marker=packet->packetBuffer[1] & 0x80;
|
|
unsigned int timestamp=((((unsigned char*)packet->packetBuffer)[4]) << 24) + ((((unsigned char*)packet->packetBuffer)[5])<<16) +((((unsigned char*)packet->packetBuffer)[6])<<8)+(((unsigned char*)packet->packetBuffer)[7]);
|
|
char str[256];
|
|
sprintf(str,"Receiving seq %u length %d m %d, ts %u\n", sequenceNumber,packet->length,marker,timestamp) ;
|
|
OutputDebugString(str);*/
|
|
|
|
_vieNetwork.ReceivedRTPPacket(packet->channel, packet->packetBuffer, packet->length);
|
|
delete packet;
|
|
packet = NULL;
|
|
}
|
|
}
|
|
while (!_rtcpPackets.empty())
|
|
{
|
|
// Take first packet in queue
|
|
_crit.Enter();
|
|
packet = _rtcpPackets.front();
|
|
WebRtc_Word64 timeToReceive = packet->receiveTime - NowMs();
|
|
if (timeToReceive > 0)
|
|
{
|
|
// No packets to receive yet
|
|
if (timeToReceive < waitTime &&
|
|
timeToReceive > 0)
|
|
{
|
|
waitTime = (unsigned int) timeToReceive;
|
|
}
|
|
_crit.Leave();
|
|
break;
|
|
}
|
|
packet = _rtcpPackets.front();
|
|
_rtcpPackets.pop();
|
|
_crit.Leave();
|
|
|
|
// Send to ViE
|
|
if (packet)
|
|
{
|
|
_vieNetwork.ReceivedRTCPPacket(packet->channel, packet->packetBuffer, packet->length);
|
|
delete packet;
|
|
packet = NULL;
|
|
}
|
|
}
|
|
_event.Wait(waitTime + 1); // Add 1 ms to not call to early...
|
|
return true;
|
|
}
|
|
|
|
WebRtc_Word64 tbExternalTransport::NowMs()
|
|
{
|
|
return TickTime::MillisecondTimestamp();
|
|
}
|