blob: f0910eeae419e00e45a49196c51cf2b8ecfcbefb [file] [log] [blame]
/*
* 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();
}