blob: adb154994a9064004a465a538b911bcc5bcbeddb [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 Huber799688d2012-10-01 11:26:30 -070044 : mState(INITIALIZED),
45 mNetSession(netSession),
Andreas Huber28169b12012-09-05 10:26:52 -070046 mClient(client),
Andreas Huber35213f12012-08-29 11:41:50 -070047 mSessionID(0),
Andreas Hubera71c3ea2012-09-21 16:02:39 -070048 mStopReplyID(0),
Andreas Huberc438b882012-09-17 15:07:30 -070049 mClientSessionID(0),
Andreas Huber35213f12012-08-29 11:41:50 -070050 mReaperPending(false),
Andreas Huber75a8df92012-09-18 14:47:48 -070051 mNextCSeq(1)
52#if REQUIRE_HDCP
53 ,mIsHDCP2_0(false)
54 ,mHDCPPort(0)
55 ,mHDCPInitializationComplete(false)
56 ,mSetupTriggerDeferred(false)
57#endif
58{
Andreas Huber35213f12012-08-29 11:41:50 -070059}
60
61WifiDisplaySource::~WifiDisplaySource() {
62}
63
Andreas Huberab1bd842012-08-30 14:51:40 -070064status_t WifiDisplaySource::start(const char *iface) {
Andreas Huber799688d2012-10-01 11:26:30 -070065 CHECK_EQ(mState, INITIALIZED);
66
Andreas Huber35213f12012-08-29 11:41:50 -070067 sp<AMessage> msg = new AMessage(kWhatStart, id());
Andreas Huberab1bd842012-08-30 14:51:40 -070068 msg->setString("iface", iface);
Andreas Huber35213f12012-08-29 11:41:50 -070069
70 sp<AMessage> response;
71 status_t err = msg->postAndAwaitResponse(&response);
72
73 if (err != OK) {
74 return err;
75 }
76
77 if (!response->findInt32("err", &err)) {
78 err = OK;
79 }
80
81 return err;
82}
83
84status_t WifiDisplaySource::stop() {
85 sp<AMessage> msg = new AMessage(kWhatStop, id());
86
87 sp<AMessage> response;
88 status_t err = msg->postAndAwaitResponse(&response);
89
90 if (err != OK) {
91 return err;
92 }
93
94 if (!response->findInt32("err", &err)) {
95 err = OK;
96 }
97
98 return err;
99}
100
101void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) {
102 switch (msg->what()) {
103 case kWhatStart:
104 {
105 uint32_t replyID;
106 CHECK(msg->senderAwaitsResponse(&replyID));
107
Andreas Huberab1bd842012-08-30 14:51:40 -0700108 AString iface;
109 CHECK(msg->findString("iface", &iface));
Andreas Huber35213f12012-08-29 11:41:50 -0700110
Andreas Huberab1bd842012-08-30 14:51:40 -0700111 status_t err = OK;
Andreas Huber35213f12012-08-29 11:41:50 -0700112
Andreas Huberab1bd842012-08-30 14:51:40 -0700113 ssize_t colonPos = iface.find(":");
114
115 unsigned long port;
116
117 if (colonPos >= 0) {
118 const char *s = iface.c_str() + colonPos + 1;
119
120 char *end;
121 port = strtoul(s, &end, 10);
122
123 if (end == s || *end != '\0' || port > 65535) {
124 err = -EINVAL;
125 } else {
126 iface.erase(colonPos, iface.size() - colonPos);
127 }
128 } else {
129 port = kWifiDisplayDefaultPort;
130 }
131
Andreas Huberab1bd842012-08-30 14:51:40 -0700132 if (err == OK) {
Andreas Huber7d34f832012-09-13 11:25:33 -0700133 if (inet_aton(iface.c_str(), &mInterfaceAddr) != 0) {
Andreas Huberab1bd842012-08-30 14:51:40 -0700134 sp<AMessage> notify = new AMessage(kWhatRTSPNotify, id());
135
136 err = mNetSession->createRTSPServer(
Andreas Huber7d34f832012-09-13 11:25:33 -0700137 mInterfaceAddr, port, notify, &mSessionID);
Andreas Huberab1bd842012-08-30 14:51:40 -0700138 } else {
139 err = -EINVAL;
140 }
141 }
Andreas Huber35213f12012-08-29 11:41:50 -0700142
Andreas Huber799688d2012-10-01 11:26:30 -0700143 if (err == OK) {
144 mState = AWAITING_CLIENT_CONNECTION;
145 }
146
Andreas Huber35213f12012-08-29 11:41:50 -0700147 sp<AMessage> response = new AMessage;
148 response->setInt32("err", err);
149 response->postReply(replyID);
150 break;
151 }
152
153 case kWhatRTSPNotify:
154 {
155 int32_t reason;
156 CHECK(msg->findInt32("reason", &reason));
157
158 switch (reason) {
159 case ANetworkSession::kWhatError:
160 {
161 int32_t sessionID;
162 CHECK(msg->findInt32("sessionID", &sessionID));
163
164 int32_t err;
165 CHECK(msg->findInt32("err", &err));
166
167 AString detail;
168 CHECK(msg->findString("detail", &detail));
169
170 ALOGE("An error occurred in session %d (%d, '%s/%s').",
171 sessionID,
172 err,
173 detail.c_str(),
174 strerror(-err));
175
176 mNetSession->destroySession(sessionID);
177
Andreas Huberc438b882012-09-17 15:07:30 -0700178 if (sessionID == mClientSessionID) {
Andreas Huberbe996642012-09-27 14:13:05 -0700179 mClientSessionID = 0;
Andreas Huberc438b882012-09-17 15:07:30 -0700180
Andreas Huberbe996642012-09-27 14:13:05 -0700181 mClient->onDisplayError(
182 IRemoteDisplayClient::kDisplayErrorUnknown);
Andreas Huberc438b882012-09-17 15:07:30 -0700183 }
Andreas Huber35213f12012-08-29 11:41:50 -0700184 break;
185 }
186
187 case ANetworkSession::kWhatClientConnected:
188 {
189 int32_t sessionID;
190 CHECK(msg->findInt32("sessionID", &sessionID));
191
Andreas Huberc438b882012-09-17 15:07:30 -0700192 if (mClientSessionID > 0) {
193 ALOGW("A client tried to connect, but we already "
194 "have one.");
195
196 mNetSession->destroySession(sessionID);
197 break;
198 }
199
Andreas Huber799688d2012-10-01 11:26:30 -0700200 CHECK_EQ(mState, AWAITING_CLIENT_CONNECTION);
201
Andreas Huberc438b882012-09-17 15:07:30 -0700202 CHECK(msg->findString("client-ip", &mClientInfo.mRemoteIP));
203 CHECK(msg->findString("server-ip", &mClientInfo.mLocalIP));
204
205 if (mClientInfo.mRemoteIP == mClientInfo.mLocalIP) {
206 // Disallow connections from the local interface
207 // for security reasons.
208 mNetSession->destroySession(sessionID);
209 break;
210 }
211
212 CHECK(msg->findInt32(
213 "server-port", &mClientInfo.mLocalPort));
214 mClientInfo.mPlaybackSessionID = -1;
215
216 mClientSessionID = sessionID;
Andreas Huber35213f12012-08-29 11:41:50 -0700217
218 ALOGI("We now have a client (%d) connected.", sessionID);
219
Andreas Huber799688d2012-10-01 11:26:30 -0700220 mState = AWAITING_CLIENT_SETUP;
221
Andreas Huber35213f12012-08-29 11:41:50 -0700222 status_t err = sendM1(sessionID);
223 CHECK_EQ(err, (status_t)OK);
224 break;
225 }
226
227 case ANetworkSession::kWhatData:
228 {
Andreas Huber75a8df92012-09-18 14:47:48 -0700229 status_t err = onReceiveClientData(msg);
230
231 if (err != OK) {
Andreas Huberbe996642012-09-27 14:13:05 -0700232 mClient->onDisplayError(
233 IRemoteDisplayClient::kDisplayErrorUnknown);
Andreas Huber75a8df92012-09-18 14:47:48 -0700234 }
Andreas Huber35213f12012-08-29 11:41:50 -0700235 break;
236 }
237
238 default:
239 TRESPASS();
240 }
241 break;
242 }
243
244 case kWhatStop:
245 {
Andreas Huber8cc2fd32012-09-26 12:54:26 -0700246 CHECK(msg->senderAwaitsResponse(&mStopReplyID));
Andreas Huber35213f12012-08-29 11:41:50 -0700247
Andreas Huber799688d2012-10-01 11:26:30 -0700248 CHECK_LT(mState, AWAITING_CLIENT_TEARDOWN);
249
250 if (mState >= AWAITING_CLIENT_PLAY) {
251 // We have a session, i.e. a previous SETUP succeeded.
252
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700253 status_t err = sendM5(
254 mClientSessionID, true /* requestShutdown */);
Andreas Huber28169b12012-09-05 10:26:52 -0700255
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700256 if (err == OK) {
Andreas Huber799688d2012-10-01 11:26:30 -0700257 mState = AWAITING_CLIENT_TEARDOWN;
258
259 (new AMessage(kWhatTeardownTriggerTimedOut, id()))->post(
260 kTeardownTriggerTimeouSecs * 1000000ll);
261
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700262 break;
263 }
Andreas Huber799688d2012-10-01 11:26:30 -0700264
265 // fall through.
Andreas Huber75a8df92012-09-18 14:47:48 -0700266 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700267
Andreas Huber8cc2fd32012-09-26 12:54:26 -0700268 finishStop();
Andreas Huber35213f12012-08-29 11:41:50 -0700269 break;
270 }
271
272 case kWhatReapDeadClients:
273 {
274 mReaperPending = false;
275
Andreas Huberc438b882012-09-17 15:07:30 -0700276 if (mClientSessionID == 0
277 || mClientInfo.mPlaybackSession == NULL) {
278 break;
Andreas Huber35213f12012-08-29 11:41:50 -0700279 }
280
Andreas Huberc438b882012-09-17 15:07:30 -0700281 if (mClientInfo.mPlaybackSession->getLastLifesignUs()
282 + kPlaybackSessionTimeoutUs < ALooper::GetNowUs()) {
283 ALOGI("playback session timed out, reaping.");
284
Andreas Huberbe996642012-09-27 14:13:05 -0700285 mNetSession->destroySession(mClientSessionID);
286 mClientSessionID = 0;
287
288 mClient->onDisplayError(
289 IRemoteDisplayClient::kDisplayErrorUnknown);
Andreas Huberc438b882012-09-17 15:07:30 -0700290 } else {
Andreas Huber35213f12012-08-29 11:41:50 -0700291 scheduleReaper();
292 }
293 break;
294 }
295
296 case kWhatPlaybackSessionNotify:
297 {
298 int32_t playbackSessionID;
299 CHECK(msg->findInt32("playbackSessionID", &playbackSessionID));
300
301 int32_t what;
302 CHECK(msg->findInt32("what", &what));
303
Andreas Huberc438b882012-09-17 15:07:30 -0700304 if (what == PlaybackSession::kWhatSessionDead) {
305 ALOGI("playback session wants to quit.");
Andreas Huber35213f12012-08-29 11:41:50 -0700306
Andreas Huberbe996642012-09-27 14:13:05 -0700307 mClient->onDisplayError(
308 IRemoteDisplayClient::kDisplayErrorUnknown);
Andreas Huberc438b882012-09-17 15:07:30 -0700309 } else if (what == PlaybackSession::kWhatSessionEstablished) {
310 if (mClient != NULL) {
311 mClient->onDisplayConnected(
312 mClientInfo.mPlaybackSession->getSurfaceTexture(),
313 mClientInfo.mPlaybackSession->width(),
314 mClientInfo.mPlaybackSession->height(),
315 0 /* flags */);
Andreas Huber35213f12012-08-29 11:41:50 -0700316 }
Andreas Huber799688d2012-10-01 11:26:30 -0700317
318 if (mState == ABOUT_TO_PLAY) {
319 mState = PLAYING;
320 }
Andreas Hubera7f7e0a2012-09-28 10:23:51 -0700321 } else if (what == PlaybackSession::kWhatSessionDestroyed) {
322 disconnectClient2();
Andreas Huberc438b882012-09-17 15:07:30 -0700323 } else {
324 CHECK_EQ(what, PlaybackSession::kWhatBinaryData);
325
326 int32_t channel;
327 CHECK(msg->findInt32("channel", &channel));
328
329 sp<ABuffer> data;
330 CHECK(msg->findBuffer("data", &data));
331
332 CHECK_LE(channel, 0xffu);
333 CHECK_LE(data->size(), 0xffffu);
334
335 int32_t sessionID;
336 CHECK(msg->findInt32("sessionID", &sessionID));
337
338 char header[4];
339 header[0] = '$';
340 header[1] = channel;
341 header[2] = data->size() >> 8;
342 header[3] = data->size() & 0xff;
343
344 mNetSession->sendRequest(
345 sessionID, header, sizeof(header));
346
347 mNetSession->sendRequest(
348 sessionID, data->data(), data->size());
Andreas Huber35213f12012-08-29 11:41:50 -0700349 }
350 break;
351 }
352
Andreas Huber54408d82012-08-30 16:04:34 -0700353 case kWhatKeepAlive:
354 {
355 int32_t sessionID;
356 CHECK(msg->findInt32("sessionID", &sessionID));
357
Andreas Huberc438b882012-09-17 15:07:30 -0700358 if (mClientSessionID != sessionID) {
Andreas Huber54408d82012-08-30 16:04:34 -0700359 // Obsolete event, client is already gone.
360 break;
361 }
362
363 sendM16(sessionID);
364 break;
365 }
366
Andreas Huber799688d2012-10-01 11:26:30 -0700367 case kWhatTeardownTriggerTimedOut:
368 {
369 if (mState == AWAITING_CLIENT_TEARDOWN) {
370 ALOGI("TEARDOWN trigger timed out, forcing disconnection.");
371
372 CHECK_NE(mStopReplyID, 0);
373 finishStop();
374 break;
375 }
376 break;
377 }
378
Andreas Huber75a8df92012-09-18 14:47:48 -0700379#if REQUIRE_HDCP
380 case kWhatHDCPNotify:
381 {
382 int32_t msgCode, ext1, ext2;
383 CHECK(msg->findInt32("msg", &msgCode));
384 CHECK(msg->findInt32("ext1", &ext1));
385 CHECK(msg->findInt32("ext2", &ext2));
386
Andreas Huber8cc2fd32012-09-26 12:54:26 -0700387 ALOGI("Saw HDCP notification code %d, ext1 %d, ext2 %d",
Andreas Huber75a8df92012-09-18 14:47:48 -0700388 msgCode, ext1, ext2);
389
390 switch (msgCode) {
391 case HDCPModule::HDCP_INITIALIZATION_COMPLETE:
392 {
393 mHDCPInitializationComplete = true;
394
395 if (mSetupTriggerDeferred) {
396 mSetupTriggerDeferred = false;
397
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700398 sendM5(mClientSessionID, false /* requestShutdown */);
Andreas Huber75a8df92012-09-18 14:47:48 -0700399 }
400 break;
401 }
402
Andreas Huber8cc2fd32012-09-26 12:54:26 -0700403 case HDCPModule::HDCP_SHUTDOWN_COMPLETE:
Andreas Huberbe996642012-09-27 14:13:05 -0700404 case HDCPModule::HDCP_SHUTDOWN_FAILED:
Andreas Huber8cc2fd32012-09-26 12:54:26 -0700405 {
Andreas Huberbe996642012-09-27 14:13:05 -0700406 // Ugly hack to make sure that the call to
407 // HDCPObserver::notify is completely handled before
408 // we clear the HDCP instance and unload the shared
409 // library :(
410 (new AMessage(kWhatFinishStop2, id()))->post(300000ll);
Andreas Huber8cc2fd32012-09-26 12:54:26 -0700411 break;
412 }
413
Andreas Huber75a8df92012-09-18 14:47:48 -0700414 default:
415 {
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700416 ALOGE("HDCP failure, shutting down.");
417
Andreas Huberbe996642012-09-27 14:13:05 -0700418 mClient->onDisplayError(
419 IRemoteDisplayClient::kDisplayErrorUnknown);
Andreas Huber75a8df92012-09-18 14:47:48 -0700420 break;
421 }
422 }
423 break;
424 }
Andreas Huberbe996642012-09-27 14:13:05 -0700425
426 case kWhatFinishStop2:
427 {
428 finishStop2();
429 break;
430 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700431#endif
432
Andreas Huber35213f12012-08-29 11:41:50 -0700433 default:
434 TRESPASS();
435 }
436}
437
438void WifiDisplaySource::registerResponseHandler(
439 int32_t sessionID, int32_t cseq, HandleRTSPResponseFunc func) {
440 ResponseID id;
441 id.mSessionID = sessionID;
442 id.mCSeq = cseq;
443 mResponseHandlers.add(id, func);
444}
445
446status_t WifiDisplaySource::sendM1(int32_t sessionID) {
447 AString request = "OPTIONS * RTSP/1.0\r\n";
448 AppendCommonResponse(&request, mNextCSeq);
449
450 request.append(
451 "Require: org.wfa.wfd1.0\r\n"
452 "\r\n");
453
454 status_t err =
455 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
456
457 if (err != OK) {
458 return err;
459 }
460
461 registerResponseHandler(
462 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM1Response);
463
464 ++mNextCSeq;
465
466 return OK;
467}
468
469status_t WifiDisplaySource::sendM3(int32_t sessionID) {
470 AString body =
Andreas Huber75a8df92012-09-18 14:47:48 -0700471#if REQUIRE_HDCP
472 "wfd_content_protection\r\n"
473#endif
Andreas Huber35213f12012-08-29 11:41:50 -0700474 "wfd_video_formats\r\n"
475 "wfd_audio_codecs\r\n"
476 "wfd_client_rtp_ports\r\n";
477
478 AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
479 AppendCommonResponse(&request, mNextCSeq);
480
481 request.append("Content-Type: text/parameters\r\n");
482 request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
483 request.append("\r\n");
484 request.append(body);
485
486 status_t err =
487 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
488
489 if (err != OK) {
490 return err;
491 }
492
493 registerResponseHandler(
494 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM3Response);
495
496 ++mNextCSeq;
497
498 return OK;
499}
500
501status_t WifiDisplaySource::sendM4(int32_t sessionID) {
502 // wfd_video_formats:
503 // 1 byte "native"
504 // 1 byte "preferred-display-mode-supported" 0 or 1
505 // one or more avc codec structures
506 // 1 byte profile
507 // 1 byte level
508 // 4 byte CEA mask
509 // 4 byte VESA mask
510 // 4 byte HH mask
511 // 1 byte latency
512 // 2 byte min-slice-slice
513 // 2 byte slice-enc-params
514 // 1 byte framerate-control-support
515 // max-hres (none or 2 byte)
516 // max-vres (none or 2 byte)
517
Andreas Huberc438b882012-09-17 15:07:30 -0700518 CHECK_EQ(sessionID, mClientSessionID);
Andreas Huber35213f12012-08-29 11:41:50 -0700519
Andreas Huber7d34f832012-09-13 11:25:33 -0700520 AString transportString = "UDP";
521
522 char val[PROPERTY_VALUE_MAX];
523 if (property_get("media.wfd.enable-tcp", val, NULL)
524 && (!strcasecmp("true", val) || !strcmp("1", val))) {
525 ALOGI("Using TCP transport.");
526 transportString = "TCP";
527 }
528
Andreas Huber75a8df92012-09-18 14:47:48 -0700529 // For 720p60:
530 // use "30 00 02 02 00000040 00000000 00000000 00 0000 0000 00 none none\r\n"
531 // For 720p30:
532 // use "28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none\r\n"
Andreas Huber8000e362012-09-26 14:30:33 -0700533 // For 720p24:
534 // use "78 00 02 02 00008000 00000000 00000000 00 0000 0000 00 none none\r\n"
Andreas Huber35213f12012-08-29 11:41:50 -0700535 AString body = StringPrintf(
536 "wfd_video_formats: "
Andreas Huber8000e362012-09-26 14:30:33 -0700537 "78 00 02 02 00008000 00000000 00000000 00 0000 0000 00 none none\r\n"
Andreas Huber35213f12012-08-29 11:41:50 -0700538 "wfd_audio_codecs: AAC 00000001 00\r\n" // 2 ch AAC 48kHz
Andreas Huber83972432012-09-27 14:27:42 -0700539 "wfd_presentation_URL: rtsp://%s/wfd1.0/streamid=0 none\r\n"
Andreas Huber7d34f832012-09-13 11:25:33 -0700540 "wfd_client_rtp_ports: RTP/AVP/%s;unicast 19000 0 mode=play\r\n",
Andreas Huber83972432012-09-27 14:27:42 -0700541 mClientInfo.mLocalIP.c_str(), transportString.c_str());
Andreas Huber35213f12012-08-29 11:41:50 -0700542
543 AString request = "SET_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::onReceiveM4Response);
560
561 ++mNextCSeq;
562
563 return OK;
564}
565
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700566status_t WifiDisplaySource::sendM5(int32_t sessionID, bool requestShutdown) {
567 AString body = "wfd_trigger_method: ";
568 if (requestShutdown) {
Andreas Huberbe996642012-09-27 14:13:05 -0700569 ALOGI("Sending TEARDOWN trigger.");
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700570 body.append("TEARDOWN");
571 } else {
572 body.append("SETUP");
573 }
574
575 body.append("\r\n");
Andreas Huber35213f12012-08-29 11:41:50 -0700576
577 AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
578 AppendCommonResponse(&request, mNextCSeq);
579
580 request.append("Content-Type: text/parameters\r\n");
581 request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
582 request.append("\r\n");
583 request.append(body);
584
585 status_t err =
586 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
587
588 if (err != OK) {
589 return err;
590 }
591
592 registerResponseHandler(
593 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM5Response);
594
595 ++mNextCSeq;
596
597 return OK;
598}
599
Andreas Huber54408d82012-08-30 16:04:34 -0700600status_t WifiDisplaySource::sendM16(int32_t sessionID) {
601 AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
602 AppendCommonResponse(&request, mNextCSeq);
603
Andreas Huberc438b882012-09-17 15:07:30 -0700604 CHECK_EQ(sessionID, mClientSessionID);
605 request.append(
606 StringPrintf("Session: %d\r\n", mClientInfo.mPlaybackSessionID));
Andreas Huber596b4cd2012-09-12 16:25:14 -0700607 request.append("\r\n"); // Empty body
Andreas Huber54408d82012-08-30 16:04:34 -0700608
609 status_t err =
610 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
611
612 if (err != OK) {
613 return err;
614 }
615
616 registerResponseHandler(
617 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM16Response);
618
619 ++mNextCSeq;
620
621 return OK;
622}
623
Andreas Huber35213f12012-08-29 11:41:50 -0700624status_t WifiDisplaySource::onReceiveM1Response(
625 int32_t sessionID, const sp<ParsedMessage> &msg) {
626 int32_t statusCode;
627 if (!msg->getStatusCode(&statusCode)) {
628 return ERROR_MALFORMED;
629 }
630
631 if (statusCode != 200) {
632 return ERROR_UNSUPPORTED;
633 }
634
635 return OK;
636}
637
638status_t WifiDisplaySource::onReceiveM3Response(
639 int32_t sessionID, const sp<ParsedMessage> &msg) {
640 int32_t statusCode;
641 if (!msg->getStatusCode(&statusCode)) {
642 return ERROR_MALFORMED;
643 }
644
645 if (statusCode != 200) {
646 return ERROR_UNSUPPORTED;
647 }
648
Andreas Huber75a8df92012-09-18 14:47:48 -0700649 sp<Parameters> params =
650 Parameters::Parse(msg->getContent(), strlen(msg->getContent()));
651
652 if (params == NULL) {
653 return ERROR_MALFORMED;
654 }
655
656#if REQUIRE_HDCP
657 AString value;
658 if (!params->findParameter("wfd_content_protection", &value)) {
659 ALOGE("Sink doesn't appear to support content protection.");
660 return -EACCES;
661 }
662
663 if (value == "none") {
664 ALOGE("Sink does not support content protection.");
665 return -EACCES;
666 }
667
668 bool isHDCP2_0 = false;
669 if (value.startsWith("HDCP2.0 ")) {
670 isHDCP2_0 = true;
671 } else if (!value.startsWith("HDCP2.1 ")) {
672 return ERROR_MALFORMED;
673 }
674
675 int32_t hdcpPort;
676 if (!ParsedMessage::GetInt32Attribute(value.c_str() + 8, "port", &hdcpPort)
677 || hdcpPort < 1 || hdcpPort > 65535) {
678 return ERROR_MALFORMED;
679 }
680
681 mIsHDCP2_0 = isHDCP2_0;
682 mHDCPPort = hdcpPort;
683
684 status_t err = makeHDCP();
685 if (err != OK) {
686 ALOGE("Unable to instantiate HDCP component.");
687 return err;
688 }
689#endif
690
Andreas Huber35213f12012-08-29 11:41:50 -0700691 return sendM4(sessionID);
692}
693
694status_t WifiDisplaySource::onReceiveM4Response(
695 int32_t sessionID, const sp<ParsedMessage> &msg) {
696 int32_t statusCode;
697 if (!msg->getStatusCode(&statusCode)) {
698 return ERROR_MALFORMED;
699 }
700
701 if (statusCode != 200) {
702 return ERROR_UNSUPPORTED;
703 }
704
Andreas Huber75a8df92012-09-18 14:47:48 -0700705#if REQUIRE_HDCP
706 if (!mHDCPInitializationComplete) {
707 ALOGI("Deferring SETUP trigger until HDCP initialization completes.");
708
709 mSetupTriggerDeferred = true;
710 return OK;
711 }
712#endif
713
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700714 return sendM5(sessionID, false /* requestShutdown */);
Andreas Huber35213f12012-08-29 11:41:50 -0700715}
716
717status_t WifiDisplaySource::onReceiveM5Response(
718 int32_t sessionID, const sp<ParsedMessage> &msg) {
719 int32_t statusCode;
720 if (!msg->getStatusCode(&statusCode)) {
721 return ERROR_MALFORMED;
722 }
723
724 if (statusCode != 200) {
725 return ERROR_UNSUPPORTED;
726 }
727
728 return OK;
729}
730
Andreas Huber54408d82012-08-30 16:04:34 -0700731status_t WifiDisplaySource::onReceiveM16Response(
732 int32_t sessionID, const sp<ParsedMessage> &msg) {
733 // If only the response was required to include a "Session:" header...
734
Andreas Huberc438b882012-09-17 15:07:30 -0700735 CHECK_EQ(sessionID, mClientSessionID);
Andreas Huber54408d82012-08-30 16:04:34 -0700736
Andreas Huberc438b882012-09-17 15:07:30 -0700737 if (mClientInfo.mPlaybackSession != NULL) {
738 mClientInfo.mPlaybackSession->updateLiveness();
Andreas Huber54408d82012-08-30 16:04:34 -0700739
740 scheduleKeepAlive(sessionID);
741 }
742
743 return OK;
744}
745
Andreas Huber35213f12012-08-29 11:41:50 -0700746void WifiDisplaySource::scheduleReaper() {
747 if (mReaperPending) {
748 return;
749 }
750
751 mReaperPending = true;
752 (new AMessage(kWhatReapDeadClients, id()))->post(kReaperIntervalUs);
753}
754
Andreas Huber54408d82012-08-30 16:04:34 -0700755void WifiDisplaySource::scheduleKeepAlive(int32_t sessionID) {
756 // We need to send updates at least 5 secs before the timeout is set to
757 // expire, make sure the timeout is greater than 5 secs to begin with.
758 CHECK_GT(kPlaybackSessionTimeoutUs, 5000000ll);
759
760 sp<AMessage> msg = new AMessage(kWhatKeepAlive, id());
761 msg->setInt32("sessionID", sessionID);
762 msg->post(kPlaybackSessionTimeoutUs - 5000000ll);
763}
764
Andreas Huber75a8df92012-09-18 14:47:48 -0700765status_t WifiDisplaySource::onReceiveClientData(const sp<AMessage> &msg) {
Andreas Huber35213f12012-08-29 11:41:50 -0700766 int32_t sessionID;
767 CHECK(msg->findInt32("sessionID", &sessionID));
768
769 sp<RefBase> obj;
770 CHECK(msg->findObject("data", &obj));
771
772 sp<ParsedMessage> data =
773 static_cast<ParsedMessage *>(obj.get());
774
775 ALOGV("session %d received '%s'",
776 sessionID, data->debugString().c_str());
777
778 AString method;
779 AString uri;
780 data->getRequestField(0, &method);
781
782 int32_t cseq;
783 if (!data->findInt32("cseq", &cseq)) {
784 sendErrorResponse(sessionID, "400 Bad Request", -1 /* cseq */);
Andreas Huber75a8df92012-09-18 14:47:48 -0700785 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700786 }
787
788 if (method.startsWith("RTSP/")) {
789 // This is a response.
790
791 ResponseID id;
792 id.mSessionID = sessionID;
793 id.mCSeq = cseq;
794
795 ssize_t index = mResponseHandlers.indexOfKey(id);
796
797 if (index < 0) {
798 ALOGW("Received unsolicited server response, cseq %d", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700799 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700800 }
801
802 HandleRTSPResponseFunc func = mResponseHandlers.valueAt(index);
803 mResponseHandlers.removeItemsAt(index);
804
805 status_t err = (this->*func)(sessionID, data);
806
807 if (err != OK) {
808 ALOGW("Response handler for session %d, cseq %d returned "
809 "err %d (%s)",
810 sessionID, cseq, err, strerror(-err));
Andreas Huber75a8df92012-09-18 14:47:48 -0700811
812 return err;
Andreas Huber35213f12012-08-29 11:41:50 -0700813 }
814
Andreas Huber75a8df92012-09-18 14:47:48 -0700815 return OK;
Andreas Huber35213f12012-08-29 11:41:50 -0700816 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700817
818 AString version;
819 data->getRequestField(2, &version);
820 if (!(version == AString("RTSP/1.0"))) {
821 sendErrorResponse(sessionID, "505 RTSP Version not supported", cseq);
822 return ERROR_UNSUPPORTED;
823 }
824
825 status_t err;
826 if (method == "OPTIONS") {
827 err = onOptionsRequest(sessionID, cseq, data);
828 } else if (method == "SETUP") {
829 err = onSetupRequest(sessionID, cseq, data);
830 } else if (method == "PLAY") {
831 err = onPlayRequest(sessionID, cseq, data);
832 } else if (method == "PAUSE") {
833 err = onPauseRequest(sessionID, cseq, data);
834 } else if (method == "TEARDOWN") {
835 err = onTeardownRequest(sessionID, cseq, data);
836 } else if (method == "GET_PARAMETER") {
837 err = onGetParameterRequest(sessionID, cseq, data);
838 } else if (method == "SET_PARAMETER") {
839 err = onSetParameterRequest(sessionID, cseq, data);
840 } else {
841 sendErrorResponse(sessionID, "405 Method Not Allowed", cseq);
842
843 err = ERROR_UNSUPPORTED;
844 }
845
846 return err;
Andreas Huber35213f12012-08-29 11:41:50 -0700847}
848
Andreas Huber75a8df92012-09-18 14:47:48 -0700849status_t WifiDisplaySource::onOptionsRequest(
Andreas Huber35213f12012-08-29 11:41:50 -0700850 int32_t sessionID,
851 int32_t cseq,
852 const sp<ParsedMessage> &data) {
853 int32_t playbackSessionID;
854 sp<PlaybackSession> playbackSession =
855 findPlaybackSession(data, &playbackSessionID);
856
857 if (playbackSession != NULL) {
858 playbackSession->updateLiveness();
859 }
860
861 AString response = "RTSP/1.0 200 OK\r\n";
862 AppendCommonResponse(&response, cseq);
863
864 response.append(
Andreas Huber75a8df92012-09-18 14:47:48 -0700865 "Public: org.wfa.wfd1.0, SETUP, TEARDOWN, PLAY, PAUSE, "
Andreas Huber35213f12012-08-29 11:41:50 -0700866 "GET_PARAMETER, SET_PARAMETER\r\n");
867
868 response.append("\r\n");
869
870 status_t err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber35213f12012-08-29 11:41:50 -0700871
Andreas Huber75a8df92012-09-18 14:47:48 -0700872 if (err == OK) {
873 err = sendM3(sessionID);
874 }
875
876 return err;
Andreas Huber35213f12012-08-29 11:41:50 -0700877}
878
Andreas Huber75a8df92012-09-18 14:47:48 -0700879status_t WifiDisplaySource::onSetupRequest(
Andreas Huber35213f12012-08-29 11:41:50 -0700880 int32_t sessionID,
881 int32_t cseq,
882 const sp<ParsedMessage> &data) {
Andreas Huberc438b882012-09-17 15:07:30 -0700883 CHECK_EQ(sessionID, mClientSessionID);
884 if (mClientInfo.mPlaybackSessionID != -1) {
Andreas Huber54408d82012-08-30 16:04:34 -0700885 // We only support a single playback session per client.
886 // This is due to the reversed keep-alive design in the wfd specs...
887 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700888 return ERROR_MALFORMED;
Andreas Huber54408d82012-08-30 16:04:34 -0700889 }
890
Andreas Huber35213f12012-08-29 11:41:50 -0700891 AString transport;
892 if (!data->findString("transport", &transport)) {
893 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700894 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700895 }
896
Andreas Huber7d34f832012-09-13 11:25:33 -0700897 PlaybackSession::TransportMode transportMode =
898 PlaybackSession::TRANSPORT_UDP;
Andreas Huber35213f12012-08-29 11:41:50 -0700899
900 int clientRtp, clientRtcp;
901 if (transport.startsWith("RTP/AVP/TCP;")) {
902 AString interleaved;
Andreas Huber7d34f832012-09-13 11:25:33 -0700903 if (ParsedMessage::GetAttribute(
Andreas Huber35213f12012-08-29 11:41:50 -0700904 transport.c_str(), "interleaved", &interleaved)
Andreas Huber7d34f832012-09-13 11:25:33 -0700905 && sscanf(interleaved.c_str(), "%d-%d",
906 &clientRtp, &clientRtcp) == 2) {
907 transportMode = PlaybackSession::TRANSPORT_TCP_INTERLEAVED;
908 } else {
909 bool badRequest = false;
Andreas Huber35213f12012-08-29 11:41:50 -0700910
Andreas Huber7d34f832012-09-13 11:25:33 -0700911 AString clientPort;
912 if (!ParsedMessage::GetAttribute(
913 transport.c_str(), "client_port", &clientPort)) {
914 badRequest = true;
915 } else if (sscanf(clientPort.c_str(), "%d-%d",
916 &clientRtp, &clientRtcp) == 2) {
917 } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
918 // No RTCP.
919 clientRtcp = -1;
920 } else {
921 badRequest = true;
922 }
923
924 if (badRequest) {
925 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700926 return ERROR_MALFORMED;
Andreas Huber7d34f832012-09-13 11:25:33 -0700927 }
928
929 transportMode = PlaybackSession::TRANSPORT_TCP;
930 }
Andreas Huber35213f12012-08-29 11:41:50 -0700931 } else if (transport.startsWith("RTP/AVP;unicast;")
932 || transport.startsWith("RTP/AVP/UDP;unicast;")) {
933 bool badRequest = false;
934
935 AString clientPort;
936 if (!ParsedMessage::GetAttribute(
937 transport.c_str(), "client_port", &clientPort)) {
938 badRequest = true;
939 } else if (sscanf(clientPort.c_str(), "%d-%d",
940 &clientRtp, &clientRtcp) == 2) {
941 } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
942 // No RTCP.
943 clientRtcp = -1;
944 } else {
945 badRequest = true;
946 }
947
948 if (badRequest) {
949 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700950 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700951 }
952#if 1
Andreas Huber596b4cd2012-09-12 16:25:14 -0700953 // The older LG dongles doesn't specify client_port=xxx apparently.
Andreas Huber35213f12012-08-29 11:41:50 -0700954 } else if (transport == "RTP/AVP/UDP;unicast") {
955 clientRtp = 19000;
Andreas Huber0d767952012-09-25 14:20:08 -0700956 clientRtcp = -1;
Andreas Huber35213f12012-08-29 11:41:50 -0700957#endif
958 } else {
959 sendErrorResponse(sessionID, "461 Unsupported Transport", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700960 return ERROR_UNSUPPORTED;
Andreas Huber35213f12012-08-29 11:41:50 -0700961 }
962
963 int32_t playbackSessionID = makeUniquePlaybackSessionID();
964
965 sp<AMessage> notify = new AMessage(kWhatPlaybackSessionNotify, id());
966 notify->setInt32("playbackSessionID", playbackSessionID);
967 notify->setInt32("sessionID", sessionID);
968
969 sp<PlaybackSession> playbackSession =
Andreas Huber28169b12012-09-05 10:26:52 -0700970 new PlaybackSession(
Andreas Huber7d34f832012-09-13 11:25:33 -0700971 mNetSession, notify, mInterfaceAddr,
Andreas Huber75a8df92012-09-18 14:47:48 -0700972#if REQUIRE_HDCP
973 mHDCP
974#else
975 NULL
976#endif
977 );
Andreas Huber35213f12012-08-29 11:41:50 -0700978
979 looper()->registerHandler(playbackSession);
980
981 AString uri;
982 data->getRequestField(1, &uri);
983
984 if (strncasecmp("rtsp://", uri.c_str(), 7)) {
985 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700986 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700987 }
988
989 if (!(uri.startsWith("rtsp://") && uri.endsWith("/wfd1.0/streamid=0"))) {
990 sendErrorResponse(sessionID, "404 Not found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700991 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700992 }
993
Andreas Huber35213f12012-08-29 11:41:50 -0700994 status_t err = playbackSession->init(
Andreas Huberc438b882012-09-17 15:07:30 -0700995 mClientInfo.mRemoteIP.c_str(),
Andreas Huber35213f12012-08-29 11:41:50 -0700996 clientRtp,
997 clientRtcp,
Andreas Huber7d34f832012-09-13 11:25:33 -0700998 transportMode);
Andreas Huber35213f12012-08-29 11:41:50 -0700999
1000 if (err != OK) {
1001 looper()->unregisterHandler(playbackSession->id());
1002 playbackSession.clear();
1003 }
1004
1005 switch (err) {
1006 case OK:
1007 break;
1008 case -ENOENT:
1009 sendErrorResponse(sessionID, "404 Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001010 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001011 default:
1012 sendErrorResponse(sessionID, "403 Forbidden", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001013 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001014 }
1015
Andreas Huberc438b882012-09-17 15:07:30 -07001016 mClientInfo.mPlaybackSessionID = playbackSessionID;
1017 mClientInfo.mPlaybackSession = playbackSession;
Andreas Huber54408d82012-08-30 16:04:34 -07001018
Andreas Huber35213f12012-08-29 11:41:50 -07001019 AString response = "RTSP/1.0 200 OK\r\n";
1020 AppendCommonResponse(&response, cseq, playbackSessionID);
1021
Andreas Huber7d34f832012-09-13 11:25:33 -07001022 if (transportMode == PlaybackSession::TRANSPORT_TCP_INTERLEAVED) {
Andreas Huber35213f12012-08-29 11:41:50 -07001023 response.append(
1024 StringPrintf(
1025 "Transport: RTP/AVP/TCP;interleaved=%d-%d;",
1026 clientRtp, clientRtcp));
1027 } else {
1028 int32_t serverRtp = playbackSession->getRTPPort();
1029
Andreas Huber7d34f832012-09-13 11:25:33 -07001030 AString transportString = "UDP";
1031 if (transportMode == PlaybackSession::TRANSPORT_TCP) {
1032 transportString = "TCP";
1033 }
1034
Andreas Huber35213f12012-08-29 11:41:50 -07001035 if (clientRtcp >= 0) {
1036 response.append(
1037 StringPrintf(
Andreas Huber7d34f832012-09-13 11:25:33 -07001038 "Transport: RTP/AVP/%s;unicast;client_port=%d-%d;"
Andreas Huber35213f12012-08-29 11:41:50 -07001039 "server_port=%d-%d\r\n",
Andreas Huber7d34f832012-09-13 11:25:33 -07001040 transportString.c_str(),
Andreas Huber35213f12012-08-29 11:41:50 -07001041 clientRtp, clientRtcp, serverRtp, serverRtp + 1));
1042 } else {
1043 response.append(
1044 StringPrintf(
Andreas Huber7d34f832012-09-13 11:25:33 -07001045 "Transport: RTP/AVP/%s;unicast;client_port=%d;"
Andreas Huber35213f12012-08-29 11:41:50 -07001046 "server_port=%d\r\n",
Andreas Huber7d34f832012-09-13 11:25:33 -07001047 transportString.c_str(),
Andreas Huber35213f12012-08-29 11:41:50 -07001048 clientRtp, serverRtp));
1049 }
1050 }
1051
1052 response.append("\r\n");
1053
1054 err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001055
1056 if (err != OK) {
1057 return err;
1058 }
Andreas Huber35213f12012-08-29 11:41:50 -07001059
Andreas Huber799688d2012-10-01 11:26:30 -07001060 mState = AWAITING_CLIENT_PLAY;
1061
Andreas Huber35213f12012-08-29 11:41:50 -07001062 scheduleReaper();
Andreas Huber54408d82012-08-30 16:04:34 -07001063 scheduleKeepAlive(sessionID);
Andreas Huber75a8df92012-09-18 14:47:48 -07001064
1065 return OK;
Andreas Huber35213f12012-08-29 11:41:50 -07001066}
1067
Andreas Huber75a8df92012-09-18 14:47:48 -07001068status_t WifiDisplaySource::onPlayRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001069 int32_t sessionID,
1070 int32_t cseq,
1071 const sp<ParsedMessage> &data) {
1072 int32_t playbackSessionID;
1073 sp<PlaybackSession> playbackSession =
1074 findPlaybackSession(data, &playbackSessionID);
1075
1076 if (playbackSession == NULL) {
1077 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001078 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001079 }
1080
Andreas Huberbe996642012-09-27 14:13:05 -07001081 ALOGI("Received PLAY request.");
1082
Andreas Huber35213f12012-08-29 11:41:50 -07001083 status_t err = playbackSession->play();
1084 CHECK_EQ(err, (status_t)OK);
1085
1086 AString response = "RTSP/1.0 200 OK\r\n";
1087 AppendCommonResponse(&response, cseq, playbackSessionID);
1088 response.append("Range: npt=now-\r\n");
1089 response.append("\r\n");
1090
1091 err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001092
1093 if (err != OK) {
1094 return err;
1095 }
Andreas Huber28169b12012-09-05 10:26:52 -07001096
Andreas Huber7d34f832012-09-13 11:25:33 -07001097 playbackSession->finishPlay();
Andreas Huber75a8df92012-09-18 14:47:48 -07001098
Andreas Huber799688d2012-10-01 11:26:30 -07001099 CHECK_EQ(mState, AWAITING_CLIENT_PLAY);
1100 mState = ABOUT_TO_PLAY;
1101
Andreas Huber75a8df92012-09-18 14:47:48 -07001102 return OK;
Andreas Huber35213f12012-08-29 11:41:50 -07001103}
1104
Andreas Huber75a8df92012-09-18 14:47:48 -07001105status_t WifiDisplaySource::onPauseRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001106 int32_t sessionID,
1107 int32_t cseq,
1108 const sp<ParsedMessage> &data) {
1109 int32_t playbackSessionID;
1110 sp<PlaybackSession> playbackSession =
1111 findPlaybackSession(data, &playbackSessionID);
1112
1113 if (playbackSession == NULL) {
1114 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001115 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001116 }
1117
1118 status_t err = playbackSession->pause();
1119 CHECK_EQ(err, (status_t)OK);
1120
1121 AString response = "RTSP/1.0 200 OK\r\n";
1122 AppendCommonResponse(&response, cseq, playbackSessionID);
1123 response.append("\r\n");
1124
1125 err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001126
1127 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001128}
1129
Andreas Huber75a8df92012-09-18 14:47:48 -07001130status_t WifiDisplaySource::onTeardownRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001131 int32_t sessionID,
1132 int32_t cseq,
1133 const sp<ParsedMessage> &data) {
Andreas Huberbe996642012-09-27 14:13:05 -07001134 ALOGI("Received TEARDOWN request.");
1135
Andreas Huber35213f12012-08-29 11:41:50 -07001136 int32_t playbackSessionID;
1137 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 }
1144
Andreas Huber35213f12012-08-29 11:41:50 -07001145 AString response = "RTSP/1.0 200 OK\r\n";
1146 AppendCommonResponse(&response, cseq, playbackSessionID);
Andreas Huberc438b882012-09-17 15:07:30 -07001147 response.append("Connection: close\r\n");
Andreas Huber35213f12012-08-29 11:41:50 -07001148 response.append("\r\n");
1149
Andreas Huberbe996642012-09-27 14:13:05 -07001150 mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huberc438b882012-09-17 15:07:30 -07001151
Andreas Huber799688d2012-10-01 11:26:30 -07001152 if (mState == AWAITING_CLIENT_TEARDOWN) {
1153 CHECK_NE(mStopReplyID, 0);
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001154 finishStop();
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001155 } else {
Andreas Huberbe996642012-09-27 14:13:05 -07001156 mClient->onDisplayError(IRemoteDisplayClient::kDisplayErrorUnknown);
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001157 }
Andreas Huber75a8df92012-09-18 14:47:48 -07001158
1159 return OK;
Andreas Huber35213f12012-08-29 11:41:50 -07001160}
1161
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001162void WifiDisplaySource::finishStop() {
Andreas Huberbe996642012-09-27 14:13:05 -07001163 ALOGV("finishStop");
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001164
Andreas Huber799688d2012-10-01 11:26:30 -07001165 mState = STOPPING;
1166
Andreas Hubera7f7e0a2012-09-28 10:23:51 -07001167 disconnectClientAsync();
1168}
1169
1170void WifiDisplaySource::finishStopAfterDisconnectingClient() {
1171 ALOGV("finishStopAfterDisconnectingClient");
1172
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001173#if REQUIRE_HDCP
1174 if (mHDCP != NULL) {
Andreas Huberbe996642012-09-27 14:13:05 -07001175 ALOGI("Initiating HDCP shutdown.");
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001176 mHDCP->shutdownAsync();
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001177 return;
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001178 }
1179#endif
1180
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001181 finishStop2();
1182}
1183
1184void WifiDisplaySource::finishStop2() {
Andreas Huberbe996642012-09-27 14:13:05 -07001185 ALOGV("finishStop2");
1186
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001187#if REQUIRE_HDCP
Andreas Huberd1805eb2012-09-28 15:13:18 -07001188 if (mHDCP != NULL) {
1189 mHDCP->setObserver(NULL);
1190 mHDCPObserver.clear();
1191 mHDCP.clear();
1192 }
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001193#endif
1194
Andreas Huberbe996642012-09-27 14:13:05 -07001195 if (mSessionID != 0) {
1196 mNetSession->destroySession(mSessionID);
1197 mSessionID = 0;
1198 }
1199
Andreas Hubera7f7e0a2012-09-28 10:23:51 -07001200 ALOGI("We're stopped.");
Andreas Huber799688d2012-10-01 11:26:30 -07001201 mState = STOPPED;
Andreas Huberbe996642012-09-27 14:13:05 -07001202
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001203 status_t err = OK;
1204
1205 sp<AMessage> response = new AMessage;
1206 response->setInt32("err", err);
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001207 response->postReply(mStopReplyID);
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001208}
1209
Andreas Huber75a8df92012-09-18 14:47:48 -07001210status_t WifiDisplaySource::onGetParameterRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001211 int32_t sessionID,
1212 int32_t cseq,
1213 const sp<ParsedMessage> &data) {
1214 int32_t playbackSessionID;
1215 sp<PlaybackSession> playbackSession =
1216 findPlaybackSession(data, &playbackSessionID);
1217
1218 if (playbackSession == NULL) {
1219 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001220 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001221 }
1222
1223 playbackSession->updateLiveness();
1224
1225 AString response = "RTSP/1.0 200 OK\r\n";
1226 AppendCommonResponse(&response, cseq, playbackSessionID);
1227 response.append("\r\n");
1228
1229 status_t err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001230 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001231}
1232
Andreas Huber75a8df92012-09-18 14:47:48 -07001233status_t WifiDisplaySource::onSetParameterRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001234 int32_t sessionID,
1235 int32_t cseq,
1236 const sp<ParsedMessage> &data) {
1237 int32_t playbackSessionID;
Andreas Huber35213f12012-08-29 11:41:50 -07001238 sp<PlaybackSession> playbackSession =
1239 findPlaybackSession(data, &playbackSessionID);
1240
1241 if (playbackSession == NULL) {
1242 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001243 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001244 }
Andreas Huber35213f12012-08-29 11:41:50 -07001245
Andreas Huber75a8df92012-09-18 14:47:48 -07001246 if (strstr(data->getContent(), "wfd_idr_request\r\n")) {
1247 playbackSession->requestIDRFrame();
1248 }
Andreas Huber03e2ffa2012-09-13 16:43:51 -07001249
Andreas Huber35213f12012-08-29 11:41:50 -07001250 playbackSession->updateLiveness();
1251
1252 AString response = "RTSP/1.0 200 OK\r\n";
1253 AppendCommonResponse(&response, cseq, playbackSessionID);
1254 response.append("\r\n");
1255
1256 status_t err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001257 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001258}
1259
1260// static
1261void WifiDisplaySource::AppendCommonResponse(
1262 AString *response, int32_t cseq, int32_t playbackSessionID) {
1263 time_t now = time(NULL);
1264 struct tm *now2 = gmtime(&now);
1265 char buf[128];
1266 strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", now2);
1267
1268 response->append("Date: ");
1269 response->append(buf);
1270 response->append("\r\n");
1271
1272 response->append("Server: Mine/1.0\r\n");
1273
1274 if (cseq >= 0) {
1275 response->append(StringPrintf("CSeq: %d\r\n", cseq));
1276 }
1277
1278 if (playbackSessionID >= 0ll) {
1279 response->append(
1280 StringPrintf(
1281 "Session: %d;timeout=%lld\r\n",
1282 playbackSessionID, kPlaybackSessionTimeoutSecs));
1283 }
1284}
1285
1286void WifiDisplaySource::sendErrorResponse(
1287 int32_t sessionID,
1288 const char *errorDetail,
1289 int32_t cseq) {
1290 AString response;
1291 response.append("RTSP/1.0 ");
1292 response.append(errorDetail);
1293 response.append("\r\n");
1294
1295 AppendCommonResponse(&response, cseq);
1296
1297 response.append("\r\n");
1298
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001299 mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber35213f12012-08-29 11:41:50 -07001300}
1301
1302int32_t WifiDisplaySource::makeUniquePlaybackSessionID() const {
Andreas Huberc438b882012-09-17 15:07:30 -07001303 return rand();
Andreas Huber35213f12012-08-29 11:41:50 -07001304}
1305
1306sp<WifiDisplaySource::PlaybackSession> WifiDisplaySource::findPlaybackSession(
1307 const sp<ParsedMessage> &data, int32_t *playbackSessionID) const {
1308 if (!data->findInt32("session", playbackSessionID)) {
Andreas Huberc438b882012-09-17 15:07:30 -07001309 // XXX the older dongles do not always include a "Session:" header.
1310 *playbackSessionID = mClientInfo.mPlaybackSessionID;
1311 return mClientInfo.mPlaybackSession;
1312 }
1313
1314 if (*playbackSessionID != mClientInfo.mPlaybackSessionID) {
Andreas Huber35213f12012-08-29 11:41:50 -07001315 return NULL;
1316 }
1317
Andreas Huberc438b882012-09-17 15:07:30 -07001318 return mClientInfo.mPlaybackSession;
1319}
1320
Andreas Hubera7f7e0a2012-09-28 10:23:51 -07001321void WifiDisplaySource::disconnectClientAsync() {
1322 ALOGV("disconnectClient");
Andreas Huberbe996642012-09-27 14:13:05 -07001323
Andreas Hubera7f7e0a2012-09-28 10:23:51 -07001324 if (mClientInfo.mPlaybackSession == NULL) {
1325 disconnectClient2();
1326 return;
1327 }
1328
1329 if (mClientInfo.mPlaybackSession != NULL) {
1330 ALOGV("Destroying PlaybackSession");
1331 mClientInfo.mPlaybackSession->destroyAsync();
1332 }
1333}
1334
1335void WifiDisplaySource::disconnectClient2() {
1336 ALOGV("disconnectClient2");
1337
1338 if (mClientInfo.mPlaybackSession != NULL) {
1339 looper()->unregisterHandler(mClientInfo.mPlaybackSession->id());
1340 mClientInfo.mPlaybackSession.clear();
Andreas Huberbe996642012-09-27 14:13:05 -07001341 }
1342
Andreas Huberc438b882012-09-17 15:07:30 -07001343 if (mClientSessionID != 0) {
Andreas Huberc438b882012-09-17 15:07:30 -07001344 mNetSession->destroySession(mClientSessionID);
1345 mClientSessionID = 0;
Andreas Huber35213f12012-08-29 11:41:50 -07001346 }
1347
Andreas Huberbe996642012-09-27 14:13:05 -07001348 mClient->onDisplayDisconnected();
Andreas Hubera7f7e0a2012-09-28 10:23:51 -07001349
1350 finishStopAfterDisconnectingClient();
Andreas Huber35213f12012-08-29 11:41:50 -07001351}
1352
Andreas Huber75a8df92012-09-18 14:47:48 -07001353#if REQUIRE_HDCP
1354struct WifiDisplaySource::HDCPObserver : public BnHDCPObserver {
1355 HDCPObserver(const sp<AMessage> &notify);
1356
1357 virtual void notify(
1358 int msg, int ext1, int ext2, const Parcel *obj);
1359
1360private:
1361 sp<AMessage> mNotify;
1362
1363 DISALLOW_EVIL_CONSTRUCTORS(HDCPObserver);
1364};
1365
1366WifiDisplaySource::HDCPObserver::HDCPObserver(
1367 const sp<AMessage> &notify)
1368 : mNotify(notify) {
1369}
1370
1371void WifiDisplaySource::HDCPObserver::notify(
1372 int msg, int ext1, int ext2, const Parcel *obj) {
1373 sp<AMessage> notify = mNotify->dup();
1374 notify->setInt32("msg", msg);
1375 notify->setInt32("ext1", ext1);
1376 notify->setInt32("ext2", ext2);
1377 notify->post();
1378}
1379
1380status_t WifiDisplaySource::makeHDCP() {
1381 sp<IServiceManager> sm = defaultServiceManager();
1382 sp<IBinder> binder = sm->getService(String16("media.player"));
1383 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
1384 CHECK(service != NULL);
1385
1386 mHDCP = service->makeHDCP();
1387
1388 if (mHDCP == NULL) {
1389 return ERROR_UNSUPPORTED;
1390 }
1391
1392 sp<AMessage> notify = new AMessage(kWhatHDCPNotify, id());
1393 mHDCPObserver = new HDCPObserver(notify);
1394
1395 status_t err = mHDCP->setObserver(mHDCPObserver);
1396
1397 if (err != OK) {
1398 ALOGE("Failed to set HDCP observer.");
1399
1400 mHDCPObserver.clear();
1401 mHDCP.clear();
1402
1403 return err;
1404 }
1405
Andreas Huberbe996642012-09-27 14:13:05 -07001406 ALOGI("Initiating HDCP negotiation w/ host %s:%d",
Andreas Huber75a8df92012-09-18 14:47:48 -07001407 mClientInfo.mRemoteIP.c_str(), mHDCPPort);
1408
1409 err = mHDCP->initAsync(mClientInfo.mRemoteIP.c_str(), mHDCPPort);
1410
1411 if (err != OK) {
1412 return err;
1413 }
1414
1415 return OK;
1416}
1417#endif
1418
Andreas Huber35213f12012-08-29 11:41:50 -07001419} // namespace android
1420