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
40namespace 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
49static int uniformRand(int limit) {
50    return ((double)rand() * limit) / RAND_MAX;
51}
52
53static 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
77struct MyTransmitter : public AHandler {
78    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
140    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
154    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
239    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
268    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
292    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
345    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
825protected:
826    virtual ~MyTransmitter() {
827    }
828
829private:
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