WifiDisplaySource.cpp revision efd9c63dc846dd3dea2c979fe2a9d6770e73f9ac
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
26#include <binder/IServiceManager.h>
27#include <gui/ISurfaceTexture.h>
28#include <media/IHDCP.h>
29#include <media/IMediaPlayerService.h>
30#include <media/IRemoteDisplayClient.h>
31#include <media/stagefright/foundation/ABuffer.h>
32#include <media/stagefright/foundation/ADebug.h>
33#include <media/stagefright/foundation/AMessage.h>
34#include <media/stagefright/MediaErrors.h>
35
36#include <arpa/inet.h>
37#include <cutils/properties.h>
38
39namespace android {
40
41WifiDisplaySource::WifiDisplaySource(
42        const sp<ANetworkSession> &netSession,
43        const sp<IRemoteDisplayClient> &client)
44    : mNetSession(netSession),
45      mClient(client),
46      mSessionID(0),
47      mClientSessionID(0),
48      mReaperPending(false),
49      mNextCSeq(1)
50#if REQUIRE_HDCP
51      ,mIsHDCP2_0(false)
52      ,mHDCPPort(0)
53      ,mHDCPInitializationComplete(false)
54      ,mSetupTriggerDeferred(false)
55#endif
56{
57}
58
59WifiDisplaySource::~WifiDisplaySource() {
60}
61
62status_t WifiDisplaySource::start(const char *iface) {
63    sp<AMessage> msg = new AMessage(kWhatStart, id());
64    msg->setString("iface", iface);
65
66    sp<AMessage> response;
67    status_t err = msg->postAndAwaitResponse(&response);
68
69    if (err != OK) {
70        return err;
71    }
72
73    if (!response->findInt32("err", &err)) {
74        err = OK;
75    }
76
77    return err;
78}
79
80status_t WifiDisplaySource::stop() {
81    sp<AMessage> msg = new AMessage(kWhatStop, id());
82
83    sp<AMessage> response;
84    status_t err = msg->postAndAwaitResponse(&response);
85
86    if (err != OK) {
87        return err;
88    }
89
90    if (!response->findInt32("err", &err)) {
91        err = OK;
92    }
93
94    return err;
95}
96
97void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) {
98    switch (msg->what()) {
99        case kWhatStart:
100        {
101            uint32_t replyID;
102            CHECK(msg->senderAwaitsResponse(&replyID));
103
104            AString iface;
105            CHECK(msg->findString("iface", &iface));
106
107            status_t err = OK;
108
109            ssize_t colonPos = iface.find(":");
110
111            unsigned long port;
112
113            if (colonPos >= 0) {
114                const char *s = iface.c_str() + colonPos + 1;
115
116                char *end;
117                port = strtoul(s, &end, 10);
118
119                if (end == s || *end != '\0' || port > 65535) {
120                    err = -EINVAL;
121                } else {
122                    iface.erase(colonPos, iface.size() - colonPos);
123                }
124            } else {
125                port = kWifiDisplayDefaultPort;
126            }
127
128            if (err == OK) {
129                if (inet_aton(iface.c_str(), &mInterfaceAddr) != 0) {
130                    sp<AMessage> notify = new AMessage(kWhatRTSPNotify, id());
131
132                    err = mNetSession->createRTSPServer(
133                            mInterfaceAddr, port, notify, &mSessionID);
134                } else {
135                    err = -EINVAL;
136                }
137            }
138
139            sp<AMessage> response = new AMessage;
140            response->setInt32("err", err);
141            response->postReply(replyID);
142            break;
143        }
144
145        case kWhatRTSPNotify:
146        {
147            int32_t reason;
148            CHECK(msg->findInt32("reason", &reason));
149
150            switch (reason) {
151                case ANetworkSession::kWhatError:
152                {
153                    int32_t sessionID;
154                    CHECK(msg->findInt32("sessionID", &sessionID));
155
156                    int32_t err;
157                    CHECK(msg->findInt32("err", &err));
158
159                    AString detail;
160                    CHECK(msg->findString("detail", &detail));
161
162                    ALOGE("An error occurred in session %d (%d, '%s/%s').",
163                          sessionID,
164                          err,
165                          detail.c_str(),
166                          strerror(-err));
167
168                    mNetSession->destroySession(sessionID);
169
170                    if (sessionID == mClientSessionID) {
171                        mClientSessionID = -1;
172
173                        disconnectClient(UNKNOWN_ERROR);
174                    }
175                    break;
176                }
177
178                case ANetworkSession::kWhatClientConnected:
179                {
180                    int32_t sessionID;
181                    CHECK(msg->findInt32("sessionID", &sessionID));
182
183                    if (mClientSessionID > 0) {
184                        ALOGW("A client tried to connect, but we already "
185                              "have one.");
186
187                        mNetSession->destroySession(sessionID);
188                        break;
189                    }
190
191                    CHECK(msg->findString("client-ip", &mClientInfo.mRemoteIP));
192                    CHECK(msg->findString("server-ip", &mClientInfo.mLocalIP));
193
194                    if (mClientInfo.mRemoteIP == mClientInfo.mLocalIP) {
195                        // Disallow connections from the local interface
196                        // for security reasons.
197                        mNetSession->destroySession(sessionID);
198                        break;
199                    }
200
201                    CHECK(msg->findInt32(
202                                "server-port", &mClientInfo.mLocalPort));
203                    mClientInfo.mPlaybackSessionID = -1;
204
205                    mClientSessionID = sessionID;
206
207                    ALOGI("We now have a client (%d) connected.", sessionID);
208
209                    status_t err = sendM1(sessionID);
210                    CHECK_EQ(err, (status_t)OK);
211                    break;
212                }
213
214                case ANetworkSession::kWhatData:
215                {
216                    status_t err = onReceiveClientData(msg);
217
218                    if (err != OK) {
219                        disconnectClient(err);
220                    }
221                    break;
222                }
223
224                default:
225                    TRESPASS();
226            }
227            break;
228        }
229
230        case kWhatStop:
231        {
232            uint32_t replyID;
233            CHECK(msg->senderAwaitsResponse(&replyID));
234
235            disconnectClient(OK);
236
237#if REQUIRE_HDCP
238            if (mHDCP != NULL) {
239                mHDCP->shutdownAsync();
240                mHDCP.clear();
241            }
242#endif
243
244            status_t err = OK;
245
246            sp<AMessage> response = new AMessage;
247            response->setInt32("err", err);
248            response->postReply(replyID);
249            break;
250        }
251
252        case kWhatReapDeadClients:
253        {
254            mReaperPending = false;
255
256            if (mClientSessionID == 0
257                    || mClientInfo.mPlaybackSession == NULL) {
258                break;
259            }
260
261            if (mClientInfo.mPlaybackSession->getLastLifesignUs()
262                    + kPlaybackSessionTimeoutUs < ALooper::GetNowUs()) {
263                ALOGI("playback session timed out, reaping.");
264
265                disconnectClient(-ETIMEDOUT);
266            } else {
267                scheduleReaper();
268            }
269            break;
270        }
271
272        case kWhatPlaybackSessionNotify:
273        {
274            int32_t playbackSessionID;
275            CHECK(msg->findInt32("playbackSessionID", &playbackSessionID));
276
277            int32_t what;
278            CHECK(msg->findInt32("what", &what));
279
280            if (what == PlaybackSession::kWhatSessionDead) {
281                ALOGI("playback session wants to quit.");
282
283                disconnectClient(UNKNOWN_ERROR);
284            } else if (what == PlaybackSession::kWhatSessionEstablished) {
285                if (mClient != NULL) {
286                    mClient->onDisplayConnected(
287                            mClientInfo.mPlaybackSession->getSurfaceTexture(),
288                            mClientInfo.mPlaybackSession->width(),
289                            mClientInfo.mPlaybackSession->height(),
290                            0 /* flags */);
291                }
292            } else {
293                CHECK_EQ(what, PlaybackSession::kWhatBinaryData);
294
295                int32_t channel;
296                CHECK(msg->findInt32("channel", &channel));
297
298                sp<ABuffer> data;
299                CHECK(msg->findBuffer("data", &data));
300
301                CHECK_LE(channel, 0xffu);
302                CHECK_LE(data->size(), 0xffffu);
303
304                int32_t sessionID;
305                CHECK(msg->findInt32("sessionID", &sessionID));
306
307                char header[4];
308                header[0] = '$';
309                header[1] = channel;
310                header[2] = data->size() >> 8;
311                header[3] = data->size() & 0xff;
312
313                mNetSession->sendRequest(
314                        sessionID, header, sizeof(header));
315
316                mNetSession->sendRequest(
317                        sessionID, data->data(), data->size());
318            }
319            break;
320        }
321
322        case kWhatKeepAlive:
323        {
324            int32_t sessionID;
325            CHECK(msg->findInt32("sessionID", &sessionID));
326
327            if (mClientSessionID != sessionID) {
328                // Obsolete event, client is already gone.
329                break;
330            }
331
332            sendM16(sessionID);
333            break;
334        }
335
336#if REQUIRE_HDCP
337        case kWhatHDCPNotify:
338        {
339            int32_t msgCode, ext1, ext2;
340            CHECK(msg->findInt32("msg", &msgCode));
341            CHECK(msg->findInt32("ext1", &ext1));
342            CHECK(msg->findInt32("ext2", &ext2));
343
344            ALOGV("Saw HDCP notification code %d, ext1 %d, ext2 %d",
345                    msgCode, ext1, ext2);
346
347            switch (msgCode) {
348                case HDCPModule::HDCP_INITIALIZATION_COMPLETE:
349                {
350                    mHDCPInitializationComplete = true;
351
352                    if (mSetupTriggerDeferred) {
353                        mSetupTriggerDeferred = false;
354
355                        sendM5(mClientSessionID);
356                    }
357                    break;
358                }
359
360                default:
361                {
362                    disconnectClient(-EACCES);
363                    break;
364                }
365            }
366            break;
367        }
368#endif
369
370        default:
371            TRESPASS();
372    }
373}
374
375void WifiDisplaySource::registerResponseHandler(
376        int32_t sessionID, int32_t cseq, HandleRTSPResponseFunc func) {
377    ResponseID id;
378    id.mSessionID = sessionID;
379    id.mCSeq = cseq;
380    mResponseHandlers.add(id, func);
381}
382
383status_t WifiDisplaySource::sendM1(int32_t sessionID) {
384    AString request = "OPTIONS * RTSP/1.0\r\n";
385    AppendCommonResponse(&request, mNextCSeq);
386
387    request.append(
388            "Require: org.wfa.wfd1.0\r\n"
389            "\r\n");
390
391    status_t err =
392        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
393
394    if (err != OK) {
395        return err;
396    }
397
398    registerResponseHandler(
399            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM1Response);
400
401    ++mNextCSeq;
402
403    return OK;
404}
405
406status_t WifiDisplaySource::sendM3(int32_t sessionID) {
407    AString body =
408#if REQUIRE_HDCP
409        "wfd_content_protection\r\n"
410#endif
411        "wfd_video_formats\r\n"
412        "wfd_audio_codecs\r\n"
413        "wfd_client_rtp_ports\r\n";
414
415    AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
416    AppendCommonResponse(&request, mNextCSeq);
417
418    request.append("Content-Type: text/parameters\r\n");
419    request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
420    request.append("\r\n");
421    request.append(body);
422
423    status_t err =
424        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
425
426    if (err != OK) {
427        return err;
428    }
429
430    registerResponseHandler(
431            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM3Response);
432
433    ++mNextCSeq;
434
435    return OK;
436}
437
438status_t WifiDisplaySource::sendM4(int32_t sessionID) {
439    // wfd_video_formats:
440    // 1 byte "native"
441    // 1 byte "preferred-display-mode-supported" 0 or 1
442    // one or more avc codec structures
443    //   1 byte profile
444    //   1 byte level
445    //   4 byte CEA mask
446    //   4 byte VESA mask
447    //   4 byte HH mask
448    //   1 byte latency
449    //   2 byte min-slice-slice
450    //   2 byte slice-enc-params
451    //   1 byte framerate-control-support
452    //   max-hres (none or 2 byte)
453    //   max-vres (none or 2 byte)
454
455    CHECK_EQ(sessionID, mClientSessionID);
456
457    AString transportString = "UDP";
458
459    char val[PROPERTY_VALUE_MAX];
460    if (property_get("media.wfd.enable-tcp", val, NULL)
461            && (!strcasecmp("true", val) || !strcmp("1", val))) {
462        ALOGI("Using TCP transport.");
463        transportString = "TCP";
464    }
465
466    // For 720p60:
467    //   use "30 00 02 02 00000040 00000000 00000000 00 0000 0000 00 none none\r\n"
468    // For 720p30:
469    //   use "28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none\r\n"
470    AString body = StringPrintf(
471        "wfd_video_formats: "
472        "28 00 02 02 00000020 00000000 00000000 00 0000 0000 00 none none\r\n"
473        "wfd_audio_codecs: AAC 00000001 00\r\n"  // 2 ch AAC 48kHz
474        "wfd_presentation_URL: rtsp://%s:%d/wfd1.0/streamid=0 none\r\n"
475        "wfd_client_rtp_ports: RTP/AVP/%s;unicast 19000 0 mode=play\r\n",
476        mClientInfo.mLocalIP.c_str(), mClientInfo.mLocalPort,
477        transportString.c_str());
478
479    AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
480    AppendCommonResponse(&request, mNextCSeq);
481
482    request.append("Content-Type: text/parameters\r\n");
483    request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
484    request.append("\r\n");
485    request.append(body);
486
487    status_t err =
488        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
489
490    if (err != OK) {
491        return err;
492    }
493
494    registerResponseHandler(
495            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM4Response);
496
497    ++mNextCSeq;
498
499    return OK;
500}
501
502status_t WifiDisplaySource::sendM5(int32_t sessionID) {
503    AString body = "wfd_trigger_method: SETUP\r\n";
504
505    AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
506    AppendCommonResponse(&request, mNextCSeq);
507
508    request.append("Content-Type: text/parameters\r\n");
509    request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
510    request.append("\r\n");
511    request.append(body);
512
513    status_t err =
514        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
515
516    if (err != OK) {
517        return err;
518    }
519
520    registerResponseHandler(
521            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM5Response);
522
523    ++mNextCSeq;
524
525    return OK;
526}
527
528status_t WifiDisplaySource::sendM16(int32_t sessionID) {
529    AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
530    AppendCommonResponse(&request, mNextCSeq);
531
532    CHECK_EQ(sessionID, mClientSessionID);
533    request.append(
534            StringPrintf("Session: %d\r\n", mClientInfo.mPlaybackSessionID));
535    request.append("\r\n");  // Empty body
536
537    status_t err =
538        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
539
540    if (err != OK) {
541        return err;
542    }
543
544    registerResponseHandler(
545            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM16Response);
546
547    ++mNextCSeq;
548
549    return OK;
550}
551
552status_t WifiDisplaySource::onReceiveM1Response(
553        int32_t sessionID, const sp<ParsedMessage> &msg) {
554    int32_t statusCode;
555    if (!msg->getStatusCode(&statusCode)) {
556        return ERROR_MALFORMED;
557    }
558
559    if (statusCode != 200) {
560        return ERROR_UNSUPPORTED;
561    }
562
563    return OK;
564}
565
566status_t WifiDisplaySource::onReceiveM3Response(
567        int32_t sessionID, const sp<ParsedMessage> &msg) {
568    int32_t statusCode;
569    if (!msg->getStatusCode(&statusCode)) {
570        return ERROR_MALFORMED;
571    }
572
573    if (statusCode != 200) {
574        return ERROR_UNSUPPORTED;
575    }
576
577    sp<Parameters> params =
578        Parameters::Parse(msg->getContent(), strlen(msg->getContent()));
579
580    if (params == NULL) {
581        return ERROR_MALFORMED;
582    }
583
584#if REQUIRE_HDCP
585    AString value;
586    if (!params->findParameter("wfd_content_protection", &value)) {
587        ALOGE("Sink doesn't appear to support content protection.");
588        return -EACCES;
589    }
590
591    if (value == "none") {
592        ALOGE("Sink does not support content protection.");
593        return -EACCES;
594    }
595
596    bool isHDCP2_0 = false;
597    if (value.startsWith("HDCP2.0 ")) {
598        isHDCP2_0 = true;
599    } else if (!value.startsWith("HDCP2.1 ")) {
600        return ERROR_MALFORMED;
601    }
602
603    int32_t hdcpPort;
604    if (!ParsedMessage::GetInt32Attribute(value.c_str() + 8, "port", &hdcpPort)
605            || hdcpPort < 1 || hdcpPort > 65535) {
606        return ERROR_MALFORMED;
607    }
608
609    mIsHDCP2_0 = isHDCP2_0;
610    mHDCPPort = hdcpPort;
611
612    status_t err = makeHDCP();
613    if (err != OK) {
614        ALOGE("Unable to instantiate HDCP component.");
615        return err;
616    }
617#endif
618
619    return sendM4(sessionID);
620}
621
622status_t WifiDisplaySource::onReceiveM4Response(
623        int32_t sessionID, const sp<ParsedMessage> &msg) {
624    int32_t statusCode;
625    if (!msg->getStatusCode(&statusCode)) {
626        return ERROR_MALFORMED;
627    }
628
629    if (statusCode != 200) {
630        return ERROR_UNSUPPORTED;
631    }
632
633#if REQUIRE_HDCP
634    if (!mHDCPInitializationComplete) {
635        ALOGI("Deferring SETUP trigger until HDCP initialization completes.");
636
637        mSetupTriggerDeferred = true;
638        return OK;
639    }
640#endif
641
642    return sendM5(sessionID);
643}
644
645status_t WifiDisplaySource::onReceiveM5Response(
646        int32_t sessionID, const sp<ParsedMessage> &msg) {
647    int32_t statusCode;
648    if (!msg->getStatusCode(&statusCode)) {
649        return ERROR_MALFORMED;
650    }
651
652    if (statusCode != 200) {
653        return ERROR_UNSUPPORTED;
654    }
655
656    return OK;
657}
658
659status_t WifiDisplaySource::onReceiveM16Response(
660        int32_t sessionID, const sp<ParsedMessage> &msg) {
661    // If only the response was required to include a "Session:" header...
662
663    CHECK_EQ(sessionID, mClientSessionID);
664
665    if (mClientInfo.mPlaybackSession != NULL) {
666        mClientInfo.mPlaybackSession->updateLiveness();
667
668        scheduleKeepAlive(sessionID);
669    }
670
671    return OK;
672}
673
674void WifiDisplaySource::scheduleReaper() {
675    if (mReaperPending) {
676        return;
677    }
678
679    mReaperPending = true;
680    (new AMessage(kWhatReapDeadClients, id()))->post(kReaperIntervalUs);
681}
682
683void WifiDisplaySource::scheduleKeepAlive(int32_t sessionID) {
684    // We need to send updates at least 5 secs before the timeout is set to
685    // expire, make sure the timeout is greater than 5 secs to begin with.
686    CHECK_GT(kPlaybackSessionTimeoutUs, 5000000ll);
687
688    sp<AMessage> msg = new AMessage(kWhatKeepAlive, id());
689    msg->setInt32("sessionID", sessionID);
690    msg->post(kPlaybackSessionTimeoutUs - 5000000ll);
691}
692
693status_t WifiDisplaySource::onReceiveClientData(const sp<AMessage> &msg) {
694    int32_t sessionID;
695    CHECK(msg->findInt32("sessionID", &sessionID));
696
697    sp<RefBase> obj;
698    CHECK(msg->findObject("data", &obj));
699
700    sp<ParsedMessage> data =
701        static_cast<ParsedMessage *>(obj.get());
702
703    ALOGV("session %d received '%s'",
704          sessionID, data->debugString().c_str());
705
706    AString method;
707    AString uri;
708    data->getRequestField(0, &method);
709
710    int32_t cseq;
711    if (!data->findInt32("cseq", &cseq)) {
712        sendErrorResponse(sessionID, "400 Bad Request", -1 /* cseq */);
713        return ERROR_MALFORMED;
714    }
715
716    if (method.startsWith("RTSP/")) {
717        // This is a response.
718
719        ResponseID id;
720        id.mSessionID = sessionID;
721        id.mCSeq = cseq;
722
723        ssize_t index = mResponseHandlers.indexOfKey(id);
724
725        if (index < 0) {
726            ALOGW("Received unsolicited server response, cseq %d", cseq);
727            return ERROR_MALFORMED;
728        }
729
730        HandleRTSPResponseFunc func = mResponseHandlers.valueAt(index);
731        mResponseHandlers.removeItemsAt(index);
732
733        status_t err = (this->*func)(sessionID, data);
734
735        if (err != OK) {
736            ALOGW("Response handler for session %d, cseq %d returned "
737                  "err %d (%s)",
738                  sessionID, cseq, err, strerror(-err));
739
740            return err;
741        }
742
743        return OK;
744    }
745
746    AString version;
747    data->getRequestField(2, &version);
748    if (!(version == AString("RTSP/1.0"))) {
749        sendErrorResponse(sessionID, "505 RTSP Version not supported", cseq);
750        return ERROR_UNSUPPORTED;
751    }
752
753    status_t err;
754    if (method == "OPTIONS") {
755        err = onOptionsRequest(sessionID, cseq, data);
756    } else if (method == "SETUP") {
757        err = onSetupRequest(sessionID, cseq, data);
758    } else if (method == "PLAY") {
759        err = onPlayRequest(sessionID, cseq, data);
760    } else if (method == "PAUSE") {
761        err = onPauseRequest(sessionID, cseq, data);
762    } else if (method == "TEARDOWN") {
763        err = onTeardownRequest(sessionID, cseq, data);
764    } else if (method == "GET_PARAMETER") {
765        err = onGetParameterRequest(sessionID, cseq, data);
766    } else if (method == "SET_PARAMETER") {
767        err = onSetParameterRequest(sessionID, cseq, data);
768    } else {
769        sendErrorResponse(sessionID, "405 Method Not Allowed", cseq);
770
771        err = ERROR_UNSUPPORTED;
772    }
773
774    return err;
775}
776
777status_t WifiDisplaySource::onOptionsRequest(
778        int32_t sessionID,
779        int32_t cseq,
780        const sp<ParsedMessage> &data) {
781    int32_t playbackSessionID;
782    sp<PlaybackSession> playbackSession =
783        findPlaybackSession(data, &playbackSessionID);
784
785    if (playbackSession != NULL) {
786        playbackSession->updateLiveness();
787    }
788
789    AString response = "RTSP/1.0 200 OK\r\n";
790    AppendCommonResponse(&response, cseq);
791
792    response.append(
793            "Public: org.wfa.wfd1.0, SETUP, TEARDOWN, PLAY, PAUSE, "
794            "GET_PARAMETER, SET_PARAMETER\r\n");
795
796    response.append("\r\n");
797
798    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
799
800    if (err == OK) {
801        err = sendM3(sessionID);
802    }
803
804    return err;
805}
806
807status_t WifiDisplaySource::onSetupRequest(
808        int32_t sessionID,
809        int32_t cseq,
810        const sp<ParsedMessage> &data) {
811    CHECK_EQ(sessionID, mClientSessionID);
812    if (mClientInfo.mPlaybackSessionID != -1) {
813        // We only support a single playback session per client.
814        // This is due to the reversed keep-alive design in the wfd specs...
815        sendErrorResponse(sessionID, "400 Bad Request", cseq);
816        return ERROR_MALFORMED;
817    }
818
819    AString transport;
820    if (!data->findString("transport", &transport)) {
821        sendErrorResponse(sessionID, "400 Bad Request", cseq);
822        return ERROR_MALFORMED;
823    }
824
825    PlaybackSession::TransportMode transportMode =
826        PlaybackSession::TRANSPORT_UDP;
827
828    int clientRtp, clientRtcp;
829    if (transport.startsWith("RTP/AVP/TCP;")) {
830        AString interleaved;
831        if (ParsedMessage::GetAttribute(
832                    transport.c_str(), "interleaved", &interleaved)
833                && sscanf(interleaved.c_str(), "%d-%d",
834                          &clientRtp, &clientRtcp) == 2) {
835            transportMode = PlaybackSession::TRANSPORT_TCP_INTERLEAVED;
836        } else {
837            bool badRequest = false;
838
839            AString clientPort;
840            if (!ParsedMessage::GetAttribute(
841                        transport.c_str(), "client_port", &clientPort)) {
842                badRequest = true;
843            } else if (sscanf(clientPort.c_str(), "%d-%d",
844                              &clientRtp, &clientRtcp) == 2) {
845            } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
846                // No RTCP.
847                clientRtcp = -1;
848            } else {
849                badRequest = true;
850            }
851
852            if (badRequest) {
853                sendErrorResponse(sessionID, "400 Bad Request", cseq);
854                return ERROR_MALFORMED;
855            }
856
857            transportMode = PlaybackSession::TRANSPORT_TCP;
858        }
859    } else if (transport.startsWith("RTP/AVP;unicast;")
860            || transport.startsWith("RTP/AVP/UDP;unicast;")) {
861        bool badRequest = false;
862
863        AString clientPort;
864        if (!ParsedMessage::GetAttribute(
865                    transport.c_str(), "client_port", &clientPort)) {
866            badRequest = true;
867        } else if (sscanf(clientPort.c_str(), "%d-%d",
868                          &clientRtp, &clientRtcp) == 2) {
869        } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
870            // No RTCP.
871            clientRtcp = -1;
872            clientRtcp = clientRtp + 1;  // XXX
873        } else {
874            badRequest = true;
875        }
876
877        if (badRequest) {
878            sendErrorResponse(sessionID, "400 Bad Request", cseq);
879            return ERROR_MALFORMED;
880        }
881#if 1
882    // The older LG dongles doesn't specify client_port=xxx apparently.
883    } else if (transport == "RTP/AVP/UDP;unicast") {
884        clientRtp = 19000;
885        clientRtcp = clientRtp + 1;
886#endif
887    } else {
888        sendErrorResponse(sessionID, "461 Unsupported Transport", cseq);
889        return ERROR_UNSUPPORTED;
890    }
891
892    int32_t playbackSessionID = makeUniquePlaybackSessionID();
893
894    sp<AMessage> notify = new AMessage(kWhatPlaybackSessionNotify, id());
895    notify->setInt32("playbackSessionID", playbackSessionID);
896    notify->setInt32("sessionID", sessionID);
897
898    sp<PlaybackSession> playbackSession =
899        new PlaybackSession(
900                mNetSession, notify, mInterfaceAddr,
901                mClient == NULL,  /* legacyMode */
902#if REQUIRE_HDCP
903                mHDCP
904#else
905                NULL
906#endif
907                );
908
909    looper()->registerHandler(playbackSession);
910
911    AString uri;
912    data->getRequestField(1, &uri);
913
914    if (strncasecmp("rtsp://", uri.c_str(), 7)) {
915        sendErrorResponse(sessionID, "400 Bad Request", cseq);
916        return ERROR_MALFORMED;
917    }
918
919    if (!(uri.startsWith("rtsp://") && uri.endsWith("/wfd1.0/streamid=0"))) {
920        sendErrorResponse(sessionID, "404 Not found", cseq);
921        return ERROR_MALFORMED;
922    }
923
924    status_t err = playbackSession->init(
925            mClientInfo.mRemoteIP.c_str(),
926            clientRtp,
927            clientRtcp,
928            transportMode);
929
930    if (err != OK) {
931        looper()->unregisterHandler(playbackSession->id());
932        playbackSession.clear();
933    }
934
935    switch (err) {
936        case OK:
937            break;
938        case -ENOENT:
939            sendErrorResponse(sessionID, "404 Not Found", cseq);
940            return err;
941        default:
942            sendErrorResponse(sessionID, "403 Forbidden", cseq);
943            return err;
944    }
945
946    mClientInfo.mPlaybackSessionID = playbackSessionID;
947    mClientInfo.mPlaybackSession = playbackSession;
948
949    AString response = "RTSP/1.0 200 OK\r\n";
950    AppendCommonResponse(&response, cseq, playbackSessionID);
951
952    if (transportMode == PlaybackSession::TRANSPORT_TCP_INTERLEAVED) {
953        response.append(
954                StringPrintf(
955                    "Transport: RTP/AVP/TCP;interleaved=%d-%d;",
956                    clientRtp, clientRtcp));
957    } else {
958        int32_t serverRtp = playbackSession->getRTPPort();
959
960        AString transportString = "UDP";
961        if (transportMode == PlaybackSession::TRANSPORT_TCP) {
962            transportString = "TCP";
963        }
964
965        if (clientRtcp >= 0) {
966            response.append(
967                    StringPrintf(
968                        "Transport: RTP/AVP/%s;unicast;client_port=%d-%d;"
969                        "server_port=%d-%d\r\n",
970                        transportString.c_str(),
971                        clientRtp, clientRtcp, serverRtp, serverRtp + 1));
972        } else {
973            response.append(
974                    StringPrintf(
975                        "Transport: RTP/AVP/%s;unicast;client_port=%d;"
976                        "server_port=%d\r\n",
977                        transportString.c_str(),
978                        clientRtp, serverRtp));
979        }
980    }
981
982    response.append("\r\n");
983
984    err = mNetSession->sendRequest(sessionID, response.c_str());
985
986    if (err != OK) {
987        return err;
988    }
989
990    scheduleReaper();
991    scheduleKeepAlive(sessionID);
992
993    return OK;
994}
995
996status_t WifiDisplaySource::onPlayRequest(
997        int32_t sessionID,
998        int32_t cseq,
999        const sp<ParsedMessage> &data) {
1000    int32_t playbackSessionID;
1001    sp<PlaybackSession> playbackSession =
1002        findPlaybackSession(data, &playbackSessionID);
1003
1004    if (playbackSession == NULL) {
1005        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
1006        return ERROR_MALFORMED;
1007    }
1008
1009    status_t err = playbackSession->play();
1010    CHECK_EQ(err, (status_t)OK);
1011
1012    AString response = "RTSP/1.0 200 OK\r\n";
1013    AppendCommonResponse(&response, cseq, playbackSessionID);
1014    response.append("Range: npt=now-\r\n");
1015    response.append("\r\n");
1016
1017    err = mNetSession->sendRequest(sessionID, response.c_str());
1018
1019    if (err != OK) {
1020        return err;
1021    }
1022
1023    playbackSession->finishPlay();
1024
1025    return OK;
1026}
1027
1028status_t WifiDisplaySource::onPauseRequest(
1029        int32_t sessionID,
1030        int32_t cseq,
1031        const sp<ParsedMessage> &data) {
1032    int32_t playbackSessionID;
1033    sp<PlaybackSession> playbackSession =
1034        findPlaybackSession(data, &playbackSessionID);
1035
1036    if (playbackSession == NULL) {
1037        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
1038        return ERROR_MALFORMED;
1039    }
1040
1041    status_t err = playbackSession->pause();
1042    CHECK_EQ(err, (status_t)OK);
1043
1044    AString response = "RTSP/1.0 200 OK\r\n";
1045    AppendCommonResponse(&response, cseq, playbackSessionID);
1046    response.append("\r\n");
1047
1048    err = mNetSession->sendRequest(sessionID, response.c_str());
1049
1050    return err;
1051}
1052
1053status_t WifiDisplaySource::onTeardownRequest(
1054        int32_t sessionID,
1055        int32_t cseq,
1056        const sp<ParsedMessage> &data) {
1057    int32_t playbackSessionID;
1058    sp<PlaybackSession> playbackSession =
1059        findPlaybackSession(data, &playbackSessionID);
1060
1061    if (playbackSession == NULL) {
1062        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
1063        return ERROR_MALFORMED;
1064    }
1065
1066    AString response = "RTSP/1.0 200 OK\r\n";
1067    AppendCommonResponse(&response, cseq, playbackSessionID);
1068    response.append("Connection: close\r\n");
1069    response.append("\r\n");
1070
1071    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
1072
1073    if (err != OK) {
1074        return err;
1075    }
1076
1077    disconnectClient(UNKNOWN_ERROR);
1078
1079    return OK;
1080}
1081
1082status_t WifiDisplaySource::onGetParameterRequest(
1083        int32_t sessionID,
1084        int32_t cseq,
1085        const sp<ParsedMessage> &data) {
1086    int32_t playbackSessionID;
1087    sp<PlaybackSession> playbackSession =
1088        findPlaybackSession(data, &playbackSessionID);
1089
1090    if (playbackSession == NULL) {
1091        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
1092        return ERROR_MALFORMED;
1093    }
1094
1095    playbackSession->updateLiveness();
1096
1097    AString response = "RTSP/1.0 200 OK\r\n";
1098    AppendCommonResponse(&response, cseq, playbackSessionID);
1099    response.append("\r\n");
1100
1101    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
1102    return err;
1103}
1104
1105status_t WifiDisplaySource::onSetParameterRequest(
1106        int32_t sessionID,
1107        int32_t cseq,
1108        const sp<ParsedMessage> &data) {
1109    int32_t playbackSessionID;
1110    sp<PlaybackSession> playbackSession =
1111        findPlaybackSession(data, &playbackSessionID);
1112
1113    if (playbackSession == NULL) {
1114        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
1115        return ERROR_MALFORMED;
1116    }
1117
1118    if (strstr(data->getContent(), "wfd_idr_request\r\n")) {
1119        playbackSession->requestIDRFrame();
1120    }
1121
1122    playbackSession->updateLiveness();
1123
1124    AString response = "RTSP/1.0 200 OK\r\n";
1125    AppendCommonResponse(&response, cseq, playbackSessionID);
1126    response.append("\r\n");
1127
1128    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
1129    return err;
1130}
1131
1132// static
1133void WifiDisplaySource::AppendCommonResponse(
1134        AString *response, int32_t cseq, int32_t playbackSessionID) {
1135    time_t now = time(NULL);
1136    struct tm *now2 = gmtime(&now);
1137    char buf[128];
1138    strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", now2);
1139
1140    response->append("Date: ");
1141    response->append(buf);
1142    response->append("\r\n");
1143
1144    response->append("Server: Mine/1.0\r\n");
1145
1146    if (cseq >= 0) {
1147        response->append(StringPrintf("CSeq: %d\r\n", cseq));
1148    }
1149
1150    if (playbackSessionID >= 0ll) {
1151        response->append(
1152                StringPrintf(
1153                    "Session: %d;timeout=%lld\r\n",
1154                    playbackSessionID, kPlaybackSessionTimeoutSecs));
1155    }
1156}
1157
1158void WifiDisplaySource::sendErrorResponse(
1159        int32_t sessionID,
1160        const char *errorDetail,
1161        int32_t cseq) {
1162    AString response;
1163    response.append("RTSP/1.0 ");
1164    response.append(errorDetail);
1165    response.append("\r\n");
1166
1167    AppendCommonResponse(&response, cseq);
1168
1169    response.append("\r\n");
1170
1171    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
1172    CHECK_EQ(err, (status_t)OK);
1173}
1174
1175int32_t WifiDisplaySource::makeUniquePlaybackSessionID() const {
1176    return rand();
1177}
1178
1179sp<WifiDisplaySource::PlaybackSession> WifiDisplaySource::findPlaybackSession(
1180        const sp<ParsedMessage> &data, int32_t *playbackSessionID) const {
1181    if (!data->findInt32("session", playbackSessionID)) {
1182        // XXX the older dongles do not always include a "Session:" header.
1183        *playbackSessionID = mClientInfo.mPlaybackSessionID;
1184        return mClientInfo.mPlaybackSession;
1185    }
1186
1187    if (*playbackSessionID != mClientInfo.mPlaybackSessionID) {
1188        return NULL;
1189    }
1190
1191    return mClientInfo.mPlaybackSession;
1192}
1193
1194void WifiDisplaySource::disconnectClient(status_t err) {
1195    if (mClientSessionID != 0) {
1196        if (mClientInfo.mPlaybackSession != NULL) {
1197            looper()->unregisterHandler(mClientInfo.mPlaybackSession->id());
1198            mClientInfo.mPlaybackSession.clear();
1199        }
1200
1201        mNetSession->destroySession(mClientSessionID);
1202        mClientSessionID = 0;
1203    }
1204
1205    if (mClient != NULL) {
1206        if (err != OK) {
1207            mClient->onDisplayError(IRemoteDisplayClient::kDisplayErrorUnknown);
1208        } else {
1209            mClient->onDisplayDisconnected();
1210        }
1211    }
1212}
1213
1214#if REQUIRE_HDCP
1215struct WifiDisplaySource::HDCPObserver : public BnHDCPObserver {
1216    HDCPObserver(const sp<AMessage> &notify);
1217
1218    virtual void notify(
1219            int msg, int ext1, int ext2, const Parcel *obj);
1220
1221private:
1222    sp<AMessage> mNotify;
1223
1224    DISALLOW_EVIL_CONSTRUCTORS(HDCPObserver);
1225};
1226
1227WifiDisplaySource::HDCPObserver::HDCPObserver(
1228        const sp<AMessage> &notify)
1229    : mNotify(notify) {
1230}
1231
1232void WifiDisplaySource::HDCPObserver::notify(
1233        int msg, int ext1, int ext2, const Parcel *obj) {
1234    sp<AMessage> notify = mNotify->dup();
1235    notify->setInt32("msg", msg);
1236    notify->setInt32("ext1", ext1);
1237    notify->setInt32("ext2", ext2);
1238    notify->post();
1239}
1240
1241status_t WifiDisplaySource::makeHDCP() {
1242    sp<IServiceManager> sm = defaultServiceManager();
1243    sp<IBinder> binder = sm->getService(String16("media.player"));
1244    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
1245    CHECK(service != NULL);
1246
1247    mHDCP = service->makeHDCP();
1248
1249    if (mHDCP == NULL) {
1250        return ERROR_UNSUPPORTED;
1251    }
1252
1253    sp<AMessage> notify = new AMessage(kWhatHDCPNotify, id());
1254    mHDCPObserver = new HDCPObserver(notify);
1255
1256    status_t err = mHDCP->setObserver(mHDCPObserver);
1257
1258    if (err != OK) {
1259        ALOGE("Failed to set HDCP observer.");
1260
1261        mHDCPObserver.clear();
1262        mHDCP.clear();
1263
1264        return err;
1265    }
1266
1267    ALOGI("initiating HDCP negotiation w/ host %s:%d",
1268            mClientInfo.mRemoteIP.c_str(), mHDCPPort);
1269
1270    err = mHDCP->initAsync(mClientInfo.mRemoteIP.c_str(), mHDCPPort);
1271
1272    if (err != OK) {
1273        return err;
1274    }
1275
1276    return OK;
1277}
1278#endif
1279
1280}  // namespace android
1281
1282