ARTPSession.cpp revision 6e4c5c499999c04c2477b987f9e64f3ff2bf1a06
1/* 2 * Copyright (C) 2010 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17//#define LOG_NDEBUG 0 18#define LOG_TAG "ARTPSession" 19#include <utils/Log.h> 20 21#include "ARTPSession.h" 22 23#include <media/stagefright/foundation/ABuffer.h> 24#include <media/stagefright/foundation/ADebug.h> 25#include <media/stagefright/foundation/AMessage.h> 26#include <media/stagefright/foundation/hexdump.h> 27 28#include <ctype.h> 29#include <arpa/inet.h> 30#include <sys/socket.h> 31 32#include "APacketSource.h" 33#include "ARTPConnection.h" 34#include "ASessionDescription.h" 35 36namespace android { 37 38ARTPSession::ARTPSession() 39 : mInitCheck(NO_INIT) { 40} 41 42status_t ARTPSession::setup(const sp<ASessionDescription> &desc) { 43 CHECK_EQ(mInitCheck, (status_t)NO_INIT); 44 45 mDesc = desc; 46 47 mRTPConn = new ARTPConnection( 48 ARTPConnection::kFakeTimestamps 49 | ARTPConnection::kRegularlyRequestFIR); 50 51 looper()->registerHandler(mRTPConn); 52 53 for (size_t i = 1; i < mDesc->countTracks(); ++i) { 54 AString connection; 55 if (!mDesc->findAttribute(i, "c=", &connection)) { 56 // No per-stream connection information, try global fallback. 57 if (!mDesc->findAttribute(0, "c=", &connection)) { 58 LOGE("Unable to find connection attribute."); 59 return mInitCheck; 60 } 61 } 62 if (!(connection == "IN IP4 127.0.0.1")) { 63 LOGE("We only support localhost connections for now."); 64 return mInitCheck; 65 } 66 67 unsigned port; 68 if (!validateMediaFormat(i, &port) || (port & 1) != 0) { 69 LOGE("Invalid media format."); 70 return mInitCheck; 71 } 72 73 sp<APacketSource> source = new APacketSource(mDesc, i); 74 if (source->initCheck() != OK) { 75 LOGE("Unsupported format."); 76 return mInitCheck; 77 } 78 79 int rtpSocket = MakeUDPSocket(port); 80 int rtcpSocket = MakeUDPSocket(port + 1); 81 82 mTracks.push(TrackInfo()); 83 TrackInfo *info = &mTracks.editItemAt(mTracks.size() - 1); 84 info->mRTPSocket = rtpSocket; 85 info->mRTCPSocket = rtcpSocket; 86 87 sp<AMessage> notify = new AMessage(kWhatAccessUnitComplete, id()); 88 notify->setSize("track-index", mTracks.size() - 1); 89 90 mRTPConn->addStream( 91 rtpSocket, rtcpSocket, mDesc, i, notify, false /* injected */); 92 93 info->mPacketSource = source; 94 } 95 96 mInitCheck = OK; 97 98 return OK; 99} 100 101// static 102int ARTPSession::MakeUDPSocket(unsigned port) { 103 int s = socket(AF_INET, SOCK_DGRAM, 0); 104 CHECK_GE(s, 0); 105 106 struct sockaddr_in addr; 107 memset(addr.sin_zero, 0, sizeof(addr.sin_zero)); 108 addr.sin_family = AF_INET; 109 addr.sin_addr.s_addr = INADDR_ANY; 110 addr.sin_port = htons(port); 111 112 CHECK_EQ(0, bind(s, (const struct sockaddr *)&addr, sizeof(addr))); 113 114 return s; 115} 116 117ARTPSession::~ARTPSession() { 118 for (size_t i = 0; i < mTracks.size(); ++i) { 119 TrackInfo *info = &mTracks.editItemAt(i); 120 121 info->mPacketSource->signalEOS(UNKNOWN_ERROR); 122 123 close(info->mRTPSocket); 124 close(info->mRTCPSocket); 125 } 126} 127 128void ARTPSession::onMessageReceived(const sp<AMessage> &msg) { 129 switch (msg->what()) { 130 case kWhatAccessUnitComplete: 131 { 132 int32_t firstRTCP; 133 if (msg->findInt32("first-rtcp", &firstRTCP)) { 134 // There won't be an access unit here, it's just a notification 135 // that the data communication worked since we got the first 136 // rtcp packet. 137 break; 138 } 139 140 size_t trackIndex; 141 CHECK(msg->findSize("track-index", &trackIndex)); 142 143 int32_t eos; 144 if (msg->findInt32("eos", &eos) && eos) { 145 TrackInfo *info = &mTracks.editItemAt(trackIndex); 146 info->mPacketSource->signalEOS(ERROR_END_OF_STREAM); 147 break; 148 } 149 150 sp<RefBase> obj; 151 CHECK(msg->findObject("access-unit", &obj)); 152 153 sp<ABuffer> accessUnit = static_cast<ABuffer *>(obj.get()); 154 155 uint64_t ntpTime; 156 CHECK(accessUnit->meta()->findInt64( 157 "ntp-time", (int64_t *)&ntpTime)); 158 159#if 0 160#if 0 161 printf("access unit complete size=%d\tntp-time=0x%016llx\n", 162 accessUnit->size(), ntpTime); 163#else 164 LOGI("access unit complete, size=%d, ntp-time=%llu", 165 accessUnit->size(), ntpTime); 166 hexdump(accessUnit->data(), accessUnit->size()); 167#endif 168#endif 169 170#if 0 171 CHECK_GE(accessUnit->size(), 5u); 172 CHECK(!memcmp("\x00\x00\x00\x01", accessUnit->data(), 4)); 173 unsigned x = accessUnit->data()[4]; 174 175 LOGI("access unit complete: nalType=0x%02x, nalRefIdc=0x%02x", 176 x & 0x1f, (x & 0x60) >> 5); 177#endif 178 179 accessUnit->meta()->setInt64("ntp-time", ntpTime); 180 accessUnit->meta()->setInt64("timeUs", 0); 181 182#if 0 183 int32_t damaged; 184 if (accessUnit->meta()->findInt32("damaged", &damaged) 185 && damaged != 0) { 186 LOGI("ignoring damaged AU"); 187 } else 188#endif 189 { 190 TrackInfo *info = &mTracks.editItemAt(trackIndex); 191 info->mPacketSource->queueAccessUnit(accessUnit); 192 } 193 break; 194 } 195 196 default: 197 TRESPASS(); 198 break; 199 } 200} 201 202bool ARTPSession::validateMediaFormat(size_t index, unsigned *port) const { 203 AString format; 204 mDesc->getFormat(index, &format); 205 206 ssize_t i = format.find(" "); 207 if (i < 0) { 208 return false; 209 } 210 211 ++i; 212 size_t j = i; 213 while (isdigit(format.c_str()[j])) { 214 ++j; 215 } 216 if (format.c_str()[j] != ' ') { 217 return false; 218 } 219 220 AString portString(format, i, j - i); 221 222 char *end; 223 unsigned long x = strtoul(portString.c_str(), &end, 10); 224 if (end == portString.c_str() || *end != '\0') { 225 return false; 226 } 227 228 if (x == 0 || x > 65535) { 229 return false; 230 } 231 232 *port = x; 233 234 return true; 235} 236 237size_t ARTPSession::countTracks() { 238 return mTracks.size(); 239} 240 241sp<MediaSource> ARTPSession::trackAt(size_t index) { 242 CHECK_LT(index, mTracks.size()); 243 return mTracks.editItemAt(index).mPacketSource; 244} 245 246} // namespace android 247