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