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