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