summaryrefslogtreecommitdiffstats
path: root/media/libstagefright/rtsp
diff options
context:
space:
mode:
authorAndreas Huber <andih@google.com>2010-10-11 11:05:52 -0700
committerAndreas Huber <andih@google.com>2010-10-11 11:30:30 -0700
commit2bc940b4f961e588459c83862b2c6bea314a4027 (patch)
tree53dd017ef6b9e961b885159a4cbb3d6efecac053 /media/libstagefright/rtsp
parent0dcd837af4169bdb6fb2a0c384722dc4f57433c6 (diff)
downloadframeworks_av-2bc940b4f961e588459c83862b2c6bea314a4027.zip
frameworks_av-2bc940b4f961e588459c83862b2c6bea314a4027.tar.gz
frameworks_av-2bc940b4f961e588459c83862b2c6bea314a4027.tar.bz2
Just in case we're behind a NAT router/firewall, attempt to poke holes into it for future incoming RTP/RTCP packets to pass through.
Change-Id: Idd47968d4027f357222f19f15eecfd70fdec3282 related-to-bug: 3073813
Diffstat (limited to 'media/libstagefright/rtsp')
-rw-r--r--media/libstagefright/rtsp/MyHandler.h153
1 files changed, 153 insertions, 0 deletions
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 05dd61b..0f4c1f3 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -28,6 +28,7 @@
#include "ASessionDescription.h"
#include <ctype.h>
+#include <cutils/properties.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -35,6 +36,9 @@
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+
// If no access units are received within 3 secs, assume that the rtp
// stream has ended and signal end of stream.
static int64_t kAccessUnitTimeoutUs = 3000000ll;
@@ -45,6 +49,19 @@ static int64_t kStartupTimeoutUs = 10000000ll;
namespace android {
+static void MakeUserAgentString(AString *s) {
+ s->setTo("stagefright/1.1 (Linux;Android ");
+
+#if (PROPERTY_VALUE_MAX < 8)
+#error "PROPERTY_VALUE_MAX must be at least 8"
+#endif
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.build.version.release", value, "Unknown");
+ s->append(value);
+ s->append(")");
+}
+
static bool GetAttribute(const char *s, const char *key, AString *value) {
value->clear();
@@ -137,6 +154,131 @@ struct MyHandler : public AHandler {
return maxTimeUs;
}
+ static void addRR(const sp<ABuffer> &buf) {
+ uint8_t *ptr = buf->data() + buf->size();
+ ptr[0] = 0x80 | 0;
+ ptr[1] = 201; // RR
+ ptr[2] = 0;
+ ptr[3] = 1;
+ ptr[4] = 0xde; // SSRC
+ ptr[5] = 0xad;
+ ptr[6] = 0xbe;
+ ptr[7] = 0xef;
+
+ buf->setRange(0, buf->size() + 8);
+ }
+
+ static void addSDES(int s, const sp<ABuffer> &buffer) {
+ struct sockaddr_in addr;
+ socklen_t addrSize = sizeof(addr);
+ CHECK_EQ(0, getsockname(s, (sockaddr *)&addr, &addrSize));
+
+ uint8_t *data = buffer->data() + buffer->size();
+ data[0] = 0x80 | 1;
+ data[1] = 202; // SDES
+ data[4] = 0xde; // SSRC
+ data[5] = 0xad;
+ data[6] = 0xbe;
+ data[7] = 0xef;
+
+ size_t offset = 8;
+
+ data[offset++] = 1; // CNAME
+
+ AString cname = "stagefright@";
+ cname.append(inet_ntoa(addr.sin_addr));
+ data[offset++] = cname.size();
+
+ memcpy(&data[offset], cname.c_str(), cname.size());
+ offset += cname.size();
+
+ data[offset++] = 6; // TOOL
+
+ AString tool;
+ MakeUserAgentString(&tool);
+
+ data[offset++] = tool.size();
+
+ memcpy(&data[offset], tool.c_str(), tool.size());
+ offset += tool.size();
+
+ data[offset++] = 0;
+
+ if ((offset % 4) > 0) {
+ size_t count = 4 - (offset % 4);
+ switch (count) {
+ case 3:
+ data[offset++] = 0;
+ case 2:
+ data[offset++] = 0;
+ case 1:
+ data[offset++] = 0;
+ }
+ }
+
+ size_t numWords = (offset / 4) - 1;
+ data[2] = numWords >> 8;
+ data[3] = numWords & 0xff;
+
+ buffer->setRange(buffer->offset(), buffer->size() + offset);
+ }
+
+ // In case we're behind NAT, fire off two UDP packets to the remote
+ // rtp/rtcp ports to poke a hole into the firewall for future incoming
+ // packets. We're going to send an RR/SDES RTCP packet to both of them.
+ void pokeAHole(int rtpSocket, int rtcpSocket, const AString &transport) {
+ AString source;
+ AString server_port;
+ if (!GetAttribute(transport.c_str(),
+ "source",
+ &source)
+ || !GetAttribute(transport.c_str(),
+ "server_port",
+ &server_port)) {
+ return;
+ }
+
+ int rtpPort, rtcpPort;
+ if (sscanf(server_port.c_str(), "%d-%d", &rtpPort, &rtcpPort) != 2
+ || rtpPort <= 0 || rtpPort > 65535
+ || rtcpPort <=0 || rtcpPort > 65535
+ || rtcpPort != rtpPort + 1
+ || (rtpPort & 1) != 0) {
+ return;
+ }
+
+ struct sockaddr_in addr;
+ memset(addr.sin_zero, 0, sizeof(addr.sin_zero));
+ addr.sin_family = AF_INET;
+ addr.sin_addr.s_addr = inet_addr(source.c_str());
+
+ if (addr.sin_addr.s_addr == INADDR_NONE) {
+ return;
+ }
+
+ // Make up an RR/SDES RTCP packet.
+ sp<ABuffer> buf = new ABuffer(65536);
+ buf->setRange(0, 0);
+ addRR(buf);
+ addSDES(rtpSocket, buf);
+
+ addr.sin_port = htons(rtpPort);
+
+ ssize_t n = sendto(
+ rtpSocket, buf->data(), buf->size(), 0,
+ (const sockaddr *)&addr, sizeof(addr));
+ CHECK_EQ(n, (ssize_t)buf->size());
+
+ addr.sin_port = htons(rtcpPort);
+
+ n = sendto(
+ rtcpSocket, buf->data(), buf->size(), 0,
+ (const sockaddr *)&addr, sizeof(addr));
+ CHECK_EQ(n, (ssize_t)buf->size());
+
+ LOGV("successfully poked holes.");
+ }
+
virtual void onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case 'conn':
@@ -285,6 +427,17 @@ struct MyHandler : public AHandler {
sp<AMessage> notify = new AMessage('accu', id());
notify->setSize("track-index", trackIndex);
+ i = response->mHeaders.indexOfKey("transport");
+ CHECK_GE(i, 0);
+
+ if (!track->mUsingInterleavedTCP) {
+ AString transport = response->mHeaders.valueAt(i);
+
+ pokeAHole(track->mRTPSocket,
+ track->mRTCPSocket,
+ transport);
+ }
+
mRTPConn->addStream(
track->mRTPSocket, track->mRTCPSocket,
mSessionDesc, index,