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