/* * Copyright (c) 2012 Yoann Blein * Licensed under the simplified BSD license. * See Documentation/Licenses/BSD-simplified.txt for more information. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace Swift { Sender::Sender(boost::shared_ptr udpSocket) : udpSocket(udpSocket), jRTPLocalAddress(RTPSessionImpl::nativeAddressToJRTPAddress(udpSocket->getLocalAddress())) { } Sender::~Sender() { delete jRTPLocalAddress; } bool Sender::SendRTP(const void *data, size_t len) { send(data, len); return true; } bool Sender::SendRTCP(const void* data, size_t len) { send(data, len); return true; } bool Sender::ComesFromThisSender (const jrtplib::RTPAddress* address) { return jRTPLocalAddress->IsSameAddress(address); } void Sender::send(const void* data, size_t len) { uint8_t* uint8Data = (uint8_t*)data; udpSocket->send(SafeByteArray(uint8Data, uint8Data + len)); } RTPSessionImpl::RTPSessionImpl(boost::shared_ptr udpSocket, const RTPPayloadType& payloadType) : udpSocket(udpSocket), payloadType(payloadType), jRTPRemotePeer(nativeAddressToJRTPAddress(udpSocket->getRemoteAddress())), sender(udpSocket) { jrtplib::RTPExternalTransmissionParams transparams(&sender, 0); jrtplib::RTPSessionParams sessparams; // IMPORTANT: The local timestamp unit MUST be set, otherwise RTCP Sender Report info will be calculated wrong sessparams.SetOwnTimestampUnit(1.0 / payloadType.getClockrate()); checkError(Create(sessparams, &transparams, jrtplib::RTPTransmitter::ExternalProto)); packetInjecter = static_cast(GetTransmissionInfo())->GetPacketInjector(); udpSocket->onDataRead.connect(boost::bind(&RTPSessionImpl::handleDataRead, this, _1)); udpSocket->listen(); } RTPSessionImpl::~RTPSessionImpl() { delete jRTPRemotePeer; } void RTPSessionImpl::poll() { checkError(Poll()); // Required if threading disabled } void RTPSessionImpl::checkIncomingPackets() { // session.BeginDataAccess(); // useless without threading if (GotoFirstSourceWithData() && GetCurrentSourceInfo()->GetRTPDataAddress()->IsSameAddress(jRTPRemotePeer)) { do { jrtplib::RTPPacket *pack; while ((pack = GetNextPacket()) != NULL) { onIncomingPacket(pack->GetPayloadData(), pack->GetPayloadLength(), pack->HasMarker()); DeletePacket(pack); } } while (GotoNextSourceWithData()); } // session.EndDataAccess(); // useless without threading } void RTPSessionImpl::sendPacket(const SafeByteArray& data, int timestampinc, bool marker) { checkError(SendPacket((void*)(data.data()), data.size(), payloadType.getID(), marker, timestampinc)); poll(); } void RTPSessionImpl::injectData(const SafeByteArray& data) { packetInjecter->InjectRTPorRTCP((void*)(data.data()), data.size(), *jRTPRemotePeer); checkIncomingPackets(); poll(); } void RTPSessionImpl::stop(int maxWaitMs) { BYEDestroy(jrtplib::RTPTime(0, maxWaitMs * 1000), "", 0); udpSocket->close(); } void RTPSessionImpl::sendSLIFeedback(int pictureID) { // Send an SLI as negative feedback. VP8: 0, total number of macroblocks, pictureID (6 bits) int first = 0; // 13 bits int number = 0; // 13 bits // TODO : Find the total number of macroblocks per frame uint32_t data = 0; data |= first << 19; data |= (number & 2047) << 6; data |= (pictureID & 63); SendUnknownPacket(false, PSFB, PSFB_SLI, (void*)&data, sizeof(uint32_t)); } void RTPSessionImpl::sendRPSIFeedback(int pictureID) { // Send an RPSI as positive feedback. With VP8, it only contains the picture ID (7 bits) int pb = 9; // trailing padding bits int pt = payloadType.getID(); // payload type (7 bits) uint32_t data = 0; data |= pb << 24; data |= (pt & 127) << 16; data |= (pictureID & 127) << 9; SendUnknownPacket(false, PSFB, PSFB_RPSI, (void*)&data, sizeof(uint32_t)); } size_t RTPSessionImpl::getMaxRTPPayloadSize() const { jrtplib::RTPSessionParams sessparams; return sessparams.GetMaximumPacketSize(); } void RTPSessionImpl::OnUnknownPacketType(jrtplib::RTCPPacket* rtcpPack, const jrtplib::RTPTime& /*receivetime*/, const jrtplib::RTPAddress* senderAddress) { if (!senderAddress->IsSameAddress(jRTPRemotePeer)) return; uint8_t* data = rtcpPack->GetPacketData(); size_t len = rtcpPack->GetPacketLength(); jrtplib::RTCPCommonHeader* rtcpHdr = (jrtplib::RTCPCommonHeader*)data; int type = rtcpHdr->packettype; if (type != PSFB) return; int subtype = rtcpHdr->count; switch (subtype) { case PSFB_SLI: parseSLIFeedBack(data + 8, len - 8); break; case PSFB_RPSI: parseRPSIFeedBack(data + 8, len - 8); break; default: break; } } void RTPSessionImpl::checkError(int rtperr) const { if (rtperr < 0) throw RTPException(jrtplib::RTPGetErrorString(rtperr)); } void RTPSessionImpl::handleDataRead(boost::shared_ptr data) { injectData(*data); } void RTPSessionImpl::parseSLIFeedBack(uint8_t* data, size_t len) { SWIFT_LOG(debug) << "Got SLI feedback (negative)" << std::endl; if (len < 4) return; int pictureID = data[len - 1] & 63; // pictureID correspond to the 6 last bits onSLIFeedback(pictureID); } void RTPSessionImpl::parseRPSIFeedBack(uint8_t* data, size_t len) { SWIFT_LOG(debug) << "Got RPSI feedback (postive)" << std::endl; if (len < 4) return; int pb = data[0]; // First byte : trailing padding bits uint32_t intData = *((uint32_t*)(data)); intData >>= pb; // remove padding bits int pictureID = (intData & 127); // pictureID correspond to the 7 last bits onRPSIFeedback(pictureID); } jrtplib::RTPAddress* RTPSessionImpl::nativeAddressToJRTPAddress(const HostAddressPort& hostAddressPort) { jrtplib::RTPAddress* jrtpAddress = 0; std::string ipAddress = hostAddressPort.getAddress().toString(); uint16_t port = boost::numeric_cast(hostAddressPort.getPort()); if (hostAddressPort.getAddress().getRawAddress().is_v4()) { // Split address std::vector subStrings; boost::algorithm::split(subStrings, ipAddress, boost::is_any_of(".")); // Cast sub strings array to array of byte uint8_t ipNumbers[4]; for (int i = 0; i < std::min(4, (int)subStrings.size()); ++i) ipNumbers[i] = boost::numeric_cast(boost::lexical_cast(subStrings[i])); jrtpAddress = new jrtplib::RTPIPv4Address(ipNumbers, port); } else if (hostAddressPort.getAddress().getRawAddress().is_v6()) { in6_addr addr; inet_pton(AF_INET6, ipAddress.c_str(), &addr); jrtpAddress = new jrtplib::RTPIPv6Address(addr, port); } return jrtpAddress; } }