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