summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
Diffstat (limited to 'media')
-rw-r--r--media/libmedia/IDrm.cpp408
-rw-r--r--media/libmedia/ToneGenerator.cpp4
-rw-r--r--media/libmediaplayerservice/Drm.cpp148
-rw-r--r--media/libmediaplayerservice/Drm.h53
-rw-r--r--media/libmediaplayerservice/MediaPlayerFactory.cpp3
-rw-r--r--media/libmediaplayerservice/nuplayer/NuPlayer.cpp19
-rw-r--r--media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp2
-rw-r--r--media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp2
-rw-r--r--media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp3
-rw-r--r--media/libstagefright/httplive/LiveSession.cpp24
-rw-r--r--media/libstagefright/wifi-display/ANetworkSession.cpp26
-rw-r--r--media/libstagefright/wifi-display/Android.mk22
-rw-r--r--media/libstagefright/wifi-display/TimeSyncer.cpp6
-rw-r--r--media/libstagefright/wifi-display/TimeSyncer.h2
-rw-r--r--media/libstagefright/wifi-display/nettest.cpp400
-rw-r--r--media/libstagefright/wifi-display/rtp/RTPAssembler.cpp1
-rw-r--r--media/libstagefright/wifi-display/rtp/RTPBase.h1
-rw-r--r--media/libstagefright/wifi-display/rtp/RTPReceiver.cpp272
-rw-r--r--media/libstagefright/wifi-display/rtp/RTPReceiver.h8
-rw-r--r--media/libstagefright/wifi-display/rtp/RTPSender.cpp44
-rw-r--r--media/libstagefright/wifi-display/rtp/RTPSender.h1
-rw-r--r--media/libstagefright/wifi-display/rtptest.cpp278
-rw-r--r--media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp21
-rw-r--r--media/libstagefright/wifi-display/sink/WifiDisplaySink.h4
-rw-r--r--media/libstagefright/wifi-display/source/PlaybackSession.cpp7
25 files changed, 1446 insertions, 313 deletions
diff --git a/media/libmedia/IDrm.cpp b/media/libmedia/IDrm.cpp
index 3b13ec6..1641b56 100644
--- a/media/libmedia/IDrm.cpp
+++ b/media/libmedia/IDrm.cpp
@@ -33,10 +33,11 @@ enum {
DESTROY_PLUGIN,
OPEN_SESSION,
CLOSE_SESSION,
- GET_LICENSE_REQUEST,
- PROVIDE_LICENSE_RESPONSE,
- REMOVE_LICENSE,
- QUERY_LICENSE_STATUS,
+ GET_KEY_REQUEST,
+ PROVIDE_KEY_RESPONSE,
+ REMOVE_KEYS,
+ RESTORE_KEYS,
+ QUERY_KEY_STATUS,
GET_PROVISION_REQUEST,
PROVIDE_PROVISION_RESPONSE,
GET_SECURE_STOPS,
@@ -44,7 +45,13 @@ enum {
GET_PROPERTY_STRING,
GET_PROPERTY_BYTE_ARRAY,
SET_PROPERTY_STRING,
- SET_PROPERTY_BYTE_ARRAY
+ SET_PROPERTY_BYTE_ARRAY,
+ SET_CIPHER_ALGORITHM,
+ SET_MAC_ALGORITHM,
+ ENCRYPT,
+ DECRYPT,
+ SIGN,
+ VERIFY
};
struct BpDrm : public BpInterface<IDrm> {
@@ -92,9 +99,7 @@ struct BpDrm : public BpInterface<IDrm> {
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
remote()->transact(OPEN_SESSION, data, &reply);
- uint32_t size = reply.readInt32();
- sessionId.insertAt((size_t)0, size);
- reply.read(sessionId.editArray(), size);
+ readVector(reply, sessionId);
return reply.readInt32();
}
@@ -103,80 +108,81 @@ struct BpDrm : public BpInterface<IDrm> {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- data.writeInt32(sessionId.size());
- data.write(sessionId.array(), sessionId.size());
+ writeVector(data, sessionId);
remote()->transact(CLOSE_SESSION, data, &reply);
return reply.readInt32();
}
virtual status_t
- getLicenseRequest(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &initData,
- String8 const &mimeType, DrmPlugin::LicenseType licenseType,
- KeyedVector<String8, String8> const &optionalParameters,
- Vector<uint8_t> &request, String8 &defaultUrl) {
+ getKeyRequest(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &initData,
+ String8 const &mimeType, DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const &optionalParameters,
+ Vector<uint8_t> &request, String8 &defaultUrl) {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- data.writeInt32(sessionId.size());
- data.write(sessionId.array(), sessionId.size());
-
- data.writeInt32(initData.size());
- data.write(initData.array(), initData.size());
-
+ writeVector(data, sessionId);
+ writeVector(data, initData);
data.writeString8(mimeType);
- data.writeInt32((uint32_t)licenseType);
+ data.writeInt32((uint32_t)keyType);
data.writeInt32(optionalParameters.size());
for (size_t i = 0; i < optionalParameters.size(); ++i) {
data.writeString8(optionalParameters.keyAt(i));
data.writeString8(optionalParameters.valueAt(i));
}
- remote()->transact(GET_LICENSE_REQUEST, data, &reply);
+ remote()->transact(GET_KEY_REQUEST, data, &reply);
- uint32_t len = reply.readInt32();
- request.insertAt((size_t)0, len);
- reply.read(request.editArray(), len);
+ readVector(reply, request);
defaultUrl = reply.readString8();
return reply.readInt32();
}
- virtual status_t provideLicenseResponse(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &response) {
+ virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &response,
+ Vector<uint8_t> &keySetId) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+ writeVector(data, sessionId);
+ writeVector(data, response);
+ remote()->transact(PROVIDE_KEY_RESPONSE, data, &reply);
+ readVector(reply, keySetId);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t removeKeys(Vector<uint8_t> const &keySetId) {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- data.writeInt32(sessionId.size());
- data.write(sessionId.array(), sessionId.size());
- data.writeInt32(response.size());
- data.write(response.array(), response.size());
- remote()->transact(PROVIDE_LICENSE_RESPONSE, data, &reply);
+ writeVector(data, keySetId);
+ remote()->transact(REMOVE_KEYS, data, &reply);
return reply.readInt32();
}
- virtual status_t removeLicense(Vector<uint8_t> const &sessionId) {
+ virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keySetId) {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- data.writeInt32(sessionId.size());
- data.write(sessionId.array(), sessionId.size());
- remote()->transact(REMOVE_LICENSE, data, &reply);
+ writeVector(data, sessionId);
+ writeVector(data, keySetId);
+ remote()->transact(RESTORE_KEYS, data, &reply);
return reply.readInt32();
}
- virtual status_t queryLicenseStatus(Vector<uint8_t> const &sessionId,
+ virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
KeyedVector<String8, String8> &infoMap) const {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- data.writeInt32(sessionId.size());
- data.write(sessionId.array(), sessionId.size());
-
- remote()->transact(QUERY_LICENSE_STATUS, data, &reply);
+ writeVector(data, sessionId);
+ remote()->transact(QUERY_KEY_STATUS, data, &reply);
infoMap.clear();
size_t count = reply.readInt32();
@@ -195,9 +201,7 @@ struct BpDrm : public BpInterface<IDrm> {
remote()->transact(GET_PROVISION_REQUEST, data, &reply);
- uint32_t len = reply.readInt32();
- request.insertAt((size_t)0, len);
- reply.read(request.editArray(), len);
+ readVector(reply, request);
defaultUrl = reply.readString8();
return reply.readInt32();
@@ -207,8 +211,7 @@ struct BpDrm : public BpInterface<IDrm> {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- data.writeInt32(response.size());
- data.write(response.array(), response.size());
+ writeVector(data, response);
remote()->transact(PROVIDE_PROVISION_RESPONSE, data, &reply);
return reply.readInt32();
@@ -224,9 +227,7 @@ struct BpDrm : public BpInterface<IDrm> {
uint32_t count = reply.readInt32();
for (size_t i = 0; i < count; i++) {
Vector<uint8_t> secureStop;
- uint32_t len = reply.readInt32();
- secureStop.insertAt((size_t)0, len);
- reply.read(secureStop.editArray(), len);
+ readVector(reply, secureStop);
secureStops.push_back(secureStop);
}
return reply.readInt32();
@@ -236,8 +237,7 @@ struct BpDrm : public BpInterface<IDrm> {
Parcel data, reply;
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
- data.writeInt32(ssRelease.size());
- data.write(ssRelease.array(), ssRelease.size());
+ writeVector(data, ssRelease);
remote()->transact(RELEASE_SECURE_STOPS, data, &reply);
return reply.readInt32();
@@ -261,10 +261,7 @@ struct BpDrm : public BpInterface<IDrm> {
data.writeString8(name);
remote()->transact(GET_PROPERTY_BYTE_ARRAY, data, &reply);
- uint32_t len = reply.readInt32();
- value.insertAt((size_t)0, len);
- reply.read(value.editArray(), len);
-
+ readVector(reply, value);
return reply.readInt32();
}
@@ -285,15 +282,120 @@ struct BpDrm : public BpInterface<IDrm> {
data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
data.writeString8(name);
- data.writeInt32(value.size());
- data.write(value.array(), value.size());
+ writeVector(data, value);
remote()->transact(SET_PROPERTY_BYTE_ARRAY, data, &reply);
return reply.readInt32();
}
+ virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+ writeVector(data, sessionId);
+ data.writeString8(algorithm);
+ remote()->transact(SET_CIPHER_ALGORITHM, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+ writeVector(data, sessionId);
+ data.writeString8(algorithm);
+ remote()->transact(SET_MAC_ALGORITHM, data, &reply);
+ return reply.readInt32();
+ }
+
+ virtual status_t encrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+ writeVector(data, sessionId);
+ writeVector(data, keyId);
+ writeVector(data, input);
+ writeVector(data, iv);
+
+ remote()->transact(ENCRYPT, data, &reply);
+ readVector(reply, output);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t decrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+ writeVector(data, sessionId);
+ writeVector(data, keyId);
+ writeVector(data, input);
+ writeVector(data, iv);
+
+ remote()->transact(DECRYPT, data, &reply);
+ readVector(reply, output);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t sign(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> &signature) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+ writeVector(data, sessionId);
+ writeVector(data, keyId);
+ writeVector(data, message);
+
+ remote()->transact(SIGN, data, &reply);
+ readVector(reply, signature);
+
+ return reply.readInt32();
+ }
+
+ virtual status_t verify(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &signature,
+ bool &match) {
+ Parcel data, reply;
+ data.writeInterfaceToken(IDrm::getInterfaceDescriptor());
+
+ writeVector(data, sessionId);
+ writeVector(data, keyId);
+ writeVector(data, message);
+ writeVector(data, signature);
+
+ remote()->transact(VERIFY, data, &reply);
+ match = (bool)reply.readInt32();
+ return reply.readInt32();
+ }
+
private:
+ void readVector(Parcel &reply, Vector<uint8_t> &vector) const {
+ uint32_t size = reply.readInt32();
+ vector.insertAt((size_t)0, size);
+ reply.read(vector.editArray(), size);
+ }
+
+ void writeVector(Parcel &data, Vector<uint8_t> const &vector) const {
+ data.writeInt32(vector.size());
+ data.write(vector.array(), vector.size());
+ }
+
DISALLOW_EVIL_CONSTRUCTORS(BpDrm);
};
@@ -301,6 +403,17 @@ IMPLEMENT_META_INTERFACE(Drm, "android.drm.IDrm");
////////////////////////////////////////////////////////////////////////////////
+void BnDrm::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
+ uint32_t size = data.readInt32();
+ vector.insertAt((size_t)0, size);
+ data.read(vector.editArray(), size);
+}
+
+void BnDrm::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
+ reply->writeInt32(vector.size());
+ reply->write(vector.array(), vector.size());
+}
+
status_t BnDrm::onTransact(
uint32_t code, const Parcel &data, Parcel *reply, uint32_t flags) {
switch (code) {
@@ -341,8 +454,7 @@ status_t BnDrm::onTransact(
CHECK_INTERFACE(IDrm, data, reply);
Vector<uint8_t> sessionId;
status_t result = openSession(sessionId);
- reply->writeInt32(sessionId.size());
- reply->write(sessionId.array(), sessionId.size());
+ writeVector(reply, sessionId);
reply->writeInt32(result);
return OK;
}
@@ -351,28 +463,20 @@ status_t BnDrm::onTransact(
{
CHECK_INTERFACE(IDrm, data, reply);
Vector<uint8_t> sessionId;
- uint32_t size = data.readInt32();
- sessionId.insertAt((size_t)0, size);
- data.read(sessionId.editArray(), size);
+ readVector(data, sessionId);
reply->writeInt32(closeSession(sessionId));
return OK;
}
- case GET_LICENSE_REQUEST:
+ case GET_KEY_REQUEST:
{
CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId;
- uint32_t size = data.readInt32();
- sessionId.insertAt((size_t)0, size);
- data.read(sessionId.editArray(), size);
-
- Vector<uint8_t> initData;
- size = data.readInt32();
- initData.insertAt((size_t)0, size);
- data.read(initData.editArray(), size);
+ Vector<uint8_t> sessionId, initData;
+ readVector(data, sessionId);
+ readVector(data, initData);
String8 mimeType = data.readString8();
- DrmPlugin::LicenseType licenseType = (DrmPlugin::LicenseType)data.readInt32();
+ DrmPlugin::KeyType keyType = (DrmPlugin::KeyType)data.readInt32();
KeyedVector<String8, String8> optionalParameters;
uint32_t count = data.readInt32();
@@ -386,55 +490,54 @@ status_t BnDrm::onTransact(
Vector<uint8_t> request;
String8 defaultUrl;
- status_t result = getLicenseRequest(sessionId, initData,
- mimeType, licenseType,
- optionalParameters,
- request, defaultUrl);
- reply->writeInt32(request.size());
- reply->write(request.array(), request.size());
+ status_t result = getKeyRequest(sessionId, initData,
+ mimeType, keyType,
+ optionalParameters,
+ request, defaultUrl);
+ writeVector(reply, request);
reply->writeString8(defaultUrl);
reply->writeInt32(result);
return OK;
}
- case PROVIDE_LICENSE_RESPONSE:
+ case PROVIDE_KEY_RESPONSE:
{
CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId;
- uint32_t size = data.readInt32();
- sessionId.insertAt((size_t)0, size);
- data.read(sessionId.editArray(), size);
- Vector<uint8_t> response;
- size = data.readInt32();
- response.insertAt((size_t)0, size);
- data.read(response.editArray(), size);
+ Vector<uint8_t> sessionId, response, keySetId;
+ readVector(data, sessionId);
+ readVector(data, response);
+ uint32_t result = provideKeyResponse(sessionId, response, keySetId);
+ writeVector(reply, keySetId);
+ reply->writeInt32(result);
+ return OK;
+ }
- reply->writeInt32(provideLicenseResponse(sessionId, response));
+ case REMOVE_KEYS:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+ Vector<uint8_t> keySetId;
+ readVector(data, keySetId);
+ reply->writeInt32(removeKeys(keySetId));
return OK;
}
- case REMOVE_LICENSE:
+ case RESTORE_KEYS:
{
CHECK_INTERFACE(IDrm, data, reply);
- Vector<uint8_t> sessionId;
- uint32_t size = data.readInt32();
- sessionId.insertAt((size_t)0, size);
- data.read(sessionId.editArray(), size);
- reply->writeInt32(removeLicense(sessionId));
+ Vector<uint8_t> sessionId, keySetId;
+ readVector(data, sessionId);
+ readVector(data, keySetId);
+ reply->writeInt32(restoreKeys(sessionId, keySetId));
return OK;
}
- case QUERY_LICENSE_STATUS:
+ case QUERY_KEY_STATUS:
{
CHECK_INTERFACE(IDrm, data, reply);
Vector<uint8_t> sessionId;
- uint32_t size = data.readInt32();
- sessionId.insertAt((size_t)0, size);
- data.read(sessionId.editArray(), size);
+ readVector(data, sessionId);
KeyedVector<String8, String8> infoMap;
-
- status_t result = queryLicenseStatus(sessionId, infoMap);
-
+ status_t result = queryKeyStatus(sessionId, infoMap);
size_t count = infoMap.size();
reply->writeInt32(count);
for (size_t i = 0; i < count; ++i) {
@@ -451,8 +554,7 @@ status_t BnDrm::onTransact(
Vector<uint8_t> request;
String8 defaultUrl;
status_t result = getProvisionRequest(request, defaultUrl);
- reply->writeInt32(request.size());
- reply->write(request.array(), request.size());
+ writeVector(reply, request);
reply->writeString8(defaultUrl);
reply->writeInt32(result);
return OK;
@@ -462,11 +564,8 @@ status_t BnDrm::onTransact(
{
CHECK_INTERFACE(IDrm, data, reply);
Vector<uint8_t> response;
- uint32_t size = data.readInt32();
- response.insertAt((size_t)0, size);
- data.read(response.editArray(), size);
+ readVector(data, response);
reply->writeInt32(provideProvisionResponse(response));
-
return OK;
}
@@ -491,9 +590,7 @@ status_t BnDrm::onTransact(
{
CHECK_INTERFACE(IDrm, data, reply);
Vector<uint8_t> ssRelease;
- uint32_t size = data.readInt32();
- ssRelease.insertAt((size_t)0, size);
- data.read(ssRelease.editArray(), size);
+ readVector(data, ssRelease);
reply->writeInt32(releaseSecureStops(ssRelease));
return OK;
}
@@ -515,8 +612,7 @@ status_t BnDrm::onTransact(
String8 name = data.readString8();
Vector<uint8_t> value;
status_t result = getPropertyByteArray(name, value);
- reply->writeInt32(value.size());
- reply->write(value.array(), value.size());
+ writeVector(reply, value);
reply->writeInt32(result);
return OK;
}
@@ -535,15 +631,89 @@ status_t BnDrm::onTransact(
CHECK_INTERFACE(IDrm, data, reply);
String8 name = data.readString8();
Vector<uint8_t> value;
- size_t count = data.readInt32();
- value.insertAt((size_t)0, count);
- data.read(value.editArray(), count);
+ readVector(data, value);
reply->writeInt32(setPropertyByteArray(name, value));
return OK;
}
- default:
- return BBinder::onTransact(code, data, reply, flags);
+ case SET_CIPHER_ALGORITHM:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+ Vector<uint8_t> sessionId;
+ readVector(data, sessionId);
+ String8 algorithm = data.readString8();
+ reply->writeInt32(setCipherAlgorithm(sessionId, algorithm));
+ return OK;
+ }
+
+ case SET_MAC_ALGORITHM:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+ Vector<uint8_t> sessionId;
+ readVector(data, sessionId);
+ String8 algorithm = data.readString8();
+ reply->writeInt32(setMacAlgorithm(sessionId, algorithm));
+ return OK;
+ }
+
+ case ENCRYPT:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+ Vector<uint8_t> sessionId, keyId, input, iv, output;
+ readVector(data, sessionId);
+ readVector(data, keyId);
+ readVector(data, input);
+ readVector(data, iv);
+ uint32_t result = encrypt(sessionId, keyId, input, iv, output);
+ writeVector(reply, output);
+ reply->writeInt32(result);
+ return OK;
+ }
+
+ case DECRYPT:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+ Vector<uint8_t> sessionId, keyId, input, iv, output;
+ readVector(data, sessionId);
+ readVector(data, keyId);
+ readVector(data, input);
+ readVector(data, iv);
+ uint32_t result = decrypt(sessionId, keyId, input, iv, output);
+ writeVector(reply, output);
+ reply->writeInt32(result);
+ return OK;
+ }
+
+ case SIGN:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+ Vector<uint8_t> sessionId, keyId, message, signature;
+ readVector(data, sessionId);
+ readVector(data, keyId);
+ readVector(data, message);
+ uint32_t result = sign(sessionId, keyId, message, signature);
+ writeVector(reply, signature);
+ reply->writeInt32(result);
+ return OK;
+ }
+
+ case VERIFY:
+ {
+ CHECK_INTERFACE(IDrm, data, reply);
+ Vector<uint8_t> sessionId, keyId, message, signature;
+ readVector(data, sessionId);
+ readVector(data, keyId);
+ readVector(data, message);
+ readVector(data, signature);
+ bool match;
+ uint32_t result = verify(sessionId, keyId, message, signature, match);
+ reply->writeInt32(match);
+ reply->writeInt32(result);
+ return OK;
+ }
+
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
}
}
diff --git a/media/libmedia/ToneGenerator.cpp b/media/libmedia/ToneGenerator.cpp
index 9ea3ea7..f09ce75 100644
--- a/media/libmedia/ToneGenerator.cpp
+++ b/media/libmedia/ToneGenerator.cpp
@@ -986,7 +986,7 @@ void ToneGenerator::stopTone() {
// If the start time is valid, make sure that the number of audio samples produced
// corresponds at least to the time between the start and stop commands.
// This is needed in case of cold start of the output stream.
- if ((mStartTime. tv_sec != 0) && (clock_gettime(CLOCK_MONOTONIC, &stopTime) == 0)) {
+ if ((mStartTime.tv_sec != 0) && (clock_gettime(CLOCK_MONOTONIC, &stopTime) == 0)) {
time_t sec = stopTime.tv_sec - mStartTime.tv_sec;
long nsec = stopTime.tv_nsec - mStartTime.tv_nsec;
long durationMs;
@@ -1000,7 +1000,7 @@ void ToneGenerator::stopTone() {
} else {
// mSamplingRate is always > 1000
sec = sec * 1000 + nsec / 1000000; // duration in milliseconds
- mMaxSmp = (sec * mSamplingRate) / 1000;
+ mMaxSmp = (unsigned int)(((int64_t)sec * mSamplingRate) / 1000);
}
ALOGV("stopTone() forcing mMaxSmp to %d, total for far %d", mMaxSmp, mTotalSmp);
} else {
diff --git a/media/libmediaplayerservice/Drm.cpp b/media/libmediaplayerservice/Drm.cpp
index 6ac7530..5fdb9f4 100644
--- a/media/libmediaplayerservice/Drm.cpp
+++ b/media/libmediaplayerservice/Drm.cpp
@@ -243,11 +243,11 @@ status_t Drm::closeSession(Vector<uint8_t> const &sessionId) {
return mPlugin->closeSession(sessionId);
}
-status_t Drm::getLicenseRequest(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &initData,
- String8 const &mimeType, DrmPlugin::LicenseType licenseType,
- KeyedVector<String8, String8> const &optionalParameters,
- Vector<uint8_t> &request, String8 &defaultUrl) {
+status_t Drm::getKeyRequest(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &initData,
+ String8 const &mimeType, DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const &optionalParameters,
+ Vector<uint8_t> &request, String8 &defaultUrl) {
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) {
@@ -258,12 +258,13 @@ status_t Drm::getLicenseRequest(Vector<uint8_t> const &sessionId,
return -EINVAL;
}
- return mPlugin->getLicenseRequest(sessionId, initData, mimeType, licenseType,
- optionalParameters, request, defaultUrl);
+ return mPlugin->getKeyRequest(sessionId, initData, mimeType, keyType,
+ optionalParameters, request, defaultUrl);
}
-status_t Drm::provideLicenseResponse(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &response) {
+status_t Drm::provideKeyResponse(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &response,
+ Vector<uint8_t> &keySetId) {
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) {
@@ -274,10 +275,10 @@ status_t Drm::provideLicenseResponse(Vector<uint8_t> const &sessionId,
return -EINVAL;
}
- return mPlugin->provideLicenseResponse(sessionId, response);
+ return mPlugin->provideKeyResponse(sessionId, response, keySetId);
}
-status_t Drm::removeLicense(Vector<uint8_t> const &sessionId) {
+status_t Drm::removeKeys(Vector<uint8_t> const &keySetId) {
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) {
@@ -288,11 +289,11 @@ status_t Drm::removeLicense(Vector<uint8_t> const &sessionId) {
return -EINVAL;
}
- return mPlugin->removeLicense(sessionId);
+ return mPlugin->removeKeys(keySetId);
}
-status_t Drm::queryLicenseStatus(Vector<uint8_t> const &sessionId,
- KeyedVector<String8, String8> &infoMap) const {
+status_t Drm::restoreKeys(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keySetId) {
Mutex::Autolock autoLock(mLock);
if (mInitCheck != OK) {
@@ -303,7 +304,22 @@ status_t Drm::queryLicenseStatus(Vector<uint8_t> const &sessionId,
return -EINVAL;
}
- return mPlugin->queryLicenseStatus(sessionId, infoMap);
+ return mPlugin->restoreKeys(sessionId, keySetId);
+}
+
+status_t Drm::queryKeyStatus(Vector<uint8_t> const &sessionId,
+ KeyedVector<String8, String8> &infoMap) const {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPlugin == NULL) {
+ return -EINVAL;
+ }
+
+ return mPlugin->queryKeyStatus(sessionId, infoMap);
}
status_t Drm::getProvisionRequest(Vector<uint8_t> &request, String8 &defaultUrl) {
@@ -420,4 +436,106 @@ status_t Drm::setPropertyByteArray(String8 const &name,
return mPlugin->setPropertyByteArray(name, value);
}
+
+status_t Drm::setCipherAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPlugin == NULL) {
+ return -EINVAL;
+ }
+
+ return mPlugin->setCipherAlgorithm(sessionId, algorithm);
+}
+
+status_t Drm::setMacAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPlugin == NULL) {
+ return -EINVAL;
+ }
+
+ return mPlugin->setMacAlgorithm(sessionId, algorithm);
+}
+
+status_t Drm::encrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPlugin == NULL) {
+ return -EINVAL;
+ }
+
+ return mPlugin->encrypt(sessionId, keyId, input, iv, output);
+}
+
+status_t Drm::decrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPlugin == NULL) {
+ return -EINVAL;
+ }
+
+ return mPlugin->decrypt(sessionId, keyId, input, iv, output);
+}
+
+status_t Drm::sign(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> &signature) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPlugin == NULL) {
+ return -EINVAL;
+ }
+
+ return mPlugin->sign(sessionId, keyId, message, signature);
+}
+
+status_t Drm::verify(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &signature,
+ bool &match) {
+ Mutex::Autolock autoLock(mLock);
+
+ if (mInitCheck != OK) {
+ return mInitCheck;
+ }
+
+ if (mPlugin == NULL) {
+ return -EINVAL;
+ }
+
+ return mPlugin->verify(sessionId, keyId, message, signature, match);
+}
+
} // namespace android
diff --git a/media/libmediaplayerservice/Drm.h b/media/libmediaplayerservice/Drm.h
index 1b10958..f24921e 100644
--- a/media/libmediaplayerservice/Drm.h
+++ b/media/libmediaplayerservice/Drm.h
@@ -45,19 +45,23 @@ struct Drm : public BnDrm {
virtual status_t closeSession(Vector<uint8_t> const &sessionId);
virtual status_t
- getLicenseRequest(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &initData,
- String8 const &mimeType, DrmPlugin::LicenseType licenseType,
- KeyedVector<String8, String8> const &optionalParameters,
- Vector<uint8_t> &request, String8 &defaultUrl);
+ getKeyRequest(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &initData,
+ String8 const &mimeType, DrmPlugin::KeyType keyType,
+ KeyedVector<String8, String8> const &optionalParameters,
+ Vector<uint8_t> &request, String8 &defaultUrl);
- virtual status_t provideLicenseResponse(Vector<uint8_t> const &sessionId,
- Vector<uint8_t> const &response);
+ virtual status_t provideKeyResponse(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &response,
+ Vector<uint8_t> &keySetId);
- virtual status_t removeLicense(Vector<uint8_t> const &sessionId);
+ virtual status_t removeKeys(Vector<uint8_t> const &keySetId);
- virtual status_t queryLicenseStatus(Vector<uint8_t> const &sessionId,
- KeyedVector<String8, String8> &infoMap) const;
+ virtual status_t restoreKeys(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keySetId);
+
+ virtual status_t queryKeyStatus(Vector<uint8_t> const &sessionId,
+ KeyedVector<String8, String8> &infoMap) const;
virtual status_t getProvisionRequest(Vector<uint8_t> &request,
String8 &defaulUrl);
@@ -75,6 +79,35 @@ struct Drm : public BnDrm {
virtual status_t setPropertyByteArray(String8 const &name,
Vector<uint8_t> const &value ) const;
+ virtual status_t setCipherAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm);
+
+ virtual status_t setMacAlgorithm(Vector<uint8_t> const &sessionId,
+ String8 const &algorithm);
+
+ virtual status_t encrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output);
+
+ virtual status_t decrypt(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &input,
+ Vector<uint8_t> const &iv,
+ Vector<uint8_t> &output);
+
+ virtual status_t sign(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> &signature);
+
+ virtual status_t verify(Vector<uint8_t> const &sessionId,
+ Vector<uint8_t> const &keyId,
+ Vector<uint8_t> const &message,
+ Vector<uint8_t> const &signature,
+ bool &match);
+
private:
mutable Mutex mLock;
diff --git a/media/libmediaplayerservice/MediaPlayerFactory.cpp b/media/libmediaplayerservice/MediaPlayerFactory.cpp
index 1fb8b1a..90aed39 100644
--- a/media/libmediaplayerservice/MediaPlayerFactory.cpp
+++ b/media/libmediaplayerservice/MediaPlayerFactory.cpp
@@ -206,7 +206,8 @@ class NuPlayerFactory : public MediaPlayerFactory::IFactory {
return 0.0;
if (!strncasecmp("http://", url, 7)
- || !strncasecmp("https://", url, 8)) {
+ || !strncasecmp("https://", url, 8)
+ || !strncasecmp("file://", url, 7)) {
size_t len = strlen(url);
if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
return kOurScore;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index 5387e1a..46d0a5a 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -161,7 +161,8 @@ void NuPlayer::setDataSourceAsync(const sp<IStreamSource> &source) {
static bool IsHTTPLiveURL(const char *url) {
if (!strncasecmp("http://", url, 7)
- || !strncasecmp("https://", url, 8)) {
+ || !strncasecmp("https://", url, 8)
+ || !strncasecmp("file://", url, 7)) {
size_t len = strlen(url);
if (len >= 5 && !strcasecmp(".m3u8", &url[len - 5])) {
return true;
@@ -833,14 +834,6 @@ status_t NuPlayer::instantiateDecoder(bool audio, sp<Decoder> *decoder) {
(*decoder)->configure(format);
- int64_t durationUs;
- if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
- sp<NuPlayerDriver> driver = mDriver.promote();
- if (driver != NULL) {
- driver->notifyDuration(durationUs);
- }
- }
-
return OK;
}
@@ -1271,6 +1264,14 @@ void NuPlayer::onSourceNotify(const sp<AMessage> &msg) {
if (driver != NULL) {
driver->notifyPrepareCompleted(err);
}
+
+ int64_t durationUs;
+ if (mDriver != NULL && mSource->getDuration(&durationUs) == OK) {
+ sp<NuPlayerDriver> driver = mDriver.promote();
+ if (driver != NULL) {
+ driver->notifyDuration(durationUs);
+ }
+ }
break;
}
diff --git a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
index 7719435..5749733 100644
--- a/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
+++ b/media/libstagefright/codecs/aacenc/SoftAACEncoder2.cpp
@@ -481,7 +481,7 @@ void SoftAACEncoder2::onQueueFilled(OMX_U32 portIndex) {
void* inBuffer[] = { (unsigned char *)mInputFrame };
INT inBufferIds[] = { IN_AUDIO_DATA };
- INT inBufferSize[] = { numBytesPerInputFrame };
+ INT inBufferSize[] = { (INT)numBytesPerInputFrame };
INT inBufferElSize[] = { sizeof(int16_t) };
AACENC_BufDesc inBufDesc;
diff --git a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
index 07f8b4f..50b739c 100644
--- a/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
+++ b/media/libstagefright/codecs/amrnb/enc/SoftAMRNBEncoder.cpp
@@ -257,7 +257,7 @@ OMX_ERRORTYPE SoftAMRNBEncoder::internalSetParameter(
}
if (pcmParams->nChannels != 1
- || pcmParams->nSamplingRate != kSampleRate) {
+ || pcmParams->nSamplingRate != (OMX_U32)kSampleRate) {
return OMX_ErrorUndefined;
}
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index cc38dc3..e25637a 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -655,7 +655,8 @@ void SoftVPXEncoder::onQueueFilled(OMX_U32 portIndex) {
vpx_codec_iter_t encoded_packet_iterator = NULL;
const vpx_codec_cx_pkt_t* encoded_packet;
- while (encoded_packet = vpx_codec_get_cx_data(mCodecContext, &encoded_packet_iterator)) {
+ while ((encoded_packet = vpx_codec_get_cx_data(
+ mCodecContext, &encoded_packet_iterator))) {
if (encoded_packet->kind == VPX_CODEC_CX_FRAME_PKT) {
outputBufferHeader->nTimeStamp = encoded_packet->data.frame.pts;
outputBufferHeader->nFlags = 0;
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 962b01c..505bdb3 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -631,22 +631,20 @@ rinse_repeat:
if (index < mPlaylist->size()) {
int32_t newSeqNumber = firstSeqNumberInPlaylist + index;
- if (newSeqNumber != mSeqNumber) {
- ALOGI("seeking to seq no %d", newSeqNumber);
+ ALOGI("seeking to seq no %d", newSeqNumber);
- mSeqNumber = newSeqNumber;
+ mSeqNumber = newSeqNumber;
- mDataSource->reset();
+ mDataSource->reset();
- // reseting the data source will have had the
- // side effect of discarding any previously queued
- // bandwidth change discontinuity.
- // Therefore we'll need to treat these seek
- // discontinuities as involving a bandwidth change
- // even if they aren't directly.
- seekDiscontinuity = true;
- bandwidthChanged = true;
- }
+ // reseting the data source will have had the
+ // side effect of discarding any previously queued
+ // bandwidth change discontinuity.
+ // Therefore we'll need to treat these seek
+ // discontinuities as involving a bandwidth change
+ // even if they aren't directly.
+ seekDiscontinuity = true;
+ bandwidthChanged = true;
}
}
diff --git a/media/libstagefright/wifi-display/ANetworkSession.cpp b/media/libstagefright/wifi-display/ANetworkSession.cpp
index 88ca1cc..f074438 100644
--- a/media/libstagefright/wifi-display/ANetworkSession.cpp
+++ b/media/libstagefright/wifi-display/ANetworkSession.cpp
@@ -451,24 +451,6 @@ status_t ANetworkSession::Session::writeMore() {
const Fragment &frag = *mOutFragments.begin();
const sp<ABuffer> &datagram = frag.mBuffer;
- uint8_t *data = datagram->data();
- if (data[0] == 0x80 && (data[1] & 0x7f) == 33) {
- int64_t nowUs = ALooper::GetNowUs();
-
- uint32_t prevRtpTime = U32_AT(&data[4]);
-
- // 90kHz time scale
- uint32_t rtpTime = (nowUs * 9ll) / 100ll;
- int32_t diffTime = (int32_t)rtpTime - (int32_t)prevRtpTime;
-
- ALOGV("correcting rtpTime by %.0f ms", diffTime / 90.0);
-
- data[4] = rtpTime >> 24;
- data[5] = (rtpTime >> 16) & 0xff;
- data[6] = (rtpTime >> 8) & 0xff;
- data[7] = rtpTime & 0xff;
- }
-
int n;
do {
n = send(mSocket, datagram->data(), datagram->size(), 0);
@@ -874,6 +856,14 @@ status_t ANetworkSession::createClientOrServer(
err = -errno;
goto bail2;
}
+
+ int tos = 224; // VOICE
+ res = setsockopt(s, IPPROTO_IP, IP_TOS, &tos, sizeof(tos));
+
+ if (res < 0) {
+ err = -errno;
+ goto bail2;
+ }
}
err = MakeSocketNonBlocking(s);
diff --git a/media/libstagefright/wifi-display/Android.mk b/media/libstagefright/wifi-display/Android.mk
index f1f9f45..1578c21 100644
--- a/media/libstagefright/wifi-display/Android.mk
+++ b/media/libstagefright/wifi-display/Android.mk
@@ -109,3 +109,25 @@ LOCAL_MODULE:= rtptest
LOCAL_MODULE_TAGS := debug
include $(BUILD_EXECUTABLE)
+
+################################################################################
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ nettest.cpp \
+
+LOCAL_SHARED_LIBRARIES:= \
+ libbinder \
+ libgui \
+ libmedia \
+ libstagefright \
+ libstagefright_foundation \
+ libstagefright_wfd \
+ libutils \
+
+LOCAL_MODULE:= nettest
+
+LOCAL_MODULE_TAGS := debug
+
+include $(BUILD_EXECUTABLE)
diff --git a/media/libstagefright/wifi-display/TimeSyncer.cpp b/media/libstagefright/wifi-display/TimeSyncer.cpp
index 64e182e..cb429bc 100644
--- a/media/libstagefright/wifi-display/TimeSyncer.cpp
+++ b/media/libstagefright/wifi-display/TimeSyncer.cpp
@@ -102,6 +102,10 @@ void TimeSyncer::onMessageReceived(const sp<AMessage> &msg) {
case kWhatSendPacket:
{
+ if (mHistory.size() == 0) {
+ ALOGI("starting batch");
+ }
+
TimeInfo ti;
memset(&ti, 0, sizeof(ti));
@@ -229,6 +233,8 @@ void TimeSyncer::onMessageReceived(const sp<AMessage> &msg) {
} else {
notifyOffset();
+ ALOGI("batch done");
+
mHistory.clear();
postSendPacket(kBatchDelayUs);
}
diff --git a/media/libstagefright/wifi-display/TimeSyncer.h b/media/libstagefright/wifi-display/TimeSyncer.h
index 0e3aed7..4e7571f 100644
--- a/media/libstagefright/wifi-display/TimeSyncer.h
+++ b/media/libstagefright/wifi-display/TimeSyncer.h
@@ -75,7 +75,7 @@ private:
kNumPacketsPerBatch = 30,
};
static const int64_t kTimeoutDelayUs = 500000ll;
- static const int64_t kBatchDelayUs = 10000000ll; // every 10 secs
+ static const int64_t kBatchDelayUs = 60000000ll; // every minute
sp<ANetworkSession> mNetSession;
sp<AMessage> mNotify;
diff --git a/media/libstagefright/wifi-display/nettest.cpp b/media/libstagefright/wifi-display/nettest.cpp
new file mode 100644
index 0000000..0779bf5
--- /dev/null
+++ b/media/libstagefright/wifi-display/nettest.cpp
@@ -0,0 +1,400 @@
+/*
+ * Copyright 2013, 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_NEBUG 0
+#define LOG_TAG "nettest"
+#include <utils/Log.h>
+
+#include "ANetworkSession.h"
+#include "TimeSyncer.h"
+
+#include <binder/ProcessState.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <media/stagefright/foundation/AHandler.h>
+#include <media/stagefright/foundation/ALooper.h>
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/hexdump.h>
+#include <media/stagefright/DataSource.h>
+#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/NuMediaExtractor.h>
+#include <media/stagefright/Utils.h>
+
+namespace android {
+
+struct TestHandler : public AHandler {
+ TestHandler(const sp<ANetworkSession> &netSession);
+
+ void listen(int32_t port);
+ void connect(const char *host, int32_t port);
+
+protected:
+ virtual ~TestHandler();
+ virtual void onMessageReceived(const sp<AMessage> &msg);
+
+private:
+ enum {
+ kTimeSyncerPort = 8123,
+ };
+
+ enum {
+ kWhatListen,
+ kWhatConnect,
+ kWhatTimeSyncerNotify,
+ kWhatNetNotify,
+ kWhatSendMore,
+ kWhatStop,
+ };
+
+ sp<ANetworkSession> mNetSession;
+ sp<TimeSyncer> mTimeSyncer;
+
+ int32_t mServerSessionID;
+ int32_t mSessionID;
+
+ int64_t mTimeOffsetUs;
+ bool mTimeOffsetValid;
+
+ int32_t mCounter;
+
+ int64_t mMaxDelayMs;
+
+ void dumpDelay(int32_t counter, int64_t delayMs);
+
+ DISALLOW_EVIL_CONSTRUCTORS(TestHandler);
+};
+
+TestHandler::TestHandler(const sp<ANetworkSession> &netSession)
+ : mNetSession(netSession),
+ mServerSessionID(0),
+ mSessionID(0),
+ mTimeOffsetUs(-1ll),
+ mTimeOffsetValid(false),
+ mCounter(0),
+ mMaxDelayMs(-1ll) {
+}
+
+TestHandler::~TestHandler() {
+}
+
+void TestHandler::listen(int32_t port) {
+ sp<AMessage> msg = new AMessage(kWhatListen, id());
+ msg->setInt32("port", port);
+ msg->post();
+}
+
+void TestHandler::connect(const char *host, int32_t port) {
+ sp<AMessage> msg = new AMessage(kWhatConnect, id());
+ msg->setString("host", host);
+ msg->setInt32("port", port);
+ msg->post();
+}
+
+void TestHandler::dumpDelay(int32_t counter, int64_t delayMs) {
+ 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;
+ }
+
+ if (delayMs > mMaxDelayMs) {
+ mMaxDelayMs = delayMs;
+ }
+
+ ALOGI("[%d] (%4lld ms / %4lld ms) %s",
+ counter,
+ delayMs,
+ mMaxDelayMs,
+ kPattern + kPatternSize - n);
+}
+
+void TestHandler::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatListen:
+ {
+ sp<AMessage> notify = new AMessage(kWhatTimeSyncerNotify, id());
+ mTimeSyncer = new TimeSyncer(mNetSession, notify);
+ looper()->registerHandler(mTimeSyncer);
+
+ notify = new AMessage(kWhatNetNotify, id());
+
+ int32_t port;
+ CHECK(msg->findInt32("port", &port));
+
+ struct in_addr ifaceAddr;
+ ifaceAddr.s_addr = INADDR_ANY;
+
+ CHECK_EQ((status_t)OK,
+ mNetSession->createTCPDatagramSession(
+ ifaceAddr,
+ port,
+ notify,
+ &mServerSessionID));
+ break;
+ }
+
+ case kWhatConnect:
+ {
+ sp<AMessage> notify = new AMessage(kWhatTimeSyncerNotify, id());
+ mTimeSyncer = new TimeSyncer(mNetSession, notify);
+ looper()->registerHandler(mTimeSyncer);
+ mTimeSyncer->startServer(kTimeSyncerPort);
+
+ AString host;
+ CHECK(msg->findString("host", &host));
+
+ int32_t port;
+ CHECK(msg->findInt32("port", &port));
+
+ notify = new AMessage(kWhatNetNotify, id());
+
+ CHECK_EQ((status_t)OK,
+ mNetSession->createTCPDatagramSession(
+ 0 /* localPort */,
+ host.c_str(),
+ port,
+ notify,
+ &mSessionID));
+ break;
+ }
+
+ case kWhatNetNotify:
+ {
+ int32_t reason;
+ CHECK(msg->findInt32("reason", &reason));
+
+ switch (reason) {
+ case ANetworkSession::kWhatConnected:
+ {
+ ALOGI("kWhatConnected");
+
+ (new AMessage(kWhatSendMore, id()))->post();
+ break;
+ }
+
+ case ANetworkSession::kWhatClientConnected:
+ {
+ ALOGI("kWhatClientConnected");
+
+ CHECK_EQ(mSessionID, 0);
+ CHECK(msg->findInt32("sessionID", &mSessionID));
+
+ AString clientIP;
+ CHECK(msg->findString("client-ip", &clientIP));
+
+ mTimeSyncer->startClient(clientIP.c_str(), kTimeSyncerPort);
+ break;
+ }
+
+ case ANetworkSession::kWhatDatagram:
+ {
+ sp<ABuffer> packet;
+ CHECK(msg->findBuffer("data", &packet));
+
+ CHECK_EQ(packet->size(), 12u);
+
+ int32_t counter = U32_AT(packet->data());
+ int64_t timeUs = U64_AT(packet->data() + 4);
+
+ if (mTimeOffsetValid) {
+ timeUs -= mTimeOffsetUs;
+ int64_t nowUs = ALooper::GetNowUs();
+ int64_t delayMs = (nowUs - timeUs) / 1000ll;
+
+ dumpDelay(counter, delayMs);
+ } else {
+ ALOGI("received %d", counter);
+ }
+ break;
+ }
+
+ case ANetworkSession::kWhatError:
+ {
+ ALOGE("kWhatError");
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+ break;
+ }
+
+ case kWhatTimeSyncerNotify:
+ {
+ CHECK(msg->findInt64("offset", &mTimeOffsetUs));
+ mTimeOffsetValid = true;
+ break;
+ }
+
+ case kWhatSendMore:
+ {
+ uint8_t buffer[4 + 8];
+ buffer[0] = mCounter >> 24;
+ buffer[1] = (mCounter >> 16) & 0xff;
+ buffer[2] = (mCounter >> 8) & 0xff;
+ buffer[3] = mCounter & 0xff;
+
+ int64_t nowUs = ALooper::GetNowUs();
+
+ buffer[4] = nowUs >> 56;
+ buffer[5] = (nowUs >> 48) & 0xff;
+ buffer[6] = (nowUs >> 40) & 0xff;
+ buffer[7] = (nowUs >> 32) & 0xff;
+ buffer[8] = (nowUs >> 24) & 0xff;
+ buffer[9] = (nowUs >> 16) & 0xff;
+ buffer[10] = (nowUs >> 8) & 0xff;
+ buffer[11] = nowUs & 0xff;
+
+ ++mCounter;
+
+ CHECK_EQ((status_t)OK,
+ mNetSession->sendRequest(
+ mSessionID,
+ buffer,
+ sizeof(buffer),
+ true /* timeValid */,
+ nowUs));
+
+ msg->post(100000ll);
+ break;
+ }
+
+ case kWhatStop:
+ {
+ if (mSessionID != 0) {
+ mNetSession->destroySession(mSessionID);
+ mSessionID = 0;
+ }
+
+ if (mServerSessionID != 0) {
+ mNetSession->destroySession(mServerSessionID);
+ mServerSessionID = 0;
+ }
+
+ looper()->stop();
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+}
+
+} // namespace android
+
+static void usage(const char *me) {
+ fprintf(stderr,
+ "usage: %s -c host:port\tconnect to remote host\n"
+ " -l port \tlisten\n",
+ me);
+}
+
+int main(int argc, char **argv) {
+ using namespace android;
+
+ // srand(time(NULL));
+
+ ProcessState::self()->startThreadPool();
+
+ DataSource::RegisterDefaultSniffers();
+
+ int32_t connectToPort = -1;
+ AString connectToHost;
+
+ int32_t listenOnPort = -1;
+
+ int res;
+ while ((res = getopt(argc, argv, "hc:l:")) >= 0) {
+ switch (res) {
+ case 'c':
+ {
+ const char *colonPos = strrchr(optarg, ':');
+
+ if (colonPos == NULL) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ connectToHost.setTo(optarg, colonPos - optarg);
+
+ char *end;
+ connectToPort = strtol(colonPos + 1, &end, 10);
+
+ if (*end != '\0' || end == colonPos + 1
+ || connectToPort < 0 || connectToPort > 65535) {
+ fprintf(stderr, "Illegal port specified.\n");
+ exit(1);
+ }
+ break;
+ }
+
+ case 'l':
+ {
+ char *end;
+ listenOnPort = strtol(optarg, &end, 10);
+
+ if (*end != '\0' || end == optarg
+ || listenOnPort < 0 || listenOnPort > 65535) {
+ fprintf(stderr, "Illegal port specified.\n");
+ exit(1);
+ }
+ break;
+ }
+
+ case '?':
+ case 'h':
+ usage(argv[0]);
+ exit(1);
+ }
+ }
+
+ if ((listenOnPort < 0 && connectToPort < 0)
+ || (listenOnPort >= 0 && connectToPort >= 0)) {
+ fprintf(stderr,
+ "You need to select either client or server mode.\n");
+ exit(1);
+ }
+
+ sp<ANetworkSession> netSession = new ANetworkSession;
+ netSession->start();
+
+ sp<ALooper> looper = new ALooper;
+
+ sp<TestHandler> handler = new TestHandler(netSession);
+ looper->registerHandler(handler);
+
+ if (listenOnPort) {
+ handler->listen(listenOnPort);
+ }
+
+ if (connectToPort >= 0) {
+ handler->connect(connectToHost.c_str(), connectToPort);
+ }
+
+ looper->start(true /* runOnCallingThread */);
+
+ return 0;
+}
diff --git a/media/libstagefright/wifi-display/rtp/RTPAssembler.cpp b/media/libstagefright/wifi-display/rtp/RTPAssembler.cpp
index 5f189e7..7a96081 100644
--- a/media/libstagefright/wifi-display/rtp/RTPAssembler.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPAssembler.cpp
@@ -40,7 +40,6 @@ void RTPReceiver::Assembler::postAccessUnit(
notify->setInt32("followsDiscontinuity", followsDiscontinuity);
notify->post();
}
-
////////////////////////////////////////////////////////////////////////////////
RTPReceiver::TSAssembler::TSAssembler(const sp<AMessage> &notify)
diff --git a/media/libstagefright/wifi-display/rtp/RTPBase.h b/media/libstagefright/wifi-display/rtp/RTPBase.h
index e3fa845..6178f00 100644
--- a/media/libstagefright/wifi-display/rtp/RTPBase.h
+++ b/media/libstagefright/wifi-display/rtp/RTPBase.h
@@ -25,6 +25,7 @@ struct RTPBase {
PACKETIZATION_TRANSPORT_STREAM,
PACKETIZATION_H264,
PACKETIZATION_AAC,
+ PACKETIZATION_NONE,
};
enum TransportMode {
diff --git a/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp b/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp
index 238fb82..8fa1dae 100644
--- a/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPReceiver.cpp
@@ -30,11 +30,13 @@
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/Utils.h>
+#define TRACK_PACKET_LOSS 0
+
namespace android {
////////////////////////////////////////////////////////////////////////////////
-struct RTPReceiver::Source : public RefBase {
+struct RTPReceiver::Source : public AHandler {
Source(RTPReceiver *receiver, uint32_t ssrc);
void onPacketReceived(uint16_t seq, const sp<ABuffer> &buffer);
@@ -44,7 +46,14 @@ struct RTPReceiver::Source : public RefBase {
protected:
virtual ~Source();
+ virtual void onMessageReceived(const sp<AMessage> &msg);
+
private:
+ enum {
+ kWhatRetransmit,
+ kWhatDeclareLost,
+ };
+
static const uint32_t kMinSequential = 2;
static const uint32_t kMaxDropout = 3000;
static const uint32_t kMaxMisorder = 100;
@@ -67,6 +76,17 @@ private:
// Ordered by extended seq number.
List<sp<ABuffer> > mPackets;
+ enum StatusBits {
+ STATUS_DECLARED_LOST = 1,
+ STATUS_REQUESTED_RETRANSMISSION = 2,
+ STATUS_ARRIVED_LATE = 4,
+ };
+#if TRACK_PACKET_LOSS
+ KeyedVector<int32_t, uint32_t> mLostPackets;
+#endif
+
+ void modifyPacketStatus(int32_t extSeqNo, uint32_t mask);
+
int32_t mAwaitingExtSeqNo;
bool mRequestedRetransmission;
@@ -78,12 +98,20 @@ private:
int32_t mNumDeclaredLost;
int32_t mNumDeclaredLostPrior;
+ int32_t mRetransmitGeneration;
+ int32_t mDeclareLostGeneration;
+ bool mDeclareLostTimerPending;
+
void queuePacket(const sp<ABuffer> &packet);
void dequeueMore();
sp<ABuffer> getNextPacket();
void resync();
+ void postRetransmitTimer(int64_t delayUs);
+ void postDeclareLostTimer(int64_t delayUs);
+ void cancelTimers();
+
DISALLOW_EVIL_CONSTRUCTORS(Source);
};
@@ -106,12 +134,71 @@ RTPReceiver::Source::Source(RTPReceiver *receiver, uint32_t ssrc)
mActivePacketType(-1),
mNextReportTimeUs(-1ll),
mNumDeclaredLost(0),
- mNumDeclaredLostPrior(0) {
+ mNumDeclaredLostPrior(0),
+ mRetransmitGeneration(0),
+ mDeclareLostGeneration(0),
+ mDeclareLostTimerPending(false) {
}
RTPReceiver::Source::~Source() {
}
+void RTPReceiver::Source::onMessageReceived(const sp<AMessage> &msg) {
+ switch (msg->what()) {
+ case kWhatRetransmit:
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+
+ if (generation != mRetransmitGeneration) {
+ break;
+ }
+
+ mRequestedRetransmission = true;
+ mReceiver->requestRetransmission(mSSRC, mAwaitingExtSeqNo);
+
+ modifyPacketStatus(
+ mAwaitingExtSeqNo, STATUS_REQUESTED_RETRANSMISSION);
+ break;
+ }
+
+ case kWhatDeclareLost:
+ {
+ int32_t generation;
+ CHECK(msg->findInt32("generation", &generation));
+
+ if (generation != mDeclareLostGeneration) {
+ break;
+ }
+
+ cancelTimers();
+
+ ALOGV("Lost packet extSeqNo %d %s",
+ mAwaitingExtSeqNo,
+ mRequestedRetransmission ? "*" : "");
+
+ mRequestedRetransmission = false;
+ if (mActiveAssembler != NULL) {
+ mActiveAssembler->signalDiscontinuity();
+ }
+
+ modifyPacketStatus(mAwaitingExtSeqNo, STATUS_DECLARED_LOST);
+
+ // resync();
+ ++mAwaitingExtSeqNo;
+ ++mNumDeclaredLost;
+
+ mReceiver->notifyPacketLost();
+
+ dequeueMore();
+ break;
+ }
+
+ default:
+ TRESPASS();
+ }
+}
+
void RTPReceiver::Source::onPacketReceived(
uint16_t seq, const sp<ABuffer> &buffer) {
if (mFirst) {
@@ -164,6 +251,8 @@ void RTPReceiver::Source::queuePacket(const sp<ABuffer> &packet) {
if (mAwaitingExtSeqNo >= 0 && newExtendedSeqNo < mAwaitingExtSeqNo) {
// We're no longer interested in these. They're old.
ALOGV("dropping stale extSeqNo %d", newExtendedSeqNo);
+
+ modifyPacketStatus(newExtendedSeqNo, STATUS_ARRIVED_LATE);
return;
}
@@ -230,85 +319,89 @@ void RTPReceiver::Source::dequeueMore() {
}
mNextReportTimeUs = nowUs + kReportIntervalUs;
- }
- for (;;) {
- sp<ABuffer> packet = getNextPacket();
+#if TRACK_PACKET_LOSS
+ for (size_t i = 0; i < mLostPackets.size(); ++i) {
+ int32_t key = mLostPackets.keyAt(i);
+ uint32_t value = mLostPackets.valueAt(i);
- if (packet == NULL) {
- if (mPackets.empty()) {
- break;
+ AString status;
+ if (value & STATUS_REQUESTED_RETRANSMISSION) {
+ status.append("retrans ");
+ }
+ if (value & STATUS_ARRIVED_LATE) {
+ status.append("arrived-late ");
}
+ ALOGI("Packet %d declared lost %s", key, status.c_str());
+ }
+#endif
+ }
+
+ sp<ABuffer> packet;
+ while ((packet = getNextPacket()) != NULL) {
+ if (mDeclareLostTimerPending) {
+ cancelTimers();
+ }
+
+ CHECK_GE(mAwaitingExtSeqNo, 0);
+#if TRACK_PACKET_LOSS
+ mLostPackets.removeItem(mAwaitingExtSeqNo);
+#endif
- CHECK_GE(mAwaitingExtSeqNo, 0);
+ int32_t packetType;
+ CHECK(packet->meta()->findInt32("PT", &packetType));
- const sp<ABuffer> &firstPacket = *mPackets.begin();
+ if (packetType != mActivePacketType) {
+ mActiveAssembler = mReceiver->makeAssembler(packetType);
+ mActivePacketType = packetType;
+ }
- uint32_t rtpTime;
- CHECK(firstPacket->meta()->findInt32(
- "rtp-time", (int32_t *)&rtpTime));
+ if (mActiveAssembler != NULL) {
+ status_t err = mActiveAssembler->processPacket(packet);
+ if (err != OK) {
+ ALOGV("assembler returned error %d", err);
+ }
+ }
+ ++mAwaitingExtSeqNo;
+ }
- int64_t rtpUs = (rtpTime * 100ll) / 9ll;
+ if (mDeclareLostTimerPending) {
+ return;
+ }
- int64_t maxArrivalTimeUs =
- mFirstArrivalTimeUs + rtpUs - mFirstRTPTimeUs;
+ if (mPackets.empty()) {
+ return;
+ }
- int64_t nowUs = ALooper::GetNowUs();
+ CHECK_GE(mAwaitingExtSeqNo, 0);
- CHECK_LT(mAwaitingExtSeqNo, firstPacket->int32Data());
+ const sp<ABuffer> &firstPacket = *mPackets.begin();
- ALOGV("waiting for %d, comparing against %d, %lld us left",
- mAwaitingExtSeqNo,
- firstPacket->int32Data(),
- maxArrivalTimeUs - nowUs);
+ uint32_t rtpTime;
+ CHECK(firstPacket->meta()->findInt32(
+ "rtp-time", (int32_t *)&rtpTime));
- if (maxArrivalTimeUs + kPacketLostAfterUs <= nowUs) {
- ALOGV("Lost packet extSeqNo %d %s",
- mAwaitingExtSeqNo,
- mRequestedRetransmission ? "*" : "");
- mRequestedRetransmission = false;
- if (mActiveAssembler != NULL) {
- mActiveAssembler->signalDiscontinuity();
- }
+ int64_t rtpUs = (rtpTime * 100ll) / 9ll;
- // resync();
- ++mAwaitingExtSeqNo;
- ++mNumDeclaredLost;
-
- mReceiver->notifyPacketLost();
- continue;
- } else if (kRequestRetransmissionAfterUs > 0
- && maxArrivalTimeUs + kRequestRetransmissionAfterUs <= nowUs
- && !mRequestedRetransmission
- && mAwaitingExtSeqNo >= 0) {
- mRequestedRetransmission = true;
- mReceiver->requestRetransmission(mSSRC, mAwaitingExtSeqNo);
- break;
- } else {
- break;
- }
- }
+ int64_t maxArrivalTimeUs =
+ mFirstArrivalTimeUs + rtpUs - mFirstRTPTimeUs;
- mRequestedRetransmission = false;
+ nowUs = ALooper::GetNowUs();
- int32_t packetType;
- CHECK(packet->meta()->findInt32("PT", &packetType));
+ CHECK_LT(mAwaitingExtSeqNo, firstPacket->int32Data());
- if (packetType != mActivePacketType) {
- mActiveAssembler = mReceiver->makeAssembler(packetType);
- mActivePacketType = packetType;
- }
+ ALOGV("waiting for %d, comparing against %d, %lld us left",
+ mAwaitingExtSeqNo,
+ firstPacket->int32Data(),
+ maxArrivalTimeUs - nowUs);
- if (mActiveAssembler == NULL) {
- continue;
- }
+ postDeclareLostTimer(maxArrivalTimeUs + kPacketLostAfterUs);
- status_t err = mActiveAssembler->processPacket(packet);
- if (err != OK) {
- ALOGV("assembler returned error %d", err);
- }
+ if (kRequestRetransmissionAfterUs > 0ll) {
+ postRetransmitTimer(
+ maxArrivalTimeUs + kRequestRetransmissionAfterUs);
}
}
@@ -328,8 +421,6 @@ sp<ABuffer> RTPReceiver::Source::getNextPacket() {
sp<ABuffer> packet = *mPackets.begin();
mPackets.erase(mPackets.begin());
- ++mAwaitingExtSeqNo;
-
return packet;
}
@@ -404,9 +495,11 @@ void RTPReceiver::Source::addReportBlock(
RTPReceiver::RTPReceiver(
const sp<ANetworkSession> &netSession,
- const sp<AMessage> &notify)
+ const sp<AMessage> &notify,
+ uint32_t flags)
: mNetSession(netSession),
mNotify(notify),
+ mFlags(flags),
mRTPMode(TRANSPORT_UNDEFINED),
mRTCPMode(TRANSPORT_UNDEFINED),
mRTPSessionID(0),
@@ -693,6 +786,20 @@ void RTPReceiver::onNetNotify(bool isRTP, const sp<AMessage> &msg) {
CHECK(msg->findBuffer("data", &data));
if (isRTP) {
+ if (mFlags & FLAG_AUTO_CONNECT) {
+ AString fromAddr;
+ CHECK(msg->findString("fromAddr", &fromAddr));
+
+ int32_t fromPort;
+ CHECK(msg->findInt32("fromPort", &fromPort));
+
+ CHECK_EQ((status_t)OK,
+ connect(
+ fromAddr.c_str(), fromPort, fromPort + 1));
+
+ mFlags &= ~FLAG_AUTO_CONNECT;
+ }
+
onRTPData(data);
} else {
onRTCPData(data);
@@ -835,6 +942,8 @@ status_t RTPReceiver::onRTPData(const sp<ABuffer> &buffer) {
sp<Source> source;
if (index < 0) {
source = new Source(this, srcId);
+ looper()->registerHandler(source);
+
mSources.add(srcId, source);
} else {
source = mSources.valueAt(index);
@@ -965,6 +1074,7 @@ sp<RTPReceiver::Assembler> RTPReceiver::makeAssembler(uint8_t packetType) {
PacketizationMode mode = mPacketTypes.valueAt(index);
switch (mode) {
+ case PACKETIZATION_NONE:
case PACKETIZATION_TRANSPORT_STREAM:
return new TSAssembler(mNotify);
@@ -1005,5 +1115,39 @@ void RTPReceiver::requestRetransmission(uint32_t senderSSRC, int32_t extSeqNo) {
mNetSession->sendRequest(mRTCPSessionID, buf->data(), buf->size());
}
+void RTPReceiver::Source::modifyPacketStatus(int32_t extSeqNo, uint32_t mask) {
+#if TRACK_PACKET_LOSS
+ ssize_t index = mLostPackets.indexOfKey(extSeqNo);
+ if (index < 0) {
+ mLostPackets.add(extSeqNo, mask);
+ } else {
+ mLostPackets.editValueAt(index) |= mask;
+ }
+#endif
+}
+
+void RTPReceiver::Source::postRetransmitTimer(int64_t timeUs) {
+ int64_t delayUs = timeUs - ALooper::GetNowUs();
+ sp<AMessage> msg = new AMessage(kWhatRetransmit, id());
+ msg->setInt32("generation", mRetransmitGeneration);
+ msg->post(delayUs);
+}
+
+void RTPReceiver::Source::postDeclareLostTimer(int64_t timeUs) {
+ CHECK(!mDeclareLostTimerPending);
+ mDeclareLostTimerPending = true;
+
+ int64_t delayUs = timeUs - ALooper::GetNowUs();
+ sp<AMessage> msg = new AMessage(kWhatDeclareLost, id());
+ msg->setInt32("generation", mDeclareLostGeneration);
+ msg->post(delayUs);
+}
+
+void RTPReceiver::Source::cancelTimers() {
+ ++mRetransmitGeneration;
+ ++mDeclareLostGeneration;
+ mDeclareLostTimerPending = false;
+}
+
} // namespace android
diff --git a/media/libstagefright/wifi-display/rtp/RTPReceiver.h b/media/libstagefright/wifi-display/rtp/RTPReceiver.h
index 630bce9..240ab2e 100644
--- a/media/libstagefright/wifi-display/rtp/RTPReceiver.h
+++ b/media/libstagefright/wifi-display/rtp/RTPReceiver.h
@@ -39,9 +39,14 @@ struct RTPReceiver : public RTPBase, public AHandler {
kWhatAccessUnit,
kWhatPacketLost,
};
+
+ enum Flags {
+ FLAG_AUTO_CONNECT = 1,
+ };
RTPReceiver(
const sp<ANetworkSession> &netSession,
- const sp<AMessage> &notify);
+ const sp<AMessage> &notify,
+ uint32_t flags = 0);
status_t registerPacketType(
uint8_t packetType, PacketizationMode mode);
@@ -82,6 +87,7 @@ private:
sp<ANetworkSession> mNetSession;
sp<AMessage> mNotify;
+ uint32_t mFlags;
TransportMode mRTPMode;
TransportMode mRTCPMode;
int32_t mRTPSessionID;
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.cpp b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
index 9eeeabd..6bbe650 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.cpp
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.cpp
@@ -187,6 +187,10 @@ status_t RTPSender::queueBuffer(
status_t err;
switch (mode) {
+ case PACKETIZATION_NONE:
+ err = queueRawPacket(buffer, packetType);
+ break;
+
case PACKETIZATION_TRANSPORT_STREAM:
err = queueTSPackets(buffer, packetType);
break;
@@ -202,6 +206,46 @@ status_t RTPSender::queueBuffer(
return err;
}
+status_t RTPSender::queueRawPacket(
+ const sp<ABuffer> &packet, uint8_t packetType) {
+ CHECK_LE(packet->size(), kMaxUDPPacketSize - 12);
+
+ int64_t timeUs;
+ CHECK(packet->meta()->findInt64("timeUs", &timeUs));
+
+ sp<ABuffer> udpPacket = new ABuffer(12 + packet->size());
+
+ udpPacket->setInt32Data(mRTPSeqNo);
+
+ uint8_t *rtp = udpPacket->data();
+ rtp[0] = 0x80;
+ rtp[1] = packetType;
+
+ rtp[2] = (mRTPSeqNo >> 8) & 0xff;
+ rtp[3] = mRTPSeqNo & 0xff;
+ ++mRTPSeqNo;
+
+ uint32_t rtpTime = (timeUs * 9) / 100ll;
+
+ rtp[4] = rtpTime >> 24;
+ rtp[5] = (rtpTime >> 16) & 0xff;
+ rtp[6] = (rtpTime >> 8) & 0xff;
+ rtp[7] = rtpTime & 0xff;
+
+ rtp[8] = kSourceID >> 24;
+ rtp[9] = (kSourceID >> 16) & 0xff;
+ rtp[10] = (kSourceID >> 8) & 0xff;
+ rtp[11] = kSourceID & 0xff;
+
+ memcpy(&rtp[12], packet->data(), packet->size());
+
+ return sendRTPPacket(
+ udpPacket,
+ true /* storeInHistory */,
+ true /* timeValid */,
+ ALooper::GetNowUs());
+}
+
status_t RTPSender::queueTSPackets(
const sp<ABuffer> &tsPackets, uint8_t packetType) {
CHECK_EQ(0, tsPackets->size() % 188);
diff --git a/media/libstagefright/wifi-display/rtp/RTPSender.h b/media/libstagefright/wifi-display/rtp/RTPSender.h
index 3a926ea..fefcab7 100644
--- a/media/libstagefright/wifi-display/rtp/RTPSender.h
+++ b/media/libstagefright/wifi-display/rtp/RTPSender.h
@@ -94,6 +94,7 @@ private:
static uint64_t GetNowNTP();
+ status_t queueRawPacket(const sp<ABuffer> &tsPackets, uint8_t packetType);
status_t queueTSPackets(const sp<ABuffer> &tsPackets, uint8_t packetType);
status_t queueAVCBuffer(const sp<ABuffer> &accessUnit, uint8_t packetType);
diff --git a/media/libstagefright/wifi-display/rtptest.cpp b/media/libstagefright/wifi-display/rtptest.cpp
index eade832..764a38b 100644
--- a/media/libstagefright/wifi-display/rtptest.cpp
+++ b/media/libstagefright/wifi-display/rtptest.cpp
@@ -21,6 +21,7 @@
#include "ANetworkSession.h"
#include "rtp/RTPSender.h"
#include "rtp/RTPReceiver.h"
+#include "TimeSyncer.h"
#include <binder/ProcessState.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -28,12 +29,116 @@
#include <media/stagefright/foundation/AHandler.h>
#include <media/stagefright/foundation/ALooper.h>
#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/foundation/hexdump.h>
#include <media/stagefright/DataSource.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/NuMediaExtractor.h>
+#include <media/stagefright/Utils.h>
+
+#define MEDIA_FILENAME "/sdcard/Frame Counter HD 30FPS_1080p.mp4"
namespace android {
+struct PacketSource : public RefBase {
+ PacketSource() {}
+
+ virtual sp<ABuffer> getNextAccessUnit() = 0;
+
+protected:
+ virtual ~PacketSource() {}
+
+private:
+ DISALLOW_EVIL_CONSTRUCTORS(PacketSource);
+};
+
+struct MediaPacketSource : public PacketSource {
+ MediaPacketSource()
+ : mMaxSampleSize(1024 * 1024) {
+ mExtractor = new NuMediaExtractor;
+ CHECK_EQ((status_t)OK,
+ mExtractor->setDataSource(MEDIA_FILENAME));
+
+ bool haveVideo = false;
+ for (size_t i = 0; i < mExtractor->countTracks(); ++i) {
+ sp<AMessage> format;
+ CHECK_EQ((status_t)OK, mExtractor->getTrackFormat(i, &format));
+
+ AString mime;
+ CHECK(format->findString("mime", &mime));
+
+ if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str())) {
+ mExtractor->selectTrack(i);
+ haveVideo = true;
+ break;
+ }
+ }
+
+ CHECK(haveVideo);
+ }
+
+ virtual sp<ABuffer> getNextAccessUnit() {
+ int64_t timeUs;
+ status_t err = mExtractor->getSampleTime(&timeUs);
+
+ if (err != OK) {
+ return NULL;
+ }
+
+ sp<ABuffer> accessUnit = new ABuffer(mMaxSampleSize);
+ CHECK_EQ((status_t)OK, mExtractor->readSampleData(accessUnit));
+
+ accessUnit->meta()->setInt64("timeUs", timeUs);
+
+ CHECK_EQ((status_t)OK, mExtractor->advance());
+
+ return accessUnit;
+ }
+
+protected:
+ virtual ~MediaPacketSource() {
+ }
+
+private:
+ sp<NuMediaExtractor> mExtractor;
+ size_t mMaxSampleSize;
+
+ DISALLOW_EVIL_CONSTRUCTORS(MediaPacketSource);
+};
+
+struct SimplePacketSource : public PacketSource {
+ SimplePacketSource()
+ : mCounter(0) {
+ }
+
+ virtual sp<ABuffer> getNextAccessUnit() {
+ sp<ABuffer> buffer = new ABuffer(4);
+ uint8_t *dst = buffer->data();
+ dst[0] = mCounter >> 24;
+ dst[1] = (mCounter >> 16) & 0xff;
+ dst[2] = (mCounter >> 8) & 0xff;
+ dst[3] = mCounter & 0xff;
+
+ buffer->meta()->setInt64("timeUs", mCounter * 1000000ll / kFrameRate);
+
+ ++mCounter;
+
+ return buffer;
+ }
+
+protected:
+ virtual ~SimplePacketSource() {
+ }
+
+private:
+ enum {
+ kFrameRate = 30
+ };
+
+ uint32_t mCounter;
+
+ DISALLOW_EVIL_CONSTRUCTORS(SimplePacketSource);
+};
+
struct TestHandler : public AHandler {
TestHandler(const sp<ANetworkSession> &netSession);
@@ -52,18 +157,39 @@ private:
kWhatSenderNotify,
kWhatSendMore,
kWhatStop,
+ kWhatTimeSyncerNotify,
};
+#if 1
+ static const RTPBase::TransportMode kRTPMode = RTPBase::TRANSPORT_UDP;
+ static const RTPBase::TransportMode kRTCPMode = RTPBase::TRANSPORT_UDP;
+#else
+ static const RTPBase::TransportMode kRTPMode = RTPBase::TRANSPORT_TCP;
+ static const RTPBase::TransportMode kRTCPMode = RTPBase::TRANSPORT_NONE;
+#endif
+
+#if 1
+ static const RTPBase::PacketizationMode kPacketizationMode
+ = RTPBase::PACKETIZATION_H264;
+#else
+ static const RTPBase::PacketizationMode kPacketizationMode
+ = RTPBase::PACKETIZATION_NONE;
+#endif
+
sp<ANetworkSession> mNetSession;
- sp<NuMediaExtractor> mExtractor;
+ sp<PacketSource> mSource;
sp<RTPSender> mSender;
sp<RTPReceiver> mReceiver;
- size_t mMaxSampleSize;
+ sp<TimeSyncer> mTimeSyncer;
+ bool mTimeSyncerStarted;
int64_t mFirstTimeRealUs;
int64_t mFirstTimeMediaUs;
+ int64_t mTimeOffsetUs;
+ bool mTimeOffsetValid;
+
status_t readMore();
DISALLOW_EVIL_CONSTRUCTORS(TestHandler);
@@ -71,9 +197,11 @@ private:
TestHandler::TestHandler(const sp<ANetworkSession> &netSession)
: mNetSession(netSession),
- mMaxSampleSize(1024 * 1024),
+ mTimeSyncerStarted(false),
mFirstTimeRealUs(-1ll),
- mFirstTimeMediaUs(-1ll) {
+ mFirstTimeMediaUs(-1ll),
+ mTimeOffsetUs(-1ll),
+ mTimeOffsetValid(false) {
}
TestHandler::~TestHandler() {
@@ -91,23 +219,48 @@ void TestHandler::connect(const char *host, int32_t port) {
msg->post();
}
+static void dumpDelay(int64_t delayMs) {
+ 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("(%4lld ms) %s\n",
+ delayMs,
+ kPattern + kPatternSize - n);
+}
+
void TestHandler::onMessageReceived(const sp<AMessage> &msg) {
switch (msg->what()) {
case kWhatListen:
{
- sp<AMessage> notify = new AMessage(kWhatReceiverNotify, id());
- mReceiver = new RTPReceiver(mNetSession, notify);
+ sp<AMessage> notify = new AMessage(kWhatTimeSyncerNotify, id());
+ mTimeSyncer = new TimeSyncer(mNetSession, notify);
+ looper()->registerHandler(mTimeSyncer);
+
+ notify = new AMessage(kWhatReceiverNotify, id());
+ mReceiver = new RTPReceiver(
+ mNetSession, notify, RTPReceiver::FLAG_AUTO_CONNECT);
looper()->registerHandler(mReceiver);
CHECK_EQ((status_t)OK,
- mReceiver->registerPacketType(
- 33, RTPReceiver::PACKETIZATION_H264));
+ mReceiver->registerPacketType(33, kPacketizationMode));
int32_t receiverRTPPort;
CHECK_EQ((status_t)OK,
mReceiver->initAsync(
- RTPReceiver::TRANSPORT_UDP, // rtpMode
- RTPReceiver::TRANSPORT_UDP, // rtcpMode
+ kRTPMode,
+ kRTCPMode,
&receiverRTPPort));
printf("picked receiverRTPPort %d\n", receiverRTPPort);
@@ -125,33 +278,23 @@ void TestHandler::onMessageReceived(const sp<AMessage> &msg) {
AString host;
CHECK(msg->findString("host", &host));
+ sp<AMessage> notify = new AMessage(kWhatTimeSyncerNotify, id());
+ mTimeSyncer = new TimeSyncer(mNetSession, notify);
+ looper()->registerHandler(mTimeSyncer);
+ mTimeSyncer->startServer(8123);
+
int32_t receiverRTPPort;
CHECK(msg->findInt32("port", &receiverRTPPort));
- mExtractor = new NuMediaExtractor;
- CHECK_EQ((status_t)OK,
- mExtractor->setDataSource(
- "/sdcard/Frame Counter HD 30FPS_1080p.mp4"));
-
- bool haveVideo = false;
- for (size_t i = 0; i < mExtractor->countTracks(); ++i) {
- sp<AMessage> format;
- CHECK_EQ((status_t)OK, mExtractor->getTrackFormat(i, &format));
-
- AString mime;
- CHECK(format->findString("mime", &mime));
-
- if (!strcasecmp(MEDIA_MIMETYPE_VIDEO_AVC, mime.c_str())) {
- mExtractor->selectTrack(i);
- haveVideo = true;
- break;
- }
- }
-
- CHECK(haveVideo);
+#if 1
+ mSource = new MediaPacketSource;
+#else
+ mSource = new SimplePacketSource;
+#endif
- sp<AMessage> notify = new AMessage(kWhatSenderNotify, id());
+ notify = new AMessage(kWhatSenderNotify, id());
mSender = new RTPSender(mNetSession, notify);
+
looper()->registerHandler(mSender);
int32_t senderRTPPort;
@@ -159,9 +302,10 @@ void TestHandler::onMessageReceived(const sp<AMessage> &msg) {
mSender->initAsync(
host.c_str(),
receiverRTPPort,
- RTPSender::TRANSPORT_UDP, // rtpMode
- receiverRTPPort + 1,
- RTPSender::TRANSPORT_UDP, // rtcpMode
+ kRTPMode,
+ kRTCPMode == RTPBase::TRANSPORT_NONE
+ ? -1 : receiverRTPPort + 1,
+ kRTCPMode,
&senderRTPPort));
printf("picked senderRTPPort %d\n", senderRTPPort);
@@ -201,7 +345,7 @@ void TestHandler::onMessageReceived(const sp<AMessage> &msg) {
case kWhatReceiverNotify:
{
- ALOGI("kWhatReceiverNotify");
+ ALOGV("kWhatReceiverNotify");
int32_t what;
CHECK(msg->findInt32("what", &what));
@@ -216,8 +360,40 @@ void TestHandler::onMessageReceived(const sp<AMessage> &msg) {
break;
}
- case RTPSender::kWhatError:
+ case RTPReceiver::kWhatError:
break;
+
+ case RTPReceiver::kWhatAccessUnit:
+ {
+#if 0
+ if (!mTimeSyncerStarted) {
+ mTimeSyncer->startClient("172.18.41.216", 8123);
+ mTimeSyncerStarted = true;
+ }
+
+ sp<ABuffer> accessUnit;
+ CHECK(msg->findBuffer("accessUnit", &accessUnit));
+
+ int64_t timeUs;
+ CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+
+ if (mTimeOffsetValid) {
+ timeUs -= mTimeOffsetUs;
+ int64_t nowUs = ALooper::GetNowUs();
+ int64_t delayMs = (nowUs - timeUs) / 1000ll;
+
+ dumpDelay(delayMs);
+ }
+#endif
+ break;
+ }
+
+ case RTPReceiver::kWhatPacketLost:
+ ALOGV("kWhatPacketLost");
+ break;
+
+ default:
+ TRESPASS();
}
break;
}
@@ -231,7 +407,7 @@ void TestHandler::onMessageReceived(const sp<AMessage> &msg) {
mSender->queueBuffer(
accessUnit,
33,
- RTPSender::PACKETIZATION_H264));
+ kPacketizationMode));
status_t err = readMore();
@@ -253,31 +429,33 @@ void TestHandler::onMessageReceived(const sp<AMessage> &msg) {
mSender.clear();
}
- mExtractor.clear();
+ mSource.clear();
looper()->stop();
break;
}
+ case kWhatTimeSyncerNotify:
+ {
+ CHECK(msg->findInt64("offset", &mTimeOffsetUs));
+ mTimeOffsetValid = true;
+ break;
+ }
+
default:
TRESPASS();
}
}
status_t TestHandler::readMore() {
- int64_t timeUs;
- status_t err = mExtractor->getSampleTime(&timeUs);
+ sp<ABuffer> accessUnit = mSource->getNextAccessUnit();
- if (err != OK) {
- return err;
+ if (accessUnit == NULL) {
+ return ERROR_END_OF_STREAM;
}
- sp<ABuffer> accessUnit = new ABuffer(mMaxSampleSize);
- CHECK_EQ((status_t)OK, mExtractor->readSampleData(accessUnit));
-
- accessUnit->meta()->setInt64("timeUs", timeUs);
-
- CHECK_EQ((status_t)OK, mExtractor->advance());
+ int64_t timeUs;
+ CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
int64_t nowUs = ALooper::GetNowUs();
int64_t whenUs;
@@ -289,6 +467,8 @@ status_t TestHandler::readMore() {
whenUs = mFirstTimeRealUs + timeUs - mFirstTimeMediaUs;
}
+ accessUnit->meta()->setInt64("timeUs", whenUs);
+
sp<AMessage> msg = new AMessage(kWhatSendMore, id());
msg->setBuffer("accessUnit", accessUnit);
msg->post(whenUs - nowUs);
diff --git a/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp b/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
index 1a08bf5..5db2099 100644
--- a/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
+++ b/media/libstagefright/wifi-display/sink/WifiDisplaySink.cpp
@@ -57,7 +57,8 @@ WifiDisplaySink::WifiDisplaySink(
mSetupDeferred(false),
mLatencyCount(0),
mLatencySumUs(0ll),
- mLatencyMaxUs(0ll) {
+ mLatencyMaxUs(0ll),
+ mMaxDelayMs(-1ll) {
// We support any and all resolutions, but prefer 720p30
mSinkSupportedVideoFormats.setNativeResolution(
VideoFormats::RESOLUTION_CEA, 5); // 1280 x 720 p30
@@ -296,9 +297,13 @@ void WifiDisplaySink::onMessageReceived(const sp<AMessage> &msg) {
}
}
-static void dumpDelay(size_t trackIndex, int64_t timeUs) {
+void WifiDisplaySink::dumpDelay(size_t trackIndex, int64_t timeUs) {
int64_t delayMs = (ALooper::GetNowUs() - timeUs) / 1000ll;
+ if (delayMs > mMaxDelayMs) {
+ mMaxDelayMs = delayMs;
+ }
+
static const int64_t kMinDelayMs = 0;
static const int64_t kMaxDelayMs = 300;
@@ -314,9 +319,10 @@ static void dumpDelay(size_t trackIndex, int64_t timeUs) {
n = kPatternSize;
}
- ALOGI("[%lld]: (%4lld ms) %s",
+ ALOGI("[%lld]: (%4lld ms / %4lld ms) %s",
timeUs / 1000,
delayMs,
+ mMaxDelayMs,
kPattern + kPatternSize - n);
}
@@ -350,14 +356,19 @@ void WifiDisplaySink::onMediaReceiverNotify(const sp<AMessage> &msg) {
looper()->registerHandler(mRenderer);
}
- CHECK(mTimeOffsetValid);
-
sp<ABuffer> accessUnit;
CHECK(msg->findBuffer("accessUnit", &accessUnit));
int64_t timeUs;
CHECK(accessUnit->meta()->findInt64("timeUs", &timeUs));
+ if (!mTimeOffsetValid && !(mFlags & FLAG_SPECIAL_MODE)) {
+ mTimeOffsetUs = timeUs - ALooper::GetNowUs();
+ mTimeOffsetValid = true;
+ }
+
+ CHECK(mTimeOffsetValid);
+
// We are the timesync _client_,
// client time = server time - time offset.
timeUs -= mTimeOffsetUs;
diff --git a/media/libstagefright/wifi-display/sink/WifiDisplaySink.h b/media/libstagefright/wifi-display/sink/WifiDisplaySink.h
index 7c62057..adb9d89 100644
--- a/media/libstagefright/wifi-display/sink/WifiDisplaySink.h
+++ b/media/libstagefright/wifi-display/sink/WifiDisplaySink.h
@@ -132,6 +132,8 @@ private:
int64_t mLatencySumUs;
int64_t mLatencyMaxUs;
+ int64_t mMaxDelayMs;
+
status_t sendM2(int32_t sessionID);
status_t sendSetup(int32_t sessionID, const char *uri);
status_t sendPlay(int32_t sessionID, const char *uri);
@@ -184,6 +186,8 @@ private:
const char *url, AString *host, int32_t *port, AString *path,
AString *user, AString *pass);
+ void dumpDelay(size_t trackIndex, int64_t timeUs);
+
DISALLOW_EVIL_CONSTRUCTORS(WifiDisplaySink);
};
diff --git a/media/libstagefright/wifi-display/source/PlaybackSession.cpp b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
index 715d0b5..cacfcca 100644
--- a/media/libstagefright/wifi-display/source/PlaybackSession.cpp
+++ b/media/libstagefright/wifi-display/source/PlaybackSession.cpp
@@ -709,8 +709,11 @@ void WifiDisplaySource::PlaybackSession::onSinkFeedback(const sp<AMessage> &msg)
Converter::GetInt32Property(
"media.wfd.video-framerate", -1);
- if (rateHz < 0.0) {
- rateHz = repeaterSource->getFrameRate();
+ char val[PROPERTY_VALUE_MAX];
+ if (rateHz < 0.0
+ && property_get("media.wfd.video-framerate", val, NULL)
+ && !strcasecmp("adaptive", val)) {
+ rateHz = repeaterSource->getFrameRate();
if (avgLatencyUs > 300000ll) {
rateHz *= 0.9;