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