Home | History | Annotate | Download | only in rtsp
      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 #ifndef MY_TRANSMITTER_H_
     18 
     19 #define MY_TRANSMITTER_H_
     20 
     21 #include "ARTPConnection.h"
     22 
     23 #include <arpa/inet.h>
     24 #include <sys/socket.h>
     25 
     26 #include <openssl/md5.h>
     27 
     28 #include <media/stagefright/foundation/ADebug.h>
     29 #include <media/stagefright/foundation/base64.h>
     30 #include <media/stagefright/foundation/hexdump.h>
     31 
     32 #ifdef ANDROID
     33 #include "VideoSource.h"
     34 
     35 #include <media/stagefright/OMXClient.h>
     36 #include <media/stagefright/OMXCodec.h>
     37 #endif
     38 
     39 namespace android {
     40 
     41 #define TRACK_SUFFIX    "trackid=1"
     42 #define PT              96
     43 #define PT_STR          "96"
     44 
     45 #define USERNAME        "bcast"
     46 #define PASSWORD        "test"
     47 
     48 static int uniformRand(int limit) {
     49     return ((double)rand() * limit) / RAND_MAX;
     50 }
     51 
     52 static bool GetAttribute(const char *s, const char *key, AString *value) {
     53     value->clear();
     54 
     55     size_t keyLen = strlen(key);
     56 
     57     for (;;) {
     58         const char *colonPos = strchr(s, ';');
     59 
     60         size_t len =
     61             (colonPos == NULL) ? strlen(s) : colonPos - s;
     62 
     63         if (len >= keyLen + 1 && s[keyLen] == '=' && !strncmp(s, key, keyLen)) {
     64             value->setTo(&s[keyLen + 1], len - keyLen - 1);
     65             return true;
     66         }
     67 
     68         if (colonPos == NULL) {
     69             return false;
     70         }
     71 
     72         s = colonPos + 1;
     73     }
     74 }
     75 
     76 struct MyTransmitter : public AHandler {
     77     MyTransmitter(const char *url, const sp<ALooper> &looper)
     78         : mServerURL(url),
     79           mLooper(looper),
     80           mConn(new ARTSPConnection),
     81           mConnected(false),
     82           mAuthType(NONE),
     83           mRTPSocket(-1),
     84           mRTCPSocket(-1),
     85           mSourceID(rand()),
     86           mSeqNo(uniformRand(65536)),
     87           mRTPTimeBase(rand()),
     88           mNumSamplesSent(0),
     89           mNumRTPSent(0),
     90           mNumRTPOctetsSent(0),
     91           mLastRTPTime(0),
     92           mLastNTPTime(0) {
     93         mStreamURL = mServerURL;
     94         mStreamURL.append("/bazong.sdp");
     95 
     96         mTrackURL = mStreamURL;
     97         mTrackURL.append("/");
     98         mTrackURL.append(TRACK_SUFFIX);
     99 
    100         mLooper->registerHandler(this);
    101         mLooper->registerHandler(mConn);
    102 
    103         sp<AMessage> reply = new AMessage('conn', id());
    104         mConn->connect(mServerURL.c_str(), reply);
    105 
    106 #ifdef ANDROID
    107         int width = 640;
    108         int height = 480;
    109 
    110         sp<MediaSource> source = new VideoSource(width, height);
    111 
    112         sp<MetaData> encMeta = new MetaData;
    113         encMeta->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
    114         encMeta->setInt32(kKeyWidth, width);
    115         encMeta->setInt32(kKeyHeight, height);
    116 
    117         OMXClient client;
    118         client.connect();
    119 
    120         mEncoder = OMXCodec::Create(
    121                 client.interface(), encMeta,
    122                 true /* createEncoder */, source);
    123 
    124         mEncoder->start();
    125 
    126         MediaBuffer *buffer;
    127         CHECK_EQ(mEncoder->read(&buffer), (status_t)OK);
    128         CHECK(buffer != NULL);
    129 
    130         makeH264SPropParamSets(buffer);
    131 
    132         buffer->release();
    133         buffer = NULL;
    134 #endif
    135     }
    136 
    137     uint64_t ntpTime() {
    138         struct timeval tv;
    139         gettimeofday(&tv, NULL);
    140 
    141         uint64_t nowUs = tv.tv_sec * 1000000ll + tv.tv_usec;
    142 
    143         nowUs += ((70ll * 365 + 17) * 24) * 60 * 60 * 1000000ll;
    144 
    145         uint64_t hi = nowUs / 1000000ll;
    146         uint64_t lo = ((1ll << 32) * (nowUs % 1000000ll)) / 1000000ll;
    147 
    148         return (hi << 32) | lo;
    149     }
    150 
    151     void issueAnnounce() {
    152         AString sdp;
    153         sdp = "v=0\r\n";
    154 
    155         sdp.append("o=- ");
    156 
    157         uint64_t ntp = ntpTime();
    158         sdp.append(ntp);
    159         sdp.append(" ");
    160         sdp.append(ntp);
    161         sdp.append(" IN IP4 127.0.0.0\r\n");
    162 
    163         sdp.append(
    164               "s=Sample\r\n"
    165               "i=Playing around with ANNOUNCE\r\n"
    166               "c=IN IP4 ");
    167 
    168         struct in_addr addr;
    169         addr.s_addr = htonl(mServerIP);
    170 
    171         sdp.append(inet_ntoa(addr));
    172 
    173         sdp.append(
    174               "\r\n"
    175               "t=0 0\r\n"
    176               "a=range:npt=now-\r\n");
    177 
    178 #ifdef ANDROID
    179         sp<MetaData> meta = mEncoder->getFormat();
    180         int32_t width, height;
    181         CHECK(meta->findInt32(kKeyWidth, &width));
    182         CHECK(meta->findInt32(kKeyHeight, &height));
    183 
    184         sdp.append(
    185               "m=video 0 RTP/AVP " PT_STR "\r\n"
    186               "b=AS 320000\r\n"
    187               "a=rtpmap:" PT_STR " H264/90000\r\n");
    188 
    189         sdp.append("a=cliprect 0,0,");
    190         sdp.append(height);
    191         sdp.append(",");
    192         sdp.append(width);
    193         sdp.append("\r\n");
    194 
    195         sdp.append(
    196               "a=framesize:" PT_STR " ");
    197         sdp.append(width);
    198         sdp.append("-");
    199         sdp.append(height);
    200         sdp.append("\r\n");
    201 
    202         sdp.append(
    203               "a=fmtp:" PT_STR " profile-level-id=42C015;sprop-parameter-sets=");
    204 
    205         sdp.append(mSeqParamSet);
    206         sdp.append(",");
    207         sdp.append(mPicParamSet);
    208         sdp.append(";packetization-mode=1\r\n");
    209 #else
    210         sdp.append(
    211                 "m=audio 0 RTP/AVP " PT_STR "\r\n"
    212                 "a=rtpmap:" PT_STR " L8/8000/1\r\n");
    213 #endif
    214 
    215         sdp.append("a=control:" TRACK_SUFFIX "\r\n");
    216 
    217         AString request;
    218         request.append("ANNOUNCE ");
    219         request.append(mStreamURL);
    220         request.append(" RTSP/1.0\r\n");
    221 
    222         addAuthentication(&request, "ANNOUNCE", mStreamURL.c_str());
    223 
    224         request.append("Content-Type: application/sdp\r\n");
    225         request.append("Content-Length: ");
    226         request.append(sdp.size());
    227         request.append("\r\n");
    228 
    229         request.append("\r\n");
    230         request.append(sdp);
    231 
    232         sp<AMessage> reply = new AMessage('anno', id());
    233         mConn->sendRequest(request.c_str(), reply);
    234     }
    235 
    236     void H(const AString &s, AString *out) {
    237         out->clear();
    238 
    239         MD5_CTX m;
    240         MD5_Init(&m);
    241         MD5_Update(&m, s.c_str(), s.size());
    242 
    243         uint8_t key[16];
    244         MD5_Final(key, &m);
    245 
    246         for (size_t i = 0; i < 16; ++i) {
    247             char nibble = key[i] >> 4;
    248             if (nibble <= 9) {
    249                 nibble += '0';
    250             } else {
    251                 nibble += 'a' - 10;
    252             }
    253             out->append(&nibble, 1);
    254 
    255             nibble = key[i] & 0x0f;
    256             if (nibble <= 9) {
    257                 nibble += '0';
    258             } else {
    259                 nibble += 'a' - 10;
    260             }
    261             out->append(&nibble, 1);
    262         }
    263     }
    264 
    265     void authenticate(const sp<ARTSPResponse> &response) {
    266         ssize_t i = response->mHeaders.indexOfKey("www-authenticate");
    267         CHECK_GE(i, 0);
    268 
    269         AString value = response->mHeaders.valueAt(i);
    270 
    271         if (!strncmp(value.c_str(), "Basic", 5)) {
    272             mAuthType = BASIC;
    273         } else {
    274             CHECK(!strncmp(value.c_str(), "Digest", 6));
    275             mAuthType = DIGEST;
    276 
    277             i = value.find("nonce=");
    278             CHECK_GE(i, 0);
    279             CHECK_EQ(value.c_str()[i + 6], '\"');
    280             ssize_t j = value.find("\"", i + 7);
    281             CHECK_GE(j, 0);
    282 
    283             mNonce.setTo(value, i + 7, j - i - 7);
    284         }
    285 
    286         issueAnnounce();
    287     }
    288 
    289     void addAuthentication(
    290             AString *request, const char *method, const char *url) {
    291         if (mAuthType == NONE) {
    292             return;
    293         }
    294 
    295         if (mAuthType == BASIC) {
    296             request->append("Authorization: Basic YmNhc3Q6dGVzdAo=\r\n");
    297             return;
    298         }
    299 
    300         CHECK_EQ((int)mAuthType, (int)DIGEST);
    301 
    302         AString A1;
    303         A1.append(USERNAME);
    304         A1.append(":");
    305         A1.append("Streaming Server");
    306         A1.append(":");
    307         A1.append(PASSWORD);
    308 
    309         AString A2;
    310         A2.append(method);
    311         A2.append(":");
    312         A2.append(url);
    313 
    314         AString HA1, HA2;
    315         H(A1, &HA1);
    316         H(A2, &HA2);
    317 
    318         AString tmp;
    319         tmp.append(HA1);
    320         tmp.append(":");
    321         tmp.append(mNonce);
    322         tmp.append(":");
    323         tmp.append(HA2);
    324 
    325         AString digest;
    326         H(tmp, &digest);
    327 
    328         request->append("Authorization: Digest ");
    329         request->append("nonce=\"");
    330         request->append(mNonce);
    331         request->append("\", ");
    332         request->append("username=\"" USERNAME "\", ");
    333         request->append("uri=\"");
    334         request->append(url);
    335         request->append("\", ");
    336         request->append("response=\"");
    337         request->append(digest);
    338         request->append("\"");
    339         request->append("\r\n");
    340     }
    341 
    342     virtual void onMessageReceived(const sp<AMessage> &msg) {
    343         switch (msg->what()) {
    344             case 'conn':
    345             {
    346                 int32_t result;
    347                 CHECK(msg->findInt32("result", &result));
    348 
    349                 LOG(INFO) << "connection request completed with result "
    350                      << result << " (" << strerror(-result) << ")";
    351 
    352                 if (result != OK) {
    353                     (new AMessage('quit', id()))->post();
    354                     break;
    355                 }
    356 
    357                 mConnected = true;
    358 
    359                 CHECK(msg->findInt32("server-ip", (int32_t *)&mServerIP));
    360 
    361                 issueAnnounce();
    362                 break;
    363             }
    364 
    365             case 'anno':
    366             {
    367                 int32_t result;
    368                 CHECK(msg->findInt32("result", &result));
    369 
    370                 LOG(INFO) << "ANNOUNCE completed with result "
    371                      << result << " (" << strerror(-result) << ")";
    372 
    373                 sp<RefBase> obj;
    374                 CHECK(msg->findObject("response", &obj));
    375                 sp<ARTSPResponse> response;
    376 
    377                 if (result == OK) {
    378                     response = static_cast<ARTSPResponse *>(obj.get());
    379                     CHECK(response != NULL);
    380 
    381                     if (response->mStatusCode == 401) {
    382                         if (mAuthType != NONE) {
    383                             LOG(INFO) << "FAILED to authenticate";
    384                             (new AMessage('quit', id()))->post();
    385                             break;
    386                         }
    387 
    388                         authenticate(response);
    389                         break;
    390                     }
    391                 }
    392 
    393                 if (result != OK || response->mStatusCode != 200) {
    394                     (new AMessage('quit', id()))->post();
    395                     break;
    396                 }
    397 
    398                 unsigned rtpPort;
    399                 ARTPConnection::MakePortPair(&mRTPSocket, &mRTCPSocket, &rtpPort);
    400 
    401                 // (new AMessage('poll', id()))->post();
    402 
    403                 AString request;
    404                 request.append("SETUP ");
    405                 request.append(mTrackURL);
    406                 request.append(" RTSP/1.0\r\n");
    407 
    408                 addAuthentication(&request, "SETUP", mTrackURL.c_str());
    409 
    410                 request.append("Transport: RTP/AVP;unicast;client_port=");
    411                 request.append(rtpPort);
    412                 request.append("-");
    413                 request.append(rtpPort + 1);
    414                 request.append(";mode=record\r\n");
    415                 request.append("\r\n");
    416 
    417                 sp<AMessage> reply = new AMessage('setu', id());
    418                 mConn->sendRequest(request.c_str(), reply);
    419                 break;
    420             }
    421 
    422 #if 0
    423             case 'poll':
    424             {
    425                 fd_set rs;
    426                 FD_ZERO(&rs);
    427                 FD_SET(mRTCPSocket, &rs);
    428 
    429                 struct timeval tv;
    430                 tv.tv_sec = 0;
    431                 tv.tv_usec = 0;
    432 
    433                 int res = select(mRTCPSocket + 1, &rs, NULL, NULL, &tv);
    434 
    435                 if (res == 1) {
    436                     sp<ABuffer> buffer = new ABuffer(65536);
    437                     ssize_t n = recv(mRTCPSocket, buffer->data(), buffer->size(), 0);
    438 
    439                     if (n <= 0) {
    440                         LOG(ERROR) << "recv returned " << n;
    441                     } else {
    442                         LOG(INFO) << "recv returned " << n << " bytes of data.";
    443 
    444                         hexdump(buffer->data(), n);
    445                     }
    446                 }
    447 
    448                 msg->post(50000);
    449                 break;
    450             }
    451 #endif
    452 
    453             case 'setu':
    454             {
    455                 int32_t result;
    456                 CHECK(msg->findInt32("result", &result));
    457 
    458                 LOG(INFO) << "SETUP completed with result "
    459                      << result << " (" << strerror(-result) << ")";
    460 
    461                 sp<RefBase> obj;
    462                 CHECK(msg->findObject("response", &obj));
    463                 sp<ARTSPResponse> response;
    464 
    465                 if (result == OK) {
    466                     response = static_cast<ARTSPResponse *>(obj.get());
    467                     CHECK(response != NULL);
    468                 }
    469 
    470                 if (result != OK || response->mStatusCode != 200) {
    471                     (new AMessage('quit', id()))->post();
    472                     break;
    473                 }
    474 
    475                 ssize_t i = response->mHeaders.indexOfKey("session");
    476                 CHECK_GE(i, 0);
    477                 mSessionID = response->mHeaders.valueAt(i);
    478                 i = mSessionID.find(";");
    479                 if (i >= 0) {
    480                     // Remove options, i.e. ";timeout=90"
    481                     mSessionID.erase(i, mSessionID.size() - i);
    482                 }
    483 
    484                 i = response->mHeaders.indexOfKey("transport");
    485                 CHECK_GE(i, 0);
    486                 AString transport = response->mHeaders.valueAt(i);
    487 
    488                 LOG(INFO) << "transport = '" << transport << "'";
    489 
    490                 AString value;
    491                 CHECK(GetAttribute(transport.c_str(), "server_port", &value));
    492 
    493                 unsigned rtpPort, rtcpPort;
    494                 CHECK_EQ(sscanf(value.c_str(), "%u-%u", &rtpPort, &rtcpPort), 2);
    495 
    496                 CHECK(GetAttribute(transport.c_str(), "source", &value));
    497 
    498                 memset(mRemoteAddr.sin_zero, 0, sizeof(mRemoteAddr.sin_zero));
    499                 mRemoteAddr.sin_family = AF_INET;
    500                 mRemoteAddr.sin_addr.s_addr = inet_addr(value.c_str());
    501                 mRemoteAddr.sin_port = htons(rtpPort);
    502 
    503                 mRemoteRTCPAddr = mRemoteAddr;
    504                 mRemoteRTCPAddr.sin_port = htons(rtpPort + 1);
    505 
    506                 CHECK_EQ(0, connect(mRTPSocket,
    507                                     (const struct sockaddr *)&mRemoteAddr,
    508                                     sizeof(mRemoteAddr)));
    509 
    510                 CHECK_EQ(0, connect(mRTCPSocket,
    511                                     (const struct sockaddr *)&mRemoteRTCPAddr,
    512                                     sizeof(mRemoteRTCPAddr)));
    513 
    514                 uint32_t x = ntohl(mRemoteAddr.sin_addr.s_addr);
    515                 LOG(INFO) << "sending data to "
    516                      << (x >> 24)
    517                      << "."
    518                      << ((x >> 16) & 0xff)
    519                      << "."
    520                      << ((x >> 8) & 0xff)
    521                      << "."
    522                      << (x & 0xff)
    523                      << ":"
    524                      << rtpPort;
    525 
    526                 AString request;
    527                 request.append("RECORD ");
    528                 request.append(mStreamURL);
    529                 request.append(" RTSP/1.0\r\n");
    530 
    531                 addAuthentication(&request, "RECORD", mStreamURL.c_str());
    532 
    533                 request.append("Session: ");
    534                 request.append(mSessionID);
    535                 request.append("\r\n");
    536                 request.append("\r\n");
    537 
    538                 sp<AMessage> reply = new AMessage('reco', id());
    539                 mConn->sendRequest(request.c_str(), reply);
    540                 break;
    541             }
    542 
    543             case 'reco':
    544             {
    545                 int32_t result;
    546                 CHECK(msg->findInt32("result", &result));
    547 
    548                 LOG(INFO) << "RECORD completed with result "
    549                      << result << " (" << strerror(-result) << ")";
    550 
    551                 sp<RefBase> obj;
    552                 CHECK(msg->findObject("response", &obj));
    553                 sp<ARTSPResponse> response;
    554 
    555                 if (result == OK) {
    556                     response = static_cast<ARTSPResponse *>(obj.get());
    557                     CHECK(response != NULL);
    558                 }
    559 
    560                 if (result != OK) {
    561                     (new AMessage('quit', id()))->post();
    562                     break;
    563                 }
    564 
    565                 (new AMessage('more', id()))->post();
    566                 (new AMessage('sr  ', id()))->post();
    567                 (new AMessage('aliv', id()))->post(30000000ll);
    568                 break;
    569             }
    570 
    571             case 'aliv':
    572             {
    573                 if (!mConnected) {
    574                     break;
    575                 }
    576 
    577                 AString request;
    578                 request.append("OPTIONS ");
    579                 request.append(mStreamURL);
    580                 request.append(" RTSP/1.0\r\n");
    581 
    582                 addAuthentication(&request, "RECORD", mStreamURL.c_str());
    583 
    584                 request.append("Session: ");
    585                 request.append(mSessionID);
    586                 request.append("\r\n");
    587                 request.append("\r\n");
    588 
    589                 sp<AMessage> reply = new AMessage('opts', id());
    590                 mConn->sendRequest(request.c_str(), reply);
    591                 break;
    592             }
    593 
    594             case 'opts':
    595             {
    596                 int32_t result;
    597                 CHECK(msg->findInt32("result", &result));
    598 
    599                 LOG(INFO) << "OPTIONS completed with result "
    600                      << result << " (" << strerror(-result) << ")";
    601 
    602                 if (!mConnected) {
    603                     break;
    604                 }
    605 
    606                 (new AMessage('aliv', id()))->post(30000000ll);
    607                 break;
    608             }
    609 
    610             case 'more':
    611             {
    612                 if (!mConnected) {
    613                     break;
    614                 }
    615 
    616                 sp<ABuffer> buffer = new ABuffer(65536);
    617                 uint8_t *data = buffer->data();
    618                 data[0] = 0x80;
    619                 data[1] = (1 << 7) | PT;  // M-bit
    620                 data[2] = (mSeqNo >> 8) & 0xff;
    621                 data[3] = mSeqNo & 0xff;
    622                 data[8] = mSourceID >> 24;
    623                 data[9] = (mSourceID >> 16) & 0xff;
    624                 data[10] = (mSourceID >> 8) & 0xff;
    625                 data[11] = mSourceID & 0xff;
    626 
    627 #ifdef ANDROID
    628                 MediaBuffer *mediaBuf = NULL;
    629                 for (;;) {
    630                     CHECK_EQ(mEncoder->read(&mediaBuf), (status_t)OK);
    631                     if (mediaBuf->range_length() > 0) {
    632                         break;
    633                     }
    634                     mediaBuf->release();
    635                     mediaBuf = NULL;
    636                 }
    637 
    638                 int64_t timeUs;
    639                 CHECK(mediaBuf->meta_data()->findInt64(kKeyTime, &timeUs));
    640 
    641                 uint32_t rtpTime = mRTPTimeBase + (timeUs * 9 / 100ll);
    642 
    643                 const uint8_t *mediaData =
    644                     (const uint8_t *)mediaBuf->data() + mediaBuf->range_offset();
    645 
    646                 CHECK(!memcmp("\x00\x00\x00\x01", mediaData, 4));
    647 
    648                 CHECK_LE(mediaBuf->range_length() - 4 + 12, buffer->size());
    649 
    650                 memcpy(&data[12],
    651                        mediaData + 4, mediaBuf->range_length() - 4);
    652 
    653                 buffer->setRange(0, mediaBuf->range_length() - 4 + 12);
    654 
    655                 mediaBuf->release();
    656                 mediaBuf = NULL;
    657 #else
    658                 uint32_t rtpTime = mRTPTimeBase + mNumRTPSent * 128;
    659                 memset(&data[12], 0, 128);
    660                 buffer->setRange(0, 12 + 128);
    661 #endif
    662 
    663                 data[4] = rtpTime >> 24;
    664                 data[5] = (rtpTime >> 16) & 0xff;
    665                 data[6] = (rtpTime >> 8) & 0xff;
    666                 data[7] = rtpTime & 0xff;
    667 
    668                 ssize_t n = send(
    669                         mRTPSocket, data, buffer->size(), 0);
    670                 if (n < 0) {
    671                     LOG(ERROR) << "send failed (" << strerror(errno) << ")";
    672                 }
    673                 CHECK_EQ(n, (ssize_t)buffer->size());
    674 
    675                 ++mSeqNo;
    676 
    677                 ++mNumRTPSent;
    678                 mNumRTPOctetsSent += buffer->size() - 12;
    679 
    680                 mLastRTPTime = rtpTime;
    681                 mLastNTPTime = ntpTime();
    682 
    683 #ifdef ANDROID
    684                 if (mNumRTPSent < 60 * 25) {  // 60 secs worth
    685                     msg->post(40000);
    686 #else
    687                 if (mNumRTPOctetsSent < 8000 * 60) {
    688                     msg->post(1000000ll * 128 / 8000);
    689 #endif
    690                 } else {
    691                     LOG(INFO) << "That's enough, pausing.";
    692 
    693                     AString request;
    694                     request.append("PAUSE ");
    695                     request.append(mStreamURL);
    696                     request.append(" RTSP/1.0\r\n");
    697 
    698                     addAuthentication(&request, "PAUSE", mStreamURL.c_str());
    699 
    700                     request.append("Session: ");
    701                     request.append(mSessionID);
    702                     request.append("\r\n");
    703                     request.append("\r\n");
    704 
    705                     sp<AMessage> reply = new AMessage('paus', id());
    706                     mConn->sendRequest(request.c_str(), reply);
    707                 }
    708                 break;
    709             }
    710 
    711             case 'sr  ':
    712             {
    713                 if (!mConnected) {
    714                     break;
    715                 }
    716 
    717                 sp<ABuffer> buffer = new ABuffer(65536);
    718                 buffer->setRange(0, 0);
    719 
    720                 addSR(buffer);
    721                 addSDES(buffer);
    722 
    723                 uint8_t *data = buffer->data();
    724                 ssize_t n = send(
    725                         mRTCPSocket, data, buffer->size(), 0);
    726                 CHECK_EQ(n, (ssize_t)buffer->size());
    727 
    728                 msg->post(3000000);
    729                 break;
    730             }
    731 
    732             case 'paus':
    733             {
    734                 int32_t result;
    735                 CHECK(msg->findInt32("result", &result));
    736 
    737                 LOG(INFO) << "PAUSE completed with result "
    738                      << result << " (" << strerror(-result) << ")";
    739 
    740                 sp<RefBase> obj;
    741                 CHECK(msg->findObject("response", &obj));
    742                 sp<ARTSPResponse> response;
    743 
    744                 AString request;
    745                 request.append("TEARDOWN ");
    746                 request.append(mStreamURL);
    747                 request.append(" RTSP/1.0\r\n");
    748 
    749                 addAuthentication(&request, "TEARDOWN", mStreamURL.c_str());
    750 
    751                 request.append("Session: ");
    752                 request.append(mSessionID);
    753                 request.append("\r\n");
    754                 request.append("\r\n");
    755 
    756                 sp<AMessage> reply = new AMessage('tear', id());
    757                 mConn->sendRequest(request.c_str(), reply);
    758                 break;
    759             }
    760 
    761             case 'tear':
    762             {
    763                 int32_t result;
    764                 CHECK(msg->findInt32("result", &result));
    765 
    766                 LOG(INFO) << "TEARDOWN completed with result "
    767                      << result << " (" << strerror(-result) << ")";
    768 
    769                 sp<RefBase> obj;
    770                 CHECK(msg->findObject("response", &obj));
    771                 sp<ARTSPResponse> response;
    772 
    773                 if (result == OK) {
    774                     response = static_cast<ARTSPResponse *>(obj.get());
    775                     CHECK(response != NULL);
    776                 }
    777 
    778                 (new AMessage('quit', id()))->post();
    779                 break;
    780             }
    781 
    782             case 'disc':
    783             {
    784                 LOG(INFO) << "disconnect completed";
    785 
    786                 mConnected = false;
    787                 (new AMessage('quit', id()))->post();
    788                 break;
    789             }
    790 
    791             case 'quit':
    792             {
    793                 if (mConnected) {
    794                     mConn->disconnect(new AMessage('disc', id()));
    795                     break;
    796                 }
    797 
    798                 if (mRTPSocket >= 0) {
    799                     close(mRTPSocket);
    800                     mRTPSocket = -1;
    801                 }
    802 
    803                 if (mRTCPSocket >= 0) {
    804                     close(mRTCPSocket);
    805                     mRTCPSocket = -1;
    806                 }
    807 
    808 #ifdef ANDROID
    809                 mEncoder->stop();
    810                 mEncoder.clear();
    811 #endif
    812 
    813                 mLooper->stop();
    814                 break;
    815             }
    816 
    817             default:
    818                 TRESPASS();
    819         }
    820     }
    821 
    822 protected:
    823     virtual ~MyTransmitter() {
    824     }
    825 
    826 private:
    827     enum AuthType {
    828         NONE,
    829         BASIC,
    830         DIGEST
    831     };
    832 
    833     AString mServerURL;
    834     AString mTrackURL;
    835     AString mStreamURL;
    836 
    837     sp<ALooper> mLooper;
    838     sp<ARTSPConnection> mConn;
    839     bool mConnected;
    840     uint32_t mServerIP;
    841     AuthType mAuthType;
    842     AString mNonce;
    843     AString mSessionID;
    844     int mRTPSocket, mRTCPSocket;
    845     uint32_t mSourceID;
    846     uint32_t mSeqNo;
    847     uint32_t mRTPTimeBase;
    848     struct sockaddr_in mRemoteAddr;
    849     struct sockaddr_in mRemoteRTCPAddr;
    850     size_t mNumSamplesSent;
    851     uint32_t mNumRTPSent;
    852     uint32_t mNumRTPOctetsSent;
    853     uint32_t mLastRTPTime;
    854     uint64_t mLastNTPTime;
    855 
    856 #ifdef ANDROID
    857     sp<MediaSource> mEncoder;
    858     AString mSeqParamSet;
    859     AString mPicParamSet;
    860 
    861     void makeH264SPropParamSets(MediaBuffer *buffer) {
    862         static const char kStartCode[] = "\x00\x00\x00\x01";
    863 
    864         const uint8_t *data =
    865             (const uint8_t *)buffer->data() + buffer->range_offset();
    866         size_t size = buffer->range_length();
    867 
    868         CHECK_GE(size, 0u);
    869         CHECK(!memcmp(kStartCode, data, 4));
    870 
    871         data += 4;
    872         size -= 4;
    873 
    874         size_t startCodePos = 0;
    875         while (startCodePos + 3 < size
    876                 && memcmp(kStartCode, &data[startCodePos], 4)) {
    877             ++startCodePos;
    878         }
    879 
    880         CHECK_LT(startCodePos + 3, size);
    881 
    882         encodeBase64(data, startCodePos, &mSeqParamSet);
    883 
    884         encodeBase64(&data[startCodePos + 4], size - startCodePos - 4,
    885                      &mPicParamSet);
    886     }
    887 #endif
    888 
    889     void addSR(const sp<ABuffer> &buffer) {
    890         uint8_t *data = buffer->data() + buffer->size();
    891 
    892         data[0] = 0x80 | 0;
    893         data[1] = 200;  // SR
    894         data[2] = 0;
    895         data[3] = 6;
    896         data[4] = mSourceID >> 24;
    897         data[5] = (mSourceID >> 16) & 0xff;
    898         data[6] = (mSourceID >> 8) & 0xff;
    899         data[7] = mSourceID & 0xff;
    900 
    901         data[8] = mLastNTPTime >> (64 - 8);
    902         data[9] = (mLastNTPTime >> (64 - 16)) & 0xff;
    903         data[10] = (mLastNTPTime >> (64 - 24)) & 0xff;
    904         data[11] = (mLastNTPTime >> 32) & 0xff;
    905         data[12] = (mLastNTPTime >> 24) & 0xff;
    906         data[13] = (mLastNTPTime >> 16) & 0xff;
    907         data[14] = (mLastNTPTime >> 8) & 0xff;
    908         data[15] = mLastNTPTime & 0xff;
    909 
    910         data[16] = (mLastRTPTime >> 24) & 0xff;
    911         data[17] = (mLastRTPTime >> 16) & 0xff;
    912         data[18] = (mLastRTPTime >> 8) & 0xff;
    913         data[19] = mLastRTPTime & 0xff;
    914 
    915         data[20] = mNumRTPSent >> 24;
    916         data[21] = (mNumRTPSent >> 16) & 0xff;
    917         data[22] = (mNumRTPSent >> 8) & 0xff;
    918         data[23] = mNumRTPSent & 0xff;
    919 
    920         data[24] = mNumRTPOctetsSent >> 24;
    921         data[25] = (mNumRTPOctetsSent >> 16) & 0xff;
    922         data[26] = (mNumRTPOctetsSent >> 8) & 0xff;
    923         data[27] = mNumRTPOctetsSent & 0xff;
    924 
    925         buffer->setRange(buffer->offset(), buffer->size() + 28);
    926     }
    927 
    928     void addSDES(const sp<ABuffer> &buffer) {
    929         uint8_t *data = buffer->data() + buffer->size();
    930         data[0] = 0x80 | 1;
    931         data[1] = 202;  // SDES
    932         data[4] = mSourceID >> 24;
    933         data[5] = (mSourceID >> 16) & 0xff;
    934         data[6] = (mSourceID >> 8) & 0xff;
    935         data[7] = mSourceID & 0xff;
    936 
    937         size_t offset = 8;
    938 
    939         data[offset++] = 1;  // CNAME
    940 
    941         static const char *kCNAME = "andih@laptop";
    942         data[offset++] = strlen(kCNAME);
    943 
    944         memcpy(&data[offset], kCNAME, strlen(kCNAME));
    945         offset += strlen(kCNAME);
    946 
    947         data[offset++] = 7;  // NOTE
    948 
    949         static const char *kNOTE = "Hell's frozen over.";
    950         data[offset++] = strlen(kNOTE);
    951 
    952         memcpy(&data[offset], kNOTE, strlen(kNOTE));
    953         offset += strlen(kNOTE);
    954 
    955         data[offset++] = 0;
    956 
    957         if ((offset % 4) > 0) {
    958             size_t count = 4 - (offset % 4);
    959             switch (count) {
    960                 case 3:
    961                     data[offset++] = 0;
    962                 case 2:
    963                     data[offset++] = 0;
    964                 case 1:
    965                     data[offset++] = 0;
    966             }
    967         }
    968 
    969         size_t numWords = (offset / 4) - 1;
    970         data[2] = numWords >> 8;
    971         data[3] = numWords & 0xff;
    972 
    973         buffer->setRange(buffer->offset(), buffer->size() + offset);
    974     }
    975 
    976     DISALLOW_EVIL_CONSTRUCTORS(MyTransmitter);
    977 };
    978 
    979 }  // namespace android
    980 
    981 #endif  // MY_TRANSMITTER_H_
    982