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