summaryrefslogtreecommitdiffstats
blob: 62b05d5d1fafc901b2314180ba10260bba562a92 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/*
 * Copyright (c) 2012 Yoann Blein
 * Licensed under the simplified BSD license.
 * See Documentation/Licenses/BSD-simplified.txt for more information.
 */

#include <Swiften/ScreenSharing/RTPSessionImpl.h>

#include <Swiften/ScreenSharing/RTPException.h>
#include <Swiften/Network/BoostUDPSocket.h>
#include <Swiften/Base/boost_bsignals.h>
#include <Swiften/Network/UDPSocket.h>

#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/numeric/conversion/cast.hpp>
#include <boost/bind.hpp>

#include <rtppacket.h>
#include <rtpsourcedata.h>
#include <rtpsessionparams.h>

namespace Swift {

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 RTPSessionImpl::nativeAddressToJRTPAddress(udpSocket->getLocalAddress()).IsSameAddress(address);
}

void Sender::send(const void* data, size_t len) {
	unsigned char *uint8Data = (unsigned char*)data;
	udpSocket->send(SafeByteArray(uint8Data, uint8Data + len));
}

RTPSessionImpl::RTPSessionImpl(boost::shared_ptr<UDPSocket> 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(session.Create(sessparams, &transparams, jrtplib::RTPTransmitter::ExternalProto));

	packetInjecter = static_cast<jrtplib::RTPExternalTransmissionInfo*>(session.GetTransmissionInfo())->GetPacketInjector();

	udpSocket->onDataRead.connect(boost::bind(&RTPSessionImpl::handleDataRead, this, _1));
}

RTPSessionImpl::~RTPSessionImpl()
{
}

void RTPSessionImpl::poll()
{
	checkError(session.Poll()); // Required if threading disabled
}

void RTPSessionImpl::checkIncomingPackets()
{
	// session.BeginDataAccess(); // useless without threading
	if (session.GotoFirstSourceWithData() && session.GetCurrentSourceInfo()->GetRTPDataAddress()->IsSameAddress(&jRTPRemotePeer)) {
		do {
			jrtplib::RTPPacket *pack;
			while ((pack = session.GetNextPacket()) != NULL) {
				onIncomingPacket(pack->GetPayloadData(), pack->GetPayloadLength(), pack->HasMarker());
				session.DeletePacket(pack);
			}
		} while (session.GotoNextSourceWithData());
	}
	// session.EndDataAccess(); // useless without threading
}

void RTPSessionImpl::sendPacket(const SafeByteArray& data, int timestampinc, bool marker)
{
	checkError(session.SendPacket((void*)(&data[0]), data.size(), payloadType.getID(), marker, timestampinc));
	poll();
}

void RTPSessionImpl::injectData(const SafeByteArray& data)
{
	packetInjecter->InjectRTPorRTCP((void*)(&data[0]), data.size(), jRTPRemotePeer);
	checkIncomingPackets();
	poll();
}

void RTPSessionImpl::stop(int maxWaitMs)
{
	session.BYEDestroy(jrtplib::RTPTime(0, maxWaitMs * 1000), "", 0);
	// TODO: shutdown socket
}

void RTPSessionImpl::checkError(int rtperr) const
{
	if (rtperr < 0)
		throw RTPException(jrtplib::RTPGetErrorString(rtperr));
}

void RTPSessionImpl::handleDataRead(boost::shared_ptr<SafeByteArray> data)
{
	injectData(*data);
}

jrtplib::RTPIPv4Address RTPSessionImpl::nativeAddressToJRTPAddress(const HostAddressPort& hostAddressPort)
{
	// Split address
	std::vector<std::string> subStrings;
	std::string ipAddress = hostAddressPort.getAddress().toString();
	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<uint8_t>(boost::lexical_cast<int>(subStrings[i]));

	return jrtplib::RTPIPv4Address(ipNumbers, boost::numeric_cast<uint16_t>(hostAddressPort.getPort()));
}

}