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