diff options
Diffstat (limited to 'media')
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> ¬ify) 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> ¬ify) + const sp<AMessage> ¬ify, + 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> ¬ify); + const sp<AMessage> ¬ify, + 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; |