diff options
author | Andreas Huber <andih@google.com> | 2010-10-11 12:37:50 -0700 |
---|---|---|
committer | Android Git Automerger <android-git-automerger@android.com> | 2010-10-11 12:37:50 -0700 |
commit | 5b0d063010b364102ffb7a533e2b76ecfd9636d5 (patch) | |
tree | 9c73712caf102aca4edea86d15aaaaa5c524db14 /media | |
parent | 431dd3b1bc8f2acf7cbcf08463649b5629baf398 (diff) | |
parent | 1010da2e02216b2f94fbe763a82d53201b340217 (diff) | |
download | frameworks_base-5b0d063010b364102ffb7a533e2b76ecfd9636d5.zip frameworks_base-5b0d063010b364102ffb7a533e2b76ecfd9636d5.tar.gz frameworks_base-5b0d063010b364102ffb7a533e2b76ecfd9636d5.tar.bz2 |
am 1010da2e: Merge "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." into gingerbread
Merge commit '1010da2e02216b2f94fbe763a82d53201b340217' into gingerbread-plus-aosp
* commit '1010da2e02216b2f94fbe763a82d53201b340217':
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.
Diffstat (limited to 'media')
-rw-r--r-- | media/libstagefright/rtsp/MyHandler.h | 153 |
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, |