WifiDisplaySource.cpp revision 126568c7aeeb5570789e70a310477f44dbdbd885
199e53b86eebb605b70dd7591b89bf61a9414ed0eGlenn Kasten/*
289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * Copyright 2012, The Android Open Source Project
389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project *
489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * you may not use this file except in compliance with the License.
689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * You may obtain a copy of the License at
789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project *
889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project *     http://www.apache.org/licenses/LICENSE-2.0
989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project *
1089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * See the License for the specific language governing permissions and
1489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project * limitations under the License.
1589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project */
1689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
1789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project//#define LOG_NDEBUG 0
1889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#define LOG_TAG "WifiDisplaySource"
1989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include <utils/Log.h>
2089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
2189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include "WifiDisplaySource.h"
2289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include "PlaybackSession.h"
2389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include "Parameters.h"
2489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include "ParsedMessage.h"
2589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include "rtp/RTPSender.h"
2689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include "TimeSyncer.h"
277562408b2261d38415453378b6188f74fda99d88Mathias Agopian
287562408b2261d38415453378b6188f74fda99d88Mathias Agopian#include <binder/IServiceManager.h>
2989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include <gui/IGraphicBufferProducer.h>
3061c7ef5bde2c7ed94a078396aa65da67b47e5402Jamie Gennis#include <media/IHDCP.h>
3161c7ef5bde2c7ed94a078396aa65da67b47e5402Jamie Gennis#include <media/IMediaPlayerService.h>
3289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include <media/IRemoteDisplayClient.h>
33a3f1fa308728976fc9ca1b4f37d26e633b32b9acGlenn Kasten#include <media/stagefright/foundation/ABuffer.h>
3489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include <media/stagefright/foundation/ADebug.h>
357562408b2261d38415453378b6188f74fda99d88Mathias Agopian#include <media/stagefright/foundation/AMessage.h>
3689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#include <media/stagefright/MediaErrors.h>
372db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber
382db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber#include <arpa/inet.h>
392db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber#include <cutils/properties.h>
4064760240f931714858a59c1579f07264d7182ba2Dima Zavin
4161c7ef5bde2c7ed94a078396aa65da67b47e5402Jamie Gennis#include <ctype.h>
42fce7a473248381cc83a01855f92581077d3c9ee2Dima Zavin
4389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectnamespace android {
4489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
4589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source ProjectWifiDisplaySource::WifiDisplaySource(
4689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        const sp<ANetworkSession> &netSession,
473856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        const sp<IRemoteDisplayClient> &client)
4889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    : mState(INITIALIZED),
4989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project      mNetSession(netSession),
50fce7a473248381cc83a01855f92581077d3c9ee2Dima Zavin      mClient(client),
5189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project      mSessionID(0),
5289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project      mStopReplyID(0),
5389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project      mChosenRTPPort(-1),
5489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project      mUsingPCMAudio(false),
5589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project      mClientSessionID(0),
5689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project      mReaperPending(false),
5789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project      mNextCSeq(1),
5889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project      mUsingHDCP(false),
591af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams      mIsHDCP2_0(false),
60a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent      mHDCPPort(0),
613a34befc6fb04a4945a849e8bda8b84e4bf973feMarco Nelissen      mHDCPInitializationComplete(false),
628c563ed9ca8a863a66965330b5d14bb4b4ab59d4Eric Laurent      mSetupTriggerDeferred(false) {
63c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    mSupportedSourceVideoFormats.disableAll();
6489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
6589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    mSupportedSourceVideoFormats.setNativeResolution(
6689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            VideoFormats::RESOLUTION_CEA, 5);  // 1280x720 p30
6789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
683856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
693a34befc6fb04a4945a849e8bda8b84e4bf973feMarco NelissenWifiDisplaySource::~WifiDisplaySource() {
7089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
7189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
7289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatic status_t PostAndAwaitResponse(
7389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        const sp<AMessage> &msg, sp<AMessage> *response) {
7489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    status_t err = msg->postAndAwaitResponse(response);
7589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
763856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    if (err != OK) {
7789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return err;
7889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
7989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
8089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (response == NULL || !(*response)->findInt32("err", &err)) {
8189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        err = OK;
8289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
8389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
8489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return err;
8589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
8689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
8789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t WifiDisplaySource::start(const char *iface) {
8889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    CHECK_EQ(mState, INITIALIZED);
8989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
9089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    sp<AMessage> msg = new AMessage(kWhatStart, id());
9189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    msg->setString("iface", iface);
9289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
9389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    sp<AMessage> response;
9489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return PostAndAwaitResponse(msg, &response);
95c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman}
9689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
9789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t WifiDisplaySource::stop() {
9889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    sp<AMessage> msg = new AMessage(kWhatStop, id());
9989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
1003856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    sp<AMessage> response;
10189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return PostAndAwaitResponse(msg, &response);
10289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
10389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
10489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t WifiDisplaySource::pause() {
10589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    sp<AMessage> msg = new AMessage(kWhatPause, id());
10689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
107d681bbb1767bed09415e050ba78975df214bcd68Dave Burke    sp<AMessage> response;
10889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return PostAndAwaitResponse(msg, &response);
10989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
11089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
11189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t WifiDisplaySource::resume() {
11289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    sp<AMessage> msg = new AMessage(kWhatResume, id());
11389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
11483ff1438d2d1d5dbf39ca5e6f2e4fa1799e7ba80Marco Nelissen    sp<AMessage> response;
11583ff1438d2d1d5dbf39ca5e6f2e4fa1799e7ba80Marco Nelissen    return PostAndAwaitResponse(msg, &response);
11629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block}
11789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
11889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectvoid WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) {
11989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    switch (msg->what()) {
12089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        case kWhatStart:
12189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        {
12289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            uint32_t replyID;
12389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            CHECK(msg->senderAwaitsResponse(&replyID));
12489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
12589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            AString iface;
12689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            CHECK(msg->findString("iface", &iface));
12729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block
12889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            status_t err = OK;
12989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
13089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            ssize_t colonPos = iface.find(":");
13189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
13289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            unsigned long port;
13389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
13489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            if (colonPos >= 0) {
13589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                const char *s = iface.c_str() + colonPos + 1;
13689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
13789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                char *end;
1382db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber                port = strtoul(s, &end, 10);
1392db8455d8f4468a637109d31f319ce02d9d743ecAndreas Huber
14089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                if (end == s || *end != '\0' || port > 65535) {
1413856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                    err = -EINVAL;
14289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                } else {
14389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    iface.erase(colonPos, iface.size() - colonPos);
14489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                }
14589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            } else {
146d681bbb1767bed09415e050ba78975df214bcd68Dave Burke                port = kWifiDisplayDefaultPort;
147c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman            }
148c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
1490662067b06658a4a56a8416c676f6cce8ccddb53Dave Burke            if (err == OK) {
150d681bbb1767bed09415e050ba78975df214bcd68Dave Burke                if (inet_aton(iface.c_str(), &mInterfaceAddr) != 0) {
1510662067b06658a4a56a8416c676f6cce8ccddb53Dave Burke                    sp<AMessage> notify = new AMessage(kWhatRTSPNotify, id());
15289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
15389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    err = mNetSession->createRTSPServer(
15489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                            mInterfaceAddr, port, notify, &mSessionID);
15589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                } else {
15689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    err = -EINVAL;
15789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                }
15889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            }
1593856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
16089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            if (err == OK) {
16189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                sp<AMessage> notify = new AMessage(kWhatTimeSyncerNotify, id());
16289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                mTimeSyncer = new TimeSyncer(mNetSession, notify);
163d681bbb1767bed09415e050ba78975df214bcd68Dave Burke                looper()->registerHandler(mTimeSyncer);
164c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
165c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman                mTimeSyncer->startServer(8123);
1660662067b06658a4a56a8416c676f6cce8ccddb53Dave Burke
167d681bbb1767bed09415e050ba78975df214bcd68Dave Burke                mState = AWAITING_CLIENT_CONNECTION;
1680662067b06658a4a56a8416c676f6cce8ccddb53Dave Burke            }
169d681bbb1767bed09415e050ba78975df214bcd68Dave Burke
170d681bbb1767bed09415e050ba78975df214bcd68Dave Burke            sp<AMessage> response = new AMessage;
171d681bbb1767bed09415e050ba78975df214bcd68Dave Burke            response->setInt32("err", err);
172d681bbb1767bed09415e050ba78975df214bcd68Dave Burke            response->postReply(replyID);
173d681bbb1767bed09415e050ba78975df214bcd68Dave Burke            break;
174d681bbb1767bed09415e050ba78975df214bcd68Dave Burke        }
1753856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
176d681bbb1767bed09415e050ba78975df214bcd68Dave Burke        case kWhatRTSPNotify:
177d681bbb1767bed09415e050ba78975df214bcd68Dave Burke        {
178d681bbb1767bed09415e050ba78975df214bcd68Dave Burke            int32_t reason;
179d681bbb1767bed09415e050ba78975df214bcd68Dave Burke            CHECK(msg->findInt32("reason", &reason));
180c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
181c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman            switch (reason) {
1820662067b06658a4a56a8416c676f6cce8ccddb53Dave Burke                case ANetworkSession::kWhatError:
183d681bbb1767bed09415e050ba78975df214bcd68Dave Burke                {
1840662067b06658a4a56a8416c676f6cce8ccddb53Dave Burke                    int32_t sessionID;
18589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    CHECK(msg->findInt32("sessionID", &sessionID));
18689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
18789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    int32_t err;
18889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    CHECK(msg->findInt32("err", &err));
1891d187f1a86855f5f0694d7ec30efc9833bf7c589Nicolas Catania
1901d187f1a86855f5f0694d7ec30efc9833bf7c589Nicolas Catania                    AString detail;
1911d187f1a86855f5f0694d7ec30efc9833bf7c589Nicolas Catania                    CHECK(msg->findString("detail", &detail));
1924023493a827bc9751d8e40795516d0d536a53348Nicolas Catania
1934023493a827bc9751d8e40795516d0d536a53348Nicolas Catania                    ALOGE("An error occurred in session %d (%d, '%s/%s').",
1944023493a827bc9751d8e40795516d0d536a53348Nicolas Catania                          sessionID,
1954023493a827bc9751d8e40795516d0d536a53348Nicolas Catania                          err,
196e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten                          detail.c_str(),
197e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten                          strerror(-err));
1981d187f1a86855f5f0694d7ec30efc9833bf7c589Nicolas Catania
19929357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                    mNetSession->destroySession(sessionID);
2001d187f1a86855f5f0694d7ec30efc9833bf7c589Nicolas Catania
2011d187f1a86855f5f0694d7ec30efc9833bf7c589Nicolas Catania                    if (sessionID == mClientSessionID) {
2021d187f1a86855f5f0694d7ec30efc9833bf7c589Nicolas Catania                        mClientSessionID = 0;
203a7e0e8b4c429fc68eb1bd5b5a30f5b91352288f9Nicolas Catania
204a7e0e8b4c429fc68eb1bd5b5a30f5b91352288f9Nicolas Catania                        mClient->onDisplayError(
205b8a805261bf0282e992d3608035e47d05a898710Steve Block                                IRemoteDisplayClient::kDisplayErrorUnknown);
2068e1b6cce24574b9ecd5b0300155776bd0b4ef756Nicolas Catania                    }
2078e1b6cce24574b9ecd5b0300155776bd0b4ef756Nicolas Catania                    break;
208a7e0e8b4c429fc68eb1bd5b5a30f5b91352288f9Nicolas Catania                }
209a7e0e8b4c429fc68eb1bd5b5a30f5b91352288f9Nicolas Catania
210a7e0e8b4c429fc68eb1bd5b5a30f5b91352288f9Nicolas Catania                case ANetworkSession::kWhatClientConnected:
211a7e0e8b4c429fc68eb1bd5b5a30f5b91352288f9Nicolas Catania                {
2121d187f1a86855f5f0694d7ec30efc9833bf7c589Nicolas Catania                    int32_t sessionID;
2138e1b6cce24574b9ecd5b0300155776bd0b4ef756Nicolas Catania                    CHECK(msg->findInt32("sessionID", &sessionID));
2148e1b6cce24574b9ecd5b0300155776bd0b4ef756Nicolas Catania
215b8a805261bf0282e992d3608035e47d05a898710Steve Block                    if (mClientSessionID > 0) {
2168e1b6cce24574b9ecd5b0300155776bd0b4ef756Nicolas Catania                        ALOGW("A client tried to connect, but we already "
2178e1b6cce24574b9ecd5b0300155776bd0b4ef756Nicolas Catania                              "have one.");
2188e1b6cce24574b9ecd5b0300155776bd0b4ef756Nicolas Catania
2198e1b6cce24574b9ecd5b0300155776bd0b4ef756Nicolas Catania                        mNetSession->destroySession(sessionID);
2208e1b6cce24574b9ecd5b0300155776bd0b4ef756Nicolas Catania                        break;
2218e1b6cce24574b9ecd5b0300155776bd0b4ef756Nicolas Catania                    }
2228e1b6cce24574b9ecd5b0300155776bd0b4ef756Nicolas Catania
2231173118eace0e9e347cb007f0da817cee87579edGlenn Kasten                    CHECK_EQ(mState, AWAITING_CLIENT_CONNECTION);
2241173118eace0e9e347cb007f0da817cee87579edGlenn Kasten
2251173118eace0e9e347cb007f0da817cee87579edGlenn Kasten                    CHECK(msg->findString("client-ip", &mClientInfo.mRemoteIP));
2263856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                    CHECK(msg->findString("server-ip", &mClientInfo.mLocalIP));
2271173118eace0e9e347cb007f0da817cee87579edGlenn Kasten
2281173118eace0e9e347cb007f0da817cee87579edGlenn Kasten                    if (mClientInfo.mRemoteIP == mClientInfo.mLocalIP) {
2297dae00baa6e8957be15523c46bb948bd1dde64c3Jamie Gennis                        // Disallow connections from the local interface
2301173118eace0e9e347cb007f0da817cee87579edGlenn Kasten                        // for security reasons.
2311173118eace0e9e347cb007f0da817cee87579edGlenn Kasten                        mNetSession->destroySession(sessionID);
23289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                        break;
23389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    }
23489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
23589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    CHECK(msg->findInt32(
23689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                "server-port", &mClientInfo.mLocalPort));
23789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    mClientInfo.mPlaybackSessionID = -1;
23889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
23989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    mClientSessionID = sessionID;
24029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block
24189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    ALOGI("We now have a client (%d) connected.", sessionID);
24289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
24389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    mState = AWAITING_CLIENT_SETUP;
24465e731f393f704eedab6fbe0af7f8a580c8d4617The Android Open Source Project
24565e731f393f704eedab6fbe0af7f8a580c8d4617The Android Open Source Project                    status_t err = sendM1(sessionID);
24665e731f393f704eedab6fbe0af7f8a580c8d4617The Android Open Source Project                    CHECK_EQ(err, (status_t)OK);
24765e731f393f704eedab6fbe0af7f8a580c8d4617The Android Open Source Project                    break;
24889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                }
24989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
2503856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                case ANetworkSession::kWhatData:
25189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                {
2521af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams                    status_t err = onReceiveClientData(msg);
2531af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams
2541af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams                    if (err != OK) {
2551af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams                        mClient->onDisplayError(
2561af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams                                IRemoteDisplayClient::kDisplayErrorUnknown);
25789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    }
25889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
2591af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams#if 0
2601af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams                    // testing only.
2611af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams                    char val[PROPERTY_VALUE_MAX];
2621af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams                    if (property_get("media.wfd.trigger", val, NULL)) {
26389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                        if (!strcasecmp(val, "pause") && mState == PLAYING) {
26489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                            mState = PLAYING_TO_PAUSED;
26589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                            sendTrigger(mClientSessionID, TRIGGER_PAUSE);
26689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                        } else if (!strcasecmp(val, "play") && mState == PAUSED) {
26789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                            mState = PAUSED_TO_PLAYING;
2683856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                            sendTrigger(mClientSessionID, TRIGGER_PLAY);
2691af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams                        }
27089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    }
27189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project#endif
27289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    break;
27389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                }
27489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
2753856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                case ANetworkSession::kWhatNetworkStall:
27689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                {
27789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    break;
27889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                }
27989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
28089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                default:
28189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    TRESPASS();
2823856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            }
28389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            break;
28489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        }
28589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
28689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        case kWhatStop:
28789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        {
28889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            CHECK(msg->senderAwaitsResponse(&mStopReplyID));
28989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
2902beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent            CHECK_LT(mState, AWAITING_CLIENT_TEARDOWN);
29189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
29289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            if (mState >= AWAITING_CLIENT_PLAY) {
29389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                // We have a session, i.e. a previous SETUP succeeded.
29489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
29589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                status_t err = sendTrigger(
29689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                        mClientSessionID, TRIGGER_TEARDOWN);
2973856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
29889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                if (err == OK) {
29989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    mState = AWAITING_CLIENT_TEARDOWN;
30089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
30189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    (new AMessage(kWhatTeardownTriggerTimedOut, id()))->post(
30229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                            kTeardownTriggerTimeouSecs * 1000000ll);
30389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
30489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    break;
30589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                }
30689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
30789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                // fall through.
3083856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            }
30989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
31089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            finishStop();
31189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            break;
31289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        }
31389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
31489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        case kWhatPause:
31589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        {
31689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            uint32_t replyID;
31789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            CHECK(msg->senderAwaitsResponse(&replyID));
31889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
31989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            status_t err = OK;
32089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
32129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            if (mState != PLAYING) {
32289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                err = INVALID_OPERATION;
32389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            } else {
32489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                mState = PLAYING_TO_PAUSED;
32589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                sendTrigger(mClientSessionID, TRIGGER_PAUSE);
32689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            }
3273856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
32889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            sp<AMessage> response = new AMessage;
329698f476590bc9e38d4d1d4155da9efdbedd357c4Marco Nelissen            response->setInt32("err", err);
33089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            response->postReply(replyID);
33189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            break;
33289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        }
33389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
33489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        case kWhatResume:
33589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        {
33689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            uint32_t replyID;
33789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            CHECK(msg->senderAwaitsResponse(&replyID));
33889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
33989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            status_t err = OK;
34029357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block
34189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            if (mState != PAUSED) {
34289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                err = INVALID_OPERATION;
34389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            } else {
34489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                mState = PAUSED_TO_PLAYING;
34589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                sendTrigger(mClientSessionID, TRIGGER_PLAY);
34689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            }
34789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
34889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            sp<AMessage> response = new AMessage;
34989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            response->setInt32("err", err);
3503856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            response->postReply(replyID);
35189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            break;
35229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        }
35389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
35489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        case kWhatReapDeadClients:
35589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        {
35689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            mReaperPending = false;
3573856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
35889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            if (mClientSessionID == 0
35989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    || mClientInfo.mPlaybackSession == NULL) {
36089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                break;
36189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            }
36289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
3633856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            if (mClientInfo.mPlaybackSession->getLastLifesignUs()
36489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    + kPlaybackSessionTimeoutUs < ALooper::GetNowUs()) {
36589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                ALOGI("playback session timed out, reaping.");
36689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
36789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                mNetSession->destroySession(mClientSessionID);
36889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                mClientSessionID = 0;
36989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
37089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                mClient->onDisplayError(
37189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                        IRemoteDisplayClient::kDisplayErrorUnknown);
3723856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            } else {
37389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                scheduleReaper();
37489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            }
37589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            break;
37689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        }
37789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
37889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        case kWhatPlaybackSessionNotify:
37989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        {
38089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            int32_t playbackSessionID;
3813856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            CHECK(msg->findInt32("playbackSessionID", &playbackSessionID));
38289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
38389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            int32_t what;
38489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            CHECK(msg->findInt32("what", &what));
3853856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
38689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            if (what == PlaybackSession::kWhatSessionDead) {
38789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                ALOGI("playback session wants to quit.");
38889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
38989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                mClient->onDisplayError(
39089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                        IRemoteDisplayClient::kDisplayErrorUnknown);
39189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            } else if (what == PlaybackSession::kWhatSessionEstablished) {
39289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                if (mClient != NULL) {
39389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    if (!mSinkSupportsVideo) {
39489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                        mClient->onDisplayConnected(
39589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                NULL,  // SurfaceTexture
396a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                                0, // width,
39789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                0, // height,
39889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                mUsingHDCP
399a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                                    ? IRemoteDisplayClient::kDisplayFlagSecure
400a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                                    : 0);
401a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                    } else {
402a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                        size_t width, height;
403a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber
40489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                        CHECK(VideoFormats::GetConfiguration(
40589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                    mChosenVideoResolutionType,
40629357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                                    mChosenVideoResolutionIndex,
40789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                    &width,
40889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                    &height,
40989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                    NULL /* framesPerSecond */,
41089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                    NULL /* interlaced */));
41189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
41289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                        mClient->onDisplayConnected(
41389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                mClientInfo.mPlaybackSession->getSurfaceTexture(),
41489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                width,
41589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                height,
41689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                mUsingHDCP
41789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                                    ? IRemoteDisplayClient::kDisplayFlagSecure
4183856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                                    : 0);
41989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    }
42089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                }
4215ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block
42289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                if (mState == ABOUT_TO_PLAY) {
42389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    mState = PLAYING;
424a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                }
425a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber            } else if (what == PlaybackSession::kWhatSessionDestroyed) {
426a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                disconnectClient2();
427a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber            } else {
428a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                CHECK_EQ(what, PlaybackSession::kWhatBinaryData);
429a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber
430a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                int32_t channel;
431a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                CHECK(msg->findInt32("channel", &channel));
432a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber
433a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                sp<ABuffer> data;
434a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                CHECK(msg->findBuffer("data", &data));
435a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber
436a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                CHECK_LE(channel, 0xffu);
437a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                CHECK_LE(data->size(), 0xffffu);
438a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber
439a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                int32_t sessionID;
440a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber                CHECK(msg->findInt32("sessionID", &sessionID));
441a4c5bc0f18fe272146426ab2eccad6215279c9f3Andreas Huber
44289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                char header[4];
44389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                header[0] = '$';
44489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                header[1] = channel;
44589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                header[2] = data->size() >> 8;
44689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                header[3] = data->size() & 0xff;
44789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
44889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                mNetSession->sendRequest(
4493856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                        sessionID, header, sizeof(header));
45089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
45189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                mNetSession->sendRequest(
45289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                        sessionID, data->data(), data->size());
45329357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            }
45489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            break;
45589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        }
45689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
45789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        case kWhatKeepAlive:
45889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        {
4595cb07aa071b43a214e4c880b3b7852714e06451bAndreas Huber            int32_t sessionID;
46089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            CHECK(msg->findInt32("sessionID", &sessionID));
4615cb07aa071b43a214e4c880b3b7852714e06451bAndreas Huber
4625cb07aa071b43a214e4c880b3b7852714e06451bAndreas Huber            if (mClientSessionID != sessionID) {
4635cb07aa071b43a214e4c880b3b7852714e06451bAndreas Huber                // Obsolete event, client is already gone.
4645cb07aa071b43a214e4c880b3b7852714e06451bAndreas Huber                break;
46589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            }
46689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
46761c7ef5bde2c7ed94a078396aa65da67b47e5402Jamie Gennis            sendM16(sessionID);
46889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            break;
46989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        }
47089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
47189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        case kWhatTeardownTriggerTimedOut:
47289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        {
47389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            if (mState == AWAITING_CLIENT_TEARDOWN) {
47489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                ALOGI("TEARDOWN trigger timed out, forcing disconnection.");
47529357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block
47689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                CHECK_NE(mStopReplyID, 0);
47789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                finishStop();
47889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                break;
47989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            }
480a1680bce73ea1b051cc92e0df651a53944b104eeJames Dong            break;
481a1680bce73ea1b051cc92e0df651a53944b104eeJames Dong        }
482a1680bce73ea1b051cc92e0df651a53944b104eeJames Dong
48389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        case kWhatHDCPNotify:
48489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        {
48589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            int32_t msgCode, ext1, ext2;
48689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            CHECK(msg->findInt32("msg", &msgCode));
48789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            CHECK(msg->findInt32("ext1", &ext1));
48889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            CHECK(msg->findInt32("ext2", &ext2));
489c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
490c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman            ALOGI("Saw HDCP notification code %d, ext1 %d, ext2 %d",
491c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman                    msgCode, ext1, ext2);
492c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
493c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman            switch (msgCode) {
494c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman                case HDCPModule::HDCP_INITIALIZATION_COMPLETE:
495c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman                {
496c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman                    mHDCPInitializationComplete = true;
497c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
498c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman                    if (mSetupTriggerDeferred) {
499c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman                        mSetupTriggerDeferred = false;
500c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
501c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman                        sendTrigger(mClientSessionID, TRIGGER_SETUP);
502c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman                    }
50361c7ef5bde2c7ed94a078396aa65da67b47e5402Jamie Gennis                    break;
50461c7ef5bde2c7ed94a078396aa65da67b47e5402Jamie Gennis                }
5053856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
50661c7ef5bde2c7ed94a078396aa65da67b47e5402Jamie Gennis                case HDCPModule::HDCP_SHUTDOWN_COMPLETE:
50761c7ef5bde2c7ed94a078396aa65da67b47e5402Jamie Gennis                case HDCPModule::HDCP_SHUTDOWN_FAILED:
50861c7ef5bde2c7ed94a078396aa65da67b47e5402Jamie Gennis                {
50961c7ef5bde2c7ed94a078396aa65da67b47e5402Jamie Gennis                    // Ugly hack to make sure that the call to
510fff6d715a8db0daf08a50634f242c40268de3d49Glenn Kasten                    // HDCPObserver::notify is completely handled before
51189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    // we clear the HDCP instance and unload the shared
5123856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                    // library :(
51389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    (new AMessage(kWhatFinishStop2, id()))->post(300000ll);
51489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    break;
51589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                }
51689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
51789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                default:
51829357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block                {
51989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    ALOGE("HDCP failure, shutting down.");
52089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
52189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    mClient->onDisplayError(
52289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                            IRemoteDisplayClient::kDisplayErrorUnknown);
52389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                    break;
52489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                }
52589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            }
52689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            break;
52789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        }
5283856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
52989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        case kWhatFinishStop2:
53089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        {
53189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            finishStop2();
53289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            break;
53389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        }
53489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
53589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        case kWhatTimeSyncerNotify:
53689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        {
53789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            break;
5383856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        }
53989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
54089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        default:
54189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            TRESPASS();
54289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
5433856b090cd04ba5dd4a59a12430ed724d5995909Steve Block}
54489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
54589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectvoid WifiDisplaySource::registerResponseHandler(
54689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        int32_t sessionID, int32_t cseq, HandleRTSPResponseFunc func) {
54789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    ResponseID id;
54889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    id.mSessionID = sessionID;
5493856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    id.mCSeq = cseq;
55089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    mResponseHandlers.add(id, func);
55189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
55289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
55389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t WifiDisplaySource::sendM1(int32_t sessionID) {
55489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    AString request = "OPTIONS * RTSP/1.0\r\n";
55589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    AppendCommonResponse(&request, mNextCSeq);
55689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
55789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    request.append(
55889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            "Require: org.wfa.wfd1.0\r\n"
559a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent            "\r\n");
560a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent
5613856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    status_t err =
562a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
563a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent
56429357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block    if (err != OK) {
565a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent        return err;
566a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent    }
567a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent
568a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent    registerResponseHandler(
569a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM1Response);
5703a34befc6fb04a4945a849e8bda8b84e4bf973feMarco Nelissen
571e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten    ++mNextCSeq;
572e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten
573e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten    return OK;
5743a34befc6fb04a4945a849e8bda8b84e4bf973feMarco Nelissen}
575a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent
576a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurentstatus_t WifiDisplaySource::sendM3(int32_t sessionID) {
577a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent    AString body =
578a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent        "wfd_content_protection\r\n"
579a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent        "wfd_video_formats\r\n"
580a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent        "wfd_audio_codecs\r\n"
581a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent        "wfd_client_rtp_ports\r\n";
582a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent
583a514bdb58b5de4986679f72b7204b4764f7a2778Eric Laurent    AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
5842beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent    AppendCommonResponse(&request, mNextCSeq);
5852beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent
5863856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    request.append("Content-Type: text/parameters\r\n");
5872beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent    request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
5882beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent    request.append("\r\n");
5892beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent    request.append(body);
5902beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent
5912beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent    status_t err =
5922beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
5932beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent
5942beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent    if (err != OK) {
5952beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent        return err;
5962beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent    }
5973856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
5982beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent    registerResponseHandler(
5992beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM3Response);
6002beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent
6012beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent    ++mNextCSeq;
60229357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block
6032beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent    return OK;
6042beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent}
6052beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent
6062beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurentstatus_t WifiDisplaySource::sendM4(int32_t sessionID) {
6072beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent    CHECK_EQ(sessionID, mClientSessionID);
6082beeb50b1bba9e92f6cacfeca37fe9fa9d36ead1Eric Laurent
6094f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang    AString body;
6104f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang
6113856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    if (mSinkSupportsVideo) {
6124f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang        body.append("wfd_video_formats: ");
6134f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang
6144f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang        VideoFormats chosenVideoFormat;
6154f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang        chosenVideoFormat.disableAll();
6163856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        chosenVideoFormat.setNativeResolution(
6174f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang                mChosenVideoResolutionType, mChosenVideoResolutionIndex);
6184f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang
6194f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang        body.append(chosenVideoFormat.getFormatSpec(true /* forM4Message */));
6204f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang        body.append("\r\n");
6214f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang    }
6223856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
6234f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang    if (mSinkSupportsAudio) {
6244f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang        body.append(
625e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten                StringPrintf("wfd_audio_codecs: %s\r\n",
6264f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang                             (mUsingPCMAudio
6273856b090cd04ba5dd4a59a12430ed724d5995909Steve Block                                ? "LPCM 00000002 00" // 2 ch PCM 48kHz
6284f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang                                : "AAC 00000001 00")));  // 2 ch AAC 48kHz
6294f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang    }
6304f9e47f2c03ce36261c4717cd7e131d7940bb068Gloria Wang
631c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    body.append(
632c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman            StringPrintf(
633c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman                "wfd_presentation_URL: rtsp://%s/wfd1.0/streamid=0 none\r\n",
634c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman                mClientInfo.mLocalIP.c_str()));
635c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
636c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    body.append(mWfdClientRtpPorts);
637c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    body.append("\r\n");
638c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
639c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
640c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    AppendCommonResponse(&request, mNextCSeq);
641c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
642c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    request.append("Content-Type: text/parameters\r\n");
643c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
644c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    request.append("\r\n");
645c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    request.append(body);
646c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
647c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    status_t err =
648c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
649c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
650c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    if (err != OK) {
651c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman        return err;
652c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    }
653c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
654c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    registerResponseHandler(
655c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM4Response);
656c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
657c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman    ++mNextCSeq;
658c795b64060c3af9d7961fc1371e4ccfa8ee3e450John Grossman
659b483c4724846c0b8d4e82afcbb7c17f671bae81cGloria Wang    return OK;
66089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
6613856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
66289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t WifiDisplaySource::sendTrigger(
6631af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams        int32_t sessionID, TriggerType triggerType) {
66489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    AString body = "wfd_trigger_method: ";
66589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    switch (triggerType) {
66689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        case TRIGGER_SETUP:
66789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            body.append("SETUP");
668660951867e959ebe98612742ef1f72d33ea7e9a3Nicolas Catania            break;
6691af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams        case TRIGGER_TEARDOWN:
6705cb07aa071b43a214e4c880b3b7852714e06451bAndreas Huber            ALOGI("Sending TEARDOWN trigger.");
6715cb07aa071b43a214e4c880b3b7852714e06451bAndreas Huber            body.append("TEARDOWN");
6725cb07aa071b43a214e4c880b3b7852714e06451bAndreas Huber            break;
673e53b9ead781c36e96d6b6f012ddffc93a3d80f0dGlenn Kasten        case TRIGGER_PAUSE:
6741af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams            body.append("PAUSE");
6751af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams            break;
676660951867e959ebe98612742ef1f72d33ea7e9a3Nicolas Catania        case TRIGGER_PLAY:
6771af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams            body.append("PLAY");
6783b26844e60f8487388e7e62709faf0dada86e7e1Eric Laurent            break;
6793b26844e60f8487388e7e62709faf0dada86e7e1Eric Laurent        default:
6803856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            TRESPASS();
6811af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams    }
68289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
68389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    body.append("\r\n");
68489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
68589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
68689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    AppendCommonResponse(&request, mNextCSeq);
68789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
68889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    request.append("Content-Type: text/parameters\r\n");
6893856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    request.append(StringPrintf("Content-Length: %d\r\n", body.size()));
69089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    request.append("\r\n");
69189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    request.append(body);
6923856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
69389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    status_t err =
69489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
69589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
69689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (err != OK) {
69789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return err;
69889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
6993856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
7001c1503cf47c0a37a30e7acac2c5d29140fc61a5fMarco Nelissen    registerResponseHandler(
70129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM5Response);
7021c1503cf47c0a37a30e7acac2c5d29140fc61a5fMarco Nelissen
70389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    ++mNextCSeq;
70489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
70589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return OK;
70689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
70789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
70865e731f393f704eedab6fbe0af7f8a580c8d4617The Android Open Source Projectstatus_t WifiDisplaySource::sendM16(int32_t sessionID) {
70965e731f393f704eedab6fbe0af7f8a580c8d4617The Android Open Source Project    AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n";
71065e731f393f704eedab6fbe0af7f8a580c8d4617The Android Open Source Project    AppendCommonResponse(&request, mNextCSeq);
71129357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block
71289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    CHECK_EQ(sessionID, mClientSessionID);
71389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    request.append(
71489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            StringPrintf("Session: %d\r\n", mClientInfo.mPlaybackSessionID));
7153856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    request.append("\r\n");  // Empty body
71689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
71789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    status_t err =
71889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        mNetSession->sendRequest(sessionID, request.c_str(), request.size());
71989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
72089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (err != OK) {
72189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return err;
72265e731f393f704eedab6fbe0af7f8a580c8d4617The Android Open Source Project    }
72365e731f393f704eedab6fbe0af7f8a580c8d4617The Android Open Source Project
72465e731f393f704eedab6fbe0af7f8a580c8d4617The Android Open Source Project    registerResponseHandler(
725145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber            sessionID, mNextCSeq, &WifiDisplaySource::onReceiveM16Response);
7265ff1dd576bb93c45b44088a51544a18fc43ebf58Steve Block
727145e68fc778275963189b02a1adcbe27cce4d769Andreas Huber    ++mNextCSeq;
72865e731f393f704eedab6fbe0af7f8a580c8d4617The Android Open Source Project
72989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return OK;
7303856b090cd04ba5dd4a59a12430ed724d5995909Steve Block}
73189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
7323856b090cd04ba5dd4a59a12430ed724d5995909Steve Blockstatus_t WifiDisplaySource::onReceiveM1Response(
73389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        int32_t sessionID, const sp<ParsedMessage> &msg) {
73489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    int32_t statusCode;
73589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (!msg->getStatusCode(&statusCode)) {
73689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return ERROR_MALFORMED;
7373856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    }
73889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
73989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (statusCode != 200) {
74089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return ERROR_UNSUPPORTED;
74189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
7423856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
74389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    return OK;
74489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
7453856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
74689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project// sink_audio_list := ("LPCM"|"AAC"|"AC3" HEXDIGIT*8 HEXDIGIT*2)
74789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project//                       (", " sink_audio_list)*
74889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatic void GetAudioModes(const char *s, const char *prefix, uint32_t *modes) {
749b483c4724846c0b8d4e82afcbb7c17f671bae81cGloria Wang    *modes = 0;
7503856b090cd04ba5dd4a59a12430ed724d5995909Steve Block
751b483c4724846c0b8d4e82afcbb7c17f671bae81cGloria Wang    size_t prefixLen = strlen(prefix);
75289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
7533856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    while (*s != '0') {
75489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        if (!strncmp(s, prefix, prefixLen) && s[prefixLen] == ' ') {
75589fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            unsigned latency;
75689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            if (sscanf(&s[prefixLen + 1], "%08x %02x", modes, &latency) != 2) {
75789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                *modes = 0;
7581af452f333664e8b0a61d96a9b3bb682d8b9a00fJason Sams            }
75989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
76089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            return;
76189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        }
76289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
7633856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        char *commaPos = strchr(s, ',');
764b483c4724846c0b8d4e82afcbb7c17f671bae81cGloria Wang        if (commaPos != NULL) {
7653856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            s = commaPos + 1;
76689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
76789fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project            while (isspace(*s)) {
76889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                ++s;
769e1c3962e268ffc12bfd1bd9ea84da1f135f36960Glenn Kasten            }
77089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        } else {
7713856b090cd04ba5dd4a59a12430ed724d5995909Steve Block            break;
77289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        }
77389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
77489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project}
775dd172fce75b2a1c3cb3a5d3b3bbb5020b1ae8675James Dong
77689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Projectstatus_t WifiDisplaySource::onReceiveM3Response(
77729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        int32_t sessionID, const sp<ParsedMessage> &msg) {
77889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    int32_t statusCode;
77989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (!msg->getStatusCode(&statusCode)) {
78089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        return ERROR_MALFORMED;
78189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
78289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
783dd172fce75b2a1c3cb3a5d3b3bbb5020b1ae8675James Dong    if (statusCode != 200) {
784dd172fce75b2a1c3cb3a5d3b3bbb5020b1ae8675James Dong        return ERROR_UNSUPPORTED;
7853856b090cd04ba5dd4a59a12430ed724d5995909Steve Block    }
786dd172fce75b2a1c3cb3a5d3b3bbb5020b1ae8675James Dong
787dd172fce75b2a1c3cb3a5d3b3bbb5020b1ae8675James Dong    sp<Parameters> params =
788dd172fce75b2a1c3cb3a5d3b3bbb5020b1ae8675James Dong        Parameters::Parse(msg->getContent(), strlen(msg->getContent()));
789e1c3962e268ffc12bfd1bd9ea84da1f135f36960Glenn Kasten
79089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (params == NULL) {
7913856b090cd04ba5dd4a59a12430ed724d5995909Steve Block        return ERROR_MALFORMED;
79289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
79389fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
79489fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    AString value;
795dd172fce75b2a1c3cb3a5d3b3bbb5020b1ae8675James Dong    if (!params->findParameter("wfd_client_rtp_ports", &value)) {
79689fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project        ALOGE("Sink doesn't report its choice of wfd_client_rtp_ports.");
79729357bc2c0dd7c43ad3bd0c8e3efa4e6fd9bfd47Steve Block        return ERROR_MALFORMED;
79889fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    }
79989fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project
80089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    unsigned port0 = 0, port1 = 0;
80189fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project    if (sscanf(value.c_str(),
80289fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project               "RTP/AVP/UDP;unicast %u %u mode=play",
8036b74d671a1321a6ecc4a40b6c87beedfecc1ec44Marco Nelissen               &port0,
8046b74d671a1321a6ecc4a40b6c87beedfecc1ec44Marco Nelissen               &port1) == 2
8056b74d671a1321a6ecc4a40b6c87beedfecc1ec44Marco Nelissen        || sscanf(value.c_str(),
8066b74d671a1321a6ecc4a40b6c87beedfecc1ec44Marco Nelissen               "RTP/AVP/TCP;unicast %u %u mode=play",
8076b74d671a1321a6ecc4a40b6c87beedfecc1ec44Marco Nelissen               &port0,
8086b74d671a1321a6ecc4a40b6c87beedfecc1ec44Marco Nelissen               &port1) == 2) {
8096b74d671a1321a6ecc4a40b6c87beedfecc1ec44Marco Nelissen            if (port0 == 0 || port0 > 65535 || port1 != 0) {
81089fa4ad53f2f4d57adbc97ae1149fc00c9b6f3c5The Android Open Source Project                ALOGE("Sink chose its wfd_client_rtp_ports poorly (%s)",
811                      value.c_str());
812
813                return ERROR_MALFORMED;
814            }
815    } else if (strcmp(value.c_str(), "RTP/AVP/TCP;interleaved mode=play")) {
816        ALOGE("Unsupported value for wfd_client_rtp_ports (%s)",
817              value.c_str());
818
819        return ERROR_UNSUPPORTED;
820    }
821
822    mWfdClientRtpPorts = value;
823    mChosenRTPPort = port0;
824
825    if (!params->findParameter("wfd_video_formats", &value)) {
826        ALOGE("Sink doesn't report its choice of wfd_video_formats.");
827        return ERROR_MALFORMED;
828    }
829
830    mSinkSupportsVideo = false;
831
832    if  (!(value == "none")) {
833        mSinkSupportsVideo = true;
834        if (!mSupportedSinkVideoFormats.parseFormatSpec(value.c_str())) {
835            ALOGE("Failed to parse sink provided wfd_video_formats (%s)",
836                  value.c_str());
837
838            return ERROR_MALFORMED;
839        }
840
841        if (!VideoFormats::PickBestFormat(
842                    mSupportedSinkVideoFormats,
843                    mSupportedSourceVideoFormats,
844                    &mChosenVideoResolutionType,
845                    &mChosenVideoResolutionIndex)) {
846            ALOGE("Sink and source share no commonly supported video "
847                  "formats.");
848
849            return ERROR_UNSUPPORTED;
850        }
851
852        size_t width, height, framesPerSecond;
853        bool interlaced;
854        CHECK(VideoFormats::GetConfiguration(
855                    mChosenVideoResolutionType,
856                    mChosenVideoResolutionIndex,
857                    &width,
858                    &height,
859                    &framesPerSecond,
860                    &interlaced));
861
862        ALOGI("Picked video resolution %u x %u %c%u",
863              width, height, interlaced ? 'i' : 'p', framesPerSecond);
864    } else {
865        ALOGI("Sink doesn't support video at all.");
866    }
867
868    if (!params->findParameter("wfd_audio_codecs", &value)) {
869        ALOGE("Sink doesn't report its choice of wfd_audio_codecs.");
870        return ERROR_MALFORMED;
871    }
872
873    mSinkSupportsAudio = false;
874
875    if  (!(value == "none")) {
876        mSinkSupportsAudio = true;
877
878        uint32_t modes;
879        GetAudioModes(value.c_str(), "AAC", &modes);
880
881        bool supportsAAC = (modes & 1) != 0;  // AAC 2ch 48kHz
882
883        GetAudioModes(value.c_str(), "LPCM", &modes);
884
885        bool supportsPCM = (modes & 2) != 0;  // LPCM 2ch 48kHz
886
887        char val[PROPERTY_VALUE_MAX];
888        if (supportsPCM
889                && property_get("media.wfd.use-pcm-audio", val, NULL)
890                && (!strcasecmp("true", val) || !strcmp("1", val))) {
891            ALOGI("Using PCM audio.");
892            mUsingPCMAudio = true;
893        } else if (supportsAAC) {
894            ALOGI("Using AAC audio.");
895            mUsingPCMAudio = false;
896        } else if (supportsPCM) {
897            ALOGI("Using PCM audio.");
898            mUsingPCMAudio = true;
899        } else {
900            ALOGI("Sink doesn't support an audio format we do.");
901            return ERROR_UNSUPPORTED;
902        }
903    } else {
904        ALOGI("Sink doesn't support audio at all.");
905    }
906
907    if (!mSinkSupportsVideo && !mSinkSupportsAudio) {
908        ALOGE("Sink supports neither video nor audio...");
909        return ERROR_UNSUPPORTED;
910    }
911
912    mUsingHDCP = false;
913    if (!params->findParameter("wfd_content_protection", &value)) {
914        ALOGI("Sink doesn't appear to support content protection.");
915    } else if (value == "none") {
916        ALOGI("Sink does not support content protection.");
917    } else {
918        mUsingHDCP = true;
919
920        bool isHDCP2_0 = false;
921        if (value.startsWith("HDCP2.0 ")) {
922            isHDCP2_0 = true;
923        } else if (!value.startsWith("HDCP2.1 ")) {
924            ALOGE("malformed wfd_content_protection: '%s'", value.c_str());
925
926            return ERROR_MALFORMED;
927        }
928
929        int32_t hdcpPort;
930        if (!ParsedMessage::GetInt32Attribute(
931                    value.c_str() + 8, "port", &hdcpPort)
932                || hdcpPort < 1 || hdcpPort > 65535) {
933            return ERROR_MALFORMED;
934        }
935
936        mIsHDCP2_0 = isHDCP2_0;
937        mHDCPPort = hdcpPort;
938
939        status_t err = makeHDCP();
940        if (err != OK) {
941            ALOGE("Unable to instantiate HDCP component. "
942                  "Not using HDCP after all.");
943
944            mUsingHDCP = false;
945        }
946    }
947
948    return sendM4(sessionID);
949}
950
951status_t WifiDisplaySource::onReceiveM4Response(
952        int32_t sessionID, const sp<ParsedMessage> &msg) {
953    int32_t statusCode;
954    if (!msg->getStatusCode(&statusCode)) {
955        return ERROR_MALFORMED;
956    }
957
958    if (statusCode != 200) {
959        return ERROR_UNSUPPORTED;
960    }
961
962    if (mUsingHDCP && !mHDCPInitializationComplete) {
963        ALOGI("Deferring SETUP trigger until HDCP initialization completes.");
964
965        mSetupTriggerDeferred = true;
966        return OK;
967    }
968
969    return sendTrigger(sessionID, TRIGGER_SETUP);
970}
971
972status_t WifiDisplaySource::onReceiveM5Response(
973        int32_t sessionID, const sp<ParsedMessage> &msg) {
974    int32_t statusCode;
975    if (!msg->getStatusCode(&statusCode)) {
976        return ERROR_MALFORMED;
977    }
978
979    if (statusCode != 200) {
980        return ERROR_UNSUPPORTED;
981    }
982
983    return OK;
984}
985
986status_t WifiDisplaySource::onReceiveM16Response(
987        int32_t sessionID, const sp<ParsedMessage> &msg) {
988    // If only the response was required to include a "Session:" header...
989
990    CHECK_EQ(sessionID, mClientSessionID);
991
992    if (mClientInfo.mPlaybackSession != NULL) {
993        mClientInfo.mPlaybackSession->updateLiveness();
994
995        scheduleKeepAlive(sessionID);
996    }
997
998    return OK;
999}
1000
1001void WifiDisplaySource::scheduleReaper() {
1002    if (mReaperPending) {
1003        return;
1004    }
1005
1006    mReaperPending = true;
1007    (new AMessage(kWhatReapDeadClients, id()))->post(kReaperIntervalUs);
1008}
1009
1010void WifiDisplaySource::scheduleKeepAlive(int32_t sessionID) {
1011    // We need to send updates at least 5 secs before the timeout is set to
1012    // expire, make sure the timeout is greater than 5 secs to begin with.
1013    CHECK_GT(kPlaybackSessionTimeoutUs, 5000000ll);
1014
1015    sp<AMessage> msg = new AMessage(kWhatKeepAlive, id());
1016    msg->setInt32("sessionID", sessionID);
1017    msg->post(kPlaybackSessionTimeoutUs - 5000000ll);
1018}
1019
1020status_t WifiDisplaySource::onReceiveClientData(const sp<AMessage> &msg) {
1021    int32_t sessionID;
1022    CHECK(msg->findInt32("sessionID", &sessionID));
1023
1024    sp<RefBase> obj;
1025    CHECK(msg->findObject("data", &obj));
1026
1027    sp<ParsedMessage> data =
1028        static_cast<ParsedMessage *>(obj.get());
1029
1030    ALOGV("session %d received '%s'",
1031          sessionID, data->debugString().c_str());
1032
1033    AString method;
1034    AString uri;
1035    data->getRequestField(0, &method);
1036
1037    int32_t cseq;
1038    if (!data->findInt32("cseq", &cseq)) {
1039        sendErrorResponse(sessionID, "400 Bad Request", -1 /* cseq */);
1040        return ERROR_MALFORMED;
1041    }
1042
1043    if (method.startsWith("RTSP/")) {
1044        // This is a response.
1045
1046        ResponseID id;
1047        id.mSessionID = sessionID;
1048        id.mCSeq = cseq;
1049
1050        ssize_t index = mResponseHandlers.indexOfKey(id);
1051
1052        if (index < 0) {
1053            ALOGW("Received unsolicited server response, cseq %d", cseq);
1054            return ERROR_MALFORMED;
1055        }
1056
1057        HandleRTSPResponseFunc func = mResponseHandlers.valueAt(index);
1058        mResponseHandlers.removeItemsAt(index);
1059
1060        status_t err = (this->*func)(sessionID, data);
1061
1062        if (err != OK) {
1063            ALOGW("Response handler for session %d, cseq %d returned "
1064                  "err %d (%s)",
1065                  sessionID, cseq, err, strerror(-err));
1066
1067            return err;
1068        }
1069
1070        return OK;
1071    }
1072
1073    AString version;
1074    data->getRequestField(2, &version);
1075    if (!(version == AString("RTSP/1.0"))) {
1076        sendErrorResponse(sessionID, "505 RTSP Version not supported", cseq);
1077        return ERROR_UNSUPPORTED;
1078    }
1079
1080    status_t err;
1081    if (method == "OPTIONS") {
1082        err = onOptionsRequest(sessionID, cseq, data);
1083    } else if (method == "SETUP") {
1084        err = onSetupRequest(sessionID, cseq, data);
1085    } else if (method == "PLAY") {
1086        err = onPlayRequest(sessionID, cseq, data);
1087    } else if (method == "PAUSE") {
1088        err = onPauseRequest(sessionID, cseq, data);
1089    } else if (method == "TEARDOWN") {
1090        err = onTeardownRequest(sessionID, cseq, data);
1091    } else if (method == "GET_PARAMETER") {
1092        err = onGetParameterRequest(sessionID, cseq, data);
1093    } else if (method == "SET_PARAMETER") {
1094        err = onSetParameterRequest(sessionID, cseq, data);
1095    } else {
1096        sendErrorResponse(sessionID, "405 Method Not Allowed", cseq);
1097
1098        err = ERROR_UNSUPPORTED;
1099    }
1100
1101    return err;
1102}
1103
1104status_t WifiDisplaySource::onOptionsRequest(
1105        int32_t sessionID,
1106        int32_t cseq,
1107        const sp<ParsedMessage> &data) {
1108    int32_t playbackSessionID;
1109    sp<PlaybackSession> playbackSession =
1110        findPlaybackSession(data, &playbackSessionID);
1111
1112    if (playbackSession != NULL) {
1113        playbackSession->updateLiveness();
1114    }
1115
1116    AString response = "RTSP/1.0 200 OK\r\n";
1117    AppendCommonResponse(&response, cseq);
1118
1119    response.append(
1120            "Public: org.wfa.wfd1.0, SETUP, TEARDOWN, PLAY, PAUSE, "
1121            "GET_PARAMETER, SET_PARAMETER\r\n");
1122
1123    response.append("\r\n");
1124
1125    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
1126
1127    if (err == OK) {
1128        err = sendM3(sessionID);
1129    }
1130
1131    return err;
1132}
1133
1134status_t WifiDisplaySource::onSetupRequest(
1135        int32_t sessionID,
1136        int32_t cseq,
1137        const sp<ParsedMessage> &data) {
1138    CHECK_EQ(sessionID, mClientSessionID);
1139    if (mClientInfo.mPlaybackSessionID != -1) {
1140        // We only support a single playback session per client.
1141        // This is due to the reversed keep-alive design in the wfd specs...
1142        sendErrorResponse(sessionID, "400 Bad Request", cseq);
1143        return ERROR_MALFORMED;
1144    }
1145
1146    AString transport;
1147    if (!data->findString("transport", &transport)) {
1148        sendErrorResponse(sessionID, "400 Bad Request", cseq);
1149        return ERROR_MALFORMED;
1150    }
1151
1152    RTPSender::TransportMode transportMode = RTPSender::TRANSPORT_UDP;
1153
1154    int clientRtp, clientRtcp;
1155    if (transport.startsWith("RTP/AVP/TCP;")) {
1156        AString interleaved;
1157        if (ParsedMessage::GetAttribute(
1158                    transport.c_str(), "interleaved", &interleaved)
1159                && sscanf(interleaved.c_str(), "%d-%d",
1160                          &clientRtp, &clientRtcp) == 2) {
1161            transportMode = RTPSender::TRANSPORT_TCP_INTERLEAVED;
1162        } else {
1163            bool badRequest = false;
1164
1165            AString clientPort;
1166            if (!ParsedMessage::GetAttribute(
1167                        transport.c_str(), "client_port", &clientPort)) {
1168                badRequest = true;
1169            } else if (sscanf(clientPort.c_str(), "%d-%d",
1170                              &clientRtp, &clientRtcp) == 2) {
1171            } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
1172                // No RTCP.
1173                clientRtcp = -1;
1174            } else {
1175                badRequest = true;
1176            }
1177
1178            if (badRequest) {
1179                sendErrorResponse(sessionID, "400 Bad Request", cseq);
1180                return ERROR_MALFORMED;
1181            }
1182
1183            transportMode = RTPSender::TRANSPORT_TCP;
1184        }
1185    } else if (transport.startsWith("RTP/AVP;unicast;")
1186            || transport.startsWith("RTP/AVP/UDP;unicast;")) {
1187        bool badRequest = false;
1188
1189        AString clientPort;
1190        if (!ParsedMessage::GetAttribute(
1191                    transport.c_str(), "client_port", &clientPort)) {
1192            badRequest = true;
1193        } else if (sscanf(clientPort.c_str(), "%d-%d",
1194                          &clientRtp, &clientRtcp) == 2) {
1195        } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) {
1196            // No RTCP.
1197            clientRtcp = -1;
1198        } else {
1199            badRequest = true;
1200        }
1201
1202        if (badRequest) {
1203            sendErrorResponse(sessionID, "400 Bad Request", cseq);
1204            return ERROR_MALFORMED;
1205        }
1206#if 1
1207    // The older LG dongles doesn't specify client_port=xxx apparently.
1208    } else if (transport == "RTP/AVP/UDP;unicast") {
1209        clientRtp = 19000;
1210        clientRtcp = -1;
1211#endif
1212    } else {
1213        sendErrorResponse(sessionID, "461 Unsupported Transport", cseq);
1214        return ERROR_UNSUPPORTED;
1215    }
1216
1217    int32_t playbackSessionID = makeUniquePlaybackSessionID();
1218
1219    sp<AMessage> notify = new AMessage(kWhatPlaybackSessionNotify, id());
1220    notify->setInt32("playbackSessionID", playbackSessionID);
1221    notify->setInt32("sessionID", sessionID);
1222
1223    sp<PlaybackSession> playbackSession =
1224        new PlaybackSession(
1225                mNetSession, notify, mInterfaceAddr, mHDCP);
1226
1227    looper()->registerHandler(playbackSession);
1228
1229    AString uri;
1230    data->getRequestField(1, &uri);
1231
1232    if (strncasecmp("rtsp://", uri.c_str(), 7)) {
1233        sendErrorResponse(sessionID, "400 Bad Request", cseq);
1234        return ERROR_MALFORMED;
1235    }
1236
1237    if (!(uri.startsWith("rtsp://") && uri.endsWith("/wfd1.0/streamid=0"))) {
1238        sendErrorResponse(sessionID, "404 Not found", cseq);
1239        return ERROR_MALFORMED;
1240    }
1241
1242    status_t err = playbackSession->init(
1243            mClientInfo.mRemoteIP.c_str(),
1244            clientRtp,
1245            clientRtcp,
1246            transportMode,
1247            mSinkSupportsAudio,
1248            mUsingPCMAudio,
1249            mSinkSupportsVideo,
1250            mChosenVideoResolutionType,
1251            mChosenVideoResolutionIndex);
1252
1253    if (err != OK) {
1254        looper()->unregisterHandler(playbackSession->id());
1255        playbackSession.clear();
1256    }
1257
1258    switch (err) {
1259        case OK:
1260            break;
1261        case -ENOENT:
1262            sendErrorResponse(sessionID, "404 Not Found", cseq);
1263            return err;
1264        default:
1265            sendErrorResponse(sessionID, "403 Forbidden", cseq);
1266            return err;
1267    }
1268
1269    mClientInfo.mPlaybackSessionID = playbackSessionID;
1270    mClientInfo.mPlaybackSession = playbackSession;
1271
1272    AString response = "RTSP/1.0 200 OK\r\n";
1273    AppendCommonResponse(&response, cseq, playbackSessionID);
1274
1275    if (transportMode == RTPSender::TRANSPORT_TCP_INTERLEAVED) {
1276        response.append(
1277                StringPrintf(
1278                    "Transport: RTP/AVP/TCP;interleaved=%d-%d;",
1279                    clientRtp, clientRtcp));
1280    } else {
1281        int32_t serverRtp = playbackSession->getRTPPort();
1282
1283        AString transportString = "UDP";
1284        if (transportMode == RTPSender::TRANSPORT_TCP) {
1285            transportString = "TCP";
1286        }
1287
1288        if (clientRtcp >= 0) {
1289            response.append(
1290                    StringPrintf(
1291                        "Transport: RTP/AVP/%s;unicast;client_port=%d-%d;"
1292                        "server_port=%d-%d\r\n",
1293                        transportString.c_str(),
1294                        clientRtp, clientRtcp, serverRtp, serverRtp + 1));
1295        } else {
1296            response.append(
1297                    StringPrintf(
1298                        "Transport: RTP/AVP/%s;unicast;client_port=%d;"
1299                        "server_port=%d\r\n",
1300                        transportString.c_str(),
1301                        clientRtp, serverRtp));
1302        }
1303    }
1304
1305    response.append("\r\n");
1306
1307    err = mNetSession->sendRequest(sessionID, response.c_str());
1308
1309    if (err != OK) {
1310        return err;
1311    }
1312
1313    mState = AWAITING_CLIENT_PLAY;
1314
1315    scheduleReaper();
1316    scheduleKeepAlive(sessionID);
1317
1318    return OK;
1319}
1320
1321status_t WifiDisplaySource::onPlayRequest(
1322        int32_t sessionID,
1323        int32_t cseq,
1324        const sp<ParsedMessage> &data) {
1325    int32_t playbackSessionID;
1326    sp<PlaybackSession> playbackSession =
1327        findPlaybackSession(data, &playbackSessionID);
1328
1329    if (playbackSession == NULL) {
1330        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
1331        return ERROR_MALFORMED;
1332    }
1333
1334    ALOGI("Received PLAY request.");
1335
1336    status_t err = playbackSession->play();
1337    CHECK_EQ(err, (status_t)OK);
1338
1339    AString response = "RTSP/1.0 200 OK\r\n";
1340    AppendCommonResponse(&response, cseq, playbackSessionID);
1341    response.append("Range: npt=now-\r\n");
1342    response.append("\r\n");
1343
1344    err = mNetSession->sendRequest(sessionID, response.c_str());
1345
1346    if (err != OK) {
1347        return err;
1348    }
1349
1350    if (mState == PAUSED_TO_PLAYING) {
1351        mState = PLAYING;
1352        return OK;
1353    }
1354
1355    playbackSession->finishPlay();
1356
1357    CHECK_EQ(mState, AWAITING_CLIENT_PLAY);
1358    mState = ABOUT_TO_PLAY;
1359
1360    return OK;
1361}
1362
1363status_t WifiDisplaySource::onPauseRequest(
1364        int32_t sessionID,
1365        int32_t cseq,
1366        const sp<ParsedMessage> &data) {
1367    int32_t playbackSessionID;
1368    sp<PlaybackSession> playbackSession =
1369        findPlaybackSession(data, &playbackSessionID);
1370
1371    if (playbackSession == NULL) {
1372        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
1373        return ERROR_MALFORMED;
1374    }
1375
1376    ALOGI("Received PAUSE request.");
1377
1378    if (mState != PLAYING_TO_PAUSED) {
1379        return INVALID_OPERATION;
1380    }
1381
1382    status_t err = playbackSession->pause();
1383    CHECK_EQ(err, (status_t)OK);
1384
1385    AString response = "RTSP/1.0 200 OK\r\n";
1386    AppendCommonResponse(&response, cseq, playbackSessionID);
1387    response.append("\r\n");
1388
1389    err = mNetSession->sendRequest(sessionID, response.c_str());
1390
1391    if (err != OK) {
1392        return err;
1393    }
1394
1395    mState = PAUSED;
1396
1397    return err;
1398}
1399
1400status_t WifiDisplaySource::onTeardownRequest(
1401        int32_t sessionID,
1402        int32_t cseq,
1403        const sp<ParsedMessage> &data) {
1404    ALOGI("Received TEARDOWN request.");
1405
1406    int32_t playbackSessionID;
1407    sp<PlaybackSession> playbackSession =
1408        findPlaybackSession(data, &playbackSessionID);
1409
1410    if (playbackSession == NULL) {
1411        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
1412        return ERROR_MALFORMED;
1413    }
1414
1415    AString response = "RTSP/1.0 200 OK\r\n";
1416    AppendCommonResponse(&response, cseq, playbackSessionID);
1417    response.append("Connection: close\r\n");
1418    response.append("\r\n");
1419
1420    mNetSession->sendRequest(sessionID, response.c_str());
1421
1422    if (mState == AWAITING_CLIENT_TEARDOWN) {
1423        CHECK_NE(mStopReplyID, 0);
1424        finishStop();
1425    } else {
1426        mClient->onDisplayError(IRemoteDisplayClient::kDisplayErrorUnknown);
1427    }
1428
1429    return OK;
1430}
1431
1432void WifiDisplaySource::finishStop() {
1433    ALOGV("finishStop");
1434
1435    mState = STOPPING;
1436
1437    disconnectClientAsync();
1438}
1439
1440void WifiDisplaySource::finishStopAfterDisconnectingClient() {
1441    ALOGV("finishStopAfterDisconnectingClient");
1442
1443    if (mHDCP != NULL) {
1444        ALOGI("Initiating HDCP shutdown.");
1445        mHDCP->shutdownAsync();
1446        return;
1447    }
1448
1449    finishStop2();
1450}
1451
1452void WifiDisplaySource::finishStop2() {
1453    ALOGV("finishStop2");
1454
1455    if (mHDCP != NULL) {
1456        mHDCP->setObserver(NULL);
1457        mHDCPObserver.clear();
1458        mHDCP.clear();
1459    }
1460
1461    if (mSessionID != 0) {
1462        mNetSession->destroySession(mSessionID);
1463        mSessionID = 0;
1464    }
1465
1466    ALOGI("We're stopped.");
1467    mState = STOPPED;
1468
1469    status_t err = OK;
1470
1471    sp<AMessage> response = new AMessage;
1472    response->setInt32("err", err);
1473    response->postReply(mStopReplyID);
1474}
1475
1476status_t WifiDisplaySource::onGetParameterRequest(
1477        int32_t sessionID,
1478        int32_t cseq,
1479        const sp<ParsedMessage> &data) {
1480    int32_t playbackSessionID;
1481    sp<PlaybackSession> playbackSession =
1482        findPlaybackSession(data, &playbackSessionID);
1483
1484    if (playbackSession == NULL) {
1485        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
1486        return ERROR_MALFORMED;
1487    }
1488
1489    playbackSession->updateLiveness();
1490
1491    AString response = "RTSP/1.0 200 OK\r\n";
1492    AppendCommonResponse(&response, cseq, playbackSessionID);
1493    response.append("\r\n");
1494
1495    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
1496    return err;
1497}
1498
1499status_t WifiDisplaySource::onSetParameterRequest(
1500        int32_t sessionID,
1501        int32_t cseq,
1502        const sp<ParsedMessage> &data) {
1503    int32_t playbackSessionID;
1504    sp<PlaybackSession> playbackSession =
1505        findPlaybackSession(data, &playbackSessionID);
1506
1507    if (playbackSession == NULL) {
1508        sendErrorResponse(sessionID, "454 Session Not Found", cseq);
1509        return ERROR_MALFORMED;
1510    }
1511
1512    if (strstr(data->getContent(), "wfd_idr_request\r\n")) {
1513        playbackSession->requestIDRFrame();
1514    }
1515
1516    playbackSession->updateLiveness();
1517
1518    AString response = "RTSP/1.0 200 OK\r\n";
1519    AppendCommonResponse(&response, cseq, playbackSessionID);
1520    response.append("\r\n");
1521
1522    status_t err = mNetSession->sendRequest(sessionID, response.c_str());
1523    return err;
1524}
1525
1526// static
1527void WifiDisplaySource::AppendCommonResponse(
1528        AString *response, int32_t cseq, int32_t playbackSessionID) {
1529    time_t now = time(NULL);
1530    struct tm *now2 = gmtime(&now);
1531    char buf[128];
1532    strftime(buf, sizeof(buf), "%a, %d %b %Y %H:%M:%S %z", now2);
1533
1534    response->append("Date: ");
1535    response->append(buf);
1536    response->append("\r\n");
1537
1538    response->append("Server: Mine/1.0\r\n");
1539
1540    if (cseq >= 0) {
1541        response->append(StringPrintf("CSeq: %d\r\n", cseq));
1542    }
1543
1544    if (playbackSessionID >= 0ll) {
1545        response->append(
1546                StringPrintf(
1547                    "Session: %d;timeout=%lld\r\n",
1548                    playbackSessionID, kPlaybackSessionTimeoutSecs));
1549    }
1550}
1551
1552void WifiDisplaySource::sendErrorResponse(
1553        int32_t sessionID,
1554        const char *errorDetail,
1555        int32_t cseq) {
1556    AString response;
1557    response.append("RTSP/1.0 ");
1558    response.append(errorDetail);
1559    response.append("\r\n");
1560
1561    AppendCommonResponse(&response, cseq);
1562
1563    response.append("\r\n");
1564
1565    mNetSession->sendRequest(sessionID, response.c_str());
1566}
1567
1568int32_t WifiDisplaySource::makeUniquePlaybackSessionID() const {
1569    return rand();
1570}
1571
1572sp<WifiDisplaySource::PlaybackSession> WifiDisplaySource::findPlaybackSession(
1573        const sp<ParsedMessage> &data, int32_t *playbackSessionID) const {
1574    if (!data->findInt32("session", playbackSessionID)) {
1575        // XXX the older dongles do not always include a "Session:" header.
1576        *playbackSessionID = mClientInfo.mPlaybackSessionID;
1577        return mClientInfo.mPlaybackSession;
1578    }
1579
1580    if (*playbackSessionID != mClientInfo.mPlaybackSessionID) {
1581        return NULL;
1582    }
1583
1584    return mClientInfo.mPlaybackSession;
1585}
1586
1587void WifiDisplaySource::disconnectClientAsync() {
1588    ALOGV("disconnectClient");
1589
1590    if (mClientInfo.mPlaybackSession == NULL) {
1591        disconnectClient2();
1592        return;
1593    }
1594
1595    if (mClientInfo.mPlaybackSession != NULL) {
1596        ALOGV("Destroying PlaybackSession");
1597        mClientInfo.mPlaybackSession->destroyAsync();
1598    }
1599}
1600
1601void WifiDisplaySource::disconnectClient2() {
1602    ALOGV("disconnectClient2");
1603
1604    if (mClientInfo.mPlaybackSession != NULL) {
1605        looper()->unregisterHandler(mClientInfo.mPlaybackSession->id());
1606        mClientInfo.mPlaybackSession.clear();
1607    }
1608
1609    if (mClientSessionID != 0) {
1610        mNetSession->destroySession(mClientSessionID);
1611        mClientSessionID = 0;
1612    }
1613
1614    mClient->onDisplayDisconnected();
1615
1616    finishStopAfterDisconnectingClient();
1617}
1618
1619struct WifiDisplaySource::HDCPObserver : public BnHDCPObserver {
1620    HDCPObserver(const sp<AMessage> &notify);
1621
1622    virtual void notify(
1623            int msg, int ext1, int ext2, const Parcel *obj);
1624
1625private:
1626    sp<AMessage> mNotify;
1627
1628    DISALLOW_EVIL_CONSTRUCTORS(HDCPObserver);
1629};
1630
1631WifiDisplaySource::HDCPObserver::HDCPObserver(
1632        const sp<AMessage> &notify)
1633    : mNotify(notify) {
1634}
1635
1636void WifiDisplaySource::HDCPObserver::notify(
1637        int msg, int ext1, int ext2, const Parcel *obj) {
1638    sp<AMessage> notify = mNotify->dup();
1639    notify->setInt32("msg", msg);
1640    notify->setInt32("ext1", ext1);
1641    notify->setInt32("ext2", ext2);
1642    notify->post();
1643}
1644
1645status_t WifiDisplaySource::makeHDCP() {
1646    sp<IServiceManager> sm = defaultServiceManager();
1647    sp<IBinder> binder = sm->getService(String16("media.player"));
1648    sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
1649    CHECK(service != NULL);
1650
1651    mHDCP = service->makeHDCP(true /* createEncryptionModule */);
1652
1653    if (mHDCP == NULL) {
1654        return ERROR_UNSUPPORTED;
1655    }
1656
1657    sp<AMessage> notify = new AMessage(kWhatHDCPNotify, id());
1658    mHDCPObserver = new HDCPObserver(notify);
1659
1660    status_t err = mHDCP->setObserver(mHDCPObserver);
1661
1662    if (err != OK) {
1663        ALOGE("Failed to set HDCP observer.");
1664
1665        mHDCPObserver.clear();
1666        mHDCP.clear();
1667
1668        return err;
1669    }
1670
1671    ALOGI("Initiating HDCP negotiation w/ host %s:%d",
1672            mClientInfo.mRemoteIP.c_str(), mHDCPPort);
1673
1674    err = mHDCP->initAsync(mClientInfo.mRemoteIP.c_str(), mHDCPPort);
1675
1676    if (err != OK) {
1677        return err;
1678    }
1679
1680    return OK;
1681}
1682
1683}  // namespace android
1684
1685