WifiDisplaySink.cpp revision fbe9d81ff5fbdc5aecdcdd13e4a5d7f019824f96
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 "WifiDisplaySink"
19#include <utils/Log.h>
20
21#include "WifiDisplaySink.h"
22#include "ParsedMessage.h"
23#include "RTPSink.h"
24
25#include <media/stagefright/foundation/ABuffer.h>
26#include <media/stagefright/foundation/ADebug.h>
27#include <media/stagefright/foundation/AMessage.h>
28#include <media/stagefright/MediaErrors.h>
29
30namespace android {
31
32WifiDisplaySink::WifiDisplaySink(
33        const sp<ANetworkSession> &netSession,
34        const sp<ISurfaceTexture> &surfaceTex)
35    : mState(UNDEFINED),
36      mNetSession(netSession),
37      mSurfaceTex(surfaceTex),
38      mSessionID(0),
39      mNextCSeq(1) {
40}
41
42WifiDisplaySink::~WifiDisplaySink() {
43}
44
45void WifiDisplaySink::start(const char *sourceHost, int32_t sourcePort) {
46    sp<AMessage> msg = new AMessage(kWhatStart, id());
47    msg->setString("sourceHost", sourceHost);
48    msg->setInt32("sourcePort", sourcePort);
49    msg->post();
50}
51
52void WifiDisplaySink::start(const char *uri) {
53    sp<AMessage> msg = new AMessage(kWhatStart, id());
54    msg->setString("setupURI", uri);
55    msg->post();
56}
57
58// static
59bool WifiDisplaySink::ParseURL(
60        const char *url, AString *host, int32_t *port, AString *path,
61        AString *user, AString *pass) {
62    host->clear();
63    *port = 0;
64    path->clear();
65    user->clear();
66    pass->clear();
67
68    if (strncasecmp("rtsp://", url, 7)) {
69        return false;
70    }
71
72    const char *slashPos = strchr(&url[7], '/');
73
74    if (slashPos == NULL) {
75        host->setTo(&url[7]);
76        path->setTo("/");
77    } else {
78        host->setTo(&url[7], slashPos - &url[7]);
79        path->setTo(slashPos);
80    }
81
82    ssize_t atPos = host->find("@");
83
84    if (atPos >= 0) {
85        // Split of user:pass@ from hostname.
86
87        AString userPass(*host, 0, atPos);
88        host->erase(0, atPos + 1);
89
90        ssize_t colonPos = userPass.find(":");
91
92        if (colonPos < 0) {
93            *user = userPass;
94        } else {
95            user->setTo(userPass, 0, colonPos);
96            pass->setTo(userPass, colonPos + 1, userPass.size() - colonPos - 1);
97        }
98    }
99
100    const char *colonPos = strchr(host->c_str(), ':');
101
102    if (colonPos != NULL) {
103        char *end;
104        unsigned long x = strtoul(colonPos + 1, &end, 10);
105
106        if (end == colonPos + 1 || *end != '\0' || x >= 65536) {
107            return false;
108        }
109
110        *port = x;
111
112        size_t colonOffset = colonPos - host->c_str();
113        size_t trailing = host->size() - colonOffset;
114        host->erase(colonOffset, trailing);
115    } else {
116        *port = 554;
117    }
118
119    return true;
120}
121
122void WifiDisplaySink::onMessageReceived(const sp<AMessage> &msg) {
123    switch (msg->what()) {
124        case kWhatStart:
125        {
126            int32_t sourcePort;
127
128            if (msg->findString("setupURI", &mSetupURI)) {
129                AString path, user, pass;
130                CHECK(ParseURL(
131                            mSetupURI.c_str(),
132                            &mRTSPHost, &sourcePort, &path, &user, &pass)
133                        && user.empty() && pass.empty());
134            } else {
135                CHECK(msg->findString("sourceHost", &mRTSPHost));
136                CHECK(msg->findInt32("sourcePort", &sourcePort));
137            }
138
139            sp<AMessage> notify = new AMessage(kWhatRTSPNotify, id());
140
141            status_t err = mNetSession->createRTSPClient(
142                    mRTSPHost.c_str(), sourcePort, notify, &mSessionID);
143            CHECK_EQ(err, (status_t)OK);
144
145            mState = CONNECTING;
146            break;
147        }
148
149        case kWhatRTSPNotify:
150        {
151            int32_t reason;
152            CHECK(msg->findInt32("reason", &reason));
153
154            switch (reason) {
155                case ANetworkSession::kWhatError:
156                {
157                    int32_t sessionID;
158                    CHECK(msg->findInt32("sessionID", &sessionID));
159
160                    int32_t err;
161                    CHECK(msg->findInt32("err", &err));
162
163                    AString detail;
164                    CHECK(msg->findString("detail", &detail));
165
166                    ALOGE("An error occurred in session %d (%d, '%s/%s').",
167                          sessionID,
168                          err,
169                          detail.c_str(),
170                          strerror(-err));
171
172                    if (sessionID == mSessionID) {
173                        ALOGI("Lost control connection.");
174
175                        // The control connection is dead now.
176                        mNetSession->destroySession(mSessionID);
177                        mSessionID = 0;
178
179                        looper()->stop();
180                    }
181                    break;
182                }
183
184                case ANetworkSession::kWhatConnected:
185                {
186                    ALOGI("We're now connected.");
187                    mState = CONNECTED;
188
189                    if (!mSetupURI.empty()) {
190                        status_t err =
191                            sendDescribe(mSessionID, mSetupURI.c_str());
192
193                        CHECK_EQ(err, (status_t)OK);
194                    }
195                    break;
196                }
197
198                case ANetworkSession::kWhatData:
199                {
200                    onReceiveClientData(msg);
201                    break;
202                }
203
204                case ANetworkSession::kWhatBinaryData:
205                {
206                    CHECK(sUseTCPInterleaving);
207
208                    int32_t channel;
209                    CHECK(msg->findInt32("channel", &channel));
210
211                    sp<ABuffer> data;
212                    CHECK(msg->findBuffer("data", &data));
213
214                    mRTPSink->injectPacket(channel == 0 /* isRTP */, data);
215                    break;
216                }
217
218                default:
219                    TRESPASS();
220            }
221            break;
222        }
223
224        case kWhatStop:
225        {
226            looper()->stop();
227            break;
228        }
229
230        default:
231            TRESPASS();
232    }
233}
234
235void WifiDisplaySink::registerResponseHandler(
236        int32_t sessionID, int32_t cseq, HandleRTSPResponseFunc func) {
237    ResponseID id;
238    id.mSessionID = sessionID;
239    id.mCSeq = cseq;
240    mResponseHandlers.add(id, func);
241}
242
243status_t WifiDisplaySink::sendM2(int32_t sessionID) {
244    AString request = "OPTIONS * RTSP/1.0\r\n";
245    AppendCommonResponse(&request, mNextCSeq);
246
247    request.append(
248            "Require: org.wfa.wfd1.0\r\n"
249            "\r\n");
250
251    status_t err =
252        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
253
254    if (err != OK) {
255        return err;
256    }
257
258    registerResponseHandler(
259            sessionID, mNextCSeq, &WifiDisplaySink::onReceiveM2Response);
260
261    ++mNextCSeq;
262
263    return OK;
264}
265
266status_t WifiDisplaySink::onReceiveM2Response(
267        int32_t sessionID, const sp<ParsedMessage> &msg) {
268    int32_t statusCode;
269    if (!msg->getStatusCode(&statusCode)) {
270        return ERROR_MALFORMED;
271    }
272
273    if (statusCode != 200) {
274        return ERROR_UNSUPPORTED;
275    }
276
277    return OK;
278}
279
280status_t WifiDisplaySink::onReceiveDescribeResponse(
281        int32_t sessionID, const sp<ParsedMessage> &msg) {
282    int32_t statusCode;
283    if (!msg->getStatusCode(&statusCode)) {
284        return ERROR_MALFORMED;
285    }
286
287    if (statusCode != 200) {
288        return ERROR_UNSUPPORTED;
289    }
290
291    return sendSetup(sessionID, mSetupURI.c_str());
292}
293
294status_t WifiDisplaySink::onReceiveSetupResponse(
295        int32_t sessionID, const sp<ParsedMessage> &msg) {
296    int32_t statusCode;
297    if (!msg->getStatusCode(&statusCode)) {
298        return ERROR_MALFORMED;
299    }
300
301    if (statusCode != 200) {
302        return ERROR_UNSUPPORTED;
303    }
304
305    if (!msg->findString("session", &mPlaybackSessionID)) {
306        return ERROR_MALFORMED;
307    }
308
309    if (!ParsedMessage::GetInt32Attribute(
310                mPlaybackSessionID.c_str(),
311                "timeout",
312                &mPlaybackSessionTimeoutSecs)) {
313        mPlaybackSessionTimeoutSecs = -1;
314    }
315
316    ssize_t colonPos = mPlaybackSessionID.find(";");
317    if (colonPos >= 0) {
318        // Strip any options from the returned session id.
319        mPlaybackSessionID.erase(
320                colonPos, mPlaybackSessionID.size() - colonPos);
321    }
322
323    status_t err = configureTransport(msg);
324
325    if (err != OK) {
326        return err;
327    }
328
329    mState = PAUSED;
330
331    return sendPlay(
332            sessionID,
333            !mSetupURI.empty()
334                ? mSetupURI.c_str() : "rtsp://x.x.x.x:x/wfd1.0/streamid=0");
335}
336
337status_t WifiDisplaySink::configureTransport(const sp<ParsedMessage> &msg) {
338    if (sUseTCPInterleaving) {
339        return OK;
340    }
341
342    AString transport;
343    if (!msg->findString("transport", &transport)) {
344        ALOGE("Missing 'transport' field in SETUP response.");
345        return ERROR_MALFORMED;
346    }
347
348    AString sourceHost;
349    if (!ParsedMessage::GetAttribute(
350                transport.c_str(), "source", &sourceHost)) {
351        sourceHost = mRTSPHost;
352    }
353
354    AString serverPortStr;
355    if (!ParsedMessage::GetAttribute(
356                transport.c_str(), "server_port", &serverPortStr)) {
357        ALOGE("Missing 'server_port' in Transport field.");
358        return ERROR_MALFORMED;
359    }
360
361    int rtpPort, rtcpPort;
362    if (sscanf(serverPortStr.c_str(), "%d-%d", &rtpPort, &rtcpPort) != 2
363            || rtpPort <= 0 || rtpPort > 65535
364            || rtcpPort <=0 || rtcpPort > 65535
365            || rtcpPort != rtpPort + 1) {
366        ALOGE("Invalid server_port description '%s'.",
367                serverPortStr.c_str());
368
369        return ERROR_MALFORMED;
370    }
371
372    if (rtpPort & 1) {
373        ALOGW("Server picked an odd numbered RTP port.");
374    }
375
376    return mRTPSink->connect(sourceHost.c_str(), rtpPort, rtcpPort);
377}
378
379status_t WifiDisplaySink::onReceivePlayResponse(
380        int32_t sessionID, const sp<ParsedMessage> &msg) {
381    int32_t statusCode;
382    if (!msg->getStatusCode(&statusCode)) {
383        return ERROR_MALFORMED;
384    }
385
386    if (statusCode != 200) {
387        return ERROR_UNSUPPORTED;
388    }
389
390    mState = PLAYING;
391
392    return OK;
393}
394
395void WifiDisplaySink::onReceiveClientData(const sp<AMessage> &msg) {
396    int32_t sessionID;
397    CHECK(msg->findInt32("sessionID", &sessionID));
398
399    sp<RefBase> obj;
400    CHECK(msg->findObject("data", &obj));
401
402    sp<ParsedMessage> data =
403        static_cast<ParsedMessage *>(obj.get());
404
405    ALOGV("session %d received '%s'",
406          sessionID, data->debugString().c_str());
407
408    AString method;
409    AString uri;
410    data->getRequestField(0, &method);
411
412    int32_t cseq;
413    if (!data->findInt32("cseq", &cseq)) {
414        sendErrorResponse(sessionID, "400 Bad Request", -1 /* cseq */);
415        return;
416    }
417
418    if (method.startsWith("RTSP/")) {
419        // This is a response.
420
421        ResponseID id;
422        id.mSessionID = sessionID;
423        id.mCSeq = cseq;
424
425        ssize_t index = mResponseHandlers.indexOfKey(id);
426
427        if (index < 0) {
428            ALOGW("Received unsolicited server response, cseq %d", cseq);
429            return;
430        }
431
432        HandleRTSPResponseFunc func = mResponseHandlers.valueAt(index);
433        mResponseHandlers.removeItemsAt(index);
434
435        status_t err = (this->*func)(sessionID, data);
436        CHECK_EQ(err, (status_t)OK);
437    } else {
438        AString version;
439        data->getRequestField(2, &version);
440        if (!(version == AString("RTSP/1.0"))) {
441            sendErrorResponse(sessionID, "505 RTSP Version not supported", cseq);
442            return;
443        }
444
445        if (method == "OPTIONS") {
446            onOptionsRequest(sessionID, cseq, data);
447        } else if (method == "GET_PARAMETER") {
448            onGetParameterRequest(sessionID, cseq, data);
449        } else if (method == "SET_PARAMETER") {
450            onSetParameterRequest(sessionID, cseq, data);
451        } else {
452            sendErrorResponse(sessionID, "405 Method Not Allowed", cseq);
453        }
454    }
455}
456
457void WifiDisplaySink::onOptionsRequest(
458        int32_t sessionID,
459        int32_t cseq,
460        const sp<ParsedMessage> &data) {
461    AString response = "RTSP/1.0 200 OK\r\n";
462    AppendCommonResponse(&response, cseq);
463    response.append("Public: org.wfa.wfd1.0, GET_PARAMETER, SET_PARAMETER\r\n");
464    response.append("\r\n");
465
466    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
467    CHECK_EQ(err, (status_t)OK);
468
469    err = sendM2(sessionID);
470    CHECK_EQ(err, (status_t)OK);
471}
472
473void WifiDisplaySink::onGetParameterRequest(
474        int32_t sessionID,
475        int32_t cseq,
476        const sp<ParsedMessage> &data) {
477    AString body =
478        "wfd_video_formats: xxx\r\n"
479        "wfd_audio_codecs: xxx\r\n"
480        "wfd_client_rtp_ports: RTP/AVP/UDP;unicast xxx 0 mode=play\r\n";
481
482    AString response = "RTSP/1.0 200 OK\r\n";
483    AppendCommonResponse(&response, cseq);
484    response.append("Content-Type: text/parameters\r\n");
485    response.append(StringPrintf("Content-Length: %d\r\n", body.size()));
486    response.append("\r\n");
487    response.append(body);
488
489    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
490    CHECK_EQ(err, (status_t)OK);
491}
492
493status_t WifiDisplaySink::sendDescribe(int32_t sessionID, const char *uri) {
494    uri = "rtsp://xwgntvx.is.livestream-api.com/livestreamiphone/wgntv";
495    uri = "rtsp://v2.cache6.c.youtube.com/video.3gp?cid=e101d4bf280055f9&fmt=18";
496
497    AString request = StringPrintf("DESCRIBE %s RTSP/1.0\r\n", uri);
498    AppendCommonResponse(&request, mNextCSeq);
499
500    request.append("Accept: application/sdp\r\n");
501    request.append("\r\n");
502
503    status_t err = mNetSession->sendRequest(
504            sessionID, request.c_str(), request.size());
505
506    if (err != OK) {
507        return err;
508    }
509
510    registerResponseHandler(
511            sessionID, mNextCSeq, &WifiDisplaySink::onReceiveDescribeResponse);
512
513    ++mNextCSeq;
514
515    return OK;
516}
517
518status_t WifiDisplaySink::sendSetup(int32_t sessionID, const char *uri) {
519    mRTPSink = new RTPSink(mNetSession, mSurfaceTex);
520    looper()->registerHandler(mRTPSink);
521
522    status_t err = mRTPSink->init(sUseTCPInterleaving);
523
524    if (err != OK) {
525        looper()->unregisterHandler(mRTPSink->id());
526        mRTPSink.clear();
527        return err;
528    }
529
530    AString request = StringPrintf("SETUP %s RTSP/1.0\r\n", uri);
531
532    AppendCommonResponse(&request, mNextCSeq);
533
534    if (sUseTCPInterleaving) {
535        request.append("Transport: RTP/AVP/TCP;interleaved=0-1\r\n");
536    } else {
537        int32_t rtpPort = mRTPSink->getRTPPort();
538
539        request.append(
540                StringPrintf(
541                    "Transport: RTP/AVP/UDP;unicast;client_port=%d-%d\r\n",
542                    rtpPort, rtpPort + 1));
543    }
544
545    request.append("\r\n");
546
547    ALOGV("request = '%s'", request.c_str());
548
549    err = mNetSession->sendRequest(sessionID, request.c_str(), request.size());
550
551    if (err != OK) {
552        return err;
553    }
554
555    registerResponseHandler(
556            sessionID, mNextCSeq, &WifiDisplaySink::onReceiveSetupResponse);
557
558    ++mNextCSeq;
559
560    return OK;
561}
562
563status_t WifiDisplaySink::sendPlay(int32_t sessionID, const char *uri) {
564    AString request = StringPrintf("PLAY %s RTSP/1.0\r\n", uri);
565
566    AppendCommonResponse(&request, mNextCSeq);
567
568    request.append(StringPrintf("Session: %s\r\n", mPlaybackSessionID.c_str()));
569    request.append("\r\n");
570
571    status_t err =
572        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
573
574    if (err != OK) {
575        return err;
576    }
577
578    registerResponseHandler(
579            sessionID, mNextCSeq, &WifiDisplaySink::onReceivePlayResponse);
580
581    ++mNextCSeq;
582
583    return OK;
584}
585
586void WifiDisplaySink::onSetParameterRequest(
587        int32_t sessionID,
588        int32_t cseq,
589        const sp<ParsedMessage> &data) {
590    const char *content = data->getContent();
591
592    if (strstr(content, "wfd_trigger_method: SETUP\r\n") != NULL) {
593        status_t err =
594            sendSetup(
595                    sessionID,
596                    "rtsp://x.x.x.x:x/wfd1.0/streamid=0");
597
598        CHECK_EQ(err, (status_t)OK);
599    }
600
601    AString response = "RTSP/1.0 200 OK\r\n";
602    AppendCommonResponse(&response, cseq);
603    response.append("\r\n");
604
605    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
606    CHECK_EQ(err, (status_t)OK);
607}
608
609void WifiDisplaySink::sendErrorResponse(
610        int32_t sessionID,
611        const char *errorDetail,
612        int32_t cseq) {
613    AString response;
614    response.append("RTSP/1.0 ");
615    response.append(errorDetail);
616    response.append("\r\n");
617
618    AppendCommonResponse(&response, cseq);
619
620    response.append("\r\n");
621
622    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
623    CHECK_EQ(err, (status_t)OK);
624}
625
626// static
627void WifiDisplaySink::AppendCommonResponse(AString *response, int32_t cseq) {
628    time_t now = time(NULL);
629    struct tm *now2 = gmtime(&now);
630    char buf[128];
631    strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", now2);
632
633    response->append("Date: ");
634    response->append(buf);
635    response->append("\r\n");
636
637    response->append("User-Agent: stagefright/1.1 (Linux;Android 4.1)\r\n");
638
639    if (cseq >= 0) {
640        response->append(StringPrintf("CSeq: %d\r\n", cseq));
641    }
642}
643
644}  // namespace android
645