blob: 009a3b1fb0eac6bc1903e848bcfc0091f08b92ae [file] [log] [blame]
Andreas Huber7a747b82010-06-07 15:19:40 -07001/*
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_