blob: 7f7aeacaab44fa423a7ee466d66f7b0e78bf47df [file] [log] [blame]
Andreas Huber35213f12012-08-29 11:41:50 -07001/*
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
Andreas Huber52299d82012-09-07 15:46:41 -070017//#define LOG_NDEBUG 0
Andreas Huber35213f12012-08-29 11:41:50 -070018#define LOG_TAG "WifiDisplaySource"
19#include <utils/Log.h>
20
21#include "WifiDisplaySource.h"
22#include "PlaybackSession.h"
Andreas Huber75a8df92012-09-18 14:47:48 -070023#include "Parameters.h"
Andreas Huber35213f12012-08-29 11:41:50 -070024#include "ParsedMessage.h"
25
Andreas Huber75a8df92012-09-18 14:47:48 -070026#include <binder/IServiceManager.h>
Andreas Huber28169b12012-09-05 10:26:52 -070027#include <gui/ISurfaceTexture.h>
Andreas Huber75a8df92012-09-18 14:47:48 -070028#include <media/IHDCP.h>
29#include <media/IMediaPlayerService.h>
Andreas Huber28169b12012-09-05 10:26:52 -070030#include <media/IRemoteDisplayClient.h>
Andreas Huber35213f12012-08-29 11:41:50 -070031#include <media/stagefright/foundation/ABuffer.h>
32#include <media/stagefright/foundation/ADebug.h>
33#include <media/stagefright/foundation/AMessage.h>
34#include <media/stagefright/MediaErrors.h>
35
Andreas Huberab1bd842012-08-30 14:51:40 -070036#include <arpa/inet.h>
Andreas Huber7d34f832012-09-13 11:25:33 -070037#include <cutils/properties.h>
Andreas Huberab1bd842012-08-30 14:51:40 -070038
Andreas Huber35213f12012-08-29 11:41:50 -070039namespace android {
40
Andreas Huber28169b12012-09-05 10:26:52 -070041WifiDisplaySource::WifiDisplaySource(
42 const sp<ANetworkSession> &netSession,
43 const sp<IRemoteDisplayClient> &client)
Andreas Huber35213f12012-08-29 11:41:50 -070044 : mNetSession(netSession),
Andreas Huber28169b12012-09-05 10:26:52 -070045 mClient(client),
Andreas Huber35213f12012-08-29 11:41:50 -070046 mSessionID(0),
Andreas Hubera71c3ea2012-09-21 16:02:39 -070047 mStopReplyID(0),
Andreas Huberc438b882012-09-17 15:07:30 -070048 mClientSessionID(0),
Andreas Huber35213f12012-08-29 11:41:50 -070049 mReaperPending(false),
Andreas Huber75a8df92012-09-18 14:47:48 -070050 mNextCSeq(1)
51#if REQUIRE_HDCP
52 ,mIsHDCP2_0(false)
53 ,mHDCPPort(0)
54 ,mHDCPInitializationComplete(false)
55 ,mSetupTriggerDeferred(false)
56#endif
57{
Andreas Huber35213f12012-08-29 11:41:50 -070058}
59
60WifiDisplaySource::~WifiDisplaySource() {
61}
62
Andreas Huberab1bd842012-08-30 14:51:40 -070063status_t WifiDisplaySource::start(const char *iface) {
Andreas Huber35213f12012-08-29 11:41:50 -070064 sp<AMessage> msg = new AMessage(kWhatStart, id());
Andreas Huberab1bd842012-08-30 14:51:40 -070065 msg->setString("iface", iface);
Andreas Huber35213f12012-08-29 11:41:50 -070066
67 sp<AMessage> response;
68 status_t err = msg->postAndAwaitResponse(&response);
69
70 if (err != OK) {
71 return err;
72 }
73
74 if (!response->findInt32("err", &err)) {
75 err = OK;
76 }
77
78 return err;
79}
80
81status_t WifiDisplaySource::stop() {
82 sp<AMessage> msg = new AMessage(kWhatStop, id());
83
84 sp<AMessage> response;
85 status_t err = msg->postAndAwaitResponse(&response);
86
87 if (err != OK) {
88 return err;
89 }
90
91 if (!response->findInt32("err", &err)) {
92 err = OK;
93 }
94
95 return err;
96}
97
98void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) {
99 switch (msg->what()) {
100 case kWhatStart:
101 {
102 uint32_t replyID;
103 CHECK(msg->senderAwaitsResponse(&replyID));
104
Andreas Huberab1bd842012-08-30 14:51:40 -0700105 AString iface;
106 CHECK(msg->findString("iface", &iface));
Andreas Huber35213f12012-08-29 11:41:50 -0700107
Andreas Huberab1bd842012-08-30 14:51:40 -0700108 status_t err = OK;
Andreas Huber35213f12012-08-29 11:41:50 -0700109
Andreas Huberab1bd842012-08-30 14:51:40 -0700110 ssize_t colonPos = iface.find(":");
111
112 unsigned long port;
113
114 if (colonPos >= 0) {
115 const char *s = iface.c_str() + colonPos + 1;
116
117 char *end;
118 port = strtoul(s, &end, 10);
119
120 if (end == s || *end != '\0' || port > 65535) {
121 err = -EINVAL;
122 } else {
123 iface.erase(colonPos, iface.size() - colonPos);
124 }
125 } else {
126 port = kWifiDisplayDefaultPort;
127 }
128
Andreas Huberab1bd842012-08-30 14:51:40 -0700129 if (err == OK) {
Andreas Huber7d34f832012-09-13 11:25:33 -0700130 if (inet_aton(iface.c_str(), &mInterfaceAddr) != 0) {
Andreas Huberab1bd842012-08-30 14:51:40 -0700131 sp<AMessage> notify = new AMessage(kWhatRTSPNotify, id());
132
133 err = mNetSession->createRTSPServer(
Andreas Huber7d34f832012-09-13 11:25:33 -0700134 mInterfaceAddr, port, notify, &mSessionID);
Andreas Huberab1bd842012-08-30 14:51:40 -0700135 } else {
136 err = -EINVAL;
137 }
138 }
Andreas Huber35213f12012-08-29 11:41:50 -0700139
140 sp<AMessage> response = new AMessage;
141 response->setInt32("err", err);
142 response->postReply(replyID);
143 break;
144 }
145
146 case kWhatRTSPNotify:
147 {
148 int32_t reason;
149 CHECK(msg->findInt32("reason", &reason));
150
151 switch (reason) {
152 case ANetworkSession::kWhatError:
153 {
154 int32_t sessionID;
155 CHECK(msg->findInt32("sessionID", &sessionID));
156
157 int32_t err;
158 CHECK(msg->findInt32("err", &err));
159
160 AString detail;
161 CHECK(msg->findString("detail", &detail));
162
163 ALOGE("An error occurred in session %d (%d, '%s/%s').",
164 sessionID,
165 err,
166 detail.c_str(),
167 strerror(-err));
168
169 mNetSession->destroySession(sessionID);
170
Andreas Huberc438b882012-09-17 15:07:30 -0700171 if (sessionID == mClientSessionID) {
172 mClientSessionID = -1;
173
174 disconnectClient(UNKNOWN_ERROR);
175 }
Andreas Huber35213f12012-08-29 11:41:50 -0700176 break;
177 }
178
179 case ANetworkSession::kWhatClientConnected:
180 {
181 int32_t sessionID;
182 CHECK(msg->findInt32("sessionID", &sessionID));
183
Andreas Huberc438b882012-09-17 15:07:30 -0700184 if (mClientSessionID > 0) {
185 ALOGW("A client tried to connect, but we already "
186 "have one.");
187
188 mNetSession->destroySession(sessionID);
189 break;
190 }
191
192 CHECK(msg->findString("client-ip", &mClientInfo.mRemoteIP));
193 CHECK(msg->findString("server-ip", &mClientInfo.mLocalIP));
194
195 if (mClientInfo.mRemoteIP == mClientInfo.mLocalIP) {
196 // Disallow connections from the local interface
197 // for security reasons.
198 mNetSession->destroySession(sessionID);
199 break;
200 }
201
202 CHECK(msg->findInt32(
203 "server-port", &mClientInfo.mLocalPort));
204 mClientInfo.mPlaybackSessionID = -1;
205
206 mClientSessionID = sessionID;
Andreas Huber35213f12012-08-29 11:41:50 -0700207
208 ALOGI("We now have a client (%d) connected.", sessionID);
209
Andreas Huber35213f12012-08-29 11:41:50 -0700210 status_t err = sendM1(sessionID);
211 CHECK_EQ(err, (status_t)OK);
212 break;
213 }
214
215 case ANetworkSession::kWhatData:
216 {
Andreas Huber75a8df92012-09-18 14:47:48 -0700217 status_t err = onReceiveClientData(msg);
218
219 if (err != OK) {
220 disconnectClient(err);
221 }
Andreas Huber35213f12012-08-29 11:41:50 -0700222 break;
223 }
224
225 default:
226 TRESPASS();
227 }
228 break;
229 }
230
231 case kWhatStop:
232 {
233 uint32_t replyID;
234 CHECK(msg->senderAwaitsResponse(&replyID));
235
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700236 if (mSessionID != 0 && mClientSessionID != 0) {
237 status_t err = sendM5(
238 mClientSessionID, true /* requestShutdown */);
Andreas Huber28169b12012-09-05 10:26:52 -0700239
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700240 if (err == OK) {
241 mStopReplyID = replyID;
242 break;
243 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700244 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700245
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700246 finishStop(replyID);
Andreas Huber35213f12012-08-29 11:41:50 -0700247 break;
248 }
249
250 case kWhatReapDeadClients:
251 {
252 mReaperPending = false;
253
Andreas Huberc438b882012-09-17 15:07:30 -0700254 if (mClientSessionID == 0
255 || mClientInfo.mPlaybackSession == NULL) {
256 break;
Andreas Huber35213f12012-08-29 11:41:50 -0700257 }
258
Andreas Huberc438b882012-09-17 15:07:30 -0700259 if (mClientInfo.mPlaybackSession->getLastLifesignUs()
260 + kPlaybackSessionTimeoutUs < ALooper::GetNowUs()) {
261 ALOGI("playback session timed out, reaping.");
262
263 disconnectClient(-ETIMEDOUT);
264 } else {
Andreas Huber35213f12012-08-29 11:41:50 -0700265 scheduleReaper();
266 }
267 break;
268 }
269
270 case kWhatPlaybackSessionNotify:
271 {
272 int32_t playbackSessionID;
273 CHECK(msg->findInt32("playbackSessionID", &playbackSessionID));
274
275 int32_t what;
276 CHECK(msg->findInt32("what", &what));
277
Andreas Huberc438b882012-09-17 15:07:30 -0700278 if (what == PlaybackSession::kWhatSessionDead) {
279 ALOGI("playback session wants to quit.");
Andreas Huber35213f12012-08-29 11:41:50 -0700280
Andreas Huberc438b882012-09-17 15:07:30 -0700281 disconnectClient(UNKNOWN_ERROR);
282 } else if (what == PlaybackSession::kWhatSessionEstablished) {
283 if (mClient != NULL) {
284 mClient->onDisplayConnected(
285 mClientInfo.mPlaybackSession->getSurfaceTexture(),
286 mClientInfo.mPlaybackSession->width(),
287 mClientInfo.mPlaybackSession->height(),
288 0 /* flags */);
Andreas Huber35213f12012-08-29 11:41:50 -0700289 }
Andreas Huberc438b882012-09-17 15:07:30 -0700290 } else {
291 CHECK_EQ(what, PlaybackSession::kWhatBinaryData);
292
293 int32_t channel;
294 CHECK(msg->findInt32("channel", &channel));
295
296 sp<ABuffer> data;
297 CHECK(msg->findBuffer("data", &data));
298
299 CHECK_LE(channel, 0xffu);
300 CHECK_LE(data->size(), 0xffffu);
301
302 int32_t sessionID;
303 CHECK(msg->findInt32("sessionID", &sessionID));
304
305 char header[4];
306 header[0] = '$';
307 header[1] = channel;
308 header[2] = data->size() >> 8;
309 header[3] = data->size() & 0xff;
310
311 mNetSession->sendRequest(
312 sessionID, header, sizeof(header));
313
314 mNetSession->sendRequest(
315 sessionID, data->data(), data->size());
Andreas Huber35213f12012-08-29 11:41:50 -0700316 }
317 break;
318 }
319
Andreas Huber54408d82012-08-30 16:04:34 -0700320 case kWhatKeepAlive:
321 {
322 int32_t sessionID;
323 CHECK(msg->findInt32("sessionID", &sessionID));
324
Andreas Huberc438b882012-09-17 15:07:30 -0700325 if (mClientSessionID != sessionID) {
Andreas Huber54408d82012-08-30 16:04:34 -0700326 // Obsolete event, client is already gone.
327 break;
328 }
329
330 sendM16(sessionID);
331 break;
332 }
333
Andreas Huber75a8df92012-09-18 14:47:48 -0700334#if REQUIRE_HDCP
335 case kWhatHDCPNotify:
336 {
337 int32_t msgCode, ext1, ext2;
338 CHECK(msg->findInt32("msg", &msgCode));
339 CHECK(msg->findInt32("ext1", &ext1));
340 CHECK(msg->findInt32("ext2", &ext2));
341
342 ALOGV("Saw HDCP notification code %d, ext1 %d, ext2 %d",
343 msgCode, ext1, ext2);
344
345 switch (msgCode) {
346 case HDCPModule::HDCP_INITIALIZATION_COMPLETE:
347 {
348 mHDCPInitializationComplete = true;
349
350 if (mSetupTriggerDeferred) {
351 mSetupTriggerDeferred = false;
352
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700353 sendM5(mClientSessionID, false /* requestShutdown */);
Andreas Huber75a8df92012-09-18 14:47:48 -0700354 }
355 break;
356 }
357
358 default:
359 {
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700360 ALOGE("HDCP failure, shutting down.");
361
Andreas Huber75a8df92012-09-18 14:47:48 -0700362 disconnectClient(-EACCES);
363 break;
364 }
365 }
366 break;
367 }
368#endif
369
Andreas Huber35213f12012-08-29 11:41:50 -0700370 default:
371 TRESPASS();
372 }
373}
374
375void WifiDisplaySource::registerResponseHandler(
376 int32_t sessionID, int32_t cseq, HandleRTSPResponseFunc func) {
377 ResponseID id;
378 id.mSessionID = sessionID;
379 id.mCSeq = cseq;
380 mResponseHandlers.add(id, func);
381}
382
383status_t WifiDisplaySource::sendM1(int32_t sessionID) {
384 AString request = "OPTIONS * RTSP/1.0\r\n";
385 AppendCommonResponse(&request, mNextCSeq);
386
387 request.append(
388 "Require: org.wfa.wfd1.0\r\n"
389 "\r\n");
390
391 status_t err =
392 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
393
394 if (err != OK) {
395 return err;
396 }
397
398 registerResponseHandler(
399 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM1Response);
400
401 ++mNextCSeq;
402
403 return OK;
404}
405
406status_t WifiDisplaySource::sendM3(int32_t sessionID) {
407 AString body =
Andreas Huber75a8df92012-09-18 14:47:48 -0700408#if REQUIRE_HDCP
409 "wfd_content_protection\r\n"
410#endif
Andreas Huber35213f12012-08-29 11:41:50 -0700411 "wfd_video_formats\r\n"
412 "wfd_audio_codecs\r\n"
413 "wfd_client_rtp_ports\r\n";
414
415 AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
416 AppendCommonResponse(&request, mNextCSeq);
417
418 request.append("Content-Type: text/parameters\r\n");
419 request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
420 request.append("\r\n");
421 request.append(body);
422
423 status_t err =
424 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
425
426 if (err != OK) {
427 return err;
428 }
429
430 registerResponseHandler(
431 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM3Response);
432
433 ++mNextCSeq;
434
435 return OK;
436}
437
438status_t WifiDisplaySource::sendM4(int32_t sessionID) {
439 // wfd_video_formats:
440 // 1 byte "native"
441 // 1 byte "preferred-display-mode-supported" 0 or 1
442 // one or more avc codec structures
443 // 1 byte profile
444 // 1 byte level
445 // 4 byte CEA mask
446 // 4 byte VESA mask
447 // 4 byte HH mask
448 // 1 byte latency
449 // 2 byte min-slice-slice
450 // 2 byte slice-enc-params
451 // 1 byte framerate-control-support
452 // max-hres (none or 2 byte)
453 // max-vres (none or 2 byte)
454
Andreas Huberc438b882012-09-17 15:07:30 -0700455 CHECK_EQ(sessionID, mClientSessionID);
Andreas Huber35213f12012-08-29 11:41:50 -0700456
Andreas Huber7d34f832012-09-13 11:25:33 -0700457 AString transportString = "UDP";
458
459 char val[PROPERTY_VALUE_MAX];
460 if (property_get("media.wfd.enable-tcp", val, NULL)
461 && (!strcasecmp("true", val) || !strcmp("1", val))) {
462 ALOGI("Using TCP transport.");
463 transportString = "TCP";
464 }
465
Andreas Huber75a8df92012-09-18 14:47:48 -0700466 // For 720p60:
467 // use "30 00 02 02 00000040 00000000 00000000 00 0000 0000 00 none none\r\n"
468 // For 720p30:
469 // use "28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none\r\n"
Andreas Huber35213f12012-08-29 11:41:50 -0700470 AString body = StringPrintf(
471 "wfd_video_formats: "
Andreas Huber75a8df92012-09-18 14:47:48 -0700472 "28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none\r\n"
Andreas Huber35213f12012-08-29 11:41:50 -0700473 "wfd_audio_codecs: AAC 00000001 00\r\n" // 2 ch AAC 48kHz
474 "wfd_presentation_URL: rtsp://%s:%d/wfd1.0/streamid=0 none\r\n"
Andreas Huber7d34f832012-09-13 11:25:33 -0700475 "wfd_client_rtp_ports: RTP/AVP/%s;unicast 19000 0 mode=play\r\n",
Andreas Huberc438b882012-09-17 15:07:30 -0700476 mClientInfo.mLocalIP.c_str(), mClientInfo.mLocalPort,
477 transportString.c_str());
Andreas Huber35213f12012-08-29 11:41:50 -0700478
479 AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
480 AppendCommonResponse(&request, mNextCSeq);
481
482 request.append("Content-Type: text/parameters\r\n");
483 request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
484 request.append("\r\n");
485 request.append(body);
486
487 status_t err =
488 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
489
490 if (err != OK) {
491 return err;
492 }
493
494 registerResponseHandler(
495 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM4Response);
496
497 ++mNextCSeq;
498
499 return OK;
500}
501
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700502status_t WifiDisplaySource::sendM5(int32_t sessionID, bool requestShutdown) {
503 AString body = "wfd_trigger_method: ";
504 if (requestShutdown) {
505 body.append("TEARDOWN");
506 } else {
507 body.append("SETUP");
508 }
509
510 body.append("\r\n");
Andreas Huber35213f12012-08-29 11:41:50 -0700511
512 AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
513 AppendCommonResponse(&request, mNextCSeq);
514
515 request.append("Content-Type: text/parameters\r\n");
516 request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
517 request.append("\r\n");
518 request.append(body);
519
520 status_t err =
521 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
522
523 if (err != OK) {
524 return err;
525 }
526
527 registerResponseHandler(
528 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM5Response);
529
530 ++mNextCSeq;
531
532 return OK;
533}
534
Andreas Huber54408d82012-08-30 16:04:34 -0700535status_t WifiDisplaySource::sendM16(int32_t sessionID) {
536 AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
537 AppendCommonResponse(&request, mNextCSeq);
538
Andreas Huberc438b882012-09-17 15:07:30 -0700539 CHECK_EQ(sessionID, mClientSessionID);
540 request.append(
541 StringPrintf("Session: %d\r\n", mClientInfo.mPlaybackSessionID));
Andreas Huber596b4cd2012-09-12 16:25:14 -0700542 request.append("\r\n"); // Empty body
Andreas Huber54408d82012-08-30 16:04:34 -0700543
544 status_t err =
545 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
546
547 if (err != OK) {
548 return err;
549 }
550
551 registerResponseHandler(
552 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM16Response);
553
554 ++mNextCSeq;
555
556 return OK;
557}
558
Andreas Huber35213f12012-08-29 11:41:50 -0700559status_t WifiDisplaySource::onReceiveM1Response(
560 int32_t sessionID, const sp<ParsedMessage> &msg) {
561 int32_t statusCode;
562 if (!msg->getStatusCode(&statusCode)) {
563 return ERROR_MALFORMED;
564 }
565
566 if (statusCode != 200) {
567 return ERROR_UNSUPPORTED;
568 }
569
570 return OK;
571}
572
573status_t WifiDisplaySource::onReceiveM3Response(
574 int32_t sessionID, const sp<ParsedMessage> &msg) {
575 int32_t statusCode;
576 if (!msg->getStatusCode(&statusCode)) {
577 return ERROR_MALFORMED;
578 }
579
580 if (statusCode != 200) {
581 return ERROR_UNSUPPORTED;
582 }
583
Andreas Huber75a8df92012-09-18 14:47:48 -0700584 sp<Parameters> params =
585 Parameters::Parse(msg->getContent(), strlen(msg->getContent()));
586
587 if (params == NULL) {
588 return ERROR_MALFORMED;
589 }
590
591#if REQUIRE_HDCP
592 AString value;
593 if (!params->findParameter("wfd_content_protection", &value)) {
594 ALOGE("Sink doesn't appear to support content protection.");
595 return -EACCES;
596 }
597
598 if (value == "none") {
599 ALOGE("Sink does not support content protection.");
600 return -EACCES;
601 }
602
603 bool isHDCP2_0 = false;
604 if (value.startsWith("HDCP2.0 ")) {
605 isHDCP2_0 = true;
606 } else if (!value.startsWith("HDCP2.1 ")) {
607 return ERROR_MALFORMED;
608 }
609
610 int32_t hdcpPort;
611 if (!ParsedMessage::GetInt32Attribute(value.c_str() + 8, "port", &hdcpPort)
612 || hdcpPort < 1 || hdcpPort > 65535) {
613 return ERROR_MALFORMED;
614 }
615
616 mIsHDCP2_0 = isHDCP2_0;
617 mHDCPPort = hdcpPort;
618
619 status_t err = makeHDCP();
620 if (err != OK) {
621 ALOGE("Unable to instantiate HDCP component.");
622 return err;
623 }
624#endif
625
Andreas Huber35213f12012-08-29 11:41:50 -0700626 return sendM4(sessionID);
627}
628
629status_t WifiDisplaySource::onReceiveM4Response(
630 int32_t sessionID, const sp<ParsedMessage> &msg) {
631 int32_t statusCode;
632 if (!msg->getStatusCode(&statusCode)) {
633 return ERROR_MALFORMED;
634 }
635
636 if (statusCode != 200) {
637 return ERROR_UNSUPPORTED;
638 }
639
Andreas Huber75a8df92012-09-18 14:47:48 -0700640#if REQUIRE_HDCP
641 if (!mHDCPInitializationComplete) {
642 ALOGI("Deferring SETUP trigger until HDCP initialization completes.");
643
644 mSetupTriggerDeferred = true;
645 return OK;
646 }
647#endif
648
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700649 return sendM5(sessionID, false /* requestShutdown */);
Andreas Huber35213f12012-08-29 11:41:50 -0700650}
651
652status_t WifiDisplaySource::onReceiveM5Response(
653 int32_t sessionID, const sp<ParsedMessage> &msg) {
654 int32_t statusCode;
655 if (!msg->getStatusCode(&statusCode)) {
656 return ERROR_MALFORMED;
657 }
658
659 if (statusCode != 200) {
660 return ERROR_UNSUPPORTED;
661 }
662
663 return OK;
664}
665
Andreas Huber54408d82012-08-30 16:04:34 -0700666status_t WifiDisplaySource::onReceiveM16Response(
667 int32_t sessionID, const sp<ParsedMessage> &msg) {
668 // If only the response was required to include a "Session:" header...
669
Andreas Huberc438b882012-09-17 15:07:30 -0700670 CHECK_EQ(sessionID, mClientSessionID);
Andreas Huber54408d82012-08-30 16:04:34 -0700671
Andreas Huberc438b882012-09-17 15:07:30 -0700672 if (mClientInfo.mPlaybackSession != NULL) {
673 mClientInfo.mPlaybackSession->updateLiveness();
Andreas Huber54408d82012-08-30 16:04:34 -0700674
675 scheduleKeepAlive(sessionID);
676 }
677
678 return OK;
679}
680
Andreas Huber35213f12012-08-29 11:41:50 -0700681void WifiDisplaySource::scheduleReaper() {
682 if (mReaperPending) {
683 return;
684 }
685
686 mReaperPending = true;
687 (new AMessage(kWhatReapDeadClients, id()))->post(kReaperIntervalUs);
688}
689
Andreas Huber54408d82012-08-30 16:04:34 -0700690void WifiDisplaySource::scheduleKeepAlive(int32_t sessionID) {
691 // We need to send updates at least 5 secs before the timeout is set to
692 // expire, make sure the timeout is greater than 5 secs to begin with.
693 CHECK_GT(kPlaybackSessionTimeoutUs, 5000000ll);
694
695 sp<AMessage> msg = new AMessage(kWhatKeepAlive, id());
696 msg->setInt32("sessionID", sessionID);
697 msg->post(kPlaybackSessionTimeoutUs - 5000000ll);
698}
699
Andreas Huber75a8df92012-09-18 14:47:48 -0700700status_t WifiDisplaySource::onReceiveClientData(const sp<AMessage> &msg) {
Andreas Huber35213f12012-08-29 11:41:50 -0700701 int32_t sessionID;
702 CHECK(msg->findInt32("sessionID", &sessionID));
703
704 sp<RefBase> obj;
705 CHECK(msg->findObject("data", &obj));
706
707 sp<ParsedMessage> data =
708 static_cast<ParsedMessage *>(obj.get());
709
710 ALOGV("session %d received '%s'",
711 sessionID, data->debugString().c_str());
712
713 AString method;
714 AString uri;
715 data->getRequestField(0, &method);
716
717 int32_t cseq;
718 if (!data->findInt32("cseq", &cseq)) {
719 sendErrorResponse(sessionID, "400 Bad Request", -1 /* cseq */);
Andreas Huber75a8df92012-09-18 14:47:48 -0700720 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700721 }
722
723 if (method.startsWith("RTSP/")) {
724 // This is a response.
725
726 ResponseID id;
727 id.mSessionID = sessionID;
728 id.mCSeq = cseq;
729
730 ssize_t index = mResponseHandlers.indexOfKey(id);
731
732 if (index < 0) {
733 ALOGW("Received unsolicited server response, cseq %d", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700734 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700735 }
736
737 HandleRTSPResponseFunc func = mResponseHandlers.valueAt(index);
738 mResponseHandlers.removeItemsAt(index);
739
740 status_t err = (this->*func)(sessionID, data);
741
742 if (err != OK) {
743 ALOGW("Response handler for session %d, cseq %d returned "
744 "err %d (%s)",
745 sessionID, cseq, err, strerror(-err));
Andreas Huber75a8df92012-09-18 14:47:48 -0700746
747 return err;
Andreas Huber35213f12012-08-29 11:41:50 -0700748 }
749
Andreas Huber75a8df92012-09-18 14:47:48 -0700750 return OK;
Andreas Huber35213f12012-08-29 11:41:50 -0700751 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700752
753 AString version;
754 data->getRequestField(2, &version);
755 if (!(version == AString("RTSP/1.0"))) {
756 sendErrorResponse(sessionID, "505 RTSP Version not supported", cseq);
757 return ERROR_UNSUPPORTED;
758 }
759
760 status_t err;
761 if (method == "OPTIONS") {
762 err = onOptionsRequest(sessionID, cseq, data);
763 } else if (method == "SETUP") {
764 err = onSetupRequest(sessionID, cseq, data);
765 } else if (method == "PLAY") {
766 err = onPlayRequest(sessionID, cseq, data);
767 } else if (method == "PAUSE") {
768 err = onPauseRequest(sessionID, cseq, data);
769 } else if (method == "TEARDOWN") {
770 err = onTeardownRequest(sessionID, cseq, data);
771 } else if (method == "GET_PARAMETER") {
772 err = onGetParameterRequest(sessionID, cseq, data);
773 } else if (method == "SET_PARAMETER") {
774 err = onSetParameterRequest(sessionID, cseq, data);
775 } else {
776 sendErrorResponse(sessionID, "405 Method Not Allowed", cseq);
777
778 err = ERROR_UNSUPPORTED;
779 }
780
781 return err;
Andreas Huber35213f12012-08-29 11:41:50 -0700782}
783
Andreas Huber75a8df92012-09-18 14:47:48 -0700784status_t WifiDisplaySource::onOptionsRequest(
Andreas Huber35213f12012-08-29 11:41:50 -0700785 int32_t sessionID,
786 int32_t cseq,
787 const sp<ParsedMessage> &data) {
788 int32_t playbackSessionID;
789 sp<PlaybackSession> playbackSession =
790 findPlaybackSession(data, &playbackSessionID);
791
792 if (playbackSession != NULL) {
793 playbackSession->updateLiveness();
794 }
795
796 AString response = "RTSP/1.0 200 OK\r\n";
797 AppendCommonResponse(&response, cseq);
798
799 response.append(
Andreas Huber75a8df92012-09-18 14:47:48 -0700800 "Public: org.wfa.wfd1.0, SETUP, TEARDOWN, PLAY, PAUSE, "
Andreas Huber35213f12012-08-29 11:41:50 -0700801 "GET_PARAMETER, SET_PARAMETER\r\n");
802
803 response.append("\r\n");
804
805 status_t err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber35213f12012-08-29 11:41:50 -0700806
Andreas Huber75a8df92012-09-18 14:47:48 -0700807 if (err == OK) {
808 err = sendM3(sessionID);
809 }
810
811 return err;
Andreas Huber35213f12012-08-29 11:41:50 -0700812}
813
Andreas Huber75a8df92012-09-18 14:47:48 -0700814status_t WifiDisplaySource::onSetupRequest(
Andreas Huber35213f12012-08-29 11:41:50 -0700815 int32_t sessionID,
816 int32_t cseq,
817 const sp<ParsedMessage> &data) {
Andreas Huberc438b882012-09-17 15:07:30 -0700818 CHECK_EQ(sessionID, mClientSessionID);
819 if (mClientInfo.mPlaybackSessionID != -1) {
Andreas Huber54408d82012-08-30 16:04:34 -0700820 // We only support a single playback session per client.
821 // This is due to the reversed keep-alive design in the wfd specs...
822 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700823 return ERROR_MALFORMED;
Andreas Huber54408d82012-08-30 16:04:34 -0700824 }
825
Andreas Huber35213f12012-08-29 11:41:50 -0700826 AString transport;
827 if (!data->findString("transport", &transport)) {
828 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700829 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700830 }
831
Andreas Huber7d34f832012-09-13 11:25:33 -0700832 PlaybackSession::TransportMode transportMode =
833 PlaybackSession::TRANSPORT_UDP;
Andreas Huber35213f12012-08-29 11:41:50 -0700834
835 int clientRtp, clientRtcp;
836 if (transport.startsWith("RTP/AVP/TCP;")) {
837 AString interleaved;
Andreas Huber7d34f832012-09-13 11:25:33 -0700838 if (ParsedMessage::GetAttribute(
Andreas Huber35213f12012-08-29 11:41:50 -0700839 transport.c_str(), "interleaved", &interleaved)
Andreas Huber7d34f832012-09-13 11:25:33 -0700840 && sscanf(interleaved.c_str(), "%d-%d",
841 &clientRtp, &clientRtcp) == 2) {
842 transportMode = PlaybackSession::TRANSPORT_TCP_INTERLEAVED;
843 } else {
844 bool badRequest = false;
Andreas Huber35213f12012-08-29 11:41:50 -0700845
Andreas Huber7d34f832012-09-13 11:25:33 -0700846 AString clientPort;
847 if (!ParsedMessage::GetAttribute(
848 transport.c_str(), "client_port", &clientPort)) {
849 badRequest = true;
850 } else if (sscanf(clientPort.c_str(), "%d-%d",
851 &clientRtp, &clientRtcp) == 2) {
852 } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
853 // No RTCP.
854 clientRtcp = -1;
855 } else {
856 badRequest = true;
857 }
858
859 if (badRequest) {
860 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700861 return ERROR_MALFORMED;
Andreas Huber7d34f832012-09-13 11:25:33 -0700862 }
863
864 transportMode = PlaybackSession::TRANSPORT_TCP;
865 }
Andreas Huber35213f12012-08-29 11:41:50 -0700866 } else if (transport.startsWith("RTP/AVP;unicast;")
867 || transport.startsWith("RTP/AVP/UDP;unicast;")) {
868 bool badRequest = false;
869
870 AString clientPort;
871 if (!ParsedMessage::GetAttribute(
872 transport.c_str(), "client_port", &clientPort)) {
873 badRequest = true;
874 } else if (sscanf(clientPort.c_str(), "%d-%d",
875 &clientRtp, &clientRtcp) == 2) {
876 } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
877 // No RTCP.
878 clientRtcp = -1;
879 } else {
880 badRequest = true;
881 }
882
883 if (badRequest) {
884 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700885 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700886 }
887#if 1
Andreas Huber596b4cd2012-09-12 16:25:14 -0700888 // The older LG dongles doesn't specify client_port=xxx apparently.
Andreas Huber35213f12012-08-29 11:41:50 -0700889 } else if (transport == "RTP/AVP/UDP;unicast") {
890 clientRtp = 19000;
Andreas Huber0d767952012-09-25 14:20:08 -0700891 clientRtcp = -1;
Andreas Huber35213f12012-08-29 11:41:50 -0700892#endif
893 } else {
894 sendErrorResponse(sessionID, "461 Unsupported Transport", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700895 return ERROR_UNSUPPORTED;
Andreas Huber35213f12012-08-29 11:41:50 -0700896 }
897
898 int32_t playbackSessionID = makeUniquePlaybackSessionID();
899
900 sp<AMessage> notify = new AMessage(kWhatPlaybackSessionNotify, id());
901 notify->setInt32("playbackSessionID", playbackSessionID);
902 notify->setInt32("sessionID", sessionID);
903
904 sp<PlaybackSession> playbackSession =
Andreas Huber28169b12012-09-05 10:26:52 -0700905 new PlaybackSession(
Andreas Huber7d34f832012-09-13 11:25:33 -0700906 mNetSession, notify, mInterfaceAddr,
Andreas Huber75a8df92012-09-18 14:47:48 -0700907#if REQUIRE_HDCP
908 mHDCP
909#else
910 NULL
911#endif
912 );
Andreas Huber35213f12012-08-29 11:41:50 -0700913
914 looper()->registerHandler(playbackSession);
915
916 AString uri;
917 data->getRequestField(1, &uri);
918
919 if (strncasecmp("rtsp://", uri.c_str(), 7)) {
920 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700921 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700922 }
923
924 if (!(uri.startsWith("rtsp://") && uri.endsWith("/wfd1.0/streamid=0"))) {
925 sendErrorResponse(sessionID, "404 Not found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700926 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700927 }
928
Andreas Huber35213f12012-08-29 11:41:50 -0700929 status_t err = playbackSession->init(
Andreas Huberc438b882012-09-17 15:07:30 -0700930 mClientInfo.mRemoteIP.c_str(),
Andreas Huber35213f12012-08-29 11:41:50 -0700931 clientRtp,
932 clientRtcp,
Andreas Huber7d34f832012-09-13 11:25:33 -0700933 transportMode);
Andreas Huber35213f12012-08-29 11:41:50 -0700934
935 if (err != OK) {
936 looper()->unregisterHandler(playbackSession->id());
937 playbackSession.clear();
938 }
939
940 switch (err) {
941 case OK:
942 break;
943 case -ENOENT:
944 sendErrorResponse(sessionID, "404 Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700945 return err;
Andreas Huber35213f12012-08-29 11:41:50 -0700946 default:
947 sendErrorResponse(sessionID, "403 Forbidden", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700948 return err;
Andreas Huber35213f12012-08-29 11:41:50 -0700949 }
950
Andreas Huberc438b882012-09-17 15:07:30 -0700951 mClientInfo.mPlaybackSessionID = playbackSessionID;
952 mClientInfo.mPlaybackSession = playbackSession;
Andreas Huber54408d82012-08-30 16:04:34 -0700953
Andreas Huber35213f12012-08-29 11:41:50 -0700954 AString response = "RTSP/1.0 200 OK\r\n";
955 AppendCommonResponse(&response, cseq, playbackSessionID);
956
Andreas Huber7d34f832012-09-13 11:25:33 -0700957 if (transportMode == PlaybackSession::TRANSPORT_TCP_INTERLEAVED) {
Andreas Huber35213f12012-08-29 11:41:50 -0700958 response.append(
959 StringPrintf(
960 "Transport: RTP/AVP/TCP;interleaved=%d-%d;",
961 clientRtp, clientRtcp));
962 } else {
963 int32_t serverRtp = playbackSession->getRTPPort();
964
Andreas Huber7d34f832012-09-13 11:25:33 -0700965 AString transportString = "UDP";
966 if (transportMode == PlaybackSession::TRANSPORT_TCP) {
967 transportString = "TCP";
968 }
969
Andreas Huber35213f12012-08-29 11:41:50 -0700970 if (clientRtcp >= 0) {
971 response.append(
972 StringPrintf(
Andreas Huber7d34f832012-09-13 11:25:33 -0700973 "Transport: RTP/AVP/%s;unicast;client_port=%d-%d;"
Andreas Huber35213f12012-08-29 11:41:50 -0700974 "server_port=%d-%d\r\n",
Andreas Huber7d34f832012-09-13 11:25:33 -0700975 transportString.c_str(),
Andreas Huber35213f12012-08-29 11:41:50 -0700976 clientRtp, clientRtcp, serverRtp, serverRtp + 1));
977 } else {
978 response.append(
979 StringPrintf(
Andreas Huber7d34f832012-09-13 11:25:33 -0700980 "Transport: RTP/AVP/%s;unicast;client_port=%d;"
Andreas Huber35213f12012-08-29 11:41:50 -0700981 "server_port=%d\r\n",
Andreas Huber7d34f832012-09-13 11:25:33 -0700982 transportString.c_str(),
Andreas Huber35213f12012-08-29 11:41:50 -0700983 clientRtp, serverRtp));
984 }
985 }
986
987 response.append("\r\n");
988
989 err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -0700990
991 if (err != OK) {
992 return err;
993 }
Andreas Huber35213f12012-08-29 11:41:50 -0700994
Andreas Huber35213f12012-08-29 11:41:50 -0700995 scheduleReaper();
Andreas Huber54408d82012-08-30 16:04:34 -0700996 scheduleKeepAlive(sessionID);
Andreas Huber75a8df92012-09-18 14:47:48 -0700997
998 return OK;
Andreas Huber35213f12012-08-29 11:41:50 -0700999}
1000
Andreas Huber75a8df92012-09-18 14:47:48 -07001001status_t WifiDisplaySource::onPlayRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001002 int32_t sessionID,
1003 int32_t cseq,
1004 const sp<ParsedMessage> &data) {
1005 int32_t playbackSessionID;
1006 sp<PlaybackSession> playbackSession =
1007 findPlaybackSession(data, &playbackSessionID);
1008
1009 if (playbackSession == NULL) {
1010 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001011 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001012 }
1013
1014 status_t err = playbackSession->play();
1015 CHECK_EQ(err, (status_t)OK);
1016
1017 AString response = "RTSP/1.0 200 OK\r\n";
1018 AppendCommonResponse(&response, cseq, playbackSessionID);
1019 response.append("Range: npt=now-\r\n");
1020 response.append("\r\n");
1021
1022 err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001023
1024 if (err != OK) {
1025 return err;
1026 }
Andreas Huber28169b12012-09-05 10:26:52 -07001027
Andreas Huber7d34f832012-09-13 11:25:33 -07001028 playbackSession->finishPlay();
Andreas Huber75a8df92012-09-18 14:47:48 -07001029
1030 return OK;
Andreas Huber35213f12012-08-29 11:41:50 -07001031}
1032
Andreas Huber75a8df92012-09-18 14:47:48 -07001033status_t WifiDisplaySource::onPauseRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001034 int32_t sessionID,
1035 int32_t cseq,
1036 const sp<ParsedMessage> &data) {
1037 int32_t playbackSessionID;
1038 sp<PlaybackSession> playbackSession =
1039 findPlaybackSession(data, &playbackSessionID);
1040
1041 if (playbackSession == NULL) {
1042 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001043 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001044 }
1045
1046 status_t err = playbackSession->pause();
1047 CHECK_EQ(err, (status_t)OK);
1048
1049 AString response = "RTSP/1.0 200 OK\r\n";
1050 AppendCommonResponse(&response, cseq, playbackSessionID);
1051 response.append("\r\n");
1052
1053 err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001054
1055 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001056}
1057
Andreas Huber75a8df92012-09-18 14:47:48 -07001058status_t WifiDisplaySource::onTeardownRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001059 int32_t sessionID,
1060 int32_t cseq,
1061 const sp<ParsedMessage> &data) {
1062 int32_t playbackSessionID;
1063 sp<PlaybackSession> playbackSession =
1064 findPlaybackSession(data, &playbackSessionID);
1065
1066 if (playbackSession == NULL) {
1067 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001068 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001069 }
1070
Andreas Huber35213f12012-08-29 11:41:50 -07001071 AString response = "RTSP/1.0 200 OK\r\n";
1072 AppendCommonResponse(&response, cseq, playbackSessionID);
Andreas Huberc438b882012-09-17 15:07:30 -07001073 response.append("Connection: close\r\n");
Andreas Huber35213f12012-08-29 11:41:50 -07001074 response.append("\r\n");
1075
1076 status_t err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001077
1078 if (err != OK) {
1079 return err;
1080 }
Andreas Huberc438b882012-09-17 15:07:30 -07001081
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001082 if (mStopReplyID != 0) {
1083 finishStop(mStopReplyID);
1084 mStopReplyID = 0;
1085 } else {
1086 disconnectClient(UNKNOWN_ERROR);
1087 }
Andreas Huber75a8df92012-09-18 14:47:48 -07001088
1089 return OK;
Andreas Huber35213f12012-08-29 11:41:50 -07001090}
1091
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001092void WifiDisplaySource::finishStop(uint32_t replyID) {
1093 disconnectClient(OK);
1094
1095#if REQUIRE_HDCP
1096 if (mHDCP != NULL) {
1097 mHDCP->shutdownAsync();
1098 mHDCP.clear();
1099 }
1100#endif
1101
1102 status_t err = OK;
1103
1104 sp<AMessage> response = new AMessage;
1105 response->setInt32("err", err);
1106 response->postReply(replyID);
1107}
1108
Andreas Huber75a8df92012-09-18 14:47:48 -07001109status_t WifiDisplaySource::onGetParameterRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001110 int32_t sessionID,
1111 int32_t cseq,
1112 const sp<ParsedMessage> &data) {
1113 int32_t playbackSessionID;
1114 sp<PlaybackSession> playbackSession =
1115 findPlaybackSession(data, &playbackSessionID);
1116
1117 if (playbackSession == NULL) {
1118 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001119 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001120 }
1121
1122 playbackSession->updateLiveness();
1123
1124 AString response = "RTSP/1.0 200 OK\r\n";
1125 AppendCommonResponse(&response, cseq, playbackSessionID);
1126 response.append("\r\n");
1127
1128 status_t err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001129 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001130}
1131
Andreas Huber75a8df92012-09-18 14:47:48 -07001132status_t WifiDisplaySource::onSetParameterRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001133 int32_t sessionID,
1134 int32_t cseq,
1135 const sp<ParsedMessage> &data) {
1136 int32_t playbackSessionID;
Andreas Huber35213f12012-08-29 11:41:50 -07001137 sp<PlaybackSession> playbackSession =
1138 findPlaybackSession(data, &playbackSessionID);
1139
1140 if (playbackSession == NULL) {
1141 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001142 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001143 }
Andreas Huber35213f12012-08-29 11:41:50 -07001144
Andreas Huber75a8df92012-09-18 14:47:48 -07001145 if (strstr(data->getContent(), "wfd_idr_request\r\n")) {
1146 playbackSession->requestIDRFrame();
1147 }
Andreas Huber03e2ffa2012-09-13 16:43:51 -07001148
Andreas Huber35213f12012-08-29 11:41:50 -07001149 playbackSession->updateLiveness();
1150
1151 AString response = "RTSP/1.0 200 OK\r\n";
1152 AppendCommonResponse(&response, cseq, playbackSessionID);
1153 response.append("\r\n");
1154
1155 status_t err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001156 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001157}
1158
1159// static
1160void WifiDisplaySource::AppendCommonResponse(
1161 AString *response, int32_t cseq, int32_t playbackSessionID) {
1162 time_t now = time(NULL);
1163 struct tm *now2 = gmtime(&now);
1164 char buf[128];
1165 strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", now2);
1166
1167 response->append("Date: ");
1168 response->append(buf);
1169 response->append("\r\n");
1170
1171 response->append("Server: Mine/1.0\r\n");
1172
1173 if (cseq >= 0) {
1174 response->append(StringPrintf("CSeq: %d\r\n", cseq));
1175 }
1176
1177 if (playbackSessionID >= 0ll) {
1178 response->append(
1179 StringPrintf(
1180 "Session: %d;timeout=%lld\r\n",
1181 playbackSessionID, kPlaybackSessionTimeoutSecs));
1182 }
1183}
1184
1185void WifiDisplaySource::sendErrorResponse(
1186 int32_t sessionID,
1187 const char *errorDetail,
1188 int32_t cseq) {
1189 AString response;
1190 response.append("RTSP/1.0 ");
1191 response.append(errorDetail);
1192 response.append("\r\n");
1193
1194 AppendCommonResponse(&response, cseq);
1195
1196 response.append("\r\n");
1197
1198 status_t err = mNetSession->sendRequest(sessionID, response.c_str());
1199 CHECK_EQ(err, (status_t)OK);
1200}
1201
1202int32_t WifiDisplaySource::makeUniquePlaybackSessionID() const {
Andreas Huberc438b882012-09-17 15:07:30 -07001203 return rand();
Andreas Huber35213f12012-08-29 11:41:50 -07001204}
1205
1206sp<WifiDisplaySource::PlaybackSession> WifiDisplaySource::findPlaybackSession(
1207 const sp<ParsedMessage> &data, int32_t *playbackSessionID) const {
1208 if (!data->findInt32("session", playbackSessionID)) {
Andreas Huberc438b882012-09-17 15:07:30 -07001209 // XXX the older dongles do not always include a "Session:" header.
1210 *playbackSessionID = mClientInfo.mPlaybackSessionID;
1211 return mClientInfo.mPlaybackSession;
1212 }
1213
1214 if (*playbackSessionID != mClientInfo.mPlaybackSessionID) {
Andreas Huber35213f12012-08-29 11:41:50 -07001215 return NULL;
1216 }
1217
Andreas Huberc438b882012-09-17 15:07:30 -07001218 return mClientInfo.mPlaybackSession;
1219}
1220
1221void WifiDisplaySource::disconnectClient(status_t err) {
1222 if (mClientSessionID != 0) {
1223 if (mClientInfo.mPlaybackSession != NULL) {
1224 looper()->unregisterHandler(mClientInfo.mPlaybackSession->id());
1225 mClientInfo.mPlaybackSession.clear();
1226 }
1227
1228 mNetSession->destroySession(mClientSessionID);
1229 mClientSessionID = 0;
Andreas Huber35213f12012-08-29 11:41:50 -07001230 }
1231
Andreas Huberc438b882012-09-17 15:07:30 -07001232 if (mClient != NULL) {
1233 if (err != OK) {
1234 mClient->onDisplayError(IRemoteDisplayClient::kDisplayErrorUnknown);
1235 } else {
1236 mClient->onDisplayDisconnected();
1237 }
1238 }
Andreas Huber35213f12012-08-29 11:41:50 -07001239}
1240
Andreas Huber75a8df92012-09-18 14:47:48 -07001241#if REQUIRE_HDCP
1242struct WifiDisplaySource::HDCPObserver : public BnHDCPObserver {
1243 HDCPObserver(const sp<AMessage> &notify);
1244
1245 virtual void notify(
1246 int msg, int ext1, int ext2, const Parcel *obj);
1247
1248private:
1249 sp<AMessage> mNotify;
1250
1251 DISALLOW_EVIL_CONSTRUCTORS(HDCPObserver);
1252};
1253
1254WifiDisplaySource::HDCPObserver::HDCPObserver(
1255 const sp<AMessage> &notify)
1256 : mNotify(notify) {
1257}
1258
1259void WifiDisplaySource::HDCPObserver::notify(
1260 int msg, int ext1, int ext2, const Parcel *obj) {
1261 sp<AMessage> notify = mNotify->dup();
1262 notify->setInt32("msg", msg);
1263 notify->setInt32("ext1", ext1);
1264 notify->setInt32("ext2", ext2);
1265 notify->post();
1266}
1267
1268status_t WifiDisplaySource::makeHDCP() {
1269 sp<IServiceManager> sm = defaultServiceManager();
1270 sp<IBinder> binder = sm->getService(String16("media.player"));
1271 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
1272 CHECK(service != NULL);
1273
1274 mHDCP = service->makeHDCP();
1275
1276 if (mHDCP == NULL) {
1277 return ERROR_UNSUPPORTED;
1278 }
1279
1280 sp<AMessage> notify = new AMessage(kWhatHDCPNotify, id());
1281 mHDCPObserver = new HDCPObserver(notify);
1282
1283 status_t err = mHDCP->setObserver(mHDCPObserver);
1284
1285 if (err != OK) {
1286 ALOGE("Failed to set HDCP observer.");
1287
1288 mHDCPObserver.clear();
1289 mHDCP.clear();
1290
1291 return err;
1292 }
1293
1294 ALOGI("initiating HDCP negotiation w/ host %s:%d",
1295 mClientInfo.mRemoteIP.c_str(), mHDCPPort);
1296
1297 err = mHDCP->initAsync(mClientInfo.mRemoteIP.c_str(), mHDCPPort);
1298
1299 if (err != OK) {
1300 return err;
1301 }
1302
1303 return OK;
1304}
1305#endif
1306
Andreas Huber35213f12012-08-29 11:41:50 -07001307} // namespace android
1308