WifiDisplaySource.cpp revision 5131d127a042ee88f903370be88845dc8c9f8578
1/* 2 * Copyright 2012, 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//#define LOG_NDEBUG 0 18#define LOG_TAG "WifiDisplaySource" 19#include <utils/Log.h> 20 21#include "WifiDisplaySource.h" 22#include "PlaybackSession.h" 23#include "Parameters.h" 24#include "ParsedMessage.h" 25#include "Sender.h" 26 27#include <binder/IServiceManager.h> 28#include <gui/ISurfaceTexture.h> 29#include <media/IHDCP.h> 30#include <media/IMediaPlayerService.h> 31#include <media/IRemoteDisplayClient.h> 32#include <media/stagefright/foundation/ABuffer.h> 33#include <media/stagefright/foundation/ADebug.h> 34#include <media/stagefright/foundation/AMessage.h> 35#include <media/stagefright/MediaErrors.h> 36 37#include <arpa/inet.h> 38#include <cutils/properties.h> 39 40#include <ctype.h> 41 42namespace android { 43 44WifiDisplaySource::WifiDisplaySource( 45 const sp<ANetworkSession> &netSession, 46 const sp<IRemoteDisplayClient> &client) 47 : mState(INITIALIZED), 48 mNetSession(netSession), 49 mClient(client), 50 mSessionID(0), 51 mStopReplyID(0), 52 mChosenRTPPort(-1), 53 mUsingPCMAudio(false), 54 mClientSessionID(0), 55 mReaperPending(false), 56 mNextCSeq(1), 57 mUsingHDCP(false), 58 mIsHDCP2_0(false), 59 mHDCPPort(0), 60 mHDCPInitializationComplete(false), 61 mSetupTriggerDeferred(false) 62{ 63} 64 65WifiDisplaySource::~WifiDisplaySource() { 66} 67 68static status_t PostAndAwaitResponse( 69 const sp<AMessage> &msg, sp<AMessage> *response) { 70 status_t err = msg->postAndAwaitResponse(response); 71 72 if (err != OK) { 73 return err; 74 } 75 76 if (response == NULL || !(*response)->findInt32("err", &err)) { 77 err = OK; 78 } 79 80 return err; 81} 82 83status_t WifiDisplaySource::start(const char *iface) { 84 CHECK_EQ(mState, INITIALIZED); 85 86 sp<AMessage> msg = new AMessage(kWhatStart, id()); 87 msg->setString("iface", iface); 88 89 sp<AMessage> response; 90 return PostAndAwaitResponse(msg, &response); 91} 92 93status_t WifiDisplaySource::stop() { 94 sp<AMessage> msg = new AMessage(kWhatStop, id()); 95 96 sp<AMessage> response; 97 return PostAndAwaitResponse(msg, &response); 98} 99 100status_t WifiDisplaySource::pause() { 101 sp<AMessage> msg = new AMessage(kWhatPause, id()); 102 103 sp<AMessage> response; 104 return PostAndAwaitResponse(msg, &response); 105} 106 107status_t WifiDisplaySource::resume() { 108 sp<AMessage> msg = new AMessage(kWhatResume, id()); 109 110 sp<AMessage> response; 111 return PostAndAwaitResponse(msg, &response); 112} 113 114void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { 115 switch (msg->what()) { 116 case kWhatStart: 117 { 118 uint32_t replyID; 119 CHECK(msg->senderAwaitsResponse(&replyID)); 120 121 AString iface; 122 CHECK(msg->findString("iface", &iface)); 123 124 status_t err = OK; 125 126 ssize_t colonPos = iface.find(":"); 127 128 unsigned long port; 129 130 if (colonPos >= 0) { 131 const char *s = iface.c_str() + colonPos + 1; 132 133 char *end; 134 port = strtoul(s, &end, 10); 135 136 if (end == s || *end != '\0' || port > 65535) { 137 err = -EINVAL; 138 } else { 139 iface.erase(colonPos, iface.size() - colonPos); 140 } 141 } else { 142 port = kWifiDisplayDefaultPort; 143 } 144 145 if (err == OK) { 146 if (inet_aton(iface.c_str(), &mInterfaceAddr) != 0) { 147 sp<AMessage> notify = new AMessage(kWhatRTSPNotify, id()); 148 149 err = mNetSession->createRTSPServer( 150 mInterfaceAddr, port, notify, &mSessionID); 151 } else { 152 err = -EINVAL; 153 } 154 } 155 156 if (err == OK) { 157 mState = AWAITING_CLIENT_CONNECTION; 158 } 159 160 sp<AMessage> response = new AMessage; 161 response->setInt32("err", err); 162 response->postReply(replyID); 163 break; 164 } 165 166 case kWhatRTSPNotify: 167 { 168 int32_t reason; 169 CHECK(msg->findInt32("reason", &reason)); 170 171 switch (reason) { 172 case ANetworkSession::kWhatError: 173 { 174 int32_t sessionID; 175 CHECK(msg->findInt32("sessionID", &sessionID)); 176 177 int32_t err; 178 CHECK(msg->findInt32("err", &err)); 179 180 AString detail; 181 CHECK(msg->findString("detail", &detail)); 182 183 ALOGE("An error occurred in session %d (%d, '%s/%s').", 184 sessionID, 185 err, 186 detail.c_str(), 187 strerror(-err)); 188 189 mNetSession->destroySession(sessionID); 190 191 if (sessionID == mClientSessionID) { 192 mClientSessionID = 0; 193 194 mClient->onDisplayError( 195 IRemoteDisplayClient::kDisplayErrorUnknown); 196 } 197 break; 198 } 199 200 case ANetworkSession::kWhatClientConnected: 201 { 202 int32_t sessionID; 203 CHECK(msg->findInt32("sessionID", &sessionID)); 204 205 if (mClientSessionID > 0) { 206 ALOGW("A client tried to connect, but we already " 207 "have one."); 208 209 mNetSession->destroySession(sessionID); 210 break; 211 } 212 213 CHECK_EQ(mState, AWAITING_CLIENT_CONNECTION); 214 215 CHECK(msg->findString("client-ip", &mClientInfo.mRemoteIP)); 216 CHECK(msg->findString("server-ip", &mClientInfo.mLocalIP)); 217 218 if (mClientInfo.mRemoteIP == mClientInfo.mLocalIP) { 219 // Disallow connections from the local interface 220 // for security reasons. 221 mNetSession->destroySession(sessionID); 222 break; 223 } 224 225 CHECK(msg->findInt32( 226 "server-port", &mClientInfo.mLocalPort)); 227 mClientInfo.mPlaybackSessionID = -1; 228 229 mClientSessionID = sessionID; 230 231 ALOGI("We now have a client (%d) connected.", sessionID); 232 233 mState = AWAITING_CLIENT_SETUP; 234 235 status_t err = sendM1(sessionID); 236 CHECK_EQ(err, (status_t)OK); 237 break; 238 } 239 240 case ANetworkSession::kWhatData: 241 { 242 status_t err = onReceiveClientData(msg); 243 244 if (err != OK) { 245 mClient->onDisplayError( 246 IRemoteDisplayClient::kDisplayErrorUnknown); 247 } 248 249#if 0 250 // testing only. 251 char val[PROPERTY_VALUE_MAX]; 252 if (property_get("media.wfd.trigger", val, NULL)) { 253 if (!strcasecmp(val, "pause") && mState == PLAYING) { 254 mState = PLAYING_TO_PAUSED; 255 sendTrigger(mClientSessionID, TRIGGER_PAUSE); 256 } else if (!strcasecmp(val, "play") && mState == PAUSED) { 257 mState = PAUSED_TO_PLAYING; 258 sendTrigger(mClientSessionID, TRIGGER_PLAY); 259 } 260 } 261#endif 262 break; 263 } 264 265 default: 266 TRESPASS(); 267 } 268 break; 269 } 270 271 case kWhatStop: 272 { 273 CHECK(msg->senderAwaitsResponse(&mStopReplyID)); 274 275 CHECK_LT(mState, AWAITING_CLIENT_TEARDOWN); 276 277 if (mState >= AWAITING_CLIENT_PLAY) { 278 // We have a session, i.e. a previous SETUP succeeded. 279 280 status_t err = sendTrigger( 281 mClientSessionID, TRIGGER_TEARDOWN); 282 283 if (err == OK) { 284 mState = AWAITING_CLIENT_TEARDOWN; 285 286 (new AMessage(kWhatTeardownTriggerTimedOut, id()))->post( 287 kTeardownTriggerTimeouSecs * 1000000ll); 288 289 break; 290 } 291 292 // fall through. 293 } 294 295 finishStop(); 296 break; 297 } 298 299 case kWhatPause: 300 { 301 uint32_t replyID; 302 CHECK(msg->senderAwaitsResponse(&replyID)); 303 304 status_t err = OK; 305 306 if (mState != PLAYING) { 307 err = INVALID_OPERATION; 308 } else { 309 mState = PLAYING_TO_PAUSED; 310 sendTrigger(mClientSessionID, TRIGGER_PAUSE); 311 } 312 313 sp<AMessage> response = new AMessage; 314 response->setInt32("err", err); 315 response->postReply(replyID); 316 break; 317 } 318 319 case kWhatResume: 320 { 321 uint32_t replyID; 322 CHECK(msg->senderAwaitsResponse(&replyID)); 323 324 status_t err = OK; 325 326 if (mState != PAUSED) { 327 err = INVALID_OPERATION; 328 } else { 329 mState = PAUSED_TO_PLAYING; 330 sendTrigger(mClientSessionID, TRIGGER_PLAY); 331 } 332 333 sp<AMessage> response = new AMessage; 334 response->setInt32("err", err); 335 response->postReply(replyID); 336 break; 337 } 338 339 case kWhatReapDeadClients: 340 { 341 mReaperPending = false; 342 343 if (mClientSessionID == 0 344 || mClientInfo.mPlaybackSession == NULL) { 345 break; 346 } 347 348 if (mClientInfo.mPlaybackSession->getLastLifesignUs() 349 + kPlaybackSessionTimeoutUs < ALooper::GetNowUs()) { 350 ALOGI("playback session timed out, reaping."); 351 352 mNetSession->destroySession(mClientSessionID); 353 mClientSessionID = 0; 354 355 mClient->onDisplayError( 356 IRemoteDisplayClient::kDisplayErrorUnknown); 357 } else { 358 scheduleReaper(); 359 } 360 break; 361 } 362 363 case kWhatPlaybackSessionNotify: 364 { 365 int32_t playbackSessionID; 366 CHECK(msg->findInt32("playbackSessionID", &playbackSessionID)); 367 368 int32_t what; 369 CHECK(msg->findInt32("what", &what)); 370 371 if (what == PlaybackSession::kWhatSessionDead) { 372 ALOGI("playback session wants to quit."); 373 374 mClient->onDisplayError( 375 IRemoteDisplayClient::kDisplayErrorUnknown); 376 } else if (what == PlaybackSession::kWhatSessionEstablished) { 377 if (mClient != NULL) { 378 mClient->onDisplayConnected( 379 mClientInfo.mPlaybackSession->getSurfaceTexture(), 380 mClientInfo.mPlaybackSession->width(), 381 mClientInfo.mPlaybackSession->height(), 382 mUsingHDCP 383 ? IRemoteDisplayClient::kDisplayFlagSecure 384 : 0); 385 } 386 387 if (mState == ABOUT_TO_PLAY) { 388 mState = PLAYING; 389 } 390 } else if (what == PlaybackSession::kWhatSessionDestroyed) { 391 disconnectClient2(); 392 } else { 393 CHECK_EQ(what, PlaybackSession::kWhatBinaryData); 394 395 int32_t channel; 396 CHECK(msg->findInt32("channel", &channel)); 397 398 sp<ABuffer> data; 399 CHECK(msg->findBuffer("data", &data)); 400 401 CHECK_LE(channel, 0xffu); 402 CHECK_LE(data->size(), 0xffffu); 403 404 int32_t sessionID; 405 CHECK(msg->findInt32("sessionID", &sessionID)); 406 407 char header[4]; 408 header[0] = '$'; 409 header[1] = channel; 410 header[2] = data->size() >> 8; 411 header[3] = data->size() & 0xff; 412 413 mNetSession->sendRequest( 414 sessionID, header, sizeof(header)); 415 416 mNetSession->sendRequest( 417 sessionID, data->data(), data->size()); 418 } 419 break; 420 } 421 422 case kWhatKeepAlive: 423 { 424 int32_t sessionID; 425 CHECK(msg->findInt32("sessionID", &sessionID)); 426 427 if (mClientSessionID != sessionID) { 428 // Obsolete event, client is already gone. 429 break; 430 } 431 432 sendM16(sessionID); 433 break; 434 } 435 436 case kWhatTeardownTriggerTimedOut: 437 { 438 if (mState == AWAITING_CLIENT_TEARDOWN) { 439 ALOGI("TEARDOWN trigger timed out, forcing disconnection."); 440 441 CHECK_NE(mStopReplyID, 0); 442 finishStop(); 443 break; 444 } 445 break; 446 } 447 448 case kWhatHDCPNotify: 449 { 450 int32_t msgCode, ext1, ext2; 451 CHECK(msg->findInt32("msg", &msgCode)); 452 CHECK(msg->findInt32("ext1", &ext1)); 453 CHECK(msg->findInt32("ext2", &ext2)); 454 455 ALOGI("Saw HDCP notification code %d, ext1 %d, ext2 %d", 456 msgCode, ext1, ext2); 457 458 switch (msgCode) { 459 case HDCPModule::HDCP_INITIALIZATION_COMPLETE: 460 { 461 mHDCPInitializationComplete = true; 462 463 if (mSetupTriggerDeferred) { 464 mSetupTriggerDeferred = false; 465 466 sendTrigger(mClientSessionID, TRIGGER_SETUP); 467 } 468 break; 469 } 470 471 case HDCPModule::HDCP_SHUTDOWN_COMPLETE: 472 case HDCPModule::HDCP_SHUTDOWN_FAILED: 473 { 474 // Ugly hack to make sure that the call to 475 // HDCPObserver::notify is completely handled before 476 // we clear the HDCP instance and unload the shared 477 // library :( 478 (new AMessage(kWhatFinishStop2, id()))->post(300000ll); 479 break; 480 } 481 482 default: 483 { 484 ALOGE("HDCP failure, shutting down."); 485 486 mClient->onDisplayError( 487 IRemoteDisplayClient::kDisplayErrorUnknown); 488 break; 489 } 490 } 491 break; 492 } 493 494 case kWhatFinishStop2: 495 { 496 finishStop2(); 497 break; 498 } 499 500 default: 501 TRESPASS(); 502 } 503} 504 505void WifiDisplaySource::registerResponseHandler( 506 int32_t sessionID, int32_t cseq, HandleRTSPResponseFunc func) { 507 ResponseID id; 508 id.mSessionID = sessionID; 509 id.mCSeq = cseq; 510 mResponseHandlers.add(id, func); 511} 512 513status_t WifiDisplaySource::sendM1(int32_t sessionID) { 514 AString request = "OPTIONS * RTSP/1.0\r\n"; 515 AppendCommonResponse(&request, mNextCSeq); 516 517 request.append( 518 "Require: org.wfa.wfd1.0\r\n" 519 "\r\n"); 520 521 status_t err = 522 mNetSession->sendRequest(sessionID, request.c_str(), request.size()); 523 524 if (err != OK) { 525 return err; 526 } 527 528 registerResponseHandler( 529 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM1Response); 530 531 ++mNextCSeq; 532 533 return OK; 534} 535 536status_t WifiDisplaySource::sendM3(int32_t sessionID) { 537 AString body = 538 "wfd_content_protection\r\n" 539 "wfd_video_formats\r\n" 540 "wfd_audio_codecs\r\n" 541 "wfd_client_rtp_ports\r\n"; 542 543 AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n"; 544 AppendCommonResponse(&request, mNextCSeq); 545 546 request.append("Content-Type: text/parameters\r\n"); 547 request.append(StringPrintf("Content-Length: %d\r\n", body.size())); 548 request.append("\r\n"); 549 request.append(body); 550 551 status_t err = 552 mNetSession->sendRequest(sessionID, request.c_str(), request.size()); 553 554 if (err != OK) { 555 return err; 556 } 557 558 registerResponseHandler( 559 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM3Response); 560 561 ++mNextCSeq; 562 563 return OK; 564} 565 566status_t WifiDisplaySource::sendM4(int32_t sessionID) { 567 // wfd_video_formats: 568 // 1 byte "native" 569 // 1 byte "preferred-display-mode-supported" 0 or 1 570 // one or more avc codec structures 571 // 1 byte profile 572 // 1 byte level 573 // 4 byte CEA mask 574 // 4 byte VESA mask 575 // 4 byte HH mask 576 // 1 byte latency 577 // 2 byte min-slice-slice 578 // 2 byte slice-enc-params 579 // 1 byte framerate-control-support 580 // max-hres (none or 2 byte) 581 // max-vres (none or 2 byte) 582 583 CHECK_EQ(sessionID, mClientSessionID); 584 585 AString transportString = "UDP"; 586 587 char val[PROPERTY_VALUE_MAX]; 588 if (property_get("media.wfd.enable-tcp", val, NULL) 589 && (!strcasecmp("true", val) || !strcmp("1", val))) { 590 ALOGI("Using TCP transport."); 591 transportString = "TCP"; 592 } 593 594 // For 720p60: 595 // use "30 00 02 02 00000040 00000000 00000000 00 0000 0000 00 none none\r\n" 596 // For 720p30: 597 // use "28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none\r\n" 598 // For 720p24: 599 // use "78 00 02 02 00008000 00000000 00000000 00 0000 0000 00 none none\r\n" 600 // For 1080p30: 601 // use "38 00 02 02 00000080 00000000 00000000 00 0000 0000 00 none none\r\n" 602 AString body = StringPrintf( 603 "wfd_video_formats: " 604#if USE_1080P 605 "38 00 02 02 00000080 00000000 00000000 00 0000 0000 00 none none\r\n" 606#else 607 "28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none\r\n" 608#endif 609 "wfd_audio_codecs: %s\r\n" 610 "wfd_presentation_URL: rtsp://%s/wfd1.0/streamid=0 none\r\n" 611 "wfd_client_rtp_ports: RTP/AVP/%s;unicast %d 0 mode=play\r\n", 612 (mUsingPCMAudio 613 ? "LPCM 00000002 00" // 2 ch PCM 48kHz 614 : "AAC 00000001 00"), // 2 ch AAC 48kHz 615 mClientInfo.mLocalIP.c_str(), transportString.c_str(), mChosenRTPPort); 616 617 AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n"; 618 AppendCommonResponse(&request, mNextCSeq); 619 620 request.append("Content-Type: text/parameters\r\n"); 621 request.append(StringPrintf("Content-Length: %d\r\n", body.size())); 622 request.append("\r\n"); 623 request.append(body); 624 625 status_t err = 626 mNetSession->sendRequest(sessionID, request.c_str(), request.size()); 627 628 if (err != OK) { 629 return err; 630 } 631 632 registerResponseHandler( 633 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM4Response); 634 635 ++mNextCSeq; 636 637 return OK; 638} 639 640status_t WifiDisplaySource::sendTrigger( 641 int32_t sessionID, TriggerType triggerType) { 642 AString body = "wfd_trigger_method: "; 643 switch (triggerType) { 644 case TRIGGER_SETUP: 645 body.append("SETUP"); 646 break; 647 case TRIGGER_TEARDOWN: 648 ALOGI("Sending TEARDOWN trigger."); 649 body.append("TEARDOWN"); 650 break; 651 case TRIGGER_PAUSE: 652 body.append("PAUSE"); 653 break; 654 case TRIGGER_PLAY: 655 body.append("PLAY"); 656 break; 657 default: 658 TRESPASS(); 659 } 660 661 body.append("\r\n"); 662 663 AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n"; 664 AppendCommonResponse(&request, mNextCSeq); 665 666 request.append("Content-Type: text/parameters\r\n"); 667 request.append(StringPrintf("Content-Length: %d\r\n", body.size())); 668 request.append("\r\n"); 669 request.append(body); 670 671 status_t err = 672 mNetSession->sendRequest(sessionID, request.c_str(), request.size()); 673 674 if (err != OK) { 675 return err; 676 } 677 678 registerResponseHandler( 679 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM5Response); 680 681 ++mNextCSeq; 682 683 return OK; 684} 685 686status_t WifiDisplaySource::sendM16(int32_t sessionID) { 687 AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n"; 688 AppendCommonResponse(&request, mNextCSeq); 689 690 CHECK_EQ(sessionID, mClientSessionID); 691 request.append( 692 StringPrintf("Session: %d\r\n", mClientInfo.mPlaybackSessionID)); 693 request.append("\r\n"); // Empty body 694 695 status_t err = 696 mNetSession->sendRequest(sessionID, request.c_str(), request.size()); 697 698 if (err != OK) { 699 return err; 700 } 701 702 registerResponseHandler( 703 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM16Response); 704 705 ++mNextCSeq; 706 707 return OK; 708} 709 710status_t WifiDisplaySource::onReceiveM1Response( 711 int32_t sessionID, const sp<ParsedMessage> &msg) { 712 int32_t statusCode; 713 if (!msg->getStatusCode(&statusCode)) { 714 return ERROR_MALFORMED; 715 } 716 717 if (statusCode != 200) { 718 return ERROR_UNSUPPORTED; 719 } 720 721 return OK; 722} 723 724// sink_audio_list := ("LPCM"|"AAC"|"AC3" HEXDIGIT*8 HEXDIGIT*2) 725// (", " sink_audio_list)* 726static void GetAudioModes(const char *s, const char *prefix, uint32_t *modes) { 727 *modes = 0; 728 729 size_t prefixLen = strlen(prefix); 730 731 while (*s != '0') { 732 if (!strncmp(s, prefix, prefixLen) && s[prefixLen] == ' ') { 733 unsigned latency; 734 if (sscanf(&s[prefixLen + 1], "%08x %02x", modes, &latency) != 2) { 735 *modes = 0; 736 } 737 738 return; 739 } 740 741 char *commaPos = strchr(s, ','); 742 if (commaPos != NULL) { 743 s = commaPos + 1; 744 745 while (isspace(*s)) { 746 ++s; 747 } 748 } else { 749 break; 750 } 751 } 752} 753 754status_t WifiDisplaySource::onReceiveM3Response( 755 int32_t sessionID, const sp<ParsedMessage> &msg) { 756 int32_t statusCode; 757 if (!msg->getStatusCode(&statusCode)) { 758 return ERROR_MALFORMED; 759 } 760 761 if (statusCode != 200) { 762 return ERROR_UNSUPPORTED; 763 } 764 765 sp<Parameters> params = 766 Parameters::Parse(msg->getContent(), strlen(msg->getContent())); 767 768 if (params == NULL) { 769 return ERROR_MALFORMED; 770 } 771 772 AString value; 773 if (!params->findParameter("wfd_client_rtp_ports", &value)) { 774 ALOGE("Sink doesn't report its choice of wfd_client_rtp_ports."); 775 return ERROR_MALFORMED; 776 } 777 778 unsigned port0, port1; 779 if (sscanf(value.c_str(), 780 "RTP/AVP/UDP;unicast %u %u mode=play", 781 &port0, 782 &port1) != 2 783 || port0 == 0 || port0 > 65535 || port1 != 0) { 784 ALOGE("Sink chose its wfd_client_rtp_ports poorly (%s)", 785 value.c_str()); 786 787 return ERROR_MALFORMED; 788 } 789 790 mChosenRTPPort = port0; 791 792 if (!params->findParameter("wfd_audio_codecs", &value)) { 793 ALOGE("Sink doesn't report its choice of wfd_audio_codecs."); 794 return ERROR_MALFORMED; 795 } 796 797 if (value == "none") { 798 ALOGE("Sink doesn't support audio at all."); 799 return ERROR_UNSUPPORTED; 800 } 801 802 uint32_t modes; 803 GetAudioModes(value.c_str(), "AAC", &modes); 804 805 bool supportsAAC = (modes & 1) != 0; // AAC 2ch 48kHz 806 807 GetAudioModes(value.c_str(), "LPCM", &modes); 808 809 bool supportsPCM = (modes & 2) != 0; // LPCM 2ch 48kHz 810 811 char val[PROPERTY_VALUE_MAX]; 812 if (supportsPCM 813 && property_get("media.wfd.use-pcm-audio", val, NULL) 814 && (!strcasecmp("true", val) || !strcmp("1", val))) { 815 ALOGI("Using PCM audio."); 816 mUsingPCMAudio = true; 817 } else if (supportsAAC) { 818 ALOGI("Using AAC audio."); 819 mUsingPCMAudio = false; 820 } else if (supportsPCM) { 821 ALOGI("Using PCM audio."); 822 mUsingPCMAudio = true; 823 } else { 824 ALOGI("Sink doesn't support an audio format we do."); 825 return ERROR_UNSUPPORTED; 826 } 827 828 mUsingHDCP = false; 829 if (!params->findParameter("wfd_content_protection", &value)) { 830 ALOGI("Sink doesn't appear to support content protection."); 831 } else if (value == "none") { 832 ALOGI("Sink does not support content protection."); 833 } else { 834 mUsingHDCP = true; 835 836 bool isHDCP2_0 = false; 837 if (value.startsWith("HDCP2.0 ")) { 838 isHDCP2_0 = true; 839 } else if (!value.startsWith("HDCP2.1 ")) { 840 ALOGE("malformed wfd_content_protection: '%s'", value.c_str()); 841 842 return ERROR_MALFORMED; 843 } 844 845 int32_t hdcpPort; 846 if (!ParsedMessage::GetInt32Attribute( 847 value.c_str() + 8, "port", &hdcpPort) 848 || hdcpPort < 1 || hdcpPort > 65535) { 849 return ERROR_MALFORMED; 850 } 851 852 mIsHDCP2_0 = isHDCP2_0; 853 mHDCPPort = hdcpPort; 854 855 status_t err = makeHDCP(); 856 if (err != OK) { 857 ALOGE("Unable to instantiate HDCP component. " 858 "Not using HDCP after all."); 859 860 mUsingHDCP = false; 861 } 862 } 863 864 return sendM4(sessionID); 865} 866 867status_t WifiDisplaySource::onReceiveM4Response( 868 int32_t sessionID, const sp<ParsedMessage> &msg) { 869 int32_t statusCode; 870 if (!msg->getStatusCode(&statusCode)) { 871 return ERROR_MALFORMED; 872 } 873 874 if (statusCode != 200) { 875 return ERROR_UNSUPPORTED; 876 } 877 878 if (mUsingHDCP && !mHDCPInitializationComplete) { 879 ALOGI("Deferring SETUP trigger until HDCP initialization completes."); 880 881 mSetupTriggerDeferred = true; 882 return OK; 883 } 884 885 return sendTrigger(sessionID, TRIGGER_SETUP); 886} 887 888status_t WifiDisplaySource::onReceiveM5Response( 889 int32_t sessionID, const sp<ParsedMessage> &msg) { 890 int32_t statusCode; 891 if (!msg->getStatusCode(&statusCode)) { 892 return ERROR_MALFORMED; 893 } 894 895 if (statusCode != 200) { 896 return ERROR_UNSUPPORTED; 897 } 898 899 return OK; 900} 901 902status_t WifiDisplaySource::onReceiveM16Response( 903 int32_t sessionID, const sp<ParsedMessage> &msg) { 904 // If only the response was required to include a "Session:" header... 905 906 CHECK_EQ(sessionID, mClientSessionID); 907 908 if (mClientInfo.mPlaybackSession != NULL) { 909 mClientInfo.mPlaybackSession->updateLiveness(); 910 911 scheduleKeepAlive(sessionID); 912 } 913 914 return OK; 915} 916 917void WifiDisplaySource::scheduleReaper() { 918 if (mReaperPending) { 919 return; 920 } 921 922 mReaperPending = true; 923 (new AMessage(kWhatReapDeadClients, id()))->post(kReaperIntervalUs); 924} 925 926void WifiDisplaySource::scheduleKeepAlive(int32_t sessionID) { 927 // We need to send updates at least 5 secs before the timeout is set to 928 // expire, make sure the timeout is greater than 5 secs to begin with. 929 CHECK_GT(kPlaybackSessionTimeoutUs, 5000000ll); 930 931 sp<AMessage> msg = new AMessage(kWhatKeepAlive, id()); 932 msg->setInt32("sessionID", sessionID); 933 msg->post(kPlaybackSessionTimeoutUs - 5000000ll); 934} 935 936status_t WifiDisplaySource::onReceiveClientData(const sp<AMessage> &msg) { 937 int32_t sessionID; 938 CHECK(msg->findInt32("sessionID", &sessionID)); 939 940 sp<RefBase> obj; 941 CHECK(msg->findObject("data", &obj)); 942 943 sp<ParsedMessage> data = 944 static_cast<ParsedMessage *>(obj.get()); 945 946 ALOGV("session %d received '%s'", 947 sessionID, data->debugString().c_str()); 948 949 AString method; 950 AString uri; 951 data->getRequestField(0, &method); 952 953 int32_t cseq; 954 if (!data->findInt32("cseq", &cseq)) { 955 sendErrorResponse(sessionID, "400 Bad Request", -1 /* cseq */); 956 return ERROR_MALFORMED; 957 } 958 959 if (method.startsWith("RTSP/")) { 960 // This is a response. 961 962 ResponseID id; 963 id.mSessionID = sessionID; 964 id.mCSeq = cseq; 965 966 ssize_t index = mResponseHandlers.indexOfKey(id); 967 968 if (index < 0) { 969 ALOGW("Received unsolicited server response, cseq %d", cseq); 970 return ERROR_MALFORMED; 971 } 972 973 HandleRTSPResponseFunc func = mResponseHandlers.valueAt(index); 974 mResponseHandlers.removeItemsAt(index); 975 976 status_t err = (this->*func)(sessionID, data); 977 978 if (err != OK) { 979 ALOGW("Response handler for session %d, cseq %d returned " 980 "err %d (%s)", 981 sessionID, cseq, err, strerror(-err)); 982 983 return err; 984 } 985 986 return OK; 987 } 988 989 AString version; 990 data->getRequestField(2, &version); 991 if (!(version == AString("RTSP/1.0"))) { 992 sendErrorResponse(sessionID, "505 RTSP Version not supported", cseq); 993 return ERROR_UNSUPPORTED; 994 } 995 996 status_t err; 997 if (method == "OPTIONS") { 998 err = onOptionsRequest(sessionID, cseq, data); 999 } else if (method == "SETUP") { 1000 err = onSetupRequest(sessionID, cseq, data); 1001 } else if (method == "PLAY") { 1002 err = onPlayRequest(sessionID, cseq, data); 1003 } else if (method == "PAUSE") { 1004 err = onPauseRequest(sessionID, cseq, data); 1005 } else if (method == "TEARDOWN") { 1006 err = onTeardownRequest(sessionID, cseq, data); 1007 } else if (method == "GET_PARAMETER") { 1008 err = onGetParameterRequest(sessionID, cseq, data); 1009 } else if (method == "SET_PARAMETER") { 1010 err = onSetParameterRequest(sessionID, cseq, data); 1011 } else { 1012 sendErrorResponse(sessionID, "405 Method Not Allowed", cseq); 1013 1014 err = ERROR_UNSUPPORTED; 1015 } 1016 1017 return err; 1018} 1019 1020status_t WifiDisplaySource::onOptionsRequest( 1021 int32_t sessionID, 1022 int32_t cseq, 1023 const sp<ParsedMessage> &data) { 1024 int32_t playbackSessionID; 1025 sp<PlaybackSession> playbackSession = 1026 findPlaybackSession(data, &playbackSessionID); 1027 1028 if (playbackSession != NULL) { 1029 playbackSession->updateLiveness(); 1030 } 1031 1032 AString response = "RTSP/1.0 200 OK\r\n"; 1033 AppendCommonResponse(&response, cseq); 1034 1035 response.append( 1036 "Public: org.wfa.wfd1.0, SETUP, TEARDOWN, PLAY, PAUSE, " 1037 "GET_PARAMETER, SET_PARAMETER\r\n"); 1038 1039 response.append("\r\n"); 1040 1041 status_t err = mNetSession->sendRequest(sessionID, response.c_str()); 1042 1043 if (err == OK) { 1044 err = sendM3(sessionID); 1045 } 1046 1047 return err; 1048} 1049 1050status_t WifiDisplaySource::onSetupRequest( 1051 int32_t sessionID, 1052 int32_t cseq, 1053 const sp<ParsedMessage> &data) { 1054 CHECK_EQ(sessionID, mClientSessionID); 1055 if (mClientInfo.mPlaybackSessionID != -1) { 1056 // We only support a single playback session per client. 1057 // This is due to the reversed keep-alive design in the wfd specs... 1058 sendErrorResponse(sessionID, "400 Bad Request", cseq); 1059 return ERROR_MALFORMED; 1060 } 1061 1062 AString transport; 1063 if (!data->findString("transport", &transport)) { 1064 sendErrorResponse(sessionID, "400 Bad Request", cseq); 1065 return ERROR_MALFORMED; 1066 } 1067 1068 Sender::TransportMode transportMode = Sender::TRANSPORT_UDP; 1069 1070 int clientRtp, clientRtcp; 1071 if (transport.startsWith("RTP/AVP/TCP;")) { 1072 AString interleaved; 1073 if (ParsedMessage::GetAttribute( 1074 transport.c_str(), "interleaved", &interleaved) 1075 && sscanf(interleaved.c_str(), "%d-%d", 1076 &clientRtp, &clientRtcp) == 2) { 1077 transportMode = Sender::TRANSPORT_TCP_INTERLEAVED; 1078 } else { 1079 bool badRequest = false; 1080 1081 AString clientPort; 1082 if (!ParsedMessage::GetAttribute( 1083 transport.c_str(), "client_port", &clientPort)) { 1084 badRequest = true; 1085 } else if (sscanf(clientPort.c_str(), "%d-%d", 1086 &clientRtp, &clientRtcp) == 2) { 1087 } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) { 1088 // No RTCP. 1089 clientRtcp = -1; 1090 } else { 1091 badRequest = true; 1092 } 1093 1094 if (badRequest) { 1095 sendErrorResponse(sessionID, "400 Bad Request", cseq); 1096 return ERROR_MALFORMED; 1097 } 1098 1099 transportMode = Sender::TRANSPORT_TCP; 1100 } 1101 } else if (transport.startsWith("RTP/AVP;unicast;") 1102 || transport.startsWith("RTP/AVP/UDP;unicast;")) { 1103 bool badRequest = false; 1104 1105 AString clientPort; 1106 if (!ParsedMessage::GetAttribute( 1107 transport.c_str(), "client_port", &clientPort)) { 1108 badRequest = true; 1109 } else if (sscanf(clientPort.c_str(), "%d-%d", 1110 &clientRtp, &clientRtcp) == 2) { 1111 } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) { 1112 // No RTCP. 1113 clientRtcp = -1; 1114 } else { 1115 badRequest = true; 1116 } 1117 1118 if (badRequest) { 1119 sendErrorResponse(sessionID, "400 Bad Request", cseq); 1120 return ERROR_MALFORMED; 1121 } 1122#if 1 1123 // The older LG dongles doesn't specify client_port=xxx apparently. 1124 } else if (transport == "RTP/AVP/UDP;unicast") { 1125 clientRtp = 19000; 1126 clientRtcp = -1; 1127#endif 1128 } else { 1129 sendErrorResponse(sessionID, "461 Unsupported Transport", cseq); 1130 return ERROR_UNSUPPORTED; 1131 } 1132 1133 int32_t playbackSessionID = makeUniquePlaybackSessionID(); 1134 1135 sp<AMessage> notify = new AMessage(kWhatPlaybackSessionNotify, id()); 1136 notify->setInt32("playbackSessionID", playbackSessionID); 1137 notify->setInt32("sessionID", sessionID); 1138 1139 sp<PlaybackSession> playbackSession = 1140 new PlaybackSession( 1141 mNetSession, notify, mInterfaceAddr, mHDCP); 1142 1143 looper()->registerHandler(playbackSession); 1144 1145 AString uri; 1146 data->getRequestField(1, &uri); 1147 1148 if (strncasecmp("rtsp://", uri.c_str(), 7)) { 1149 sendErrorResponse(sessionID, "400 Bad Request", cseq); 1150 return ERROR_MALFORMED; 1151 } 1152 1153 if (!(uri.startsWith("rtsp://") && uri.endsWith("/wfd1.0/streamid=0"))) { 1154 sendErrorResponse(sessionID, "404 Not found", cseq); 1155 return ERROR_MALFORMED; 1156 } 1157 1158 status_t err = playbackSession->init( 1159 mClientInfo.mRemoteIP.c_str(), 1160 clientRtp, 1161 clientRtcp, 1162 transportMode, 1163 mUsingPCMAudio); 1164 1165 if (err != OK) { 1166 looper()->unregisterHandler(playbackSession->id()); 1167 playbackSession.clear(); 1168 } 1169 1170 switch (err) { 1171 case OK: 1172 break; 1173 case -ENOENT: 1174 sendErrorResponse(sessionID, "404 Not Found", cseq); 1175 return err; 1176 default: 1177 sendErrorResponse(sessionID, "403 Forbidden", cseq); 1178 return err; 1179 } 1180 1181 mClientInfo.mPlaybackSessionID = playbackSessionID; 1182 mClientInfo.mPlaybackSession = playbackSession; 1183 1184 AString response = "RTSP/1.0 200 OK\r\n"; 1185 AppendCommonResponse(&response, cseq, playbackSessionID); 1186 1187 if (transportMode == Sender::TRANSPORT_TCP_INTERLEAVED) { 1188 response.append( 1189 StringPrintf( 1190 "Transport: RTP/AVP/TCP;interleaved=%d-%d;", 1191 clientRtp, clientRtcp)); 1192 } else { 1193 int32_t serverRtp = playbackSession->getRTPPort(); 1194 1195 AString transportString = "UDP"; 1196 if (transportMode == Sender::TRANSPORT_TCP) { 1197 transportString = "TCP"; 1198 } 1199 1200 if (clientRtcp >= 0) { 1201 response.append( 1202 StringPrintf( 1203 "Transport: RTP/AVP/%s;unicast;client_port=%d-%d;" 1204 "server_port=%d-%d\r\n", 1205 transportString.c_str(), 1206 clientRtp, clientRtcp, serverRtp, serverRtp + 1)); 1207 } else { 1208 response.append( 1209 StringPrintf( 1210 "Transport: RTP/AVP/%s;unicast;client_port=%d;" 1211 "server_port=%d\r\n", 1212 transportString.c_str(), 1213 clientRtp, serverRtp)); 1214 } 1215 } 1216 1217 response.append("\r\n"); 1218 1219 err = mNetSession->sendRequest(sessionID, response.c_str()); 1220 1221 if (err != OK) { 1222 return err; 1223 } 1224 1225 mState = AWAITING_CLIENT_PLAY; 1226 1227 scheduleReaper(); 1228 scheduleKeepAlive(sessionID); 1229 1230 return OK; 1231} 1232 1233status_t WifiDisplaySource::onPlayRequest( 1234 int32_t sessionID, 1235 int32_t cseq, 1236 const sp<ParsedMessage> &data) { 1237 int32_t playbackSessionID; 1238 sp<PlaybackSession> playbackSession = 1239 findPlaybackSession(data, &playbackSessionID); 1240 1241 if (playbackSession == NULL) { 1242 sendErrorResponse(sessionID, "454 Session Not Found", cseq); 1243 return ERROR_MALFORMED; 1244 } 1245 1246 ALOGI("Received PLAY request."); 1247 1248 status_t err = playbackSession->play(); 1249 CHECK_EQ(err, (status_t)OK); 1250 1251 AString response = "RTSP/1.0 200 OK\r\n"; 1252 AppendCommonResponse(&response, cseq, playbackSessionID); 1253 response.append("Range: npt=now-\r\n"); 1254 response.append("\r\n"); 1255 1256 err = mNetSession->sendRequest(sessionID, response.c_str()); 1257 1258 if (err != OK) { 1259 return err; 1260 } 1261 1262 if (mState == PAUSED_TO_PLAYING) { 1263 mState = PLAYING; 1264 return OK; 1265 } 1266 1267 playbackSession->finishPlay(); 1268 1269 CHECK_EQ(mState, AWAITING_CLIENT_PLAY); 1270 mState = ABOUT_TO_PLAY; 1271 1272 return OK; 1273} 1274 1275status_t WifiDisplaySource::onPauseRequest( 1276 int32_t sessionID, 1277 int32_t cseq, 1278 const sp<ParsedMessage> &data) { 1279 int32_t playbackSessionID; 1280 sp<PlaybackSession> playbackSession = 1281 findPlaybackSession(data, &playbackSessionID); 1282 1283 if (playbackSession == NULL) { 1284 sendErrorResponse(sessionID, "454 Session Not Found", cseq); 1285 return ERROR_MALFORMED; 1286 } 1287 1288 ALOGI("Received PAUSE request."); 1289 1290 if (mState != PLAYING_TO_PAUSED) { 1291 return INVALID_OPERATION; 1292 } 1293 1294 status_t err = playbackSession->pause(); 1295 CHECK_EQ(err, (status_t)OK); 1296 1297 AString response = "RTSP/1.0 200 OK\r\n"; 1298 AppendCommonResponse(&response, cseq, playbackSessionID); 1299 response.append("\r\n"); 1300 1301 err = mNetSession->sendRequest(sessionID, response.c_str()); 1302 1303 if (err != OK) { 1304 return err; 1305 } 1306 1307 mState = PAUSED; 1308 1309 return err; 1310} 1311 1312status_t WifiDisplaySource::onTeardownRequest( 1313 int32_t sessionID, 1314 int32_t cseq, 1315 const sp<ParsedMessage> &data) { 1316 ALOGI("Received TEARDOWN request."); 1317 1318 int32_t playbackSessionID; 1319 sp<PlaybackSession> playbackSession = 1320 findPlaybackSession(data, &playbackSessionID); 1321 1322 if (playbackSession == NULL) { 1323 sendErrorResponse(sessionID, "454 Session Not Found", cseq); 1324 return ERROR_MALFORMED; 1325 } 1326 1327 AString response = "RTSP/1.0 200 OK\r\n"; 1328 AppendCommonResponse(&response, cseq, playbackSessionID); 1329 response.append("Connection: close\r\n"); 1330 response.append("\r\n"); 1331 1332 mNetSession->sendRequest(sessionID, response.c_str()); 1333 1334 if (mState == AWAITING_CLIENT_TEARDOWN) { 1335 CHECK_NE(mStopReplyID, 0); 1336 finishStop(); 1337 } else { 1338 mClient->onDisplayError(IRemoteDisplayClient::kDisplayErrorUnknown); 1339 } 1340 1341 return OK; 1342} 1343 1344void WifiDisplaySource::finishStop() { 1345 ALOGV("finishStop"); 1346 1347 mState = STOPPING; 1348 1349 disconnectClientAsync(); 1350} 1351 1352void WifiDisplaySource::finishStopAfterDisconnectingClient() { 1353 ALOGV("finishStopAfterDisconnectingClient"); 1354 1355 if (mHDCP != NULL) { 1356 ALOGI("Initiating HDCP shutdown."); 1357 mHDCP->shutdownAsync(); 1358 return; 1359 } 1360 1361 finishStop2(); 1362} 1363 1364void WifiDisplaySource::finishStop2() { 1365 ALOGV("finishStop2"); 1366 1367 if (mHDCP != NULL) { 1368 mHDCP->setObserver(NULL); 1369 mHDCPObserver.clear(); 1370 mHDCP.clear(); 1371 } 1372 1373 if (mSessionID != 0) { 1374 mNetSession->destroySession(mSessionID); 1375 mSessionID = 0; 1376 } 1377 1378 ALOGI("We're stopped."); 1379 mState = STOPPED; 1380 1381 status_t err = OK; 1382 1383 sp<AMessage> response = new AMessage; 1384 response->setInt32("err", err); 1385 response->postReply(mStopReplyID); 1386} 1387 1388status_t WifiDisplaySource::onGetParameterRequest( 1389 int32_t sessionID, 1390 int32_t cseq, 1391 const sp<ParsedMessage> &data) { 1392 int32_t playbackSessionID; 1393 sp<PlaybackSession> playbackSession = 1394 findPlaybackSession(data, &playbackSessionID); 1395 1396 if (playbackSession == NULL) { 1397 sendErrorResponse(sessionID, "454 Session Not Found", cseq); 1398 return ERROR_MALFORMED; 1399 } 1400 1401 playbackSession->updateLiveness(); 1402 1403 AString response = "RTSP/1.0 200 OK\r\n"; 1404 AppendCommonResponse(&response, cseq, playbackSessionID); 1405 response.append("\r\n"); 1406 1407 status_t err = mNetSession->sendRequest(sessionID, response.c_str()); 1408 return err; 1409} 1410 1411status_t WifiDisplaySource::onSetParameterRequest( 1412 int32_t sessionID, 1413 int32_t cseq, 1414 const sp<ParsedMessage> &data) { 1415 int32_t playbackSessionID; 1416 sp<PlaybackSession> playbackSession = 1417 findPlaybackSession(data, &playbackSessionID); 1418 1419 if (playbackSession == NULL) { 1420 sendErrorResponse(sessionID, "454 Session Not Found", cseq); 1421 return ERROR_MALFORMED; 1422 } 1423 1424 if (strstr(data->getContent(), "wfd_idr_request\r\n")) { 1425 playbackSession->requestIDRFrame(); 1426 } 1427 1428 playbackSession->updateLiveness(); 1429 1430 AString response = "RTSP/1.0 200 OK\r\n"; 1431 AppendCommonResponse(&response, cseq, playbackSessionID); 1432 response.append("\r\n"); 1433 1434 status_t err = mNetSession->sendRequest(sessionID, response.c_str()); 1435 return err; 1436} 1437 1438// static 1439void WifiDisplaySource::AppendCommonResponse( 1440 AString *response, int32_t cseq, int32_t playbackSessionID) { 1441 time_t now = time(NULL); 1442 struct tm *now2 = gmtime(&now); 1443 char buf[128]; 1444 strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", now2); 1445 1446 response->append("Date: "); 1447 response->append(buf); 1448 response->append("\r\n"); 1449 1450 response->append("Server: Mine/1.0\r\n"); 1451 1452 if (cseq >= 0) { 1453 response->append(StringPrintf("CSeq: %d\r\n", cseq)); 1454 } 1455 1456 if (playbackSessionID >= 0ll) { 1457 response->append( 1458 StringPrintf( 1459 "Session: %d;timeout=%lld\r\n", 1460 playbackSessionID, kPlaybackSessionTimeoutSecs)); 1461 } 1462} 1463 1464void WifiDisplaySource::sendErrorResponse( 1465 int32_t sessionID, 1466 const char *errorDetail, 1467 int32_t cseq) { 1468 AString response; 1469 response.append("RTSP/1.0 "); 1470 response.append(errorDetail); 1471 response.append("\r\n"); 1472 1473 AppendCommonResponse(&response, cseq); 1474 1475 response.append("\r\n"); 1476 1477 mNetSession->sendRequest(sessionID, response.c_str()); 1478} 1479 1480int32_t WifiDisplaySource::makeUniquePlaybackSessionID() const { 1481 return rand(); 1482} 1483 1484sp<WifiDisplaySource::PlaybackSession> WifiDisplaySource::findPlaybackSession( 1485 const sp<ParsedMessage> &data, int32_t *playbackSessionID) const { 1486 if (!data->findInt32("session", playbackSessionID)) { 1487 // XXX the older dongles do not always include a "Session:" header. 1488 *playbackSessionID = mClientInfo.mPlaybackSessionID; 1489 return mClientInfo.mPlaybackSession; 1490 } 1491 1492 if (*playbackSessionID != mClientInfo.mPlaybackSessionID) { 1493 return NULL; 1494 } 1495 1496 return mClientInfo.mPlaybackSession; 1497} 1498 1499void WifiDisplaySource::disconnectClientAsync() { 1500 ALOGV("disconnectClient"); 1501 1502 if (mClientInfo.mPlaybackSession == NULL) { 1503 disconnectClient2(); 1504 return; 1505 } 1506 1507 if (mClientInfo.mPlaybackSession != NULL) { 1508 ALOGV("Destroying PlaybackSession"); 1509 mClientInfo.mPlaybackSession->destroyAsync(); 1510 } 1511} 1512 1513void WifiDisplaySource::disconnectClient2() { 1514 ALOGV("disconnectClient2"); 1515 1516 if (mClientInfo.mPlaybackSession != NULL) { 1517 looper()->unregisterHandler(mClientInfo.mPlaybackSession->id()); 1518 mClientInfo.mPlaybackSession.clear(); 1519 } 1520 1521 if (mClientSessionID != 0) { 1522 mNetSession->destroySession(mClientSessionID); 1523 mClientSessionID = 0; 1524 } 1525 1526 mClient->onDisplayDisconnected(); 1527 1528 finishStopAfterDisconnectingClient(); 1529} 1530 1531struct WifiDisplaySource::HDCPObserver : public BnHDCPObserver { 1532 HDCPObserver(const sp<AMessage> ¬ify); 1533 1534 virtual void notify( 1535 int msg, int ext1, int ext2, const Parcel *obj); 1536 1537private: 1538 sp<AMessage> mNotify; 1539 1540 DISALLOW_EVIL_CONSTRUCTORS(HDCPObserver); 1541}; 1542 1543WifiDisplaySource::HDCPObserver::HDCPObserver( 1544 const sp<AMessage> ¬ify) 1545 : mNotify(notify) { 1546} 1547 1548void WifiDisplaySource::HDCPObserver::notify( 1549 int msg, int ext1, int ext2, const Parcel *obj) { 1550 sp<AMessage> notify = mNotify->dup(); 1551 notify->setInt32("msg", msg); 1552 notify->setInt32("ext1", ext1); 1553 notify->setInt32("ext2", ext2); 1554 notify->post(); 1555} 1556 1557status_t WifiDisplaySource::makeHDCP() { 1558 sp<IServiceManager> sm = defaultServiceManager(); 1559 sp<IBinder> binder = sm->getService(String16("media.player")); 1560 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder); 1561 CHECK(service != NULL); 1562 1563 mHDCP = service->makeHDCP(); 1564 1565 if (mHDCP == NULL) { 1566 return ERROR_UNSUPPORTED; 1567 } 1568 1569 sp<AMessage> notify = new AMessage(kWhatHDCPNotify, id()); 1570 mHDCPObserver = new HDCPObserver(notify); 1571 1572 status_t err = mHDCP->setObserver(mHDCPObserver); 1573 1574 if (err != OK) { 1575 ALOGE("Failed to set HDCP observer."); 1576 1577 mHDCPObserver.clear(); 1578 mHDCP.clear(); 1579 1580 return err; 1581 } 1582 1583 ALOGI("Initiating HDCP negotiation w/ host %s:%d", 1584 mClientInfo.mRemoteIP.c_str(), mHDCPPort); 1585 1586 err = mHDCP->initAsync(mClientInfo.mRemoteIP.c_str(), mHDCPPort); 1587 1588 if (err != OK) { 1589 return err; 1590 } 1591 1592 return OK; 1593} 1594 1595} // namespace android 1596 1597