diff options
17 files changed, 692 insertions, 344 deletions
diff --git a/include/media/IRemoteDisplayClient.h b/include/media/IRemoteDisplayClient.h index 553ad36..252b401 100644 --- a/include/media/IRemoteDisplayClient.h +++ b/include/media/IRemoteDisplayClient.h @@ -59,8 +59,6 @@ public: // Indicates that a connection could not be established to the remote display // or an unrecoverable error occurred and the connection was severed. - // The media server should continue listening for connection attempts from the - // remote display. virtual void onDisplayError(int32_t error) = 0; // one-way }; diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp index f3f2d1e..2eae7df 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp @@ -1202,7 +1202,7 @@ void VirtualizerSetStrength(EffectContext *pContext, uint32_t strength){ //---------------------------------------------------------------------------- // EqualizerLimitBandLevels() //---------------------------------------------------------------------------- -// Purpose: limit all EQ band gains to a value less than MAX_BAND_GAIN_DB while +// Purpose: limit all EQ band gains to a value less than 0 dB while // preserving the relative band levels. // // Inputs: @@ -1214,7 +1214,6 @@ void VirtualizerSetStrength(EffectContext *pContext, uint32_t strength){ void EqualizerLimitBandLevels(EffectContext *pContext) { LVM_ControlParams_t ActiveParams; /* Current control Parameters */ LVM_ReturnStatus_en LvmStatus=LVM_SUCCESS; /* Function call status */ - LVM_EQNB_BandDef_t *BandDef; /* Get the current settings */ LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); @@ -1223,28 +1222,78 @@ void EqualizerLimitBandLevels(EffectContext *pContext) { //ALOGV("\tEqualizerLimitBandLevels just Got -> %d\n", // ActiveParams.pEQNB_BandDefinition[band].Gain); - int gainCorrection = 0; + // Apply a volume correction to avoid clipping in the EQ based on 2 factors: + // - the maximum EQ band gain: the volume correction is such that the total of volume + max + // band gain is <= 0 dB + // - the average gain in all bands weighted by their proximity to max gain band. + int maxGain = 0; + int avgGain = 0; + int avgCount = 0; for (int i = 0; i < FIVEBAND_NUMBANDS; i++) { - int level = pContext->pBundledContext->bandGaindB[i] + ActiveParams.VC_EffectLevel; - if (level > MAX_BAND_GAIN_DB) { - int correction = MAX_BAND_GAIN_DB -level; - if (correction < gainCorrection) { - gainCorrection = correction; + if (pContext->pBundledContext->bandGaindB[i] >= maxGain) { + int tmpMaxGain = pContext->pBundledContext->bandGaindB[i]; + int tmpAvgGain = 0; + int tmpAvgCount = 0; + for (int j = 0; j < FIVEBAND_NUMBANDS; j++) { + int gain = pContext->pBundledContext->bandGaindB[j]; + // skip current band and gains < 0 dB + if (j == i || gain < 0) + continue; + // no need to continue if one band not processed yet has a higher gain than current + // max + if (gain > tmpMaxGain) { + // force skipping "if (tmpAvgGain >= avgGain)" below as tmpAvgGain is not + // meaningful in this case + tmpAvgGain = -1; + break; + } + + int weight = 1; + if (j < (i + 2) && j > (i - 2)) + weight = 4; + tmpAvgGain += weight * gain; + tmpAvgCount += weight; + } + if (tmpAvgGain >= avgGain) { + maxGain = tmpMaxGain; + avgGain = tmpAvgGain; + avgCount = tmpAvgCount; } } + ActiveParams.pEQNB_BandDefinition[i].Frequency = EQNB_5BandPresetsFrequencies[i]; + ActiveParams.pEQNB_BandDefinition[i].QFactor = EQNB_5BandPresetsQFactors[i]; + ActiveParams.pEQNB_BandDefinition[i].Gain = pContext->pBundledContext->bandGaindB[i]; } - /* Set local EQ parameters */ - BandDef = ActiveParams.pEQNB_BandDefinition; - for (int i=0; i < FIVEBAND_NUMBANDS; i++) { - ActiveParams.pEQNB_BandDefinition[i].Gain = pContext->pBundledContext->bandGaindB[i] + - gainCorrection; + int gainCorrection = 0; + if (maxGain + pContext->pBundledContext->volume > 0) { + gainCorrection = maxGain + pContext->pBundledContext->volume; } + if (avgCount) { + gainCorrection += avgGain/avgCount; + } + + ALOGV("EqualizerLimitBandLevels() gainCorrection %d maxGain %d avgGain %d avgCount %d", + gainCorrection, maxGain, avgGain, avgCount); + + ActiveParams.VC_EffectLevel = pContext->pBundledContext->volume - gainCorrection; + if (ActiveParams.VC_EffectLevel < -96) { + ActiveParams.VC_EffectLevel = -96; + } + /* Activate the initial settings */ LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "EqualizerLimitBandLevels") //ALOGV("\tEqualizerLimitBandLevels just Set -> %d\n", // ActiveParams.pEQNB_BandDefinition[band].Gain); + + //ALOGV("\tEqualizerLimitBandLevels just set (-96dB -> 0dB) -> %d\n",ActiveParams.VC_EffectLevel ); + if(pContext->pBundledContext->firstVolume == LVM_TRUE){ + LvmStatus = LVM_SetVolumeNoSmoothing(pContext->pBundledContext->hInstance, &ActiveParams); + LVM_ERROR_CHECK(LvmStatus, "LVM_SetVolumeNoSmoothing", "LvmBundle_process") + ALOGV("\tLVM_VOLUME: Disabling Smoothing for first volume change to remove spikes/clicks"); + pContext->pBundledContext->firstVolume = LVM_FALSE; + } } @@ -1418,25 +1467,12 @@ void EqualizerSetPreset(EffectContext *pContext, int preset){ //ALOGV("\tEqualizerSetPreset(%d)", preset); pContext->pBundledContext->CurPreset = preset; - LVM_ControlParams_t ActiveParams; /* Current control Parameters */ - LVM_ReturnStatus_en LvmStatus=LVM_SUCCESS; /* Function call status */ - - /* Get the current settings */ - LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); - LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "EqualizerSetPreset") - //ALOGV("\tEqualizerSetPreset Succesfully returned from LVM_GetControlParameters\n"); - //ActiveParams.pEQNB_BandDefinition = &BandDefs[0]; for (int i=0; i<FIVEBAND_NUMBANDS; i++) { - ActiveParams.pEQNB_BandDefinition[i].Frequency = EQNB_5BandPresetsFrequencies[i]; - ActiveParams.pEQNB_BandDefinition[i].QFactor = EQNB_5BandPresetsQFactors[i]; pContext->pBundledContext->bandGaindB[i] = EQNB_5BandSoftPresets[i + preset * FIVEBAND_NUMBANDS]; } - /* Activate the new settings */ - LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); - LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "EqualizerSetPreset") EqualizerLimitBandLevels(pContext); @@ -1483,39 +1519,14 @@ const char * EqualizerGetPresetName(int32_t preset){ int VolumeSetVolumeLevel(EffectContext *pContext, int16_t level){ - LVM_ControlParams_t ActiveParams; /* Current control Parameters */ - LVM_ReturnStatus_en LvmStatus=LVM_SUCCESS; /* Function call status */ - - //ALOGV("\tVolumeSetVolumeLevel Level to be set is %d %d\n", level, (LVM_INT16)(level/100)); - /* Get the current settings */ - LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); - LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "VolumeSetVolumeLevel") - if(LvmStatus != LVM_SUCCESS) return -EINVAL; - //ALOGV("\tVolumeSetVolumeLevel Succesfully returned from LVM_GetControlParameters got: %d\n", - //ActiveParams.VC_EffectLevel); - - /* Volume parameters */ - ActiveParams.VC_EffectLevel = (LVM_INT16)(level/100); - //ALOGV("\tVolumeSetVolumeLevel() (-96dB -> 0dB) -> %d\n", ActiveParams.VC_EffectLevel ); - - /* Activate the initial settings */ - LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); - LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "VolumeSetVolumeLevel") - if(LvmStatus != LVM_SUCCESS) return -EINVAL; - - //ALOGV("\tVolumeSetVolumeLevel Succesfully called LVM_SetControlParameters\n"); - - /* Get the current settings */ - LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); - LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "VolumeSetVolumeLevel") - if(LvmStatus != LVM_SUCCESS) return -EINVAL; + if (level > 0 || level < -9600) { + return -EINVAL; + } - //ALOGV("\tVolumeSetVolumeLevel just set (-96dB -> 0dB) -> %d\n",ActiveParams.VC_EffectLevel ); - if(pContext->pBundledContext->firstVolume == LVM_TRUE){ - LvmStatus = LVM_SetVolumeNoSmoothing(pContext->pBundledContext->hInstance, &ActiveParams); - LVM_ERROR_CHECK(LvmStatus, "LVM_SetVolumeNoSmoothing", "LvmBundle_process") - ALOGV("\tLVM_VOLUME: Disabling Smoothing for first volume change to remove spikes/clicks"); - pContext->pBundledContext->firstVolume = LVM_FALSE; + if (pContext->pBundledContext->bMuteEnabled == LVM_TRUE) { + pContext->pBundledContext->levelSaved = level / 100; + } else { + pContext->pBundledContext->volume = level / 100; } EqualizerLimitBandLevels(pContext); @@ -1535,20 +1546,11 @@ int VolumeSetVolumeLevel(EffectContext *pContext, int16_t level){ int VolumeGetVolumeLevel(EffectContext *pContext, int16_t *level){ - //ALOGV("\tVolumeGetVolumeLevel start"); - - LVM_ControlParams_t ActiveParams; /* Current control Parameters */ - LVM_ReturnStatus_en LvmStatus = LVM_SUCCESS; /* Function call status */ - - LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); - LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "VolumeGetVolumeLevel") - if(LvmStatus != LVM_SUCCESS) return -EINVAL; - - //ALOGV("\tVolumeGetVolumeLevel() (-96dB -> 0dB) -> %d\n", ActiveParams.VC_EffectLevel ); - //ALOGV("\tVolumeGetVolumeLevel Succesfully returned from LVM_GetControlParameters\n"); - - *level = ActiveParams.VC_EffectLevel*100; // Convert dB to millibels - //ALOGV("\tVolumeGetVolumeLevel end"); + if (pContext->pBundledContext->bMuteEnabled == LVM_TRUE) { + *level = pContext->pBundledContext->levelSaved * 100; + } else { + *level = pContext->pBundledContext->volume * 100; + } return 0; } /* end VolumeGetVolumeLevel */ @@ -1568,32 +1570,16 @@ int32_t VolumeSetMute(EffectContext *pContext, uint32_t mute){ pContext->pBundledContext->bMuteEnabled = mute; - LVM_ControlParams_t ActiveParams; /* Current control Parameters */ - LVM_ReturnStatus_en LvmStatus=LVM_SUCCESS; /* Function call status */ - - /* Get the current settings */ - LvmStatus = LVM_GetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); - LVM_ERROR_CHECK(LvmStatus, "LVM_GetControlParameters", "VolumeSetMute") - if(LvmStatus != LVM_SUCCESS) return -EINVAL; - - //ALOGV("\tVolumeSetMute Succesfully returned from LVM_GetControlParameters\n"); - //ALOGV("\tVolumeSetMute to %d, level was %d\n", mute, ActiveParams.VC_EffectLevel ); - /* Set appropriate volume level */ if(pContext->pBundledContext->bMuteEnabled == LVM_TRUE){ - pContext->pBundledContext->levelSaved = ActiveParams.VC_EffectLevel; - ActiveParams.VC_EffectLevel = -96; + pContext->pBundledContext->levelSaved = pContext->pBundledContext->volume; + pContext->pBundledContext->volume = -96; }else{ - ActiveParams.VC_EffectLevel = pContext->pBundledContext->levelSaved; + pContext->pBundledContext->volume = pContext->pBundledContext->levelSaved; } - /* Activate the initial settings */ - LvmStatus = LVM_SetControlParameters(pContext->pBundledContext->hInstance, &ActiveParams); - LVM_ERROR_CHECK(LvmStatus, "LVM_SetControlParameters", "VolumeSetMute") - if(LvmStatus != LVM_SUCCESS) return -EINVAL; + EqualizerLimitBandLevels(pContext); - //ALOGV("\tVolumeSetMute Succesfully called LVM_SetControlParameters\n"); - //ALOGV("\tVolumeSetMute end"); return 0; } /* end setMute */ diff --git a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h index 9c58ecd..330bb32 100644 --- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h +++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.h @@ -38,7 +38,6 @@ extern "C" { #define VOLUME_CUP_LOAD_ARM9E 0 // Expressed in 0.1 MIPS #define BUNDLE_MEM_USAGE 25 // Expressed in kB //#define LVM_PCM -#define MAX_BAND_GAIN_DB 4 #ifndef OPENSL_ES_H_ static const effect_uuid_t SL_IID_VOLUME_ = { 0x09e8ede0, 0xddde, 0x11db, 0xb4f6, @@ -97,6 +96,7 @@ struct BundledEffectContext{ LVM_INT16 *workBuffer; int frameCount; int32_t bandGaindB[FIVEBAND_NUMBANDS]; + int volume; #ifdef LVM_PCM FILE *PcmInPtr; FILE *PcmOutPtr; diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp index dc1e351..1ddf775 100644 --- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp +++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp @@ -963,7 +963,8 @@ sp<AMessage> NuPlayer::Source::getFormat(bool audio) { status_t NuPlayer::setVideoScalingMode(int32_t mode) { mVideoScalingMode = mode; - if (mNativeWindow != NULL) { + if (mNativeWindow != NULL + && mNativeWindow->getNativeWindow() != NULL) { status_t ret = native_window_set_scaling_mode( mNativeWindow->getNativeWindow().get(), mVideoScalingMode); if (ret != OK) { diff --git a/media/libstagefright/wifi-display/ANetworkSession.cpp b/media/libstagefright/wifi-display/ANetworkSession.cpp index 435e72f..90db758 100644 --- a/media/libstagefright/wifi-display/ANetworkSession.cpp +++ b/media/libstagefright/wifi-display/ANetworkSession.cpp @@ -56,7 +56,8 @@ struct ANetworkSession::Session : public RefBase { enum State { CONNECTING, CONNECTED, - LISTENING, + LISTENING_RTSP, + LISTENING_TCP_DGRAMS, DATAGRAM, }; @@ -69,7 +70,8 @@ struct ANetworkSession::Session : public RefBase { int socket() const; sp<AMessage> getNotificationMessage() const; - bool isListening() const; + bool isRTSPServer() const; + bool isTCPDatagramServer() const; bool wantsToRead(); bool wantsToWrite(); @@ -79,12 +81,15 @@ struct ANetworkSession::Session : public RefBase { status_t sendRequest(const void *data, ssize_t size); + void setIsRTSPConnection(bool yesno); + protected: virtual ~Session(); private: int32_t mSessionID; State mState; + bool mIsRTSPConnection; int mSocket; sp<AMessage> mNotify; bool mSawReceiveFailure, mSawSendFailure; @@ -123,6 +128,7 @@ ANetworkSession::Session::Session( const sp<AMessage> ¬ify) : mSessionID(sessionID), mState(state), + mIsRTSPConnection(false), mSocket(s), mNotify(notify), mSawReceiveFailure(false), @@ -184,12 +190,20 @@ int ANetworkSession::Session::socket() const { return mSocket; } +void ANetworkSession::Session::setIsRTSPConnection(bool yesno) { + mIsRTSPConnection = yesno; +} + sp<AMessage> ANetworkSession::Session::getNotificationMessage() const { return mNotify; } -bool ANetworkSession::Session::isListening() const { - return mState == LISTENING; +bool ANetworkSession::Session::isRTSPServer() const { + return mState == LISTENING_RTSP; +} + +bool ANetworkSession::Session::isTCPDatagramServer() const { + return mState == LISTENING_TCP_DGRAMS; } bool ANetworkSession::Session::wantsToRead() { @@ -284,70 +298,93 @@ status_t ANetworkSession::Session::readMore() { err = -ECONNRESET; } - for (;;) { - size_t length; + if (!mIsRTSPConnection) { + // TCP stream carrying 16-bit length-prefixed datagrams. - if (mInBuffer.size() > 0 && mInBuffer.c_str()[0] == '$') { - if (mInBuffer.size() < 4) { - break; - } - - length = U16_AT((const uint8_t *)mInBuffer.c_str() + 2); + while (mInBuffer.size() >= 2) { + size_t packetSize = U16_AT((const uint8_t *)mInBuffer.c_str()); - if (mInBuffer.size() < 4 + length) { + if (mInBuffer.size() < packetSize + 2) { break; } + sp<ABuffer> packet = new ABuffer(packetSize); + memcpy(packet->data(), mInBuffer.c_str() + 2, packetSize); + sp<AMessage> notify = mNotify->dup(); notify->setInt32("sessionID", mSessionID); - notify->setInt32("reason", kWhatBinaryData); - notify->setInt32("channel", mInBuffer.c_str()[1]); + notify->setInt32("reason", kWhatDatagram); + notify->setBuffer("data", packet); + notify->post(); - sp<ABuffer> data = new ABuffer(length); - memcpy(data->data(), mInBuffer.c_str() + 4, length); + mInBuffer.erase(0, packetSize + 2); + } + } else { + for (;;) { + size_t length; - int64_t nowUs = ALooper::GetNowUs(); - data->meta()->setInt64("arrivalTimeUs", nowUs); + if (mInBuffer.size() > 0 && mInBuffer.c_str()[0] == '$') { + if (mInBuffer.size() < 4) { + break; + } - notify->setBuffer("data", data); - notify->post(); + length = U16_AT((const uint8_t *)mInBuffer.c_str() + 2); - mInBuffer.erase(0, 4 + length); - continue; - } + if (mInBuffer.size() < 4 + length) { + break; + } - sp<ParsedMessage> msg = - ParsedMessage::Parse( - mInBuffer.c_str(), mInBuffer.size(), err != OK, &length); + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("sessionID", mSessionID); + notify->setInt32("reason", kWhatBinaryData); + notify->setInt32("channel", mInBuffer.c_str()[1]); - if (msg == NULL) { - break; - } + sp<ABuffer> data = new ABuffer(length); + memcpy(data->data(), mInBuffer.c_str() + 4, length); - sp<AMessage> notify = mNotify->dup(); - notify->setInt32("sessionID", mSessionID); - notify->setInt32("reason", kWhatData); - notify->setObject("data", msg); - notify->post(); + int64_t nowUs = ALooper::GetNowUs(); + data->meta()->setInt64("arrivalTimeUs", nowUs); + + notify->setBuffer("data", data); + notify->post(); + + mInBuffer.erase(0, 4 + length); + continue; + } + + sp<ParsedMessage> msg = + ParsedMessage::Parse( + mInBuffer.c_str(), mInBuffer.size(), err != OK, &length); + + if (msg == NULL) { + break; + } + + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("sessionID", mSessionID); + notify->setInt32("reason", kWhatData); + notify->setObject("data", msg); + notify->post(); #if 1 - // XXX The (old) dongle sends the wrong content length header on a - // SET_PARAMETER request that signals a "wfd_idr_request". - // (17 instead of 19). - const char *content = msg->getContent(); - if (content - && !memcmp(content, "wfd_idr_request\r\n", 17) - && length >= 19 - && mInBuffer.c_str()[length] == '\r' - && mInBuffer.c_str()[length + 1] == '\n') { - length += 2; - } + // XXX The (old) dongle sends the wrong content length header on a + // SET_PARAMETER request that signals a "wfd_idr_request". + // (17 instead of 19). + const char *content = msg->getContent(); + if (content + && !memcmp(content, "wfd_idr_request\r\n", 17) + && length >= 19 + && mInBuffer.c_str()[length] == '\r' + && mInBuffer.c_str()[length + 1] == '\n') { + length += 2; + } #endif - mInBuffer.erase(0, length); + mInBuffer.erase(0, length); - if (err != OK) { - break; + if (err != OK) { + break; + } } } @@ -408,7 +445,7 @@ status_t ANetworkSession::Session::writeMore() { notifyError(kWhatError, -err, "Connection failed"); mSawSendFailure = true; - return UNKNOWN_ERROR; + return -err; } mState = CONNECTED; @@ -451,6 +488,16 @@ status_t ANetworkSession::Session::writeMore() { status_t ANetworkSession::Session::sendRequest(const void *data, ssize_t size) { CHECK(mState == CONNECTED || mState == DATAGRAM); + if (mState == CONNECTED && !mIsRTSPConnection) { + CHECK_LE(size, 65535); + + uint8_t prefix[2]; + prefix[0] = size >> 8; + prefix[1] = size & 0xff; + + mOutBuffer.append((const char *)prefix, sizeof(prefix)); + } + mOutBuffer.append( (const char *)data, (size >= 0) ? size : strlen((const char *)data)); @@ -585,6 +632,35 @@ status_t ANetworkSession::createUDPSession( sessionID); } +status_t ANetworkSession::createTCPDatagramSession( + const struct in_addr &addr, unsigned port, + const sp<AMessage> ¬ify, int32_t *sessionID) { + return createClientOrServer( + kModeCreateTCPDatagramSessionPassive, + &addr, + port, + NULL /* remoteHost */, + 0 /* remotePort */, + notify, + sessionID); +} + +status_t ANetworkSession::createTCPDatagramSession( + unsigned localPort, + const char *remoteHost, + unsigned remotePort, + const sp<AMessage> ¬ify, + int32_t *sessionID) { + return createClientOrServer( + kModeCreateTCPDatagramSessionActive, + NULL /* addr */, + localPort, + remoteHost, + remotePort, + notify, + sessionID); +} + status_t ANetworkSession::destroySession(int32_t sessionID) { Mutex::Autolock autoLock(mLock); @@ -641,7 +717,8 @@ status_t ANetworkSession::createClientOrServer( goto bail; } - if (mode == kModeCreateRTSPServer) { + if (mode == kModeCreateRTSPServer + || mode == kModeCreateTCPDatagramSessionPassive) { const int yes = 1; res = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); @@ -679,7 +756,8 @@ status_t ANetworkSession::createClientOrServer( memset(addr.sin_zero, 0, sizeof(addr.sin_zero)); addr.sin_family = AF_INET; - if (mode == kModeCreateRTSPClient) { + if (mode == kModeCreateRTSPClient + || mode == kModeCreateTCPDatagramSessionActive) { struct hostent *ent= gethostbyname(remoteHost); if (ent == NULL) { err = -h_errno; @@ -696,7 +774,17 @@ status_t ANetworkSession::createClientOrServer( addr.sin_port = htons(port); } - if (mode == kModeCreateRTSPClient) { + if (mode == kModeCreateRTSPClient + || mode == kModeCreateTCPDatagramSessionActive) { + in_addr_t x = ntohl(addr.sin_addr.s_addr); + ALOGI("connecting socket %d to %d.%d.%d.%d:%d", + s, + (x >> 24), + (x >> 16) & 0xff, + (x >> 8) & 0xff, + x & 0xff, + ntohs(addr.sin_port)); + res = connect(s, (const struct sockaddr *)&addr, sizeof(addr)); CHECK_LT(res, 0); @@ -707,7 +795,8 @@ status_t ANetworkSession::createClientOrServer( res = bind(s, (const struct sockaddr *)&addr, sizeof(addr)); if (res == 0) { - if (mode == kModeCreateRTSPServer) { + if (mode == kModeCreateRTSPServer + || mode == kModeCreateTCPDatagramSessionPassive) { res = listen(s, 4); } else { CHECK_EQ(mode, kModeCreateUDPSession); @@ -746,8 +835,16 @@ status_t ANetworkSession::createClientOrServer( state = Session::CONNECTING; break; + case kModeCreateTCPDatagramSessionActive: + state = Session::CONNECTING; + break; + + case kModeCreateTCPDatagramSessionPassive: + state = Session::LISTENING_TCP_DGRAMS; + break; + case kModeCreateRTSPServer: - state = Session::LISTENING; + state = Session::LISTENING_RTSP; break; default: @@ -762,6 +859,12 @@ status_t ANetworkSession::createClientOrServer( s, notify); + if (mode == kModeCreateTCPDatagramSessionActive) { + session->setIsRTSPConnection(false); + } else if (mode == kModeCreateRTSPClient) { + session->setIsRTSPConnection(true); + } + mSessions.add(session->sessionID(), session); interrupt(); @@ -797,7 +900,7 @@ status_t ANetworkSession::connectUDPSession( remoteAddr.sin_port = htons(remotePort); status_t err = OK; - struct hostent *ent= gethostbyname(remoteHost); + struct hostent *ent = gethostbyname(remoteHost); if (ent == NULL) { err = -h_errno; } else { @@ -932,7 +1035,7 @@ void ANetworkSession::threadLoop() { } if (FD_ISSET(s, &rs)) { - if (session->isListening()) { + if (session->isRTSPServer() || session->isTCPDatagramServer()) { struct sockaddr_in remoteAddr; socklen_t remoteAddrLen = sizeof(remoteAddr); @@ -969,6 +1072,9 @@ void ANetworkSession::threadLoop() { clientSocket, session->getNotificationMessage()); + clientSession->setIsRTSPConnection( + session->isRTSPServer()); + sessionsToAdd.push_back(clientSession); } } else { diff --git a/media/libstagefright/wifi-display/ANetworkSession.h b/media/libstagefright/wifi-display/ANetworkSession.h index 8d961ee..c1acdcc 100644 --- a/media/libstagefright/wifi-display/ANetworkSession.h +++ b/media/libstagefright/wifi-display/ANetworkSession.h @@ -58,6 +58,19 @@ struct ANetworkSession : public RefBase { status_t connectUDPSession( int32_t sessionID, const char *remoteHost, unsigned remotePort); + // passive + status_t createTCPDatagramSession( + const struct in_addr &addr, unsigned port, + const sp<AMessage> ¬ify, int32_t *sessionID); + + // active + status_t createTCPDatagramSession( + unsigned localPort, + const char *remoteHost, + unsigned remotePort, + const sp<AMessage> ¬ify, + int32_t *sessionID); + status_t destroySession(int32_t sessionID); status_t sendRequest( @@ -90,6 +103,8 @@ private: enum Mode { kModeCreateUDPSession, + kModeCreateTCPDatagramSessionPassive, + kModeCreateTCPDatagramSessionActive, kModeCreateRTSPServer, kModeCreateRTSPClient, }; diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp index f6f7030..e961518 100644 --- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp +++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp @@ -46,8 +46,8 @@ #include <OMX_IVCommon.h> -//#define FAKE_VIDEO 1 -#define USE_SERIALIZER 0 +//#define FAKE_VIDEO 1 +#define USE_SERIALIZER 0 namespace android { @@ -171,20 +171,26 @@ status_t WifiDisplaySource::PlaybackSession::Track::stop() { WifiDisplaySource::PlaybackSession::PlaybackSession( const sp<ANetworkSession> &netSession, const sp<AMessage> ¬ify, + const in_addr &interfaceAddr, bool legacyMode) : mNetSession(netSession), mNotify(notify), + mInterfaceAddr(interfaceAddr), mLegacyMode(legacyMode), mLastLifesignUs(), mVideoTrackIndex(-1), mTSQueue(new ABuffer(12 + kMaxNumTSPacketsPerRTPPacket * 188)), mPrevTimeUs(-1ll), - mUseInterleavedTCP(false), + mTransportMode(TRANSPORT_UDP), mRTPChannel(0), mRTCPChannel(0), mRTPPort(0), mRTPSessionID(0), mRTCPSessionID(0), + mClientRTPPort(0), + mClientRTCPPort(0), + mRTPConnected(false), + mRTCPConnected(false), mRTPSeqNo(0), mLastNTPTime(0), mLastRTPTime(0), @@ -208,15 +214,18 @@ WifiDisplaySource::PlaybackSession::PlaybackSession( status_t WifiDisplaySource::PlaybackSession::init( const char *clientIP, int32_t clientRtp, int32_t clientRtcp, - bool useInterleavedTCP) { + TransportMode transportMode) { + mClientIP = clientIP; + status_t err = setupPacketizer(); if (err != OK) { return err; } - if (useInterleavedTCP) { - mUseInterleavedTCP = true; + mTransportMode = transportMode; + + if (transportMode == TRANSPORT_TCP_INTERLEAVED) { mRTPChannel = clientRtp; mRTCPChannel = clientRtcp; mRTPPort = 0; @@ -227,19 +236,38 @@ status_t WifiDisplaySource::PlaybackSession::init( return OK; } - mUseInterleavedTCP = false; mRTPChannel = 0; mRTCPChannel = 0; + if (mTransportMode == TRANSPORT_TCP) { + // XXX This is wrong, we need to allocate sockets here, we only + // need to do this because the dongles are not establishing their + // end until after PLAY instead of before SETUP. + mRTPPort = 20000; + mRTPSessionID = 0; + mRTCPSessionID = 0; + mClientRTPPort = clientRtp; + mClientRTCPPort = clientRtcp; + + updateLiveness(); + return OK; + } + int serverRtp; sp<AMessage> rtpNotify = new AMessage(kWhatRTPNotify, id()); sp<AMessage> rtcpNotify = new AMessage(kWhatRTCPNotify, id()); for (serverRtp = 15550;; serverRtp += 2) { int32_t rtpSession; - err = mNetSession->createUDPSession( - serverRtp, clientIP, clientRtp, - rtpNotify, &rtpSession); + if (mTransportMode == TRANSPORT_UDP) { + err = mNetSession->createUDPSession( + serverRtp, clientIP, clientRtp, + rtpNotify, &rtpSession); + } else { + err = mNetSession->createTCPDatagramSession( + serverRtp, clientIP, clientRtp, + rtpNotify, &rtpSession); + } if (err != OK) { ALOGI("failed to create RTP socket on port %d", serverRtp); @@ -258,9 +286,15 @@ status_t WifiDisplaySource::PlaybackSession::init( } int32_t rtcpSession; - err = mNetSession->createUDPSession( - serverRtp + 1, clientIP, clientRtcp, - rtcpNotify, &rtcpSession); + if (mTransportMode == TRANSPORT_UDP) { + err = mNetSession->createUDPSession( + serverRtp + 1, clientIP, clientRtcp, + rtcpNotify, &rtcpSession); + } else { + err = mNetSession->createTCPDatagramSession( + serverRtp + 1, clientIP, clientRtcp, + rtcpNotify, &rtcpSession); + } if (err == OK) { mRTPPort = serverRtp; @@ -308,6 +342,42 @@ void WifiDisplaySource::PlaybackSession::updateLiveness() { status_t WifiDisplaySource::PlaybackSession::play() { updateLiveness(); + return OK; +} + +status_t WifiDisplaySource::PlaybackSession::finishPlay() { + // XXX Give the dongle 3 secs to bind its sockets. + (new AMessage(kWhatFinishPlay, id()))->post(3000000ll); + return OK; +} + +status_t WifiDisplaySource::PlaybackSession::onFinishPlay() { + if (mTransportMode != TRANSPORT_TCP) { + return onFinishPlay2(); + } + + sp<AMessage> rtpNotify = new AMessage(kWhatRTPNotify, id()); + + status_t err = mNetSession->createTCPDatagramSession( + mRTPPort, mClientIP.c_str(), mClientRTPPort, + rtpNotify, &mRTPSessionID); + + if (err != OK) { + return err; + } + + if (mClientRTCPPort >= 0) { + sp<AMessage> rtcpNotify = new AMessage(kWhatRTCPNotify, id()); + + err = mNetSession->createTCPDatagramSession( + mRTPPort + 1, mClientIP.c_str(), mClientRTCPPort, + rtcpNotify, &mRTCPSessionID); + } + + return err; +} + +status_t WifiDisplaySource::PlaybackSession::onFinishPlay2() { if (mRTCPSessionID != 0) { scheduleSendSR(); } @@ -328,6 +398,10 @@ status_t WifiDisplaySource::PlaybackSession::play() { } } + sp<AMessage> notify = mNotify->dup(); + notify->setInt32("what", kWhatSessionEstablished); + notify->post(); + return OK; } @@ -445,6 +519,32 @@ void WifiDisplaySource::PlaybackSession::onMessageReceived( break; } + case ANetworkSession::kWhatConnected: + { + CHECK_EQ(mTransportMode, TRANSPORT_TCP); + + int32_t sessionID; + CHECK(msg->findInt32("sessionID", &sessionID)); + + if (sessionID == mRTPSessionID) { + CHECK(!mRTPConnected); + mRTPConnected = true; + ALOGI("RTP Session now connected."); + } else if (sessionID == mRTCPSessionID) { + CHECK(!mRTCPConnected); + mRTCPConnected = true; + ALOGI("RTCP Session now connected."); + } else { + TRESPASS(); + } + + if (mRTPConnected + && (mClientRTCPPort < 0 || mRTCPConnected)) { + onFinishPlay2(); + } + break; + } + default: TRESPASS(); } @@ -610,6 +710,12 @@ void WifiDisplaySource::PlaybackSession::onMessageReceived( break; } + case kWhatFinishPlay: + { + onFinishPlay(); + break; + } + default: TRESPASS(); } @@ -956,15 +1062,14 @@ void WifiDisplaySource::PlaybackSession::onSendSR() { addSR(buffer); addSDES(buffer); - if (mUseInterleavedTCP) { + if (mTransportMode == TRANSPORT_TCP_INTERLEAVED) { sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatBinaryData); notify->setInt32("channel", mRTCPChannel); notify->setBuffer("data", buffer); notify->post(); } else { - mNetSession->sendRequest( - mRTCPSessionID, buffer->data(), buffer->size()); + sendPacket(mRTCPSessionID, buffer->data(), buffer->size()); } ++mNumSRsSent; @@ -1011,7 +1116,7 @@ ssize_t WifiDisplaySource::PlaybackSession::appendTSData( mLastRTPTime = rtpTime; mLastNTPTime = GetNowNTP(); - if (mUseInterleavedTCP) { + if (mTransportMode == TRANSPORT_TCP_INTERLEAVED) { sp<AMessage> notify = mNotify->dup(); notify->setInt32("what", kWhatBinaryData); @@ -1022,8 +1127,7 @@ ssize_t WifiDisplaySource::PlaybackSession::appendTSData( notify->setBuffer("data", data); notify->post(); } else { - mNetSession->sendRequest( - mRTPSessionID, rtp, mTSQueue->size()); + sendPacket(mRTPSessionID, rtp, mTSQueue->size()); mTotalBytesSent += mTSQueue->size(); int64_t delayUs = ALooper::GetNowUs() - mFirstPacketTimeUs; @@ -1144,8 +1248,7 @@ status_t WifiDisplaySource::PlaybackSession::parseTSFB( uint16_t bufferSeqNo = buffer->int32Data() & 0xffff; if (bufferSeqNo == seqNo) { - mNetSession->sendRequest( - mRTPSessionID, buffer->data(), buffer->size()); + sendPacket(mRTPSessionID, buffer->data(), buffer->size()); found = true; break; @@ -1172,5 +1275,10 @@ void WifiDisplaySource::PlaybackSession::requestIDRFrame() { } } +status_t WifiDisplaySource::PlaybackSession::sendPacket( + int32_t sessionID, const void *data, size_t size) { + return mNetSession->sendRequest(sessionID, data, size); +} + } // namespace android diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.h b/media/libstagefright/wifi-display/source/PlaybackSession.h index 8b6ddee..0047842 100644 --- a/media/libstagefright/wifi-display/source/PlaybackSession.h +++ b/media/libstagefright/wifi-display/source/PlaybackSession.h @@ -38,11 +38,17 @@ struct WifiDisplaySource::PlaybackSession : public AHandler { PlaybackSession( const sp<ANetworkSession> &netSession, const sp<AMessage> ¬ify, + const struct in_addr &interfaceAddr, bool legacyMode); + enum TransportMode { + TRANSPORT_UDP, + TRANSPORT_TCP_INTERLEAVED, + TRANSPORT_TCP, + }; status_t init( const char *clientIP, int32_t clientRtp, int32_t clientRtcp, - bool useInterleavedTCP); + TransportMode transportMode); status_t destroy(); @@ -52,6 +58,7 @@ struct WifiDisplaySource::PlaybackSession : public AHandler { void updateLiveness(); status_t play(); + status_t finishPlay(); status_t pause(); sp<ISurfaceTexture> getSurfaceTexture(); @@ -63,6 +70,7 @@ struct WifiDisplaySource::PlaybackSession : public AHandler { enum { kWhatSessionDead, kWhatBinaryData, + kWhatSessionEstablished, }; protected: @@ -79,6 +87,7 @@ private: kWhatSerializerNotify, kWhatConverterNotify, kWhatUpdateSurface, + kWhatFinishPlay, }; static const int64_t kSendSRIntervalUs = 10000000ll; @@ -87,6 +96,7 @@ private: sp<ANetworkSession> mNetSession; sp<AMessage> mNotify; + in_addr mInterfaceAddr; bool mLegacyMode; int64_t mLastLifesignUs; @@ -102,7 +112,9 @@ private: sp<ABuffer> mTSQueue; int64_t mPrevTimeUs; - bool mUseInterleavedTCP; + TransportMode mTransportMode; + + AString mClientIP; // in TCP mode int32_t mRTPChannel; @@ -113,6 +125,10 @@ private: int32_t mRTPSessionID; int32_t mRTCPSessionID; + int32_t mClientRTPPort; + int32_t mClientRTCPPort; + bool mRTPConnected; + bool mRTCPConnected; uint32_t mRTPSeqNo; @@ -160,6 +176,10 @@ private: status_t parseRTCP(const sp<ABuffer> &buffer); status_t parseTSFB(const uint8_t *data, size_t size); + status_t sendPacket(int32_t sessionID, const void *data, size_t size); + status_t onFinishPlay(); + status_t onFinishPlay2(); + DISALLOW_EVIL_CONSTRUCTORS(PlaybackSession); }; diff --git a/media/libstagefright/wifi-display/source/Serializer.cpp b/media/libstagefright/wifi-display/source/Serializer.cpp index 78dc4e6..598fd3e 100644 --- a/media/libstagefright/wifi-display/source/Serializer.cpp +++ b/media/libstagefright/wifi-display/source/Serializer.cpp @@ -286,8 +286,7 @@ status_t Serializer::onStart() { } if (err == OK) { - // XXX add a 5 second delay for the client to get ready. - schedulePoll(5000000ll); + schedulePoll(); } return err; diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp index 53adb87..8fead96 100644 --- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp +++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp @@ -31,7 +31,7 @@ #include <media/stagefright/MediaErrors.h> #include <arpa/inet.h> -#include <netinet/in.h> +#include <cutils/properties.h> namespace android { @@ -41,6 +41,7 @@ WifiDisplaySource::WifiDisplaySource( : mNetSession(netSession), mClient(client), mSessionID(0), + mClientSessionID(0), mReaperPending(false), mNextCSeq(1) { } @@ -114,14 +115,12 @@ void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { port = kWifiDisplayDefaultPort; } - struct in_addr addr; - if (err == OK) { - if (inet_aton(iface.c_str(), &addr) != 0) { + if (inet_aton(iface.c_str(), &mInterfaceAddr) != 0) { sp<AMessage> notify = new AMessage(kWhatRTSPNotify, id()); err = mNetSession->createRTSPServer( - addr, port, notify, &mSessionID); + mInterfaceAddr, port, notify, &mSessionID); } else { err = -EINVAL; } @@ -158,7 +157,11 @@ void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { mNetSession->destroySession(sessionID); - mClientInfos.removeItem(sessionID); + if (sessionID == mClientSessionID) { + mClientSessionID = -1; + + disconnectClient(UNKNOWN_ERROR); + } break; } @@ -167,15 +170,31 @@ void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { int32_t sessionID; CHECK(msg->findInt32("sessionID", &sessionID)); - ClientInfo info; - CHECK(msg->findString("client-ip", &info.mRemoteIP)); - CHECK(msg->findString("server-ip", &info.mLocalIP)); - CHECK(msg->findInt32("server-port", &info.mLocalPort)); - info.mPlaybackSessionID = -1; + if (mClientSessionID > 0) { + ALOGW("A client tried to connect, but we already " + "have one."); - ALOGI("We now have a client (%d) connected.", sessionID); + mNetSession->destroySession(sessionID); + break; + } + + 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; + } - mClientInfos.add(sessionID, info); + CHECK(msg->findInt32( + "server-port", &mClientInfo.mLocalPort)); + mClientInfo.mPlaybackSessionID = -1; + + mClientSessionID = sessionID; + + ALOGI("We now have a client (%d) connected.", sessionID); status_t err = sendM1(sessionID); CHECK_EQ(err, (status_t)OK); @@ -199,20 +218,7 @@ void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { uint32_t replyID; CHECK(msg->senderAwaitsResponse(&replyID)); - for (size_t i = mPlaybackSessions.size(); i-- > 0;) { - sp<PlaybackSession> playbackSession = - mPlaybackSessions.valueAt(i); - - mPlaybackSessions.removeItemsAt(i); - - playbackSession->destroy(); - looper()->unregisterHandler(playbackSession->id()); - playbackSession.clear(); - } - - if (mClient != NULL) { - mClient->onDisplayDisconnected(); - } + disconnectClient(OK); status_t err = OK; @@ -226,21 +232,17 @@ void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { { mReaperPending = false; - for (size_t i = mPlaybackSessions.size(); i-- > 0;) { - const sp<PlaybackSession> &playbackSession = - mPlaybackSessions.valueAt(i); - - if (playbackSession->getLastLifesignUs() - + kPlaybackSessionTimeoutUs < ALooper::GetNowUs()) { - ALOGI("playback session %d timed out, reaping.", - mPlaybackSessions.keyAt(i)); - - looper()->unregisterHandler(playbackSession->id()); - mPlaybackSessions.removeItemsAt(i); - } + if (mClientSessionID == 0 + || mClientInfo.mPlaybackSession == NULL) { + break; } - if (!mPlaybackSessions.isEmpty()) { + if (mClientInfo.mPlaybackSession->getLastLifesignUs() + + kPlaybackSessionTimeoutUs < ALooper::GetNowUs()) { + ALOGI("playback session timed out, reaping."); + + disconnectClient(-ETIMEDOUT); + } else { scheduleReaper(); } break; @@ -254,44 +256,44 @@ void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { int32_t what; CHECK(msg->findInt32("what", &what)); - ssize_t index = mPlaybackSessions.indexOfKey(playbackSessionID); - if (index >= 0) { - const sp<PlaybackSession> &playbackSession = - mPlaybackSessions.valueAt(index); - - if (what == PlaybackSession::kWhatSessionDead) { - ALOGI("playback sessions %d wants to quit.", - playbackSessionID); - - looper()->unregisterHandler(playbackSession->id()); - mPlaybackSessions.removeItemsAt(index); - } else { - CHECK_EQ(what, PlaybackSession::kWhatBinaryData); + if (what == PlaybackSession::kWhatSessionDead) { + ALOGI("playback session wants to quit."); + + disconnectClient(UNKNOWN_ERROR); + } else if (what == PlaybackSession::kWhatSessionEstablished) { + if (mClient != NULL) { + mClient->onDisplayConnected( + mClientInfo.mPlaybackSession->getSurfaceTexture(), + mClientInfo.mPlaybackSession->width(), + mClientInfo.mPlaybackSession->height(), + 0 /* flags */); + } + } else { + CHECK_EQ(what, PlaybackSession::kWhatBinaryData); - int32_t channel; - CHECK(msg->findInt32("channel", &channel)); + int32_t channel; + CHECK(msg->findInt32("channel", &channel)); - sp<ABuffer> data; - CHECK(msg->findBuffer("data", &data)); + sp<ABuffer> data; + CHECK(msg->findBuffer("data", &data)); - CHECK_LE(channel, 0xffu); - CHECK_LE(data->size(), 0xffffu); + CHECK_LE(channel, 0xffu); + CHECK_LE(data->size(), 0xffffu); - int32_t sessionID; - CHECK(msg->findInt32("sessionID", &sessionID)); + 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; + 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, header, sizeof(header)); - mNetSession->sendRequest( - sessionID, data->data(), data->size()); - } + mNetSession->sendRequest( + sessionID, data->data(), data->size()); } break; } @@ -301,7 +303,7 @@ void WifiDisplaySource::onMessageReceived(const sp<AMessage> &msg) { int32_t sessionID; CHECK(msg->findInt32("sessionID", &sessionID)); - if (mClientInfos.indexOfKey(sessionID) < 0) { + if (mClientSessionID != sessionID) { // Obsolete event, client is already gone. break; } @@ -392,15 +394,25 @@ status_t WifiDisplaySource::sendM4(int32_t sessionID) { // max-hres (none or 2 byte) // max-vres (none or 2 byte) - const ClientInfo &info = mClientInfos.valueFor(sessionID); + CHECK_EQ(sessionID, mClientSessionID); + + AString transportString = "UDP"; + + char val[PROPERTY_VALUE_MAX]; + if (property_get("media.wfd.enable-tcp", val, NULL) + && (!strcasecmp("true", val) || !strcmp("1", val))) { + ALOGI("Using TCP transport."); + transportString = "TCP"; + } AString body = StringPrintf( "wfd_video_formats: " "30 00 02 02 00000040 00000000 00000000 00 0000 0000 00 none none\r\n" "wfd_audio_codecs: AAC 00000001 00\r\n" // 2 ch AAC 48kHz "wfd_presentation_URL: rtsp://%s:%d/wfd1.0/streamid=0 none\r\n" - "wfd_client_rtp_ports: RTP/AVP/UDP;unicast 19000 0 mode=play\r\n", - info.mLocalIP.c_str(), info.mLocalPort); + "wfd_client_rtp_ports: RTP/AVP/%s;unicast 19000 0 mode=play\r\n", + mClientInfo.mLocalIP.c_str(), mClientInfo.mLocalPort, + transportString.c_str()); AString request = "SET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n"; AppendCommonResponse(&request, mNextCSeq); @@ -455,8 +467,9 @@ status_t WifiDisplaySource::sendM16(int32_t sessionID) { AString request = "GET_PARAMETER rtsp://localhost/wfd1.0 RTSP/1.0\r\n"; AppendCommonResponse(&request, mNextCSeq); - const ClientInfo &info = mClientInfos.valueFor(sessionID); - request.append(StringPrintf("Session: %d\r\n", info.mPlaybackSessionID)); + CHECK_EQ(sessionID, mClientSessionID); + request.append( + StringPrintf("Session: %d\r\n", mClientInfo.mPlaybackSessionID)); request.append("\r\n"); // Empty body status_t err = @@ -534,11 +547,10 @@ status_t WifiDisplaySource::onReceiveM16Response( int32_t sessionID, const sp<ParsedMessage> &msg) { // If only the response was required to include a "Session:" header... - const ClientInfo &info = mClientInfos.valueFor(sessionID); + CHECK_EQ(sessionID, mClientSessionID); - ssize_t index = mPlaybackSessions.indexOfKey(info.mPlaybackSessionID); - if (index >= 0) { - mPlaybackSessions.valueAt(index)->updateLiveness(); + if (mClientInfo.mPlaybackSession != NULL) { + mClientInfo.mPlaybackSession->updateLiveness(); scheduleKeepAlive(sessionID); } @@ -712,8 +724,8 @@ void WifiDisplaySource::onSetupRequest( int32_t sessionID, int32_t cseq, const sp<ParsedMessage> &data) { - ClientInfo *info = &mClientInfos.editValueFor(sessionID); - if (info->mPlaybackSessionID != -1) { + 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); @@ -726,20 +738,40 @@ void WifiDisplaySource::onSetupRequest( return; } - bool useInterleavedTCP = false; + PlaybackSession::TransportMode transportMode = + PlaybackSession::TRANSPORT_UDP; int clientRtp, clientRtcp; if (transport.startsWith("RTP/AVP/TCP;")) { AString interleaved; - if (!ParsedMessage::GetAttribute( + if (ParsedMessage::GetAttribute( transport.c_str(), "interleaved", &interleaved) - || sscanf(interleaved.c_str(), "%d-%d", - &clientRtp, &clientRtcp) != 2) { - sendErrorResponse(sessionID, "400 Bad Request", cseq); - return; - } + && sscanf(interleaved.c_str(), "%d-%d", + &clientRtp, &clientRtcp) == 2) { + transportMode = PlaybackSession::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; + } - useInterleavedTCP = true; + transportMode = PlaybackSession::TRANSPORT_TCP; + } } else if (transport.startsWith("RTP/AVP;unicast;") || transport.startsWith("RTP/AVP/UDP;unicast;")) { bool badRequest = false; @@ -780,7 +812,8 @@ void WifiDisplaySource::onSetupRequest( sp<PlaybackSession> playbackSession = new PlaybackSession( - mNetSession, notify, mClient == NULL /* legacyMode */); + mNetSession, notify, mInterfaceAddr, + mClient == NULL /* legacyMode */); looper()->registerHandler(playbackSession); @@ -798,10 +831,10 @@ void WifiDisplaySource::onSetupRequest( } status_t err = playbackSession->init( - info->mRemoteIP.c_str(), + mClientInfo.mRemoteIP.c_str(), clientRtp, clientRtcp, - useInterleavedTCP); + transportMode); if (err != OK) { looper()->unregisterHandler(playbackSession->id()); @@ -819,14 +852,13 @@ void WifiDisplaySource::onSetupRequest( return; } - mPlaybackSessions.add(playbackSessionID, playbackSession); - - info->mPlaybackSessionID = playbackSessionID; + mClientInfo.mPlaybackSessionID = playbackSessionID; + mClientInfo.mPlaybackSession = playbackSession; AString response = "RTSP/1.0 200 OK\r\n"; AppendCommonResponse(&response, cseq, playbackSessionID); - if (useInterleavedTCP) { + if (transportMode == PlaybackSession::TRANSPORT_TCP_INTERLEAVED) { response.append( StringPrintf( "Transport: RTP/AVP/TCP;interleaved=%d-%d;", @@ -834,17 +866,24 @@ void WifiDisplaySource::onSetupRequest( } else { int32_t serverRtp = playbackSession->getRTPPort(); + AString transportString = "UDP"; + if (transportMode == PlaybackSession::TRANSPORT_TCP) { + transportString = "TCP"; + } + if (clientRtcp >= 0) { response.append( StringPrintf( - "Transport: RTP/AVP;unicast;client_port=%d-%d;" + "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( StringPrintf( - "Transport: RTP/AVP;unicast;client_port=%d;" + "Transport: RTP/AVP/%s;unicast;client_port=%d;" "server_port=%d\r\n", + transportString.c_str(), clientRtp, serverRtp)); } } @@ -882,13 +921,7 @@ void WifiDisplaySource::onPlayRequest( err = mNetSession->sendRequest(sessionID, response.c_str()); CHECK_EQ(err, (status_t)OK); - if (mClient != NULL) { - mClient->onDisplayConnected( - playbackSession->getSurfaceTexture(), - playbackSession->width(), - playbackSession->height(), - 0 /* flags */); - } + playbackSession->finishPlay(); } void WifiDisplaySource::onPauseRequest( @@ -928,15 +961,15 @@ void WifiDisplaySource::onTeardownRequest( return; } - looper()->unregisterHandler(playbackSession->id()); - mPlaybackSessions.removeItem(playbackSessionID); - AString response = "RTSP/1.0 200 OK\r\n"; AppendCommonResponse(&response, cseq, playbackSessionID); + response.append("Connection: close\r\n"); response.append("\r\n"); status_t err = mNetSession->sendRequest(sessionID, response.c_str()); CHECK_EQ(err, (status_t)OK); + + disconnectClient(UNKNOWN_ERROR); } void WifiDisplaySource::onGetParameterRequest( @@ -970,19 +1003,10 @@ void WifiDisplaySource::onSetParameterRequest( sp<PlaybackSession> playbackSession = findPlaybackSession(data, &playbackSessionID); -#if 1 - // XXX the older dongles do not include a "Session:" header in this request. - if (playbackSession == NULL) { - CHECK_EQ(mPlaybackSessions.size(), 1u); - playbackSessionID = mPlaybackSessions.keyAt(0); - playbackSession = mPlaybackSessions.valueAt(0); - } -#else if (playbackSession == NULL) { sendErrorResponse(sessionID, "454 Session Not Found", cseq); return; } -#endif // XXX check that the parameter is about that. playbackSession->requestIDRFrame(); @@ -1041,37 +1065,42 @@ void WifiDisplaySource::sendErrorResponse( } int32_t WifiDisplaySource::makeUniquePlaybackSessionID() const { - for (;;) { - int32_t playbackSessionID = rand(); - - if (playbackSessionID == -1) { - // reserved. - continue; - } - - for (size_t i = 0; i < mPlaybackSessions.size(); ++i) { - if (mPlaybackSessions.keyAt(i) == playbackSessionID) { - continue; - } - } - - return playbackSessionID; - } + return rand(); } sp<WifiDisplaySource::PlaybackSession> WifiDisplaySource::findPlaybackSession( const sp<ParsedMessage> &data, int32_t *playbackSessionID) const { if (!data->findInt32("session", playbackSessionID)) { - *playbackSessionID = 0; - return NULL; + // XXX the older dongles do not always include a "Session:" header. + *playbackSessionID = mClientInfo.mPlaybackSessionID; + return mClientInfo.mPlaybackSession; } - ssize_t index = mPlaybackSessions.indexOfKey(*playbackSessionID); - if (index < 0) { + if (*playbackSessionID != mClientInfo.mPlaybackSessionID) { return NULL; } - return mPlaybackSessions.valueAt(index); + return mClientInfo.mPlaybackSession; +} + +void WifiDisplaySource::disconnectClient(status_t err) { + if (mClientSessionID != 0) { + if (mClientInfo.mPlaybackSession != NULL) { + looper()->unregisterHandler(mClientInfo.mPlaybackSession->id()); + mClientInfo.mPlaybackSession.clear(); + } + + mNetSession->destroySession(mClientSessionID); + mClientSessionID = 0; + } + + if (mClient != NULL) { + if (err != OK) { + mClient->onDisplayError(IRemoteDisplayClient::kDisplayErrorUnknown); + } else { + mClient->onDisplayDisconnected(); + } + } } } // namespace android diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h index 99eb4f5..3c8d50f 100644 --- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h +++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h @@ -22,6 +22,8 @@ #include <media/stagefright/foundation/AHandler.h> +#include <netinet/in.h> + namespace android { struct IRemoteDisplayClient; @@ -78,16 +80,19 @@ private: sp<ANetworkSession> mNetSession; sp<IRemoteDisplayClient> mClient; + struct in_addr mInterfaceAddr; int32_t mSessionID; + int32_t mClientSessionID; + struct ClientInfo { AString mRemoteIP; AString mLocalIP; int32_t mLocalPort; int32_t mPlaybackSessionID; + sp<PlaybackSession> mPlaybackSession; }; - // by sessionID. - KeyedVector<int32_t, ClientInfo> mClientInfos; + ClientInfo mClientInfo; bool mReaperPending; @@ -95,8 +100,6 @@ private: KeyedVector<ResponseID, HandleRTSPResponseFunc> mResponseHandlers; - KeyedVector<int32_t, sp<PlaybackSession> > mPlaybackSessions; - status_t sendM1(int32_t sessionID); status_t sendM3(int32_t sessionID); status_t sendM4(int32_t sessionID); @@ -179,6 +182,12 @@ private: sp<PlaybackSession> findPlaybackSession( const sp<ParsedMessage> &data, int32_t *playbackSessionID) const; + // Disconnects the current client and shuts down its playback session + // (if any). The reason for the disconnection is OK for orderly shutdown + // or a nonzero error code. + // A listener is notified accordingly. + void disconnectClient(status_t err); + DISALLOW_EVIL_CONSTRUCTORS(WifiDisplaySource); }; diff --git a/services/camera/libcameraservice/Camera2Client.cpp b/services/camera/libcameraservice/Camera2Client.cpp index eb72412..4fad83e 100644 --- a/services/camera/libcameraservice/Camera2Client.cpp +++ b/services/camera/libcameraservice/Camera2Client.cpp @@ -345,6 +345,8 @@ status_t Camera2Client::dump(int fd, const Vector<String16>& args) { mFrameProcessor->dump(fd, args); + mZslProcessor->dump(fd, args); + result = " Device dump:\n"; write(fd, result.string(), result.size()); diff --git a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp b/services/camera/libcameraservice/camera2/CaptureSequencer.cpp index 678f114..eb9eb5b 100644 --- a/services/camera/libcameraservice/camera2/CaptureSequencer.cpp +++ b/services/camera/libcameraservice/camera2/CaptureSequencer.cpp @@ -274,8 +274,14 @@ CaptureSequencer::CaptureState CaptureSequencer::manageZslStart( // TODO: Actually select the right thing here. res = processor->pushToReprocess(mCaptureId); if (res != OK) { - ALOGW("%s: Camera %d: Failed to use ZSL queue, falling back to standard capture", - __FUNCTION__, client->getCameraId()); + if (res == NOT_ENOUGH_DATA) { + ALOGV("%s: Camera %d: ZSL queue doesn't have good frame, " + "falling back to normal capture", __FUNCTION__, + client->getCameraId()); + } else { + ALOGE("%s: Camera %d: Error in ZSL queue: %s (%d)", + __FUNCTION__, client->getCameraId(), strerror(-res), res); + } return STANDARD_START; } @@ -410,7 +416,8 @@ CaptureSequencer::CaptureState CaptureSequencer::manageStandardCapture( return DONE; } - if (l.mParameters.playShutterSound) { + if (l.mParameters.playShutterSound && + l.mParameters.state == Parameters::STILL_CAPTURE) { client->getCameraService()->playSound(CameraService::SOUND_SHUTTER); } diff --git a/services/camera/libcameraservice/camera2/FrameProcessor.cpp b/services/camera/libcameraservice/camera2/FrameProcessor.cpp index e24db0b..a7d19aa 100644 --- a/services/camera/libcameraservice/camera2/FrameProcessor.cpp +++ b/services/camera/libcameraservice/camera2/FrameProcessor.cpp @@ -174,8 +174,7 @@ status_t FrameProcessor::processFaceDetect(const CameraMetadata &frame, SharedParameters::Lock l(client->getParameters()); entry = frame.find(ANDROID_STATS_FACE_RECTANGLES); if (entry.count == 0) { - ALOGE("%s: Camera %d: Unable to read face rectangles", - __FUNCTION__, client->getCameraId()); + // No faces this frame return res; } metadata.number_of_faces = entry.count / 4; @@ -220,7 +219,13 @@ status_t FrameProcessor::processFaceDetect(const CameraMetadata &frame, faces.setCapacity(metadata.number_of_faces); - for (int i = 0; i < metadata.number_of_faces; i++) { + size_t maxFaces = metadata.number_of_faces; + for (size_t i = 0; i < maxFaces; i++) { + if (faceScores[i] == 0) { + metadata.number_of_faces--; + continue; + } + camera_face_t face; face.rect[0] = l.mParameters.arrayXToNormalized(faceRects[i*4 + 0]); diff --git a/services/camera/libcameraservice/camera2/Parameters.cpp b/services/camera/libcameraservice/camera2/Parameters.cpp index c07a6ac..0a72c5f 100644 --- a/services/camera/libcameraservice/camera2/Parameters.cpp +++ b/services/camera/libcameraservice/camera2/Parameters.cpp @@ -750,12 +750,12 @@ status_t Parameters::initialize(const CameraMetadata *info) { previewCallbackFlags = 0; char value[PROPERTY_VALUE_MAX]; - property_get("camera.zsl_mode", value, "0"); + property_get("camera.disable_zsl_mode", value, "0"); if (!strcmp(value,"1")) { - ALOGI("Camera %d: Enabling ZSL mode", cameraId); - zslMode = true; - } else { + ALOGI("Camera %d: Disabling ZSL mode", cameraId); zslMode = false; + } else { + zslMode = true; } lightFx = LIGHTFX_NONE; @@ -1380,8 +1380,11 @@ status_t Parameters::updateRequest(CameraMetadata *request) const { &reqControlMode, 1); if (res != OK) return res; - uint8_t reqSceneMode = enableFaceDetect ? - (uint8_t)ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY : sceneMode; + uint8_t reqSceneMode = + (sceneMode != + (uint8_t)ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED) ? sceneMode : + enableFaceDetect ? (uint8_t)ANDROID_CONTROL_SCENE_MODE_FACE_PRIORITY : + (uint8_t)ANDROID_CONTROL_SCENE_MODE_UNSUPPORTED; res = request->update(ANDROID_CONTROL_SCENE_MODE, &reqSceneMode, 1); if (res != OK) return res; diff --git a/services/camera/libcameraservice/camera2/ZslProcessor.cpp b/services/camera/libcameraservice/camera2/ZslProcessor.cpp index f17b5d3..8906cd7 100644 --- a/services/camera/libcameraservice/camera2/ZslProcessor.cpp +++ b/services/camera/libcameraservice/camera2/ZslProcessor.cpp @@ -87,12 +87,14 @@ void ZslProcessor::onFrameAvailable(int32_t frameId, CameraMetadata &frame) { void ZslProcessor::onBufferReleased(buffer_handle_t *handle) { Mutex::Autolock l(mInputMutex); - buffer_handle_t *expectedHandle = - &(mZslQueue[mZslQueueTail].buffer.mGraphicBuffer->handle); - - if (handle != expectedHandle) { - ALOGE("%s: Expected buffer %p, got buffer %p", - __FUNCTION__, expectedHandle, handle); + // Verify that the buffer is in our queue + size_t i = 0; + for (; i < mZslQueue.size(); i++) { + if (&(mZslQueue[i].buffer.mGraphicBuffer->handle) == handle) break; + } + if (i == mZslQueue.size()) { + ALOGW("%s: Released buffer %p not found in queue", + __FUNCTION__, handle); } mState = RUNNING; @@ -232,7 +234,12 @@ status_t ZslProcessor::pushToReprocess(int32_t requestId) { status_t res; sp<Camera2Client> client = mClient.promote(); - if (client == 0) return false; + if (client == 0) return INVALID_OPERATION; + + IF_ALOGV() { + dumpZslQueue(-1); + } + if (mZslQueueTail != mZslQueueHead) { CameraMetadata request; @@ -242,9 +249,26 @@ status_t ZslProcessor::pushToReprocess(int32_t requestId) { index = (index + 1) % kZslBufferDepth; } if (request.isEmpty()) { - ALOGE("No request in ZSL queue to send!"); + ALOGV("%s: ZSL queue has no valid frames to send yet.", + __FUNCTION__); + return NOT_ENOUGH_DATA; + } + // Verify that the frame is reasonable for reprocessing + + camera_metadata_entry_t entry; + entry = request.find(ANDROID_CONTROL_AE_STATE); + if (entry.count == 0) { + ALOGE("%s: ZSL queue frame has no AE state field!", + __FUNCTION__); return BAD_VALUE; } + if (entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_CONVERGED && + entry.data.u8[0] != ANDROID_CONTROL_AE_STATE_LOCKED) { + ALOGV("%s: ZSL queue frame AE state is %d, need full capture", + __FUNCTION__, entry.data.u8[0]); + return NOT_ENOUGH_DATA; + } + buffer_handle_t *handle = &(mZslQueue[index].buffer.mGraphicBuffer->handle); @@ -282,13 +306,15 @@ status_t ZslProcessor::pushToReprocess(int32_t requestId) { mState = LOCKED; } else { - ALOGE("%s: Nothing to push", __FUNCTION__); - return BAD_VALUE; + ALOGV("%s: No ZSL buffers yet", __FUNCTION__); + return NOT_ENOUGH_DATA; } return OK; } void ZslProcessor::dump(int fd, const Vector<String16>& args) const { + Mutex::Autolock l(mInputMutex); + dumpZslQueue(fd); } bool ZslProcessor::threadLoop() { @@ -413,5 +439,37 @@ void ZslProcessor::findMatchesLocked() { } } +void ZslProcessor::dumpZslQueue(int fd) const { + String8 header("ZSL queue contents:"); + String8 indent(" "); + ALOGV("%s", header.string()); + if (fd != -1) { + header = indent + header + "\n"; + write(fd, header.string(), header.size()); + } + for (size_t i = 0; i < mZslQueue.size(); i++) { + const ZslPair &queueEntry = mZslQueue[i]; + nsecs_t bufferTimestamp = queueEntry.buffer.mTimestamp; + camera_metadata_ro_entry_t entry; + nsecs_t frameTimestamp = 0; + int frameAeState = -1; + if (!queueEntry.frame.isEmpty()) { + entry = queueEntry.frame.find(ANDROID_SENSOR_TIMESTAMP); + if (entry.count > 0) frameTimestamp = entry.data.i64[0]; + entry = queueEntry.frame.find(ANDROID_CONTROL_AE_STATE); + if (entry.count > 0) frameAeState = entry.data.u8[0]; + } + String8 result = + String8::format(" %d: b: %lld\tf: %lld, AE state: %d", i, + bufferTimestamp, frameTimestamp, frameAeState); + ALOGV("%s", result.string()); + if (fd != -1) { + result = indent + result + "\n"; + write(fd, result.string(), result.size()); + } + + } +} + }; // namespace camera2 }; // namespace android diff --git a/services/camera/libcameraservice/camera2/ZslProcessor.h b/services/camera/libcameraservice/camera2/ZslProcessor.h index b60f61b..268f4f5 100644 --- a/services/camera/libcameraservice/camera2/ZslProcessor.h +++ b/services/camera/libcameraservice/camera2/ZslProcessor.h @@ -110,6 +110,8 @@ class ZslProcessor: // Match up entries from frame list to buffers in ZSL queue void findMatchesLocked(); + + void dumpZslQueue(int id) const; }; |