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