Merge "ProCamera: Fix memory leak in consumeFrameMetadata" into jb-mr2-dev
diff --git a/include/media/ICrypto.h b/include/media/ICrypto.h
index 61059bd..9dcb8d9 100644
--- a/include/media/ICrypto.h
+++ b/include/media/ICrypto.h
@@ -31,7 +31,7 @@
virtual status_t initCheck() const = 0;
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const = 0;
+ virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) = 0;
virtual status_t createPlugin(
const uint8_t uuid[16], const void *data, size_t size) = 0;
diff --git a/include/media/stagefright/Utils.h b/include/media/stagefright/Utils.h
index 8213af9..73940d3 100644
--- a/include/media/stagefright/Utils.h
+++ b/include/media/stagefright/Utils.h
@@ -18,6 +18,7 @@
#define UTILS_H_
+#include <media/stagefright/foundation/AString.h>
#include <stdint.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -45,6 +46,8 @@
void convertMessageToMetaData(
const sp<AMessage> &format, sp<MetaData> &meta);
+AString MakeUserAgent();
+
} // namespace android
#endif // UTILS_H_
diff --git a/media/libmedia/ICrypto.cpp b/media/libmedia/ICrypto.cpp
index 2defc2d..98b183a 100644
--- a/media/libmedia/ICrypto.cpp
+++ b/media/libmedia/ICrypto.cpp
@@ -48,7 +48,7 @@
return reply.readInt32();
}
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const {
+ virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) {
Parcel data, reply;
data.writeInterfaceToken(ICrypto::getInterfaceDescriptor());
data.write(uuid, 16);
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 42584fe..58d495e 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -803,6 +803,7 @@
ALOGV("ToneGenerator constructor: streamType=%d, volume=%f", streamType, volume);
mState = TONE_IDLE;
+ mpAudioTrack = NULL;
if (AudioSystem::getOutputSamplingRate(&mSamplingRate, streamType) != NO_ERROR) {
ALOGE("Unable to marshal AudioFlinger");
@@ -811,7 +812,6 @@
mThreadCanCallJava = threadCanCallJava;
mStreamType = streamType;
mVolume = volume;
- mpAudioTrack = NULL;
mpToneDesc = NULL;
mpNewToneDesc = NULL;
// Generate tone by chunks of 20 ms to keep cadencing precision
@@ -885,6 +885,11 @@
if ((toneType < 0) || (toneType >= NUM_TONES))
return lResult;
+ toneType = getToneForRegion(toneType);
+ if (toneType == TONE_CDMA_SIGNAL_OFF) {
+ return true;
+ }
+
if (mState == TONE_IDLE) {
ALOGV("startTone: try to re-init AudioTrack");
if (!initAudioTrack()) {
@@ -897,7 +902,6 @@
mLock.lock();
// Get descriptor for requested tone
- toneType = getToneForRegion(toneType);
mpNewToneDesc = &sToneDescriptors[toneType];
mDurationMs = durationMs;
diff --git a/media/libmediaplayerservice/Crypto.cpp b/media/libmediaplayerservice/Crypto.cpp
index 0e8f913..ae4d845 100644
--- a/media/libmediaplayerservice/Crypto.cpp
+++ b/media/libmediaplayerservice/Crypto.cpp
@@ -17,6 +17,8 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "Crypto"
#include <utils/Log.h>
+#include <dirent.h>
+#include <dlfcn.h>
#include "Crypto.h"
@@ -26,87 +28,176 @@
#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/MediaErrors.h>
-#include <dlfcn.h>
-
namespace android {
+KeyedVector<Vector<uint8_t>, String8> Crypto::mUUIDToLibraryPathMap;
+KeyedVector<String8, wp<SharedLibrary> > Crypto::mLibraryPathToOpenLibraryMap;
+Mutex Crypto::mMapLock;
+
+static bool operator<(const Vector<uint8_t> &lhs, const Vector<uint8_t> &rhs) {
+ if (lhs.size() < rhs.size()) {
+ return true;
+ } else if (lhs.size() > rhs.size()) {
+ return false;
+ }
+
+ return memcmp((void *)lhs.array(), (void *)rhs.array(), rhs.size()) < 0;
+}
+
Crypto::Crypto()
: mInitCheck(NO_INIT),
- mLibHandle(NULL),
mFactory(NULL),
mPlugin(NULL) {
- mInitCheck = init();
}
Crypto::~Crypto() {
delete mPlugin;
mPlugin = NULL;
+ closeFactory();
+}
+void Crypto::closeFactory() {
delete mFactory;
mFactory = NULL;
-
- if (mLibHandle != NULL) {
- dlclose(mLibHandle);
- mLibHandle = NULL;
- }
+ mLibrary.clear();
}
status_t Crypto::initCheck() const {
return mInitCheck;
}
-status_t Crypto::init() {
- mLibHandle = dlopen("libdrmdecrypt.so", RTLD_NOW);
+/*
+ * Search the plugins directory for a plugin that supports the scheme
+ * specified by uuid
+ *
+ * If found:
+ * mLibrary holds a strong pointer to the dlopen'd library
+ * mFactory is set to the library's factory method
+ * mInitCheck is set to OK
+ *
+ * If not found:
+ * mLibrary is cleared and mFactory are set to NULL
+ * mInitCheck is set to an error (!OK)
+ */
+void Crypto::findFactoryForScheme(const uint8_t uuid[16]) {
- if (mLibHandle == NULL) {
- ALOGE("Unable to locate libdrmdecrypt.so");
+ closeFactory();
- return ERROR_UNSUPPORTED;
+ // lock static maps
+ Mutex::Autolock autoLock(mMapLock);
+
+ // first check cache
+ Vector<uint8_t> uuidVector;
+ uuidVector.appendArray(uuid, sizeof(uuid));
+ ssize_t index = mUUIDToLibraryPathMap.indexOfKey(uuidVector);
+ if (index >= 0) {
+ if (loadLibraryForScheme(mUUIDToLibraryPathMap[index], uuid)) {
+ mInitCheck = OK;
+ return;
+ } else {
+ ALOGE("Failed to load from cached library path!");
+ mInitCheck = ERROR_UNSUPPORTED;
+ return;
+ }
+ }
+
+ // no luck, have to search
+ String8 dirPath("/vendor/lib/mediadrm");
+ String8 pluginPath;
+
+ DIR* pDir = opendir(dirPath.string());
+ if (pDir) {
+ struct dirent* pEntry;
+ while ((pEntry = readdir(pDir))) {
+
+ pluginPath = dirPath + "/" + pEntry->d_name;
+
+ if (pluginPath.getPathExtension() == ".so") {
+
+ if (loadLibraryForScheme(pluginPath, uuid)) {
+ mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
+ mInitCheck = OK;
+ closedir(pDir);
+ return;
+ }
+ }
+ }
+
+ closedir(pDir);
+ }
+
+ // try the legacy libdrmdecrypt.so
+ pluginPath = "libdrmdecrypt.so";
+ if (loadLibraryForScheme(pluginPath, uuid)) {
+ mUUIDToLibraryPathMap.add(uuidVector, pluginPath);
+ mInitCheck = OK;
+ return;
+ }
+
+ ALOGE("Failed to find crypto plugin");
+ mInitCheck = ERROR_UNSUPPORTED;
+}
+
+bool Crypto::loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]) {
+
+ // get strong pointer to open shared library
+ ssize_t index = mLibraryPathToOpenLibraryMap.indexOfKey(path);
+ if (index >= 0) {
+ mLibrary = mLibraryPathToOpenLibraryMap[index].promote();
+ } else {
+ index = mLibraryPathToOpenLibraryMap.add(path, NULL);
+ }
+
+ if (!mLibrary.get()) {
+ mLibrary = new SharedLibrary(path);
+ if (!*mLibrary) {
+ return false;
+ }
+
+ mLibraryPathToOpenLibraryMap.replaceValueAt(index, mLibrary);
}
typedef CryptoFactory *(*CreateCryptoFactoryFunc)();
+
CreateCryptoFactoryFunc createCryptoFactory =
- (CreateCryptoFactoryFunc)dlsym(mLibHandle, "createCryptoFactory");
+ (CreateCryptoFactoryFunc)mLibrary->lookup("createCryptoFactory");
- if (createCryptoFactory == NULL
- || ((mFactory = createCryptoFactory()) == NULL)) {
- if (createCryptoFactory == NULL) {
- ALOGE("Unable to find symbol 'createCryptoFactory'.");
- } else {
- ALOGE("createCryptoFactory() failed.");
- }
-
- dlclose(mLibHandle);
- mLibHandle = NULL;
-
- return ERROR_UNSUPPORTED;
- }
-
- return OK;
-}
-
-bool Crypto::isCryptoSchemeSupported(const uint8_t uuid[16]) const {
- Mutex::Autolock autoLock(mLock);
-
- if (mInitCheck != OK) {
+ if (createCryptoFactory == NULL ||
+ (mFactory = createCryptoFactory()) == NULL ||
+ !mFactory->isCryptoSchemeSupported(uuid)) {
+ closeFactory();
return false;
}
+ return true;
+}
- return mFactory->isCryptoSchemeSupported(uuid);
+bool Crypto::isCryptoSchemeSupported(const uint8_t uuid[16]) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mFactory && mFactory->isCryptoSchemeSupported(uuid)) {
+ return true;
+ }
+
+ findFactoryForScheme(uuid);
+ return (mInitCheck == OK);
}
status_t Crypto::createPlugin(
const uint8_t uuid[16], const void *data, size_t size) {
Mutex::Autolock autoLock(mLock);
- if (mInitCheck != OK) {
- return mInitCheck;
- }
-
if (mPlugin != NULL) {
return -EINVAL;
}
+ if (!mFactory || !mFactory->isCryptoSchemeSupported(uuid)) {
+ findFactoryForScheme(uuid);
+ }
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
return mFactory->createPlugin(uuid, data, size, &mPlugin);
}
diff --git a/media/libmediaplayerservice/Crypto.h b/media/libmediaplayerservice/Crypto.h
index d066774..c44ae34 100644
--- a/media/libmediaplayerservice/Crypto.h
+++ b/media/libmediaplayerservice/Crypto.h
@@ -20,6 +20,9 @@
#include <media/ICrypto.h>
#include <utils/threads.h>
+#include <utils/KeyedVector.h>
+
+#include "SharedLibrary.h"
namespace android {
@@ -32,7 +35,7 @@
virtual status_t initCheck() const;
- virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]) const;
+ virtual bool isCryptoSchemeSupported(const uint8_t uuid[16]);
virtual status_t createPlugin(
const uint8_t uuid[16], const void *data, size_t size);
@@ -56,11 +59,17 @@
mutable Mutex mLock;
status_t mInitCheck;
- void *mLibHandle;
+ sp<SharedLibrary> mLibrary;
CryptoFactory *mFactory;
CryptoPlugin *mPlugin;
- status_t init();
+ static KeyedVector<Vector<uint8_t>, String8> mUUIDToLibraryPathMap;
+ static KeyedVector<String8, wp<SharedLibrary> > mLibraryPathToOpenLibraryMap;
+ static Mutex mMapLock;
+
+ void findFactoryForScheme(const uint8_t uuid[16]);
+ bool loadLibraryForScheme(const String8 &path, const uint8_t uuid[16]);
+ void closeFactory();
DISALLOW_EVIL_CONSTRUCTORS(Crypto);
};
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 8ed07bf..b0df379 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -21,7 +21,7 @@
#include "include/ESDS.h"
#include <arpa/inet.h>
-
+#include <cutils/properties.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
@@ -455,6 +455,21 @@
#endif
}
+AString MakeUserAgent() {
+ AString ua;
+ ua.append("stagefright/1.2 (Linux;Android ");
+
+#if (PROPERTY_VALUE_MAX < 8)
+#error "PROPERTY_VALUE_MAX must be at least 8"
+#endif
+
+ char value[PROPERTY_VALUE_MAX];
+ property_get("ro.build.version.release", value, "Unknown");
+ ua.append(value);
+ ua.append(")");
+
+ return ua;
+}
} // namespace android
diff --git a/media/libstagefright/chromium_http/support.cpp b/media/libstagefright/chromium_http/support.cpp
index 13ae3df..832e86d 100644
--- a/media/libstagefright/chromium_http/support.cpp
+++ b/media/libstagefright/chromium_http/support.cpp
@@ -36,8 +36,8 @@
#include "include/ChromiumHTTPDataSource.h"
#include <cutils/log.h>
-#include <cutils/properties.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/Utils.h>
#include <string>
namespace android {
@@ -156,19 +156,7 @@
////////////////////////////////////////////////////////////////////////////////
SfRequestContext::SfRequestContext() {
- AString ua;
- ua.append("stagefright/1.2 (Linux;Android ");
-
-#if (PROPERTY_VALUE_MAX < 8)
-#error "PROPERTY_VALUE_MAX must be at least 8"
-#endif
-
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.build.version.release", value, "Unknown");
- ua.append(value);
- ua.append(")");
-
- mUserAgent = ua.c_str();
+ mUserAgent = MakeUserAgent().c_str();
set_net_log(new SfNetLog());
diff --git a/media/libstagefright/rtsp/ARTSPConnection.cpp b/media/libstagefright/rtsp/ARTSPConnection.cpp
index 161bd4f..3068541 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.cpp
+++ b/media/libstagefright/rtsp/ARTSPConnection.cpp
@@ -20,13 +20,12 @@
#include "ARTSPConnection.h"
-#include <cutils/properties.h>
-
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/Utils.h>
#include <arpa/inet.h>
#include <fcntl.h>
@@ -41,6 +40,10 @@
// static
const int64_t ARTSPConnection::kSelectTimeoutUs = 1000ll;
+// static
+const AString ARTSPConnection::sUserAgent =
+ StringPrintf("User-Agent: %s\r\n", MakeUserAgent().c_str());
+
ARTSPConnection::ARTSPConnection(bool uidValid, uid_t uid)
: mUIDValid(uidValid),
mUID(uid),
@@ -50,7 +53,6 @@
mConnectionID(0),
mNextCSeq(0),
mReceiveResponseEventPending(false) {
- MakeUserAgent(&mUserAgent);
}
ARTSPConnection::~ARTSPConnection() {
@@ -1032,27 +1034,12 @@
#endif
}
-// static
-void ARTSPConnection::MakeUserAgent(AString *userAgent) {
- userAgent->clear();
- userAgent->setTo("User-Agent: stagefright/1.1 (Linux;Android ");
-
-#if (PROPERTY_VALUE_MAX < 8)
-#error "PROPERTY_VALUE_MAX must be at least 8"
-#endif
-
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.build.version.release", value, "Unknown");
- userAgent->append(value);
- userAgent->append(")\r\n");
-}
-
void ARTSPConnection::addUserAgent(AString *request) const {
// Find the boundary between headers and the body.
ssize_t i = request->find("\r\n\r\n");
CHECK_GE(i, 0);
- request->insert(mUserAgent, i + 2);
+ request->insert(sUserAgent, i + 2);
}
} // namespace android
diff --git a/media/libstagefright/rtsp/ARTSPConnection.h b/media/libstagefright/rtsp/ARTSPConnection.h
index 68f2d59..1fe9c99 100644
--- a/media/libstagefright/rtsp/ARTSPConnection.h
+++ b/media/libstagefright/rtsp/ARTSPConnection.h
@@ -74,6 +74,8 @@
static const int64_t kSelectTimeoutUs;
+ static const AString sUserAgent;
+
bool mUIDValid;
uid_t mUID;
State mState;
@@ -89,8 +91,6 @@
sp<AMessage> mObserveBinaryMessage;
- AString mUserAgent;
-
void performDisconnect();
void onConnect(const sp<AMessage> &msg);
@@ -122,8 +122,6 @@
static bool ParseSingleUnsignedLong(
const char *from, unsigned long *x);
- static void MakeUserAgent(AString *userAgent);
-
DISALLOW_EVIL_CONSTRUCTORS(ARTSPConnection);
};
diff --git a/media/libstagefright/rtsp/MyHandler.h b/media/libstagefright/rtsp/MyHandler.h
index 95ed43a..e067e20 100644
--- a/media/libstagefright/rtsp/MyHandler.h
+++ b/media/libstagefright/rtsp/MyHandler.h
@@ -28,13 +28,13 @@
#include "ASessionDescription.h"
#include <ctype.h>
-#include <cutils/properties.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/Utils.h>
#include <arpa/inet.h>
#include <sys/socket.h>
@@ -56,19 +56,6 @@
namespace android {
-static void MakeUserAgentString(AString *s) {
- s->setTo("stagefright/1.1 (Linux;Android ");
-
-#if (PROPERTY_VALUE_MAX < 8)
-#error "PROPERTY_VALUE_MAX must be at least 8"
-#endif
-
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.build.version.release", value, "Unknown");
- s->append(value);
- s->append(")");
-}
-
static bool GetAttribute(const char *s, const char *key, AString *value) {
value->clear();
@@ -279,8 +266,7 @@
data[offset++] = 6; // TOOL
- AString tool;
- MakeUserAgentString(&tool);
+ AString tool = MakeUserAgent();
data[offset++] = tool.size();
diff --git a/media/libstagefright/wifi-display/ANetworkSession.cpp b/media/libstagefright/wifi-display/ANetworkSession.cpp
index df20ae2..88ca1cc 100644
--- a/media/libstagefright/wifi-display/ANetworkSession.cpp
+++ b/media/libstagefright/wifi-display/ANetworkSession.cpp
@@ -565,7 +565,7 @@
mSawSendFailure = true;
}
-#if 1
+#if 0
int numBytesQueued;
int res = ioctl(mSocket, SIOCOUTQ, &numBytesQueued);
if (res == 0 && numBytesQueued > 50 * 1024) {
@@ -576,7 +576,7 @@
int64_t nowUs = ALooper::GetNowUs();
if (mLastStallReportUs < 0ll
- || nowUs > mLastStallReportUs + 500000ll) {
+ || nowUs > mLastStallReportUs + 100000ll) {
sp<AMessage> msg = mNotify->dup();
msg->setInt32("sessionID", mSessionID);
msg->setInt32("reason", kWhatNetworkStall);
diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk
index f81929c..f1f9f45 100644
--- a/media/libstagefright/wifi-display/Android.mk
+++ b/media/libstagefright/wifi-display/Android.mk
@@ -12,7 +12,6 @@
rtp/RTPReceiver.cpp \
rtp/RTPSender.cpp \
sink/DirectRenderer.cpp \
- sink/TunnelRenderer.cpp \
sink/WifiDisplaySink.cpp \
SNTPClient.cpp \
TimeSyncer.cpp \
diff --git a/media/libstagefright/wifi-display/MediaReceiver.cpp b/media/libstagefright/wifi-display/MediaReceiver.cpp
index 10a2dff..364acb9 100644
--- a/media/libstagefright/wifi-display/MediaReceiver.cpp
+++ b/media/libstagefright/wifi-display/MediaReceiver.cpp
@@ -47,7 +47,8 @@
}
ssize_t MediaReceiver::addTrack(
- RTPReceiver::TransportMode transportMode,
+ RTPReceiver::TransportMode rtpMode,
+ RTPReceiver::TransportMode rtcpMode,
int32_t *localRTPPort) {
if (mMode != MODE_UNDEFINED) {
return INVALID_OPERATION;
@@ -73,7 +74,10 @@
info.mReceiver->registerPacketType(
97, RTPReceiver::PACKETIZATION_H264);
- status_t err = info.mReceiver->initAsync(transportMode, localRTPPort);
+ status_t err = info.mReceiver->initAsync(
+ rtpMode,
+ rtcpMode,
+ localRTPPort);
if (err != OK) {
looper()->unregisterHandler(info.mReceiver->id());
@@ -309,13 +313,14 @@
notify->post();
}
-status_t MediaReceiver::notifyLateness(size_t trackIndex, int64_t latenessUs) {
+status_t MediaReceiver::informSender(
+ size_t trackIndex, const sp<AMessage> ¶ms) {
if (trackIndex >= mTrackInfos.size()) {
return -ERANGE;
}
TrackInfo *info = &mTrackInfos.editItemAt(trackIndex);
- return info->mReceiver->notifyLateness(latenessUs);
+ return info->mReceiver->informSender(params);
}
} // namespace android
diff --git a/media/libstagefright/wifi-display/MediaReceiver.h b/media/libstagefright/wifi-display/MediaReceiver.h
index cdfde99..afbb407 100644
--- a/media/libstagefright/wifi-display/MediaReceiver.h
+++ b/media/libstagefright/wifi-display/MediaReceiver.h
@@ -43,7 +43,8 @@
const sp<AMessage> ¬ify);
ssize_t addTrack(
- RTPReceiver::TransportMode transportMode,
+ RTPReceiver::TransportMode rtpMode,
+ RTPReceiver::TransportMode rtcpMode,
int32_t *localRTPPort);
status_t connectTrack(
@@ -60,7 +61,7 @@
};
status_t initAsync(Mode mode);
- status_t notifyLateness(size_t trackIndex, int64_t latenessUs);
+ status_t informSender(size_t trackIndex, const sp<AMessage> ¶ms);
protected:
virtual void onMessageReceived(const sp<AMessage> &msg);
diff --git a/media/libstagefright/wifi-display/MediaSender.cpp b/media/libstagefright/wifi-display/MediaSender.cpp
index d13a92e..33af66d 100644
--- a/media/libstagefright/wifi-display/MediaSender.cpp
+++ b/media/libstagefright/wifi-display/MediaSender.cpp
@@ -85,10 +85,11 @@
status_t MediaSender::initAsync(
ssize_t trackIndex,
- RTPSender::TransportMode transportMode,
const char *remoteHost,
int32_t remoteRTPPort,
+ RTPSender::TransportMode rtpMode,
int32_t remoteRTCPPort,
+ RTPSender::TransportMode rtcpMode,
int32_t *localRTPPort) {
if (trackIndex < 0) {
if (mMode != MODE_UNDEFINED) {
@@ -124,10 +125,11 @@
looper()->registerHandler(mTSSender);
err = mTSSender->initAsync(
- transportMode,
remoteHost,
remoteRTPPort,
+ rtpMode,
remoteRTCPPort,
+ rtcpMode,
localRTPPort);
if (err != OK) {
@@ -174,10 +176,11 @@
looper()->registerHandler(info->mSender);
status_t err = info->mSender->initAsync(
- transportMode,
remoteHost,
remoteRTPPort,
+ rtpMode,
remoteRTCPPort,
+ rtcpMode,
localRTPPort);
if (err != OK) {
@@ -260,37 +263,6 @@
tsPackets,
33 /* packetType */,
RTPSender::PACKETIZATION_TRANSPORT_STREAM);
-
-#if 0
- {
- int64_t nowUs = ALooper::GetNowUs();
-
- int64_t timeUs;
- CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
-
- int64_t delayMs = (nowUs - timeUs) / 1000ll;
-
- static const int64_t kMinDelayMs = 0;
- static const int64_t kMaxDelayMs = 300;
-
- const char *kPattern = "########################################";
- size_t kPatternSize = strlen(kPattern);
-
- int n = (kPatternSize * (delayMs - kMinDelayMs))
- / (kMaxDelayMs - kMinDelayMs);
-
- if (n < 0) {
- n = 0;
- } else if ((size_t)n > kPatternSize) {
- n = kPatternSize;
- }
-
- ALOGI("[%lld]: (%4lld ms) %s\n",
- timeUs / 1000,
- delayMs,
- kPattern + kPatternSize - n);
- }
-#endif
}
if (err != OK) {
@@ -369,6 +341,22 @@
break;
}
+ case kWhatInformSender:
+ {
+ int64_t avgLatencyUs;
+ CHECK(msg->findInt64("avgLatencyUs", &avgLatencyUs));
+
+ int64_t maxLatencyUs;
+ CHECK(msg->findInt64("maxLatencyUs", &maxLatencyUs));
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatInformSender);
+ notify->setInt64("avgLatencyUs", avgLatencyUs);
+ notify->setInt64("maxLatencyUs", maxLatencyUs);
+ notify->post();
+ break;
+ }
+
default:
TRESPASS();
}
diff --git a/media/libstagefright/wifi-display/MediaSender.h b/media/libstagefright/wifi-display/MediaSender.h
index 447abf7..04538ea 100644
--- a/media/libstagefright/wifi-display/MediaSender.h
+++ b/media/libstagefright/wifi-display/MediaSender.h
@@ -43,6 +43,7 @@
kWhatInitDone,
kWhatError,
kWhatNetworkStall,
+ kWhatInformSender,
};
MediaSender(
@@ -59,10 +60,11 @@
// If trackIndex == -1, initialize for transport stream muxing.
status_t initAsync(
ssize_t trackIndex,
- RTPSender::TransportMode transportMode,
const char *remoteHost,
int32_t remoteRTPPort,
+ RTPSender::TransportMode rtpMode,
int32_t remoteRTCPPort,
+ RTPSender::TransportMode rtcpMode,
int32_t *localRTPPort);
status_t queueAccessUnit(
diff --git a/media/libstagefright/wifi-display/rtp/RTPBase.h b/media/libstagefright/wifi-display/rtp/RTPBase.h
index 6507a6f..e3fa845 100644
--- a/media/libstagefright/wifi-display/rtp/RTPBase.h
+++ b/media/libstagefright/wifi-display/rtp/RTPBase.h
@@ -29,6 +29,7 @@
enum TransportMode {
TRANSPORT_UNDEFINED,
+ TRANSPORT_NONE,
TRANSPORT_UDP,
TRANSPORT_TCP,
TRANSPORT_TCP_INTERLEAVED,
diff --git a/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp b/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp
index 8711b08..238fb82 100644
--- a/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp
@@ -407,13 +407,22 @@
const sp<AMessage> ¬ify)
: mNetSession(netSession),
mNotify(notify),
- mMode(TRANSPORT_UNDEFINED),
+ mRTPMode(TRANSPORT_UNDEFINED),
+ mRTCPMode(TRANSPORT_UNDEFINED),
mRTPSessionID(0),
mRTCPSessionID(0),
- mRTPClientSessionID(0) {
+ mRTPConnected(false),
+ mRTCPConnected(false),
+ mRTPClientSessionID(0),
+ mRTCPClientSessionID(0) {
}
RTPReceiver::~RTPReceiver() {
+ if (mRTCPClientSessionID != 0) {
+ mNetSession->destroySession(mRTCPClientSessionID);
+ mRTCPClientSessionID = 0;
+ }
+
if (mRTPClientSessionID != 0) {
mNetSession->destroySession(mRTPClientSessionID);
mRTPClientSessionID = 0;
@@ -430,17 +439,24 @@
}
}
-status_t RTPReceiver::initAsync(TransportMode mode, int32_t *outLocalRTPPort) {
- if (mMode != TRANSPORT_UNDEFINED || mode == TRANSPORT_UNDEFINED) {
+status_t RTPReceiver::initAsync(
+ TransportMode rtpMode,
+ TransportMode rtcpMode,
+ int32_t *outLocalRTPPort) {
+ if (mRTPMode != TRANSPORT_UNDEFINED
+ || rtpMode == TRANSPORT_UNDEFINED
+ || rtpMode == TRANSPORT_NONE
+ || rtcpMode == TRANSPORT_UNDEFINED) {
return INVALID_OPERATION;
}
- CHECK_NE(mMode, TRANSPORT_TCP_INTERLEAVED);
+ CHECK_NE(rtpMode, TRANSPORT_TCP_INTERLEAVED);
+ CHECK_NE(rtcpMode, TRANSPORT_TCP_INTERLEAVED);
sp<AMessage> rtpNotify = new AMessage(kWhatRTPNotify, id());
sp<AMessage> rtcpNotify;
- if (mode == TRANSPORT_UDP) {
+ if (rtcpMode != TRANSPORT_NONE) {
rtcpNotify = new AMessage(kWhatRTCPNotify, id());
}
@@ -456,13 +472,13 @@
localRTPPort = PickRandomRTPPort();
status_t err;
- if (mode == TRANSPORT_UDP) {
+ if (rtpMode == TRANSPORT_UDP) {
err = mNetSession->createUDPSession(
localRTPPort,
rtpNotify,
&mRTPSessionID);
} else {
- CHECK_EQ(mode, TRANSPORT_TCP);
+ CHECK_EQ(rtpMode, TRANSPORT_TCP);
err = mNetSession->createTCPDatagramSession(
ifaceAddr,
localRTPPort,
@@ -474,15 +490,22 @@
continue;
}
- if (mode == TRANSPORT_TCP) {
+ if (rtcpMode == TRANSPORT_NONE) {
break;
+ } else if (rtcpMode == TRANSPORT_UDP) {
+ err = mNetSession->createUDPSession(
+ localRTPPort + 1,
+ rtcpNotify,
+ &mRTCPSessionID);
+ } else {
+ CHECK_EQ(rtpMode, TRANSPORT_TCP);
+ err = mNetSession->createTCPDatagramSession(
+ ifaceAddr,
+ localRTPPort + 1,
+ rtcpNotify,
+ &mRTCPSessionID);
}
- err = mNetSession->createUDPSession(
- localRTPPort + 1,
- rtcpNotify,
- &mRTCPSessionID);
-
if (err == OK) {
break;
}
@@ -491,7 +514,8 @@
mRTPSessionID = 0;
}
- mMode = mode;
+ mRTPMode = rtpMode;
+ mRTCPMode = rtcpMode;
*outLocalRTPPort = localRTPPort;
return OK;
@@ -499,41 +523,62 @@
status_t RTPReceiver::connect(
const char *remoteHost, int32_t remoteRTPPort, int32_t remoteRTCPPort) {
- if (mMode == TRANSPORT_TCP) {
- return OK;
+ status_t err;
+
+ if (mRTPMode == TRANSPORT_UDP) {
+ CHECK(!mRTPConnected);
+
+ err = mNetSession->connectUDPSession(
+ mRTPSessionID, remoteHost, remoteRTPPort);
+
+ if (err != OK) {
+ notifyInitDone(err);
+ return err;
+ }
+
+ ALOGI("connectUDPSession RTP successful.");
+
+ mRTPConnected = true;
}
- status_t err = mNetSession->connectUDPSession(
- mRTPSessionID, remoteHost, remoteRTPPort);
+ if (mRTCPMode == TRANSPORT_UDP) {
+ CHECK(!mRTCPConnected);
- if (err != OK) {
- notifyInitDone(err);
- return err;
- }
-
- ALOGI("connectUDPSession RTP successful.");
-
- if (remoteRTCPPort >= 0) {
err = mNetSession->connectUDPSession(
mRTCPSessionID, remoteHost, remoteRTCPPort);
if (err != OK) {
- ALOGI("connect failed w/ err %d", err);
-
notifyInitDone(err);
return err;
}
scheduleSendRR();
+
+ ALOGI("connectUDPSession RTCP successful.");
+
+ mRTCPConnected = true;
}
- notifyInitDone(OK);
+ if (mRTPConnected
+ && (mRTCPConnected || mRTCPMode == TRANSPORT_NONE)) {
+ notifyInitDone(OK);
+ }
return OK;
}
-status_t RTPReceiver::notifyLateness(int64_t latenessUs) {
- sp<ABuffer> buf = new ABuffer(20);
+status_t RTPReceiver::informSender(const sp<AMessage> ¶ms) {
+ if (!mRTCPConnected) {
+ return INVALID_OPERATION;
+ }
+
+ int64_t avgLatencyUs;
+ CHECK(params->findInt64("avgLatencyUs", &avgLatencyUs));
+
+ int64_t maxLatencyUs;
+ CHECK(params->findInt64("maxLatencyUs", &maxLatencyUs));
+
+ sp<ABuffer> buf = new ABuffer(28);
uint8_t *ptr = buf->data();
ptr[0] = 0x80 | 0;
@@ -552,14 +597,23 @@
ptr[10] = 't';
ptr[11] = 'e';
- ptr[12] = latenessUs >> 56;
- ptr[13] = (latenessUs >> 48) & 0xff;
- ptr[14] = (latenessUs >> 40) & 0xff;
- ptr[15] = (latenessUs >> 32) & 0xff;
- ptr[16] = (latenessUs >> 24) & 0xff;
- ptr[17] = (latenessUs >> 16) & 0xff;
- ptr[18] = (latenessUs >> 8) & 0xff;
- ptr[19] = latenessUs & 0xff;
+ ptr[12] = avgLatencyUs >> 56;
+ ptr[13] = (avgLatencyUs >> 48) & 0xff;
+ ptr[14] = (avgLatencyUs >> 40) & 0xff;
+ ptr[15] = (avgLatencyUs >> 32) & 0xff;
+ ptr[16] = (avgLatencyUs >> 24) & 0xff;
+ ptr[17] = (avgLatencyUs >> 16) & 0xff;
+ ptr[18] = (avgLatencyUs >> 8) & 0xff;
+ ptr[19] = avgLatencyUs & 0xff;
+
+ ptr[20] = maxLatencyUs >> 56;
+ ptr[21] = (maxLatencyUs >> 48) & 0xff;
+ ptr[22] = (maxLatencyUs >> 40) & 0xff;
+ ptr[23] = (maxLatencyUs >> 32) & 0xff;
+ ptr[24] = (maxLatencyUs >> 24) & 0xff;
+ ptr[25] = (maxLatencyUs >> 16) & 0xff;
+ ptr[26] = (maxLatencyUs >> 8) & 0xff;
+ ptr[27] = maxLatencyUs & 0xff;
mNetSession->sendRequest(mRTCPSessionID, buf->data(), buf->size());
@@ -615,15 +669,18 @@
if (sessionID == mRTPSessionID) {
mRTPSessionID = 0;
-
- if (mMode == TRANSPORT_TCP && mRTPClientSessionID == 0) {
- notifyInitDone(err);
- break;
- }
} else if (sessionID == mRTCPSessionID) {
mRTCPSessionID = 0;
} else if (sessionID == mRTPClientSessionID) {
mRTPClientSessionID = 0;
+ } else if (sessionID == mRTCPClientSessionID) {
+ mRTCPClientSessionID = 0;
+ }
+
+ if (!mRTPConnected
+ || (mRTCPMode != TRANSPORT_NONE && !mRTCPConnected)) {
+ notifyInitDone(err);
+ break;
}
notifyError(err);
@@ -645,22 +702,39 @@
case ANetworkSession::kWhatClientConnected:
{
- CHECK_EQ(mMode, TRANSPORT_TCP);
- CHECK(isRTP);
-
int32_t sessionID;
CHECK(msg->findInt32("sessionID", &sessionID));
- if (mRTPClientSessionID != 0) {
- // We only allow a single client connection.
- mNetSession->destroySession(sessionID);
- sessionID = 0;
- break;
+ if (isRTP) {
+ CHECK_EQ(mRTPMode, TRANSPORT_TCP);
+
+ if (mRTPClientSessionID != 0) {
+ // We only allow a single client connection.
+ mNetSession->destroySession(sessionID);
+ sessionID = 0;
+ break;
+ }
+
+ mRTPClientSessionID = sessionID;
+ mRTPConnected = true;
+ } else {
+ CHECK_EQ(mRTCPMode, TRANSPORT_TCP);
+
+ if (mRTCPClientSessionID != 0) {
+ // We only allow a single client connection.
+ mNetSession->destroySession(sessionID);
+ sessionID = 0;
+ break;
+ }
+
+ mRTCPClientSessionID = sessionID;
+ mRTCPConnected = true;
}
- mRTPClientSessionID = sessionID;
-
- notifyInitDone(OK);
+ if (mRTPConnected
+ && (mRTCPConnected || mRTCPMode == TRANSPORT_NONE)) {
+ notifyInitDone(OK);
+ }
break;
}
}
diff --git a/media/libstagefright/wifi-display/rtp/RTPReceiver.h b/media/libstagefright/wifi-display/rtp/RTPReceiver.h
index ec4671d..630bce9 100644
--- a/media/libstagefright/wifi-display/rtp/RTPReceiver.h
+++ b/media/libstagefright/wifi-display/rtp/RTPReceiver.h
@@ -46,14 +46,17 @@
status_t registerPacketType(
uint8_t packetType, PacketizationMode mode);
- status_t initAsync(TransportMode mode, int32_t *outLocalRTPPort);
+ status_t initAsync(
+ TransportMode rtpMode,
+ TransportMode rtcpMode,
+ int32_t *outLocalRTPPort);
status_t connect(
const char *remoteHost,
int32_t remoteRTPPort,
int32_t remoteRTCPPort);
- status_t notifyLateness(int64_t latenessUs);
+ status_t informSender(const sp<AMessage> ¶ms);
protected:
virtual ~RTPReceiver();
@@ -79,11 +82,15 @@
sp<ANetworkSession> mNetSession;
sp<AMessage> mNotify;
- TransportMode mMode;
+ TransportMode mRTPMode;
+ TransportMode mRTCPMode;
int32_t mRTPSessionID;
int32_t mRTCPSessionID;
+ bool mRTPConnected;
+ bool mRTCPConnected;
int32_t mRTPClientSessionID; // in TRANSPORT_TCP mode.
+ int32_t mRTCPClientSessionID; // in TRANSPORT_TCP mode.
KeyedVector<uint8_t, PacketizationMode> mPacketTypes;
KeyedVector<uint32_t, sp<Source> > mSources;
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
index c8e265c..9eeeabd 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
@@ -38,7 +38,8 @@
const sp<AMessage> ¬ify)
: mNetSession(netSession),
mNotify(notify),
- mMode(TRANSPORT_UNDEFINED),
+ mRTPMode(TRANSPORT_UNDEFINED),
+ mRTCPMode(TRANSPORT_UNDEFINED),
mRTPSessionID(0),
mRTCPSessionID(0),
mRTPConnected(false),
@@ -74,18 +75,24 @@
}
status_t RTPSender::initAsync(
- TransportMode mode,
const char *remoteHost,
int32_t remoteRTPPort,
+ TransportMode rtpMode,
int32_t remoteRTCPPort,
+ TransportMode rtcpMode,
int32_t *outLocalRTPPort) {
- if (mMode != TRANSPORT_UNDEFINED || mode == TRANSPORT_UNDEFINED) {
+ if (mRTPMode != TRANSPORT_UNDEFINED
+ || rtpMode == TRANSPORT_UNDEFINED
+ || rtpMode == TRANSPORT_NONE
+ || rtcpMode == TRANSPORT_UNDEFINED) {
return INVALID_OPERATION;
}
- CHECK_NE(mMode, TRANSPORT_TCP_INTERLEAVED);
+ CHECK_NE(rtpMode, TRANSPORT_TCP_INTERLEAVED);
+ CHECK_NE(rtcpMode, TRANSPORT_TCP_INTERLEAVED);
- if (mode == TRANSPORT_TCP && remoteRTCPPort >= 0) {
+ if ((rtcpMode == TRANSPORT_NONE && remoteRTCPPort >= 0)
+ || (rtcpMode != TRANSPORT_NONE && remoteRTCPPort < 0)) {
return INVALID_OPERATION;
}
@@ -105,7 +112,7 @@
localRTPPort = PickRandomRTPPort();
status_t err;
- if (mode == TRANSPORT_UDP) {
+ if (rtpMode == TRANSPORT_UDP) {
err = mNetSession->createUDPSession(
localRTPPort,
remoteHost,
@@ -113,7 +120,7 @@
rtpNotify,
&mRTPSessionID);
} else {
- CHECK_EQ(mode, TRANSPORT_TCP);
+ CHECK_EQ(rtpMode, TRANSPORT_TCP);
err = mNetSession->createTCPDatagramSession(
localRTPPort,
remoteHost,
@@ -130,7 +137,7 @@
break;
}
- if (mode == TRANSPORT_UDP) {
+ if (rtcpMode == TRANSPORT_UDP) {
err = mNetSession->createUDPSession(
localRTPPort + 1,
remoteHost,
@@ -138,7 +145,7 @@
rtcpNotify,
&mRTCPSessionID);
} else {
- CHECK_EQ(mode, TRANSPORT_TCP);
+ CHECK_EQ(rtcpMode, TRANSPORT_TCP);
err = mNetSession->createTCPDatagramSession(
localRTPPort + 1,
remoteHost,
@@ -155,15 +162,20 @@
mRTPSessionID = 0;
}
- if (mode == TRANSPORT_UDP) {
+ if (rtpMode == TRANSPORT_UDP) {
mRTPConnected = true;
+ }
+
+ if (rtcpMode == TRANSPORT_UDP) {
mRTCPConnected = true;
}
- mMode = mode;
+ mRTPMode = rtpMode;
+ mRTCPMode = rtcpMode;
*outLocalRTPPort = localRTPPort;
- if (mMode == TRANSPORT_UDP) {
+ if (mRTPMode == TRANSPORT_UDP
+ && (mRTCPMode == TRANSPORT_UDP || mRTCPMode == TRANSPORT_NONE)) {
notifyInitDone(OK);
}
@@ -496,12 +508,12 @@
mRTCPSessionID = 0;
}
- if (mMode == TRANSPORT_TCP) {
- if (!mRTPConnected
- || (mRTCPSessionID > 0 && !mRTCPConnected)) {
- notifyInitDone(err);
- break;
- }
+ if (!mRTPConnected
+ || (mRTPMode != TRANSPORT_NONE && !mRTCPConnected)) {
+ // We haven't completed initialization, attach the error
+ // to the notification instead.
+ notifyInitDone(err);
+ break;
}
notifyError(err);
@@ -523,20 +535,21 @@
case ANetworkSession::kWhatConnected:
{
- CHECK_EQ(mMode, TRANSPORT_TCP);
-
int32_t sessionID;
CHECK(msg->findInt32("sessionID", &sessionID));
if (isRTP) {
+ CHECK_EQ(mRTPMode, TRANSPORT_TCP);
CHECK_EQ(sessionID, mRTPSessionID);
mRTPConnected = true;
} else {
+ CHECK_EQ(mRTCPMode, TRANSPORT_TCP);
CHECK_EQ(sessionID, mRTCPSessionID);
mRTCPConnected = true;
}
- if (mRTPConnected && (mRTCPSessionID == 0 || mRTCPConnected)) {
+ if (mRTPConnected
+ && (mRTCPMode == TRANSPORT_NONE || mRTCPConnected)) {
notifyInitDone(OK);
}
break;
@@ -603,6 +616,7 @@
break;
case 204: // APP
+ parseAPP(data, headerLength);
break;
case 205: // TSFB (transport layer specific feedback)
@@ -708,6 +722,21 @@
return OK;
}
+status_t RTPSender::parseAPP(const uint8_t *data, size_t size) {
+ if (!memcmp("late", &data[8], 4)) {
+ int64_t avgLatencyUs = (int64_t)U64_AT(&data[12]);
+ int64_t maxLatencyUs = (int64_t)U64_AT(&data[20]);
+
+ sp<AMessage> notify = mNotify->dup();
+ notify->setInt32("what", kWhatInformSender);
+ notify->setInt64("avgLatencyUs", avgLatencyUs);
+ notify->setInt64("maxLatencyUs", maxLatencyUs);
+ notify->post();
+ }
+
+ return OK;
+}
+
void RTPSender::notifyInitDone(status_t err) {
sp<AMessage> notify = mNotify->dup();
notify->setInt32("what", kWhatInitDone);
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.h b/media/libstagefright/wifi-display/rtp/RTPSender.h
index 90b1796..3a926ea 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.h
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.h
@@ -37,16 +37,18 @@
kWhatInitDone,
kWhatError,
kWhatNetworkStall,
+ kWhatInformSender,
};
RTPSender(
const sp<ANetworkSession> &netSession,
const sp<AMessage> ¬ify);
status_t initAsync(
- TransportMode mode,
const char *remoteHost,
int32_t remoteRTPPort,
+ TransportMode rtpMode,
int32_t remoteRTCPPort,
+ TransportMode rtcpMode,
int32_t *outLocalRTPPort);
status_t queueBuffer(
@@ -72,7 +74,8 @@
sp<ANetworkSession> mNetSession;
sp<AMessage> mNotify;
- TransportMode mMode;
+ TransportMode mRTPMode;
+ TransportMode mRTCPMode;
int32_t mRTPSessionID;
int32_t mRTCPSessionID;
bool mRTPConnected;
@@ -103,6 +106,7 @@
status_t onRTCPData(const sp<ABuffer> &data);
status_t parseReceiverReport(const uint8_t *data, size_t size);
status_t parseTSFB(const uint8_t *data, size_t size);
+ status_t parseAPP(const uint8_t *data, size_t size);
void notifyInitDone(status_t err);
void notifyError(status_t err);
diff --git a/media/libstagefright/wifi-display/rtptest.cpp b/media/libstagefright/wifi-display/rtptest.cpp
index 607d9d2..eade832 100644
--- a/media/libstagefright/wifi-display/rtptest.cpp
+++ b/media/libstagefright/wifi-display/rtptest.cpp
@@ -106,7 +106,9 @@
int32_t receiverRTPPort;
CHECK_EQ((status_t)OK,
mReceiver->initAsync(
- RTPReceiver::TRANSPORT_UDP, &receiverRTPPort));
+ RTPReceiver::TRANSPORT_UDP, // rtpMode
+ RTPReceiver::TRANSPORT_UDP, // rtcpMode
+ &receiverRTPPort));
printf("picked receiverRTPPort %d\n", receiverRTPPort);
@@ -155,10 +157,11 @@
int32_t senderRTPPort;
CHECK_EQ((status_t)OK,
mSender->initAsync(
- RTPSender::TRANSPORT_UDP,
host.c_str(),
receiverRTPPort,
+ RTPSender::TRANSPORT_UDP, // rtpMode
receiverRTPPort + 1,
+ RTPSender::TRANSPORT_UDP, // rtcpMode
&senderRTPPort));
printf("picked senderRTPPort %d\n", senderRTPPort);
diff --git a/media/libstagefright/wifi-display/sink/DirectRenderer.cpp b/media/libstagefright/wifi-display/sink/DirectRenderer.cpp
index 12338e9..15f9c88 100644
--- a/media/libstagefright/wifi-display/sink/DirectRenderer.cpp
+++ b/media/libstagefright/wifi-display/sink/DirectRenderer.cpp
@@ -467,8 +467,6 @@
const sp<IGraphicBufferProducer> &bufferProducer)
: mSurfaceTex(bufferProducer),
mVideoRenderPending(false),
- mLatencySum(0ll),
- mLatencyCount(0),
mNumFramesLate(0),
mNumFrames(0) {
}
@@ -476,25 +474,6 @@
DirectRenderer::~DirectRenderer() {
}
-int64_t DirectRenderer::getAvgLatenessUs() {
- if (mLatencyCount == 0) {
- return 0ll;
- }
-
- int64_t avgLatencyUs = mLatencySum / mLatencyCount;
-
- mLatencySum = 0ll;
- mLatencyCount = 0;
-
- if (mNumFrames > 0) {
- ALOGI("%d / %d frames late", mNumFramesLate, mNumFrames);
- mNumFramesLate = 0;
- mNumFrames = 0;
- }
-
- return avgLatencyUs;
-}
-
void DirectRenderer::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatDecoderNotify:
@@ -632,9 +611,6 @@
}
++mNumFrames;
- mLatencySum += nowUs - info.mTimeUs;
- ++mLatencyCount;
-
status_t err =
mDecoderContext[0]->renderOutputBufferAndRelease(info.mIndex);
CHECK_EQ(err, (status_t)OK);
diff --git a/media/libstagefright/wifi-display/sink/DirectRenderer.h b/media/libstagefright/wifi-display/sink/DirectRenderer.h
index 92c176a..c5a4a83 100644
--- a/media/libstagefright/wifi-display/sink/DirectRenderer.h
+++ b/media/libstagefright/wifi-display/sink/DirectRenderer.h
@@ -34,8 +34,6 @@
void setFormat(size_t trackIndex, const sp<AMessage> &format);
void queueAccessUnit(size_t trackIndex, const sp<ABuffer> &accessUnit);
- int64_t getAvgLatenessUs();
-
protected:
virtual void onMessageReceived(const sp<AMessage> &msg);
virtual ~DirectRenderer();
@@ -64,9 +62,6 @@
sp<AudioRenderer> mAudioRenderer;
- int64_t mLatencySum;
- size_t mLatencyCount;
-
int32_t mNumFramesLate;
int32_t mNumFrames;
diff --git a/media/libstagefright/wifi-display/sink/TunnelRenderer.cpp b/media/libstagefright/wifi-display/sink/TunnelRenderer.cpp
deleted file mode 100644
index 6b185db..0000000
--- a/media/libstagefright/wifi-display/sink/TunnelRenderer.cpp
+++ /dev/null
@@ -1,290 +0,0 @@
-/*
- * Copyright 2012, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-//#define LOG_NDEBUG 0
-#define LOG_TAG "TunnelRenderer"
-#include <utils/Log.h>
-
-#include "TunnelRenderer.h"
-
-#include "ATSParser.h"
-
-#include <binder/IMemory.h>
-#include <binder/IServiceManager.h>
-#include <gui/SurfaceComposerClient.h>
-#include <media/IMediaPlayerService.h>
-#include <media/IStreamSource.h>
-#include <media/mediaplayer.h>
-#include <media/stagefright/foundation/ABuffer.h>
-#include <media/stagefright/foundation/ADebug.h>
-#include <media/stagefright/foundation/AMessage.h>
-#include <ui/DisplayInfo.h>
-
-namespace android {
-
-struct TunnelRenderer::PlayerClient : public BnMediaPlayerClient {
- PlayerClient() {}
-
- virtual void notify(int msg, int ext1, int ext2, const Parcel *obj) {
- ALOGI("notify %d, %d, %d", msg, ext1, ext2);
- }
-
-protected:
- virtual ~PlayerClient() {}
-
-private:
- DISALLOW_EVIL_CONSTRUCTORS(PlayerClient);
-};
-
-struct TunnelRenderer::StreamSource : public BnStreamSource {
- StreamSource(TunnelRenderer *owner);
-
- virtual void setListener(const sp<IStreamListener> &listener);
- virtual void setBuffers(const Vector<sp<IMemory> > &buffers);
-
- virtual void onBufferAvailable(size_t index);
-
- virtual uint32_t flags() const;
-
- void doSomeWork();
-
- void setTimeOffset(int64_t offset);
-
-protected:
- virtual ~StreamSource();
-
-private:
- mutable Mutex mLock;
-
- TunnelRenderer *mOwner;
-
- sp<IStreamListener> mListener;
-
- Vector<sp<IMemory> > mBuffers;
- List<size_t> mIndicesAvailable;
-
- size_t mNumDeqeued;
-
- int64_t mTimeOffsetUs;
- bool mTimeOffsetChanged;
-
- DISALLOW_EVIL_CONSTRUCTORS(StreamSource);
-};
-
-////////////////////////////////////////////////////////////////////////////////
-
-TunnelRenderer::StreamSource::StreamSource(TunnelRenderer *owner)
- : mOwner(owner),
- mNumDeqeued(0),
- mTimeOffsetUs(0ll),
- mTimeOffsetChanged(false) {
-}
-
-TunnelRenderer::StreamSource::~StreamSource() {
-}
-
-void TunnelRenderer::StreamSource::setListener(
- const sp<IStreamListener> &listener) {
- mListener = listener;
-}
-
-void TunnelRenderer::StreamSource::setBuffers(
- const Vector<sp<IMemory> > &buffers) {
- mBuffers = buffers;
-}
-
-void TunnelRenderer::StreamSource::onBufferAvailable(size_t index) {
- CHECK_LT(index, mBuffers.size());
-
- {
- Mutex::Autolock autoLock(mLock);
- mIndicesAvailable.push_back(index);
- }
-
- doSomeWork();
-}
-
-uint32_t TunnelRenderer::StreamSource::flags() const {
- return kFlagAlignedVideoData | kFlagIsRealTimeData;
-}
-
-void TunnelRenderer::StreamSource::doSomeWork() {
- Mutex::Autolock autoLock(mLock);
-
- while (!mIndicesAvailable.empty()) {
- sp<ABuffer> srcBuffer = mOwner->dequeueBuffer();
- if (srcBuffer == NULL) {
- break;
- }
-
- ++mNumDeqeued;
-
- if (mTimeOffsetChanged) {
- sp<AMessage> extra = new AMessage;
-
- extra->setInt32(
- IStreamListener::kKeyDiscontinuityMask,
- ATSParser::DISCONTINUITY_TIME_OFFSET);
-
- extra->setInt64("offset", mTimeOffsetUs);
-
- mListener->issueCommand(
- IStreamListener::DISCONTINUITY,
- false /* synchronous */,
- extra);
-
- mTimeOffsetChanged = false;
- }
-
- ALOGV("dequeue TS packet of size %d", srcBuffer->size());
-
- size_t index = *mIndicesAvailable.begin();
- mIndicesAvailable.erase(mIndicesAvailable.begin());
-
- sp<IMemory> mem = mBuffers.itemAt(index);
- CHECK_LE(srcBuffer->size(), mem->size());
- CHECK_EQ((srcBuffer->size() % 188), 0u);
-
- memcpy(mem->pointer(), srcBuffer->data(), srcBuffer->size());
- mListener->queueBuffer(index, srcBuffer->size());
- }
-}
-
-void TunnelRenderer::StreamSource::setTimeOffset(int64_t offset) {
- Mutex::Autolock autoLock(mLock);
-
- if (offset != mTimeOffsetUs) {
- mTimeOffsetUs = offset;
- mTimeOffsetChanged = true;
- }
-}
-
-////////////////////////////////////////////////////////////////////////////////
-
-TunnelRenderer::TunnelRenderer(
- const sp<IGraphicBufferProducer> &bufferProducer)
- : mSurfaceTex(bufferProducer),
- mStartup(true) {
- mStreamSource = new StreamSource(this);
-}
-
-TunnelRenderer::~TunnelRenderer() {
- destroyPlayer();
-}
-
-void TunnelRenderer::setTimeOffset(int64_t offset) {
- mStreamSource->setTimeOffset(offset);
-}
-
-void TunnelRenderer::onMessageReceived(const sp<AMessage> &msg) {
- switch (msg->what()) {
- default:
- TRESPASS();
- }
-}
-
-void TunnelRenderer::initPlayer() {
- if (mSurfaceTex == NULL) {
- mComposerClient = new SurfaceComposerClient;
- CHECK_EQ(mComposerClient->initCheck(), (status_t)OK);
-
- DisplayInfo info;
- SurfaceComposerClient::getDisplayInfo(0, &info);
- ssize_t displayWidth = info.w;
- ssize_t displayHeight = info.h;
-
- mSurfaceControl =
- mComposerClient->createSurface(
- String8("A Surface"),
- displayWidth,
- displayHeight,
- PIXEL_FORMAT_RGB_565,
- 0);
-
- CHECK(mSurfaceControl != NULL);
- CHECK(mSurfaceControl->isValid());
-
- SurfaceComposerClient::openGlobalTransaction();
- CHECK_EQ(mSurfaceControl->setLayer(INT_MAX), (status_t)OK);
- CHECK_EQ(mSurfaceControl->show(), (status_t)OK);
- SurfaceComposerClient::closeGlobalTransaction();
-
- mSurface = mSurfaceControl->getSurface();
- CHECK(mSurface != NULL);
- }
-
- sp<IServiceManager> sm = defaultServiceManager();
- sp<IBinder> binder = sm->getService(String16("media.player"));
- sp<IMediaPlayerService> service = interface_cast<IMediaPlayerService>(binder);
- CHECK(service.get() != NULL);
-
- mPlayerClient = new PlayerClient;
-
- mPlayer = service->create(mPlayerClient, 0);
- CHECK(mPlayer != NULL);
- CHECK_EQ(mPlayer->setDataSource(mStreamSource), (status_t)OK);
-
- mPlayer->setVideoSurfaceTexture(
- mSurfaceTex != NULL ? mSurfaceTex : mSurface->getIGraphicBufferProducer());
-
- mPlayer->start();
-}
-
-void TunnelRenderer::destroyPlayer() {
- mStreamSource.clear();
-
- mPlayer->setVideoSurfaceTexture(NULL);
-
- mPlayer->stop();
- mPlayer.clear();
-
- if (mSurfaceTex == NULL) {
- mSurface.clear();
- mSurfaceControl.clear();
-
- mComposerClient->dispose();
- mComposerClient.clear();
- }
-}
-
-void TunnelRenderer::queueBuffer(const sp<ABuffer> &buffer) {
- {
- Mutex::Autolock autoLock(mLock);
- mBuffers.push_back(buffer);
- }
-
- if (mStartup) {
- initPlayer();
- mStartup = false;
- }
-
- mStreamSource->doSomeWork();
-}
-
-sp<ABuffer> TunnelRenderer::dequeueBuffer() {
- Mutex::Autolock autoLock(mLock);
- if (mBuffers.empty()) {
- return NULL;
- }
-
- sp<ABuffer> buf = *mBuffers.begin();
- mBuffers.erase(mBuffers.begin());
-
- return buf;
-}
-
-} // namespace android
-
diff --git a/media/libstagefright/wifi-display/sink/TunnelRenderer.h b/media/libstagefright/wifi-display/sink/TunnelRenderer.h
deleted file mode 100644
index 479e73c..0000000
--- a/media/libstagefright/wifi-display/sink/TunnelRenderer.h
+++ /dev/null
@@ -1,78 +0,0 @@
-/*
- * Copyright 2012, The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifndef TUNNEL_RENDERER_H_
-
-#define TUNNEL_RENDERER_H_
-
-#include <gui/Surface.h>
-#include <media/stagefright/foundation/AHandler.h>
-
-namespace android {
-
-struct ABuffer;
-struct SurfaceComposerClient;
-struct SurfaceControl;
-struct Surface;
-struct IMediaPlayer;
-struct IStreamListener;
-
-// This class reassembles incoming RTP packets into the correct order
-// and sends the resulting transport stream to a mediaplayer instance
-// for playback.
-struct TunnelRenderer : public AHandler {
- TunnelRenderer(const sp<IGraphicBufferProducer> &bufferProducer);
-
- void queueBuffer(const sp<ABuffer> &buffer);
- sp<ABuffer> dequeueBuffer();
-
- void setTimeOffset(int64_t offset);
-
- int64_t getAvgLatenessUs() {
- return 0ll;
- }
-
-protected:
- virtual void onMessageReceived(const sp<AMessage> &msg);
- virtual ~TunnelRenderer();
-
-private:
- struct PlayerClient;
- struct StreamSource;
-
- mutable Mutex mLock;
-
- sp<IGraphicBufferProducer> mSurfaceTex;
-
- bool mStartup;
- List<sp<ABuffer> > mBuffers;
-
- sp<SurfaceComposerClient> mComposerClient;
- sp<SurfaceControl> mSurfaceControl;
- sp<Surface> mSurface;
- sp<PlayerClient> mPlayerClient;
- sp<IMediaPlayer> mPlayer;
- sp<StreamSource> mStreamSource;
-
- void initPlayer();
- void destroyPlayer();
-
- DISALLOW_EVIL_CONSTRUCTORS(TunnelRenderer);
-};
-
-} // namespace android
-
-#endif // TUNNEL_RENDERER_H_
diff --git a/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp b/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
index 62021c0..1a08bf5 100644
--- a/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
+++ b/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
@@ -24,16 +24,19 @@
#include "MediaReceiver.h"
#include "ParsedMessage.h"
#include "TimeSyncer.h"
-#include "TunnelRenderer.h"
#include <cutils/properties.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/Utils.h>
namespace android {
+// static
+const AString WifiDisplaySink::sUserAgent = MakeUserAgent();
+
WifiDisplaySink::WifiDisplaySink(
uint32_t flags,
const sp<ANetworkSession> &netSession,
@@ -51,8 +54,10 @@
mIDRFrameRequestPending(false),
mTimeOffsetUs(0ll),
mTimeOffsetValid(false),
- mTargetLatencyUs(-1ll),
- mSetupDeferred(false) {
+ mSetupDeferred(false),
+ mLatencyCount(0),
+ mLatencySumUs(0ll),
+ mLatencyMaxUs(0ll) {
// We support any and all resolutions, but prefer 720p30
mSinkSupportedVideoFormats.setNativeResolution(
VideoFormats::RESOLUTION_CEA, 5); // 1280 x 720 p30
@@ -265,13 +270,22 @@
case kWhatReportLateness:
{
- int64_t latenessUs = mRenderer->getAvgLatenessUs();
+ if (mLatencyCount > 0) {
+ int64_t avgLatencyUs = mLatencySumUs / mLatencyCount;
- ALOGI("avg. lateness = %lld ms",
- (latenessUs + mTargetLatencyUs) / 1000ll);
+ ALOGV("avg. latency = %lld ms (max %lld ms)",
+ avgLatencyUs / 1000ll,
+ mLatencyMaxUs / 1000ll);
- mMediaReceiver->notifyLateness(
- 0 /* trackIndex */, latenessUs);
+ sp<AMessage> params = new AMessage;
+ params->setInt64("avgLatencyUs", avgLatencyUs);
+ params->setInt64("maxLatencyUs", mLatencyMaxUs);
+ mMediaReceiver->informSender(0 /* trackIndex */, params);
+ }
+
+ mLatencyCount = 0;
+ mLatencySumUs = 0ll;
+ mLatencyMaxUs = 0ll;
msg->post(kReportLatenessEveryUs);
break;
@@ -282,6 +296,30 @@
}
}
+static void dumpDelay(size_t trackIndex, int64_t timeUs) {
+ int64_t delayMs = (ALooper::GetNowUs() - timeUs) / 1000ll;
+
+ static const int64_t kMinDelayMs = 0;
+ static const int64_t kMaxDelayMs = 300;
+
+ const char *kPattern = "########################################";
+ size_t kPatternSize = strlen(kPattern);
+
+ int n = (kPatternSize * (delayMs - kMinDelayMs))
+ / (kMaxDelayMs - kMinDelayMs);
+
+ if (n < 0) {
+ n = 0;
+ } else if ((size_t)n > kPatternSize) {
+ n = kPatternSize;
+ }
+
+ ALOGI("[%lld]: (%4lld ms) %s",
+ timeUs / 1000,
+ delayMs,
+ kPattern + kPatternSize - n);
+}
+
void WifiDisplaySink::onMediaReceiverNotify(const sp<AMessage> &msg) {
int32_t what;
CHECK(msg->findInt32("what", &what));
@@ -308,35 +346,12 @@
case MediaReceiver::kWhatAccessUnit:
{
if (mRenderer == NULL) {
-#if USE_TUNNEL_RENDERER
- mRenderer = new TunnelRenderer(mSurfaceTex);
-#else
mRenderer = new DirectRenderer(mSurfaceTex);
-#endif
-
looper()->registerHandler(mRenderer);
}
CHECK(mTimeOffsetValid);
- int64_t latencyUs = 200000ll; // 200ms by default
-
- char val[PROPERTY_VALUE_MAX];
- if (property_get("media.wfd-sink.latency", val, NULL)) {
- char *end;
- int64_t x = strtoll(val, &end, 10);
-
- if (end > val && *end == '\0' && x >= 0ll) {
- latencyUs = x;
- }
- }
-
- if (latencyUs != mTargetLatencyUs) {
- mTargetLatencyUs = latencyUs;
-
- ALOGI("Assuming %lld ms of latency.", latencyUs / 1000ll);
- }
-
sp<ABuffer> accessUnit;
CHECK(msg->findBuffer("accessUnit", &accessUnit));
@@ -345,23 +360,31 @@
// We are the timesync _client_,
// client time = server time - time offset.
- timeUs += mTargetLatencyUs - mTimeOffsetUs;
-
- accessUnit->meta()->setInt64("timeUs", timeUs);
+ timeUs -= mTimeOffsetUs;
size_t trackIndex;
CHECK(msg->findSize("trackIndex", &trackIndex));
-#if USE_TUNNEL_RENDERER
- mRenderer->queueBuffer(accessUnit);
-#else
+ int64_t nowUs = ALooper::GetNowUs();
+ int64_t delayUs = nowUs - timeUs;
+
+ mLatencySumUs += delayUs;
+ if (mLatencyCount == 0 || delayUs > mLatencyMaxUs) {
+ mLatencyMaxUs = delayUs;
+ }
+ ++mLatencyCount;
+
+ // dumpDelay(trackIndex, timeUs);
+
+ timeUs += 220000ll; // Assume 220 ms of latency
+ accessUnit->meta()->setInt64("timeUs", timeUs);
+
sp<AMessage> format;
if (msg->findMessage("format", &format)) {
mRenderer->setFormat(trackIndex, format);
}
mRenderer->queueAccessUnit(trackIndex, accessUnit);
-#endif
break;
}
@@ -470,7 +493,9 @@
}
status_t WifiDisplaySink::configureTransport(const sp<ParsedMessage> &msg) {
- if (mUsingTCPTransport) {
+ if (mUsingTCPTransport && !(mFlags & FLAG_SPECIAL_MODE)) {
+ // In "special" mode we still use a UDP RTCP back-channel that
+ // needs connecting.
return OK;
}
@@ -687,26 +712,21 @@
mMediaReceiver = new MediaReceiver(mNetSession, notify);
mMediaReceiverLooper->registerHandler(mMediaReceiver);
- RTPReceiver::TransportMode mode = RTPReceiver::TRANSPORT_UDP;
+ RTPReceiver::TransportMode rtpMode = RTPReceiver::TRANSPORT_UDP;
if (mUsingTCPTransport) {
if (mUsingTCPInterleaving) {
- mode = RTPReceiver::TRANSPORT_TCP_INTERLEAVED;
+ rtpMode = RTPReceiver::TRANSPORT_TCP_INTERLEAVED;
} else {
- mode = RTPReceiver::TRANSPORT_TCP;
+ rtpMode = RTPReceiver::TRANSPORT_TCP;
}
}
int32_t localRTPPort;
- status_t err = mMediaReceiver->addTrack(mode, &localRTPPort);
+ status_t err = mMediaReceiver->addTrack(
+ rtpMode, RTPReceiver::TRANSPORT_UDP /* rtcpMode */, &localRTPPort);
if (err == OK) {
- err = mMediaReceiver->initAsync(
-#if USE_TUNNEL_RENDERER
- MediaReceiver::MODE_TRANSPORT_STREAM_RAW
-#else
- MediaReceiver::MODE_TRANSPORT_STREAM
-#endif
- );
+ err = mMediaReceiver->initAsync(MediaReceiver::MODE_TRANSPORT_STREAM);
}
if (err != OK) {
@@ -723,13 +743,22 @@
AppendCommonResponse(&request, mNextCSeq);
- if (mode == RTPReceiver::TRANSPORT_TCP_INTERLEAVED) {
+ if (rtpMode == RTPReceiver::TRANSPORT_TCP_INTERLEAVED) {
request.append("Transport: RTP/AVP/TCP;interleaved=0-1\r\n");
- } else if (mode == RTPReceiver::TRANSPORT_TCP) {
- request.append(
- StringPrintf(
- "Transport: RTP/AVP/TCP;unicast;client_port=%d\r\n",
- localRTPPort));
+ } else if (rtpMode == RTPReceiver::TRANSPORT_TCP) {
+ if (mFlags & FLAG_SPECIAL_MODE) {
+ // This isn't quite true, since the RTP connection is through TCP
+ // and the RTCP connection through UDP...
+ request.append(
+ StringPrintf(
+ "Transport: RTP/AVP/TCP;unicast;client_port=%d-%d\r\n",
+ localRTPPort, localRTPPort + 1));
+ } else {
+ request.append(
+ StringPrintf(
+ "Transport: RTP/AVP/TCP;unicast;client_port=%d\r\n",
+ localRTPPort));
+ }
} else {
request.append(
StringPrintf(
@@ -867,7 +896,7 @@
response->append(buf);
response->append("\r\n");
- response->append("User-Agent: stagefright/1.1 (Linux;Android 4.1)\r\n");
+ response->append(StringPrintf("User-Agent: %s\r\n", sUserAgent.c_str()));
if (cseq >= 0) {
response->append(StringPrintf("CSeq: %d\r\n", cseq));
diff --git a/media/libstagefright/wifi-display/sink/WifiDisplaySink.h b/media/libstagefright/wifi-display/sink/WifiDisplaySink.h
index 2b8c6f7..7c62057 100644
--- a/media/libstagefright/wifi-display/sink/WifiDisplaySink.h
+++ b/media/libstagefright/wifi-display/sink/WifiDisplaySink.h
@@ -32,9 +32,6 @@
struct MediaReceiver;
struct ParsedMessage;
struct TimeSyncer;
-struct TunnelRenderer;
-
-#define USE_TUNNEL_RENDERER 0
// Represents the RTSP client acting as a wifi display sink.
// Connects to a wifi display source and renders the incoming
@@ -99,6 +96,8 @@
static const int64_t kReportLatenessEveryUs = 1000000ll;
+ static const AString sUserAgent;
+
State mState;
uint32_t mFlags;
VideoFormats mSinkSupportedVideoFormats;
@@ -117,12 +116,7 @@
sp<ALooper> mMediaReceiverLooper;
sp<MediaReceiver> mMediaReceiver;
-
-#if USE_TUNNEL_RENDERER
- sp<TunnelRenderer> mRenderer;
-#else
sp<DirectRenderer> mRenderer;
-#endif
AString mPlaybackSessionID;
int32_t mPlaybackSessionTimeoutSecs;
@@ -132,10 +126,12 @@
int64_t mTimeOffsetUs;
bool mTimeOffsetValid;
- int64_t mTargetLatencyUs;
-
bool mSetupDeferred;
+ size_t mLatencyCount;
+ int64_t mLatencySumUs;
+ int64_t mLatencyMaxUs;
+
status_t sendM2(int32_t sessionID);
status_t sendSetup(int32_t sessionID, const char *uri);
status_t sendPlay(int32_t sessionID, const char *uri);
diff --git a/media/libstagefright/wifi-display/source/Converter.cpp b/media/libstagefright/wifi-display/source/Converter.cpp
index bb8c387..0a8462c 100644
--- a/media/libstagefright/wifi-display/source/Converter.cpp
+++ b/media/libstagefright/wifi-display/source/Converter.cpp
@@ -135,7 +135,9 @@
return mNeedToManuallyPrependSPSPPS;
}
-static int32_t getBitrate(const char *propName, int32_t defaultValue) {
+// static
+int32_t Converter::GetInt32Property(
+ const char *propName, int32_t defaultValue) {
char val[PROPERTY_VALUE_MAX];
if (property_get(propName, val, NULL)) {
char *end;
@@ -185,8 +187,8 @@
mOutputFormat->setString("mime", outputMIME.c_str());
- int32_t audioBitrate = getBitrate("media.wfd.audio-bitrate", 128000);
- int32_t videoBitrate = getBitrate("media.wfd.video-bitrate", 5000000);
+ int32_t audioBitrate = GetInt32Property("media.wfd.audio-bitrate", 128000);
+ int32_t videoBitrate = GetInt32Property("media.wfd.video-bitrate", 5000000);
mPrevVideoBitrate = videoBitrate;
ALOGI("using audio bitrate of %d bps, video bitrate of %d bps",
@@ -622,18 +624,6 @@
}
status_t Converter::doMoreWork() {
- if (mIsVideo) {
- int32_t videoBitrate = getBitrate("media.wfd.video-bitrate", 5000000);
- if (videoBitrate != mPrevVideoBitrate) {
- sp<AMessage> params = new AMessage;
-
- params->setInt32("videoBitrate", videoBitrate);
- mEncoder->setParameters(params);
-
- mPrevVideoBitrate = videoBitrate;
- }
- }
-
status_t err;
for (;;) {
@@ -708,4 +698,19 @@
(new AMessage(kWhatDropAFrame, id()))->post();
}
+int32_t Converter::getVideoBitrate() const {
+ return mPrevVideoBitrate;
+}
+
+void Converter::setVideoBitrate(int32_t bitRate) {
+ if (mIsVideo && mEncoder != NULL && bitRate != mPrevVideoBitrate) {
+ sp<AMessage> params = new AMessage;
+ params->setInt32("videoBitrate", bitRate);
+
+ mEncoder->setParameters(params);
+
+ mPrevVideoBitrate = bitRate;
+ }
+}
+
} // namespace android
diff --git a/media/libstagefright/wifi-display/source/Converter.h b/media/libstagefright/wifi-display/source/Converter.h
index a418f69..ba297c4 100644
--- a/media/libstagefright/wifi-display/source/Converter.h
+++ b/media/libstagefright/wifi-display/source/Converter.h
@@ -70,6 +70,11 @@
void shutdownAsync();
+ int32_t getVideoBitrate() const;
+ void setVideoBitrate(int32_t bitrate);
+
+ static int32_t GetInt32Property(const char *propName, int32_t defaultValue);
+
protected:
virtual ~Converter();
virtual void onMessageReceived(const sp<AMessage> &msg);
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index a3b6542..715d0b5 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -27,6 +27,7 @@
#include "WifiDisplaySource.h"
#include <binder/IServiceManager.h>
+#include <cutils/properties.h>
#include <media/IHDCP.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -66,6 +67,7 @@
bool isAudio() const;
const sp<Converter> &converter() const;
+ const sp<RepeaterSource> &repeaterSource() const;
ssize_t mediaSenderTrackIndex() const;
void setMediaSenderTrackIndex(size_t index);
@@ -171,6 +173,11 @@
return mConverter;
}
+const sp<RepeaterSource> &
+WifiDisplaySource::PlaybackSession::Track::repeaterSource() const {
+ return mRepeaterSource;
+}
+
ssize_t WifiDisplaySource::PlaybackSession::Track::mediaSenderTrackIndex() const {
CHECK_GE(mMediaSenderTrackIndex, 0);
return mMediaSenderTrackIndex;
@@ -362,8 +369,11 @@
}
status_t WifiDisplaySource::PlaybackSession::init(
- const char *clientIP, int32_t clientRtp, int32_t clientRtcp,
- RTPSender::TransportMode transportMode,
+ const char *clientIP,
+ int32_t clientRtp,
+ RTPSender::TransportMode rtpMode,
+ int32_t clientRtcp,
+ RTPSender::TransportMode rtcpMode,
bool enableAudio,
bool usePCMAudio,
bool enableVideo,
@@ -385,10 +395,11 @@
if (err == OK) {
err = mMediaSender->initAsync(
-1 /* trackIndex */,
- transportMode,
clientIP,
clientRtp,
+ rtpMode,
clientRtcp,
+ rtcpMode,
&mLocalRTPPort);
}
@@ -548,6 +559,8 @@
converter->dropAFrame();
}
}
+ } else if (what == MediaSender::kWhatInformSender) {
+ onSinkFeedback(msg);
} else {
TRESPASS();
}
@@ -643,6 +656,86 @@
}
}
+void WifiDisplaySource::PlaybackSession::onSinkFeedback(const sp<AMessage> &msg) {
+ int64_t avgLatencyUs;
+ CHECK(msg->findInt64("avgLatencyUs", &avgLatencyUs));
+
+ int64_t maxLatencyUs;
+ CHECK(msg->findInt64("maxLatencyUs", &maxLatencyUs));
+
+ ALOGI("sink reports avg. latency of %lld ms (max %lld ms)",
+ avgLatencyUs / 1000ll,
+ maxLatencyUs / 1000ll);
+
+ if (mVideoTrackIndex >= 0) {
+ const sp<Track> &videoTrack = mTracks.valueFor(mVideoTrackIndex);
+ sp<Converter> converter = videoTrack->converter();
+
+ if (converter != NULL) {
+ int32_t videoBitrate =
+ Converter::GetInt32Property("media.wfd.video-bitrate", -1);
+
+ char val[PROPERTY_VALUE_MAX];
+ if (videoBitrate < 0
+ && property_get("media.wfd.video-bitrate", val, NULL)
+ && !strcasecmp("adaptive", val)) {
+ videoBitrate = converter->getVideoBitrate();
+
+ if (avgLatencyUs > 300000ll) {
+ videoBitrate *= 0.6;
+ } else if (avgLatencyUs < 100000ll) {
+ videoBitrate *= 1.1;
+ }
+ }
+
+ if (videoBitrate > 0) {
+ if (videoBitrate < 500000) {
+ videoBitrate = 500000;
+ } else if (videoBitrate > 10000000) {
+ videoBitrate = 10000000;
+ }
+
+ if (videoBitrate != converter->getVideoBitrate()) {
+ ALOGI("setting video bitrate to %d bps", videoBitrate);
+
+ converter->setVideoBitrate(videoBitrate);
+ }
+ }
+ }
+
+ sp<RepeaterSource> repeaterSource = videoTrack->repeaterSource();
+ if (repeaterSource != NULL) {
+ double rateHz =
+ Converter::GetInt32Property(
+ "media.wfd.video-framerate", -1);
+
+ if (rateHz < 0.0) {
+ rateHz = repeaterSource->getFrameRate();
+
+ if (avgLatencyUs > 300000ll) {
+ rateHz *= 0.9;
+ } else if (avgLatencyUs < 200000ll) {
+ rateHz *= 1.1;
+ }
+ }
+
+ if (rateHz > 0) {
+ if (rateHz < 5.0) {
+ rateHz = 5.0;
+ } else if (rateHz > 30.0) {
+ rateHz = 30.0;
+ }
+
+ if (rateHz != repeaterSource->getFrameRate()) {
+ ALOGI("setting frame rate to %.2f Hz", rateHz);
+
+ repeaterSource->setFrameRate(rateHz);
+ }
+ }
+ }
+ }
+}
+
status_t WifiDisplaySource::PlaybackSession::setupMediaPacketizer(
bool enableAudio, bool enableVideo) {
DataSource::RegisterDefaultSniffers();
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.h b/media/libstagefright/wifi-display/source/PlaybackSession.h
index da207e2..39086a1 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.h
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.h
@@ -44,8 +44,11 @@
const char *path = NULL);
status_t init(
- const char *clientIP, int32_t clientRtp, int32_t clientRtcp,
- RTPSender::TransportMode transportMode,
+ const char *clientIP,
+ int32_t clientRtp,
+ RTPSender::TransportMode rtpMode,
+ int32_t clientRtcp,
+ RTPSender::TransportMode rtcpMode,
bool enableAudio,
bool usePCMAudio,
bool enableVideo,
@@ -149,6 +152,8 @@
void schedulePullExtractor();
void onPullExtractor();
+ void onSinkFeedback(const sp<AMessage> &msg);
+
DISALLOW_EVIL_CONSTRUCTORS(PlaybackSession);
};
diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.cpp b/media/libstagefright/wifi-display/source/RepeaterSource.cpp
index 72be927..cc8dee3 100644
--- a/media/libstagefright/wifi-display/source/RepeaterSource.cpp
+++ b/media/libstagefright/wifi-display/source/RepeaterSource.cpp
@@ -27,6 +27,25 @@
CHECK(!mStarted);
}
+double RepeaterSource::getFrameRate() const {
+ return mRateHz;
+}
+
+void RepeaterSource::setFrameRate(double rateHz) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (rateHz == mRateHz) {
+ return;
+ }
+
+ if (mStartTimeUs >= 0ll) {
+ int64_t nextTimeUs = mStartTimeUs + (mFrameCount * 1000000ll) / mRateHz;
+ mStartTimeUs = nextTimeUs;
+ mFrameCount = 0;
+ }
+ mRateHz = rateHz;
+}
+
status_t RepeaterSource::start(MetaData *params) {
CHECK(!mStarted);
diff --git a/media/libstagefright/wifi-display/source/RepeaterSource.h b/media/libstagefright/wifi-display/source/RepeaterSource.h
index 146af32..8d414fd 100644
--- a/media/libstagefright/wifi-display/source/RepeaterSource.h
+++ b/media/libstagefright/wifi-display/source/RepeaterSource.h
@@ -28,6 +28,9 @@
// send updates in a while, this is its wakeup call.
void wakeUp();
+ double getFrameRate() const;
+ void setFrameRate(double rateHz);
+
protected:
virtual ~RepeaterSource();
diff --git a/media/libstagefright/wifi-display/source/TSPacketizer.cpp b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
index d993764..2c4a373 100644
--- a/media/libstagefright/wifi-display/source/TSPacketizer.cpp
+++ b/media/libstagefright/wifi-display/source/TSPacketizer.cpp
@@ -502,16 +502,121 @@
// reserved = b1
// the first fragment of "buffer" follows
+ // Each transport packet (except for the last one contributing to the PES
+ // payload) must contain a multiple of 16 bytes of payload per HDCP spec.
+ bool alignPayload =
+ (mFlags & (EMIT_HDCP20_DESCRIPTOR | EMIT_HDCP21_DESCRIPTOR));
+
+ /*
+ a) The very first PES transport stream packet contains
+
+ 4 bytes of TS header
+ ... padding
+ 14 bytes of static PES header
+ PES_private_data_len + 1 bytes (only if PES_private_data_len > 0)
+ numStuffingBytes bytes
+
+ followed by the payload
+
+ b) Subsequent PES transport stream packets contain
+
+ 4 bytes of TS header
+ ... padding
+
+ followed by the payload
+ */
+
size_t PES_packet_length = accessUnit->size() + 8 + numStuffingBytes;
if (PES_private_data_len > 0) {
PES_packet_length += PES_private_data_len + 1;
}
- size_t numTSPackets;
- if (PES_packet_length <= 178) {
- numTSPackets = 1;
- } else {
- numTSPackets = 1 + ((PES_packet_length - 178) + 183) / 184;
+ size_t numTSPackets = 1;
+
+ {
+ // Make sure the PES header fits into a single TS packet:
+ size_t PES_header_size = 14 + numStuffingBytes;
+ if (PES_private_data_len > 0) {
+ PES_header_size += PES_private_data_len + 1;
+ }
+
+ CHECK_LE(PES_header_size, 188u - 4u);
+
+ size_t sizeAvailableForPayload = 188 - 4 - PES_header_size;
+ size_t numBytesOfPayload = accessUnit->size();
+
+ if (numBytesOfPayload > sizeAvailableForPayload) {
+ numBytesOfPayload = sizeAvailableForPayload;
+
+ if (alignPayload && numBytesOfPayload > 16) {
+ numBytesOfPayload -= (numBytesOfPayload % 16);
+ }
+ }
+
+ // size_t numPaddingBytes = sizeAvailableForPayload - numBytesOfPayload;
+ ALOGV("packet 1 contains %zd padding bytes and %zd bytes of payload",
+ numPaddingBytes, numBytesOfPayload);
+
+ size_t numBytesOfPayloadRemaining = accessUnit->size() - numBytesOfPayload;
+
+#if 0
+ // The following hopefully illustrates the logic that led to the
+ // more efficient computation in the #else block...
+
+ while (numBytesOfPayloadRemaining > 0) {
+ size_t sizeAvailableForPayload = 188 - 4;
+
+ size_t numBytesOfPayload = numBytesOfPayloadRemaining;
+
+ if (numBytesOfPayload > sizeAvailableForPayload) {
+ numBytesOfPayload = sizeAvailableForPayload;
+
+ if (alignPayload && numBytesOfPayload > 16) {
+ numBytesOfPayload -= (numBytesOfPayload % 16);
+ }
+ }
+
+ size_t numPaddingBytes = sizeAvailableForPayload - numBytesOfPayload;
+ ALOGI("packet %zd contains %zd padding bytes and %zd bytes of payload",
+ numTSPackets + 1, numPaddingBytes, numBytesOfPayload);
+
+ numBytesOfPayloadRemaining -= numBytesOfPayload;
+ ++numTSPackets;
+ }
+#else
+ // This is how many bytes of payload each subsequent TS packet
+ // can contain at most.
+ sizeAvailableForPayload = 188 - 4;
+ size_t sizeAvailableForAlignedPayload = sizeAvailableForPayload;
+ if (alignPayload) {
+ // We're only going to use a subset of the available space
+ // since we need to make each fragment a multiple of 16 in size.
+ sizeAvailableForAlignedPayload -=
+ (sizeAvailableForAlignedPayload % 16);
+ }
+
+ size_t numFullTSPackets =
+ numBytesOfPayloadRemaining / sizeAvailableForAlignedPayload;
+
+ numTSPackets += numFullTSPackets;
+
+ numBytesOfPayloadRemaining -=
+ numFullTSPackets * sizeAvailableForAlignedPayload;
+
+ // numBytesOfPayloadRemaining < sizeAvailableForAlignedPayload
+ if (numFullTSPackets == 0 && numBytesOfPayloadRemaining > 0) {
+ // There wasn't enough payload left to form a full aligned payload,
+ // the last packet doesn't have to be aligned.
+ ++numTSPackets;
+ } else if (numFullTSPackets > 0
+ && numBytesOfPayloadRemaining
+ + sizeAvailableForAlignedPayload > sizeAvailableForPayload) {
+ // The last packet emitted had a full aligned payload and together
+ // with the bytes remaining does exceed the unaligned payload
+ // size, so we need another packet.
+ ++numTSPackets;
+ }
+#endif
}
if (flags & EMIT_PAT_AND_PMT) {
@@ -755,8 +860,6 @@
uint64_t PTS = (timeUs * 9ll) / 100ll;
- bool padding = (PES_packet_length < (188 - 10));
-
if (PES_packet_length >= 65536) {
// This really should only happen for video.
CHECK(track->isVideo());
@@ -765,19 +868,37 @@
PES_packet_length = 0;
}
+ size_t sizeAvailableForPayload = 188 - 4 - 14 - numStuffingBytes;
+ if (PES_private_data_len > 0) {
+ sizeAvailableForPayload -= PES_private_data_len + 1;
+ }
+
+ size_t copy = accessUnit->size();
+
+ if (copy > sizeAvailableForPayload) {
+ copy = sizeAvailableForPayload;
+
+ if (alignPayload && copy > 16) {
+ copy -= (copy % 16);
+ }
+ }
+
+ size_t numPaddingBytes = sizeAvailableForPayload - copy;
+
uint8_t *ptr = packetDataStart;
*ptr++ = 0x47;
*ptr++ = 0x40 | (track->PID() >> 8);
*ptr++ = track->PID() & 0xff;
- *ptr++ = (padding ? 0x30 : 0x10) | track->incrementContinuityCounter();
- if (padding) {
- size_t paddingSize = 188 - 10 - PES_packet_length;
- *ptr++ = paddingSize - 1;
- if (paddingSize >= 2) {
+ *ptr++ = (numPaddingBytes > 0 ? 0x30 : 0x10)
+ | track->incrementContinuityCounter();
+
+ if (numPaddingBytes > 0) {
+ *ptr++ = numPaddingBytes - 1;
+ if (numPaddingBytes >= 2) {
*ptr++ = 0x00;
- memset(ptr, 0xff, paddingSize - 2);
- ptr += paddingSize - 2;
+ memset(ptr, 0xff, numPaddingBytes - 2);
+ ptr += numPaddingBytes - 2;
}
}
@@ -813,25 +934,14 @@
*ptr++ = 0xff;
}
- // 18 bytes of TS/PES header leave 188 - 18 = 170 bytes for the payload
-
- size_t sizeLeft = packetDataStart + 188 - ptr;
- size_t copy = accessUnit->size();
- if (copy > sizeLeft) {
- copy = sizeLeft;
- }
-
memcpy(ptr, accessUnit->data(), copy);
ptr += copy;
- CHECK_EQ(sizeLeft, copy);
- memset(ptr, 0xff, sizeLeft - copy);
+ CHECK_EQ(ptr, packetDataStart + 188);
packetDataStart += 188;
size_t offset = copy;
while (offset < accessUnit->size()) {
- bool padding = (accessUnit->size() - offset) < (188 - 4);
-
// for subsequent fragments of "buffer":
// 0x47
// transport_error_indicator = b0
@@ -843,35 +953,40 @@
// continuity_counter = b????
// the fragment of "buffer" follows.
+ size_t sizeAvailableForPayload = 188 - 4;
+
+ size_t copy = accessUnit->size() - offset;
+
+ if (copy > sizeAvailableForPayload) {
+ copy = sizeAvailableForPayload;
+
+ if (alignPayload && copy > 16) {
+ copy -= (copy % 16);
+ }
+ }
+
+ size_t numPaddingBytes = sizeAvailableForPayload - copy;
+
uint8_t *ptr = packetDataStart;
*ptr++ = 0x47;
*ptr++ = 0x00 | (track->PID() >> 8);
*ptr++ = track->PID() & 0xff;
- *ptr++ = (padding ? 0x30 : 0x10) | track->incrementContinuityCounter();
+ *ptr++ = (numPaddingBytes > 0 ? 0x30 : 0x10)
+ | track->incrementContinuityCounter();
- if (padding) {
- size_t paddingSize = 188 - 4 - (accessUnit->size() - offset);
- *ptr++ = paddingSize - 1;
- if (paddingSize >= 2) {
+ if (numPaddingBytes > 0) {
+ *ptr++ = numPaddingBytes - 1;
+ if (numPaddingBytes >= 2) {
*ptr++ = 0x00;
- memset(ptr, 0xff, paddingSize - 2);
- ptr += paddingSize - 2;
+ memset(ptr, 0xff, numPaddingBytes - 2);
+ ptr += numPaddingBytes - 2;
}
}
- // 4 bytes of TS header leave 188 - 4 = 184 bytes for the payload
-
- size_t sizeLeft = packetDataStart + 188 - ptr;
- size_t copy = accessUnit->size() - offset;
- if (copy > sizeLeft) {
- copy = sizeLeft;
- }
-
memcpy(ptr, accessUnit->data() + offset, copy);
ptr += copy;
- CHECK_EQ(sizeLeft, copy);
- memset(ptr, 0xff, sizeLeft - copy);
+ CHECK_EQ(ptr, packetDataStart + 188);
offset += copy;
packetDataStart += 188;
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
index 5167cb3..792a9c5 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.cpp
@@ -34,6 +34,7 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/MediaErrors.h>
+#include <media/stagefright/Utils.h>
#include <arpa/inet.h>
#include <cutils/properties.h>
@@ -42,6 +43,9 @@
namespace android {
+// static
+const AString WifiDisplaySource::sUserAgent = MakeUserAgent();
+
WifiDisplaySource::WifiDisplaySource(
const sp<ANetworkSession> &netSession,
const sp<IRemoteDisplayClient> &client,
@@ -1159,7 +1163,7 @@
return ERROR_MALFORMED;
}
- RTPSender::TransportMode transportMode = RTPSender::TRANSPORT_UDP;
+ RTPSender::TransportMode rtpMode = RTPSender::TRANSPORT_UDP;
int clientRtp, clientRtcp;
if (transport.startsWith("RTP/AVP/TCP;")) {
@@ -1168,7 +1172,7 @@
transport.c_str(), "interleaved", &interleaved)
&& sscanf(interleaved.c_str(), "%d-%d",
&clientRtp, &clientRtcp) == 2) {
- transportMode = RTPSender::TRANSPORT_TCP_INTERLEAVED;
+ rtpMode = RTPSender::TRANSPORT_TCP_INTERLEAVED;
} else {
bool badRequest = false;
@@ -1190,7 +1194,7 @@
return ERROR_MALFORMED;
}
- transportMode = RTPSender::TRANSPORT_TCP;
+ rtpMode = RTPSender::TRANSPORT_TCP;
}
} else if (transport.startsWith("RTP/AVP;unicast;")
|| transport.startsWith("RTP/AVP/UDP;unicast;")) {
@@ -1249,11 +1253,17 @@
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,
- transportMode,
+ rtcpMode,
mSinkSupportsAudio,
mUsingPCMAudio,
mSinkSupportsVideo,
@@ -1282,7 +1292,7 @@
AString response = "RTSP/1.0 200 OK\r\n";
AppendCommonResponse(&response, cseq, playbackSessionID);
- if (transportMode == RTPSender::TRANSPORT_TCP_INTERLEAVED) {
+ if (rtpMode == RTPSender::TRANSPORT_TCP_INTERLEAVED) {
response.append(
StringPrintf(
"Transport: RTP/AVP/TCP;interleaved=%d-%d;",
@@ -1291,7 +1301,7 @@
int32_t serverRtp = playbackSession->getRTPPort();
AString transportString = "UDP";
- if (transportMode == RTPSender::TRANSPORT_TCP) {
+ if (rtpMode == RTPSender::TRANSPORT_TCP) {
transportString = "TCP";
}
@@ -1553,7 +1563,7 @@
response->append(buf);
response->append("\r\n");
- response->append("Server: Mine/1.0\r\n");
+ response->append(StringPrintf("Server: %s\r\n", sUserAgent.c_str()));
if (cseq >= 0) {
response->append(StringPrintf("CSeq: %d\r\n", cseq));
diff --git a/media/libstagefright/wifi-display/source/WifiDisplaySource.h b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
index 3a1b0f9..3efa0b4 100644
--- a/media/libstagefright/wifi-display/source/WifiDisplaySource.h
+++ b/media/libstagefright/wifi-display/source/WifiDisplaySource.h
@@ -113,6 +113,8 @@
static const int64_t kPlaybackSessionTimeoutUs =
kPlaybackSessionTimeoutSecs * 1000000ll;
+ static const AString sUserAgent;
+
State mState;
VideoFormats mSupportedSourceVideoFormats;
sp<ANetworkSession> mNetSession;
diff --git a/media/libstagefright/wifi-display/wfd.cpp b/media/libstagefright/wifi-display/wfd.cpp
index 4f7dcc8..9fee4d0 100644
--- a/media/libstagefright/wifi-display/wfd.cpp
+++ b/media/libstagefright/wifi-display/wfd.cpp
@@ -43,7 +43,8 @@
" -u uri \tconnect to an rtsp uri\n"
" -l ip[:port] \tlisten on the specified port "
" -f(ilename) \tstream media "
- "(create a sink)\n",
+ "(create a sink)\n"
+ " -s(pecial) \trun in 'special' mode\n",
me);
}
@@ -222,8 +223,10 @@
AString path;
+ bool specialMode = false;
+
int res;
- while ((res = getopt(argc, argv, "hc:l:u:f:")) >= 0) {
+ while ((res = getopt(argc, argv, "hc:l:u:f:s")) >= 0) {
switch (res) {
case 'c':
{
@@ -281,6 +284,12 @@
break;
}
+ case 's':
+ {
+ specialMode = true;
+ break;
+ }
+
case '?':
case 'h':
default:
@@ -357,7 +366,7 @@
sp<ALooper> looper = new ALooper;
sp<WifiDisplaySink> sink = new WifiDisplaySink(
- 0 /* flags */,
+ specialMode ? WifiDisplaySink::FLAG_SPECIAL_MODE : 0 /* flags */,
session,
surface->getIGraphicBufferProducer());
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index 2332b3e..f60749d 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -19,6 +19,7 @@
#include <sys/mman.h>
#include <utils/Log.h>
+#include <binder/PermissionCache.h>
#include <media/nbaio/NBLog.h>
#include <private/android_filesystem_config.h>
#include "MediaLogService.h"
@@ -55,6 +56,14 @@
status_t MediaLogService::dump(int fd, const Vector<String16>& args)
{
+ // FIXME merge with similar but not identical code at services/audioflinger/ServiceUtilities.cpp
+ static const String16 sDump("android.permission.DUMP");
+ if (!(IPCThreadState::self()->getCallingUid() == AID_MEDIA ||
+ PermissionCache::checkCallingPermission(sDump))) {
+ fdprintf(fd, "Permission denied.\n");
+ return NO_ERROR;
+ }
+
Vector<NamedReader> namedReaders;
{
Mutex::Autolock _l(mLock);