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> ¬ify); 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> ¬ify) 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