blob: 9ec1064cd299be8aa27d1bbd6a00116df4984c52 [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"
Andreas Huberbd4e99c2012-10-30 15:53:03 -070025#include "Sender.h"
Andreas Huber35213f12012-08-29 11:41:50 -070026
Andreas Huber75a8df92012-09-18 14:47:48 -070027#include <binder/IServiceManager.h>
Andy McFadden484566c2012-12-18 09:46:54 -080028#include <gui/IGraphicBufferProducer.h>
Andreas Huber75a8df92012-09-18 14:47:48 -070029#include <media/IHDCP.h>
30#include <media/IMediaPlayerService.h>
Andreas Huber28169b12012-09-05 10:26:52 -070031#include <media/IRemoteDisplayClient.h>
Andreas Huber35213f12012-08-29 11:41:50 -070032#include <media/stagefright/foundation/ABuffer.h>
33#include <media/stagefright/foundation/ADebug.h>
34#include <media/stagefright/foundation/AMessage.h>
35#include <media/stagefright/MediaErrors.h>
36
Andreas Huberab1bd842012-08-30 14:51:40 -070037#include <arpa/inet.h>
Andreas Huber7d34f832012-09-13 11:25:33 -070038#include <cutils/properties.h>
Andreas Huberab1bd842012-08-30 14:51:40 -070039
Andreas Huber1fdfd012012-10-09 15:53:34 -070040#include <ctype.h>
41
Andreas Huber35213f12012-08-29 11:41:50 -070042namespace android {
43
Andreas Huber28169b12012-09-05 10:26:52 -070044WifiDisplaySource::WifiDisplaySource(
45 const sp<ANetworkSession> &netSession,
46 const sp<IRemoteDisplayClient> &client)
Andreas Huber799688d2012-10-01 11:26:30 -070047 : mState(INITIALIZED),
48 mNetSession(netSession),
Andreas Huber28169b12012-09-05 10:26:52 -070049 mClient(client),
Andreas Huber35213f12012-08-29 11:41:50 -070050 mSessionID(0),
Andreas Hubera71c3ea2012-09-21 16:02:39 -070051 mStopReplyID(0),
Andreas Huber1fdfd012012-10-09 15:53:34 -070052 mChosenRTPPort(-1),
Andreas Huber20a5a982012-10-04 11:46:29 -070053 mUsingPCMAudio(false),
Andreas Huberc438b882012-09-17 15:07:30 -070054 mClientSessionID(0),
Andreas Huber35213f12012-08-29 11:41:50 -070055 mReaperPending(false),
Andreas Huberfe0847a2012-10-22 10:45:08 -070056 mNextCSeq(1),
57 mUsingHDCP(false),
58 mIsHDCP2_0(false),
59 mHDCPPort(0),
60 mHDCPInitializationComplete(false),
61 mSetupTriggerDeferred(false)
Andreas Huber75a8df92012-09-18 14:47:48 -070062{
Andreas Huber35213f12012-08-29 11:41:50 -070063}
64
65WifiDisplaySource::~WifiDisplaySource() {
66}
67
Andreas Huberbf4950a2012-11-16 10:38:11 -080068static status_t PostAndAwaitResponse(
69 const sp<AMessage> &msg, sp<AMessage> *response) {
70 status_t err = msg->postAndAwaitResponse(response);
71
72 if (err != OK) {
73 return err;
74 }
75
76 if (response == NULL || !(*response)->findInt32("err", &err)) {
77 err = OK;
78 }
79
80 return err;
81}
82
Andreas Huberab1bd842012-08-30 14:51:40 -070083status_t WifiDisplaySource::start(const char *iface) {
Andreas Huber799688d2012-10-01 11:26:30 -070084 CHECK_EQ(mState, INITIALIZED);
85
Andreas Huber35213f12012-08-29 11:41:50 -070086 sp<AMessage> msg = new AMessage(kWhatStart, id());
Andreas Huberab1bd842012-08-30 14:51:40 -070087 msg->setString("iface", iface);
Andreas Huber35213f12012-08-29 11:41:50 -070088
89 sp<AMessage> response;
Andreas Huberbf4950a2012-11-16 10:38:11 -080090 return PostAndAwaitResponse(msg, &response);
Andreas Huber35213f12012-08-29 11:41:50 -070091}
92
93status_t WifiDisplaySource::stop() {
94 sp<AMessage> msg = new AMessage(kWhatStop, id());
95
96 sp<AMessage> response;
Andreas Huberbf4950a2012-11-16 10:38:11 -080097 return PostAndAwaitResponse(msg, &response);
98}
Andreas Huber35213f12012-08-29 11:41:50 -070099
Andreas Huberbf4950a2012-11-16 10:38:11 -0800100status_t WifiDisplaySource::pause() {
101 sp<AMessage> msg = new AMessage(kWhatPause, id());
Andreas Huber35213f12012-08-29 11:41:50 -0700102
Andreas Huberbf4950a2012-11-16 10:38:11 -0800103 sp<AMessage> response;
104 return PostAndAwaitResponse(msg, &response);
105}
Andreas Huber35213f12012-08-29 11:41:50 -0700106
Andreas Huberbf4950a2012-11-16 10:38:11 -0800107status_t WifiDisplaySource::resume() {
108 sp<AMessage> msg = new AMessage(kWhatResume, id());
109
110 sp<AMessage> response;
111 return PostAndAwaitResponse(msg, &response);
Andreas Huber35213f12012-08-29 11:41:50 -0700112}
113
114void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) {
115 switch (msg->what()) {
116 case kWhatStart:
117 {
118 uint32_t replyID;
119 CHECK(msg->senderAwaitsResponse(&replyID));
120
Andreas Huberab1bd842012-08-30 14:51:40 -0700121 AString iface;
122 CHECK(msg->findString("iface", &iface));
Andreas Huber35213f12012-08-29 11:41:50 -0700123
Andreas Huberab1bd842012-08-30 14:51:40 -0700124 status_t err = OK;
Andreas Huber35213f12012-08-29 11:41:50 -0700125
Andreas Huberab1bd842012-08-30 14:51:40 -0700126 ssize_t colonPos = iface.find(":");
127
128 unsigned long port;
129
130 if (colonPos >= 0) {
131 const char *s = iface.c_str() + colonPos + 1;
132
133 char *end;
134 port = strtoul(s, &end, 10);
135
136 if (end == s || *end != '\0' || port > 65535) {
137 err = -EINVAL;
138 } else {
139 iface.erase(colonPos, iface.size() - colonPos);
140 }
141 } else {
142 port = kWifiDisplayDefaultPort;
143 }
144
Andreas Huberab1bd842012-08-30 14:51:40 -0700145 if (err == OK) {
Andreas Huber7d34f832012-09-13 11:25:33 -0700146 if (inet_aton(iface.c_str(), &mInterfaceAddr) != 0) {
Andreas Huberab1bd842012-08-30 14:51:40 -0700147 sp<AMessage> notify = new AMessage(kWhatRTSPNotify, id());
148
149 err = mNetSession->createRTSPServer(
Andreas Huber7d34f832012-09-13 11:25:33 -0700150 mInterfaceAddr, port, notify, &mSessionID);
Andreas Huberab1bd842012-08-30 14:51:40 -0700151 } else {
152 err = -EINVAL;
153 }
154 }
Andreas Huber35213f12012-08-29 11:41:50 -0700155
Andreas Huber799688d2012-10-01 11:26:30 -0700156 if (err == OK) {
157 mState = AWAITING_CLIENT_CONNECTION;
158 }
159
Andreas Huber35213f12012-08-29 11:41:50 -0700160 sp<AMessage> response = new AMessage;
161 response->setInt32("err", err);
162 response->postReply(replyID);
163 break;
164 }
165
166 case kWhatRTSPNotify:
167 {
168 int32_t reason;
169 CHECK(msg->findInt32("reason", &reason));
170
171 switch (reason) {
172 case ANetworkSession::kWhatError:
173 {
174 int32_t sessionID;
175 CHECK(msg->findInt32("sessionID", &sessionID));
176
177 int32_t err;
178 CHECK(msg->findInt32("err", &err));
179
180 AString detail;
181 CHECK(msg->findString("detail", &detail));
182
183 ALOGE("An error occurred in session %d (%d, '%s/%s').",
184 sessionID,
185 err,
186 detail.c_str(),
187 strerror(-err));
188
189 mNetSession->destroySession(sessionID);
190
Andreas Huberc438b882012-09-17 15:07:30 -0700191 if (sessionID == mClientSessionID) {
Andreas Huberbe996642012-09-27 14:13:05 -0700192 mClientSessionID = 0;
Andreas Huberc438b882012-09-17 15:07:30 -0700193
Andreas Huberbe996642012-09-27 14:13:05 -0700194 mClient->onDisplayError(
195 IRemoteDisplayClient::kDisplayErrorUnknown);
Andreas Huberc438b882012-09-17 15:07:30 -0700196 }
Andreas Huber35213f12012-08-29 11:41:50 -0700197 break;
198 }
199
200 case ANetworkSession::kWhatClientConnected:
201 {
202 int32_t sessionID;
203 CHECK(msg->findInt32("sessionID", &sessionID));
204
Andreas Huberc438b882012-09-17 15:07:30 -0700205 if (mClientSessionID > 0) {
206 ALOGW("A client tried to connect, but we already "
207 "have one.");
208
209 mNetSession->destroySession(sessionID);
210 break;
211 }
212
Andreas Huber799688d2012-10-01 11:26:30 -0700213 CHECK_EQ(mState, AWAITING_CLIENT_CONNECTION);
214
Andreas Huberc438b882012-09-17 15:07:30 -0700215 CHECK(msg->findString("client-ip", &mClientInfo.mRemoteIP));
216 CHECK(msg->findString("server-ip", &mClientInfo.mLocalIP));
217
218 if (mClientInfo.mRemoteIP == mClientInfo.mLocalIP) {
219 // Disallow connections from the local interface
220 // for security reasons.
221 mNetSession->destroySession(sessionID);
222 break;
223 }
224
225 CHECK(msg->findInt32(
226 "server-port", &mClientInfo.mLocalPort));
227 mClientInfo.mPlaybackSessionID = -1;
228
229 mClientSessionID = sessionID;
Andreas Huber35213f12012-08-29 11:41:50 -0700230
231 ALOGI("We now have a client (%d) connected.", sessionID);
232
Andreas Huber799688d2012-10-01 11:26:30 -0700233 mState = AWAITING_CLIENT_SETUP;
234
Andreas Huber35213f12012-08-29 11:41:50 -0700235 status_t err = sendM1(sessionID);
236 CHECK_EQ(err, (status_t)OK);
237 break;
238 }
239
240 case ANetworkSession::kWhatData:
241 {
Andreas Huber75a8df92012-09-18 14:47:48 -0700242 status_t err = onReceiveClientData(msg);
243
244 if (err != OK) {
Andreas Huberbe996642012-09-27 14:13:05 -0700245 mClient->onDisplayError(
246 IRemoteDisplayClient::kDisplayErrorUnknown);
Andreas Huber75a8df92012-09-18 14:47:48 -0700247 }
Andreas Huberbf4950a2012-11-16 10:38:11 -0800248
249#if 0
250 // testing only.
251 char val[PROPERTY_VALUE_MAX];
252 if (property_get("media.wfd.trigger", val, NULL)) {
253 if (!strcasecmp(val, "pause") && mState == PLAYING) {
254 mState = PLAYING_TO_PAUSED;
255 sendTrigger(mClientSessionID, TRIGGER_PAUSE);
256 } else if (!strcasecmp(val, "play") && mState == PAUSED) {
257 mState = PAUSED_TO_PLAYING;
258 sendTrigger(mClientSessionID, TRIGGER_PLAY);
259 }
260 }
261#endif
Andreas Huber35213f12012-08-29 11:41:50 -0700262 break;
263 }
264
265 default:
266 TRESPASS();
267 }
268 break;
269 }
270
271 case kWhatStop:
272 {
Andreas Huber8cc2fd32012-09-26 12:54:26 -0700273 CHECK(msg->senderAwaitsResponse(&mStopReplyID));
Andreas Huber35213f12012-08-29 11:41:50 -0700274
Andreas Huber799688d2012-10-01 11:26:30 -0700275 CHECK_LT(mState, AWAITING_CLIENT_TEARDOWN);
276
277 if (mState >= AWAITING_CLIENT_PLAY) {
278 // We have a session, i.e. a previous SETUP succeeded.
279
Andreas Huberbf4950a2012-11-16 10:38:11 -0800280 status_t err = sendTrigger(
281 mClientSessionID, TRIGGER_TEARDOWN);
Andreas Huber28169b12012-09-05 10:26:52 -0700282
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700283 if (err == OK) {
Andreas Huber799688d2012-10-01 11:26:30 -0700284 mState = AWAITING_CLIENT_TEARDOWN;
285
286 (new AMessage(kWhatTeardownTriggerTimedOut, id()))->post(
287 kTeardownTriggerTimeouSecs * 1000000ll);
288
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700289 break;
290 }
Andreas Huber799688d2012-10-01 11:26:30 -0700291
292 // fall through.
Andreas Huber75a8df92012-09-18 14:47:48 -0700293 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700294
Andreas Huber8cc2fd32012-09-26 12:54:26 -0700295 finishStop();
Andreas Huber35213f12012-08-29 11:41:50 -0700296 break;
297 }
298
Andreas Huberbf4950a2012-11-16 10:38:11 -0800299 case kWhatPause:
300 {
301 uint32_t replyID;
302 CHECK(msg->senderAwaitsResponse(&replyID));
303
304 status_t err = OK;
305
306 if (mState != PLAYING) {
307 err = INVALID_OPERATION;
308 } else {
309 mState = PLAYING_TO_PAUSED;
310 sendTrigger(mClientSessionID, TRIGGER_PAUSE);
311 }
312
313 sp<AMessage> response = new AMessage;
314 response->setInt32("err", err);
315 response->postReply(replyID);
316 break;
317 }
318
319 case kWhatResume:
320 {
321 uint32_t replyID;
322 CHECK(msg->senderAwaitsResponse(&replyID));
323
324 status_t err = OK;
325
326 if (mState != PAUSED) {
327 err = INVALID_OPERATION;
328 } else {
329 mState = PAUSED_TO_PLAYING;
330 sendTrigger(mClientSessionID, TRIGGER_PLAY);
331 }
332
333 sp<AMessage> response = new AMessage;
334 response->setInt32("err", err);
335 response->postReply(replyID);
336 break;
337 }
338
Andreas Huber35213f12012-08-29 11:41:50 -0700339 case kWhatReapDeadClients:
340 {
341 mReaperPending = false;
342
Andreas Huberc438b882012-09-17 15:07:30 -0700343 if (mClientSessionID == 0
344 || mClientInfo.mPlaybackSession == NULL) {
345 break;
Andreas Huber35213f12012-08-29 11:41:50 -0700346 }
347
Andreas Huberc438b882012-09-17 15:07:30 -0700348 if (mClientInfo.mPlaybackSession->getLastLifesignUs()
349 + kPlaybackSessionTimeoutUs < ALooper::GetNowUs()) {
350 ALOGI("playback session timed out, reaping.");
351
Andreas Huberbe996642012-09-27 14:13:05 -0700352 mNetSession->destroySession(mClientSessionID);
353 mClientSessionID = 0;
354
355 mClient->onDisplayError(
356 IRemoteDisplayClient::kDisplayErrorUnknown);
Andreas Huberc438b882012-09-17 15:07:30 -0700357 } else {
Andreas Huber35213f12012-08-29 11:41:50 -0700358 scheduleReaper();
359 }
360 break;
361 }
362
363 case kWhatPlaybackSessionNotify:
364 {
365 int32_t playbackSessionID;
366 CHECK(msg->findInt32("playbackSessionID", &playbackSessionID));
367
368 int32_t what;
369 CHECK(msg->findInt32("what", &what));
370
Andreas Huberc438b882012-09-17 15:07:30 -0700371 if (what == PlaybackSession::kWhatSessionDead) {
372 ALOGI("playback session wants to quit.");
Andreas Huber35213f12012-08-29 11:41:50 -0700373
Andreas Huberbe996642012-09-27 14:13:05 -0700374 mClient->onDisplayError(
375 IRemoteDisplayClient::kDisplayErrorUnknown);
Andreas Huberc438b882012-09-17 15:07:30 -0700376 } else if (what == PlaybackSession::kWhatSessionEstablished) {
377 if (mClient != NULL) {
378 mClient->onDisplayConnected(
379 mClientInfo.mPlaybackSession->getSurfaceTexture(),
380 mClientInfo.mPlaybackSession->width(),
381 mClientInfo.mPlaybackSession->height(),
Andreas Huberfe0847a2012-10-22 10:45:08 -0700382 mUsingHDCP
383 ? IRemoteDisplayClient::kDisplayFlagSecure
384 : 0);
Andreas Huber35213f12012-08-29 11:41:50 -0700385 }
Andreas Huber799688d2012-10-01 11:26:30 -0700386
387 if (mState == ABOUT_TO_PLAY) {
388 mState = PLAYING;
389 }
Andreas Hubera7f7e0a2012-09-28 10:23:51 -0700390 } else if (what == PlaybackSession::kWhatSessionDestroyed) {
391 disconnectClient2();
Andreas Huberc438b882012-09-17 15:07:30 -0700392 } else {
393 CHECK_EQ(what, PlaybackSession::kWhatBinaryData);
394
395 int32_t channel;
396 CHECK(msg->findInt32("channel", &channel));
397
398 sp<ABuffer> data;
399 CHECK(msg->findBuffer("data", &data));
400
401 CHECK_LE(channel, 0xffu);
402 CHECK_LE(data->size(), 0xffffu);
403
404 int32_t sessionID;
405 CHECK(msg->findInt32("sessionID", &sessionID));
406
407 char header[4];
408 header[0] = '$';
409 header[1] = channel;
410 header[2] = data->size() >> 8;
411 header[3] = data->size() & 0xff;
412
413 mNetSession->sendRequest(
414 sessionID, header, sizeof(header));
415
416 mNetSession->sendRequest(
417 sessionID, data->data(), data->size());
Andreas Huber35213f12012-08-29 11:41:50 -0700418 }
419 break;
420 }
421
Andreas Huber54408d82012-08-30 16:04:34 -0700422 case kWhatKeepAlive:
423 {
424 int32_t sessionID;
425 CHECK(msg->findInt32("sessionID", &sessionID));
426
Andreas Huberc438b882012-09-17 15:07:30 -0700427 if (mClientSessionID != sessionID) {
Andreas Huber54408d82012-08-30 16:04:34 -0700428 // Obsolete event, client is already gone.
429 break;
430 }
431
432 sendM16(sessionID);
433 break;
434 }
435
Andreas Huber799688d2012-10-01 11:26:30 -0700436 case kWhatTeardownTriggerTimedOut:
437 {
438 if (mState == AWAITING_CLIENT_TEARDOWN) {
439 ALOGI("TEARDOWN trigger timed out, forcing disconnection.");
440
441 CHECK_NE(mStopReplyID, 0);
442 finishStop();
443 break;
444 }
445 break;
446 }
447
Andreas Huber75a8df92012-09-18 14:47:48 -0700448 case kWhatHDCPNotify:
449 {
450 int32_t msgCode, ext1, ext2;
451 CHECK(msg->findInt32("msg", &msgCode));
452 CHECK(msg->findInt32("ext1", &ext1));
453 CHECK(msg->findInt32("ext2", &ext2));
454
Andreas Huber8cc2fd32012-09-26 12:54:26 -0700455 ALOGI("Saw HDCP notification code %d, ext1 %d, ext2 %d",
Andreas Huber75a8df92012-09-18 14:47:48 -0700456 msgCode, ext1, ext2);
457
458 switch (msgCode) {
459 case HDCPModule::HDCP_INITIALIZATION_COMPLETE:
460 {
461 mHDCPInitializationComplete = true;
462
463 if (mSetupTriggerDeferred) {
464 mSetupTriggerDeferred = false;
465
Andreas Huberbf4950a2012-11-16 10:38:11 -0800466 sendTrigger(mClientSessionID, TRIGGER_SETUP);
Andreas Huber75a8df92012-09-18 14:47:48 -0700467 }
468 break;
469 }
470
Andreas Huber8cc2fd32012-09-26 12:54:26 -0700471 case HDCPModule::HDCP_SHUTDOWN_COMPLETE:
Andreas Huberbe996642012-09-27 14:13:05 -0700472 case HDCPModule::HDCP_SHUTDOWN_FAILED:
Andreas Huber8cc2fd32012-09-26 12:54:26 -0700473 {
Andreas Huberbe996642012-09-27 14:13:05 -0700474 // Ugly hack to make sure that the call to
475 // HDCPObserver::notify is completely handled before
476 // we clear the HDCP instance and unload the shared
477 // library :(
478 (new AMessage(kWhatFinishStop2, id()))->post(300000ll);
Andreas Huber8cc2fd32012-09-26 12:54:26 -0700479 break;
480 }
481
Andreas Huber75a8df92012-09-18 14:47:48 -0700482 default:
483 {
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700484 ALOGE("HDCP failure, shutting down.");
485
Andreas Huberbe996642012-09-27 14:13:05 -0700486 mClient->onDisplayError(
487 IRemoteDisplayClient::kDisplayErrorUnknown);
Andreas Huber75a8df92012-09-18 14:47:48 -0700488 break;
489 }
490 }
491 break;
492 }
Andreas Huberbe996642012-09-27 14:13:05 -0700493
494 case kWhatFinishStop2:
495 {
496 finishStop2();
497 break;
498 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700499
Andreas Huber35213f12012-08-29 11:41:50 -0700500 default:
501 TRESPASS();
502 }
503}
504
505void WifiDisplaySource::registerResponseHandler(
506 int32_t sessionID, int32_t cseq, HandleRTSPResponseFunc func) {
507 ResponseID id;
508 id.mSessionID = sessionID;
509 id.mCSeq = cseq;
510 mResponseHandlers.add(id, func);
511}
512
513status_t WifiDisplaySource::sendM1(int32_t sessionID) {
514 AString request = "OPTIONS * RTSP/1.0\r\n";
515 AppendCommonResponse(&request, mNextCSeq);
516
517 request.append(
518 "Require: org.wfa.wfd1.0\r\n"
519 "\r\n");
520
521 status_t err =
522 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
523
524 if (err != OK) {
525 return err;
526 }
527
528 registerResponseHandler(
529 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM1Response);
530
531 ++mNextCSeq;
532
533 return OK;
534}
535
536status_t WifiDisplaySource::sendM3(int32_t sessionID) {
537 AString body =
Andreas Huber75a8df92012-09-18 14:47:48 -0700538 "wfd_content_protection\r\n"
Andreas Huber35213f12012-08-29 11:41:50 -0700539 "wfd_video_formats\r\n"
540 "wfd_audio_codecs\r\n"
541 "wfd_client_rtp_ports\r\n";
542
543 AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
544 AppendCommonResponse(&request, mNextCSeq);
545
546 request.append("Content-Type: text/parameters\r\n");
547 request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
548 request.append("\r\n");
549 request.append(body);
550
551 status_t err =
552 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
553
554 if (err != OK) {
555 return err;
556 }
557
558 registerResponseHandler(
559 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM3Response);
560
561 ++mNextCSeq;
562
563 return OK;
564}
565
566status_t WifiDisplaySource::sendM4(int32_t sessionID) {
567 // wfd_video_formats:
568 // 1 byte "native"
569 // 1 byte "preferred-display-mode-supported" 0 or 1
570 // one or more avc codec structures
571 // 1 byte profile
572 // 1 byte level
573 // 4 byte CEA mask
574 // 4 byte VESA mask
575 // 4 byte HH mask
576 // 1 byte latency
577 // 2 byte min-slice-slice
578 // 2 byte slice-enc-params
579 // 1 byte framerate-control-support
580 // max-hres (none or 2 byte)
581 // max-vres (none or 2 byte)
582
Andreas Huberc438b882012-09-17 15:07:30 -0700583 CHECK_EQ(sessionID, mClientSessionID);
Andreas Huber35213f12012-08-29 11:41:50 -0700584
Andreas Huber7d34f832012-09-13 11:25:33 -0700585 AString transportString = "UDP";
586
587 char val[PROPERTY_VALUE_MAX];
588 if (property_get("media.wfd.enable-tcp", val, NULL)
589 && (!strcasecmp("true", val) || !strcmp("1", val))) {
590 ALOGI("Using TCP transport.");
591 transportString = "TCP";
592 }
593
Andreas Huber75a8df92012-09-18 14:47:48 -0700594 // For 720p60:
595 // use "30 00 02 02 00000040 00000000 00000000 00 0000 0000 00 none none\r\n"
596 // For 720p30:
597 // use "28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none\r\n"
Andreas Huber8000e362012-09-26 14:30:33 -0700598 // For 720p24:
599 // use "78 00 02 02 00008000 00000000 00000000 00 0000 0000 00 none none\r\n"
Andreas Huber83c9bd12012-11-12 13:08:44 -0800600 // For 1080p30:
601 // use "38 00 02 02 00000080 00000000 00000000 00 0000 0000 00 none none\r\n"
Andreas Huber35213f12012-08-29 11:41:50 -0700602 AString body = StringPrintf(
603 "wfd_video_formats: "
Andreas Huber83c9bd12012-11-12 13:08:44 -0800604#if USE_1080P
605 "38 00 02 02 00000080 00000000 00000000 00 0000 0000 00 none none\r\n"
606#else
Andreas Huber77c887a2012-10-02 12:49:33 -0700607 "28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none\r\n"
Andreas Huber83c9bd12012-11-12 13:08:44 -0800608#endif
Andreas Huber20a5a982012-10-04 11:46:29 -0700609 "wfd_audio_codecs: %s\r\n"
Andreas Huber83972432012-09-27 14:27:42 -0700610 "wfd_presentation_URL: rtsp://%s/wfd1.0/streamid=0 none\r\n"
Andreas Huber1fdfd012012-10-09 15:53:34 -0700611 "wfd_client_rtp_ports: RTP/AVP/%s;unicast %d 0 mode=play\r\n",
Andreas Huber20a5a982012-10-04 11:46:29 -0700612 (mUsingPCMAudio
613 ? "LPCM 00000002 00" // 2 ch PCM 48kHz
614 : "AAC 00000001 00"), // 2 ch AAC 48kHz
Andreas Huber1fdfd012012-10-09 15:53:34 -0700615 mClientInfo.mLocalIP.c_str(), transportString.c_str(), mChosenRTPPort);
Andreas Huber35213f12012-08-29 11:41:50 -0700616
617 AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
618 AppendCommonResponse(&request, mNextCSeq);
619
620 request.append("Content-Type: text/parameters\r\n");
621 request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
622 request.append("\r\n");
623 request.append(body);
624
625 status_t err =
626 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
627
628 if (err != OK) {
629 return err;
630 }
631
632 registerResponseHandler(
633 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM4Response);
634
635 ++mNextCSeq;
636
637 return OK;
638}
639
Andreas Huberbf4950a2012-11-16 10:38:11 -0800640status_t WifiDisplaySource::sendTrigger(
641 int32_t sessionID, TriggerType triggerType) {
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700642 AString body = "wfd_trigger_method: ";
Andreas Huberbf4950a2012-11-16 10:38:11 -0800643 switch (triggerType) {
644 case TRIGGER_SETUP:
645 body.append("SETUP");
646 break;
647 case TRIGGER_TEARDOWN:
648 ALOGI("Sending TEARDOWN trigger.");
649 body.append("TEARDOWN");
650 break;
651 case TRIGGER_PAUSE:
652 body.append("PAUSE");
653 break;
654 case TRIGGER_PLAY:
655 body.append("PLAY");
656 break;
657 default:
658 TRESPASS();
Andreas Hubera71c3ea2012-09-21 16:02:39 -0700659 }
660
661 body.append("\r\n");
Andreas Huber35213f12012-08-29 11:41:50 -0700662
663 AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
664 AppendCommonResponse(&request, mNextCSeq);
665
666 request.append("Content-Type: text/parameters\r\n");
667 request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
668 request.append("\r\n");
669 request.append(body);
670
671 status_t err =
672 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
673
674 if (err != OK) {
675 return err;
676 }
677
678 registerResponseHandler(
679 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM5Response);
680
681 ++mNextCSeq;
682
683 return OK;
684}
685
Andreas Huber54408d82012-08-30 16:04:34 -0700686status_t WifiDisplaySource::sendM16(int32_t sessionID) {
687 AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
688 AppendCommonResponse(&request, mNextCSeq);
689
Andreas Huberc438b882012-09-17 15:07:30 -0700690 CHECK_EQ(sessionID, mClientSessionID);
691 request.append(
692 StringPrintf("Session: %d\r\n", mClientInfo.mPlaybackSessionID));
Andreas Huber596b4cd2012-09-12 16:25:14 -0700693 request.append("\r\n"); // Empty body
Andreas Huber54408d82012-08-30 16:04:34 -0700694
695 status_t err =
696 mNetSession->sendRequest(sessionID, request.c_str(), request.size());
697
698 if (err != OK) {
699 return err;
700 }
701
702 registerResponseHandler(
703 sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM16Response);
704
705 ++mNextCSeq;
706
707 return OK;
708}
709
Andreas Huber35213f12012-08-29 11:41:50 -0700710status_t WifiDisplaySource::onReceiveM1Response(
711 int32_t sessionID, const sp<ParsedMessage> &msg) {
712 int32_t statusCode;
713 if (!msg->getStatusCode(&statusCode)) {
714 return ERROR_MALFORMED;
715 }
716
717 if (statusCode != 200) {
718 return ERROR_UNSUPPORTED;
719 }
720
721 return OK;
722}
723
Andreas Huber1fdfd012012-10-09 15:53:34 -0700724// sink_audio_list := ("LPCM"|"AAC"|"AC3" HEXDIGIT*8 HEXDIGIT*2)
725// (", " sink_audio_list)*
726static void GetAudioModes(const char *s, const char *prefix, uint32_t *modes) {
727 *modes = 0;
728
729 size_t prefixLen = strlen(prefix);
730
731 while (*s != '0') {
732 if (!strncmp(s, prefix, prefixLen) && s[prefixLen] == ' ') {
733 unsigned latency;
734 if (sscanf(&s[prefixLen + 1], "%08x %02x", modes, &latency) != 2) {
735 *modes = 0;
736 }
737
738 return;
739 }
740
741 char *commaPos = strchr(s, ',');
742 if (commaPos != NULL) {
743 s = commaPos + 1;
744
745 while (isspace(*s)) {
746 ++s;
747 }
748 } else {
749 break;
750 }
751 }
752}
753
Andreas Huber35213f12012-08-29 11:41:50 -0700754status_t WifiDisplaySource::onReceiveM3Response(
755 int32_t sessionID, const sp<ParsedMessage> &msg) {
756 int32_t statusCode;
757 if (!msg->getStatusCode(&statusCode)) {
758 return ERROR_MALFORMED;
759 }
760
761 if (statusCode != 200) {
762 return ERROR_UNSUPPORTED;
763 }
764
Andreas Huber75a8df92012-09-18 14:47:48 -0700765 sp<Parameters> params =
766 Parameters::Parse(msg->getContent(), strlen(msg->getContent()));
767
768 if (params == NULL) {
769 return ERROR_MALFORMED;
770 }
771
Andreas Huber75a8df92012-09-18 14:47:48 -0700772 AString value;
Andreas Huber1fdfd012012-10-09 15:53:34 -0700773 if (!params->findParameter("wfd_client_rtp_ports", &value)) {
774 ALOGE("Sink doesn't report its choice of wfd_client_rtp_ports.");
775 return ERROR_MALFORMED;
776 }
777
778 unsigned port0, port1;
779 if (sscanf(value.c_str(),
780 "RTP/AVP/UDP;unicast %u %u mode=play",
781 &port0,
782 &port1) != 2
783 || port0 == 0 || port0 > 65535 || port1 != 0) {
784 ALOGE("Sink chose its wfd_client_rtp_ports poorly (%s)",
785 value.c_str());
786
787 return ERROR_MALFORMED;
788 }
789
790 mChosenRTPPort = port0;
791
792 if (!params->findParameter("wfd_audio_codecs", &value)) {
793 ALOGE("Sink doesn't report its choice of wfd_audio_codecs.");
794 return ERROR_MALFORMED;
795 }
796
797 if (value == "none") {
798 ALOGE("Sink doesn't support audio at all.");
799 return ERROR_UNSUPPORTED;
800 }
801
802 uint32_t modes;
803 GetAudioModes(value.c_str(), "AAC", &modes);
804
805 bool supportsAAC = (modes & 1) != 0; // AAC 2ch 48kHz
806
807 GetAudioModes(value.c_str(), "LPCM", &modes);
808
809 bool supportsPCM = (modes & 2) != 0; // LPCM 2ch 48kHz
810
811 char val[PROPERTY_VALUE_MAX];
812 if (supportsPCM
813 && property_get("media.wfd.use-pcm-audio", val, NULL)
814 && (!strcasecmp("true", val) || !strcmp("1", val))) {
815 ALOGI("Using PCM audio.");
816 mUsingPCMAudio = true;
817 } else if (supportsAAC) {
818 ALOGI("Using AAC audio.");
819 mUsingPCMAudio = false;
820 } else if (supportsPCM) {
821 ALOGI("Using PCM audio.");
822 mUsingPCMAudio = true;
823 } else {
824 ALOGI("Sink doesn't support an audio format we do.");
825 return ERROR_UNSUPPORTED;
826 }
827
Andreas Huberfe0847a2012-10-22 10:45:08 -0700828 mUsingHDCP = false;
Andreas Huber75a8df92012-09-18 14:47:48 -0700829 if (!params->findParameter("wfd_content_protection", &value)) {
Andreas Huberfe0847a2012-10-22 10:45:08 -0700830 ALOGI("Sink doesn't appear to support content protection.");
831 } else if (value == "none") {
832 ALOGI("Sink does not support content protection.");
833 } else {
834 mUsingHDCP = true;
Andreas Huber75a8df92012-09-18 14:47:48 -0700835
Andreas Huberfe0847a2012-10-22 10:45:08 -0700836 bool isHDCP2_0 = false;
837 if (value.startsWith("HDCP2.0 ")) {
838 isHDCP2_0 = true;
839 } else if (!value.startsWith("HDCP2.1 ")) {
840 ALOGE("malformed wfd_content_protection: '%s'", value.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -0700841
Andreas Huberfe0847a2012-10-22 10:45:08 -0700842 return ERROR_MALFORMED;
843 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700844
Andreas Huberfe0847a2012-10-22 10:45:08 -0700845 int32_t hdcpPort;
846 if (!ParsedMessage::GetInt32Attribute(
847 value.c_str() + 8, "port", &hdcpPort)
848 || hdcpPort < 1 || hdcpPort > 65535) {
849 return ERROR_MALFORMED;
850 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700851
Andreas Huberfe0847a2012-10-22 10:45:08 -0700852 mIsHDCP2_0 = isHDCP2_0;
853 mHDCPPort = hdcpPort;
Andreas Huber75a8df92012-09-18 14:47:48 -0700854
Andreas Huberfe0847a2012-10-22 10:45:08 -0700855 status_t err = makeHDCP();
856 if (err != OK) {
Andreas Huber83c9bd12012-11-12 13:08:44 -0800857 ALOGE("Unable to instantiate HDCP component. "
858 "Not using HDCP after all.");
859
860 mUsingHDCP = false;
Andreas Huberfe0847a2012-10-22 10:45:08 -0700861 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700862 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700863
Andreas Huber35213f12012-08-29 11:41:50 -0700864 return sendM4(sessionID);
865}
866
867status_t WifiDisplaySource::onReceiveM4Response(
868 int32_t sessionID, const sp<ParsedMessage> &msg) {
869 int32_t statusCode;
870 if (!msg->getStatusCode(&statusCode)) {
871 return ERROR_MALFORMED;
872 }
873
874 if (statusCode != 200) {
875 return ERROR_UNSUPPORTED;
876 }
877
Andreas Huberfe0847a2012-10-22 10:45:08 -0700878 if (mUsingHDCP && !mHDCPInitializationComplete) {
Andreas Huber75a8df92012-09-18 14:47:48 -0700879 ALOGI("Deferring SETUP trigger until HDCP initialization completes.");
880
881 mSetupTriggerDeferred = true;
882 return OK;
883 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700884
Andreas Huberbf4950a2012-11-16 10:38:11 -0800885 return sendTrigger(sessionID, TRIGGER_SETUP);
Andreas Huber35213f12012-08-29 11:41:50 -0700886}
887
888status_t WifiDisplaySource::onReceiveM5Response(
889 int32_t sessionID, const sp<ParsedMessage> &msg) {
890 int32_t statusCode;
891 if (!msg->getStatusCode(&statusCode)) {
892 return ERROR_MALFORMED;
893 }
894
895 if (statusCode != 200) {
896 return ERROR_UNSUPPORTED;
897 }
898
899 return OK;
900}
901
Andreas Huber54408d82012-08-30 16:04:34 -0700902status_t WifiDisplaySource::onReceiveM16Response(
903 int32_t sessionID, const sp<ParsedMessage> &msg) {
904 // If only the response was required to include a "Session:" header...
905
Andreas Huberc438b882012-09-17 15:07:30 -0700906 CHECK_EQ(sessionID, mClientSessionID);
Andreas Huber54408d82012-08-30 16:04:34 -0700907
Andreas Huberc438b882012-09-17 15:07:30 -0700908 if (mClientInfo.mPlaybackSession != NULL) {
909 mClientInfo.mPlaybackSession->updateLiveness();
Andreas Huber54408d82012-08-30 16:04:34 -0700910
911 scheduleKeepAlive(sessionID);
912 }
913
914 return OK;
915}
916
Andreas Huber35213f12012-08-29 11:41:50 -0700917void WifiDisplaySource::scheduleReaper() {
918 if (mReaperPending) {
919 return;
920 }
921
922 mReaperPending = true;
923 (new AMessage(kWhatReapDeadClients, id()))->post(kReaperIntervalUs);
924}
925
Andreas Huber54408d82012-08-30 16:04:34 -0700926void WifiDisplaySource::scheduleKeepAlive(int32_t sessionID) {
927 // We need to send updates at least 5 secs before the timeout is set to
928 // expire, make sure the timeout is greater than 5 secs to begin with.
929 CHECK_GT(kPlaybackSessionTimeoutUs, 5000000ll);
930
931 sp<AMessage> msg = new AMessage(kWhatKeepAlive, id());
932 msg->setInt32("sessionID", sessionID);
933 msg->post(kPlaybackSessionTimeoutUs - 5000000ll);
934}
935
Andreas Huber75a8df92012-09-18 14:47:48 -0700936status_t WifiDisplaySource::onReceiveClientData(const sp<AMessage> &msg) {
Andreas Huber35213f12012-08-29 11:41:50 -0700937 int32_t sessionID;
938 CHECK(msg->findInt32("sessionID", &sessionID));
939
940 sp<RefBase> obj;
941 CHECK(msg->findObject("data", &obj));
942
943 sp<ParsedMessage> data =
944 static_cast<ParsedMessage *>(obj.get());
945
946 ALOGV("session %d received '%s'",
947 sessionID, data->debugString().c_str());
948
949 AString method;
950 AString uri;
951 data->getRequestField(0, &method);
952
953 int32_t cseq;
954 if (!data->findInt32("cseq", &cseq)) {
955 sendErrorResponse(sessionID, "400 Bad Request", -1 /* cseq */);
Andreas Huber75a8df92012-09-18 14:47:48 -0700956 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700957 }
958
959 if (method.startsWith("RTSP/")) {
960 // This is a response.
961
962 ResponseID id;
963 id.mSessionID = sessionID;
964 id.mCSeq = cseq;
965
966 ssize_t index = mResponseHandlers.indexOfKey(id);
967
968 if (index < 0) {
969 ALOGW("Received unsolicited server response, cseq %d", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -0700970 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -0700971 }
972
973 HandleRTSPResponseFunc func = mResponseHandlers.valueAt(index);
974 mResponseHandlers.removeItemsAt(index);
975
976 status_t err = (this->*func)(sessionID, data);
977
978 if (err != OK) {
979 ALOGW("Response handler for session %d, cseq %d returned "
980 "err %d (%s)",
981 sessionID, cseq, err, strerror(-err));
Andreas Huber75a8df92012-09-18 14:47:48 -0700982
983 return err;
Andreas Huber35213f12012-08-29 11:41:50 -0700984 }
985
Andreas Huber75a8df92012-09-18 14:47:48 -0700986 return OK;
Andreas Huber35213f12012-08-29 11:41:50 -0700987 }
Andreas Huber75a8df92012-09-18 14:47:48 -0700988
989 AString version;
990 data->getRequestField(2, &version);
991 if (!(version == AString("RTSP/1.0"))) {
992 sendErrorResponse(sessionID, "505 RTSP Version not supported", cseq);
993 return ERROR_UNSUPPORTED;
994 }
995
996 status_t err;
997 if (method == "OPTIONS") {
998 err = onOptionsRequest(sessionID, cseq, data);
999 } else if (method == "SETUP") {
1000 err = onSetupRequest(sessionID, cseq, data);
1001 } else if (method == "PLAY") {
1002 err = onPlayRequest(sessionID, cseq, data);
1003 } else if (method == "PAUSE") {
1004 err = onPauseRequest(sessionID, cseq, data);
1005 } else if (method == "TEARDOWN") {
1006 err = onTeardownRequest(sessionID, cseq, data);
1007 } else if (method == "GET_PARAMETER") {
1008 err = onGetParameterRequest(sessionID, cseq, data);
1009 } else if (method == "SET_PARAMETER") {
1010 err = onSetParameterRequest(sessionID, cseq, data);
1011 } else {
1012 sendErrorResponse(sessionID, "405 Method Not Allowed", cseq);
1013
1014 err = ERROR_UNSUPPORTED;
1015 }
1016
1017 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001018}
1019
Andreas Huber75a8df92012-09-18 14:47:48 -07001020status_t WifiDisplaySource::onOptionsRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001021 int32_t sessionID,
1022 int32_t cseq,
1023 const sp<ParsedMessage> &data) {
1024 int32_t playbackSessionID;
1025 sp<PlaybackSession> playbackSession =
1026 findPlaybackSession(data, &playbackSessionID);
1027
1028 if (playbackSession != NULL) {
1029 playbackSession->updateLiveness();
1030 }
1031
1032 AString response = "RTSP/1.0 200 OK\r\n";
1033 AppendCommonResponse(&response, cseq);
1034
1035 response.append(
Andreas Huber75a8df92012-09-18 14:47:48 -07001036 "Public: org.wfa.wfd1.0, SETUP, TEARDOWN, PLAY, PAUSE, "
Andreas Huber35213f12012-08-29 11:41:50 -07001037 "GET_PARAMETER, SET_PARAMETER\r\n");
1038
1039 response.append("\r\n");
1040
1041 status_t err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber35213f12012-08-29 11:41:50 -07001042
Andreas Huber75a8df92012-09-18 14:47:48 -07001043 if (err == OK) {
1044 err = sendM3(sessionID);
1045 }
1046
1047 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001048}
1049
Andreas Huber75a8df92012-09-18 14:47:48 -07001050status_t WifiDisplaySource::onSetupRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001051 int32_t sessionID,
1052 int32_t cseq,
1053 const sp<ParsedMessage> &data) {
Andreas Huberc438b882012-09-17 15:07:30 -07001054 CHECK_EQ(sessionID, mClientSessionID);
1055 if (mClientInfo.mPlaybackSessionID != -1) {
Andreas Huber54408d82012-08-30 16:04:34 -07001056 // We only support a single playback session per client.
1057 // This is due to the reversed keep-alive design in the wfd specs...
1058 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001059 return ERROR_MALFORMED;
Andreas Huber54408d82012-08-30 16:04:34 -07001060 }
1061
Andreas Huber35213f12012-08-29 11:41:50 -07001062 AString transport;
1063 if (!data->findString("transport", &transport)) {
1064 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001065 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001066 }
1067
Andreas Huberbd4e99c2012-10-30 15:53:03 -07001068 Sender::TransportMode transportMode = Sender::TRANSPORT_UDP;
Andreas Huber35213f12012-08-29 11:41:50 -07001069
1070 int clientRtp, clientRtcp;
1071 if (transport.startsWith("RTP/AVP/TCP;")) {
1072 AString interleaved;
Andreas Huber7d34f832012-09-13 11:25:33 -07001073 if (ParsedMessage::GetAttribute(
Andreas Huber35213f12012-08-29 11:41:50 -07001074 transport.c_str(), "interleaved", &interleaved)
Andreas Huber7d34f832012-09-13 11:25:33 -07001075 && sscanf(interleaved.c_str(), "%d-%d",
1076 &clientRtp, &clientRtcp) == 2) {
Andreas Huberbd4e99c2012-10-30 15:53:03 -07001077 transportMode = Sender::TRANSPORT_TCP_INTERLEAVED;
Andreas Huber7d34f832012-09-13 11:25:33 -07001078 } else {
1079 bool badRequest = false;
Andreas Huber35213f12012-08-29 11:41:50 -07001080
Andreas Huber7d34f832012-09-13 11:25:33 -07001081 AString clientPort;
1082 if (!ParsedMessage::GetAttribute(
1083 transport.c_str(), "client_port", &clientPort)) {
1084 badRequest = true;
1085 } else if (sscanf(clientPort.c_str(), "%d-%d",
1086 &clientRtp, &clientRtcp) == 2) {
1087 } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
1088 // No RTCP.
1089 clientRtcp = -1;
1090 } else {
1091 badRequest = true;
1092 }
1093
1094 if (badRequest) {
1095 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001096 return ERROR_MALFORMED;
Andreas Huber7d34f832012-09-13 11:25:33 -07001097 }
1098
Andreas Huberbd4e99c2012-10-30 15:53:03 -07001099 transportMode = Sender::TRANSPORT_TCP;
Andreas Huber7d34f832012-09-13 11:25:33 -07001100 }
Andreas Huber35213f12012-08-29 11:41:50 -07001101 } else if (transport.startsWith("RTP/AVP;unicast;")
1102 || transport.startsWith("RTP/AVP/UDP;unicast;")) {
1103 bool badRequest = false;
1104
1105 AString clientPort;
1106 if (!ParsedMessage::GetAttribute(
1107 transport.c_str(), "client_port", &clientPort)) {
1108 badRequest = true;
1109 } else if (sscanf(clientPort.c_str(), "%d-%d",
1110 &clientRtp, &clientRtcp) == 2) {
1111 } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
1112 // No RTCP.
1113 clientRtcp = -1;
1114 } else {
1115 badRequest = true;
1116 }
1117
1118 if (badRequest) {
1119 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001120 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001121 }
1122#if 1
Andreas Huber596b4cd2012-09-12 16:25:14 -07001123 // The older LG dongles doesn't specify client_port=xxx apparently.
Andreas Huber35213f12012-08-29 11:41:50 -07001124 } else if (transport == "RTP/AVP/UDP;unicast") {
1125 clientRtp = 19000;
Andreas Huber0d767952012-09-25 14:20:08 -07001126 clientRtcp = -1;
Andreas Huber35213f12012-08-29 11:41:50 -07001127#endif
1128 } else {
1129 sendErrorResponse(sessionID, "461 Unsupported Transport", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001130 return ERROR_UNSUPPORTED;
Andreas Huber35213f12012-08-29 11:41:50 -07001131 }
1132
1133 int32_t playbackSessionID = makeUniquePlaybackSessionID();
1134
1135 sp<AMessage> notify = new AMessage(kWhatPlaybackSessionNotify, id());
1136 notify->setInt32("playbackSessionID", playbackSessionID);
1137 notify->setInt32("sessionID", sessionID);
1138
1139 sp<PlaybackSession> playbackSession =
Andreas Huber28169b12012-09-05 10:26:52 -07001140 new PlaybackSession(
Andreas Huberfe0847a2012-10-22 10:45:08 -07001141 mNetSession, notify, mInterfaceAddr, mHDCP);
Andreas Huber35213f12012-08-29 11:41:50 -07001142
1143 looper()->registerHandler(playbackSession);
1144
1145 AString uri;
1146 data->getRequestField(1, &uri);
1147
1148 if (strncasecmp("rtsp://", uri.c_str(), 7)) {
1149 sendErrorResponse(sessionID, "400 Bad Request", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001150 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001151 }
1152
1153 if (!(uri.startsWith("rtsp://") && uri.endsWith("/wfd1.0/streamid=0"))) {
1154 sendErrorResponse(sessionID, "404 Not found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001155 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001156 }
1157
Andreas Huber35213f12012-08-29 11:41:50 -07001158 status_t err = playbackSession->init(
Andreas Huberc438b882012-09-17 15:07:30 -07001159 mClientInfo.mRemoteIP.c_str(),
Andreas Huber35213f12012-08-29 11:41:50 -07001160 clientRtp,
1161 clientRtcp,
Andreas Huber20a5a982012-10-04 11:46:29 -07001162 transportMode,
1163 mUsingPCMAudio);
Andreas Huber35213f12012-08-29 11:41:50 -07001164
1165 if (err != OK) {
1166 looper()->unregisterHandler(playbackSession->id());
1167 playbackSession.clear();
1168 }
1169
1170 switch (err) {
1171 case OK:
1172 break;
1173 case -ENOENT:
1174 sendErrorResponse(sessionID, "404 Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001175 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001176 default:
1177 sendErrorResponse(sessionID, "403 Forbidden", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001178 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001179 }
1180
Andreas Huberc438b882012-09-17 15:07:30 -07001181 mClientInfo.mPlaybackSessionID = playbackSessionID;
1182 mClientInfo.mPlaybackSession = playbackSession;
Andreas Huber54408d82012-08-30 16:04:34 -07001183
Andreas Huber35213f12012-08-29 11:41:50 -07001184 AString response = "RTSP/1.0 200 OK\r\n";
1185 AppendCommonResponse(&response, cseq, playbackSessionID);
1186
Andreas Huberbd4e99c2012-10-30 15:53:03 -07001187 if (transportMode == Sender::TRANSPORT_TCP_INTERLEAVED) {
Andreas Huber35213f12012-08-29 11:41:50 -07001188 response.append(
1189 StringPrintf(
1190 "Transport: RTP/AVP/TCP;interleaved=%d-%d;",
1191 clientRtp, clientRtcp));
1192 } else {
1193 int32_t serverRtp = playbackSession->getRTPPort();
1194
Andreas Huber7d34f832012-09-13 11:25:33 -07001195 AString transportString = "UDP";
Andreas Huberbd4e99c2012-10-30 15:53:03 -07001196 if (transportMode == Sender::TRANSPORT_TCP) {
Andreas Huber7d34f832012-09-13 11:25:33 -07001197 transportString = "TCP";
1198 }
1199
Andreas Huber35213f12012-08-29 11:41:50 -07001200 if (clientRtcp >= 0) {
1201 response.append(
1202 StringPrintf(
Andreas Huber7d34f832012-09-13 11:25:33 -07001203 "Transport: RTP/AVP/%s;unicast;client_port=%d-%d;"
Andreas Huber35213f12012-08-29 11:41:50 -07001204 "server_port=%d-%d\r\n",
Andreas Huber7d34f832012-09-13 11:25:33 -07001205 transportString.c_str(),
Andreas Huber35213f12012-08-29 11:41:50 -07001206 clientRtp, clientRtcp, serverRtp, serverRtp + 1));
1207 } else {
1208 response.append(
1209 StringPrintf(
Andreas Huber7d34f832012-09-13 11:25:33 -07001210 "Transport: RTP/AVP/%s;unicast;client_port=%d;"
Andreas Huber35213f12012-08-29 11:41:50 -07001211 "server_port=%d\r\n",
Andreas Huber7d34f832012-09-13 11:25:33 -07001212 transportString.c_str(),
Andreas Huber35213f12012-08-29 11:41:50 -07001213 clientRtp, serverRtp));
1214 }
1215 }
1216
1217 response.append("\r\n");
1218
1219 err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001220
1221 if (err != OK) {
1222 return err;
1223 }
Andreas Huber35213f12012-08-29 11:41:50 -07001224
Andreas Huber799688d2012-10-01 11:26:30 -07001225 mState = AWAITING_CLIENT_PLAY;
1226
Andreas Huber35213f12012-08-29 11:41:50 -07001227 scheduleReaper();
Andreas Huber54408d82012-08-30 16:04:34 -07001228 scheduleKeepAlive(sessionID);
Andreas Huber75a8df92012-09-18 14:47:48 -07001229
1230 return OK;
Andreas Huber35213f12012-08-29 11:41:50 -07001231}
1232
Andreas Huber75a8df92012-09-18 14:47:48 -07001233status_t WifiDisplaySource::onPlayRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001234 int32_t sessionID,
1235 int32_t cseq,
1236 const sp<ParsedMessage> &data) {
1237 int32_t playbackSessionID;
1238 sp<PlaybackSession> playbackSession =
1239 findPlaybackSession(data, &playbackSessionID);
1240
1241 if (playbackSession == NULL) {
1242 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001243 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001244 }
1245
Andreas Huberbe996642012-09-27 14:13:05 -07001246 ALOGI("Received PLAY request.");
1247
Andreas Huber35213f12012-08-29 11:41:50 -07001248 status_t err = playbackSession->play();
1249 CHECK_EQ(err, (status_t)OK);
1250
1251 AString response = "RTSP/1.0 200 OK\r\n";
1252 AppendCommonResponse(&response, cseq, playbackSessionID);
1253 response.append("Range: npt=now-\r\n");
1254 response.append("\r\n");
1255
1256 err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001257
1258 if (err != OK) {
1259 return err;
1260 }
Andreas Huber28169b12012-09-05 10:26:52 -07001261
Andreas Huberbf4950a2012-11-16 10:38:11 -08001262 if (mState == PAUSED_TO_PLAYING) {
1263 mState = PLAYING;
1264 return OK;
1265 }
1266
Andreas Huber7d34f832012-09-13 11:25:33 -07001267 playbackSession->finishPlay();
Andreas Huber75a8df92012-09-18 14:47:48 -07001268
Andreas Huber799688d2012-10-01 11:26:30 -07001269 CHECK_EQ(mState, AWAITING_CLIENT_PLAY);
1270 mState = ABOUT_TO_PLAY;
1271
Andreas Huber75a8df92012-09-18 14:47:48 -07001272 return OK;
Andreas Huber35213f12012-08-29 11:41:50 -07001273}
1274
Andreas Huber75a8df92012-09-18 14:47:48 -07001275status_t WifiDisplaySource::onPauseRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001276 int32_t sessionID,
1277 int32_t cseq,
1278 const sp<ParsedMessage> &data) {
1279 int32_t playbackSessionID;
1280 sp<PlaybackSession> playbackSession =
1281 findPlaybackSession(data, &playbackSessionID);
1282
1283 if (playbackSession == NULL) {
1284 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001285 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001286 }
1287
Andreas Huberbf4950a2012-11-16 10:38:11 -08001288 ALOGI("Received PAUSE request.");
1289
1290 if (mState != PLAYING_TO_PAUSED) {
1291 return INVALID_OPERATION;
1292 }
1293
Andreas Huber35213f12012-08-29 11:41:50 -07001294 status_t err = playbackSession->pause();
1295 CHECK_EQ(err, (status_t)OK);
1296
1297 AString response = "RTSP/1.0 200 OK\r\n";
1298 AppendCommonResponse(&response, cseq, playbackSessionID);
1299 response.append("\r\n");
1300
1301 err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001302
Andreas Huberbf4950a2012-11-16 10:38:11 -08001303 if (err != OK) {
1304 return err;
1305 }
1306
1307 mState = PAUSED;
1308
Andreas Huber75a8df92012-09-18 14:47:48 -07001309 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001310}
1311
Andreas Huber75a8df92012-09-18 14:47:48 -07001312status_t WifiDisplaySource::onTeardownRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001313 int32_t sessionID,
1314 int32_t cseq,
1315 const sp<ParsedMessage> &data) {
Andreas Huberbe996642012-09-27 14:13:05 -07001316 ALOGI("Received TEARDOWN request.");
1317
Andreas Huber35213f12012-08-29 11:41:50 -07001318 int32_t playbackSessionID;
1319 sp<PlaybackSession> playbackSession =
1320 findPlaybackSession(data, &playbackSessionID);
1321
1322 if (playbackSession == NULL) {
1323 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001324 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001325 }
1326
Andreas Huber35213f12012-08-29 11:41:50 -07001327 AString response = "RTSP/1.0 200 OK\r\n";
1328 AppendCommonResponse(&response, cseq, playbackSessionID);
Andreas Huberc438b882012-09-17 15:07:30 -07001329 response.append("Connection: close\r\n");
Andreas Huber35213f12012-08-29 11:41:50 -07001330 response.append("\r\n");
1331
Andreas Huberbe996642012-09-27 14:13:05 -07001332 mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huberc438b882012-09-17 15:07:30 -07001333
Andreas Huber799688d2012-10-01 11:26:30 -07001334 if (mState == AWAITING_CLIENT_TEARDOWN) {
1335 CHECK_NE(mStopReplyID, 0);
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001336 finishStop();
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001337 } else {
Andreas Huberbe996642012-09-27 14:13:05 -07001338 mClient->onDisplayError(IRemoteDisplayClient::kDisplayErrorUnknown);
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001339 }
Andreas Huber75a8df92012-09-18 14:47:48 -07001340
1341 return OK;
Andreas Huber35213f12012-08-29 11:41:50 -07001342}
1343
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001344void WifiDisplaySource::finishStop() {
Andreas Huberbe996642012-09-27 14:13:05 -07001345 ALOGV("finishStop");
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001346
Andreas Huber799688d2012-10-01 11:26:30 -07001347 mState = STOPPING;
1348
Andreas Hubera7f7e0a2012-09-28 10:23:51 -07001349 disconnectClientAsync();
1350}
1351
1352void WifiDisplaySource::finishStopAfterDisconnectingClient() {
1353 ALOGV("finishStopAfterDisconnectingClient");
1354
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001355 if (mHDCP != NULL) {
Andreas Huberbe996642012-09-27 14:13:05 -07001356 ALOGI("Initiating HDCP shutdown.");
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001357 mHDCP->shutdownAsync();
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001358 return;
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001359 }
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001360
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001361 finishStop2();
1362}
1363
1364void WifiDisplaySource::finishStop2() {
Andreas Huberbe996642012-09-27 14:13:05 -07001365 ALOGV("finishStop2");
1366
Andreas Huberd1805eb2012-09-28 15:13:18 -07001367 if (mHDCP != NULL) {
1368 mHDCP->setObserver(NULL);
1369 mHDCPObserver.clear();
1370 mHDCP.clear();
1371 }
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001372
Andreas Huberbe996642012-09-27 14:13:05 -07001373 if (mSessionID != 0) {
1374 mNetSession->destroySession(mSessionID);
1375 mSessionID = 0;
1376 }
1377
Andreas Hubera7f7e0a2012-09-28 10:23:51 -07001378 ALOGI("We're stopped.");
Andreas Huber799688d2012-10-01 11:26:30 -07001379 mState = STOPPED;
Andreas Huberbe996642012-09-27 14:13:05 -07001380
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001381 status_t err = OK;
1382
1383 sp<AMessage> response = new AMessage;
1384 response->setInt32("err", err);
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001385 response->postReply(mStopReplyID);
Andreas Hubera71c3ea2012-09-21 16:02:39 -07001386}
1387
Andreas Huber75a8df92012-09-18 14:47:48 -07001388status_t WifiDisplaySource::onGetParameterRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001389 int32_t sessionID,
1390 int32_t cseq,
1391 const sp<ParsedMessage> &data) {
1392 int32_t playbackSessionID;
1393 sp<PlaybackSession> playbackSession =
1394 findPlaybackSession(data, &playbackSessionID);
1395
1396 if (playbackSession == NULL) {
1397 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001398 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001399 }
1400
1401 playbackSession->updateLiveness();
1402
1403 AString response = "RTSP/1.0 200 OK\r\n";
1404 AppendCommonResponse(&response, cseq, playbackSessionID);
1405 response.append("\r\n");
1406
1407 status_t err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001408 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001409}
1410
Andreas Huber75a8df92012-09-18 14:47:48 -07001411status_t WifiDisplaySource::onSetParameterRequest(
Andreas Huber35213f12012-08-29 11:41:50 -07001412 int32_t sessionID,
1413 int32_t cseq,
1414 const sp<ParsedMessage> &data) {
1415 int32_t playbackSessionID;
Andreas Huber35213f12012-08-29 11:41:50 -07001416 sp<PlaybackSession> playbackSession =
1417 findPlaybackSession(data, &playbackSessionID);
1418
1419 if (playbackSession == NULL) {
1420 sendErrorResponse(sessionID, "454 Session Not Found", cseq);
Andreas Huber75a8df92012-09-18 14:47:48 -07001421 return ERROR_MALFORMED;
Andreas Huber35213f12012-08-29 11:41:50 -07001422 }
Andreas Huber35213f12012-08-29 11:41:50 -07001423
Andreas Huber75a8df92012-09-18 14:47:48 -07001424 if (strstr(data->getContent(), "wfd_idr_request\r\n")) {
1425 playbackSession->requestIDRFrame();
1426 }
Andreas Huber03e2ffa2012-09-13 16:43:51 -07001427
Andreas Huber35213f12012-08-29 11:41:50 -07001428 playbackSession->updateLiveness();
1429
1430 AString response = "RTSP/1.0 200 OK\r\n";
1431 AppendCommonResponse(&response, cseq, playbackSessionID);
1432 response.append("\r\n");
1433
1434 status_t err = mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber75a8df92012-09-18 14:47:48 -07001435 return err;
Andreas Huber35213f12012-08-29 11:41:50 -07001436}
1437
1438// static
1439void WifiDisplaySource::AppendCommonResponse(
1440 AString *response, int32_t cseq, int32_t playbackSessionID) {
1441 time_t now = time(NULL);
1442 struct tm *now2 = gmtime(&now);
1443 char buf[128];
1444 strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", now2);
1445
1446 response->append("Date: ");
1447 response->append(buf);
1448 response->append("\r\n");
1449
1450 response->append("Server: Mine/1.0\r\n");
1451
1452 if (cseq >= 0) {
1453 response->append(StringPrintf("CSeq: %d\r\n", cseq));
1454 }
1455
1456 if (playbackSessionID >= 0ll) {
1457 response->append(
1458 StringPrintf(
1459 "Session: %d;timeout=%lld\r\n",
1460 playbackSessionID, kPlaybackSessionTimeoutSecs));
1461 }
1462}
1463
1464void WifiDisplaySource::sendErrorResponse(
1465 int32_t sessionID,
1466 const char *errorDetail,
1467 int32_t cseq) {
1468 AString response;
1469 response.append("RTSP/1.0 ");
1470 response.append(errorDetail);
1471 response.append("\r\n");
1472
1473 AppendCommonResponse(&response, cseq);
1474
1475 response.append("\r\n");
1476
Andreas Huber8cc2fd32012-09-26 12:54:26 -07001477 mNetSession->sendRequest(sessionID, response.c_str());
Andreas Huber35213f12012-08-29 11:41:50 -07001478}
1479
1480int32_t WifiDisplaySource::makeUniquePlaybackSessionID() const {
Andreas Huberc438b882012-09-17 15:07:30 -07001481 return rand();
Andreas Huber35213f12012-08-29 11:41:50 -07001482}
1483
1484sp<WifiDisplaySource::PlaybackSession> WifiDisplaySource::findPlaybackSession(
1485 const sp<ParsedMessage> &data, int32_t *playbackSessionID) const {
1486 if (!data->findInt32("session", playbackSessionID)) {
Andreas Huberc438b882012-09-17 15:07:30 -07001487 // XXX the older dongles do not always include a "Session:" header.
1488 *playbackSessionID = mClientInfo.mPlaybackSessionID;
1489 return mClientInfo.mPlaybackSession;
1490 }
1491
1492 if (*playbackSessionID != mClientInfo.mPlaybackSessionID) {
Andreas Huber35213f12012-08-29 11:41:50 -07001493 return NULL;
1494 }
1495
Andreas Huberc438b882012-09-17 15:07:30 -07001496 return mClientInfo.mPlaybackSession;
1497}
1498
Andreas Hubera7f7e0a2012-09-28 10:23:51 -07001499void WifiDisplaySource::disconnectClientAsync() {
1500 ALOGV("disconnectClient");
Andreas Huberbe996642012-09-27 14:13:05 -07001501
Andreas Hubera7f7e0a2012-09-28 10:23:51 -07001502 if (mClientInfo.mPlaybackSession == NULL) {
1503 disconnectClient2();
1504 return;
1505 }
1506
1507 if (mClientInfo.mPlaybackSession != NULL) {
1508 ALOGV("Destroying PlaybackSession");
1509 mClientInfo.mPlaybackSession->destroyAsync();
1510 }
1511}
1512
1513void WifiDisplaySource::disconnectClient2() {
1514 ALOGV("disconnectClient2");
1515
1516 if (mClientInfo.mPlaybackSession != NULL) {
1517 looper()->unregisterHandler(mClientInfo.mPlaybackSession->id());
1518 mClientInfo.mPlaybackSession.clear();
Andreas Huberbe996642012-09-27 14:13:05 -07001519 }
1520
Andreas Huberc438b882012-09-17 15:07:30 -07001521 if (mClientSessionID != 0) {
Andreas Huberc438b882012-09-17 15:07:30 -07001522 mNetSession->destroySession(mClientSessionID);
1523 mClientSessionID = 0;
Andreas Huber35213f12012-08-29 11:41:50 -07001524 }
1525
Andreas Huberbe996642012-09-27 14:13:05 -07001526 mClient->onDisplayDisconnected();
Andreas Hubera7f7e0a2012-09-28 10:23:51 -07001527
1528 finishStopAfterDisconnectingClient();
Andreas Huber35213f12012-08-29 11:41:50 -07001529}
1530
Andreas Huber75a8df92012-09-18 14:47:48 -07001531struct WifiDisplaySource::HDCPObserver : public BnHDCPObserver {
1532 HDCPObserver(const sp<AMessage> &notify);
1533
1534 virtual void notify(
1535 int msg, int ext1, int ext2, const Parcel *obj);
1536
1537private:
1538 sp<AMessage> mNotify;
1539
1540 DISALLOW_EVIL_CONSTRUCTORS(HDCPObserver);
1541};
1542
1543WifiDisplaySource::HDCPObserver::HDCPObserver(
1544 const sp<AMessage> &notify)
1545 : mNotify(notify) {
1546}
1547
1548void WifiDisplaySource::HDCPObserver::notify(
1549 int msg, int ext1, int ext2, const Parcel *obj) {
1550 sp<AMessage> notify = mNotify->dup();
1551 notify->setInt32("msg", msg);
1552 notify->setInt32("ext1", ext1);
1553 notify->setInt32("ext2", ext2);
1554 notify->post();
1555}
1556
1557status_t WifiDisplaySource::makeHDCP() {
1558 sp<IServiceManager> sm = defaultServiceManager();
1559 sp<IBinder> binder = sm->getService(String16("media.player"));
1560 sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
1561 CHECK(service != NULL);
1562
1563 mHDCP = service->makeHDCP();
1564
1565 if (mHDCP == NULL) {
1566 return ERROR_UNSUPPORTED;
1567 }
1568
1569 sp<AMessage> notify = new AMessage(kWhatHDCPNotify, id());
1570 mHDCPObserver = new HDCPObserver(notify);
1571
1572 status_t err = mHDCP->setObserver(mHDCPObserver);
1573
1574 if (err != OK) {
1575 ALOGE("Failed to set HDCP observer.");
1576
1577 mHDCPObserver.clear();
1578 mHDCP.clear();
1579
1580 return err;
1581 }
1582
Andreas Huberbe996642012-09-27 14:13:05 -07001583 ALOGI("Initiating HDCP negotiation w/ host %s:%d",
Andreas Huber75a8df92012-09-18 14:47:48 -07001584 mClientInfo.mRemoteIP.c_str(), mHDCPPort);
1585
1586 err = mHDCP->initAsync(mClientInfo.mRemoteIP.c_str(), mHDCPPort);
1587
1588 if (err != OK) {
1589 return err;
1590 }
1591
1592 return OK;
1593}
Andreas Huber75a8df92012-09-18 14:47:48 -07001594
Andreas Huber35213f12012-08-29 11:41:50 -07001595} // namespace android
1596