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
39namespace 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
48static int uniformRand(int limit) {
49    return ((double)rand() * limit) / RAND_MAX;
50}
51
52static 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
76struct 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
822protected:
823    virtual ~MyTransmitter() {
824    }
825
826private:
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