/* * 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. */ /* * vie_sender.cc */ #include "vie_sender.h" #include "critical_section_wrapper.h" #include "rtp_rtcp.h" #ifdef WEBRTC_SRTP #include "SrtpModule.h" #endif #include "rtp_dump.h" #include "trace.h" namespace webrtc { // ---------------------------------------------------------------------------- // Constructor // ---------------------------------------------------------------------------- ViESender::ViESender(int engineId, int channelId, RtpRtcp& rtpRtcpModule) : _engineId(engineId), _channelId(channelId), _sendCritsect(*CriticalSectionWrapper::CreateCriticalSection()), _rtpRtcp(rtpRtcpModule), #ifdef WEBRTC_SRTP _ptrSrtp(NULL), _ptrSrtcp(NULL), #endif _ptrExternalEncryption(NULL), _ptrSrtpBuffer(NULL), _ptrSrtcpBuffer(NULL), _ptrEncryptionBuffer(NULL), _ptrTransport(NULL), _rtpDump(NULL) { } // ---------------------------------------------------------------------------- // Destructor // ---------------------------------------------------------------------------- ViESender::~ViESender() { delete &_sendCritsect; if (_ptrSrtpBuffer) { delete[] _ptrSrtpBuffer; _ptrSrtpBuffer = NULL; } if (_ptrSrtcpBuffer) { delete[] _ptrSrtcpBuffer; _ptrSrtcpBuffer = NULL; } if (_ptrEncryptionBuffer) { delete[] _ptrEncryptionBuffer; _ptrEncryptionBuffer = NULL; } if (_rtpDump) { _rtpDump->Stop(); RtpDump::DestroyRtpDump(_rtpDump); _rtpDump = NULL; } } // ---------------------------------------------------------------------------- // RegisterExternalEncryption // ---------------------------------------------------------------------------- int ViESender::RegisterExternalEncryption(Encryption* encryption) { CriticalSectionScoped cs(_sendCritsect); if (_ptrExternalEncryption) { return -1; } _ptrEncryptionBuffer = new WebRtc_UWord8[kViEMaxMtu]; if (_ptrEncryptionBuffer == NULL) { return -1; } _ptrExternalEncryption = encryption; return 0; } // ---------------------------------------------------------------------------- // DeregisterExternalEncryption // ---------------------------------------------------------------------------- int ViESender::DeregisterExternalEncryption() { CriticalSectionScoped cs(_sendCritsect); if (_ptrExternalEncryption == NULL) { return -1; } if (_ptrEncryptionBuffer) { delete _ptrEncryptionBuffer; _ptrEncryptionBuffer = NULL; } _ptrExternalEncryption = NULL; return 0; } // ---------------------------------------------------------------------------- // RegisterSendTransport // ---------------------------------------------------------------------------- int ViESender::RegisterSendTransport(Transport* transport) { CriticalSectionScoped cs(_sendCritsect); if (_ptrTransport) { return -1; } _ptrTransport = transport; return 0; } // ---------------------------------------------------------------------------- // DeregisterSendTransport // ---------------------------------------------------------------------------- int ViESender::DeregisterSendTransport() { CriticalSectionScoped cs(_sendCritsect); if (_ptrTransport == NULL) { return -1; } _ptrTransport = NULL; return 0; } #ifdef WEBRTC_SRTP // ---------------------------------------------------------------------------- // RegisterSRTPModule // ---------------------------------------------------------------------------- int ViESender::RegisterSRTPModule(SrtpModule* srtpModule) { CriticalSectionScoped cs(_sendCritsect); if (_ptrSrtp || srtpModule == NULL) { return -1; } _ptrSrtpBuffer = new WebRtc_UWord8[KMaxPacketSize]; if (_ptrSrtpBuffer == NULL) { return -1; } _ptrSrtp = srtpModule; return 0; } // ---------------------------------------------------------------------------- // DeregisterSRTPModule // ---------------------------------------------------------------------------- int ViESender::DeregisterSRTPModule() { CriticalSectionScoped cs(_sendCritsect); if (_ptrSrtp == NULL) { return -1; } if (_ptrSrtpBuffer) { delete [] _ptrSrtpBuffer; _ptrSrtpBuffer = NULL; } _ptrSrtp = NULL; return 0; } // ---------------------------------------------------------------------------- // RegisterSRTCPModule // ---------------------------------------------------------------------------- int ViESender::RegisterSRTCPModule(SrtpModule* srtcpModule) { CriticalSectionScoped cs(_sendCritsect); if (_ptrSrtcp || srtcpModule == NULL) { return -1; } _ptrSrtcpBuffer = new WebRtc_UWord8[KMaxPacketSize]; if (_ptrSrtcpBuffer == NULL) { return -1; } _ptrSrtcp = srtcpModule; return 0; } // ---------------------------------------------------------------------------- // DeregisterSRTCPModule // ---------------------------------------------------------------------------- int ViESender::DeregisterSRTCPModule() { CriticalSectionScoped cs(_sendCritsect); if (_ptrSrtcp == NULL) { return -1; } if (_ptrSrtcpBuffer) { delete [] _ptrSrtcpBuffer; _ptrSrtcpBuffer = NULL; } _ptrSrtcp = NULL; return 0; } #endif // ---------------------------------------------------------------------------- // StartRTPDump // ---------------------------------------------------------------------------- int ViESender::StartRTPDump(const char fileNameUTF8[1024]) { CriticalSectionScoped cs(_sendCritsect); if (_rtpDump) { // Restart it if it already exists and is started _rtpDump->Stop(); } else { _rtpDump = RtpDump::CreateRtpDump(); if (_rtpDump == NULL) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Failed to create RTP dump", __FUNCTION__); return -1; } } if (_rtpDump->Start(fileNameUTF8) != 0) { RtpDump::DestroyRtpDump(_rtpDump); _rtpDump = NULL; WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Failed to start RTP dump", __FUNCTION__); return -1; } return 0; } // ---------------------------------------------------------------------------- // StopRTPDump // ---------------------------------------------------------------------------- int ViESender::StopRTPDump() { CriticalSectionScoped cs(_sendCritsect); if (_rtpDump) { if (_rtpDump->IsActive()) { _rtpDump->Stop(); } else { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: Dump not active", __FUNCTION__); } RtpDump::DestroyRtpDump(_rtpDump); _rtpDump = NULL; } else { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "%s: RTP dump not started", __FUNCTION__); return -1; } return 0; } // ---------------------------------------------------------------------------- // SendPacket // ---------------------------------------------------------------------------- int ViESender::SendPacket(int vieId, const void *data, int len) { CriticalSectionScoped cs(_sendCritsect); if (!_ptrTransport) { // No transport return -1; } int channelId = ChannelId(vieId); assert(channelId == _channelId); // Prepare for possible encryption and sending WebRtc_UWord8* sendPacket = (WebRtc_UWord8*) data; int sendPacketLength = len; if (_rtpDump) { _rtpDump->DumpPacket(sendPacket, sendPacketLength); } #ifdef WEBRTC_SRTP if (_ptrSrtp) { _ptrSrtp->encrypt(_channelId, sendPacket, _ptrSrtpBuffer, sendPacketLength, (int*) &sendPacketLength); if (sendPacketLength <= 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "RTP encryption failed for channel"); return -1; } else if (sendPacketLength > KMaxPacketSize) { WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo, ViEId(_engineId, _channelId), " %d bytes is allocated as RTP output => memory is now corrupted", KMaxPacketSize); return -1; } sendPacket = _ptrSrtpBuffer; } #endif if (_ptrExternalEncryption) { _ptrExternalEncryption->encrypt(_channelId, sendPacket, _ptrEncryptionBuffer, sendPacketLength, (int*) &sendPacketLength); sendPacket = _ptrEncryptionBuffer; } return _ptrTransport->SendPacket(_channelId, sendPacket, sendPacketLength); } // ---------------------------------------------------------------------------- // SendRTCPPacket // ---------------------------------------------------------------------------- int ViESender::SendRTCPPacket(int vieId, const void *data, int len) { CriticalSectionScoped cs(_sendCritsect); if (!_ptrTransport) { // No transport return -1; } int channelId = ChannelId(vieId); assert(channelId == _channelId); // Prepare for possible encryption and sending WebRtc_UWord8* sendPacket = (WebRtc_UWord8*) data; int sendPacketLength = len; if (_rtpDump) { _rtpDump->DumpPacket(sendPacket, sendPacketLength); } #ifdef WEBRTC_SRTP if (_ptrSrtcp) { _ptrSrtcp->encrypt_rtcp(_channelId, sendPacket, _ptrSrtcpBuffer, sendPacketLength, (int*) &sendPacketLength); if (sendPacketLength <= 0) { WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideo, ViEId(_engineId, _channelId), "RTCP encryption failed for channel"); return -1; } else if (sendPacketLength > KMaxPacketSize) { WEBRTC_TRACE(webrtc::kTraceCritical, webrtc::kTraceVideo, ViEId(_engineId, _channelId), " %d bytes is allocated as RTCP output => memory is now corrupted", KMaxPacketSize); return -1; } sendPacket = _ptrSrtcpBuffer; } #endif if (_ptrExternalEncryption) { _ptrExternalEncryption->encrypt_rtcp(_channelId, sendPacket, _ptrEncryptionBuffer, sendPacketLength, (int*) &sendPacketLength); sendPacket = _ptrEncryptionBuffer; } return _ptrTransport->SendRTCPPacket(_channelId, sendPacket, sendPacketLength); } } // namespace webrtc