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