bool NuPlayer::Decoder::supportsSeamlessFormatChange(const sp<AMessage> &targetFormat) const { if (mFormat == NULL) { return false; } if (targetFormat == NULL) { return true; } AString oldMime, newMime; if (!mFormat->findString("mime", &oldMime) || !targetFormat->findString("mime", &newMime) || !(oldMime == newMime)) { return false; } bool audio = !strncasecmp(oldMime.c_str(), "audio/", strlen("audio/")); bool seamless; if (audio) { seamless = supportsSeamlessAudioFormatChange(targetFormat); } else { seamless = mCodec != NULL && mCodec->isConfiguredForAdaptivePlayback(); } ALOGV("%s seamless support for %s", seamless ? "yes" : "no", oldMime.c_str()); return seamless; }
bool NuPlayer::Decoder::supportsSeamlessAudioFormatChange(const sp<AMessage> &targetFormat) const { if (targetFormat == NULL) { return true; } AString mime; if (!targetFormat->findString("mime", &mime)) { return false; } if (!strcasecmp(mime.c_str(), MEDIA_MIMETYPE_AUDIO_AAC)) { // field-by-field comparison const char * keys[] = { "channel-count", "sample-rate", "is-adts" }; for (unsigned int i = 0; i < sizeof(keys) / sizeof(keys[0]); i++) { int32_t oldVal, newVal; if (!mFormat->findInt32(keys[i], &oldVal) || !targetFormat->findInt32(keys[i], &newVal) || oldVal != newVal) { return false; } } sp<ABuffer> oldBuf, newBuf; if (mFormat->findBuffer("csd-0", &oldBuf) && targetFormat->findBuffer("csd-0", &newBuf)) { if (oldBuf->size() != newBuf->size()) { return false; } return !memcmp(oldBuf->data(), newBuf->data(), oldBuf->size()); } } return false; }
void MediaFilter::onAllocateComponent(const sp<AMessage> &msg) { CHECK_EQ(mState, UNINITIALIZED); CHECK(msg->findString("componentName", &mComponentName)); const char* name = mComponentName.c_str(); if (!strcasecmp(name, "android.filter.zerofilter")) { mFilter = new ZeroFilter; } else if (!strcasecmp(name, "android.filter.saturation")) { mFilter = new SaturationFilter; } else if (!strcasecmp(name, "android.filter.intrinsicblur")) { mFilter = new IntrinsicBlurFilter; } else if (!strcasecmp(name, "android.filter.RenderScript")) { mFilter = new RSFilter; } else { ALOGE("Unrecognized filter name: %s", name); signalError(NAME_NOT_FOUND); return; } sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatComponentAllocated); // HACK - need "OMX.google" to use MediaCodec's software renderer notify->setString("componentName", "OMX.google.MediaFilter"); notify->post(); mState = INITIALIZED; ALOGV("Handled kWhatAllocateComponent."); }
void ExtendedCodec::configureVideoDecoder( const sp<AMessage> &msg, const char* mime, sp<IOMX> OMXhandle, const uint32_t flags, IOMX::node_id nodeID, const char* componentName ) { if (strncmp(componentName, "OMX.qcom.", 9)) { //do nothing for non QC component return; } setDIVXFormat(msg, mime, OMXhandle, nodeID, kPortIndexOutput); AString fileFormat; const char *fileFormatCStr = NULL; bool success = msg->findString(getMsgKey(kKeyFileFormat), &fileFormat); if (success) { fileFormatCStr = fileFormat.c_str(); } // Enable timestamp reordering for AVI file type, mpeg4 and vc1 codec types if (!strcmp(componentName, "OMX.qcom.video.decoder.vc1") || !strcmp(componentName, "OMX.qcom.video.decoder.mpeg4") || (fileFormatCStr!= NULL && !strncmp(fileFormatCStr, "video/avi", 9))) { ALOGI("Enabling timestamp reordering"); QOMX_INDEXTIMESTAMPREORDER reorder; InitOMXParams(&reorder); reorder.nPortIndex = kPortIndexOutput; reorder.bEnable = OMX_TRUE; status_t err = OMXhandle->setParameter(nodeID, (OMX_INDEXTYPE)OMX_QcomIndexParamEnableTimeStampReorder, (void *)&reorder, sizeof(reorder)); if(err != OK) { ALOGW("Failed to enable timestamp reordering"); } } // Enable Sync-frame decode mode for thumbnails if (flags & OMXCodec::kClientNeedsFramebuffer) { ALOGV("Enabling thumbnail mode."); QOMX_ENABLETYPE enableType; OMX_INDEXTYPE indexType; status_t err = OMXhandle->getExtensionIndex( nodeID, OMX_QCOM_INDEX_PARAM_VIDEO_SYNCFRAMEDECODINGMODE, &indexType); if(err != OK) { ALOGW("Failed to get extension for SYNCFRAMEDECODINGMODE"); return; } enableType.bEnable = OMX_TRUE; err = OMXhandle->setParameter(nodeID,indexType, (void *)&enableType, sizeof(enableType)); if(err != OK) { ALOGW("Failed to get extension for SYNCFRAMEDECODINGMODE"); return; } ALOGI("Thumbnail mode enabled."); } }
void NuPlayer::Decoder::configure(const sp<AMessage> &format) { CHECK(mCodec == NULL); AString mime; CHECK(format->findString("mime", &mime)); sp<AMessage> notifyMsg = new AMessage(kWhatCodecNotify, id()); mCSDIndex = 0; for (size_t i = 0;; ++i) { sp<ABuffer> csd; if (!format->findBuffer(StringPrintf("csd-%d", i).c_str(), &csd)) { break; } mCSD.push(csd); } #ifdef QCOM_HARDWARE sp<ABuffer> extendedCSD = ExtendedCodec::getRawCodecSpecificData(format); if (extendedCSD != NULL) { ALOGV("pushing extended CSD of size %d", extendedCSD->size()); mCSD.push(extendedCSD); } sp<ABuffer> aacCSD = ExtendedCodec::getAacCodecSpecificData(format); if (aacCSD != NULL) { ALOGV("pushing AAC CSD of size %d", aacCSD->size()); mCSD.push(aacCSD); } #endif if (mNativeWindow != NULL) { format->setObject("native-window", mNativeWindow); } // Current video decoders do not return from OMX_FillThisBuffer // quickly, violating the OpenMAX specs, until that is remedied // we need to invest in an extra looper to free the main event // queue. bool needDedicatedLooper = !strncasecmp(mime.c_str(), "video/", 6); mFormat = format; mCodec = new ACodec; if (needDedicatedLooper && mCodecLooper == NULL) { mCodecLooper = new ALooper; mCodecLooper->setName("NuPlayerDecoder"); mCodecLooper->start(false, false, ANDROID_PRIORITY_AUDIO); } (needDedicatedLooper ? mCodecLooper : looper())->registerHandler(mCodec); mCodec->setNotificationMessage(notifyMsg); mCodec->initiateSetup(format); }
void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) { sp<AMessage> reply; CHECK(msg->findMessage("reply", &reply)); if (mState != CONNECTED) { reply->setInt32("result", -ENOTCONN); reply->post(); return; } AString request; CHECK(msg->findString("request", &request)); // Find the boundary between headers and the body. ssize_t i = request.find("\r\n\r\n"); CHECK_GE(i, 0); int32_t cseq = mNextCSeq++; AString cseqHeader = "CSeq: "; cseqHeader.append(cseq); cseqHeader.append("\r\n"); request.insert(cseqHeader, i + 2); LOGV("%s", request.c_str()); size_t numBytesSent = 0; while (numBytesSent < request.size()) { ssize_t n = send(mSocket, request.c_str() + numBytesSent, request.size() - numBytesSent, 0); if (n == 0) { // Server closed the connection. LOGE("Server unexpectedly closed the connection."); reply->setInt32("result", ERROR_IO); reply->post(); return; } else if (n < 0) { if (errno == EINTR) { continue; } LOGE("Error sending rtsp request."); reply->setInt32("result", -errno); reply->post(); return; } numBytesSent += (size_t)n; } mPendingRequests.add(cseq, reply); }
status_t SaturationFilter::configure(const sp<AMessage> &msg) { status_t err = SimpleFilter::configure(msg); if (err != OK) { return err; } if (!msg->findString("cacheDir", &mCacheDir)) { ALOGE("Failed to find cache directory in config message."); return NAME_NOT_FOUND; } return OK; }
//liluchangyou void ARTSPConnection::onSendResponse(const sp<AMessage> &msg) { AString response; sp<AMessage> notify; CHECK(msg->findString("response", &response)); // Find the boundary between headers and the body. ssize_t i = response.find("\r\n\r\n"); CHECK_GE(i, 0); LOGI(LOG_TAG,"response:\n%s", response.c_str()); size_t numBytesSent = 0; while (numBytesSent < response.size()) { ssize_t n = send(mSocket, response.c_str() + numBytesSent, response.size() - numBytesSent, 0); if (n == 0) { // Client closed the connection. LOGE(LOG_TAG,"Client unexpectedly closed the connection."); mState = DISCONNECTED; notify = new AMessage(kwhatCloseSession,mhandlerID); notify->setInt32("result",-1); notify->setInt32("sessionID",mSessionID); notify->post(); return; } else if (n < 0) { if (errno == EINTR) { continue; } mState = DISCONNECTED; LOGE(LOG_TAG,"Error sending rtsp response."); notify = new AMessage(kwhatCloseSession,mhandlerID); notify->setInt32("result",errno ); notify->setInt32("sessionID",mSessionID); notify->post(); return; } numBytesSent += (size_t)n; } }
void SinkHandler::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatSinkNotify: { AString reason; msg->findString("reason", &reason); ALOGI("SinkHandler received : %s\n", reason.c_str()); if (strncmp(reason.c_str(), "RTSP_ERROR", 10) == 0) { ALOGI("libstagefright_wfd reports RTSP_ERROR"); report_rtsp_error(); }else if (strncmp(reason.c_str(),"RTP_NO_PACKET", 13) == 0) { ALOGI("libstagefright_wfd reports no packets"); if(mStart) report_rtp_nopacket(); } break; } default: TRESPASS(); } }
status_t ConvertMessageToMap( JNIEnv *env, const sp<AMessage> &msg, jobject *map) { ScopedLocalRef<jclass> hashMapClazz( env, env->FindClass("java/util/HashMap")); if (hashMapClazz.get() == NULL) { return -EINVAL; } jmethodID hashMapConstructID = env->GetMethodID(hashMapClazz.get(), "<init>", "()V"); if (hashMapConstructID == NULL) { return -EINVAL; } jmethodID hashMapPutID = env->GetMethodID( hashMapClazz.get(), "put", "(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;"); if (hashMapPutID == NULL) { return -EINVAL; } jobject hashMap = env->NewObject(hashMapClazz.get(), hashMapConstructID); for (size_t i = 0; i < msg->countEntries(); ++i) { AMessage::Type valueType; const char *key = msg->getEntryNameAt(i, &valueType); jobject valueObj = NULL; switch (valueType) { case AMessage::kTypeInt32: { int32_t val; CHECK(msg->findInt32(key, &val)); valueObj = makeIntegerObject(env, val); break; } case AMessage::kTypeInt64: { int64_t val; CHECK(msg->findInt64(key, &val)); valueObj = makeLongObject(env, val); break; } case AMessage::kTypeFloat: { float val; CHECK(msg->findFloat(key, &val)); valueObj = makeFloatObject(env, val); break; } case AMessage::kTypeString: { AString val; CHECK(msg->findString(key, &val)); valueObj = env->NewStringUTF(val.c_str()); break; } case AMessage::kTypeBuffer: { sp<ABuffer> buffer; CHECK(msg->findBuffer(key, &buffer)); valueObj = makeByteBufferObject( env, buffer->data(), buffer->size()); break; } case AMessage::kTypeRect: { int32_t left, top, right, bottom; CHECK(msg->findRect(key, &left, &top, &right, &bottom)); SetMapInt32( env, hashMap, hashMapPutID, StringPrintf("%s-left", key).c_str(), left); SetMapInt32( env, hashMap, hashMapPutID, StringPrintf("%s-top", key).c_str(), top); SetMapInt32( env, hashMap, hashMapPutID, StringPrintf("%s-right", key).c_str(), right); SetMapInt32( env, hashMap, hashMapPutID, StringPrintf("%s-bottom", key).c_str(), bottom); break; } default: break; } if (valueObj != NULL) { jstring keyObj = env->NewStringUTF(key); env->CallObjectMethod(hashMap, hashMapPutID, keyObj, valueObj); env->DeleteLocalRef(keyObj); keyObj = NULL; env->DeleteLocalRef(valueObj); valueObj = NULL; } } *map = hashMap; return OK; }
void ARTSPConnection::onConnect(const sp<AMessage> &msg) { ++mConnectionID; if (mState != DISCONNECTED) { if (mUIDValid) { HTTPBase::UnRegisterSocketUserTag(mSocket); HTTPBase::UnRegisterSocketUserMark(mSocket); } close(mSocket); mSocket = -1; flushPendingRequests(); } mState = CONNECTING; AString url; CHECK(msg->findString("url", &url)); sp<AMessage> reply; CHECK(msg->findMessage("reply", &reply)); AString host, path; unsigned port; if (!ParseURL(url.c_str(), &host, &port, &path, &mUser, &mPass) || (mUser.size() > 0 && mPass.size() == 0)) { // If we have a user name but no password we have to give up // right here, since we currently have no way of asking the user // for this information. ALOGE("Malformed rtsp url %s", uriDebugString(url).c_str()); reply->setInt32("result", ERROR_MALFORMED); reply->post(); mState = DISCONNECTED; return; } if (mUser.size() > 0) { ALOGV("user = '******', pass = '******'", mUser.c_str(), mPass.c_str()); } struct addrinfo hints; memset(&hints, 0, sizeof (hints)); hints.ai_flags = AI_PASSIVE; hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; mConnectionTimes = 0; int err = getaddrinfo(host.c_str(), NULL, &hints, (struct addrinfo **)(&mAddrHeader)); if (err != 0 || mAddrHeader == NULL) { ALOGE("Unknown host, err %d (%s)", err, gai_strerror(err)); reply->setInt32("result", -ENOENT); reply->post(); mState = DISCONNECTED; if (mAddrHeader != NULL) { freeaddrinfo((struct addrinfo *)mAddrHeader); mAddrHeader = NULL; } return; } if (!createSocketAndConnect(mAddrHeader, port, reply)) { ALOGV("Failed to connect to %s", host.c_str()); reply->setInt32("result", -errno); mState = DISCONNECTED; mSocket = -1; reply->post(); freeaddrinfo((struct addrinfo *)mAddrHeader); mAddrHeader = NULL; } }
void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) { sp<AMessage> reply; CHECK(msg->findMessage("reply", &reply)); if (mState != CONNECTED) { reply->setInt32("result", -ENOTCONN); reply->post(); return; } AString request; CHECK(msg->findString("request", &request)); // Just in case we need to re-issue the request with proper authentication // later, stash it away. reply->setString("original-request", request.c_str(), request.size()); addAuthentication(&request); addUserAgent(&request); // Find the boundary between headers and the body. ssize_t i = request.find("\r\n\r\n"); CHECK_GE(i, 0); int32_t cseq = mNextCSeq++; AString cseqHeader = "CSeq: "; cseqHeader.append(cseq); cseqHeader.append("\r\n"); request.insert(cseqHeader, i + 2); ALOGV("request: '%s'", request.c_str()); size_t numBytesSent = 0; while (numBytesSent < request.size()) { ssize_t n = send(mSocket, request.c_str() + numBytesSent, request.size() - numBytesSent, 0); if (n < 0 && errno == EINTR) { continue; } if (n <= 0) { performDisconnect(); if (n == 0) { // Server closed the connection. ALOGE("Server unexpectedly closed the connection."); reply->setInt32("result", ERROR_IO); reply->post(); } else { ALOGE("Error sending rtsp request. (%s)", strerror(errno)); reply->setInt32("result", -errno); reply->post(); } return; } numBytesSent += (size_t)n; } mPendingRequests.add(cseq, reply); }
void ARTSPConnection::onConnect(const sp<AMessage> &msg) { ++mConnectionID; if (mState != DISCONNECTED) { close(mSocket); mSocket = -1; flushPendingRequests(); } mState = CONNECTING; AString url; CHECK(msg->findString("url", &url)); sp<AMessage> reply; CHECK(msg->findMessage("reply", &reply)); AString host, path; unsigned port; if (!ParseURL(url.c_str(), &host, &port, &path)) { LOGE("Malformed rtsp url %s", url.c_str()); reply->setInt32("result", ERROR_MALFORMED); reply->post(); mState = DISCONNECTED; return; } struct hostent *ent = gethostbyname(host.c_str()); if (ent == NULL) { LOGE("Unknown host %s", host.c_str()); reply->setInt32("result", -ENOENT); reply->post(); mState = DISCONNECTED; return; } mSocket = socket(AF_INET, SOCK_STREAM, 0); MakeSocketBlocking(mSocket, false); struct sockaddr_in remote; memset(remote.sin_zero, 0, sizeof(remote.sin_zero)); remote.sin_family = AF_INET; remote.sin_addr.s_addr = *(in_addr_t *)ent->h_addr; remote.sin_port = htons(port); int err = ::connect( mSocket, (const struct sockaddr *)&remote, sizeof(remote)); reply->setInt32("server-ip", ntohl(remote.sin_addr.s_addr)); if (err < 0) { if (errno == EINPROGRESS) { sp<AMessage> msg = new AMessage(kWhatCompleteConnection, id()); msg->setMessage("reply", reply); msg->setInt32("connection-id", mConnectionID); msg->post(); return; } reply->setInt32("result", -errno); mState = DISCONNECTED; close(mSocket); mSocket = -1; } else { reply->setInt32("result", OK); mState = CONNECTED; mNextCSeq = 1; postReceiveReponseEvent(); } reply->post(); }
status_t DirectRenderer::DecoderContext::init( const sp<AMessage> &format, const sp<IGraphicBufferProducer> &surfaceTex) { CHECK(mDecoder == NULL); AString mime; CHECK(format->findString("mime", &mime)); mDecoderLooper = new ALooper; #ifdef MTK_AOSP_ENHANCEMENT if (!strncasecmp("video/", mime.c_str(), 6)) { mDecoderLooper->setName("video codec looper"); }else{ mDecoderLooper->setName("audio codec looper"); } #else mDecoderLooper->setName("video codec looper"); #endif #ifdef MTK_AOSP_ENHANCEMENT mDecoderLooper->start( false /* runOnCallingThread */, false /* canCallJava */, PRIORITY_AUDIO); #else mDecoderLooper->start( false /* runOnCallingThread */, false /* canCallJava */, PRIORITY_DEFAULT); #endif mDecoder = MediaCodec::CreateByType( mDecoderLooper, mime.c_str(), false /* encoder */); CHECK(mDecoder != NULL); #ifdef MTK_AOSP_ENHANCEMENT if (!strncasecmp("video/", mime.c_str(), 6)) { format->setInt32("vdec-no-record", 1); format->setInt32("vdec-lowlatency", 1); } #endif status_t err = mDecoder->configure( format, surfaceTex == NULL ? NULL : new Surface(surfaceTex), NULL /* crypto */, 0 /* flags */); CHECK_EQ(err, (status_t)OK); err = mDecoder->start(); CHECK_EQ(err, (status_t)OK); err = mDecoder->getInputBuffers( &mDecoderInputBuffers); CHECK_EQ(err, (status_t)OK); err = mDecoder->getOutputBuffers( &mDecoderOutputBuffers); CHECK_EQ(err, (status_t)OK); scheduleDecoderNotification(); #ifdef MTK_AOSP_ENHANCEMENT mFormat = format; #endif return OK; }
status_t WifiDisplaySource::onSetupRequest( int32_t sessionID, int32_t cseq, const sp<ParsedMessage> &data) { CHECK_EQ(sessionID, mClientSessionID); if (mClientInfo.mPlaybackSessionID != -1) { // We only support a single playback session per client. // This is due to the reversed keep-alive design in the wfd specs... sendErrorResponse(sessionID, "400 Bad Request", cseq); return ERROR_MALFORMED; } AString transport; if (!data->findString("transport", &transport)) { sendErrorResponse(sessionID, "400 Bad Request", cseq); return ERROR_MALFORMED; } RTPSender::TransportMode rtpMode = RTPSender::TRANSPORT_UDP; int clientRtp, clientRtcp; if (transport.startsWith("RTP/AVP/TCP;")) { AString interleaved; if (ParsedMessage::GetAttribute( transport.c_str(), "interleaved", &interleaved) && sscanf(interleaved.c_str(), "%d-%d", &clientRtp, &clientRtcp) == 2) { rtpMode = RTPSender::TRANSPORT_TCP_INTERLEAVED; } else { bool badRequest = false; AString clientPort; if (!ParsedMessage::GetAttribute( transport.c_str(), "client_port", &clientPort)) { badRequest = true; } else if (sscanf(clientPort.c_str(), "%d-%d", &clientRtp, &clientRtcp) == 2) { } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) { // No RTCP. clientRtcp = -1; } else { badRequest = true; } if (badRequest) { sendErrorResponse(sessionID, "400 Bad Request", cseq); return ERROR_MALFORMED; } rtpMode = RTPSender::TRANSPORT_TCP; } } else if (transport.startsWith("RTP/AVP;unicast;") || transport.startsWith("RTP/AVP/UDP;unicast;")) { bool badRequest = false; AString clientPort; if (!ParsedMessage::GetAttribute( transport.c_str(), "client_port", &clientPort)) { badRequest = true; } else if (sscanf(clientPort.c_str(), "%d-%d", &clientRtp, &clientRtcp) == 2) { } else if (sscanf(clientPort.c_str(), "%d", &clientRtp) == 1) { // No RTCP. clientRtcp = -1; } else { badRequest = true; } if (badRequest) { sendErrorResponse(sessionID, "400 Bad Request", cseq); return ERROR_MALFORMED; } #if 1 // The older LG dongles doesn't specify client_port=xxx apparently. } else if (transport == "RTP/AVP/UDP;unicast") { clientRtp = 19000; clientRtcp = -1; #endif } else { sendErrorResponse(sessionID, "461 Unsupported Transport", cseq); return ERROR_UNSUPPORTED; } int32_t playbackSessionID = makeUniquePlaybackSessionID(); sp<AMessage> notify = new AMessage(kWhatPlaybackSessionNotify, this); notify->setInt32("playbackSessionID", playbackSessionID); notify->setInt32("sessionID", sessionID); sp<PlaybackSession> playbackSession = new PlaybackSession( mOpPackageName, mNetSession, notify, mInterfaceAddr, mHDCP, mMediaPath.c_str()); looper()->registerHandler(playbackSession); AString uri; data->getRequestField(1, &uri); if (strncasecmp("rtsp://", uri.c_str(), 7)) { sendErrorResponse(sessionID, "400 Bad Request", cseq); return ERROR_MALFORMED; } if (!(uri.startsWith("rtsp://") && uri.endsWith("/wfd1.0/streamid=0"))) { sendErrorResponse(sessionID, "404 Not found", cseq); return ERROR_MALFORMED; } RTPSender::TransportMode rtcpMode = RTPSender::TRANSPORT_UDP; if (clientRtcp < 0) { rtcpMode = RTPSender::TRANSPORT_NONE; } status_t err = playbackSession->init( mClientInfo.mRemoteIP.c_str(), clientRtp, rtpMode, clientRtcp, rtcpMode, mSinkSupportsAudio, mUsingPCMAudio, mSinkSupportsVideo, mChosenVideoResolutionType, mChosenVideoResolutionIndex, mChosenVideoProfile, mChosenVideoLevel); if (err != OK) { looper()->unregisterHandler(playbackSession->id()); playbackSession.clear(); } switch (err) { case OK: break; case -ENOENT: sendErrorResponse(sessionID, "404 Not Found", cseq); return err; default: sendErrorResponse(sessionID, "403 Forbidden", cseq); return err; } mClientInfo.mPlaybackSessionID = playbackSessionID; mClientInfo.mPlaybackSession = playbackSession; AString response = "RTSP/1.0 200 OK\r\n"; AppendCommonResponse(&response, cseq, playbackSessionID); if (rtpMode == RTPSender::TRANSPORT_TCP_INTERLEAVED) { response.append( AStringPrintf( "Transport: RTP/AVP/TCP;interleaved=%d-%d;", clientRtp, clientRtcp)); } else { int32_t serverRtp = playbackSession->getRTPPort(); AString transportString = "UDP"; if (rtpMode == RTPSender::TRANSPORT_TCP) { transportString = "TCP"; } if (clientRtcp >= 0) { response.append( AStringPrintf( "Transport: RTP/AVP/%s;unicast;client_port=%d-%d;" "server_port=%d-%d\r\n", transportString.c_str(), clientRtp, clientRtcp, serverRtp, serverRtp + 1)); } else { response.append( AStringPrintf( "Transport: RTP/AVP/%s;unicast;client_port=%d;" "server_port=%d\r\n", transportString.c_str(), clientRtp, serverRtp)); } } response.append("\r\n"); err = mNetSession->sendRequest(sessionID, response.c_str()); if (err != OK) { return err; } mState = AWAITING_CLIENT_PLAY; scheduleReaper(); scheduleKeepAlive(sessionID); return OK; }
void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatStart: { sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); AString iface; CHECK(msg->findString("iface", &iface)); status_t err = OK; ssize_t colonPos = iface.find(":"); unsigned long port; if (colonPos >= 0) { const char *s = iface.c_str() + colonPos + 1; char *end; port = strtoul(s, &end, 10); if (end == s || *end != '\0' || port > 65535) { err = -EINVAL; } else { iface.erase(colonPos, iface.size() - colonPos); } } else { port = kWifiDisplayDefaultPort; } if (err == OK) { if (inet_aton(iface.c_str(), &mInterfaceAddr) != 0) { sp<AMessage> notify = new AMessage(kWhatRTSPNotify, this); err = mNetSession->createRTSPServer( mInterfaceAddr, port, notify, &mSessionID); } else { err = -EINVAL; } } mState = AWAITING_CLIENT_CONNECTION; sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatRTSPNotify: { int32_t reason; CHECK(msg->findInt32("reason", &reason)); switch (reason) { case ANetworkSession::kWhatError: { int32_t sessionID; CHECK(msg->findInt32("sessionID", &sessionID)); int32_t err; CHECK(msg->findInt32("err", &err)); AString detail; CHECK(msg->findString("detail", &detail)); ALOGE("An error occurred in session %d (%d, '%s/%s').", sessionID, err, detail.c_str(), strerror(-err)); mNetSession->destroySession(sessionID); if (sessionID == mClientSessionID) { mClientSessionID = 0; mClient->onDisplayError( IRemoteDisplayClient::kDisplayErrorUnknown); } break; } case ANetworkSession::kWhatClientConnected: { int32_t sessionID; CHECK(msg->findInt32("sessionID", &sessionID)); if (mClientSessionID > 0) { ALOGW("A client tried to connect, but we already " "have one."); mNetSession->destroySession(sessionID); break; } CHECK_EQ(mState, AWAITING_CLIENT_CONNECTION); CHECK(msg->findString("client-ip", &mClientInfo.mRemoteIP)); CHECK(msg->findString("server-ip", &mClientInfo.mLocalIP)); if (mClientInfo.mRemoteIP == mClientInfo.mLocalIP) { // Disallow connections from the local interface // for security reasons. mNetSession->destroySession(sessionID); break; } CHECK(msg->findInt32( "server-port", &mClientInfo.mLocalPort)); mClientInfo.mPlaybackSessionID = -1; mClientSessionID = sessionID; ALOGI("We now have a client (%d) connected.", sessionID); mState = AWAITING_CLIENT_SETUP; status_t err = sendM1(sessionID); CHECK_EQ(err, (status_t)OK); break; } case ANetworkSession::kWhatData: { status_t err = onReceiveClientData(msg); if (err != OK) { mClient->onDisplayError( IRemoteDisplayClient::kDisplayErrorUnknown); } #if 0 // testing only. char val[PROPERTY_VALUE_MAX]; if (property_get("media.wfd.trigger", val, NULL)) { if (!strcasecmp(val, "pause") && mState == PLAYING) { mState = PLAYING_TO_PAUSED; sendTrigger(mClientSessionID, TRIGGER_PAUSE); } else if (!strcasecmp(val, "play") && mState == PAUSED) { mState = PAUSED_TO_PLAYING; sendTrigger(mClientSessionID, TRIGGER_PLAY); } } #endif break; } case ANetworkSession::kWhatNetworkStall: { break; } default: TRESPASS(); } break; } case kWhatStop: { CHECK(msg->senderAwaitsResponse(&mStopReplyID)); CHECK_LT(mState, AWAITING_CLIENT_TEARDOWN); if (mState >= AWAITING_CLIENT_PLAY) { // We have a session, i.e. a previous SETUP succeeded. status_t err = sendTrigger( mClientSessionID, TRIGGER_TEARDOWN); if (err == OK) { mState = AWAITING_CLIENT_TEARDOWN; (new AMessage(kWhatTeardownTriggerTimedOut, this))->post( kTeardownTriggerTimeouSecs * 1000000ll); break; } // fall through. } finishStop(); break; } case kWhatPause: { sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); status_t err = OK; if (mState != PLAYING) { err = INVALID_OPERATION; } else { mState = PLAYING_TO_PAUSED; sendTrigger(mClientSessionID, TRIGGER_PAUSE); } sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatResume: { sp<AReplyToken> replyID; CHECK(msg->senderAwaitsResponse(&replyID)); status_t err = OK; if (mState != PAUSED) { err = INVALID_OPERATION; } else { mState = PAUSED_TO_PLAYING; sendTrigger(mClientSessionID, TRIGGER_PLAY); } sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatReapDeadClients: { mReaperPending = false; if (mClientSessionID == 0 || mClientInfo.mPlaybackSession == NULL) { break; } if (mClientInfo.mPlaybackSession->getLastLifesignUs() + kPlaybackSessionTimeoutUs < ALooper::GetNowUs()) { ALOGI("playback session timed out, reaping."); mNetSession->destroySession(mClientSessionID); mClientSessionID = 0; mClient->onDisplayError( IRemoteDisplayClient::kDisplayErrorUnknown); } else { scheduleReaper(); } break; } case kWhatPlaybackSessionNotify: { int32_t playbackSessionID; CHECK(msg->findInt32("playbackSessionID", &playbackSessionID)); int32_t what; CHECK(msg->findInt32("what", &what)); if (what == PlaybackSession::kWhatSessionDead) { ALOGI("playback session wants to quit."); mClient->onDisplayError( IRemoteDisplayClient::kDisplayErrorUnknown); } else if (what == PlaybackSession::kWhatSessionEstablished) { mPlaybackSessionEstablished = true; if (mClient != NULL) { if (!mSinkSupportsVideo) { mClient->onDisplayConnected( NULL, // SurfaceTexture 0, // width, 0, // height, mUsingHDCP ? IRemoteDisplayClient::kDisplayFlagSecure : 0, 0); } else { size_t width, height; CHECK(VideoFormats::GetConfiguration( mChosenVideoResolutionType, mChosenVideoResolutionIndex, &width, &height, NULL /* framesPerSecond */, NULL /* interlaced */)); mClient->onDisplayConnected( mClientInfo.mPlaybackSession ->getSurfaceTexture(), width, height, mUsingHDCP ? IRemoteDisplayClient::kDisplayFlagSecure : 0, playbackSessionID); } } finishPlay(); if (mState == ABOUT_TO_PLAY) { mState = PLAYING; } } else if (what == PlaybackSession::kWhatSessionDestroyed) { disconnectClient2(); } else { CHECK_EQ(what, PlaybackSession::kWhatBinaryData); int32_t channel; CHECK(msg->findInt32("channel", &channel)); sp<ABuffer> data; CHECK(msg->findBuffer("data", &data)); CHECK_LE(channel, 0xff); CHECK_LE(data->size(), 0xffffu); int32_t sessionID; CHECK(msg->findInt32("sessionID", &sessionID)); char header[4]; header[0] = '$'; header[1] = channel; header[2] = data->size() >> 8; header[3] = data->size() & 0xff; mNetSession->sendRequest( sessionID, header, sizeof(header)); mNetSession->sendRequest( sessionID, data->data(), data->size()); } break; } case kWhatKeepAlive: { int32_t sessionID; CHECK(msg->findInt32("sessionID", &sessionID)); if (mClientSessionID != sessionID) { // Obsolete event, client is already gone. break; } sendM16(sessionID); break; } case kWhatTeardownTriggerTimedOut: { if (mState == AWAITING_CLIENT_TEARDOWN) { ALOGI("TEARDOWN trigger timed out, forcing disconnection."); CHECK(mStopReplyID != NULL); finishStop(); break; } break; } case kWhatHDCPNotify: { int32_t msgCode, ext1, ext2; CHECK(msg->findInt32("msg", &msgCode)); CHECK(msg->findInt32("ext1", &ext1)); CHECK(msg->findInt32("ext2", &ext2)); ALOGI("Saw HDCP notification code %d, ext1 %d, ext2 %d", msgCode, ext1, ext2); switch (msgCode) { case HDCPModule::HDCP_INITIALIZATION_COMPLETE: { mHDCPInitializationComplete = true; if (mSetupTriggerDeferred) { mSetupTriggerDeferred = false; sendTrigger(mClientSessionID, TRIGGER_SETUP); } break; } case HDCPModule::HDCP_SHUTDOWN_COMPLETE: case HDCPModule::HDCP_SHUTDOWN_FAILED: { // Ugly hack to make sure that the call to // HDCPObserver::notify is completely handled before // we clear the HDCP instance and unload the shared // library :( (new AMessage(kWhatFinishStop2, this))->post(300000ll); break; } default: { ALOGE("HDCP failure, shutting down."); mClient->onDisplayError( IRemoteDisplayClient::kDisplayErrorUnknown); break; } } break; } case kWhatFinishStop2: { finishStop2(); break; } default: TRESPASS(); } }
void MediaFilter::onConfigureComponent(const sp<AMessage> &msg) { // TODO: generalize to allow audio filters as well as video CHECK_EQ(mState, INITIALIZED); // get params - at least mime, width & height AString mime; CHECK(msg->findString("mime", &mime)); if (strcasecmp(mime.c_str(), MEDIA_MIMETYPE_VIDEO_RAW)) { ALOGE("Bad mime: %s", mime.c_str()); signalError(BAD_VALUE); return; } CHECK(msg->findInt32("width", &mWidth)); CHECK(msg->findInt32("height", &mHeight)); if (!msg->findInt32("stride", &mStride)) { mStride = mWidth; } if (!msg->findInt32("slice-height", &mSliceHeight)) { mSliceHeight = mHeight; } mMaxInputSize = mWidth * mHeight * 4; // room for ARGB8888 int32_t maxInputSize; if (msg->findInt32("max-input-size", &maxInputSize) && (size_t)maxInputSize > mMaxInputSize) { mMaxInputSize = maxInputSize; } if (!msg->findInt32("color-format", &mColorFormatIn)) { // default to OMX_COLOR_Format32bitARGB8888 mColorFormatIn = OMX_COLOR_Format32bitARGB8888; msg->setInt32("color-format", mColorFormatIn); } mColorFormatOut = mColorFormatIn; mMaxOutputSize = mWidth * mHeight * 4; // room for ARGB8888 AString cacheDir; if (!msg->findString("cacheDir", &cacheDir)) { ALOGE("Failed to find cache directory in config message."); signalError(NAME_NOT_FOUND); return; } status_t err; err = mFilter->configure(msg); if (err != (status_t)OK) { ALOGE("Failed to configure filter component, err %d", err); signalError(err); return; } mInputFormat = new AMessage(); mInputFormat->setString("mime", mime.c_str()); mInputFormat->setInt32("stride", mStride); mInputFormat->setInt32("slice-height", mSliceHeight); mInputFormat->setInt32("color-format", mColorFormatIn); mInputFormat->setRect("crop", 0, 0, mStride, mSliceHeight); mInputFormat->setInt32("width", mWidth); mInputFormat->setInt32("height", mHeight); mOutputFormat = new AMessage(); mOutputFormat->setString("mime", mime.c_str()); mOutputFormat->setInt32("stride", mStride); mOutputFormat->setInt32("slice-height", mSliceHeight); mOutputFormat->setInt32("color-format", mColorFormatOut); mOutputFormat->setRect("crop", 0, 0, mStride, mSliceHeight); mOutputFormat->setInt32("width", mWidth); mOutputFormat->setInt32("height", mHeight); sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatComponentConfigured); notify->setString("componentName", "MediaFilter"); notify->setMessage("input-format", mInputFormat); notify->setMessage("output-format", mOutputFormat); notify->post(); mState = CONFIGURED; ALOGV("Handled kWhatConfigureComponent."); sendFormatChange(); }
void TimeSyncer::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatStartClient: { AString remoteHost; CHECK(msg->findString("remoteHost", &remoteHost)); int32_t remotePort; CHECK(msg->findInt32("remotePort", &remotePort)); sp<AMessage> notify = new AMessage(kWhatUDPNotify, id()); CHECK_EQ((status_t)OK, mNetSession->createUDPSession( 0 /* localPort */, remoteHost.c_str(), remotePort, notify, &mUDPSession)); postSendPacket(); break; } case kWhatStartServer: { mIsServer = true; int32_t localPort; CHECK(msg->findInt32("localPort", &localPort)); sp<AMessage> notify = new AMessage(kWhatUDPNotify, id()); CHECK_EQ((status_t)OK, mNetSession->createUDPSession( localPort, notify, &mUDPSession)); break; } case kWhatSendPacket: { if (mHistory.size() == 0) { ALOGI("starting batch"); } TimeInfo ti; memset(&ti, 0, sizeof(ti)); ti.mT1 = ALooper::GetNowUs(); CHECK_EQ((status_t)OK, mNetSession->sendRequest( mUDPSession, &ti, sizeof(ti))); mPendingT1 = ti.mT1; postTimeout(); break; } case kWhatTimedOut: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); if (generation != mTimeoutGeneration) { break; } ALOGI("timed out, sending another request"); postSendPacket(); break; } case kWhatUDPNotify: { int32_t reason; CHECK(msg->findInt32("reason", &reason)); switch (reason) { case ANetworkSession::kWhatError: { int32_t sessionID; CHECK(msg->findInt32("sessionID", &sessionID)); int32_t err; CHECK(msg->findInt32("err", &err)); AString detail; CHECK(msg->findString("detail", &detail)); ALOGE("An error occurred in session %d (%d, '%s/%s').", sessionID, err, detail.c_str(), strerror(-err)); mNetSession->destroySession(sessionID); cancelTimeout(); notifyError(err); break; } case ANetworkSession::kWhatDatagram: { int32_t sessionID; CHECK(msg->findInt32("sessionID", &sessionID)); sp<ABuffer> packet; CHECK(msg->findBuffer("data", &packet)); int64_t arrivalTimeUs; CHECK(packet->meta()->findInt64( "arrivalTimeUs", &arrivalTimeUs)); CHECK_EQ(packet->size(), sizeof(TimeInfo)); TimeInfo *ti = (TimeInfo *)packet->data(); if (mIsServer) { if (!mConnected) { AString fromAddr; CHECK(msg->findString("fromAddr", &fromAddr)); int32_t fromPort; CHECK(msg->findInt32("fromPort", &fromPort)); CHECK_EQ((status_t)OK, mNetSession->connectUDPSession( mUDPSession, fromAddr.c_str(), fromPort)); mConnected = true; } ti->mT2 = arrivalTimeUs; ti->mT3 = ALooper::GetNowUs(); CHECK_EQ((status_t)OK, mNetSession->sendRequest( mUDPSession, ti, sizeof(*ti))); } else { if (ti->mT1 != mPendingT1) { break; } cancelTimeout(); mPendingT1 = 0; ti->mT4 = arrivalTimeUs; // One way delay for a packet to travel from client // to server or back (assumed to be the same either way). int64_t delay = (ti->mT2 - ti->mT1 + ti->mT4 - ti->mT3) / 2; // Offset between the client clock (T1, T4) and the // server clock (T2, T3) timestamps. int64_t offset = (ti->mT2 - ti->mT1 - ti->mT4 + ti->mT3) / 2; mHistory.push_back(*ti); ALOGV("delay = %lld us,\toffset %lld us", delay, offset); if (mHistory.size() < kNumPacketsPerBatch) { postSendPacket(1000000ll / 30); } else { notifyOffset(); ALOGI("batch done"); mHistory.clear(); postSendPacket(kBatchDelayUs); } } break; } default: TRESPASS(); } break; } default: TRESPASS(); } }
void ARTSPConnection::onConnect(const sp<AMessage> &msg) { ++mConnectionID; if (mState != DISCONNECTED) { if (mUIDValid) { HTTPBase::UnRegisterSocketUserTag(mSocket); } close(mSocket); mSocket = -1; flushPendingRequests(); } mState = CONNECTING; AString url; CHECK(msg->findString("url", &url)); sp<AMessage> reply; CHECK(msg->findMessage("reply", &reply)); AString host, path; unsigned port; if (!ParseURL(url.c_str(), &host, &port, &path, &mUser, &mPass) || (mUser.size() > 0 && mPass.size() == 0)) { // If we have a user name but no password we have to give up // right here, since we currently have no way of asking the user // for this information. LOGE("Malformed rtsp url %s", url.c_str()); reply->setInt32("result", ERROR_MALFORMED); reply->post(); mState = DISCONNECTED; return; } if (mUser.size() > 0) { LOGV("user = '******', pass = '******'", mUser.c_str(), mPass.c_str()); } struct hostent *ent = gethostbyname(host.c_str()); if (ent == NULL) { LOGE("Unknown host %s", host.c_str()); reply->setInt32("result", -ENOENT); reply->post(); mState = DISCONNECTED; return; } mSocket = socket(AF_INET, SOCK_STREAM, 0); if (mUIDValid) { HTTPBase::RegisterSocketUserTag(mSocket, mUID, (uint32_t)*(uint32_t*) "RTSP"); } MakeSocketBlocking(mSocket, false); union { struct sockaddr_in remote; struct sockaddr remote_generic; }; memset(remote.sin_zero, 0, sizeof(remote.sin_zero)); remote.sin_family = AF_INET; remote.sin_addr.s_addr = *(in_addr_t *)ent->h_addr; remote.sin_port = htons(port); int err = ::connect( mSocket, &remote_generic, sizeof(remote)); reply->setInt32("server-ip", ntohl(remote.sin_addr.s_addr)); if (err < 0) { if (errno == EINPROGRESS) { sp<AMessage> msg = new AMessage(kWhatCompleteConnection, id()); msg->setMessage("reply", reply); msg->setInt32("connection-id", mConnectionID); msg->post(); return; } reply->setInt32("result", -errno); mState = DISCONNECTED; if (mUIDValid) { HTTPBase::UnRegisterSocketUserTag(mSocket); } close(mSocket); mSocket = -1; } else { reply->setInt32("result", OK); mState = CONNECTED; mNextCSeq = 1; postReceiveReponseEvent(); } reply->post(); }
void SimplePlayer::onMessageReceived(const sp<AMessage> &msg) { switch (msg->what()) { case kWhatSetDataSource: { status_t err; if (mState != UNINITIALIZED) { err = INVALID_OPERATION; } else { CHECK(msg->findString("path", &mPath)); mState = UNPREPARED; } uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatSetSurface: { status_t err; if (mState != UNPREPARED) { err = INVALID_OPERATION; } else { sp<RefBase> obj; CHECK(msg->findObject("native-window", &obj)); mNativeWindow = static_cast<NativeWindowWrapper *>(obj.get()); err = OK; } uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatPrepare: { status_t err; if (mState != UNPREPARED) { err = INVALID_OPERATION; } else { err = onPrepare(); if (err == OK) { mState = STOPPED; } } uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatStart: { status_t err = OK; if (mState == UNPREPARED) { err = onPrepare(); if (err == OK) { mState = STOPPED; } } if (err == OK) { if (mState != STOPPED) { err = INVALID_OPERATION; } else { err = onStart(); if (err == OK) { mState = STARTED; } } } uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatStop: { status_t err; if (mState != STARTED) { err = INVALID_OPERATION; } else { err = onStop(); if (err == OK) { mState = STOPPED; } } uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatReset: { status_t err = OK; if (mState == STARTED) { CHECK_EQ(onStop(), (status_t)OK); mState = STOPPED; } if (mState == STOPPED) { err = onReset(); mState = UNINITIALIZED; } uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); sp<AMessage> response = new AMessage; response->setInt32("err", err); response->postReply(replyID); break; } case kWhatDoMoreStuff: { int32_t generation; CHECK(msg->findInt32("generation", &generation)); if (generation != mDoMoreStuffGeneration) { break; } status_t err = onDoMoreStuff(); if (err == OK) { msg->post(10000ll); } break; } default: TRESPASS(); } }
void SDPLoader::onLoad(const sp<AMessage> &msg) { status_t err = OK; sp<ASessionDescription> desc = NULL; AString url; CHECK(msg->findString("url", &url)); KeyedVector<String8, String8> *headers = NULL; msg->findPointer("headers", (void **)&headers); if (!(mFlags & kFlagIncognito)) { ALOGI("onLoad '%s'", url.c_str()); } else { ALOGI("onLoad <URL suppressed>"); } if (!mCancelled) { err = mHTTPDataSource->connect(url.c_str(), headers); if (err != OK) { ALOGE("connect() returned %d", err); #ifndef ANDROID_DEFAULT_CODE if (err == ERROR_IO) { err = ERROR_CANNOT_CONNECT; ALOGE("reset err id from %d to %d for connect retry", ERROR_IO, ERROR_CANNOT_CONNECT); } #endif } } if (headers != NULL) { delete headers; headers = NULL; } off64_t sdpSize; if (err == OK && !mCancelled) { err = mHTTPDataSource->getSize(&sdpSize); if (err != OK) { //We did not get the size of the sdp file, default to a large value sdpSize = DEFAULT_SDP_SIZE; err = OK; } } sp<ABuffer> buffer = new ABuffer(sdpSize); if (err == OK && !mCancelled) { ssize_t readSize = mHTTPDataSource->readAt(0, buffer->data(), sdpSize); if (readSize < 0) { ALOGE("Failed to read SDP, error code = %ld", readSize); err = UNKNOWN_ERROR; } else { desc = new ASessionDescription; if (desc == NULL || !desc->setTo(buffer->data(), (size_t)readSize)) { err = UNKNOWN_ERROR; ALOGE("Failed to parse SDP"); } } } mHTTPDataSource.clear(); sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatSDPLoaded); notify->setInt32("result", err); notify->setObject("description", desc); notify->post(); }
void ARTSPConnection::onSendRequest(const sp<AMessage> &msg) { #ifndef ANDROID_DEFAULT_CODE int32_t backup; if (msg->findInt32("backup-keep-tcp", &backup)) { mForceQuitTCP = backup; } #endif sp<AMessage> reply; CHECK(msg->findMessage("reply", &reply)); if (mState != CONNECTED) { reply->setInt32("result", -ENOTCONN); reply->post(); return; } AString request; CHECK(msg->findString("request", &request)); // Just in case we need to re-issue the request with proper authentication // later, stash it away. reply->setString("original-request", request.c_str(), request.size()); #ifndef ANDROID_DEFAULT_CODE // mtk80902: ALPS01139972 - SETUP resp with a wrong Session "xxx\0\0\0.." // so the followed \r\n is ignored by find's strstr operation if (request.find("\r\n\r\n") < 0) { ALOGW("what the hell with this req?"); // seems print str is useless.. reply->setInt32("result", -EBADMSG); reply->post(); return; } #endif addAuthentication(&request); addUserAgent(&request); // Find the boundary between headers and the body. ssize_t i = request.find("\r\n\r\n"); CHECK_GE(i, 0); int32_t cseq = mNextCSeq++; AString cseqHeader = "CSeq: "; cseqHeader.append(cseq); cseqHeader.append("\r\n"); request.insert(cseqHeader, i + 2); #ifndef ANDROID_DEFAULT_CODE ALOGI("request: '%s'", request.c_str()); #else ALOGV("request: '%s'", request.c_str()); #endif size_t numBytesSent = 0; while (numBytesSent < request.size()) { ssize_t n = #ifndef ANDROID_DEFAULT_CODE send(mSocket, request.c_str() + numBytesSent, request.size() - numBytesSent, MTK_SEND_FLAG); #else send(mSocket, request.c_str() + numBytesSent, request.size() - numBytesSent, 0); #endif if (n < 0 && errno == EINTR) { continue; } if (n <= 0) { performDisconnect(); if (n == 0) { // Server closed the connection. ALOGE("Server unexpectedly closed the connection."); reply->setInt32("result", ERROR_IO); reply->post(); } else { ALOGE("Error sending rtsp request. (%s)", strerror(errno)); reply->setInt32("result", -errno); reply->post(); } return; } numBytesSent += (size_t)n; } mPendingRequests.add(cseq, reply); #ifndef ANDROID_DEFAULT_CODE sp<AMessage> timeout = new AMessage(kWhatTimeout, id()); timeout->setInt32("cseq", cseq); int64_t t; if (reply->findInt64("timeout", &t)) { timeout->post(t); } else { timeout->post(kRequestTimeout); } #endif // #ifndef ANDROID_DEFAULT_CODE }
void ARTSPConnection::onConnect(const sp<AMessage> &msg) { ++mConnectionID; if (mState != DISCONNECTED) { if (mUIDValid) { HTTPBase::UnRegisterSocketUserTag(mSocket); HTTPBase::UnRegisterSocketUserMark(mSocket); } close(mSocket); mSocket = -1; flushPendingRequests(); } mState = CONNECTING; AString url; CHECK(msg->findString("url", &url)); sp<AMessage> reply; CHECK(msg->findMessage("reply", &reply)); AString host, path; unsigned port; if (!ParseURL(url.c_str(), &host, &port, &path, &mUser, &mPass) || (mUser.size() > 0 && mPass.size() == 0)) { // If we have a user name but no password we have to give up // right here, since we currently have no way of asking the user // for this information. ALOGE("Malformed rtsp url %s", url.c_str()); reply->setInt32("result", ERROR_MALFORMED); reply->post(); mState = DISCONNECTED; return; } if (mUser.size() > 0) { ALOGV("user = '******', pass = '******'", mUser.c_str(), mPass.c_str()); } #ifndef ANDROID_DEFAULT_CODE if (!mProxyHost.empty()) { ALOGI("connect through proxy %s:%d", mProxyHost.c_str(), mProxyPort); host = mProxyHost; port = mProxyPort; } #endif // #ifndef ANDROID_DEFAULT_CODE struct hostent *ent = gethostbyname(host.c_str()); if (ent == NULL) { ALOGE("Unknown host %s", host.c_str()); #ifndef ANDROID_DEFAULT_CODE reply->setInt32("result", -EHOSTUNREACH); #else reply->setInt32("result", -ENOENT); #endif // #ifndef ANDROID_DEFAULT_CODE reply->post(); mState = DISCONNECTED; return; } mSocket = socket(AF_INET, SOCK_STREAM, 0); if (mUIDValid) { HTTPBase::RegisterSocketUserTag(mSocket, mUID, (uint32_t)*(uint32_t*) "RTSP"); HTTPBase::RegisterSocketUserMark(mSocket, mUID); } MakeSocketBlocking(mSocket, false); struct sockaddr_in remote; memset(remote.sin_zero, 0, sizeof(remote.sin_zero)); remote.sin_family = AF_INET; remote.sin_addr.s_addr = *(in_addr_t *)ent->h_addr; remote.sin_port = htons(port); #ifndef ANDROID_DEFAULT_CODE mRemote = remote; struct timeval tv; tv.tv_sec = kAccessUnitTimeoutUs / 1000000LL; tv.tv_usec = 0; if (setsockopt(mSocket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)) < 0) { ALOGE("can not set recv timeout"); reply->setInt32("result", -errno); mState = DISCONNECTED; close(mSocket); mSocket = -1; reply->post(); return; } ALOGI("connecting %s, %s:%d now", host.c_str(), inet_ntoa(remote.sin_addr), port); #endif // #ifndef ANDROID_DEFAULT_CODE int err = ::connect( mSocket, (const struct sockaddr *)&remote, sizeof(remote)); reply->setInt32("server-ip", ntohl(remote.sin_addr.s_addr)); if (err < 0) { if (errno == EINPROGRESS) { sp<AMessage> msg = new AMessage(kWhatCompleteConnection, id()); msg->setMessage("reply", reply); msg->setInt32("connection-id", mConnectionID); #ifndef ANDROID_DEFAULT_CODE msg->setInt64("timestamp", ALooper::GetNowUs()); ALOGI("connection EINPROGRESS"); #endif // #ifndef ANDROID_DEFAULT_CODE msg->post(); return; } reply->setInt32("result", -errno); mState = DISCONNECTED; if (mUIDValid) { HTTPBase::UnRegisterSocketUserTag(mSocket); HTTPBase::UnRegisterSocketUserMark(mSocket); } close(mSocket); mSocket = -1; } else { reply->setInt32("result", OK); mState = CONNECTED; mNextCSeq = 1; postReceiveReponseEvent(); } reply->post(); }