/* * 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(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(); }