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