WifiDisplaySink.cpp revision fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96
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 "WifiDisplaySink" 19#include <utils/Log.h> 20 21#include "WifiDisplaySink.h" 22#include "ParsedMessage.h" 23#include "RTPSink.h" 24 25#include <media/stagefright/foundation/ABuffer.h> 26#include <media/stagefright/foundation/ADebug.h> 27#include <media/stagefright/foundation/AMessage.h> 28#include <media/stagefright/MediaErrors.h> 29 30namespace android { 31 32WifiDisplaySink::WifiDisplaySink( 33 const sp<ANetworkSession> &netSession, 34 const sp<ISurfaceTexture> &surfaceTex) 35 : mState(UNDEFINED), 36 mNetSession(netSession), 37 mSurfaceTex(surfaceTex), 38 mSessionID(0), 39 mNextCSeq(1) { 40} 41 42WifiDisplaySink::~WifiDisplaySink() { 43} 44 45void WifiDisplaySink::start(const char *sourceHost, int32_t sourcePort) { 46 sp<AMessage> msg = new AMessage(kWhatStart, id()); 47 msg->setString("sourceHost", sourceHost); 48 msg->setInt32("sourcePort", sourcePort); 49 msg->post(); 50} 51 52void WifiDisplaySink::start(const char *uri) { 53 sp<AMessage> msg = new AMessage(kWhatStart, id()); 54 msg->setString("setupURI", uri); 55 msg->post(); 56} 57 58// static 59bool WifiDisplaySink::ParseURL( 60 const char *url, AString *host, int32_t *port, AString *path, 61 AString *user, AString *pass) { 62 host->clear(); 63 *port = 0; 64 path->clear(); 65 user->clear(); 66 pass->clear(); 67 68 if (strncasecmp("rtsp://", url, 7)) { 69 return false; 70 } 71 72 const char *slashPos = strchr(&url[7], '/'); 73 74 if (slashPos == NULL) { 75 host->setTo(&url[7]); 76 path->setTo("/"); 77 } else { 78 host->setTo(&url[7], slashPos - &url[7]); 79 path->setTo(slashPos); 80 } 81 82 ssize_t atPos = host->find("@"); 83 84 if (atPos >= 0) { 85 // Split of user:pass@ from hostname. 86 87 AString userPass(*host, 0, atPos); 88 host->erase(0, atPos + 1); 89 90 ssize_t colonPos = userPass.find(":"); 91 92 if (colonPos < 0) { 93 *user = userPass; 94 } else { 95 user->setTo(userPass, 0, colonPos); 96 pass->setTo(userPass, colonPos + 1, userPass.size() - colonPos - 1); 97 } 98 } 99 100 const char *colonPos = strchr(host->c_str(), ':'); 101 102 if (colonPos != NULL) { 103 char *end; 104 unsigned long x = strtoul(colonPos + 1, &end, 10); 105 106 if (end == colonPos + 1 || *end != '\0' || x >= 65536) { 107 return false; 108 } 109 110 *port = x; 111 112 size_t colonOffset = colonPos - host->c_str(); 113 size_t trailing = host->size() - colonOffset; 114 host->erase(colonOffset, trailing); 115 } else { 116 *port = 554; 117 } 118 119 return true; 120} 121 122void WifiDisplaySink::onMessageReceived(const sp<AMessage> &msg) { 123 switch (msg->what()) { 124 case kWhatStart: 125 { 126 int32_t sourcePort; 127 128 if (msg->findString("setupURI", &mSetupURI)) { 129 AString path, user, pass; 130 CHECK(ParseURL( 131 mSetupURI.c_str(), 132 &mRTSPHost, &sourcePort, &path, &user, &pass) 133 && user.empty() && pass.empty()); 134 } else { 135 CHECK(msg->findString("sourceHost", &mRTSPHost)); 136 CHECK(msg->findInt32("sourcePort", &sourcePort)); 137 } 138 139 sp<AMessage> notify = new AMessage(kWhatRTSPNotify, id()); 140 141 status_t err = mNetSession->createRTSPClient( 142 mRTSPHost.c_str(), sourcePort, notify, &mSessionID); 143 CHECK_EQ(err, (status_t)OK); 144 145 mState = CONNECTING; 146 break; 147 } 148 149 case kWhatRTSPNotify: 150 { 151 int32_t reason; 152 CHECK(msg->findInt32("reason", &reason)); 153 154 switch (reason) { 155 case ANetworkSession::kWhatError: 156 { 157 int32_t sessionID; 158 CHECK(msg->findInt32("sessionID", &sessionID)); 159 160 int32_t err; 161 CHECK(msg->findInt32("err", &err)); 162 163 AString detail; 164 CHECK(msg->findString("detail", &detail)); 165 166 ALOGE("An error occurred in session %d (%d, '%s/%s').", 167 sessionID, 168 err, 169 detail.c_str(), 170 strerror(-err)); 171 172 if (sessionID == mSessionID) { 173 ALOGI("Lost control connection."); 174 175 // The control connection is dead now. 176 mNetSession->destroySession(mSessionID); 177 mSessionID = 0; 178 179 looper()->stop(); 180 } 181 break; 182 } 183 184 case ANetworkSession::kWhatConnected: 185 { 186 ALOGI("We're now connected."); 187 mState = CONNECTED; 188 189 if (!mSetupURI.empty()) { 190 status_t err = 191 sendDescribe(mSessionID, mSetupURI.c_str()); 192 193 CHECK_EQ(err, (status_t)OK); 194 } 195 break; 196 } 197 198 case ANetworkSession::kWhatData: 199 { 200 onReceiveClientData(msg); 201 break; 202 } 203 204 case ANetworkSession::kWhatBinaryData: 205 { 206 CHECK(sUseTCPInterleaving); 207 208 int32_t channel; 209 CHECK(msg->findInt32("channel", &channel)); 210 211 sp<ABuffer> data; 212 CHECK(msg->findBuffer("data", &data)); 213 214 mRTPSink->injectPacket(channel == 0 /* isRTP */, data); 215 break; 216 } 217 218 default: 219 TRESPASS(); 220 } 221 break; 222 } 223 224 case kWhatStop: 225 { 226 looper()->stop(); 227 break; 228 } 229 230 default: 231 TRESPASS(); 232 } 233} 234 235void WifiDisplaySink::registerResponseHandler( 236 int32_t sessionID, int32_t cseq, HandleRTSPResponseFunc func) { 237 ResponseID id; 238 id.mSessionID = sessionID; 239 id.mCSeq = cseq; 240 mResponseHandlers.add(id, func); 241} 242 243status_t WifiDisplaySink::sendM2(int32_t sessionID) { 244 AString request = "OPTIONS * RTSP/1.0\r\n"; 245 AppendCommonResponse(&request, mNextCSeq); 246 247 request.append( 248 "Require: org.wfa.wfd1.0\r\n" 249 "\r\n"); 250 251 status_t err = 252 mNetSession->sendRequest(sessionID, request.c_str(), request.size()); 253 254 if (err != OK) { 255 return err; 256 } 257 258 registerResponseHandler( 259 sessionID, mNextCSeq, &WifiDisplaySink::onReceiveM2Response); 260 261 ++mNextCSeq; 262 263 return OK; 264} 265 266status_t WifiDisplaySink::onReceiveM2Response( 267 int32_t sessionID, const sp<ParsedMessage> &msg) { 268 int32_t statusCode; 269 if (!msg->getStatusCode(&statusCode)) { 270 return ERROR_MALFORMED; 271 } 272 273 if (statusCode != 200) { 274 return ERROR_UNSUPPORTED; 275 } 276 277 return OK; 278} 279 280status_t WifiDisplaySink::onReceiveDescribeResponse( 281 int32_t sessionID, const sp<ParsedMessage> &msg) { 282 int32_t statusCode; 283 if (!msg->getStatusCode(&statusCode)) { 284 return ERROR_MALFORMED; 285 } 286 287 if (statusCode != 200) { 288 return ERROR_UNSUPPORTED; 289 } 290 291 return sendSetup(sessionID, mSetupURI.c_str()); 292} 293 294status_t WifiDisplaySink::onReceiveSetupResponse( 295 int32_t sessionID, const sp<ParsedMessage> &msg) { 296 int32_t statusCode; 297 if (!msg->getStatusCode(&statusCode)) { 298 return ERROR_MALFORMED; 299 } 300 301 if (statusCode != 200) { 302 return ERROR_UNSUPPORTED; 303 } 304 305 if (!msg->findString("session", &mPlaybackSessionID)) { 306 return ERROR_MALFORMED; 307 } 308 309 if (!ParsedMessage::GetInt32Attribute( 310 mPlaybackSessionID.c_str(), 311 "timeout", 312 &mPlaybackSessionTimeoutSecs)) { 313 mPlaybackSessionTimeoutSecs = -1; 314 } 315 316 ssize_t colonPos = mPlaybackSessionID.find(";"); 317 if (colonPos >= 0) { 318 // Strip any options from the returned session id. 319 mPlaybackSessionID.erase( 320 colonPos, mPlaybackSessionID.size() - colonPos); 321 } 322 323 status_t err = configureTransport(msg); 324 325 if (err != OK) { 326 return err; 327 } 328 329 mState = PAUSED; 330 331 return sendPlay( 332 sessionID, 333 !mSetupURI.empty() 334 ? mSetupURI.c_str() : "rtsp://x.x.x.x:x/wfd1.0/streamid=0"); 335} 336 337status_t WifiDisplaySink::configureTransport(const sp<ParsedMessage> &msg) { 338 if (sUseTCPInterleaving) { 339 return OK; 340 } 341 342 AString transport; 343 if (!msg->findString("transport", &transport)) { 344 ALOGE("Missing 'transport' field in SETUP response."); 345 return ERROR_MALFORMED; 346 } 347 348 AString sourceHost; 349 if (!ParsedMessage::GetAttribute( 350 transport.c_str(), "source", &sourceHost)) { 351 sourceHost = mRTSPHost; 352 } 353 354 AString serverPortStr; 355 if (!ParsedMessage::GetAttribute( 356 transport.c_str(), "server_port", &serverPortStr)) { 357 ALOGE("Missing 'server_port' in Transport field."); 358 return ERROR_MALFORMED; 359 } 360 361 int rtpPort, rtcpPort; 362 if (sscanf(serverPortStr.c_str(), "%d-%d", &rtpPort, &rtcpPort) != 2 363 || rtpPort <= 0 || rtpPort > 65535 364 || rtcpPort <=0 || rtcpPort > 65535 365 || rtcpPort != rtpPort + 1) { 366 ALOGE("Invalid server_port description '%s'.", 367 serverPortStr.c_str()); 368 369 return ERROR_MALFORMED; 370 } 371 372 if (rtpPort & 1) { 373 ALOGW("Server picked an odd numbered RTP port."); 374 } 375 376 return mRTPSink->connect(sourceHost.c_str(), rtpPort, rtcpPort); 377} 378 379status_t WifiDisplaySink::onReceivePlayResponse( 380 int32_t sessionID, const sp<ParsedMessage> &msg) { 381 int32_t statusCode; 382 if (!msg->getStatusCode(&statusCode)) { 383 return ERROR_MALFORMED; 384 } 385 386 if (statusCode != 200) { 387 return ERROR_UNSUPPORTED; 388 } 389 390 mState = PLAYING; 391 392 return OK; 393} 394 395void WifiDisplaySink::onReceiveClientData(const sp<AMessage> &msg) { 396 int32_t sessionID; 397 CHECK(msg->findInt32("sessionID", &sessionID)); 398 399 sp<RefBase> obj; 400 CHECK(msg->findObject("data", &obj)); 401 402 sp<ParsedMessage> data = 403 static_cast<ParsedMessage *>(obj.get()); 404 405 ALOGV("session %d received '%s'", 406 sessionID, data->debugString().c_str()); 407 408 AString method; 409 AString uri; 410 data->getRequestField(0, &method); 411 412 int32_t cseq; 413 if (!data->findInt32("cseq", &cseq)) { 414 sendErrorResponse(sessionID, "400 Bad Request", -1 /* cseq */); 415 return; 416 } 417 418 if (method.startsWith("RTSP/")) { 419 // This is a response. 420 421 ResponseID id; 422 id.mSessionID = sessionID; 423 id.mCSeq = cseq; 424 425 ssize_t index = mResponseHandlers.indexOfKey(id); 426 427 if (index < 0) { 428 ALOGW("Received unsolicited server response, cseq %d", cseq); 429 return; 430 } 431 432 HandleRTSPResponseFunc func = mResponseHandlers.valueAt(index); 433 mResponseHandlers.removeItemsAt(index); 434 435 status_t err = (this->*func)(sessionID, data); 436 CHECK_EQ(err, (status_t)OK); 437 } else { 438 AString version; 439 data->getRequestField(2, &version); 440 if (!(version == AString("RTSP/1.0"))) { 441 sendErrorResponse(sessionID, "505 RTSP Version not supported", cseq); 442 return; 443 } 444 445 if (method == "OPTIONS") { 446 onOptionsRequest(sessionID, cseq, data); 447 } else if (method == "GET_PARAMETER") { 448 onGetParameterRequest(sessionID, cseq, data); 449 } else if (method == "SET_PARAMETER") { 450 onSetParameterRequest(sessionID, cseq, data); 451 } else { 452 sendErrorResponse(sessionID, "405 Method Not Allowed", cseq); 453 } 454 } 455} 456 457void WifiDisplaySink::onOptionsRequest( 458 int32_t sessionID, 459 int32_t cseq, 460 const sp<ParsedMessage> &data) { 461 AString response = "RTSP/1.0 200 OK\r\n"; 462 AppendCommonResponse(&response, cseq); 463 response.append("Public: org.wfa.wfd1.0, GET_PARAMETER, SET_PARAMETER\r\n"); 464 response.append("\r\n"); 465 466 status_t err = mNetSession->sendRequest(sessionID, response.c_str()); 467 CHECK_EQ(err, (status_t)OK); 468 469 err = sendM2(sessionID); 470 CHECK_EQ(err, (status_t)OK); 471} 472 473void WifiDisplaySink::onGetParameterRequest( 474 int32_t sessionID, 475 int32_t cseq, 476 const sp<ParsedMessage> &data) { 477 AString body = 478 "wfd_video_formats: xxx\r\n" 479 "wfd_audio_codecs: xxx\r\n" 480 "wfd_client_rtp_ports: RTP/AVP/UDP;unicast xxx 0 mode=play\r\n"; 481 482 AString response = "RTSP/1.0 200 OK\r\n"; 483 AppendCommonResponse(&response, cseq); 484 response.append("Content-Type: text/parameters\r\n"); 485 response.append(StringPrintf("Content-Length: %d\r\n", body.size())); 486 response.append("\r\n"); 487 response.append(body); 488 489 status_t err = mNetSession->sendRequest(sessionID, response.c_str()); 490 CHECK_EQ(err, (status_t)OK); 491} 492 493status_t WifiDisplaySink::sendDescribe(int32_t sessionID, const char *uri) { 494 uri = "rtsp://xwgntvx.is.livestream-api.com/livestreamiphone/wgntv"; 495 uri = "rtsp://v2.cache6.c.youtube.com/video.3gp?cid=e101d4bf280055f9&fmt=18"; 496 497 AString request = StringPrintf("DESCRIBE %s RTSP/1.0\r\n", uri); 498 AppendCommonResponse(&request, mNextCSeq); 499 500 request.append("Accept: application/sdp\r\n"); 501 request.append("\r\n"); 502 503 status_t err = mNetSession->sendRequest( 504 sessionID, request.c_str(), request.size()); 505 506 if (err != OK) { 507 return err; 508 } 509 510 registerResponseHandler( 511 sessionID, mNextCSeq, &WifiDisplaySink::onReceiveDescribeResponse); 512 513 ++mNextCSeq; 514 515 return OK; 516} 517 518status_t WifiDisplaySink::sendSetup(int32_t sessionID, const char *uri) { 519 mRTPSink = new RTPSink(mNetSession, mSurfaceTex); 520 looper()->registerHandler(mRTPSink); 521 522 status_t err = mRTPSink->init(sUseTCPInterleaving); 523 524 if (err != OK) { 525 looper()->unregisterHandler(mRTPSink->id()); 526 mRTPSink.clear(); 527 return err; 528 } 529 530 AString request = StringPrintf("SETUP %s RTSP/1.0\r\n", uri); 531 532 AppendCommonResponse(&request, mNextCSeq); 533 534 if (sUseTCPInterleaving) { 535 request.append("Transport: RTP/AVP/TCP;interleaved=0-1\r\n"); 536 } else { 537 int32_t rtpPort = mRTPSink->getRTPPort(); 538 539 request.append( 540 StringPrintf( 541 "Transport: RTP/AVP/UDP;unicast;client_port=%d-%d\r\n", 542 rtpPort, rtpPort + 1)); 543 } 544 545 request.append("\r\n"); 546 547 ALOGV("request = '%s'", request.c_str()); 548 549 err = mNetSession->sendRequest(sessionID, request.c_str(), request.size()); 550 551 if (err != OK) { 552 return err; 553 } 554 555 registerResponseHandler( 556 sessionID, mNextCSeq, &WifiDisplaySink::onReceiveSetupResponse); 557 558 ++mNextCSeq; 559 560 return OK; 561} 562 563status_t WifiDisplaySink::sendPlay(int32_t sessionID, const char *uri) { 564 AString request = StringPrintf("PLAY %s RTSP/1.0\r\n", uri); 565 566 AppendCommonResponse(&request, mNextCSeq); 567 568 request.append(StringPrintf("Session: %s\r\n", mPlaybackSessionID.c_str())); 569 request.append("\r\n"); 570 571 status_t err = 572 mNetSession->sendRequest(sessionID, request.c_str(), request.size()); 573 574 if (err != OK) { 575 return err; 576 } 577 578 registerResponseHandler( 579 sessionID, mNextCSeq, &WifiDisplaySink::onReceivePlayResponse); 580 581 ++mNextCSeq; 582 583 return OK; 584} 585 586void WifiDisplaySink::onSetParameterRequest( 587 int32_t sessionID, 588 int32_t cseq, 589 const sp<ParsedMessage> &data) { 590 const char *content = data->getContent(); 591 592 if (strstr(content, "wfd_trigger_method: SETUP\r\n") != NULL) { 593 status_t err = 594 sendSetup( 595 sessionID, 596 "rtsp://x.x.x.x:x/wfd1.0/streamid=0"); 597 598 CHECK_EQ(err, (status_t)OK); 599 } 600 601 AString response = "RTSP/1.0 200 OK\r\n"; 602 AppendCommonResponse(&response, cseq); 603 response.append("\r\n"); 604 605 status_t err = mNetSession->sendRequest(sessionID, response.c_str()); 606 CHECK_EQ(err, (status_t)OK); 607} 608 609void WifiDisplaySink::sendErrorResponse( 610 int32_t sessionID, 611 const char *errorDetail, 612 int32_t cseq) { 613 AString response; 614 response.append("RTSP/1.0 "); 615 response.append(errorDetail); 616 response.append("\r\n"); 617 618 AppendCommonResponse(&response, cseq); 619 620 response.append("\r\n"); 621 622 status_t err = mNetSession->sendRequest(sessionID, response.c_str()); 623 CHECK_EQ(err, (status_t)OK); 624} 625 626// static 627void WifiDisplaySink::AppendCommonResponse(AString *response, int32_t cseq) { 628 time_t now = time(NULL); 629 struct tm *now2 = gmtime(&now); 630 char buf[128]; 631 strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", now2); 632 633 response->append("Date: "); 634 response->append(buf); 635 response->append("\r\n"); 636 637 response->append("User-Agent: stagefright/1.1 (Linux;Android 4.1)\r\n"); 638 639 if (cseq >= 0) { 640 response->append(StringPrintf("CSeq: %d\r\n", cseq)); 641 } 642} 643 644} // namespace android 645