Merge "Camera: Cache logical camera related info"
diff --git a/camera/ndk/impl/ACameraMetadata.cpp b/camera/ndk/impl/ACameraMetadata.cpp
index d73f744..94b5713 100644
--- a/camera/ndk/impl/ACameraMetadata.cpp
+++ b/camera/ndk/impl/ACameraMetadata.cpp
@@ -430,6 +430,7 @@
ANDROID_STATISTICS_INFO_MAX_HISTOGRAM_COUNT,
ANDROID_STATISTICS_INFO_MAX_SHARPNESS_MAP_VALUE,
ANDROID_STATISTICS_INFO_SHARPNESS_MAP_SIZE,
+ ANDROID_INFO_SUPPORTED_BUFFER_MANAGEMENT_VERSION,
ANDROID_DEPTH_MAX_DEPTH_SAMPLES,
});
diff --git a/cmds/stagefright/codec.cpp b/cmds/stagefright/codec.cpp
index 6a58467..980d1d2 100644
--- a/cmds/stagefright/codec.cpp
+++ b/cmds/stagefright/codec.cpp
@@ -366,13 +366,13 @@
case 'T':
{
useTimestamp = true;
+ FALLTHROUGH_INTENDED;
}
- // fall through
case 'R':
{
renderSurface = true;
+ FALLTHROUGH_INTENDED;
}
- // fall through
case 'S':
{
useSurface = true;
diff --git a/cmds/stagefright/mediafilter.cpp b/cmds/stagefright/mediafilter.cpp
index f24d2dd..630de25 100644
--- a/cmds/stagefright/mediafilter.cpp
+++ b/cmds/stagefright/mediafilter.cpp
@@ -706,13 +706,13 @@
case 'T':
{
useTimestamp = true;
+ FALLTHROUGH_INTENDED;
}
- // fall through
case 'R':
{
renderSurface = true;
+ FALLTHROUGH_INTENDED;
}
- // fall through
case 'S':
{
useSurface = true;
diff --git a/drm/common/DrmEngineBase.cpp b/drm/common/DrmEngineBase.cpp
index f734905..aec5959 100644
--- a/drm/common/DrmEngineBase.cpp
+++ b/drm/common/DrmEngineBase.cpp
@@ -79,12 +79,12 @@
}
status_t DrmEngineBase::consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) {
return onConsumeRights(uniqueId, decryptHandle, action, reserve);
}
status_t DrmEngineBase::setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position) {
return onSetPlaybackStatus(uniqueId, decryptHandle, playbackStatus, position);
}
@@ -120,7 +120,7 @@
}
status_t DrmEngineBase::openDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
int fd, off64_t offset, off64_t length, const char* mime) {
if (!mime || mime[0] == '\0') {
@@ -131,7 +131,7 @@
}
status_t DrmEngineBase::openDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
const char* uri, const char* mime) {
if (!mime || mime[0] == '\0') {
return onOpenDecryptSession(uniqueId, decryptHandle, uri);
@@ -139,33 +139,33 @@
return onOpenDecryptSession(uniqueId, decryptHandle, uri, mime);
}
-status_t DrmEngineBase::openDecryptSession(int uniqueId, DecryptHandle* decryptHandle,
+status_t DrmEngineBase::openDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle,
const DrmBuffer& buf, const String8& mimeType) {
return onOpenDecryptSession(uniqueId, decryptHandle, buf, mimeType);
}
-status_t DrmEngineBase::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmEngineBase::closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
return onCloseDecryptSession(uniqueId, decryptHandle);
}
status_t DrmEngineBase::initializeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
return onInitializeDecryptUnit(uniqueId, decryptHandle, decryptUnitId, headerInfo);
}
status_t DrmEngineBase::decrypt(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
return onDecrypt(uniqueId, decryptHandle, decryptUnitId, encBuffer, decBuffer, IV);
}
status_t DrmEngineBase::finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) {
return onFinalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
}
ssize_t DrmEngineBase::pread(
- int uniqueId, DecryptHandle* decryptHandle, void* buffer, ssize_t numBytes, off64_t offset) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, void* buffer, ssize_t numBytes, off64_t offset) {
return onPread(uniqueId, decryptHandle, buffer, numBytes, offset);
}
diff --git a/drm/common/IDrmManagerService.cpp b/drm/common/IDrmManagerService.cpp
index 44f98dd..a6d33b0 100644
--- a/drm/common/IDrmManagerService.cpp
+++ b/drm/common/IDrmManagerService.cpp
@@ -39,7 +39,7 @@
using namespace android;
static void writeDecryptHandleToParcelData(
- const DecryptHandle* handle, Parcel* data) {
+ const sp<DecryptHandle>& handle, Parcel* data) {
data->writeInt32(handle->decryptId);
data->writeString8(handle->mimeType);
data->writeInt32(handle->decryptApiType);
@@ -67,7 +67,7 @@
}
static void readDecryptHandleFromParcelData(
- DecryptHandle* handle, const Parcel& data) {
+ sp<DecryptHandle>& handle, const Parcel& data) {
if (0 == data.dataAvail()) {
return;
}
@@ -99,7 +99,7 @@
}
}
-static void clearDecryptHandle(DecryptHandle* handle) {
+static void clearDecryptHandle(sp<DecryptHandle> &handle) {
if (handle == NULL) {
return;
}
@@ -414,7 +414,7 @@
}
status_t BpDrmManagerService::consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) {
ALOGV("consumeRights");
Parcel data, reply;
@@ -431,7 +431,7 @@
}
status_t BpDrmManagerService::setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position) {
ALOGV("setPlaybackStatus");
Parcel data, reply;
@@ -603,7 +603,7 @@
return reply.readInt32();
}
-DecryptHandle* BpDrmManagerService::openDecryptSession(
+sp<DecryptHandle> BpDrmManagerService::openDecryptSession(
int uniqueId, int fd, off64_t offset, off64_t length, const char* mime) {
ALOGV("Entering BpDrmManagerService::openDecryptSession");
Parcel data, reply;
@@ -621,7 +621,7 @@
remote()->transact(OPEN_DECRYPT_SESSION, data, &reply);
- DecryptHandle* handle = NULL;
+ sp<DecryptHandle> handle;
if (0 != reply.dataAvail()) {
handle = new DecryptHandle();
readDecryptHandleFromParcelData(handle, reply);
@@ -629,7 +629,7 @@
return handle;
}
-DecryptHandle* BpDrmManagerService::openDecryptSession(
+sp<DecryptHandle> BpDrmManagerService::openDecryptSession(
int uniqueId, const char* uri, const char* mime) {
ALOGV("Entering BpDrmManagerService::openDecryptSession: mime=%s", mime? mime: "NULL");
@@ -646,7 +646,7 @@
remote()->transact(OPEN_DECRYPT_SESSION_FROM_URI, data, &reply);
- DecryptHandle* handle = NULL;
+ sp<DecryptHandle> handle;
if (0 != reply.dataAvail()) {
handle = new DecryptHandle();
readDecryptHandleFromParcelData(handle, reply);
@@ -656,7 +656,7 @@
return handle;
}
-DecryptHandle* BpDrmManagerService::openDecryptSession(
+sp<DecryptHandle> BpDrmManagerService::openDecryptSession(
int uniqueId, const DrmBuffer& buf, const String8& mimeType) {
ALOGV("Entering BpDrmManagerService::openDecryptSession");
Parcel data, reply;
@@ -673,7 +673,7 @@
remote()->transact(OPEN_DECRYPT_SESSION_FOR_STREAMING, data, &reply);
- DecryptHandle* handle = NULL;
+ sp<DecryptHandle> handle;
if (0 != reply.dataAvail()) {
handle = new DecryptHandle();
readDecryptHandleFromParcelData(handle, reply);
@@ -683,7 +683,7 @@
return handle;
}
-status_t BpDrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t BpDrmManagerService::closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
ALOGV("closeDecryptSession");
Parcel data, reply;
@@ -698,7 +698,7 @@
}
status_t BpDrmManagerService::initializeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) {
ALOGV("initializeDecryptUnit");
Parcel data, reply;
@@ -718,7 +718,7 @@
}
status_t BpDrmManagerService::decrypt(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
ALOGV("decrypt");
Parcel data, reply;
@@ -754,7 +754,7 @@
}
status_t BpDrmManagerService::finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) {
ALOGV("finalizeDecryptUnit");
Parcel data, reply;
@@ -770,7 +770,7 @@
}
ssize_t BpDrmManagerService::pread(
- int uniqueId, DecryptHandle* decryptHandle, void* buffer,
+ int uniqueId, sp<DecryptHandle>& decryptHandle, void* buffer,
ssize_t numBytes, off64_t offset) {
ALOGV("read");
Parcel data, reply;
@@ -1128,16 +1128,16 @@
const int uniqueId = data.readInt32();
- DecryptHandle handle;
- readDecryptHandleFromParcelData(&handle, data);
+ sp<DecryptHandle> handle = new DecryptHandle();
+ readDecryptHandleFromParcelData(handle, data);
const int action = data.readInt32();
const bool reserve = static_cast<bool>(data.readInt32());
const status_t status
- = consumeRights(uniqueId, &handle, action, reserve);
+ = consumeRights(uniqueId, handle, action, reserve);
reply->writeInt32(status);
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
return DRM_NO_ERROR;
}
@@ -1148,16 +1148,16 @@
const int uniqueId = data.readInt32();
- DecryptHandle handle;
- readDecryptHandleFromParcelData(&handle, data);
+ sp<DecryptHandle> handle = new DecryptHandle();
+ readDecryptHandleFromParcelData(handle, data);
const int playbackStatus = data.readInt32();
const int64_t position = data.readInt64();
const status_t status
- = setPlaybackStatus(uniqueId, &handle, playbackStatus, position);
+ = setPlaybackStatus(uniqueId, handle, playbackStatus, position);
reply->writeInt32(status);
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
return DRM_NO_ERROR;
}
@@ -1329,13 +1329,13 @@
const off64_t length = data.readInt64();
const String8 mime = data.readString8();
- DecryptHandle* handle
+ sp<DecryptHandle> handle
= openDecryptSession(uniqueId, fd, offset, length, mime.string());
- if (NULL != handle) {
- writeDecryptHandleToParcelData(handle, reply);
+ if (NULL != handle.get()) {
+ writeDecryptHandleToParcelData(handle.get(), reply);
clearDecryptHandle(handle);
- delete handle; handle = NULL;
+ handle.clear();
}
return DRM_NO_ERROR;
}
@@ -1349,13 +1349,13 @@
const String8 uri = data.readString8();
const String8 mime = data.readString8();
- DecryptHandle* handle = openDecryptSession(uniqueId, uri.string(), mime.string());
+ sp<DecryptHandle> handle = openDecryptSession(uniqueId, uri.string(), mime.string());
- if (NULL != handle) {
- writeDecryptHandleToParcelData(handle, reply);
+ if (NULL != handle.get()) {
+ writeDecryptHandleToParcelData(handle.get(), reply);
clearDecryptHandle(handle);
- delete handle; handle = NULL;
+ handle.clear();
} else {
ALOGV("NULL decryptHandle is returned");
}
@@ -1373,13 +1373,12 @@
bufferSize);
const String8 mimeType(data.readString8());
- DecryptHandle* handle = openDecryptSession(uniqueId, buf, mimeType);
+ sp<DecryptHandle> handle = openDecryptSession(uniqueId, buf, mimeType);
if (handle != NULL) {
writeDecryptHandleToParcelData(handle, reply);
clearDecryptHandle(handle);
- delete handle;
- handle = NULL;
+ handle.clear();
} else {
ALOGV("NULL decryptHandle is returned");
}
@@ -1393,7 +1392,7 @@
const int uniqueId = data.readInt32();
- DecryptHandle* handle = new DecryptHandle();
+ sp<DecryptHandle> handle = new DecryptHandle();
readDecryptHandleFromParcelData(handle, data);
const status_t status = closeDecryptSession(uniqueId, handle);
@@ -1408,8 +1407,8 @@
const int uniqueId = data.readInt32();
- DecryptHandle handle;
- readDecryptHandleFromParcelData(&handle, data);
+ sp<DecryptHandle> handle = new DecryptHandle();
+ readDecryptHandleFromParcelData(handle, data);
const int decryptUnitId = data.readInt32();
@@ -1417,17 +1416,17 @@
const uint32_t bufferSize = data.readInt32();
if (bufferSize > data.dataAvail()) {
reply->writeInt32(BAD_VALUE);
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
return DRM_NO_ERROR;
}
DrmBuffer* headerInfo = NULL;
headerInfo = new DrmBuffer((char *)data.readInplace(bufferSize), bufferSize);
const status_t status
- = initializeDecryptUnit(uniqueId, &handle, decryptUnitId, headerInfo);
+ = initializeDecryptUnit(uniqueId, handle, decryptUnitId, headerInfo);
reply->writeInt32(status);
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
delete headerInfo; headerInfo = NULL;
return DRM_NO_ERROR;
}
@@ -1439,8 +1438,8 @@
const int uniqueId = data.readInt32();
- DecryptHandle handle;
- readDecryptHandleFromParcelData(&handle, data);
+ sp<DecryptHandle> handle = new DecryptHandle;
+ readDecryptHandleFromParcelData(handle, data);
const int decryptUnitId = data.readInt32();
const uint32_t decBufferSize = data.readInt32();
@@ -1450,7 +1449,7 @@
decBufferSize > MAX_BINDER_TRANSACTION_SIZE) {
reply->writeInt32(BAD_VALUE);
reply->writeInt32(0);
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
return DRM_NO_ERROR;
}
@@ -1470,7 +1469,7 @@
}
const status_t status
- = decrypt(uniqueId, &handle, decryptUnitId, encBuffer, &decBuffer, IV);
+ = decrypt(uniqueId, handle, decryptUnitId, encBuffer, &decBuffer, IV);
reply->writeInt32(status);
@@ -1480,7 +1479,7 @@
reply->write(decBuffer->data, size);
}
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
delete encBuffer; encBuffer = NULL;
delete decBuffer; decBuffer = NULL;
delete [] buffer; buffer = NULL;
@@ -1495,13 +1494,13 @@
const int uniqueId = data.readInt32();
- DecryptHandle handle;
- readDecryptHandleFromParcelData(&handle, data);
+ sp<DecryptHandle> handle = new DecryptHandle();
+ readDecryptHandleFromParcelData(handle, data);
- const status_t status = finalizeDecryptUnit(uniqueId, &handle, data.readInt32());
+ const status_t status = finalizeDecryptUnit(uniqueId, handle, data.readInt32());
reply->writeInt32(status);
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
return DRM_NO_ERROR;
}
@@ -1512,8 +1511,8 @@
const int uniqueId = data.readInt32();
- DecryptHandle handle;
- readDecryptHandleFromParcelData(&handle, data);
+ sp<DecryptHandle> handle = new DecryptHandle();
+ readDecryptHandleFromParcelData(handle, data);
const uint32_t numBytes = data.readInt32();
if (numBytes > MAX_BINDER_TRANSACTION_SIZE) {
@@ -1524,13 +1523,13 @@
const off64_t offset = data.readInt64();
- ssize_t result = pread(uniqueId, &handle, buffer, numBytes, offset);
+ ssize_t result = pread(uniqueId, handle, buffer, numBytes, offset);
reply->writeInt32(result);
if (0 < result) {
reply->write(buffer, result);
}
- clearDecryptHandle(&handle);
+ clearDecryptHandle(handle);
delete [] buffer, buffer = NULL;
return DRM_NO_ERROR;
}
diff --git a/drm/common/include/DrmEngineBase.h b/drm/common/include/DrmEngineBase.h
index 417107f..73f11a4 100644
--- a/drm/common/include/DrmEngineBase.h
+++ b/drm/common/include/DrmEngineBase.h
@@ -59,10 +59,11 @@
int checkRightsStatus(int uniqueId, const String8& path, int action);
- status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ status_t consumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle, int action,
+ bool reserve);
status_t setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
bool validateAction(
int uniqueId, const String8& path, int action, const ActionDescription& description);
@@ -80,27 +81,28 @@
DrmSupportInfo* getSupportInfo(int uniqueId);
status_t openDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
int fd, off64_t offset, off64_t length, const char* mime);
status_t openDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
const char* uri, const char* mime);
- status_t openDecryptSession(int uniqueId, DecryptHandle* decryptHandle,
+ status_t openDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle,
const DrmBuffer& buf, const String8& mimeType);
- status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle);
- status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
- status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
- status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+ status_t finalizeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
+ int decryptUnitId);
- ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+ ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset);
protected:
@@ -265,7 +267,7 @@
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual status_t onConsumeRights(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t onConsumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle,
int action, bool reserve) = 0;
/**
@@ -280,7 +282,8 @@
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
virtual status_t onSetPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus,
+ int64_t position) = 0;
/**
* Validates whether an action on the DRM content is allowed or not.
@@ -381,7 +384,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t onOpenDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
int fd, off64_t offset, off64_t length) = 0;
/**
@@ -398,7 +401,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t onOpenDecryptSession(
- int /* uniqueId */, DecryptHandle* /* decryptHandle */,
+ int /* uniqueId */, sp<DecryptHandle>& /* decryptHandle */,
int /* fd */, off64_t /* offset */, off64_t /* length */,
const char* /* mime */) {
@@ -415,7 +418,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t onOpenDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
const char* uri) = 0;
/**
@@ -430,7 +433,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t onOpenDecryptSession(
- int /* uniqueId */, DecryptHandle* /* decryptHandle */,
+ int /* uniqueId */, sp<DecryptHandle>& /* decryptHandle */,
const char* /* uri */, const char* /* mime */) {
return DRM_ERROR_CANNOT_HANDLE;
@@ -447,7 +450,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t onOpenDecryptSession(int /* uniqueId */,
- DecryptHandle* /* decryptHandle */,
+ sp<DecryptHandle>& /* decryptHandle */,
const DrmBuffer& /* buf */,
const String8& /* mimeType */) {
return DRM_ERROR_CANNOT_HANDLE;
@@ -461,7 +464,7 @@
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual status_t onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+ virtual status_t onCloseDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) = 0;
/**
* Initialize decryption for the given unit of the protected content
@@ -473,7 +476,7 @@
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual status_t onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t onInitializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) = 0;
/**
@@ -493,7 +496,7 @@
* DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
* DRM_ERROR_DECRYPT for failure.
*/
- virtual status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ virtual status_t onDecrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
/**
@@ -506,7 +509,7 @@
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
virtual status_t onFinalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) = 0;
/**
* Reads the specified number of bytes from an open DRM file.
@@ -519,7 +522,7 @@
*
* @return Number of bytes read. Returns -1 for Failure.
*/
- virtual ssize_t onPread(int uniqueId, DecryptHandle* decryptHandle,
+ virtual ssize_t onPread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset) = 0;
};
diff --git a/drm/common/include/IDrmEngine.h b/drm/common/include/IDrmEngine.h
index acc8ed9..1837a11 100644
--- a/drm/common/include/IDrmEngine.h
+++ b/drm/common/include/IDrmEngine.h
@@ -210,7 +210,7 @@
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
virtual status_t consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) = 0;
/**
* Informs the DRM Engine about the playback actions performed on the DRM files.
@@ -223,7 +223,7 @@
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual status_t setPlaybackStatus(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t setPlaybackStatus(int uniqueId, sp<DecryptHandle>& decryptHandle,
int playbackStatus, int64_t position) = 0;
/**
@@ -327,7 +327,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t openDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
int fd, off64_t offset, off64_t length, const char* mime) = 0;
/**
@@ -342,7 +342,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
virtual status_t openDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle,
+ int uniqueId, sp<DecryptHandle>& decryptHandle,
const char* uri, const char* mime) = 0;
/**
@@ -355,7 +355,7 @@
* @return
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
- virtual status_t openDecryptSession(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t openDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle,
const DrmBuffer& buf, const String8& mimeType) = 0;
/**
@@ -366,7 +366,7 @@
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+ virtual status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) = 0;
/**
* Initialize decryption for the given unit of the protected content
@@ -378,7 +378,7 @@
* @return status_t
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
- virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) = 0;
/**
@@ -398,7 +398,7 @@
* DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
* DRM_ERROR_DECRYPT for failure.
*/
- virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ virtual status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
/**
@@ -411,7 +411,7 @@
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
virtual status_t finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) = 0;
/**
* Reads the specified number of bytes from an open DRM file.
@@ -424,7 +424,7 @@
*
* @return Number of bytes read. Returns -1 for Failure.
*/
- virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+ virtual ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset) = 0;
};
diff --git a/drm/common/include/IDrmManagerService.h b/drm/common/include/IDrmManagerService.h
index 0376b49..836ae0a 100644
--- a/drm/common/include/IDrmManagerService.h
+++ b/drm/common/include/IDrmManagerService.h
@@ -115,10 +115,11 @@
virtual int checkRightsStatus(int uniqueId, const String8& path, int action) = 0;
virtual status_t consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) = 0;
virtual status_t setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus,
+ int64_t position) = 0;
virtual bool validateAction(
int uniqueId, const String8& path,
@@ -138,28 +139,28 @@
virtual status_t getAllSupportInfo(
int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray) = 0;
- virtual DecryptHandle* openDecryptSession(
+ virtual sp<DecryptHandle> openDecryptSession(
int uniqueId, int fd, off64_t offset,
off64_t length, const char* mime) = 0;
- virtual DecryptHandle* openDecryptSession(
+ virtual sp<DecryptHandle> openDecryptSession(
int uniqueId, const char* uri, const char* mime) = 0;
- virtual DecryptHandle* openDecryptSession(
+ virtual sp<DecryptHandle> openDecryptSession(
int uniqueId, const DrmBuffer& buf, const String8& mimeType) = 0;
- virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) = 0;
+ virtual status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) = 0;
- virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) = 0;
- virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ virtual status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) = 0;
virtual status_t finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) = 0;
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) = 0;
- virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+ virtual ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes,off64_t offset) = 0;
};
@@ -203,10 +204,10 @@
virtual int checkRightsStatus(int uniqueId, const String8& path, int action);
virtual status_t consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve);
virtual status_t setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
virtual bool validateAction(
int uniqueId, const String8& path, int action, const ActionDescription& description);
@@ -225,28 +226,28 @@
virtual status_t getAllSupportInfo(
int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray);
- virtual DecryptHandle* openDecryptSession(
+ virtual sp<DecryptHandle> openDecryptSession(
int uniqueId, int fd, off64_t offset, off64_t length,
const char* mime);
- virtual DecryptHandle* openDecryptSession(
+ virtual sp<DecryptHandle> openDecryptSession(
int uniqueId, const char* uri, const char* mime);
- virtual DecryptHandle* openDecryptSession(
+ virtual sp<DecryptHandle> openDecryptSession(
int uniqueId, const DrmBuffer& buf, const String8& mimeType);
- virtual status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ virtual status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle);
- virtual status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ virtual status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
- virtual status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ virtual status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
virtual status_t finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId);
- virtual ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+ virtual ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset);
};
diff --git a/drm/drmserver/DrmManager.cpp b/drm/drmserver/DrmManager.cpp
index bf04a89..afbcb39 100644
--- a/drm/drmserver/DrmManager.cpp
+++ b/drm/drmserver/DrmManager.cpp
@@ -267,7 +267,7 @@
}
status_t DrmManager::consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) {
status_t result = DRM_ERROR_UNKNOWN;
Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
@@ -278,7 +278,7 @@
}
status_t DrmManager::setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position) {
status_t result = DRM_ERROR_UNKNOWN;
Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
@@ -396,15 +396,15 @@
return DRM_NO_ERROR;
}
-DecryptHandle* DrmManager::openDecryptSession(
+sp<DecryptHandle> DrmManager::openDecryptSession(
int uniqueId, int fd, off64_t offset, off64_t length, const char* mime) {
Mutex::Autolock _l(mDecryptLock);
status_t result = DRM_ERROR_CANNOT_HANDLE;
Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
- DecryptHandle* handle = new DecryptHandle();
- if (NULL != handle) {
+ sp<DecryptHandle> handle = new DecryptHandle();
+ if (NULL != handle.get()) {
handle->decryptId = mDecryptSessionId + 1;
for (size_t index = 0; index < plugInIdList.size(); index++) {
@@ -420,19 +420,19 @@
}
}
if (DRM_NO_ERROR != result) {
- delete handle; handle = NULL;
+ handle.clear();
}
return handle;
}
-DecryptHandle* DrmManager::openDecryptSession(
+sp<DecryptHandle> DrmManager::openDecryptSession(
int uniqueId, const char* uri, const char* mime) {
Mutex::Autolock _l(mDecryptLock);
status_t result = DRM_ERROR_CANNOT_HANDLE;
Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
- DecryptHandle* handle = new DecryptHandle();
- if (NULL != handle) {
+ sp<DecryptHandle> handle = new DecryptHandle();
+ if (NULL != handle.get()) {
handle->decryptId = mDecryptSessionId + 1;
for (size_t index = 0; index < plugInIdList.size(); index++) {
@@ -448,20 +448,20 @@
}
}
if (DRM_NO_ERROR != result) {
- delete handle; handle = NULL;
+ handle.clear();
ALOGV("DrmManager::openDecryptSession: no capable plug-in found");
}
return handle;
}
-DecryptHandle* DrmManager::openDecryptSession(
+sp<DecryptHandle> DrmManager::openDecryptSession(
int uniqueId, const DrmBuffer& buf, const String8& mimeType) {
Mutex::Autolock _l(mDecryptLock);
status_t result = DRM_ERROR_CANNOT_HANDLE;
Vector<String8> plugInIdList = mPlugInManager.getPlugInIdList();
- DecryptHandle* handle = new DecryptHandle();
- if (NULL != handle) {
+ sp<DecryptHandle> handle = new DecryptHandle();
+ if (NULL != handle.get()) {
handle->decryptId = mDecryptSessionId + 1;
for (size_t index = 0; index < plugInIdList.size(); index++) {
@@ -477,20 +477,19 @@
}
}
if (DRM_NO_ERROR != result) {
- delete handle;
- handle = NULL;
+ handle.clear();
ALOGV("DrmManager::openDecryptSession: no capable plug-in found");
}
return handle;
}
-status_t DrmManager::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmManager::closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
Mutex::Autolock _l(mDecryptLock);
status_t result = DRM_ERROR_UNKNOWN;
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
IDrmEngine* drmEngine = mDecryptSessionMap.valueFor(decryptHandle->decryptId);
result = drmEngine->closeDecryptSession(uniqueId, decryptHandle);
- if (DRM_NO_ERROR == result) {
+ if (DRM_NO_ERROR == result && NULL != decryptHandle.get()) {
mDecryptSessionMap.removeItem(decryptHandle->decryptId);
}
}
@@ -498,7 +497,8 @@
}
status_t DrmManager::initializeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId, const DrmBuffer* headerInfo) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
+ const DrmBuffer* headerInfo) {
status_t result = DRM_ERROR_UNKNOWN;
Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
@@ -508,7 +508,7 @@
return result;
}
-status_t DrmManager::decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+status_t DrmManager::decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
status_t result = DRM_ERROR_UNKNOWN;
@@ -522,7 +522,7 @@
}
status_t DrmManager::finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) {
status_t result = DRM_ERROR_UNKNOWN;
Mutex::Autolock _l(mDecryptLock);
if (mDecryptSessionMap.indexOfKey(decryptHandle->decryptId) != NAME_NOT_FOUND) {
@@ -532,7 +532,7 @@
return result;
}
-ssize_t DrmManager::pread(int uniqueId, DecryptHandle* decryptHandle,
+ssize_t DrmManager::pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset) {
ssize_t result = DECRYPT_FILE_ERROR;
diff --git a/drm/drmserver/DrmManager.h b/drm/drmserver/DrmManager.h
index e7cdd36..26222bc 100644
--- a/drm/drmserver/DrmManager.h
+++ b/drm/drmserver/DrmManager.h
@@ -89,10 +89,11 @@
int checkRightsStatus(int uniqueId, const String8& path, int action);
- status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ status_t consumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle, int action,
+ bool reserve);
status_t setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
bool validateAction(
int uniqueId, const String8& path, int action, const ActionDescription& description);
@@ -109,25 +110,26 @@
status_t getAllSupportInfo(int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray);
- DecryptHandle* openDecryptSession(
+ sp<DecryptHandle> openDecryptSession(
int uniqueId, int fd, off64_t offset, off64_t length, const char* mime);
- DecryptHandle* openDecryptSession(int uniqueId, const char* uri, const char* mime);
+ sp<DecryptHandle> openDecryptSession(int uniqueId, const char* uri, const char* mime);
- DecryptHandle* openDecryptSession(int uniqueId, const DrmBuffer& buf,
+ sp<DecryptHandle> openDecryptSession(int uniqueId, const DrmBuffer& buf,
const String8& mimeType);
- status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle);
- status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
- status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
- status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+ status_t finalizeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
+ int decryptUnitId);
- ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+ ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset);
void onInfo(const DrmInfoEvent& event);
diff --git a/drm/drmserver/DrmManagerService.cpp b/drm/drmserver/DrmManagerService.cpp
index dad599b..2532275 100644
--- a/drm/drmserver/DrmManagerService.cpp
+++ b/drm/drmserver/DrmManagerService.cpp
@@ -206,7 +206,7 @@
}
status_t DrmManagerService::consumeRights(
- int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int action, bool reserve) {
ALOGV("Entering consumeRights");
if (!isProtectedCallAllowed(CONSUME_RIGHTS)) {
return DRM_ERROR_NO_PERMISSION;
@@ -215,7 +215,7 @@
}
status_t DrmManagerService::setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position) {
ALOGV("Entering setPlaybackStatus");
if (!isProtectedCallAllowed(SET_PLAYBACK_STATUS)) {
return DRM_ERROR_NO_PERMISSION;
@@ -262,7 +262,7 @@
return mDrmManager->getAllSupportInfo(uniqueId, length, drmSupportInfoArray);
}
-DecryptHandle* DrmManagerService::openDecryptSession(
+sp<DecryptHandle> DrmManagerService::openDecryptSession(
int uniqueId, int fd, off64_t offset, off64_t length, const char* mime) {
ALOGV("Entering DrmManagerService::openDecryptSession");
if (isProtectedCallAllowed(OPEN_DECRYPT_SESSION)) {
@@ -272,7 +272,7 @@
return NULL;
}
-DecryptHandle* DrmManagerService::openDecryptSession(
+sp<DecryptHandle> DrmManagerService::openDecryptSession(
int uniqueId, const char* uri, const char* mime) {
ALOGV("Entering DrmManagerService::openDecryptSession with uri");
if (isProtectedCallAllowed(OPEN_DECRYPT_SESSION)) {
@@ -282,7 +282,7 @@
return NULL;
}
-DecryptHandle* DrmManagerService::openDecryptSession(
+sp<DecryptHandle> DrmManagerService::openDecryptSession(
int uniqueId, const DrmBuffer& buf, const String8& mimeType) {
ALOGV("Entering DrmManagerService::openDecryptSession for streaming");
if (isProtectedCallAllowed(OPEN_DECRYPT_SESSION)) {
@@ -292,7 +292,7 @@
return NULL;
}
-status_t DrmManagerService::closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmManagerService::closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
ALOGV("Entering closeDecryptSession");
if (!isProtectedCallAllowed(CLOSE_DECRYPT_SESSION)) {
return DRM_ERROR_NO_PERMISSION;
@@ -300,7 +300,7 @@
return mDrmManager->closeDecryptSession(uniqueId, decryptHandle);
}
-status_t DrmManagerService::initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+status_t DrmManagerService::initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo) {
ALOGV("Entering initializeDecryptUnit");
if (!isProtectedCallAllowed(INITIALIZE_DECRYPT_UNIT)) {
@@ -310,7 +310,7 @@
}
status_t DrmManagerService::decrypt(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV) {
ALOGV("Entering decrypt");
if (!isProtectedCallAllowed(DECRYPT)) {
@@ -320,7 +320,7 @@
}
status_t DrmManagerService::finalizeDecryptUnit(
- int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId) {
ALOGV("Entering finalizeDecryptUnit");
if (!isProtectedCallAllowed(FINALIZE_DECRYPT_UNIT)) {
return DRM_ERROR_NO_PERMISSION;
@@ -328,7 +328,7 @@
return mDrmManager->finalizeDecryptUnit(uniqueId, decryptHandle, decryptUnitId);
}
-ssize_t DrmManagerService::pread(int uniqueId, DecryptHandle* decryptHandle,
+ssize_t DrmManagerService::pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset) {
ALOGV("Entering pread");
if (!isProtectedCallAllowed(PREAD)) {
diff --git a/drm/drmserver/DrmManagerService.h b/drm/drmserver/DrmManagerService.h
index 45cee2e..7aaeab5 100644
--- a/drm/drmserver/DrmManagerService.h
+++ b/drm/drmserver/DrmManagerService.h
@@ -95,10 +95,11 @@
int checkRightsStatus(int uniqueId, const String8& path,int action);
- status_t consumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ status_t consumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle, int action,
+ bool reserve);
status_t setPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
bool validateAction(int uniqueId, const String8& path,
int action, const ActionDescription& description);
@@ -115,26 +116,27 @@
status_t getAllSupportInfo(int uniqueId, int* length, DrmSupportInfo** drmSupportInfoArray);
- DecryptHandle* openDecryptSession(
+ sp<DecryptHandle> openDecryptSession(
int uniqueId, int fd, off64_t offset, off64_t length, const char *mime);
- DecryptHandle* openDecryptSession(
+ sp<DecryptHandle> openDecryptSession(
int uniqueId, const char* uri, const char* mime);
- DecryptHandle* openDecryptSession(int uniqueId, const DrmBuffer& buf,
+ sp<DecryptHandle> openDecryptSession(int uniqueId, const DrmBuffer& buf,
const String8& mimeType);
- status_t closeDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ status_t closeDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle);
- status_t initializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ status_t initializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
- status_t decrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ status_t decrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
- status_t finalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+ status_t finalizeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
+ int decryptUnitId);
- ssize_t pread(int uniqueId, DecryptHandle* decryptHandle,
+ ssize_t pread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset);
virtual status_t dump(int fd, const Vector<String16>& args);
diff --git a/drm/libdrmframework/DrmManagerClientImpl.cpp b/drm/libdrmframework/DrmManagerClientImpl.cpp
index c047eb1..b0a441b 100644
--- a/drm/libdrmframework/DrmManagerClientImpl.cpp
+++ b/drm/libdrmframework/DrmManagerClientImpl.cpp
@@ -183,7 +183,7 @@
status_t status = DRM_ERROR_UNKNOWN;
if (NULL != decryptHandle.get()) {
status = getDrmManagerService()->consumeRights(
- uniqueId, decryptHandle.get(), action, reserve);
+ uniqueId, decryptHandle, action, reserve);
}
return status;
}
@@ -194,7 +194,7 @@
status_t status = DRM_ERROR_UNKNOWN;
if (NULL != decryptHandle.get()) {
status = getDrmManagerService()->setPlaybackStatus(
- uniqueId, decryptHandle.get(), playbackStatus, position);
+ uniqueId, decryptHandle, playbackStatus, position);
}
return status;
}
@@ -267,7 +267,7 @@
sp<DecryptHandle> DrmManagerClientImpl::openDecryptSession(
int uniqueId, const char* uri, const char* mime) {
- DecryptHandle* handle = NULL;
+ sp<DecryptHandle> handle;
if (NULL != uri) {
handle = getDrmManagerService()->openDecryptSession(uniqueId, uri, mime);
}
@@ -284,7 +284,7 @@
status_t status = DRM_ERROR_UNKNOWN;
if (NULL != decryptHandle.get()) {
status = getDrmManagerService()->closeDecryptSession(
- uniqueId, decryptHandle.get());
+ uniqueId, decryptHandle);
}
return status;
}
@@ -295,7 +295,7 @@
status_t status = DRM_ERROR_UNKNOWN;
if ((NULL != decryptHandle.get()) && (NULL != headerInfo)) {
status = getDrmManagerService()->initializeDecryptUnit(
- uniqueId, decryptHandle.get(), decryptUnitId, headerInfo);
+ uniqueId, decryptHandle, decryptUnitId, headerInfo);
}
return status;
}
@@ -308,7 +308,7 @@
if ((NULL != decryptHandle.get()) && (NULL != encBuffer)
&& (NULL != decBuffer) && (NULL != *decBuffer)) {
status = getDrmManagerService()->decrypt(
- uniqueId, decryptHandle.get(), decryptUnitId,
+ uniqueId, decryptHandle, decryptUnitId,
encBuffer, decBuffer, IV);
}
return status;
@@ -319,7 +319,7 @@
status_t status = DRM_ERROR_UNKNOWN;
if (NULL != decryptHandle.get()) {
status = getDrmManagerService()->finalizeDecryptUnit(
- uniqueId, decryptHandle.get(), decryptUnitId);
+ uniqueId, decryptHandle, decryptUnitId);
}
return status;
}
@@ -329,7 +329,7 @@
ssize_t retCode = INVALID_VALUE;
if ((NULL != decryptHandle.get()) && (NULL != buffer) && (0 < numBytes)) {
retCode = getDrmManagerService()->pread(
- uniqueId, decryptHandle.get(), buffer, numBytes, offset);
+ uniqueId, decryptHandle, buffer, numBytes, offset);
}
return retCode;
}
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
index a571b3a..b62ddb9 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/include/FwdLockEngine.h
@@ -198,7 +198,7 @@
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
status_t onConsumeRights(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
int action,
bool reserve);
@@ -215,12 +215,12 @@
*/
#ifdef USE_64BIT_DRM_API
status_t onSetPlaybackStatus(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
int playbackStatus,
int64_t position);
#else
status_t onSetPlaybackStatus(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
int playbackStatus,
int position);
#endif
@@ -330,11 +330,11 @@
*/
#ifdef USE_64BIT_DRM_API
status_t onOpenDecryptSession(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
int fd, off64_t offset, off64_t length);
#else
status_t onOpenDecryptSession(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
int fd, int offset, int length);
#endif
@@ -348,7 +348,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
status_t onOpenDecryptSession(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
const char* uri);
/**
@@ -360,7 +360,7 @@
* Returns DRM_NO_ERROR for success, DRM_ERROR_UNKNOWN for failure
*/
status_t onCloseDecryptSession(int uniqueId,
- DecryptHandle* decryptHandle);
+ sp<DecryptHandle>& decryptHandle);
/**
* Initialize decryption for the given unit of the protected content.
@@ -373,7 +373,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
status_t onInitializeDecryptUnit(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
int decryptUnitId,
const DrmBuffer* headerInfo);
@@ -394,7 +394,7 @@
* DRM_ERROR_DECRYPT for failure.
*/
status_t onDecrypt(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
int decryptUnitId,
const DrmBuffer* encBuffer,
DrmBuffer** decBuffer);
@@ -416,7 +416,7 @@
* DRM_ERROR_SESSION_NOT_OPENED, DRM_ERROR_DECRYPT_UNIT_NOT_INITIALIZED,
* DRM_ERROR_DECRYPT for failure.
*/
-status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle,
+status_t onDecrypt(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* encBuffer,
DrmBuffer** decBuffer, DrmBuffer* IV);
@@ -430,7 +430,7 @@
* DRM_ERROR_CANNOT_HANDLE for failure and DRM_NO_ERROR for success
*/
status_t onFinalizeDecryptUnit(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
int decryptUnitId);
/**
@@ -445,7 +445,7 @@
* @retval -1 Failure.
*/
ssize_t onRead(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
void* pBuffer,
int numBytes);
@@ -463,12 +463,12 @@
*/
#ifdef USE_64BIT_DRM_API
off64_t onLseek(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
off64_t offset,
int whence);
#else
off_t onLseek(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
off_t offset,
int whence);
#endif
@@ -486,13 +486,13 @@
*/
#ifdef USE_64BIT_DRM_API
ssize_t onPread(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
void* buffer,
ssize_t numBytes,
off64_t offset);
#else
ssize_t onPread(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
void* buffer,
ssize_t numBytes,
off_t offset);
diff --git a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
index 73eea89..769de0c 100644
--- a/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
+++ b/drm/libdrmframework/plugins/forward-lock/FwdLockEngine/src/FwdLockEngine.cpp
@@ -294,7 +294,7 @@
}
status_t FwdLockEngine::onConsumeRights(int /* uniqueId */,
- DecryptHandle* /* decryptHandle */,
+ sp<DecryptHandle>& /* decryptHandle */,
int /* action */,
bool /* reserve */) {
// No rights consumption
@@ -372,11 +372,13 @@
}
#ifdef USE_64BIT_DRM_API
-status_t FwdLockEngine::onSetPlaybackStatus(int /* uniqueId */, DecryptHandle* /* decryptHandle */,
- int /* playbackStatus */, int64_t /* position */) {
+status_t FwdLockEngine::onSetPlaybackStatus(int /* uniqueId */,
+ sp<DecryptHandle>& /* decryptHandle */, int /* playbackStatus */,
+ int64_t /* position */) {
#else
-status_t FwdLockEngine::onSetPlaybackStatus(int /* uniqueId */, DecryptHandle* /* decryptHandle */,
- int /* playbackStatus */, int /* position */) {
+status_t FwdLockEngine::onSetPlaybackStatus(int /* uniqueId */,
+ sp<DecryptHandle>& /* decryptHandle */,
+ int /* playbackStatus */, int /* position */) {
#endif
// Not used
LOG_VERBOSE("FwdLockEngine::onSetPlaybackStatus");
@@ -470,13 +472,13 @@
#ifdef USE_64BIT_DRM_API
status_t FwdLockEngine::onOpenDecryptSession(int /* uniqueId */,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
int fd,
off64_t offset,
off64_t /* length */) {
#else
status_t FwdLockEngine::onOpenDecryptSession(int /* uniqueId */,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
int fd,
int offset,
int /* length */) {
@@ -487,7 +489,7 @@
LOG_VERBOSE("FwdLockEngine::onOpenDecryptSession");
if ((-1 < fd) &&
- (NULL != decryptHandle) &&
+ (NULL != decryptHandle.get()) &&
(!decodeSessionMap.isCreated(decryptHandle->decryptId))) {
fileDesc = dup(fd);
} else {
@@ -533,12 +535,12 @@
}
status_t FwdLockEngine::onOpenDecryptSession(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
const char* uri) {
status_t result = DRM_ERROR_CANNOT_HANDLE;
const char fileTag [] = "file://";
- if (NULL != decryptHandle && NULL != uri && strlen(uri) > sizeof(fileTag)) {
+ if (NULL != decryptHandle.get() && NULL != uri && strlen(uri) > sizeof(fileTag)) {
String8 uriTag = String8(uri);
uriTag.toLower();
@@ -562,11 +564,11 @@
}
status_t FwdLockEngine::onCloseDecryptSession(int /* uniqueId */,
- DecryptHandle* decryptHandle) {
+ sp<DecryptHandle>& decryptHandle) {
status_t result = DRM_ERROR_UNKNOWN;
LOG_VERBOSE("FwdLockEngine::onCloseDecryptSession");
- if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
+ if (NULL != decryptHandle.get() && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
if (NULL != session && session->fileDesc > -1) {
FwdLockFile_detach(session->fileDesc);
@@ -576,7 +578,7 @@
}
}
- if (NULL != decryptHandle) {
+ if (NULL != decryptHandle.get()) {
if (NULL != decryptHandle->decryptInfo) {
delete decryptHandle->decryptInfo;
decryptHandle->decryptInfo = NULL;
@@ -584,9 +586,7 @@
decryptHandle->copyControlVector.clear();
decryptHandle->extendedData.clear();
-
- delete decryptHandle;
- decryptHandle = NULL;
+ decryptHandle.clear();
}
LOG_VERBOSE("FwdLockEngine::onCloseDecryptSession Exit");
@@ -594,7 +594,7 @@
}
status_t FwdLockEngine::onInitializeDecryptUnit(int /* uniqueId */,
- DecryptHandle* /* decryptHandle */,
+ sp<DecryptHandle>& /* decryptHandle */,
int /* decryptUnitId */,
const DrmBuffer* /* headerInfo */) {
ALOGE("FwdLockEngine::onInitializeDecryptUnit is not supported for this DRM scheme");
@@ -603,7 +603,7 @@
status_t FwdLockEngine::onDecrypt(
int /* uniqueId */,
- DecryptHandle* /* decryptHandle */,
+ sp<DecryptHandle>& /* decryptHandle */,
int /* decryptUnitId */,
const DrmBuffer* /* encBuffer */,
DrmBuffer** /* decBuffer */,
@@ -613,7 +613,7 @@
}
status_t FwdLockEngine::onDecrypt(int /* uniqueId */,
- DecryptHandle* /* decryptHandle */,
+ sp<DecryptHandle>& /* decryptHandle */,
int /* decryptUnitId */,
const DrmBuffer* /* encBuffer */,
DrmBuffer** /* decBuffer */) {
@@ -622,19 +622,19 @@
}
status_t FwdLockEngine::onFinalizeDecryptUnit(int /* uniqueId */,
- DecryptHandle* /* decryptHandle */,
+ sp<DecryptHandle>& /* decryptHandle */,
int /* decryptUnitId */) {
ALOGE("FwdLockEngine::onFinalizeDecryptUnit is not supported for this DRM scheme");
return DRM_ERROR_UNKNOWN;
}
ssize_t FwdLockEngine::onRead(int /* uniqueId */,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
void* buffer,
int numBytes) {
ssize_t size = -1;
- if (NULL != decryptHandle &&
+ if (NULL != decryptHandle.get() &&
decodeSessionMap.isCreated(decryptHandle->decryptId) &&
NULL != buffer &&
numBytes > -1) {
@@ -654,15 +654,15 @@
}
#ifdef USE_64BIT_DRM_API
-off64_t FwdLockEngine::onLseek(int /* uniqueId */, DecryptHandle* decryptHandle,
+off64_t FwdLockEngine::onLseek(int /* uniqueId */, sp<DecryptHandle>& decryptHandle,
off64_t offset, int whence) {
#else
-off_t FwdLockEngine::onLseek(int /* uniqueId */, DecryptHandle* decryptHandle,
+off_t FwdLockEngine::onLseek(int /* uniqueId */, sp<DecryptHandle>& decryptHandle,
off_t offset, int whence) {
#endif
off_t offval = -1;
- if (NULL != decryptHandle && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
+ if (NULL != decryptHandle.get() && decodeSessionMap.isCreated(decryptHandle->decryptId)) {
DecodeSession* session = decodeSessionMap.getValue(decryptHandle->decryptId);
if (NULL != session && session->fileDesc > -1) {
offval = FwdLockFile_lseek(session->fileDesc, offset, whence);
@@ -675,13 +675,13 @@
#ifdef USE_64BIT_DRM_API
ssize_t FwdLockEngine::onPread(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
void* buffer,
ssize_t numBytes,
off64_t offset) {
#else
ssize_t FwdLockEngine::onPread(int uniqueId,
- DecryptHandle* decryptHandle,
+ sp<DecryptHandle>& decryptHandle,
void* buffer,
ssize_t numBytes,
off_t offset) {
@@ -690,7 +690,7 @@
DecodeSession* decoderSession = NULL;
- if ((NULL != decryptHandle) &&
+ if ((NULL != decryptHandle.get()) &&
(NULL != (decoderSession = decodeSessionMap.getValue(decryptHandle->decryptId))) &&
(NULL != buffer) &&
(numBytes > -1) &&
diff --git a/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h b/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
index 7b66dc7..4ab5272 100644
--- a/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
+++ b/drm/libdrmframework/plugins/passthru/include/DrmPassthruPlugIn.h
@@ -53,10 +53,11 @@
int onCheckRightsStatus(int uniqueId, const String8& path, int action);
- status_t onConsumeRights(int uniqueId, DecryptHandle* decryptHandle, int action, bool reserve);
+ status_t onConsumeRights(int uniqueId, sp<DecryptHandle>& decryptHandle,
+ int action, bool reserve);
status_t onSetPlaybackStatus(
- int uniqueId, DecryptHandle* decryptHandle, int playbackStatus, int64_t position);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int playbackStatus, int64_t position);
bool onValidateAction(
int uniqueId, const String8& path, int action, const ActionDescription& description);
@@ -74,26 +75,25 @@
DrmSupportInfo* onGetSupportInfo(int uniqueId);
status_t onOpenDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle, int fd, off64_t offset, off64_t length);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int fd, off64_t offset,
+ off64_t length);
status_t onOpenDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle, const char* uri);
+ int uniqueId, sp<DecryptHandle>& decryptHandle, const char* uri);
- status_t onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle);
+ status_t onCloseDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle);
- status_t onInitializeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle,
+ status_t onInitializeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
int decryptUnitId, const DrmBuffer* headerInfo);
- status_t onDecrypt(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId,
+ status_t onDecrypt(int uniqueId, sp<DecryptHandle>& decryptHandle, int decryptUnitId,
const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* IV);
- status_t onFinalizeDecryptUnit(int uniqueId, DecryptHandle* decryptHandle, int decryptUnitId);
+ status_t onFinalizeDecryptUnit(int uniqueId, sp<DecryptHandle>& decryptHandle,
+ int decryptUnitId);
- ssize_t onPread(int uniqueId, DecryptHandle* decryptHandle,
+ ssize_t onPread(int uniqueId, sp<DecryptHandle>& decryptHandle,
void* buffer, ssize_t numBytes, off64_t offset);
-
-private:
- DecryptHandle* openDecryptSessionImpl();
};
};
diff --git a/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
index d7f2d28..0fa3478 100644
--- a/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
+++ b/drm/libdrmframework/plugins/passthru/src/DrmPassthruPlugIn.cpp
@@ -183,13 +183,13 @@
}
status_t DrmPassthruPlugIn::onConsumeRights(int uniqueId,
- DecryptHandle* /*decryptHandle*/, int /*action*/, bool /*reserve*/) {
+ sp<DecryptHandle>& /*decryptHandle*/, int /*action*/, bool /*reserve*/) {
ALOGV("DrmPassthruPlugIn::onConsumeRights() : %d", uniqueId);
return DRM_NO_ERROR;
}
status_t DrmPassthruPlugIn::onSetPlaybackStatus(int uniqueId,
- DecryptHandle* /*decryptHandle*/, int /*playbackStatus*/, int64_t /*position*/) {
+ sp<DecryptHandle>& /*decryptHandle*/, int /*playbackStatus*/, int64_t /*position*/) {
ALOGV("DrmPassthruPlugIn::onSetPlaybackStatus() : %d", uniqueId);
return DRM_NO_ERROR;
}
@@ -236,7 +236,8 @@
}
status_t DrmPassthruPlugIn::onOpenDecryptSession(
- int uniqueId, DecryptHandle* decryptHandle, int /*fd*/, off64_t /*offset*/, off64_t /*length*/) {
+ int uniqueId, sp<DecryptHandle>& decryptHandle, int /*fd*/, off64_t /*offset*/,
+ off64_t /*length*/) {
ALOGV("DrmPassthruPlugIn::onOpenDecryptSession() : %d", uniqueId);
#ifdef ENABLE_PASSTHRU_DECRYPTION
@@ -246,36 +247,38 @@
decryptHandle->decryptInfo = NULL;
return DRM_NO_ERROR;
#else
- (void)(decryptHandle); // unused
+ (void)(decryptHandle.get()); // unused
#endif
return DRM_ERROR_CANNOT_HANDLE;
}
status_t DrmPassthruPlugIn::onOpenDecryptSession(
- int /*uniqueId*/, DecryptHandle* /*decryptHandle*/, const char* /*uri*/) {
+ int /*uniqueId*/, sp<DecryptHandle>& /*decryptHandle*/, const char* /*uri*/) {
return DRM_ERROR_CANNOT_HANDLE;
}
-status_t DrmPassthruPlugIn::onCloseDecryptSession(int uniqueId, DecryptHandle* decryptHandle) {
+status_t DrmPassthruPlugIn::onCloseDecryptSession(int uniqueId, sp<DecryptHandle>& decryptHandle) {
ALOGV("DrmPassthruPlugIn::onCloseDecryptSession() : %d", uniqueId);
- if (NULL != decryptHandle) {
+ if (NULL != decryptHandle.get()) {
if (NULL != decryptHandle->decryptInfo) {
delete decryptHandle->decryptInfo; decryptHandle->decryptInfo = NULL;
}
- delete decryptHandle; decryptHandle = NULL;
+ decryptHandle.clear();
}
return DRM_NO_ERROR;
}
-status_t DrmPassthruPlugIn::onInitializeDecryptUnit(int uniqueId, DecryptHandle* /*decryptHandle*/,
- int /*decryptUnitId*/, const DrmBuffer* /*headerInfo*/) {
+status_t DrmPassthruPlugIn::onInitializeDecryptUnit(int uniqueId,
+ sp<DecryptHandle>& /*decryptHandle*/,
+ int /*decryptUnitId*/, const DrmBuffer* /*headerInfo*/) {
ALOGV("DrmPassthruPlugIn::onInitializeDecryptUnit() : %d", uniqueId);
return DRM_NO_ERROR;
}
-status_t DrmPassthruPlugIn::onDecrypt(int uniqueId, DecryptHandle* /*decryptHandle*/,
- int /*decryptUnitId*/, const DrmBuffer* encBuffer, DrmBuffer** decBuffer, DrmBuffer* /*IV*/) {
+status_t DrmPassthruPlugIn::onDecrypt(int uniqueId, sp<DecryptHandle>& /*decryptHandle*/,
+ int /*decryptUnitId*/, const DrmBuffer* encBuffer, DrmBuffer** decBuffer,
+ DrmBuffer* /*IV*/) {
ALOGV("DrmPassthruPlugIn::onDecrypt() : %d", uniqueId);
/**
* As a workaround implementation passthru would copy the given
@@ -296,12 +299,12 @@
}
status_t DrmPassthruPlugIn::onFinalizeDecryptUnit(
- int uniqueId, DecryptHandle* /*decryptHandle*/, int /*decryptUnitId*/) {
+ int uniqueId, sp<DecryptHandle>& /*decryptHandle*/, int /*decryptUnitId*/) {
ALOGV("DrmPassthruPlugIn::onFinalizeDecryptUnit() : %d", uniqueId);
return DRM_NO_ERROR;
}
-ssize_t DrmPassthruPlugIn::onPread(int uniqueId, DecryptHandle* /*decryptHandle*/,
+ssize_t DrmPassthruPlugIn::onPread(int uniqueId, sp<DecryptHandle>& /*decryptHandle*/,
void* /*buffer*/, ssize_t /*numBytes*/, off64_t /*offset*/) {
ALOGV("DrmPassthruPlugIn::onPread() : %d", uniqueId);
return 0;
diff --git a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
index 3b61085..d04d976 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/DrmPlugin.cpp
@@ -346,6 +346,9 @@
if (name == kDeviceIdKey) {
ALOGD("Cannot set immutable property: %s", name.c_str());
return Status::BAD_VALUE;
+ } else if (name == kClientIdKey) {
+ mByteArrayProperties[kClientIdKey] = toVector(value);
+ return Status::OK;
}
// Setting of undefined properties is not supported
diff --git a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
index d65b25c..cad9222 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
+++ b/drm/mediadrm/plugins/clearkey/hidl/include/ClearKeyDrmProperties.h
@@ -40,6 +40,10 @@
static const uint8_t kTestDeviceIdData[] =
{0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
+
+// settable byte array property
+static const std::string kClientIdKey("clientId");
+
// TODO stub out metrics for nw
static const std::string kMetricsKey("metrics");
static const uint8_t kMetricsData[] = { 0 };
diff --git a/include/media/MediaExtractorPluginApi.h b/include/media/MediaExtractorPluginApi.h
index 930b6e2..b071a58 100644
--- a/include/media/MediaExtractorPluginApi.h
+++ b/include/media/MediaExtractorPluginApi.h
@@ -19,10 +19,13 @@
#include <utils/Errors.h> // for status_t
+struct AMediaFormat;
+
namespace android {
struct MediaTrack;
class MetaDataBase;
+class MediaBufferBase;
extern "C" {
@@ -34,12 +37,45 @@
void *handle;
};
-struct CMediaExtractor {
+enum CMediaTrackReadOptions : uint32_t {
+ SEEK_PREVIOUS_SYNC = 0,
+ SEEK_NEXT_SYNC = 1,
+ SEEK_CLOSEST_SYNC = 2,
+ SEEK_CLOSEST = 3,
+ SEEK_FRAME_INDEX = 4,
+ SEEK = 8,
+ NONBLOCKING = 16
+};
+
+struct CMediaTrack {
+ void *data;
+ void (*free)(void *data);
+
+ status_t (*start)(void *data);
+ status_t (*stop)(void *data);
+ status_t (*getFormat)(void *data, MetaDataBase &format);
+ status_t (*read)(void *data, MediaBufferBase **buffer, uint32_t options, int64_t seekPosUs);
+ bool (*supportsNonBlockingRead)(void *data);
+};
+
+struct CMediaTrackV2 {
+ void *data;
+ void (*free)(void *data);
+
+ status_t (*start)(void *data);
+ status_t (*stop)(void *data);
+ status_t (*getFormat)(void *data, AMediaFormat *format);
+ status_t (*read)(void *data, MediaBufferBase **buffer, uint32_t options, int64_t seekPosUs);
+ bool (*supportsNonBlockingRead)(void *data);
+};
+
+
+struct CMediaExtractorV1 {
void *data;
void (*free)(void *data);
size_t (*countTracks)(void *data);
- MediaTrack* (*getTrack)(void *data, size_t index);
+ CMediaTrack* (*getTrack)(void *data, size_t index);
status_t (*getTrackMetaData)(
void *data,
MetaDataBase& meta,
@@ -51,22 +87,49 @@
const char * (*name)(void *data);
};
-typedef CMediaExtractor* (*CreatorFunc)(CDataSource *source, void *meta);
+struct CMediaExtractorV2 {
+ void *data;
+
+ void (*free)(void *data);
+ size_t (*countTracks)(void *data);
+ CMediaTrackV2* (*getTrack)(void *data, size_t index);
+ status_t (*getTrackMetaData)(
+ void *data,
+ AMediaFormat *meta,
+ size_t index, uint32_t flags);
+
+ status_t (*getMetaData)(void *data, AMediaFormat *meta);
+ uint32_t (*flags)(void *data);
+ status_t (*setMediaCas)(void *data, const uint8_t* casToken, size_t size);
+ const char * (*name)(void *data);
+};
+
+typedef CMediaExtractorV1* (*CreatorFuncV1)(CDataSource *source, void *meta);
typedef void (*FreeMetaFunc)(void *meta);
// The sniffer can optionally fill in an opaque object, "meta", that helps
// the corresponding extractor initialize its state without duplicating
// effort already exerted by the sniffer. If "freeMeta" is given, it will be
// called against the opaque object when it is no longer used.
-typedef CreatorFunc (*SnifferFunc)(
+typedef CreatorFuncV1 (*SnifferFuncV1)(
CDataSource *source, float *confidence,
void **meta, FreeMetaFunc *freeMeta);
+typedef CMediaExtractorV2* (*CreatorFuncV2)(CDataSource *source, void *meta);
+
+typedef CreatorFuncV2 (*SnifferFuncV2)(
+ CDataSource *source, float *confidence,
+ void **meta, FreeMetaFunc *freeMeta);
+
+typedef CMediaExtractorV1 CMediaExtractor;
+typedef CreatorFuncV1 CreatorFunc;
+
+
typedef struct {
const uint8_t b[16];
} media_uuid_t;
-typedef struct {
+struct ExtractorDef {
// version number of this structure
const uint32_t def_version;
@@ -82,11 +145,16 @@
// a human readable name
const char *extractor_name;
- // the sniffer function
- const SnifferFunc sniff;
-} ExtractorDef;
+ union {
+ SnifferFuncV1 v1;
+ SnifferFuncV2 v2;
+ } sniff;
+};
-const uint32_t EXTRACTORDEF_VERSION = 1;
+const uint32_t EXTRACTORDEF_VERSION_LEGACY = 1;
+const uint32_t EXTRACTORDEF_VERSION_CURRENT = 2;
+
+const uint32_t EXTRACTORDEF_VERSION = EXTRACTORDEF_VERSION_LEGACY;
// each plugin library exports one function of this type
typedef ExtractorDef (*GetExtractorDef)();
diff --git a/include/media/MediaExtractorPluginHelper.h b/include/media/MediaExtractorPluginHelper.h
index c817b30..d76d5f8 100644
--- a/include/media/MediaExtractorPluginHelper.h
+++ b/include/media/MediaExtractorPluginHelper.h
@@ -33,6 +33,146 @@
class MetaDataBase;
struct MediaTrack;
+
+class MediaTrackHelper {
+public:
+ virtual ~MediaTrackHelper() {};
+ virtual status_t start() = 0;
+ virtual status_t stop() = 0;
+ virtual status_t getFormat(MetaDataBase& format) = 0;
+
+ class ReadOptions {
+ public:
+ enum SeekMode : int32_t {
+ SEEK_PREVIOUS_SYNC,
+ SEEK_NEXT_SYNC,
+ SEEK_CLOSEST_SYNC,
+ SEEK_CLOSEST,
+ SEEK_FRAME_INDEX,
+ };
+
+ ReadOptions(uint32_t options, int64_t seekPosUs) {
+ mOptions = options;
+ mSeekPosUs = seekPosUs;
+ }
+ bool getSeekTo(int64_t *time_us, SeekMode *mode) const {
+ if ((mOptions & CMediaTrackReadOptions::SEEK) == 0) {
+ return false;
+ }
+ *time_us = mSeekPosUs;
+ *mode = (SeekMode) (mOptions & 7);
+ return true;
+ }
+ bool getNonBlocking() const {
+ return mOptions & CMediaTrackReadOptions::NONBLOCKING;
+ }
+ private:
+ uint32_t mOptions;
+ int64_t mSeekPosUs;
+ };
+
+ virtual status_t read(
+ MediaBufferBase **buffer, const ReadOptions *options = NULL) = 0;
+ virtual bool supportsNonBlockingRead() { return false; }
+};
+
+inline CMediaTrack *wrap(MediaTrackHelper *track) {
+ CMediaTrack *wrapper = (CMediaTrack*) malloc(sizeof(CMediaTrack));
+ wrapper->data = track;
+ wrapper->free = [](void *data) -> void {
+ delete (MediaTrackHelper*)(data);
+ };
+ wrapper->start = [](void *data) -> status_t {
+ return ((MediaTrackHelper*)data)->start();
+ };
+ wrapper->stop = [](void *data) -> status_t {
+ return ((MediaTrackHelper*)data)->stop();
+ };
+ wrapper->getFormat = [](void *data, MetaDataBase &meta) -> status_t {
+ return ((MediaTrackHelper*)data)->getFormat(meta);
+ };
+ wrapper->read = [](void *data, MediaBufferBase **buffer, uint32_t options, int64_t seekPosUs)
+ -> status_t {
+ MediaTrackHelper::ReadOptions opts(options, seekPosUs);
+ return ((MediaTrackHelper*)data)->read(buffer, &opts);
+ };
+ wrapper->supportsNonBlockingRead = [](void *data) -> bool {
+ return ((MediaTrackHelper*)data)->supportsNonBlockingRead();
+ };
+ return wrapper;
+}
+
+
+class MediaTrackHelperV2 {
+public:
+ virtual ~MediaTrackHelperV2() {};
+ virtual status_t start() = 0;
+ virtual status_t stop() = 0;
+ virtual status_t getFormat(AMediaFormat *format) = 0;
+
+ class ReadOptions {
+ public:
+ enum SeekMode : int32_t {
+ SEEK_PREVIOUS_SYNC,
+ SEEK_NEXT_SYNC,
+ SEEK_CLOSEST_SYNC,
+ SEEK_CLOSEST,
+ SEEK_FRAME_INDEX,
+ };
+
+ ReadOptions(uint32_t options, int64_t seekPosUs) {
+ mOptions = options;
+ mSeekPosUs = seekPosUs;
+ }
+ bool getSeekTo(int64_t *time_us, SeekMode *mode) const {
+ if ((mOptions & CMediaTrackReadOptions::SEEK) == 0) {
+ return false;
+ }
+ *time_us = mSeekPosUs;
+ *mode = (SeekMode) (mOptions & 7);
+ return true;
+ }
+ bool getNonBlocking() const {
+ return mOptions & CMediaTrackReadOptions::NONBLOCKING;
+ }
+ private:
+ uint32_t mOptions;
+ int64_t mSeekPosUs;
+ };
+
+ virtual status_t read(
+ MediaBufferBase **buffer, const ReadOptions *options = NULL) = 0;
+ virtual bool supportsNonBlockingRead() { return false; }
+};
+
+inline CMediaTrackV2 *wrapV2(MediaTrackHelperV2 *track) {
+ CMediaTrackV2 *wrapper = (CMediaTrackV2*) malloc(sizeof(CMediaTrackV2));
+ wrapper->data = track;
+ wrapper->free = [](void *data) -> void {
+ delete (MediaTrackHelperV2*)(data);
+ };
+ wrapper->start = [](void *data) -> status_t {
+ return ((MediaTrackHelperV2*)data)->start();
+ };
+ wrapper->stop = [](void *data) -> status_t {
+ return ((MediaTrackHelperV2*)data)->stop();
+ };
+ wrapper->getFormat = [](void *data, AMediaFormat *meta) -> status_t {
+ return ((MediaTrackHelperV2*)data)->getFormat(meta);
+ };
+ wrapper->read = [](void *data, MediaBufferBase **buffer, uint32_t options, int64_t seekPosUs)
+ -> status_t {
+ MediaTrackHelperV2::ReadOptions opts(options, seekPosUs);
+ return ((MediaTrackHelperV2*)data)->read(buffer, &opts);
+ };
+ wrapper->supportsNonBlockingRead = [](void *data) -> bool {
+ return ((MediaTrackHelperV2*)data)->supportsNonBlockingRead();
+ };
+ return wrapper;
+}
+
+
+
// extractor plugins can derive from this class which looks remarkably
// like MediaExtractor and can be easily wrapped in the required C API
class MediaExtractorPluginHelper
@@ -40,7 +180,7 @@
public:
virtual ~MediaExtractorPluginHelper() {}
virtual size_t countTracks() = 0;
- virtual MediaTrack *getTrack(size_t index) = 0;
+ virtual MediaTrackHelper *getTrack(size_t index) = 0;
enum GetTrackMetaDataFlags {
kIncludeExtensiveMetaData = 1
@@ -89,8 +229,8 @@
wrapper->countTracks = [](void *data) -> size_t {
return ((MediaExtractorPluginHelper*)data)->countTracks();
};
- wrapper->getTrack = [](void *data, size_t index) -> MediaTrack* {
- return ((MediaExtractorPluginHelper*)data)->getTrack(index);
+ wrapper->getTrack = [](void *data, size_t index) -> CMediaTrack* {
+ return wrap(((MediaExtractorPluginHelper*)data)->getTrack(index));
};
wrapper->getTrackMetaData = [](
void *data,
@@ -118,6 +258,89 @@
return wrapper;
}
+class MediaExtractorPluginHelperV2
+{
+public:
+ virtual ~MediaExtractorPluginHelperV2() {}
+ virtual size_t countTracks() = 0;
+ virtual MediaTrackHelperV2 *getTrack(size_t index) = 0;
+
+ enum GetTrackMetaDataFlags {
+ kIncludeExtensiveMetaData = 1
+ };
+ virtual status_t getTrackMetaData(
+ AMediaFormat *meta,
+ size_t index, uint32_t flags = 0) = 0;
+
+ // Return container specific meta-data. The default implementation
+ // returns an empty metadata object.
+ virtual status_t getMetaData(AMediaFormat *meta) = 0;
+
+ enum Flags {
+ CAN_SEEK_BACKWARD = 1, // the "seek 10secs back button"
+ CAN_SEEK_FORWARD = 2, // the "seek 10secs forward button"
+ CAN_PAUSE = 4,
+ CAN_SEEK = 8, // the "seek bar"
+ };
+
+ // If subclasses do _not_ override this, the default is
+ // CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE
+ virtual uint32_t flags() const {
+ return CAN_SEEK_BACKWARD | CAN_SEEK_FORWARD | CAN_SEEK | CAN_PAUSE;
+ };
+
+ virtual status_t setMediaCas(const uint8_t* /*casToken*/, size_t /*size*/) {
+ return INVALID_OPERATION;
+ }
+
+ virtual const char * name() { return "<unspecified>"; }
+
+protected:
+ MediaExtractorPluginHelperV2() {}
+
+private:
+ MediaExtractorPluginHelperV2(const MediaExtractorPluginHelperV2 &);
+ MediaExtractorPluginHelperV2 &operator=(const MediaExtractorPluginHelperV2 &);
+};
+
+inline CMediaExtractorV2 *wrapV2(MediaExtractorPluginHelperV2 *extractor) {
+ CMediaExtractorV2 *wrapper = (CMediaExtractorV2*) malloc(sizeof(CMediaExtractorV2));
+ wrapper->data = extractor;
+ wrapper->free = [](void *data) -> void {
+ delete (MediaExtractorPluginHelperV2*)(data);
+ };
+ wrapper->countTracks = [](void *data) -> size_t {
+ return ((MediaExtractorPluginHelperV2*)data)->countTracks();
+ };
+ wrapper->getTrack = [](void *data, size_t index) -> CMediaTrackV2* {
+ return wrapV2(((MediaExtractorPluginHelperV2*)data)->getTrack(index));
+ };
+ wrapper->getTrackMetaData = [](
+ void *data,
+ AMediaFormat *meta,
+ size_t index, uint32_t flags) -> status_t {
+ return ((MediaExtractorPluginHelperV2*)data)->getTrackMetaData(meta, index, flags);
+ };
+ wrapper->getMetaData = [](
+ void *data,
+ AMediaFormat *meta) -> status_t {
+ return ((MediaExtractorPluginHelperV2*)data)->getMetaData(meta);
+ };
+ wrapper->flags = [](
+ void *data) -> uint32_t {
+ return ((MediaExtractorPluginHelperV2*)data)->flags();
+ };
+ wrapper->setMediaCas = [](
+ void *data, const uint8_t *casToken, size_t size) -> status_t {
+ return ((MediaExtractorPluginHelperV2*)data)->setMediaCas(casToken, size);
+ };
+ wrapper->name = [](
+ void *data) -> const char * {
+ return ((MediaExtractorPluginHelperV2*)data)->name();
+ };
+ return wrapper;
+}
+
/* adds some convience methods */
class DataSourceHelper {
public:
@@ -129,11 +352,13 @@
mSource = source->mSource;
}
- ssize_t readAt(off64_t offset, void *data, size_t size) {
+ virtual ~DataSourceHelper() {}
+
+ virtual ssize_t readAt(off64_t offset, void *data, size_t size) {
return mSource->readAt(mSource->handle, offset, data, size);
}
- status_t getSize(off64_t *size) {
+ virtual status_t getSize(off64_t *size) {
return mSource->getSize(mSource->handle, size);
}
@@ -141,7 +366,7 @@
return mSource->getUri(mSource->handle, uriString, bufferSize);
}
- uint32_t flags() {
+ virtual uint32_t flags() {
return mSource->flags(mSource->handle);
}
diff --git a/include/media/MediaTrack.h b/include/media/MediaTrack.h
deleted file mode 120000
index 5a63287a..0000000
--- a/include/media/MediaTrack.h
+++ /dev/null
@@ -1 +0,0 @@
-../../media/libmediaextractor/include/media/MediaTrack.h
\ No newline at end of file
diff --git a/media/libmediaextractor/include/media/MediaTrack.h b/include/media/MediaTrack.h
similarity index 68%
rename from media/libmediaextractor/include/media/MediaTrack.h
rename to include/media/MediaTrack.h
index 94510a2..ee3591e 100644
--- a/media/libmediaextractor/include/media/MediaTrack.h
+++ b/include/media/MediaTrack.h
@@ -22,8 +22,10 @@
#include <binder/IMemory.h>
#include <binder/MemoryDealer.h>
+#include <media/MediaExtractorPluginApi.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
+#include <media/MediaExtractorPluginApi.h>
#include <utils/Log.h>
#include <utils/RefBase.h>
#include <utils/Vector.h>
@@ -31,6 +33,7 @@
namespace android {
class MediaBufferBase;
+struct CMediaTrack;
class SourceBaseAllocTracker {
public:
@@ -49,7 +52,7 @@
// To be called before any other methods on this object, except
// getFormat().
- virtual status_t start(MetaDataBase *params = NULL) = 0;
+ virtual status_t start() = 0;
// Any blocking read call returns immediately with a result of NO_INIT.
// It is an error to call any methods other than start after this call
@@ -67,20 +70,30 @@
// b) not be late, i.e. lateness_us = 0
struct ReadOptions {
enum SeekMode : int32_t {
- SEEK_PREVIOUS_SYNC,
- SEEK_NEXT_SYNC,
- SEEK_CLOSEST_SYNC,
- SEEK_CLOSEST,
- SEEK_FRAME_INDEX,
+ SEEK_PREVIOUS_SYNC = CMediaTrackReadOptions::SEEK_PREVIOUS_SYNC,
+ SEEK_NEXT_SYNC = CMediaTrackReadOptions::SEEK_NEXT_SYNC,
+ SEEK_CLOSEST_SYNC = CMediaTrackReadOptions::SEEK_CLOSEST_SYNC,
+ SEEK_CLOSEST = CMediaTrackReadOptions::SEEK_CLOSEST,
+ SEEK_FRAME_INDEX = CMediaTrackReadOptions::SEEK_FRAME_INDEX,
};
- ReadOptions();
+ ReadOptions() {
+ reset();
+ }
// Reset everything back to defaults.
- void reset();
+ void reset() {
+ mOptions = 0;
+ mSeekTimeUs = 0;
+ mNonBlocking = false;
+ }
void setSeekTo(int64_t time_us, SeekMode mode = SEEK_CLOSEST_SYNC);
- void clearSeekTo();
+ void clearSeekTo() {
+ mOptions &= ~kSeekTo_Option;
+ mSeekTimeUs = 0;
+ mSeekMode = SEEK_CLOSEST_SYNC;
+ }
bool getSeekTo(int64_t *time_us, SeekMode *mode) const;
void setNonBlocking();
@@ -126,6 +139,42 @@
MediaTrack &operator=(const MediaTrack &);
};
+class MediaTrackCUnwrapper : public MediaTrack {
+public:
+ explicit MediaTrackCUnwrapper(CMediaTrack *wrapper);
+
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t getFormat(MetaDataBase& format);
+ virtual status_t read(MediaBufferBase **buffer, const ReadOptions *options = NULL);
+
+ virtual bool supportNonblockingRead();
+
+protected:
+ virtual ~MediaTrackCUnwrapper();
+
+private:
+ CMediaTrack *wrapper;
+};
+
+class MediaTrackCUnwrapperV2 : public MediaTrack {
+public:
+ explicit MediaTrackCUnwrapperV2(CMediaTrackV2 *wrapper);
+
+ virtual status_t start();
+ virtual status_t stop();
+ virtual status_t getFormat(MetaDataBase& format);
+ virtual status_t read(MediaBufferBase **buffer, const ReadOptions *options = NULL);
+
+ virtual bool supportNonblockingRead();
+
+protected:
+ virtual ~MediaTrackCUnwrapperV2();
+
+private:
+ CMediaTrackV2 *wrapper;
+};
+
} // namespace android
#endif // MEDIA_SOURCE_BASE_H_
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index 8a97299..1ca0fdc 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -18,12 +18,10 @@
libmedia \
libmedialogservice \
libnbaio \
+ libnblog \
libsoundtriggerservice \
libutils
-LOCAL_STATIC_LIBRARIES := \
- libjsoncpp
-
# TODO oboeservice is the old folder name for aaudioservice. It will be changed.
LOCAL_C_INCLUDES := \
frameworks/av/services/audioflinger \
@@ -57,13 +55,9 @@
# both to build both 32 bit and 64 bit libraries,
# and use primary target architecture (32 or 64) for audioserver.
# first to build libraries and audioserver for the primary target architecture only.
-# <empty> to build both 32 and 64 bit libraries and 32 bit audioserver.
+# <empty> to build both 32 and 64 bit libraries and primary target audioserver.
-ifeq ($(strip $(AUDIOSERVER_MULTILIB)),)
-LOCAL_MULTILIB := 32
-else
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-endif
LOCAL_MODULE := audioserver
diff --git a/media/bufferpool/2.0/Accessor.cpp b/media/bufferpool/2.0/Accessor.cpp
index c1b62f8..3eaea7c 100644
--- a/media/bufferpool/2.0/Accessor.cpp
+++ b/media/bufferpool/2.0/Accessor.cpp
@@ -114,7 +114,10 @@
}
// Methods from ::android::hardware::media::bufferpool::V2_0::IAccessor follow.
-Return<void> Accessor::connect(connect_cb _hidl_cb) {
+Return<void> Accessor::connect(
+ const sp<::android::hardware::media::bufferpool::V2_0::IObserver>& observer,
+ connect_cb _hidl_cb) {
+ (void)observer;
sp<Connection> connection;
ConnectionId connectionId;
const StatusDescriptor* fmqDesc;
@@ -122,7 +125,7 @@
ResultStatus status = connect(&connection, &connectionId, &fmqDesc, false);
if (status == ResultStatus::OK) {
_hidl_cb(status, connection, connectionId, *fmqDesc,
- android::hardware::MQDescriptorSync<BufferInvalidationMessage>(
+ android::hardware::MQDescriptorUnsync<BufferInvalidationMessage>(
std::vector<android::hardware::GrantorDescriptor>(),
nullptr /* nhandle */, 0 /* size */));
} else {
@@ -130,7 +133,7 @@
android::hardware::MQDescriptorSync<BufferStatusMessage>(
std::vector<android::hardware::GrantorDescriptor>(),
nullptr /* nhandle */, 0 /* size */),
- android::hardware::MQDescriptorSync<BufferInvalidationMessage>(
+ android::hardware::MQDescriptorUnsync<BufferInvalidationMessage>(
std::vector<android::hardware::GrantorDescriptor>(),
nullptr /* nhandle */, 0 /* size */));
}
diff --git a/media/bufferpool/2.0/Accessor.h b/media/bufferpool/2.0/Accessor.h
index fa2cb1b..a718da1 100644
--- a/media/bufferpool/2.0/Accessor.h
+++ b/media/bufferpool/2.0/Accessor.h
@@ -18,6 +18,7 @@
#define ANDROID_HARDWARE_MEDIA_BUFFERPOOL_V2_0_ACCESSOR_H
#include <android/hardware/media/bufferpool/2.0/IAccessor.h>
+#include <android/hardware/media/bufferpool/2.0/IObserver.h>
#include <bufferpool/BufferPoolTypes.h>
#include <hidl/MQDescriptor.h>
#include <hidl/Status.h>
@@ -79,7 +80,7 @@
*/
struct Accessor : public IAccessor {
// Methods from ::android::hardware::media::bufferpool::V2_0::IAccessor follow.
- Return<void> connect(connect_cb _hidl_cb) override;
+ Return<void> connect(const sp<::android::hardware::media::bufferpool::V2_0::IObserver>& observer, connect_cb _hidl_cb) override;
/**
* Creates a buffer pool accessor which uses the specified allocator.
diff --git a/media/bufferpool/2.0/AccessorImpl.cpp b/media/bufferpool/2.0/AccessorImpl.cpp
index ef62d03..0ba6600 100644
--- a/media/bufferpool/2.0/AccessorImpl.cpp
+++ b/media/bufferpool/2.0/AccessorImpl.cpp
@@ -399,6 +399,9 @@
case BufferStatus::TRANSFER_ERROR:
ret = handleTransferResult(message);
break;
+ case BufferStatus::INVALIDATION_ACK:
+ // TODO
+ break;
}
if (ret == false) {
ALOGW("buffer status message processing failure - message : %d connection : %lld",
diff --git a/media/bufferpool/2.0/BufferPoolClient.cpp b/media/bufferpool/2.0/BufferPoolClient.cpp
index 4eeebb4..0f763f7 100644
--- a/media/bufferpool/2.0/BufferPoolClient.cpp
+++ b/media/bufferpool/2.0/BufferPoolClient.cpp
@@ -262,11 +262,13 @@
: mLocal(false), mValid(false), mAccessor(accessor), mSeqId(0),
mLastEvictCacheUs(getTimestampNow()) {
bool valid = false;
+ sp<IObserver> observer; // TODO
sp<IConnection>& outConnection = mRemoteConnection;
ConnectionId& id = mConnectionId;
std::unique_ptr<BufferStatusChannel>& outChannel =
mReleasing.mStatusChannel;
Return<void> transResult = accessor->connect(
+ observer,
[&valid, &outConnection, &id, &outChannel]
(ResultStatus status, sp<IConnection> connection,
ConnectionId connectionId, const StatusDescriptor& desc,
diff --git a/media/bufferpool/2.0/BufferPoolClient.h b/media/bufferpool/2.0/BufferPoolClient.h
index 00d6839..1889ea3 100644
--- a/media/bufferpool/2.0/BufferPoolClient.h
+++ b/media/bufferpool/2.0/BufferPoolClient.h
@@ -20,6 +20,7 @@
#include <memory>
#include <android/hardware/media/bufferpool/2.0/IAccessor.h>
#include <android/hardware/media/bufferpool/2.0/IConnection.h>
+#include <android/hardware/media/bufferpool/2.0/IObserver.h>
#include <bufferpool/BufferPoolTypes.h>
#include <cutils/native_handle.h>
#include "Accessor.h"
@@ -33,6 +34,7 @@
using ::android::hardware::media::bufferpool::V2_0::IAccessor;
using ::android::hardware::media::bufferpool::V2_0::IConnection;
+using ::android::hardware::media::bufferpool::V2_0::IObserver;
using ::android::hardware::media::bufferpool::V2_0::ResultStatus;
using ::android::sp;
diff --git a/media/bufferpool/2.0/include/bufferpool/BufferPoolTypes.h b/media/bufferpool/2.0/include/bufferpool/BufferPoolTypes.h
index eb845e1..7c906cb 100644
--- a/media/bufferpool/2.0/include/bufferpool/BufferPoolTypes.h
+++ b/media/bufferpool/2.0/include/bufferpool/BufferPoolTypes.h
@@ -48,6 +48,7 @@
namespace implementation {
using ::android::hardware::kSynchronizedReadWrite;
+using ::android::hardware::kUnsynchronizedWrite;
typedef uint32_t BufferId;
typedef uint64_t TransactionId;
@@ -60,7 +61,7 @@
typedef android::hardware::MessageQueue<BufferStatusMessage, kSynchronizedReadWrite> BufferStatusQueue;
typedef BufferStatusQueue::Descriptor StatusDescriptor;
-typedef android::hardware::MessageQueue<BufferInvalidationMessage, kSynchronizedReadWrite>
+typedef android::hardware::MessageQueue<BufferInvalidationMessage, kUnsynchronizedWrite>
BufferInvalidationQueue;
typedef BufferInvalidationQueue::Descriptor InvalidationDescriptor;
diff --git a/media/extractors/aac/AACExtractor.cpp b/media/extractors/aac/AACExtractor.cpp
index 955a588..f179e03 100644
--- a/media/extractors/aac/AACExtractor.cpp
+++ b/media/extractors/aac/AACExtractor.cpp
@@ -20,31 +20,29 @@
#include "AACExtractor.h"
#include <media/MediaExtractorPluginApi.h>
-#include <media/MediaTrack.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MediaErrors.h>
-#include <media/stagefright/MetaData.h>
#include <media/stagefright/MetaDataUtils.h>
#include <utils/String8.h>
namespace android {
-class AACSource : public MediaTrack {
+class AACSource : public MediaTrackHelperV2 {
public:
AACSource(
DataSourceHelper *source,
- MetaDataBase &meta,
+ AMediaFormat *meta,
const Vector<uint64_t> &offset_vector,
int64_t frame_duration_us);
- virtual status_t start(MetaDataBase *params = NULL);
+ virtual status_t start();
virtual status_t stop();
- virtual status_t getFormat(MetaDataBase&);
+ virtual status_t getFormat(AMediaFormat*);
virtual status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL);
@@ -55,7 +53,7 @@
private:
static const size_t kMaxFrameSize;
DataSourceHelper *mDataSource;
- MetaDataBase mMeta;
+ AMediaFormat *mMeta;
off64_t mOffset;
int64_t mCurrentTimeUs;
@@ -151,6 +149,7 @@
}
channel = (header[0] & 0x1) << 2 | (header[1] >> 6);
+ mMeta = AMediaFormat_new();
MakeAACCodecSpecificData(mMeta, profile, sf_index, channel);
off64_t streamSize, numFrames = 0;
@@ -174,19 +173,20 @@
// Round up and get the duration
mFrameDurationUs = (1024 * 1000000ll + (sr - 1)) / sr;
duration = numFrames * mFrameDurationUs;
- mMeta.setInt64(kKeyDuration, duration);
+ AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, duration);
}
mInitCheck = OK;
}
AACExtractor::~AACExtractor() {
+ AMediaFormat_delete(mMeta);
}
-status_t AACExtractor::getMetaData(MetaDataBase &meta) {
- meta.clear();
+status_t AACExtractor::getMetaData(AMediaFormat *meta) {
+ AMediaFormat_clear(meta);
if (mInitCheck == OK) {
- meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC_ADTS);
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_AAC_ADTS);
}
return OK;
@@ -196,7 +196,7 @@
return mInitCheck == OK ? 1 : 0;
}
-MediaTrack *AACExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *AACExtractor::getTrack(size_t index) {
if (mInitCheck != OK || index != 0) {
return NULL;
}
@@ -204,12 +204,12 @@
return new AACSource(mDataSource, mMeta, mOffsetVector, mFrameDurationUs);
}
-status_t AACExtractor::getTrackMetaData(MetaDataBase &meta, size_t index, uint32_t /* flags */) {
+status_t AACExtractor::getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t /* flags */) {
if (mInitCheck != OK || index != 0) {
return UNKNOWN_ERROR;
}
- meta = mMeta;
+ AMediaFormat_copy(meta, mMeta);
return OK;
}
@@ -220,7 +220,7 @@
AACSource::AACSource(
DataSourceHelper *source,
- MetaDataBase &meta,
+ AMediaFormat *meta,
const Vector<uint64_t> &offset_vector,
int64_t frame_duration_us)
: mDataSource(source),
@@ -239,7 +239,7 @@
}
}
-status_t AACSource::start(MetaDataBase * /* params */) {
+status_t AACSource::start() {
CHECK(!mStarted);
if (mOffsetVector.empty()) {
@@ -266,8 +266,8 @@
return OK;
}
-status_t AACSource::getFormat(MetaDataBase &meta) {
- meta = mMeta;
+status_t AACSource::getFormat(AMediaFormat *meta) {
+ AMediaFormat_copy(meta, mMeta);
return OK;
}
@@ -323,14 +323,14 @@
////////////////////////////////////////////////////////////////////////////////
-static CMediaExtractor* CreateExtractor(
+static CMediaExtractorV2* CreateExtractor(
CDataSource *source,
void *meta) {
off64_t offset = *static_cast<off64_t*>(meta);
- return wrap(new AACExtractor(new DataSourceHelper(source), offset));
+ return wrapV2(new AACExtractor(new DataSourceHelper(source), offset));
}
-static CreatorFunc Sniff(
+static CreatorFuncV2 Sniff(
CDataSource *source, float *confidence, void **meta,
FreeMetaFunc *freeMeta) {
off64_t pos = 0;
@@ -390,11 +390,11 @@
__attribute__ ((visibility ("default")))
ExtractorDef GETEXTRACTORDEF() {
return {
- EXTRACTORDEF_VERSION,
+ EXTRACTORDEF_VERSION_CURRENT,
UUID("4fd80eae-03d2-4d72-9eb9-48fa6bb54613"),
1, // version
"AAC Extractor",
- Sniff
+ { .v2 = Sniff }
};
}
diff --git a/media/extractors/aac/AACExtractor.h b/media/extractors/aac/AACExtractor.h
index 3f20461..add7d22 100644
--- a/media/extractors/aac/AACExtractor.h
+++ b/media/extractors/aac/AACExtractor.h
@@ -20,7 +20,7 @@
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
#include <utils/Vector.h>
@@ -29,15 +29,15 @@
struct AMessage;
class String8;
-class AACExtractor : public MediaExtractorPluginHelper {
+class AACExtractor : public MediaExtractorPluginHelperV2 {
public:
AACExtractor(DataSourceHelper *source, off64_t offset);
virtual size_t countTracks();
- virtual MediaTrack *getTrack(size_t index);
- virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+ virtual MediaTrackHelperV2 *getTrack(size_t index);
+ virtual status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
- virtual status_t getMetaData(MetaDataBase& meta);
+ virtual status_t getMetaData(AMediaFormat *meta);
virtual const char * name() { return "AACExtractor"; }
protected:
@@ -45,7 +45,7 @@
private:
DataSourceHelper *mDataSource;
- MetaDataBase mMeta;
+ AMediaFormat *mMeta;
status_t mInitCheck;
Vector<uint64_t> mOffsetVector;
diff --git a/media/extractors/aac/Android.bp b/media/extractors/aac/Android.bp
index 5f05b42..42b0a64 100644
--- a/media/extractors/aac/Android.bp
+++ b/media/extractors/aac/Android.bp
@@ -9,6 +9,7 @@
shared_libs: [
"liblog",
"libmediaextractor",
+ "libmediandk",
],
static_libs: [
diff --git a/media/extractors/amr/AMRExtractor.cpp b/media/extractors/amr/AMRExtractor.cpp
index e109fb3..99d24c9 100644
--- a/media/extractors/amr/AMRExtractor.cpp
+++ b/media/extractors/amr/AMRExtractor.cpp
@@ -20,7 +20,6 @@
#include "AMRExtractor.h"
-#include <media/MediaTrack.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
@@ -30,19 +29,19 @@
namespace android {
-class AMRSource : public MediaTrack {
+class AMRSource : public MediaTrackHelperV2 {
public:
AMRSource(
DataSourceHelper *source,
- MetaDataBase &meta,
+ AMediaFormat *meta,
bool isWide,
const off64_t *offset_table,
size_t offset_table_length);
- virtual status_t start(MetaDataBase *params = NULL);
+ virtual status_t start();
virtual status_t stop();
- virtual status_t getFormat(MetaDataBase &);
+ virtual status_t getFormat(AMediaFormat *);
virtual status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL);
@@ -52,7 +51,7 @@
private:
DataSourceHelper *mDataSource;
- MetaDataBase mMeta;
+ AMediaFormat *mMeta;
bool mIsWide;
off64_t mOffset;
@@ -152,12 +151,12 @@
return;
}
- mMeta.setCString(
- kKeyMIMEType, mIsWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB
- : MEDIA_MIMETYPE_AUDIO_AMR_NB);
+ mMeta = AMediaFormat_new();
+ AMediaFormat_setString(mMeta, AMEDIAFORMAT_KEY_MIME,
+ mIsWide ? MEDIA_MIMETYPE_AUDIO_AMR_WB : MEDIA_MIMETYPE_AUDIO_AMR_NB);
- mMeta.setInt32(kKeyChannelCount, 1);
- mMeta.setInt32(kKeySampleRate, mIsWide ? 16000 : 8000);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, 1);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mIsWide ? 16000 : 8000);
off64_t offset = mIsWide ? 9 : 6;
off64_t streamSize;
@@ -165,11 +164,11 @@
int64_t duration = 0;
if (mDataSource->getSize(&streamSize) == OK) {
- while (offset < streamSize) {
- status_t status = getFrameSizeByOffset(source, offset, mIsWide, &frameSize);
- if (status == ERROR_END_OF_STREAM) {
- break;
- } else if (status != OK) {
+ while (offset < streamSize) {
+ status_t status = getFrameSizeByOffset(source, offset, mIsWide, &frameSize);
+ if (status == ERROR_END_OF_STREAM) {
+ break;
+ } else if (status != OK) {
return;
}
@@ -184,7 +183,7 @@
numFrames ++;
}
- mMeta.setInt64(kKeyDuration, duration);
+ AMediaFormat_setInt64(mMeta, AMEDIAFORMAT_KEY_DURATION, duration);
}
mInitCheck = OK;
@@ -192,13 +191,15 @@
AMRExtractor::~AMRExtractor() {
delete mDataSource;
+ AMediaFormat_delete(mMeta);
}
-status_t AMRExtractor::getMetaData(MetaDataBase &meta) {
- meta.clear();
+status_t AMRExtractor::getMetaData(AMediaFormat *meta) {
+ AMediaFormat_clear(meta);
if (mInitCheck == OK) {
- meta.setCString(kKeyMIMEType, mIsWide ? "audio/amr-wb" : "audio/amr");
+ AMediaFormat_setString(meta,
+ AMEDIAFORMAT_KEY_MIME, mIsWide ? "audio/amr-wb" : "audio/amr");
}
return OK;
@@ -208,7 +209,7 @@
return mInitCheck == OK ? 1 : 0;
}
-MediaTrack *AMRExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *AMRExtractor::getTrack(size_t index) {
if (mInitCheck != OK || index != 0) {
return NULL;
}
@@ -217,19 +218,19 @@
mOffsetTable, mOffsetTableLength);
}
-status_t AMRExtractor::getTrackMetaData(MetaDataBase &meta, size_t index, uint32_t /* flags */) {
+status_t AMRExtractor::getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t /* flags */) {
if (mInitCheck != OK || index != 0) {
return UNKNOWN_ERROR;
}
- meta = mMeta;
+ AMediaFormat_copy(meta, mMeta);
return OK;
}
////////////////////////////////////////////////////////////////////////////////
AMRSource::AMRSource(
- DataSourceHelper *source, MetaDataBase &meta,
+ DataSourceHelper *source, AMediaFormat *meta,
bool isWide, const off64_t *offset_table, size_t offset_table_length)
: mDataSource(source),
mMeta(meta),
@@ -250,7 +251,7 @@
}
}
-status_t AMRSource::start(MetaDataBase * /* params */) {
+status_t AMRSource::start() {
CHECK(!mStarted);
mOffset = mIsWide ? 9 : 6;
@@ -272,8 +273,8 @@
return OK;
}
-status_t AMRSource::getFormat(MetaDataBase &meta) {
- meta = mMeta;
+status_t AMRSource::getFormat(AMediaFormat *meta) {
+ AMediaFormat_copy(meta, mMeta);
return OK;
}
@@ -367,23 +368,25 @@
__attribute__ ((visibility ("default")))
ExtractorDef GETEXTRACTORDEF() {
return {
- EXTRACTORDEF_VERSION,
+ EXTRACTORDEF_VERSION_CURRENT,
UUID("c86639c9-2f31-40ac-a715-fa01b4493aaf"),
1,
"AMR Extractor",
- [](
- CDataSource *source,
- float *confidence,
- void **,
- FreeMetaFunc *) -> CreatorFunc {
- DataSourceHelper helper(source);
- if (SniffAMR(&helper, nullptr, confidence)) {
- return [](
- CDataSource *source,
- void *) -> CMediaExtractor* {
- return wrap(new AMRExtractor(new DataSourceHelper(source)));};
+ {
+ .v2 = [](
+ CDataSource *source,
+ float *confidence,
+ void **,
+ FreeMetaFunc *) -> CreatorFuncV2 {
+ DataSourceHelper helper(source);
+ if (SniffAMR(&helper, nullptr, confidence)) {
+ return [](
+ CDataSource *source,
+ void *) -> CMediaExtractorV2* {
+ return wrapV2(new AMRExtractor(new DataSourceHelper(source)));};
+ }
+ return NULL;
}
- return NULL;
}
};
}
diff --git a/media/extractors/amr/AMRExtractor.h b/media/extractors/amr/AMRExtractor.h
index 499ca67..145fe08 100644
--- a/media/extractors/amr/AMRExtractor.h
+++ b/media/extractors/amr/AMRExtractor.h
@@ -21,7 +21,7 @@
#include <utils/Errors.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
namespace android {
@@ -29,15 +29,15 @@
class String8;
#define OFFSET_TABLE_LEN 300
-class AMRExtractor : public MediaExtractorPluginHelper {
+class AMRExtractor : public MediaExtractorPluginHelperV2 {
public:
explicit AMRExtractor(DataSourceHelper *source);
virtual size_t countTracks();
- virtual MediaTrack *getTrack(size_t index);
- virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+ virtual MediaTrackHelperV2 *getTrack(size_t index);
+ virtual status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
- virtual status_t getMetaData(MetaDataBase& meta);
+ virtual status_t getMetaData(AMediaFormat *meta);
virtual const char * name() { return "AMRExtractor"; }
protected:
@@ -45,7 +45,7 @@
private:
DataSourceHelper *mDataSource;
- MetaDataBase mMeta;
+ AMediaFormat *mMeta;
status_t mInitCheck;
bool mIsWide;
diff --git a/media/extractors/amr/Android.bp b/media/extractors/amr/Android.bp
index d962b93..83ea4c7 100644
--- a/media/extractors/amr/Android.bp
+++ b/media/extractors/amr/Android.bp
@@ -9,6 +9,7 @@
shared_libs: [
"liblog",
"libmediaextractor",
+ "libmediandk",
],
static_libs: [
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index 1efaa0c..337ada5 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -25,13 +25,13 @@
#include "FLAC/stream_decoder.h"
#include <media/MediaExtractorPluginApi.h>
-#include <media/MediaTrack.h>
#include <media/VorbisComment.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/base64.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
#include <media/stagefright/MediaBufferBase.h>
@@ -39,14 +39,14 @@
class FLACParser;
-class FLACSource : public MediaTrack {
+class FLACSource : public MediaTrackHelper {
public:
FLACSource(
DataSourceHelper *dataSource,
MetaDataBase &meta);
- virtual status_t start(MetaDataBase *params);
+ virtual status_t start();
virtual status_t stop();
virtual status_t getFormat(MetaDataBase &meta);
@@ -731,7 +731,7 @@
delete mParser;
}
-status_t FLACSource::start(MetaDataBase * /* params */)
+status_t FLACSource::start()
{
ALOGV("FLACSource::start");
@@ -812,7 +812,7 @@
return mInitCheck == OK ? 1 : 0;
}
-MediaTrack *FLACExtractor::getTrack(size_t index)
+MediaTrackHelper *FLACExtractor::getTrack(size_t index)
{
if (mInitCheck != OK || index > 0) {
return NULL;
@@ -866,19 +866,21 @@
UUID("1364b048-cc45-4fda-9934-327d0ebf9829"),
1,
"FLAC Extractor",
- [](
- CDataSource *source,
- float *confidence,
- void **,
- FreeMetaFunc *) -> CreatorFunc {
- DataSourceHelper helper(source);
- if (SniffFLAC(&helper, confidence)) {
- return [](
- CDataSource *source,
- void *) -> CMediaExtractor* {
- return wrap(new FLACExtractor(new DataSourceHelper(source)));};
+ {
+ [](
+ CDataSource *source,
+ float *confidence,
+ void **,
+ FreeMetaFunc *) -> CreatorFunc {
+ DataSourceHelper helper(source);
+ if (SniffFLAC(&helper, confidence)) {
+ return [](
+ CDataSource *source,
+ void *) -> CMediaExtractor* {
+ return wrap(new FLACExtractor(new DataSourceHelper(source)));};
+ }
+ return NULL;
}
- return NULL;
}
};
}
diff --git a/media/extractors/flac/FLACExtractor.h b/media/extractors/flac/FLACExtractor.h
index 1ddff43..829f661 100644
--- a/media/extractors/flac/FLACExtractor.h
+++ b/media/extractors/flac/FLACExtractor.h
@@ -33,7 +33,7 @@
explicit FLACExtractor(DataSourceHelper *source);
virtual size_t countTracks();
- virtual MediaTrack *getTrack(size_t index);
+ virtual MediaTrackHelper *getTrack(size_t index);
virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
virtual status_t getMetaData(MetaDataBase& meta);
diff --git a/media/extractors/midi/Android.bp b/media/extractors/midi/Android.bp
index fde09df18..c5df5c7 100644
--- a/media/extractors/midi/Android.bp
+++ b/media/extractors/midi/Android.bp
@@ -9,6 +9,7 @@
shared_libs: [
"liblog",
"libmediaextractor",
+ "libmediandk",
],
static_libs: [
diff --git a/media/extractors/midi/MidiExtractor.cpp b/media/extractors/midi/MidiExtractor.cpp
index 233033e..9c2c863 100644
--- a/media/extractors/midi/MidiExtractor.cpp
+++ b/media/extractors/midi/MidiExtractor.cpp
@@ -24,8 +24,8 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
+#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/MetaData.h>
-#include <media/MediaTrack.h>
#include <libsonivox/eas_reverb.h>
namespace android {
@@ -33,16 +33,16 @@
// how many Sonivox output buffers to aggregate into one MediaBufferBase
static const int NUM_COMBINE_BUFFERS = 4;
-class MidiSource : public MediaTrack {
+class MidiSource : public MediaTrackHelperV2 {
public:
MidiSource(
MidiEngine &engine,
- MetaDataBase &trackMetadata);
+ AMediaFormat *trackMetadata);
- virtual status_t start(MetaDataBase *params);
+ virtual status_t start();
virtual status_t stop();
- virtual status_t getFormat(MetaDataBase&);
+ virtual status_t getFormat(AMediaFormat *);
virtual status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL);
@@ -52,7 +52,7 @@
private:
MidiEngine &mEngine;
- MetaDataBase &mTrackMetadata;
+ AMediaFormat *mTrackMetadata;
bool mInitCheck;
bool mStarted;
@@ -69,7 +69,7 @@
MidiSource::MidiSource(
MidiEngine &engine,
- MetaDataBase &trackMetadata)
+ AMediaFormat *trackMetadata)
: mEngine(engine),
mTrackMetadata(trackMetadata),
mInitCheck(false),
@@ -87,7 +87,7 @@
}
}
-status_t MidiSource::start(MetaDataBase * /* params */)
+status_t MidiSource::start()
{
ALOGV("MidiSource::start");
@@ -108,9 +108,9 @@
return OK;
}
-status_t MidiSource::getFormat(MetaDataBase &meta)
+status_t MidiSource::getFormat(AMediaFormat *meta)
{
- meta = mTrackMetadata;
+ AMediaFormat_copy(meta, mTrackMetadata);
return OK;
}
@@ -143,8 +143,8 @@
// MidiEngine
MidiEngine::MidiEngine(CDataSource *dataSource,
- MetaDataBase *fileMetadata,
- MetaDataBase *trackMetadata) :
+ AMediaFormat *fileMetadata,
+ AMediaFormat *trackMetadata) :
mGroup(NULL),
mEasData(NULL),
mEasHandle(NULL),
@@ -170,16 +170,20 @@
}
if (fileMetadata != NULL) {
- fileMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MIDI);
+ AMediaFormat_setString(fileMetadata, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MIDI);
}
if (trackMetadata != NULL) {
- trackMetadata->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
- trackMetadata->setInt64(kKeyDuration, 1000ll * temp); // milli->micro
+ AMediaFormat_setString(trackMetadata, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
+ AMediaFormat_setInt64(
+ trackMetadata, AMEDIAFORMAT_KEY_DURATION, 1000ll * temp); // milli->micro
mEasConfig = EAS_Config();
- trackMetadata->setInt32(kKeySampleRate, mEasConfig->sampleRate);
- trackMetadata->setInt32(kKeyChannelCount, mEasConfig->numChannels);
- trackMetadata->setInt32(kKeyPcmEncoding, kAudioEncodingPcm16bit);
+ AMediaFormat_setInt32(
+ trackMetadata, AMEDIAFORMAT_KEY_SAMPLE_RATE, mEasConfig->sampleRate);
+ AMediaFormat_setInt32(
+ trackMetadata, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mEasConfig->numChannels);
+ AMediaFormat_setInt32(
+ trackMetadata, AMEDIAFORMAT_KEY_PCM_ENCODING, kAudioEncodingPcm16bit);
}
mIsInitialized = true;
}
@@ -268,13 +272,17 @@
mInitCheck(false)
{
ALOGV("MidiExtractor ctor");
- mEngine = new MidiEngine(mDataSource, &mFileMetadata, &mTrackMetadata);
+ mFileMetadata = AMediaFormat_new();
+ mTrackMetadata = AMediaFormat_new();
+ mEngine = new MidiEngine(mDataSource, mFileMetadata, mTrackMetadata);
mInitCheck = mEngine->initCheck();
}
MidiExtractor::~MidiExtractor()
{
ALOGV("MidiExtractor dtor");
+ AMediaFormat_delete(mFileMetadata);
+ AMediaFormat_delete(mTrackMetadata);
}
size_t MidiExtractor::countTracks()
@@ -282,7 +290,7 @@
return mInitCheck == OK ? 1 : 0;
}
-MediaTrack *MidiExtractor::getTrack(size_t index)
+MediaTrackHelperV2 *MidiExtractor::getTrack(size_t index)
{
if (mInitCheck != OK || index > 0) {
return NULL;
@@ -291,20 +299,20 @@
}
status_t MidiExtractor::getTrackMetaData(
- MetaDataBase &meta,
+ AMediaFormat *meta,
size_t index, uint32_t /* flags */) {
ALOGV("MidiExtractor::getTrackMetaData");
if (mInitCheck != OK || index > 0) {
return UNKNOWN_ERROR;
}
- meta = mTrackMetadata;
+ AMediaFormat_copy(meta, mTrackMetadata);
return OK;
}
-status_t MidiExtractor::getMetaData(MetaDataBase &meta)
+status_t MidiExtractor::getMetaData(AMediaFormat *meta)
{
ALOGV("MidiExtractor::getMetaData");
- meta = mFileMetadata;
+ AMediaFormat_copy(meta, mFileMetadata);
return OK;
}
@@ -323,27 +331,30 @@
}
+
extern "C" {
// This is the only symbol that needs to be exported
__attribute__ ((visibility ("default")))
ExtractorDef GETEXTRACTORDEF() {
return {
- EXTRACTORDEF_VERSION,
+ EXTRACTORDEF_VERSION_CURRENT,
UUID("ef6cca0a-f8a2-43e6-ba5f-dfcd7c9a7ef2"),
1,
"MIDI Extractor",
- [](
+ {
+ .v2 = [](
CDataSource *source,
float *confidence,
void **,
- FreeMetaFunc *) -> CreatorFunc {
- if (SniffMidi(source, confidence)) {
- return [](
- CDataSource *source,
- void *) -> CMediaExtractor* {
- return wrap(new MidiExtractor(source));};
+ FreeMetaFunc *) -> CreatorFuncV2 {
+ if (SniffMidi(source, confidence)) {
+ return [](
+ CDataSource *source,
+ void *) -> CMediaExtractorV2* {
+ return wrapV2(new MidiExtractor(source));};
+ }
+ return NULL;
}
- return NULL;
}
};
}
diff --git a/media/extractors/midi/MidiExtractor.h b/media/extractors/midi/MidiExtractor.h
index fbbe93e..d82c5be 100644
--- a/media/extractors/midi/MidiExtractor.h
+++ b/media/extractors/midi/MidiExtractor.h
@@ -22,8 +22,8 @@
#include <media/MediaExtractorPluginHelper.h>
#include <media/stagefright/MediaBufferBase.h>
#include <media/stagefright/MediaBufferGroup.h>
-#include <media/stagefright/MetaDataBase.h>
#include <media/MidiIoWrapper.h>
+#include <media/NdkMediaFormat.h>
#include <utils/String8.h>
#include <libsonivox/eas.h>
@@ -32,8 +32,8 @@
class MidiEngine {
public:
explicit MidiEngine(CDataSource *dataSource,
- MetaDataBase *fileMetadata,
- MetaDataBase *trackMetadata);
+ AMediaFormat *fileMetadata,
+ AMediaFormat *trackMetadata);
~MidiEngine();
status_t initCheck();
@@ -51,16 +51,16 @@
bool mIsInitialized;
};
-class MidiExtractor : public MediaExtractorPluginHelper {
+class MidiExtractor : public MediaExtractorPluginHelperV2 {
public:
explicit MidiExtractor(CDataSource *source);
virtual size_t countTracks();
- virtual MediaTrack *getTrack(size_t index);
- virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+ virtual MediaTrackHelperV2 *getTrack(size_t index);
+ virtual status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
- virtual status_t getMetaData(MetaDataBase& meta);
+ virtual status_t getMetaData(AMediaFormat *meta);
virtual const char * name() { return "MidiExtractor"; }
protected:
@@ -69,10 +69,10 @@
private:
CDataSource *mDataSource;
status_t mInitCheck;
- MetaDataBase mFileMetadata;
+ AMediaFormat *mFileMetadata;
// There is only one track
- MetaDataBase mTrackMetadata;
+ AMediaFormat *mTrackMetadata;
MidiEngine *mEngine;
diff --git a/media/extractors/mkv/MatroskaExtractor.cpp b/media/extractors/mkv/MatroskaExtractor.cpp
index a387970..3578d4c 100644
--- a/media/extractors/mkv/MatroskaExtractor.cpp
+++ b/media/extractors/mkv/MatroskaExtractor.cpp
@@ -23,7 +23,6 @@
#include <media/DataSourceBase.h>
#include <media/ExtractorUtils.h>
-#include <media/MediaTrack.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AUtils.h>
#include <media/stagefright/foundation/ABuffer.h>
@@ -124,10 +123,10 @@
BlockIterator &operator=(const BlockIterator &);
};
-struct MatroskaSource : public MediaTrack {
+struct MatroskaSource : public MediaTrackHelper {
MatroskaSource(MatroskaExtractor *extractor, size_t index);
- virtual status_t start(MetaDataBase *params);
+ virtual status_t start();
virtual status_t stop();
virtual status_t getFormat(MetaDataBase &);
@@ -222,7 +221,8 @@
mExtractor->mTracks.itemAt(index).mTrackNum,
index),
mNALSizeLen(-1) {
- MetaDataBase &meta = mExtractor->mTracks.editItemAt(index).mMeta;
+ MatroskaExtractor::TrackInfo &trackInfo = mExtractor->mTracks.editItemAt(index);
+ MetaDataBase &meta = trackInfo.mMeta;
const char *mime;
CHECK(meta.findCString(kKeyMIMEType, &mime));
@@ -235,9 +235,9 @@
uint32_t dummy;
const uint8_t *avcc;
size_t avccSize;
- int32_t nalSizeLen = 0;
- if (meta.findInt32(kKeyNalLengthSize, &nalSizeLen)) {
- if (nalSizeLen >= 0 && nalSizeLen <= 4) {
+ int32_t nalSizeLen = trackInfo.mNalLengthSize;
+ if (nalSizeLen >= 0) {
+ if (nalSizeLen <= 4) {
mNALSizeLen = nalSizeLen;
}
} else if (meta.findData(kKeyAVCC, &dummy, (const void **)&avcc, &avccSize)
@@ -269,7 +269,7 @@
clearPendingFrames();
}
-status_t MatroskaSource::start(MetaDataBase * /* params */) {
+status_t MatroskaSource::start() {
if (mType == AVC && mNALSizeLen < 0) {
return ERROR_MALFORMED;
}
@@ -1002,7 +1002,7 @@
return mTracks.size();
}
-MediaTrack *MatroskaExtractor::getTrack(size_t index) {
+MediaTrackHelper *MatroskaExtractor::getTrack(size_t index) {
if (index >= mTracks.size()) {
return NULL;
}
@@ -1227,7 +1227,7 @@
}
// Override the synthesized nal length size, which is arbitrary
- trackInfo->mMeta.setInt32(kKeyNalLengthSize, 0);
+ trackInfo->mNalLengthSize = 0;
return OK;
}
@@ -1344,6 +1344,7 @@
trackInfo->mEncrypted = false;
trackInfo->mHeader = NULL;
trackInfo->mHeaderLen = 0;
+ trackInfo->mNalLengthSize = -1;
for(size_t i = 0; i < track->GetContentEncodingCount(); i++) {
const mkvparser::ContentEncoding *encoding = track->GetContentEncodingByIndex(i);
@@ -1646,19 +1647,21 @@
UUID("abbedd92-38c4-4904-a4c1-b3f45f899980"),
1,
"Matroska Extractor",
- [](
- CDataSource *source,
- float *confidence,
- void **,
- FreeMetaFunc *) -> CreatorFunc {
- DataSourceHelper helper(source);
- if (SniffMatroska(&helper, confidence)) {
- return [](
- CDataSource *source,
- void *) -> CMediaExtractor* {
- return wrap(new MatroskaExtractor(new DataSourceHelper(source)));};
+ {
+ [](
+ CDataSource *source,
+ float *confidence,
+ void **,
+ FreeMetaFunc *) -> CreatorFunc {
+ DataSourceHelper helper(source);
+ if (SniffMatroska(&helper, confidence)) {
+ return [](
+ CDataSource *source,
+ void *) -> CMediaExtractor* {
+ return wrap(new MatroskaExtractor(new DataSourceHelper(source)));};
+ }
+ return NULL;
}
- return NULL;
}
};
}
diff --git a/media/extractors/mkv/MatroskaExtractor.h b/media/extractors/mkv/MatroskaExtractor.h
index 2c6ca85..03fdeee 100644
--- a/media/extractors/mkv/MatroskaExtractor.h
+++ b/media/extractors/mkv/MatroskaExtractor.h
@@ -40,7 +40,7 @@
virtual size_t countTracks();
- virtual MediaTrack *getTrack(size_t index);
+ virtual MediaTrackHelper *getTrack(size_t index);
virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
@@ -69,6 +69,7 @@
// in ~MatroskaExtractor.
unsigned char *mHeader;
size_t mHeaderLen;
+ int32_t mNalLengthSize;
const mkvparser::Track* getTrack() const;
const mkvparser::CuePoint::TrackPosition *find(long long timeNs) const;
diff --git a/media/extractors/mp3/MP3Extractor.cpp b/media/extractors/mp3/MP3Extractor.cpp
index a1e5593..eca5711 100644
--- a/media/extractors/mp3/MP3Extractor.cpp
+++ b/media/extractors/mp3/MP3Extractor.cpp
@@ -24,7 +24,6 @@
#include "VBRISeeker.h"
#include "XINGSeeker.h"
-#include <media/MediaTrack.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AMessage.h>
#include <media/stagefright/foundation/avc_utils.h>
@@ -208,14 +207,14 @@
return valid;
}
-class MP3Source : public MediaTrack {
+class MP3Source : public MediaTrackHelper {
public:
MP3Source(
MetaDataBase &meta, DataSourceHelper *source,
off64_t first_frame_pos, uint32_t fixed_header,
MP3Seeker *seeker);
- virtual status_t start(MetaDataBase *params = NULL);
+ virtual status_t start();
virtual status_t stop();
virtual status_t getFormat(MetaDataBase &meta);
@@ -411,7 +410,7 @@
return mInitCheck != OK ? 0 : 1;
}
-MediaTrack *MP3Extractor::getTrack(size_t index) {
+MediaTrackHelper *MP3Extractor::getTrack(size_t index) {
if (mInitCheck != OK || index != 0) {
return NULL;
}
@@ -463,7 +462,7 @@
}
}
-status_t MP3Source::start(MetaDataBase *) {
+status_t MP3Source::start() {
CHECK(!mStarted);
mGroup = new MediaBufferGroup;
@@ -719,7 +718,7 @@
UUID("812a3f6c-c8cf-46de-b529-3774b14103d4"),
1, // version
"MP3 Extractor",
- Sniff
+ { Sniff }
};
}
diff --git a/media/extractors/mp3/MP3Extractor.h b/media/extractors/mp3/MP3Extractor.h
index 585d9f6..92e0665 100644
--- a/media/extractors/mp3/MP3Extractor.h
+++ b/media/extractors/mp3/MP3Extractor.h
@@ -38,7 +38,7 @@
~MP3Extractor();
virtual size_t countTracks();
- virtual MediaTrack *getTrack(size_t index);
+ virtual MediaTrackHelper *getTrack(size_t index);
virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
virtual status_t getMetaData(MetaDataBase& meta);
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index f52d451..e81e9b2 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -34,7 +34,6 @@
#include <media/DataSourceBase.h>
#include <media/ExtractorUtils.h>
-#include <media/MediaTrack.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -68,7 +67,7 @@
kMaxAtomSize = 64 * 1024 * 1024,
};
-class MPEG4Source : public MediaTrack {
+class MPEG4Source : public MediaTrackHelper {
static const size_t kMaxPcmFrameSize = 8192;
public:
// Caller retains ownership of both "dataSource" and "sampleTable".
@@ -82,7 +81,7 @@
const sp<ItemTable> &itemTable);
virtual status_t init();
- virtual status_t start(MetaDataBase *params = NULL);
+ virtual status_t start();
virtual status_t stop();
virtual status_t getFormat(MetaDataBase &);
@@ -138,8 +137,6 @@
MediaBufferBase *mBuffer;
- bool mWantsNALFragments;
-
uint8_t *mSrcBuffer;
bool mIsHeif;
@@ -198,13 +195,14 @@
// possibly wrapping multiple times to cover all tracks, i.e.
// Each CachedRangedDataSource caches the sampletable metadata for a single track.
-struct CachedRangedDataSource : public DataSourceHelper {
+class CachedRangedDataSource : public DataSourceHelper {
+public:
explicit CachedRangedDataSource(DataSourceHelper *source);
virtual ~CachedRangedDataSource();
- virtual ssize_t readAt(off64_t offset, void *data, size_t size);
- virtual status_t getSize(off64_t *size);
- virtual uint32_t flags();
+ ssize_t readAt(off64_t offset, void *data, size_t size) override;
+ status_t getSize(off64_t *size) override;
+ uint32_t flags() override;
status_t setCachedRange(off64_t offset, size_t size, bool assumeSourceOwnershipOnSuccess);
@@ -236,7 +234,7 @@
CachedRangedDataSource::~CachedRangedDataSource() {
clearCache();
if (mOwnsDataSource) {
- delete (CachedRangedDataSource*)mSource;
+ delete mSource;
}
}
@@ -366,7 +364,6 @@
mMoofFound(false),
mMdatFound(false),
mDataSource(source),
- mCachedSource(NULL),
mInitCheck(NO_INIT),
mHeaderTimescale(0),
mIsQT(false),
@@ -393,9 +390,6 @@
}
mPssh.clear();
- if (mCachedSource != mDataSource) {
- delete mCachedSource;
- }
delete mDataSource;
}
@@ -909,8 +903,8 @@
if (cachedSource->setCachedRange(
*offset, chunk_size,
- mCachedSource != NULL /* assume ownership on success */) == OK) {
- mDataSource = mCachedSource = cachedSource;
+ true /* assume ownership on success */) == OK) {
+ mDataSource = cachedSource;
} else {
delete cachedSource;
}
@@ -3619,7 +3613,7 @@
}
}
-MediaTrack *MPEG4Extractor::getTrack(size_t index) {
+MediaTrackHelper *MPEG4Extractor::getTrack(size_t index) {
status_t err;
if ((err = readMetaData()) != OK) {
return NULL;
@@ -4126,7 +4120,6 @@
mStarted(false),
mGroup(NULL),
mBuffer(NULL),
- mWantsNALFragments(false),
mSrcBuffer(NULL),
mIsHeif(itemTable != NULL),
mItemTable(itemTable) {
@@ -4225,19 +4218,11 @@
free(mCurrentSampleInfoOffsets);
}
-status_t MPEG4Source::start(MetaDataBase *params) {
+status_t MPEG4Source::start() {
Mutex::Autolock autoLock(mLock);
CHECK(!mStarted);
- int32_t val;
- if (params && params->findInt32(kKeyWantsNALFragments, &val)
- && val != 0) {
- mWantsNALFragments = true;
- } else {
- mWantsNALFragments = false;
- }
-
int32_t tmp;
CHECK(mFormat.findInt32(kKeyMaxInputSize, &tmp));
size_t max_size = tmp;
@@ -5117,7 +5102,7 @@
}
}
- if ((!mIsAVC && !mIsHEVC && !mIsAC4) || mWantsNALFragments) {
+ if ((!mIsAVC && !mIsHEVC && !mIsAC4)) {
if (newBuffer) {
if (mIsPcm) {
// The twos' PCM block reader assumes that all samples has the same size.
@@ -5545,7 +5530,7 @@
}
- if ((!mIsAVC && !mIsHEVC)|| mWantsNALFragments) {
+ if ((!mIsAVC && !mIsHEVC)) {
if (newBuffer) {
if (!isInRange((size_t)0u, mBuffer->size(), size)) {
mBuffer->release();
@@ -5973,7 +5958,7 @@
UUID("27575c67-4417-4c54-8d3d-8e626985a164"),
1, // version
"MP4 Extractor",
- Sniff
+ { Sniff }
};
}
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index ca273e0..9b8de20 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -33,7 +33,6 @@
struct AMessage;
struct CDataSource;
class DataSourceHelper;
-struct CachedRangedDataSource;
class SampleTable;
class String8;
namespace heif {
@@ -59,7 +58,7 @@
explicit MPEG4Extractor(DataSourceHelper *source, const char *mime = NULL);
virtual size_t countTracks();
- virtual MediaTrack *getTrack(size_t index);
+ virtual MediaTrackHelper *getTrack(size_t index);
virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
virtual status_t getMetaData(MetaDataBase& meta);
@@ -99,7 +98,6 @@
Vector<Trex> mTrex;
DataSourceHelper *mDataSource;
- CachedRangedDataSource *mCachedSource;
status_t mInitCheck;
uint32_t mHeaderTimescale;
bool mIsQT;
diff --git a/media/extractors/mpeg2/Android.bp b/media/extractors/mpeg2/Android.bp
index 5e4a592..40314dc 100644
--- a/media/extractors/mpeg2/Android.bp
+++ b/media/extractors/mpeg2/Android.bp
@@ -25,6 +25,10 @@
"libstagefright_foundation",
],
+ header_libs: [
+ "libbase_headers",
+ ],
+
static_libs: [
"libstagefright_mpeg2support",
"libutils",
diff --git a/media/extractors/mpeg2/ExtractorBundle.cpp b/media/extractors/mpeg2/ExtractorBundle.cpp
index 88c2d87..366aa59 100644
--- a/media/extractors/mpeg2/ExtractorBundle.cpp
+++ b/media/extractors/mpeg2/ExtractorBundle.cpp
@@ -35,24 +35,26 @@
UUID("3d1dcfeb-e40a-436d-a574-c2438a555e5f"),
1,
"MPEG2-PS/TS Extractor",
- [](
- CDataSource *source,
- float *confidence,
- void **,
- FreeMetaFunc *) -> CreatorFunc {
- DataSourceHelper helper(source);
- if (SniffMPEG2TS(&helper, confidence)) {
- return [](
- CDataSource *source,
- void *) -> CMediaExtractor* {
- return wrap(new MPEG2TSExtractor(new DataSourceHelper(source)));};
- } else if (SniffMPEG2PS(&helper, confidence)) {
- return [](
- CDataSource *source,
- void *) -> CMediaExtractor* {
- return wrap(new MPEG2PSExtractor(new DataSourceHelper(source)));};
+ {
+ [](
+ CDataSource *source,
+ float *confidence,
+ void **,
+ FreeMetaFunc *) -> CreatorFunc {
+ DataSourceHelper helper(source);
+ if (SniffMPEG2TS(&helper, confidence)) {
+ return [](
+ CDataSource *source,
+ void *) -> CMediaExtractor* {
+ return wrap(new MPEG2TSExtractor(new DataSourceHelper(source)));};
+ } else if (SniffMPEG2PS(&helper, confidence)) {
+ return [](
+ CDataSource *source,
+ void *) -> CMediaExtractor* {
+ return wrap(new MPEG2PSExtractor(new DataSourceHelper(source)));};
+ }
+ return NULL;
}
- return NULL;
}
};
}
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.cpp b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
index ae1e6ba..fc13d2c 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.cpp
@@ -24,7 +24,6 @@
#include "mpeg2ts/ESQueue.h"
#include <media/DataSourceBase.h>
-#include <media/MediaTrack.h>
#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -40,11 +39,11 @@
namespace android {
-struct MPEG2PSExtractor::Track : public MediaTrack, public RefBase {
+struct MPEG2PSExtractor::Track : public MediaTrackHelper, public RefBase {
Track(MPEG2PSExtractor *extractor,
unsigned stream_id, unsigned stream_type);
- virtual status_t start(MetaDataBase *params);
+ virtual status_t start();
virtual status_t stop();
virtual status_t getFormat(MetaDataBase &);
@@ -72,10 +71,10 @@
DISALLOW_EVIL_CONSTRUCTORS(Track);
};
-struct MPEG2PSExtractor::WrappedTrack : public MediaTrack {
+struct MPEG2PSExtractor::WrappedTrack : public MediaTrackHelper {
WrappedTrack(MPEG2PSExtractor *extractor, const sp<Track> &track);
- virtual status_t start(MetaDataBase *params);
+ virtual status_t start();
virtual status_t stop();
virtual status_t getFormat(MetaDataBase &);
@@ -127,7 +126,7 @@
return mTracks.size();
}
-MediaTrack *MPEG2PSExtractor::getTrack(size_t index) {
+MediaTrackHelper *MPEG2PSExtractor::getTrack(size_t index) {
if (index >= mTracks.size()) {
return NULL;
}
@@ -636,7 +635,7 @@
mQueue = NULL;
}
-status_t MPEG2PSExtractor::Track::start(MetaDataBase *) {
+status_t MPEG2PSExtractor::Track::start() {
if (mSource == NULL) {
return NO_INIT;
}
@@ -681,7 +680,7 @@
}
}
- return mSource->read(buffer, options);
+ return mSource->read(buffer, (MediaSource::ReadOptions*)options);
}
status_t MPEG2PSExtractor::Track::appendPESData(
@@ -735,8 +734,8 @@
MPEG2PSExtractor::WrappedTrack::~WrappedTrack() {
}
-status_t MPEG2PSExtractor::WrappedTrack::start(MetaDataBase *params) {
- return mTrack->start(params);
+status_t MPEG2PSExtractor::WrappedTrack::start() {
+ return mTrack->start();
}
status_t MPEG2PSExtractor::WrappedTrack::stop() {
diff --git a/media/extractors/mpeg2/MPEG2PSExtractor.h b/media/extractors/mpeg2/MPEG2PSExtractor.h
index 7689910..c4082ef 100644
--- a/media/extractors/mpeg2/MPEG2PSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2PSExtractor.h
@@ -36,7 +36,7 @@
explicit MPEG2PSExtractor(DataSourceHelper *source);
virtual size_t countTracks();
- virtual MediaTrack *getTrack(size_t index);
+ virtual MediaTrackHelper *getTrack(size_t index);
virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
virtual status_t getMetaData(MetaDataBase& meta);
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.cpp b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
index cbe8556..a74ddaa 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.cpp
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.cpp
@@ -20,11 +20,12 @@
#include <inttypes.h>
#include <utils/Log.h>
+#include <android-base/macros.h>
+
#include "MPEG2TSExtractor.h"
#include <media/DataSourceBase.h>
#include <media/IStreamSource.h>
-#include <media/MediaTrack.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/ALooper.h>
@@ -49,14 +50,14 @@
static const int kMaxDurationReadSize = 250000LL;
static const int kMaxDurationRetry = 6;
-struct MPEG2TSSource : public MediaTrack {
+struct MPEG2TSSource : public MediaTrackHelper {
MPEG2TSSource(
MPEG2TSExtractor *extractor,
const sp<AnotherPacketSource> &impl,
bool doesSeek);
virtual ~MPEG2TSSource();
- virtual status_t start(MetaDataBase *params = NULL);
+ virtual status_t start();
virtual status_t stop();
virtual status_t getFormat(MetaDataBase &);
@@ -86,7 +87,7 @@
MPEG2TSSource::~MPEG2TSSource() {
}
-status_t MPEG2TSSource::start(MetaDataBase *) {
+status_t MPEG2TSSource::start() {
return mImpl->start(NULL); // AnotherPacketSource::start() doesn't use its argument
}
@@ -108,7 +109,7 @@
ReadOptions::SeekMode seekMode;
if (mDoesSeek && options && options->getSeekTo(&seekTimeUs, &seekMode)) {
// seek is needed
- status_t err = mExtractor->seek(seekTimeUs, seekMode);
+ status_t err = mExtractor->seek(seekTimeUs, (ReadOptions::SeekMode)seekMode);
if (err != OK) {
return err;
}
@@ -118,7 +119,7 @@
return ERROR_END_OF_STREAM;
}
- return mImpl->read(out, options);
+ return mImpl->read(out, (MediaSource::ReadOptions*) options);
}
////////////////////////////////////////////////////////////////////////////////
@@ -139,7 +140,7 @@
return mSourceImpls.size();
}
-MediaTrack *MPEG2TSExtractor::getTrack(size_t index) {
+MediaTrackHelper *MPEG2TSExtractor::getTrack(size_t index) {
if (index >= mSourceImpls.size()) {
return NULL;
}
@@ -481,7 +482,7 @@
}
status_t MPEG2TSExtractor::seek(int64_t seekTimeUs,
- const MediaTrack::ReadOptions::SeekMode &seekMode) {
+ const MediaTrackHelper::ReadOptions::SeekMode &seekMode) {
if (mSeekSyncPoints == NULL || mSeekSyncPoints->isEmpty()) {
ALOGW("No sync point to seek to.");
// ... and therefore we have nothing useful to do here.
@@ -502,18 +503,18 @@
}
switch (seekMode) {
- case MediaTrack::ReadOptions::SEEK_NEXT_SYNC:
+ case MediaTrackHelper::ReadOptions::SEEK_NEXT_SYNC:
if (index == mSeekSyncPoints->size()) {
ALOGW("Next sync not found; starting from the latest sync.");
--index;
}
break;
- case MediaTrack::ReadOptions::SEEK_CLOSEST_SYNC:
- case MediaTrack::ReadOptions::SEEK_CLOSEST:
+ case MediaTrackHelper::ReadOptions::SEEK_CLOSEST_SYNC:
+ case MediaTrackHelper::ReadOptions::SEEK_CLOSEST:
ALOGW("seekMode not supported: %d; falling back to PREVIOUS_SYNC",
seekMode);
- // fall-through
- case MediaTrack::ReadOptions::SEEK_PREVIOUS_SYNC:
+ FALLTHROUGH_INTENDED;
+ case MediaTrackHelper::ReadOptions::SEEK_PREVIOUS_SYNC:
if (index == 0) {
ALOGW("Previous sync not found; starting from the earliest "
"sync.");
diff --git a/media/extractors/mpeg2/MPEG2TSExtractor.h b/media/extractors/mpeg2/MPEG2TSExtractor.h
index cdaede3..4013442 100644
--- a/media/extractors/mpeg2/MPEG2TSExtractor.h
+++ b/media/extractors/mpeg2/MPEG2TSExtractor.h
@@ -22,7 +22,6 @@
#include <media/stagefright/foundation/ABase.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
-#include <media/MediaTrack.h>
#include <media/stagefright/MetaDataBase.h>
#include <utils/threads.h>
#include <utils/KeyedVector.h>
@@ -43,7 +42,7 @@
explicit MPEG2TSExtractor(DataSourceHelper *source);
virtual size_t countTracks();
- virtual MediaTrack *getTrack(size_t index);
+ virtual MediaTrackHelper *getTrack(size_t index);
virtual status_t getTrackMetaData(MetaDataBase &meta, size_t index, uint32_t flags);
virtual status_t getMetaData(MetaDataBase& meta);
@@ -91,7 +90,7 @@
// the data has syntax error during parsing, etc.
status_t feedMore(bool isInit = false);
status_t seek(int64_t seekTimeUs,
- const MediaSource::ReadOptions::SeekMode& seekMode);
+ const MediaTrackHelper::ReadOptions::SeekMode& seekMode);
status_t queueDiscontinuityForSeek(int64_t actualSeekTimeUs);
status_t seekBeyond(int64_t seekTimeUs);
diff --git a/media/extractors/ogg/OggExtractor.cpp b/media/extractors/ogg/OggExtractor.cpp
index 4e97921..123ac91 100644
--- a/media/extractors/ogg/OggExtractor.cpp
+++ b/media/extractors/ogg/OggExtractor.cpp
@@ -21,9 +21,9 @@
#include "OggExtractor.h"
#include <cutils/properties.h>
+#include <utils/Vector.h>
#include <media/DataSourceBase.h>
#include <media/ExtractorUtils.h>
-#include <media/MediaTrack.h>
#include <media/VorbisComment.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -47,12 +47,12 @@
namespace android {
-struct OggSource : public MediaTrack {
+struct OggSource : public MediaTrackHelper {
explicit OggSource(OggExtractor *extractor);
virtual status_t getFormat(MetaDataBase &);
- virtual status_t start(MetaDataBase *params = NULL);
+ virtual status_t start();
virtual status_t stop();
virtual status_t read(
@@ -241,7 +241,7 @@
return mExtractor->mImpl->getFormat(meta);
}
-status_t OggSource::start(MetaDataBase * /* params */) {
+status_t OggSource::start() {
if (mStarted) {
return INVALID_OPERATION;
}
@@ -1227,7 +1227,7 @@
return mInitCheck != OK ? 0 : 1;
}
-MediaTrack *OggExtractor::getTrack(size_t index) {
+MediaTrackHelper *OggExtractor::getTrack(size_t index) {
if (index >= 1) {
return NULL;
}
@@ -1280,7 +1280,7 @@
UUID("8cc5cd06-f772-495e-8a62-cba9649374e9"),
1, // version
"Ogg Extractor",
- Sniff
+ { Sniff }
};
}
diff --git a/media/extractors/ogg/OggExtractor.h b/media/extractors/ogg/OggExtractor.h
index fbd4663..c70f832 100644
--- a/media/extractors/ogg/OggExtractor.h
+++ b/media/extractors/ogg/OggExtractor.h
@@ -34,7 +34,7 @@
explicit OggExtractor(DataSourceHelper *source);
virtual size_t countTracks();
- virtual MediaTrack *getTrack(size_t index);
+ virtual MediaTrackHelper *getTrack(size_t index);
virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
virtual status_t getMetaData(MetaDataBase& meta);
diff --git a/media/extractors/wav/Android.bp b/media/extractors/wav/Android.bp
index 067933e..d8b4144 100644
--- a/media/extractors/wav/Android.bp
+++ b/media/extractors/wav/Android.bp
@@ -9,6 +9,7 @@
shared_libs: [
"liblog",
"libmediaextractor",
+ "libmediandk",
],
static_libs: [
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index c739c2a..cc1a501 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -22,7 +22,6 @@
#include <audio_utils/primitives.h>
#include <media/DataSourceBase.h>
-#include <media/MediaTrack.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaBufferGroup.h>
#include <media/stagefright/MediaDefs.h>
@@ -55,17 +54,17 @@
return ptr[1] << 8 | ptr[0];
}
-struct WAVSource : public MediaTrack {
+struct WAVSource : public MediaTrackHelperV2 {
WAVSource(
DataSourceHelper *dataSource,
- MetaDataBase &meta,
+ AMediaFormat *meta,
uint16_t waveFormat,
int32_t bitsPerSample,
off64_t offset, size_t size);
- virtual status_t start(MetaDataBase *params = NULL);
+ virtual status_t start();
virtual status_t stop();
- virtual status_t getFormat(MetaDataBase &meta);
+ virtual status_t getFormat(AMediaFormat *meta);
virtual status_t read(
MediaBufferBase **buffer, const ReadOptions *options = NULL);
@@ -79,7 +78,7 @@
static const size_t kMaxFrameSize;
DataSourceHelper *mDataSource;
- MetaDataBase &mMeta;
+ AMediaFormat *mMeta;
uint16_t mWaveFormat;
int32_t mSampleRate;
int32_t mNumChannels;
@@ -98,17 +97,19 @@
: mDataSource(source),
mValidFormat(false),
mChannelMask(CHANNEL_MASK_USE_CHANNEL_ORDER) {
+ mTrackMeta = AMediaFormat_new();
mInitCheck = init();
}
WAVExtractor::~WAVExtractor() {
delete mDataSource;
+ AMediaFormat_delete(mTrackMeta);
}
-status_t WAVExtractor::getMetaData(MetaDataBase &meta) {
- meta.clear();
+status_t WAVExtractor::getMetaData(AMediaFormat *meta) {
+ AMediaFormat_clear(meta);
if (mInitCheck == OK) {
- meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_CONTAINER_WAV);
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_CONTAINER_WAV);
}
return OK;
@@ -118,7 +119,7 @@
return mInitCheck == OK ? 1 : 0;
}
-MediaTrack *WAVExtractor::getTrack(size_t index) {
+MediaTrackHelperV2 *WAVExtractor::getTrack(size_t index) {
if (mInitCheck != OK || index > 0) {
return NULL;
}
@@ -129,13 +130,13 @@
}
status_t WAVExtractor::getTrackMetaData(
- MetaDataBase &meta,
+ AMediaFormat *meta,
size_t index, uint32_t /* flags */) {
if (mInitCheck != OK || index > 0) {
return UNKNOWN_ERROR;
}
- meta = mTrackMeta;
+ AMediaFormat_copy(meta, mTrackMeta);
return OK;
}
@@ -285,33 +286,34 @@
mDataOffset = offset;
mDataSize = chunkSize;
- mTrackMeta.clear();
+ AMediaFormat_clear(mTrackMeta);
switch (mWaveFormat) {
case WAVE_FORMAT_PCM:
case WAVE_FORMAT_IEEE_FLOAT:
- mTrackMeta.setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_RAW);
+ AMediaFormat_setString(mTrackMeta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_RAW);
break;
case WAVE_FORMAT_ALAW:
- mTrackMeta.setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_ALAW);
+ AMediaFormat_setString(mTrackMeta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_G711_ALAW);
break;
case WAVE_FORMAT_MSGSM:
- mTrackMeta.setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_MSGSM);
+ AMediaFormat_setString(mTrackMeta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_MSGSM);
break;
default:
CHECK_EQ(mWaveFormat, (uint16_t)WAVE_FORMAT_MULAW);
- mTrackMeta.setCString(
- kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_G711_MLAW);
+ AMediaFormat_setString(mTrackMeta,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_G711_MLAW);
break;
}
- mTrackMeta.setInt32(kKeyChannelCount, mNumChannels);
- mTrackMeta.setInt32(kKeyChannelMask, mChannelMask);
- mTrackMeta.setInt32(kKeySampleRate, mSampleRate);
- mTrackMeta.setInt32(kKeyPcmEncoding, kAudioEncodingPcm16bit);
+ AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, mNumChannels);
+ AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_CHANNEL_MASK, mChannelMask);
+ AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, mSampleRate);
+ AMediaFormat_setInt32(mTrackMeta, AMEDIAFORMAT_KEY_PCM_ENCODING,
+ kAudioEncodingPcm16bit);
int64_t durationUs = 0;
if (mWaveFormat == WAVE_FORMAT_MSGSM) {
@@ -333,7 +335,7 @@
1000000LL * num_samples / mSampleRate;
}
- mTrackMeta.setInt64(kKeyDuration, durationUs);
+ AMediaFormat_setInt64(mTrackMeta, AMEDIAFORMAT_KEY_DURATION, durationUs);
return OK;
}
@@ -349,7 +351,7 @@
WAVSource::WAVSource(
DataSourceHelper *dataSource,
- MetaDataBase &meta,
+ AMediaFormat *meta,
uint16_t waveFormat,
int32_t bitsPerSample,
off64_t offset, size_t size)
@@ -363,10 +365,10 @@
mSize(size),
mStarted(false),
mGroup(NULL) {
- CHECK(mMeta.findInt32(kKeySampleRate, &mSampleRate));
- CHECK(mMeta.findInt32(kKeyChannelCount, &mNumChannels));
+ CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate));
+ CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &mNumChannels));
- mMeta.setInt32(kKeyMaxInputSize, kMaxFrameSize);
+ AMediaFormat_setInt32(mMeta, AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, kMaxFrameSize);
}
WAVSource::~WAVSource() {
@@ -375,7 +377,7 @@
}
}
-status_t WAVSource::start(MetaDataBase * /* params */) {
+status_t WAVSource::start() {
ALOGV("WAVSource::start");
CHECK(!mStarted);
@@ -408,10 +410,10 @@
return OK;
}
-status_t WAVSource::getFormat(MetaDataBase &meta) {
+status_t WAVSource::getFormat(AMediaFormat *meta) {
ALOGV("WAVSource::getFormat");
- meta = mMeta;
+ AMediaFormat_copy(meta, mMeta);
return OK;
}
@@ -545,13 +547,13 @@
////////////////////////////////////////////////////////////////////////////////
-static CMediaExtractor* CreateExtractor(
+static CMediaExtractorV2* CreateExtractor(
CDataSource *source,
void *) {
- return wrap(new WAVExtractor(new DataSourceHelper(source)));
+ return wrapV2(new WAVExtractor(new DataSourceHelper(source)));
}
-static CreatorFunc Sniff(
+static CreatorFuncV2 Sniff(
CDataSource *source,
float *confidence,
void **,
@@ -585,11 +587,11 @@
__attribute__ ((visibility ("default")))
ExtractorDef GETEXTRACTORDEF() {
return {
- EXTRACTORDEF_VERSION,
+ EXTRACTORDEF_VERSION_CURRENT,
UUID("7d613858-5837-4a38-84c5-332d1cddee27"),
1, // version
"WAV Extractor",
- Sniff
+ { .v2 = Sniff }
};
}
diff --git a/media/extractors/wav/WAVExtractor.h b/media/extractors/wav/WAVExtractor.h
index 5136aa8..2822e80 100644
--- a/media/extractors/wav/WAVExtractor.h
+++ b/media/extractors/wav/WAVExtractor.h
@@ -21,7 +21,7 @@
#include <utils/Errors.h>
#include <media/MediaExtractorPluginApi.h>
#include <media/MediaExtractorPluginHelper.h>
-#include <media/stagefright/MetaDataBase.h>
+#include <media/NdkMediaFormat.h>
namespace android {
@@ -29,15 +29,15 @@
struct CDataSource;
class String8;
-class WAVExtractor : public MediaExtractorPluginHelper {
+class WAVExtractor : public MediaExtractorPluginHelperV2 {
public:
explicit WAVExtractor(DataSourceHelper *source);
virtual size_t countTracks();
- virtual MediaTrack *getTrack(size_t index);
- virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags);
+ virtual MediaTrackHelperV2 *getTrack(size_t index);
+ virtual status_t getTrackMetaData(AMediaFormat *meta, size_t index, uint32_t flags);
- virtual status_t getMetaData(MetaDataBase& meta);
+ virtual status_t getMetaData(AMediaFormat *meta);
virtual const char * name() { return "WAVExtractor"; }
virtual ~WAVExtractor();
@@ -53,7 +53,7 @@
uint16_t mBitsPerSample;
off64_t mDataOffset;
size_t mDataSize;
- MetaDataBase mTrackMeta;
+ AMediaFormat *mTrackMeta;
status_t init();
diff --git a/media/libaaudio/examples/utils/AAudioArgsParser.h b/media/libaaudio/examples/utils/AAudioArgsParser.h
index 0e61589..ece9e6a 100644
--- a/media/libaaudio/examples/utils/AAudioArgsParser.h
+++ b/media/libaaudio/examples/utils/AAudioArgsParser.h
@@ -185,18 +185,26 @@
mNumberOfBursts = numBursts;
}
+ int32_t getFramesPerCallback() const {
+ return mFramesPerCallback;
+ }
+ void setFramesPerCallback(int32_t size) {
+ mFramesPerCallback = size;
+ }
+
/**
* Apply these parameters to a stream builder.
* @param builder
*/
void applyParameters(AAudioStreamBuilder *builder) const {
- AAudioStreamBuilder_setChannelCount(builder, mChannelCount);
- AAudioStreamBuilder_setFormat(builder, mFormat);
- AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
AAudioStreamBuilder_setBufferCapacityInFrames(builder, mBufferCapacity);
+ AAudioStreamBuilder_setChannelCount(builder, mChannelCount);
AAudioStreamBuilder_setDeviceId(builder, mDeviceId);
- AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
+ AAudioStreamBuilder_setFormat(builder, mFormat);
+ AAudioStreamBuilder_setFramesPerDataCallback(builder, mFramesPerCallback);
AAudioStreamBuilder_setPerformanceMode(builder, mPerformanceMode);
+ AAudioStreamBuilder_setSampleRate(builder, mSampleRate);
+ AAudioStreamBuilder_setSharingMode(builder, mSharingMode);
// Call P functions if supported.
loadFutureFunctions();
@@ -232,6 +240,7 @@
aaudio_input_preset_t mInputPreset = AAUDIO_UNSPECIFIED;
int32_t mNumberOfBursts = AAUDIO_UNSPECIFIED;
+ int32_t mFramesPerCallback = AAUDIO_UNSPECIFIED;
};
class AAudioArgsParser : public AAudioParameters {
@@ -297,6 +306,9 @@
case 'y':
setContentType(atoi(&arg[2]));
break;
+ case 'z':
+ setFramesPerCallback(atoi(&arg[2]));
+ break;
default:
unrecognized = true;
break;
@@ -350,6 +362,7 @@
printf(" -u{usage} eg. 14 for AAUDIO_USAGE_GAME\n");
printf(" -x to use EXCLUSIVE mode\n");
printf(" -y{contentType} eg. 1 for AAUDIO_CONTENT_TYPE_SPEECH\n");
+ printf(" -z{callbackSize} or block size, in frames, default = 0\n");
}
static aaudio_performance_mode_t parsePerformanceMode(char c) {
@@ -406,6 +419,9 @@
printf(" Capacity: requested = %d, actual = %d\n", getBufferCapacity(),
AAudioStream_getBufferCapacityInFrames(stream));
+ printf(" CallbackSize: requested = %d, actual = %d\n", getFramesPerCallback(),
+ AAudioStream_getFramesPerDataCallback(stream));
+
printf(" SharingMode: requested = %s, actual = %s\n",
getSharingModeText(getSharingMode()),
getSharingModeText(AAudioStream_getSharingMode(stream)));
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.cpp b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
index dbf00a9..40e22ac 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.cpp
@@ -57,6 +57,9 @@
// Try to create an AudioRecord
+ const aaudio_session_id_t requestedSessionId = builder.getSessionId();
+ const audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
+
// TODO Support UNSPECIFIED in AudioRecord. For now, use stereo if unspecified.
int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
? 2 : getSamplesPerFrame();
@@ -66,17 +69,21 @@
: builder.getBufferCapacity();
- audio_input_flags_t flags = AUDIO_INPUT_FLAG_NONE;
+ audio_input_flags_t flags;
aaudio_performance_mode_t perfMode = getPerformanceMode();
switch (perfMode) {
case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
- flags = (audio_input_flags_t) (AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW);
+ // If the app asks for a sessionId then it means they want to use effects.
+ // So don't use RAW flag.
+ flags = (audio_input_flags_t) ((requestedSessionId == AAUDIO_SESSION_ID_NONE)
+ ? (AUDIO_INPUT_FLAG_FAST | AUDIO_INPUT_FLAG_RAW)
+ : (AUDIO_INPUT_FLAG_FAST));
break;
case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
case AAUDIO_PERFORMANCE_MODE_NONE:
default:
- // No flags.
+ flags = AUDIO_INPUT_FLAG_NONE;
break;
}
@@ -141,9 +148,6 @@
.tags = ""
};
- aaudio_session_id_t requestedSessionId = builder.getSessionId();
- audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
-
// ----------- open the AudioRecord ---------------------
// Might retry, but never more than once.
for (int i = 0; i < 2; i ++) {
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.cpp b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
index 1572f0d..1ac2558 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.cpp
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.cpp
@@ -59,18 +59,25 @@
return result;
}
+ const aaudio_session_id_t requestedSessionId = builder.getSessionId();
+ const audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
+
// Try to create an AudioTrack
// Use stereo if unspecified.
int32_t samplesPerFrame = (getSamplesPerFrame() == AAUDIO_UNSPECIFIED)
? 2 : getSamplesPerFrame();
audio_channel_mask_t channelMask = audio_channel_out_mask_from_count(samplesPerFrame);
- audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE;
+ audio_output_flags_t flags;
aaudio_performance_mode_t perfMode = getPerformanceMode();
switch(perfMode) {
case AAUDIO_PERFORMANCE_MODE_LOW_LATENCY:
// Bypass the normal mixer and go straight to the FAST mixer.
- flags = (audio_output_flags_t)(AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW);
+ // If the app asks for a sessionId then it means they want to use effects.
+ // So don't use RAW flag.
+ flags = (audio_output_flags_t) ((requestedSessionId == AAUDIO_SESSION_ID_NONE)
+ ? (AUDIO_OUTPUT_FLAG_FAST | AUDIO_OUTPUT_FLAG_RAW)
+ : (AUDIO_OUTPUT_FLAG_FAST));
break;
case AAUDIO_PERFORMANCE_MODE_POWER_SAVING:
@@ -81,6 +88,7 @@
case AAUDIO_PERFORMANCE_MODE_NONE:
default:
// No flags. Use a normal mixer in front of the FAST mixer.
+ flags = AUDIO_OUTPUT_FLAG_NONE;
break;
}
@@ -135,11 +143,6 @@
.tags = ""
};
- static_assert(AAUDIO_UNSPECIFIED == AUDIO_SESSION_ALLOCATE, "Session IDs should match");
-
- aaudio_session_id_t requestedSessionId = builder.getSessionId();
- audio_session_t sessionId = AAudioConvert_aaudioToAndroidSessionId(requestedSessionId);
-
mAudioTrack = new AudioTrack();
mAudioTrack->set(
AUDIO_STREAM_DEFAULT, // ignored because we pass attributes below
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index 6146c0e..827df6a 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -40,21 +40,25 @@
"TrackPlayerBase.cpp",
],
shared_libs: [
- "liblog",
- "libcutils",
- "libutils",
- "libbinder",
- "libdl",
"libaudioutils",
"libaudiomanager",
+ "libbinder",
+ "libcutils",
+ "libdl",
+ "liblog",
"libmedia_helper",
"libmediametrics",
"libmediautils",
+ "libnblog",
+ "libutils",
],
export_shared_lib_headers: ["libbinder"],
local_include_dirs: ["include/media", "aidl"],
- header_libs: ["libaudioclient_headers"],
+ header_libs: [
+ "libaudioclient_headers",
+ "libbase_headers",
+ ],
export_header_lib_headers: ["libaudioclient_headers"],
// for memory heap analysis
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 17f17a3..34c5428 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -19,6 +19,7 @@
#define LOG_TAG "AudioRecord"
#include <inttypes.h>
+#include <android-base/macros.h>
#include <sys/resource.h>
#include <binder/IPCThreadState.h>
@@ -1462,7 +1463,7 @@
case NS_WHENEVER:
// Event driven: call wake() when callback notifications conditions change.
ns = INT64_MAX;
- // fall through
+ FALLTHROUGH_INTENDED;
default:
LOG_ALWAYS_FATAL_IF(ns < 0, "%s() returned %lld", __func__, (long long)ns);
pauseInternal(ns);
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 4e39585..e77abc6 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -22,6 +22,7 @@
#include <math.h>
#include <sys/resource.h>
+#include <android-base/macros.h>
#include <audio_utils/clock.h>
#include <audio_utils/primitives.h>
#include <binder/IPCThreadState.h>
@@ -3009,7 +3010,7 @@
if (mProxy->getStreamEndDone()) {
return true;
}
- // fall through
+ FALLTHROUGH_INTENDED;
case STATE_ACTIVE:
case STATE_STOPPING:
break;
@@ -3130,7 +3131,7 @@
case NS_WHENEVER:
// Event driven: call wake() when callback notifications conditions change.
ns = INT64_MAX;
- // fall through
+ FALLTHROUGH_INTENDED;
default:
LOG_ALWAYS_FATAL_IF(ns < 0, "%s(%d): processAudioBuffer() returned %lld",
__func__, mReceiver.mId, (long long)ns);
diff --git a/media/libaudioclient/AudioTrackShared.cpp b/media/libaudioclient/AudioTrackShared.cpp
index b8156c6..c997cfa 100644
--- a/media/libaudioclient/AudioTrackShared.cpp
+++ b/media/libaudioclient/AudioTrackShared.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "AudioTrackShared"
//#define LOG_NDEBUG 0
+#include <android-base/macros.h>
#include <private/media/AudioTrackShared.h>
#include <utils/Log.h>
@@ -25,6 +26,24 @@
namespace android {
+// TODO: consider pulling this into a shared header.
+// safe_sub_overflow is used ensure that subtraction occurs in the same native type
+// with proper 2's complement overflow. Without calling this function, it is possible,
+// for example, that optimizing compilers may elect to treat 32 bit subtraction
+// as 64 bit subtraction when storing into a 64 bit destination as integer overflow is
+// technically undefined.
+template<typename T,
+ typename U,
+ typename = std::enable_if_t<std::is_same<std::decay_t<T>,
+ std::decay_t<U>>{}>>
+ // ensure arguments are same type (ignoring volatile, which is used in cblk variables).
+auto safe_sub_overflow(const T& a, const U& b) {
+ std::decay_t<T> result;
+ (void)__builtin_sub_overflow(a, b, &result);
+ // note if __builtin_sub_overflow returns true, an overflow occurred.
+ return result;
+}
+
// used to clamp a value to size_t. TODO: move to another file.
template <typename T>
size_t clampToSize(T x) {
@@ -185,7 +204,7 @@
front = cblk->u.mStreaming.mFront;
}
// write to rear, read from front
- ssize_t filled = rear - front;
+ ssize_t filled = safe_sub_overflow(rear, front);
// pipe should not be overfull
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
if (mIsOut) {
@@ -247,7 +266,7 @@
ts = requested;
break;
}
- // fall through
+ FALLTHROUGH_INTENDED;
case TIMEOUT_CONTINUE:
// FIXME we do not retry if requested < 10ms? needs documentation on this state machine
if (!measure || requested->tv_sec < total.tv_sec ||
@@ -505,7 +524,7 @@
ts = requested;
break;
}
- // fall through
+ FALLTHROUGH_INTENDED;
case TIMEOUT_CONTINUE:
// FIXME we do not retry if requested < 10ms? needs documentation on this state machine
if (requested->tv_sec < total.tv_sec ||
@@ -683,7 +702,7 @@
const size_t overflowBit = mFrameCountP2 << 1;
const size_t mask = overflowBit - 1;
int32_t newFront = (front & ~mask) | (flush & mask);
- ssize_t filled = rear - newFront;
+ ssize_t filled = safe_sub_overflow(rear, newFront);
if (filled >= (ssize_t)overflowBit) {
// front and rear offsets span the overflow bit of the p2 mask
// so rebasing newFront on the front offset is off by the overflow bit.
@@ -725,7 +744,7 @@
const size_t overflowBit = mFrameCountP2 << 1;
const size_t mask = overflowBit - 1;
int32_t newRear = (rear & ~mask) | (stop & mask);
- ssize_t filled = newRear - front;
+ ssize_t filled = safe_sub_overflow(newRear, front);
// overflowBit is unsigned, so cast to signed for comparison.
if (filled >= (ssize_t)overflowBit) {
// front and rear offsets span the overflow bit of the p2 mask
@@ -777,7 +796,7 @@
front = android_atomic_acquire_load(&cblk->u.mStreaming.mFront);
rear = cblk->u.mStreaming.mRear;
}
- ssize_t filled = rear - front;
+ ssize_t filled = safe_sub_overflow(rear, front);
// pipe should not already be overfull
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); shutting down",
@@ -904,7 +923,7 @@
return mFrameCount;
}
const int32_t rear = getRear();
- ssize_t filled = rear - cblk->u.mStreaming.mFront;
+ ssize_t filled = safe_sub_overflow(rear, cblk->u.mStreaming.mFront);
// pipe should not already be overfull
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
ALOGE("Shared memory control block is corrupt (filled=%zd, mFrameCount=%zu); shutting down",
@@ -930,7 +949,7 @@
return mFrameCount;
}
const int32_t rear = getRear();
- const ssize_t filled = rear - cblk->u.mStreaming.mFront;
+ const ssize_t filled = safe_sub_overflow(rear, cblk->u.mStreaming.mFront);
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
return 0; // error condition, silently return 0.
}
@@ -1240,7 +1259,7 @@
}
const int32_t front = android_atomic_acquire_load(&mCblk->u.mStreaming.mFront);
const int32_t rear = mCblk->u.mStreaming.mRear;
- const ssize_t filled = rear - front;
+ const ssize_t filled = safe_sub_overflow(rear, front);
if (!(0 <= filled && (size_t) filled <= mFrameCount)) {
return 0; // error condition, silently return 0.
}
diff --git a/media/libaudioclient/ToneGenerator.cpp b/media/libaudioclient/ToneGenerator.cpp
index c9263f4..5c5dbd6 100644
--- a/media/libaudioclient/ToneGenerator.cpp
+++ b/media/libaudioclient/ToneGenerator.cpp
@@ -826,6 +826,34 @@
{ .duration = 0 , .waveFreq = { 0 }, 0, 0}},
.repeatCnt = ToneGenerator::TONEGEN_INF,
.repeatSegment = 0 }, // TONE_IE_CALL_WAITING
+ { .segments = { { .duration = ToneGenerator::TONEGEN_INF, .waveFreq = { 375, 400, 425, 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_INDIA_DIAL
+ { .segments = { { .duration = 750, .waveFreq = { 400, 0 }, 0, 0 },
+ { .duration = 750, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_INDIA_BUSY
+ { .segments = { { .duration = 250, .waveFreq = { 400, 0 }, 0, 0 },
+ { .duration = 250, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_INDIA_CONGESTION
+ { .segments = { { .duration = 200, .waveFreq = { 400, 0 }, 0, 0 },
+ { .duration = 100, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 200, .waveFreq = { 400, 0 }, 0, 0 },
+ { .duration = 7500, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_INDIA_CALL_WAITING
+ { .segments = { { .duration = 400, .waveFreq = { 375, 400, 425, 0 }, 0, 0 },
+ { .duration = 200, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 400, .waveFreq = { 375, 400, 425, 0 }, 0, 0 },
+ { .duration = 2000, .waveFreq = { 0 }, 0, 0 },
+ { .duration = 0 , .waveFreq = { 0 }, 0, 0}},
+ .repeatCnt = ToneGenerator::TONEGEN_INF,
+ .repeatSegment = 0 }, // TONE_INDIA_RINGTONE
};
// Used by ToneGenerator::getToneForRegion() to convert user specified supervisory tone type
@@ -900,6 +928,16 @@
TONE_SUP_ERROR, // TONE_SUP_ERROR
TONE_IE_CALL_WAITING, // TONE_SUP_CALL_WAITING
TONE_IE_RINGTONE // TONE_SUP_RINGTONE
+ },
+ { // INDIA
+ TONE_INDIA_DIAL, // TONE_SUP_DIAL
+ TONE_INDIA_BUSY, // TONE_SUP_BUSY
+ TONE_INDIA_CONGESTION, // TONE_SUP_CONGESTION
+ TONE_SUP_RADIO_ACK, // TONE_SUP_RADIO_ACK
+ TONE_SUP_RADIO_NOTAVAIL, // TONE_SUP_RADIO_NOTAVAIL
+ TONE_SUP_ERROR, // TONE_SUP_ERROR
+ TONE_INDIA_CALL_WAITING, // TONE_SUP_CALL_WAITING
+ TONE_INDIA_RINGTONE // TONE_SUP_RINGTONE
}
};
@@ -971,6 +1009,8 @@
mRegion = HONGKONG;
} else if (strstr(value, "ie") != NULL) {
mRegion = IRELAND;
+ } else if (strstr(value, "in") != NULL) {
+ mRegion = INDIA;
} else {
mRegion = CEPT;
}
diff --git a/media/libaudioclient/include/media/AudioMixer.h b/media/libaudioclient/include/media/AudioMixer.h
index cf7d90f..aa036a8 100644
--- a/media/libaudioclient/include/media/AudioMixer.h
+++ b/media/libaudioclient/include/media/AudioMixer.h
@@ -18,17 +18,18 @@
#ifndef ANDROID_AUDIO_MIXER_H
#define ANDROID_AUDIO_MIXER_H
+#include <map>
#include <pthread.h>
#include <sstream>
#include <stdint.h>
#include <sys/types.h>
#include <unordered_map>
+#include <vector>
#include <media/AudioBufferProvider.h>
#include <media/AudioResampler.h>
#include <media/AudioResamplerPublic.h>
#include <media/BufferProviders.h>
-#include <media/nblog/NBLog.h>
#include <system/audio.h>
#include <utils/Compat.h>
#include <utils/threads.h>
@@ -41,6 +42,10 @@
namespace android {
+namespace NBLog {
+class Writer;
+} // namespace NBLog
+
// ----------------------------------------------------------------------------
class AudioMixer
diff --git a/media/libaudioclient/include/media/AudioPolicyHelper.h b/media/libaudioclient/include/media/AudioPolicyHelper.h
index 35d2e85..49432b7 100644
--- a/media/libaudioclient/include/media/AudioPolicyHelper.h
+++ b/media/libaudioclient/include/media/AudioPolicyHelper.h
@@ -16,6 +16,7 @@
#ifndef AUDIO_POLICY_HELPER_H_
#define AUDIO_POLICY_HELPER_H_
+#include <android-base/macros.h>
#include <system/audio.h>
static inline
@@ -87,7 +88,7 @@
break;
case AUDIO_STREAM_ENFORCED_AUDIBLE:
attr->flags |= AUDIO_FLAG_AUDIBILITY_ENFORCED;
- // intended fall through, attributes in common with STREAM_SYSTEM
+ FALLTHROUGH_INTENDED; // attributes in common with STREAM_SYSTEM
case AUDIO_STREAM_SYSTEM:
attr->content_type = AUDIO_CONTENT_TYPE_SONIFICATION;
attr->usage = AUDIO_USAGE_ASSISTANCE_SONIFICATION;
diff --git a/media/libaudioclient/include/media/ToneGenerator.h b/media/libaudioclient/include/media/ToneGenerator.h
index e0e3bb1..5b0689a 100644
--- a/media/libaudioclient/include/media/ToneGenerator.h
+++ b/media/libaudioclient/include/media/ToneGenerator.h
@@ -212,6 +212,12 @@
// IRELAND Supervisory tones
TONE_IE_RINGTONE, // Ring Tone: A 400Hz + 450Hz tone repeated in a 0.4s on, 0.2s off, 0.4s on, 2.0s off pattern.
TONE_IE_CALL_WAITING, // Call waiting tone: 425Hz tone repeated in a 0.18s on, 0.2s off, 0.2s on, 4.5s off pattern.
+ // INDIA supervisory tones
+ TONE_INDIA_DIAL, // Dial tone: 400 Hz tone modulated with 25Hz, continuous
+ TONE_INDIA_BUSY, // Busy tone: 400 Hz, 750ms ON, 750ms OFF...
+ TONE_INDIA_CONGESTION, // Congestion tone: 400 Hz, 250ms ON, 250ms OFF...
+ TONE_INDIA_CALL_WAITING, // Call waiting tone: 400 Hz, tone repeated in a 0.2s on, 0.1s off, 0.2s on, 7.5s off pattern.
+ TONE_INDIA_RINGTONE, // Ring tone: 400 Hz tone modulated with 25Hz, 0.4 on 0.2 off 0.4 on 2..0 off
NUM_ALTERNATE_TONES
};
@@ -223,6 +229,7 @@
SINGAPORE,
HONGKONG,
IRELAND,
+ INDIA,
CEPT,
NUM_REGIONS
};
diff --git a/media/libaudioprocessing/tests/Android.mk b/media/libaudioprocessing/tests/Android.mk
index 23e1c3a..8e081a3 100644
--- a/media/libaudioprocessing/tests/Android.mk
+++ b/media/libaudioprocessing/tests/Android.mk
@@ -78,6 +78,8 @@
liblog \
libutils \
+LOCAL_HEADER_LIBRARIES := libbase_headers
+
LOCAL_MODULE := test-resampler
LOCAL_MODULE_TAGS := optional
diff --git a/media/libaudioprocessing/tests/test-resampler.cpp b/media/libaudioprocessing/tests/test-resampler.cpp
index fbc9326..f178bde 100644
--- a/media/libaudioprocessing/tests/test-resampler.cpp
+++ b/media/libaudioprocessing/tests/test-resampler.cpp
@@ -27,6 +27,7 @@
#include <math.h>
#include <audio_utils/primitives.h>
#include <audio_utils/sndfile.h>
+#include <android-base/macros.h>
#include <utils/Vector.h>
#include <media/AudioBufferProvider.h>
#include <media/AudioResampler.h>
@@ -87,14 +88,14 @@
}
return numValues;
}
- // fall through
+ FALLTHROUGH_INTENDED;
case ',':
if (hadDigit) {
hadDigit = false;
numValues++;
break;
}
- // fall through
+ FALLTHROUGH_INTENDED;
default:
return -1;
}
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index 686ec4c..d558169 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -1751,15 +1751,14 @@
// *(int16_t *)pValue);
break;
case REVERB_PARAM_DENSITY:
- *(uint16_t *)pValue = 0;
*(int16_t *)pValue = ReverbGetDensity(pContext);
//ALOGV("\tReverb_getParameter() REVERB_PARAM_DENSITY Value is %d",
// *(uint32_t *)pValue);
break;
case REVERB_PARAM_REFLECTIONS_LEVEL:
*(uint16_t *)pValue = 0;
+ break;
case REVERB_PARAM_REFLECTIONS_DELAY:
- *(uint32_t *)pValue = 0;
case REVERB_PARAM_REVERB_DELAY:
*(uint32_t *)pValue = 0;
break;
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index b914f4b..50c33c6 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -698,6 +698,7 @@
case PREPROC_EFFECT_STATE_ACTIVE:
effect->ops->disable(effect);
Session_SetProcEnabled(effect->session, effect->procId, false);
+ break;
case PREPROC_EFFECT_STATE_CONFIG:
case PREPROC_EFFECT_STATE_CREATED:
case PREPROC_EFFECT_STATE_INIT:
diff --git a/media/libheif/include/HeifDecoderAPI.h b/media/libheif/include/HeifDecoderAPI.h
index 5183c39..aa10f33 100644
--- a/media/libheif/include/HeifDecoderAPI.h
+++ b/media/libheif/include/HeifDecoderAPI.h
@@ -74,7 +74,7 @@
int32_t mRotationAngle; // Rotation angle, clockwise, should be multiple of 90
uint32_t mBytesPerPixel; // Number of bytes for one pixel
uint32_t mIccSize; // Number of bytes in mIccData
- std::unique_ptr<uint8_t> mIccData; // Actual ICC data, memory is owned by this structure
+ std::unique_ptr<uint8_t[]> mIccData; // Actual ICC data, memory is owned by this structure
};
/*
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 9fe9ee5..bb87b10 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -3,6 +3,7 @@
vendor_available: true,
export_include_dirs: ["include"],
header_libs:[
+ "libbase_headers",
"libgui_headers",
"libstagefright_headers",
"media_plugin_headers",
@@ -265,18 +266,13 @@
},
}
-cc_library {
+cc_library_static {
name: "libmedia_player2_util",
srcs: [
"BufferingSettings.cpp",
"DataSourceDesc.cpp",
- "IDataSource.cpp",
- "IMediaExtractor.cpp",
- "IMediaExtractorService.cpp",
- "IMediaSource.cpp",
"MediaCodecBuffer.cpp",
- "MediaUtils.cpp",
"Metadata.cpp",
"NdkWrapper.cpp",
],
diff --git a/media/libmedia/IMediaSource.cpp b/media/libmedia/IMediaSource.cpp
index f185fd4..e7da488 100644
--- a/media/libmedia/IMediaSource.cpp
+++ b/media/libmedia/IMediaSource.cpp
@@ -186,6 +186,9 @@
ret = reply.readInt32();
ALOGV("readMultiple status %d, bufferCount %u, sinceStop %u",
ret, bufferCount, mBuffersSinceStop);
+ if (bufferCount && ret == WOULD_BLOCK) {
+ ret = OK;
+ }
return ret;
}
diff --git a/media/libmedia/NdkWrapper.cpp b/media/libmedia/NdkWrapper.cpp
index 272bc30..7d67262 100644
--- a/media/libmedia/NdkWrapper.cpp
+++ b/media/libmedia/NdkWrapper.cpp
@@ -31,18 +31,6 @@
#include <media/stagefright/foundation/AMessage.h>
#include <utils/Errors.h>
-// TODO: remove forward declaration when AMediaExtractor_disconnect is offcially added to NDK
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-media_status_t AMediaExtractor_disconnect(AMediaExtractor *);
-
-#ifdef __cplusplus
-} // extern "C"
-#endif
-
namespace android {
static const size_t kAESBlockSize = 16; // AES_BLOCK_SIZE
@@ -1080,14 +1068,6 @@
return OK;
}
-status_t AMediaExtractorWrapper::disconnect() {
- if (mAMediaExtractor != NULL) {
- media_status_t err = AMediaExtractor_disconnect(mAMediaExtractor);
- return translateErrorCode(err);
- }
- return DEAD_OBJECT;
-}
-
AMediaExtractor *AMediaExtractorWrapper::getAMediaExtractor() const {
return mAMediaExtractor;
}
diff --git a/media/libmedia/OMXBuffer.cpp b/media/libmedia/OMXBuffer.cpp
index 6d54a13..30dc22d 100644
--- a/media/libmedia/OMXBuffer.cpp
+++ b/media/libmedia/OMXBuffer.cpp
@@ -172,7 +172,7 @@
return OK;
}
-OMXBuffer& OMXBuffer::operator=(OMXBuffer&& source) {
+OMXBuffer& OMXBuffer::operator=(OMXBuffer&& source) noexcept {
mBufferType = std::move(source.mBufferType);
mRangeOffset = std::move(source.mRangeOffset);
mRangeLength = std::move(source.mRangeLength);
diff --git a/media/libmedia/include/media/NdkWrapper.h b/media/libmedia/include/media/NdkWrapper.h
index c97d171..191665a 100644
--- a/media/libmedia/include/media/NdkWrapper.h
+++ b/media/libmedia/include/media/NdkWrapper.h
@@ -287,8 +287,6 @@
status_t release();
- status_t disconnect();
-
status_t setDataSource(int fd, off64_t offset, off64_t length);
status_t setDataSource(const char *location);
diff --git a/media/libmedia/include/media/OMXBuffer.h b/media/libmedia/include/media/OMXBuffer.h
index 9c9f5e7..4abe9e6 100644
--- a/media/libmedia/include/media/OMXBuffer.h
+++ b/media/libmedia/include/media/OMXBuffer.h
@@ -137,7 +137,7 @@
hidl_memory mHidlMemory;
// Move assignment
- OMXBuffer &operator=(OMXBuffer&&);
+ OMXBuffer &operator=(OMXBuffer&&) noexcept;
// Deleted copy constructor and assignment.
OMXBuffer(const OMXBuffer&) = delete;
diff --git a/media/libmedia/mediarecorder.cpp b/media/libmedia/mediarecorder.cpp
index 721a043..92cfb1c 100644
--- a/media/libmedia/mediarecorder.cpp
+++ b/media/libmedia/mediarecorder.cpp
@@ -20,6 +20,7 @@
#include <inttypes.h>
+#include <android-base/macros.h>
#include <utils/Log.h>
#include <media/mediarecorder.h>
#include <binder/IServiceManager.h>
@@ -597,7 +598,8 @@
if (OK != ret) {
return ret; // No need to continue
}
- } // Intentional fall through
+ FALLTHROUGH_INTENDED;
+ }
case MEDIA_RECORDER_INITIALIZED:
ret = close();
break;
diff --git a/media/libmediaextractor/Android.bp b/media/libmediaextractor/Android.bp
index 0208ad4..cf7d74f 100644
--- a/media/libmediaextractor/Android.bp
+++ b/media/libmediaextractor/Android.bp
@@ -28,7 +28,6 @@
"MediaBufferBase.cpp",
"MediaBufferGroup.cpp",
"MediaSource.cpp",
- "MediaTrack.cpp",
"MetaData.cpp",
"MetaDataBase.cpp",
"VorbisComment.cpp",
diff --git a/media/libmediaextractor/MediaBufferGroup.cpp b/media/libmediaextractor/MediaBufferGroup.cpp
index 2a8dd41..62b83cc 100644
--- a/media/libmediaextractor/MediaBufferGroup.cpp
+++ b/media/libmediaextractor/MediaBufferGroup.cpp
@@ -157,11 +157,15 @@
Mutex::Autolock autoLock(mInternal->mLock);
for (;;) {
size_t smallest = requestedSize;
+ size_t biggest = requestedSize;
MediaBufferBase *buffer = nullptr;
auto free = mInternal->mBuffers.end();
for (auto it = mInternal->mBuffers.begin(); it != mInternal->mBuffers.end(); ++it) {
+ const size_t size = (*it)->size();
+ if (size > biggest) {
+ biggest = size;
+ }
if ((*it)->refcount() == 0) {
- const size_t size = (*it)->size();
if (size >= requestedSize) {
buffer = *it;
break;
@@ -176,7 +180,8 @@
&& (free != mInternal->mBuffers.end()
|| mInternal->mBuffers.size() < mInternal->mGrowthLimit)) {
// We alloc before we free so failure leaves group unchanged.
- const size_t allocateSize = requestedSize < SIZE_MAX / 3 * 2 /* NB: ordering */ ?
+ const size_t allocateSize = requestedSize == 0 ? biggest :
+ requestedSize < SIZE_MAX / 3 * 2 /* NB: ordering */ ?
requestedSize * 3 / 2 : requestedSize;
buffer = new MediaBuffer(allocateSize);
if (buffer->data() == nullptr) {
diff --git a/media/libmediaextractor/MediaTrack.cpp b/media/libmediaextractor/MediaTrack.cpp
deleted file mode 100644
index 4963f58..0000000
--- a/media/libmediaextractor/MediaTrack.cpp
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2009 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.
- */
-
-#include <media/MediaTrack.h>
-
-namespace android {
-
-MediaTrack::MediaTrack() {}
-
-MediaTrack::~MediaTrack() {}
-
-////////////////////////////////////////////////////////////////////////////////
-
-MediaTrack::ReadOptions::ReadOptions() {
- reset();
-}
-
-void MediaTrack::ReadOptions::reset() {
- mOptions = 0;
- mSeekTimeUs = 0;
- mNonBlocking = false;
-}
-
-void MediaTrack::ReadOptions::setNonBlocking() {
- mNonBlocking = true;
-}
-
-void MediaTrack::ReadOptions::clearNonBlocking() {
- mNonBlocking = false;
-}
-
-bool MediaTrack::ReadOptions::getNonBlocking() const {
- return mNonBlocking;
-}
-
-void MediaTrack::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
- mOptions |= kSeekTo_Option;
- mSeekTimeUs = time_us;
- mSeekMode = mode;
-}
-
-void MediaTrack::ReadOptions::clearSeekTo() {
- mOptions &= ~kSeekTo_Option;
- mSeekTimeUs = 0;
- mSeekMode = SEEK_CLOSEST_SYNC;
-}
-
-bool MediaTrack::ReadOptions::getSeekTo(
- int64_t *time_us, SeekMode *mode) const {
- *time_us = mSeekTimeUs;
- *mode = mSeekMode;
- return (mOptions & kSeekTo_Option) != 0;
-}
-
-} // namespace android
diff --git a/media/libmediaextractor/include/media/DataSourceBase.h b/media/libmediaextractor/include/media/DataSourceBase.h
index 51993da..af5b83d 100644
--- a/media/libmediaextractor/include/media/DataSourceBase.h
+++ b/media/libmediaextractor/include/media/DataSourceBase.h
@@ -66,6 +66,10 @@
virtual void close() {};
+ virtual status_t getAvailableSize(off64_t /*offset*/, off64_t * /*size*/) {
+ return -1;
+ }
+
protected:
virtual ~DataSourceBase() {}
diff --git a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
index 2e9aede..fa5c723 100644
--- a/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
+++ b/media/libmediaextractor/include/media/stagefright/MetaDataBase.h
@@ -68,7 +68,6 @@
kKeyOpusSeekPreRoll = 'ospr', // uint64_t (seek preroll in ns)
kKeyFlacMetadata = 'flMd', // raw data
kKeyVp9CodecPrivate = 'vp9p', // raw data (vp9 csd information)
- kKeyWantsNALFragments = 'NALf',
kKeyIsSyncFrame = 'sync', // int32_t (bool)
kKeyIsCodecConfig = 'conf', // int32_t (bool)
kKeyIsMuxerData = 'muxd', // int32_t (bool)
@@ -199,9 +198,6 @@
// MPEG user data offsets
kKeyMpegUserData = 'mpud', // size_t[]
- // Size of NALU length in mkv/mp4
- kKeyNalLengthSize = 'nals', // int32_t
-
// HDR related
kKeyHdrStaticInfo = 'hdrS', // HDRStaticInfo
diff --git a/media/libmediaplayer2/Android.bp b/media/libmediaplayer2/Android.bp
index 0672ca9..a26cc81 100644
--- a/media/libmediaplayer2/Android.bp
+++ b/media/libmediaplayer2/Android.bp
@@ -4,12 +4,10 @@
export_include_dirs: ["include"],
}
-cc_library {
+cc_library_static {
name: "libmediaplayer2",
srcs: [
- "JAudioTrack.cpp",
- "JavaVMHelper.cpp",
"MediaPlayer2AudioOutput.cpp",
"mediaplayer2.cpp",
],
@@ -22,14 +20,12 @@
"libgui",
"liblog",
"libmedia_omx",
- "libmedia_player2_util",
"libmediaextractor",
"libstagefright_foundation",
"libui",
"libutils",
"libcrypto",
- "libmediadrm",
"libmediametrics",
"libmediandk",
"libmediautils",
@@ -37,7 +33,6 @@
"libnativewindow",
"libpowermanager",
"libstagefright_httplive",
- "libstagefright_player2",
],
export_shared_lib_headers: [
@@ -57,8 +52,10 @@
static_libs: [
"libmedia_helper",
"libmediaplayer2-protos",
+ "libmedia_player2_util",
"libprotobuf-cpp-lite",
"libstagefright_nuplayer2",
+ "libstagefright_player2",
"libstagefright_rtsp",
"libstagefright_timedtext2",
],
@@ -84,3 +81,55 @@
},
},
}
+
+cc_library {
+ name: "libmedia2_jni_core",
+
+ srcs: [
+ "JavaVMHelper.cpp",
+ "JAudioTrack.cpp",
+ "JMedia2HTTPService.cpp",
+ "JMedia2HTTPConnection.cpp",
+ ],
+
+ shared_libs: [
+ "android.hidl.token@1.0-utils",
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libbinder",
+ "libstagefright_foundation",
+ "libmediaextractor",
+ "libdl",
+ "libaudioutils",
+ "libaudioclient",
+ "libnativehelper",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/libmedia/include",
+ "frameworks/base/core/jni",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
+ },
+
+}
diff --git a/media/libmediaplayer2/JMedia2HTTPConnection.cpp b/media/libmediaplayer2/JMedia2HTTPConnection.cpp
new file mode 100644
index 0000000..d264a7f
--- /dev/null
+++ b/media/libmediaplayer2/JMedia2HTTPConnection.cpp
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "JMedia2HTTPConnection"
+#include <utils/Log.h>
+
+#include <mediaplayer2/JavaVMHelper.h>
+#include <mediaplayer2/JMedia2HTTPConnection.h>
+#include <media/stagefright/foundation/ADebug.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+#include "log/log.h"
+#include "jni.h"
+#include <nativehelper/JNIHelp.h>
+
+namespace android {
+
+static const size_t kBufferSize = 32768;
+
+JMedia2HTTPConnection::JMedia2HTTPConnection(JNIEnv *env, jobject thiz) {
+ mMedia2HTTPConnectionObj = env->NewGlobalRef(thiz);
+ CHECK(mMedia2HTTPConnectionObj != NULL);
+
+ ScopedLocalRef<jclass> media2HTTPConnectionClass(
+ env, env->GetObjectClass(mMedia2HTTPConnectionObj));
+ CHECK(media2HTTPConnectionClass.get() != NULL);
+
+ mConnectMethod = env->GetMethodID(
+ media2HTTPConnectionClass.get(),
+ "connect",
+ "(Ljava/lang/String;Ljava/lang/String;)Z");
+ CHECK(mConnectMethod != NULL);
+
+ mDisconnectMethod = env->GetMethodID(
+ media2HTTPConnectionClass.get(),
+ "disconnect",
+ "()V");
+ CHECK(mDisconnectMethod != NULL);
+
+ mReadAtMethod = env->GetMethodID(
+ media2HTTPConnectionClass.get(),
+ "readAt",
+ "(J[BI)I");
+ CHECK(mReadAtMethod != NULL);
+
+ mGetSizeMethod = env->GetMethodID(
+ media2HTTPConnectionClass.get(),
+ "getSize",
+ "()J");
+ CHECK(mGetSizeMethod != NULL);
+
+ mGetMIMETypeMethod = env->GetMethodID(
+ media2HTTPConnectionClass.get(),
+ "getMIMEType",
+ "()Ljava/lang/String;");
+ CHECK(mGetMIMETypeMethod != NULL);
+
+ mGetUriMethod = env->GetMethodID(
+ media2HTTPConnectionClass.get(),
+ "getUri",
+ "()Ljava/lang/String;");
+ CHECK(mGetUriMethod != NULL);
+
+ ScopedLocalRef<jbyteArray> tmp(
+ env, env->NewByteArray(kBufferSize));
+ mByteArrayObj = (jbyteArray)env->NewGlobalRef(tmp.get());
+ CHECK(mByteArrayObj != NULL);
+}
+
+JMedia2HTTPConnection::~JMedia2HTTPConnection() {
+ JNIEnv *env = JavaVMHelper::getJNIEnv();
+ env->DeleteGlobalRef(mMedia2HTTPConnectionObj);
+ env->DeleteGlobalRef(mByteArrayObj);
+}
+
+bool JMedia2HTTPConnection::connect(
+ const char *uri, const KeyedVector<String8, String8> *headers) {
+ String8 tmp("");
+ if (headers != NULL) {
+ for (size_t i = 0; i < headers->size(); ++i) {
+ tmp.append(headers->keyAt(i));
+ tmp.append(String8(": "));
+ tmp.append(headers->valueAt(i));
+ tmp.append(String8("\r\n"));
+ }
+ }
+
+ JNIEnv* env = JavaVMHelper::getJNIEnv();
+ jstring juri = env->NewStringUTF(uri);
+ jstring jheaders = env->NewStringUTF(tmp.string());
+
+ jboolean ret =
+ env->CallBooleanMethod(mMedia2HTTPConnectionObj, mConnectMethod, juri, jheaders);
+
+ env->DeleteLocalRef(juri);
+ env->DeleteLocalRef(jheaders);
+
+ return (bool)ret;
+}
+
+void JMedia2HTTPConnection::disconnect() {
+ JNIEnv* env = JavaVMHelper::getJNIEnv();
+ env->CallVoidMethod(mMedia2HTTPConnectionObj, mDisconnectMethod);
+}
+
+ssize_t JMedia2HTTPConnection::readAt(off64_t offset, void *data, size_t size) {
+ JNIEnv* env = JavaVMHelper::getJNIEnv();
+
+ if (size > kBufferSize) {
+ size = kBufferSize;
+ }
+
+ jint n = env->CallIntMethod(
+ mMedia2HTTPConnectionObj, mReadAtMethod, (jlong)offset, mByteArrayObj, (jint)size);
+
+ if (n > 0) {
+ env->GetByteArrayRegion(
+ mByteArrayObj,
+ 0,
+ n,
+ (jbyte *)data);
+ }
+
+ return n;
+}
+
+off64_t JMedia2HTTPConnection::getSize() {
+ JNIEnv* env = JavaVMHelper::getJNIEnv();
+ return (off64_t)(env->CallLongMethod(mMedia2HTTPConnectionObj, mGetSizeMethod));
+}
+
+status_t JMedia2HTTPConnection::getMIMEType(String8 *mimeType) {
+ JNIEnv* env = JavaVMHelper::getJNIEnv();
+ jstring jmime = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetMIMETypeMethod);
+ jboolean flag = env->ExceptionCheck();
+ if (flag) {
+ env->ExceptionClear();
+ return UNKNOWN_ERROR;
+ }
+
+ const char *str = env->GetStringUTFChars(jmime, 0);
+ if (str != NULL) {
+ *mimeType = String8(str);
+ } else {
+ *mimeType = "application/octet-stream";
+ }
+ env->ReleaseStringUTFChars(jmime, str);
+ return OK;
+}
+
+status_t JMedia2HTTPConnection::getUri(String8 *uri) {
+ JNIEnv* env = JavaVMHelper::getJNIEnv();
+ jstring juri = (jstring)env->CallObjectMethod(mMedia2HTTPConnectionObj, mGetUriMethod);
+ jboolean flag = env->ExceptionCheck();
+ if (flag) {
+ env->ExceptionClear();
+ return UNKNOWN_ERROR;
+ }
+
+ const char *str = env->GetStringUTFChars(juri, 0);
+ *uri = String8(str);
+ env->ReleaseStringUTFChars(juri, str);
+ return OK;
+}
+
+} // namespace android
diff --git a/media/libmediaplayer2/JMedia2HTTPService.cpp b/media/libmediaplayer2/JMedia2HTTPService.cpp
new file mode 100644
index 0000000..264c15d
--- /dev/null
+++ b/media/libmediaplayer2/JMedia2HTTPService.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "JMedia2HTTPService"
+#include <utils/Log.h>
+
+#include <jni.h>
+
+#include <mediaplayer2/JavaVMHelper.h>
+#include <mediaplayer2/JMedia2HTTPService.h>
+#include <mediaplayer2/JMedia2HTTPConnection.h>
+#include <media/stagefright/foundation/ADebug.h>
+
+#include <nativehelper/JNIHelp.h>
+#include <nativehelper/ScopedLocalRef.h>
+
+namespace android {
+
+JMedia2HTTPService::JMedia2HTTPService(JNIEnv *env, jobject thiz) {
+ mMedia2HTTPServiceObj = env->NewGlobalRef(thiz);
+ CHECK(mMedia2HTTPServiceObj != NULL);
+
+ ScopedLocalRef<jclass> media2HTTPServiceClass(env, env->GetObjectClass(mMedia2HTTPServiceObj));
+ CHECK(media2HTTPServiceClass.get() != NULL);
+
+ mMakeHTTPConnectionMethod = env->GetMethodID(
+ media2HTTPServiceClass.get(),
+ "makeHTTPConnection",
+ "()Landroid/media/Media2HTTPConnection;");
+ CHECK(mMakeHTTPConnectionMethod != NULL);
+}
+
+JMedia2HTTPService::~JMedia2HTTPService() {
+ JNIEnv *env = JavaVMHelper::getJNIEnv();
+ env->DeleteGlobalRef(mMedia2HTTPServiceObj);
+}
+
+sp<MediaHTTPConnection> JMedia2HTTPService::makeHTTPConnection() {
+ JNIEnv* env = JavaVMHelper::getJNIEnv();
+ jobject media2HTTPConnectionObj =
+ env->CallObjectMethod(mMedia2HTTPServiceObj, mMakeHTTPConnectionMethod);
+
+ return new JMedia2HTTPConnection(env, media2HTTPConnectionObj);
+}
+
+} // namespace android
diff --git a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
index eba78ed..9dd5e4c 100644
--- a/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
+++ b/media/libmediaplayer2/MediaPlayer2AudioOutput.cpp
@@ -299,14 +299,14 @@
status_t MediaPlayer2AudioOutput::open(
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format, int bufferCount,
+ audio_format_t format,
AudioCallback cb, void *cookie,
audio_output_flags_t flags,
const audio_offload_info_t *offloadInfo,
bool doNotReconnect,
uint32_t suggestedFrameCount) {
- ALOGV("open(%u, %d, 0x%x, 0x%x, %d, %d 0x%x)", sampleRate, channelCount, channelMask,
- format, bufferCount, mSessionId, flags);
+ ALOGV("open(%u, %d, 0x%x, 0x%x, %d 0x%x)", sampleRate, channelCount, channelMask,
+ format, mSessionId, flags);
// offloading is only supported in callback mode for now.
// offloadInfo must be present if offload flag is set
@@ -316,36 +316,8 @@
}
// compute frame count for the AudioTrack internal buffer
- size_t frameCount;
- if ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) {
- frameCount = 0; // AudioTrack will get frame count from AudioFlinger
- } else {
- // try to estimate the buffer processing fetch size from AudioFlinger.
- // framesPerBuffer is approximate and generally correct, except when it's not :-).
- uint32_t afSampleRate;
- size_t afFrameCount;
- if (AudioSystem::getOutputFrameCount(&afFrameCount, mStreamType) != NO_ERROR) {
- return NO_INIT;
- }
- if (AudioSystem::getOutputSamplingRate(&afSampleRate, mStreamType) != NO_ERROR) {
- return NO_INIT;
- }
- const size_t framesPerBuffer =
- (unsigned long long)sampleRate * afFrameCount / afSampleRate;
-
- if (bufferCount == 0) {
- // use suggestedFrameCount
- bufferCount = (suggestedFrameCount + framesPerBuffer - 1) / framesPerBuffer;
- }
- // Check argument bufferCount against the mininum buffer count
- if (bufferCount != 0 && bufferCount < mMinBufferCount) {
- ALOGV("bufferCount (%d) increased to %d", bufferCount, mMinBufferCount);
- bufferCount = mMinBufferCount;
- }
- // if frameCount is 0, then AudioTrack will get frame count from AudioFlinger
- // which will be the minimum size permitted.
- frameCount = bufferCount * framesPerBuffer;
- }
+ const size_t frameCount =
+ ((flags & AUDIO_OUTPUT_FLAG_COMPRESS_OFFLOAD) != 0) ? 0 : suggestedFrameCount;
if (channelMask == CHANNEL_MASK_USE_CHANNEL_ORDER) {
channelMask = audio_channel_out_mask_from_count(channelCount);
diff --git a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h
new file mode 100644
index 0000000..15f7f83
--- /dev/null
+++ b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPConnection.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _J_MEDIA2_HTTP_CONNECTION_H_
+#define _J_MEDIA2_HTTP_CONNECTION_H_
+
+#include "jni.h"
+
+#include <media/MediaHTTPConnection.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct JMedia2HTTPConnection : public MediaHTTPConnection {
+ JMedia2HTTPConnection(JNIEnv *env, jobject thiz);
+
+ virtual bool connect(
+ const char *uri, const KeyedVector<String8, String8> *headers) override;
+
+ virtual void disconnect() override;
+ virtual ssize_t readAt(off64_t offset, void *data, size_t size) override;
+ virtual off64_t getSize() override;
+ virtual status_t getMIMEType(String8 *mimeType) override;
+ virtual status_t getUri(String8 *uri) override;
+
+protected:
+ virtual ~JMedia2HTTPConnection();
+
+private:
+ jobject mMedia2HTTPConnectionObj;
+ jmethodID mConnectMethod;
+ jmethodID mDisconnectMethod;
+ jmethodID mReadAtMethod;
+ jmethodID mGetSizeMethod;
+ jmethodID mGetMIMETypeMethod;
+ jmethodID mGetUriMethod;
+
+ jbyteArray mByteArrayObj;
+
+ DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPConnection);
+};
+
+} // namespace android
+
+#endif // _J_MEDIA2_HTTP_CONNECTION_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h
new file mode 100644
index 0000000..bf61a7f
--- /dev/null
+++ b/media/libmediaplayer2/include/mediaplayer2/JMedia2HTTPService.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2017, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _J_MEDIA2_HTTP_SERVICE_H_
+#define _J_MEDIA2_HTTP_SERVICE_H_
+
+#include <jni.h>
+#include <utils/RefBase.h>
+
+#include <media/MediaHTTPService.h>
+#include <media/MediaHTTPConnection.h>
+#include <media/stagefright/foundation/ABase.h>
+
+namespace android {
+
+struct JMedia2HTTPService : public MediaHTTPService {
+ JMedia2HTTPService(JNIEnv *env, jobject thiz);
+
+ virtual sp<MediaHTTPConnection> makeHTTPConnection() override;
+
+protected:
+ virtual ~JMedia2HTTPService();
+
+private:
+ jobject mMedia2HTTPServiceObj;
+
+ jmethodID mMakeHTTPConnectionMethod;
+
+ DISALLOW_EVIL_CONSTRUCTORS(JMedia2HTTPService);
+};
+
+} // namespace android
+
+#endif // _J_MEDIA2_HTTP_SERVICE_H_
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
index 5d5b8e4..ee67abf 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2AudioOutput.h
@@ -58,7 +58,7 @@
virtual status_t open(
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
- audio_format_t format, int bufferCount,
+ audio_format_t format,
AudioCallback cb, void *cookie,
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
const audio_offload_info_t *offloadInfo = NULL,
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
index 55d812b..846441e 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Interface.h
@@ -47,7 +47,6 @@
class Parcel;
struct ANativeWindowWrapper;
-#define DEFAULT_AUDIOSINK_BUFFERCOUNT 4
#define DEFAULT_AUDIOSINK_BUFFERSIZE 1200
#define DEFAULT_AUDIOSINK_SAMPLERATE 44100
@@ -103,7 +102,6 @@
virtual status_t open(
uint32_t sampleRate, int channelCount, audio_channel_mask_t channelMask,
audio_format_t format=AUDIO_FORMAT_PCM_16_BIT,
- int bufferCount=DEFAULT_AUDIOSINK_BUFFERCOUNT,
AudioCallback cb = NULL,
void *cookie = NULL,
audio_output_flags_t flags = AUDIO_OUTPUT_FLAG_NONE,
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
index 4b0a960..10e07ea 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
@@ -34,8 +34,7 @@
MEDIA2_SET_VIDEO_SIZE = 5,
MEDIA2_STARTED = 6,
MEDIA2_PAUSED = 7,
- MEDIA2_STOPPED = 8,
- MEDIA2_SKIPPED = 9,
+ MEDIA2_SKIPPED = 8,
MEDIA2_NOTIFY_TIME = 98,
MEDIA2_TIMED_TEXT = 99,
MEDIA2_ERROR = 100,
@@ -155,8 +154,8 @@
enum mediaplayer2_states {
MEDIAPLAYER2_STATE_IDLE = 1001,
MEDIAPLAYER2_STATE_PREPARED = 1002,
- MEDIAPLAYER2_STATE_PLAYING = 1003,
- MEDIAPLAYER2_STATE_PAUSED = 1004,
+ MEDIAPLAYER2_STATE_PAUSED = 1003,
+ MEDIAPLAYER2_STATE_PLAYING = 1004,
MEDIAPLAYER2_STATE_ERROR = 1005,
};
diff --git a/media/libmediaplayer2/mediaplayer2.cpp b/media/libmediaplayer2/mediaplayer2.cpp
index bafd32c..d9c9826 100644
--- a/media/libmediaplayer2/mediaplayer2.cpp
+++ b/media/libmediaplayer2/mediaplayer2.cpp
@@ -660,7 +660,7 @@
Mutex::Autolock _l(mLock);
if (mCurrentState & (MEDIA_PLAYER2_PAUSED|MEDIA_PLAYER2_PLAYBACK_COMPLETE))
return NO_ERROR;
- if ((mPlayer != 0) && (mCurrentState & MEDIA_PLAYER2_STARTED)) {
+ if ((mPlayer != 0) && (mCurrentState & (MEDIA_PLAYER2_STARTED | MEDIA_PLAYER2_PREPARED))) {
status_t ret = mPlayer->pause();
if (ret != NO_ERROR) {
mCurrentState = MEDIA_PLAYER2_STATE_ERROR;
diff --git a/media/libmediaplayer2/nuplayer2/Android.bp b/media/libmediaplayer2/nuplayer2/Android.bp
index 7cf4522..26da491 100644
--- a/media/libmediaplayer2/nuplayer2/Android.bp
+++ b/media/libmediaplayer2/nuplayer2/Android.bp
@@ -48,7 +48,6 @@
"libui",
"libgui",
"libmedia",
- "libmediadrm",
"libmediandk",
"libpowermanager",
],
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 2f90825..5bd1674 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -487,7 +487,7 @@
status_t NuPlayer2::setPlaybackSettings(const AudioPlaybackRate &rate) {
// do some cursory validation of the settings here. audio modes are
// only validated when set on the audiosink.
- if ((rate.mSpeed != 0.f && rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN)
+ if (rate.mSpeed < AUDIO_TIMESTRETCH_SPEED_MIN
|| rate.mSpeed > AUDIO_TIMESTRETCH_SPEED_MAX
|| rate.mPitch < AUDIO_TIMESTRETCH_SPEED_MIN
|| rate.mPitch > AUDIO_TIMESTRETCH_SPEED_MAX) {
@@ -969,7 +969,7 @@
onResume();
}
} else {
- onStart();
+ onStart(true /* play */);
}
mPausedByClient = false;
notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
@@ -986,8 +986,7 @@
if (mRenderer != NULL) {
// AudioSink allows only 1.f and 0.f for offload mode.
// For other speed, switch to non-offload mode.
- if (mOffloadAudio && ((rate.mSpeed != 0.f && rate.mSpeed != 1.f)
- || rate.mPitch != 1.f)) {
+ if (mOffloadAudio && (rate.mSpeed != 1.f || rate.mPitch != 1.f)) {
int64_t currentPositionUs;
if (getCurrentPosition(¤tPositionUs) != OK) {
currentPositionUs = mPreviousSeekTimeUs;
@@ -1010,36 +1009,15 @@
err = mRenderer->setPlaybackSettings(rate);
}
if (err == OK) {
- if (rate.mSpeed == 0.f) {
- onPause();
- notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
- mPausedByClient = true;
- // save all other settings (using non-paused speed)
- // so we can restore them on start
- AudioPlaybackRate newRate = rate;
- newRate.mSpeed = mPlaybackSettings.mSpeed;
- mPlaybackSettings = newRate;
- } else { /* rate.mSpeed != 0.f */
- mPlaybackSettings = rate;
- if (mStarted) {
- // do not resume yet if the source is still buffering
- if (!mPausedForBuffering) {
- onResume();
- }
- } else if (mPrepared) {
- onStart();
- }
+ mPlaybackSettings = rate;
- mPausedByClient = false;
+ if (mVideoDecoder != NULL) {
+ sp<AMessage> params = new AMessage();
+ params->setFloat("playback-speed", mPlaybackSettings.mSpeed);
+ mVideoDecoder->setParameters(params);
}
}
- if (mVideoDecoder != NULL) {
- sp<AMessage> params = new AMessage();
- params->setFloat("playback-speed", mPlaybackSettings.mSpeed);
- mVideoDecoder->setParameters(params);
- }
-
sp<AMessage> response = new AMessage;
response->setInt32("err", err);
response->postReply(replyID);
@@ -1059,9 +1037,6 @@
// get playback settings used by renderer, as it may be
// slightly off due to audiosink not taking small changes.
mPlaybackSettings = rate;
- if (mPaused) {
- rate.mSpeed = 0.f;
- }
}
sp<AMessage> response = new AMessage;
if (err == OK) {
@@ -1527,6 +1502,9 @@
case kWhatPause:
{
+ if (!mStarted) {
+ onStart(false /* play */);
+ }
onPause();
notifyListener(mSrcId, MEDIA2_PAUSED, 0, 0);
mPausedByClient = true;
@@ -1600,7 +1578,7 @@
startPlaybackTimer("onresume");
}
-void NuPlayer2::onStart() {
+void NuPlayer2::onStart(bool play) {
ALOGV("onStart: mCrypto: %p", mCrypto.get());
if (!mSourceStarted) {
@@ -1674,6 +1652,11 @@
mRenderer->setVideoFrameRate(rate);
}
+ // Renderer is created in paused state.
+ if (play) {
+ mRenderer->resume();
+ }
+
if (mVideoDecoder != NULL) {
mVideoDecoder->setRenderer(mRenderer);
}
@@ -2497,7 +2480,7 @@
mRenderer->resume();
}
- onStart();
+ onStart(true /* play */);
mPausedByClient = false;
notifyListener(mSrcId, MEDIA2_STARTED, 0, 0);
}
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.h b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
index 77845ac..e55cdbe 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.h
@@ -301,7 +301,7 @@
void handleFlushComplete(bool audio, bool isDecoder);
void finishFlushIfPossible();
- void onStart();
+ void onStart(bool play);
void onResume();
void onPause();
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index d3be53a..cb4b06d 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -327,9 +327,9 @@
switch (mState) {
case STATE_PAUSED:
- case STATE_PREPARED:
return OK;
+ case STATE_PREPARED:
case STATE_RUNNING:
mState = STATE_PAUSED;
mPlayer->pause();
@@ -352,14 +352,6 @@
// try to update position
int64_t unused;
getCurrentPosition(&unused);
- Mutex::Autolock autoLock(mLock);
- if (rate.mSpeed == 0.f && mState == STATE_RUNNING) {
- mState = STATE_PAUSED;
- } else if (rate.mSpeed != 0.f
- && (mState == STATE_PAUSED
- || mState == STATE_PREPARED)) {
- err = start_l();
- }
}
return err;
}
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
index 57d1147..f41a431 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Drm.cpp
@@ -147,9 +147,10 @@
}
uint32_t psshSize = pssh.tellp();
- const uint8_t* psshPtr = reinterpret_cast<const uint8_t*>(pssh.str().c_str());
- const char *psshHex = DrmUUID::arrayToHex(psshPtr, psshSize).string();
- ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO PSSH: size: %u %s", psshSize, psshHex);
+ std::string psshBase = pssh.str();
+ const auto* psshPtr = reinterpret_cast<const uint8_t*>(psshBase.c_str());
+ ALOGV("retrieveDrmInfo: MEDIA_DRM_INFO PSSH: size: %u %s", psshSize,
+ DrmUUID::arrayToHex(psshPtr, psshSize).string());
// 1) Write PSSH bytes
playerMsg->add_values()->set_bytes_value(
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
index a0bd900..452b781 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.cpp
@@ -115,7 +115,7 @@
mNotifyCompleteAudio(false),
mNotifyCompleteVideo(false),
mSyncQueues(false),
- mPaused(false),
+ mPaused(true),
mPauseDrainAudioAllowedUs(0),
mVideoSampleReceived(false),
mVideoRenderingStarted(false),
@@ -133,8 +133,7 @@
mUseAudioCallback(false),
mWakeLock(new JWakeLock()) {
CHECK(mediaClock != NULL);
- mPlaybackRate = mPlaybackSettings.mSpeed;
- mMediaClock->setPlaybackRate(mPlaybackRate);
+ mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
}
NuPlayer2::Renderer::~Renderer() {
@@ -190,26 +189,20 @@
}
status_t NuPlayer2::Renderer::onConfigPlayback(const AudioPlaybackRate &rate /* sanitized */) {
- if (rate.mSpeed == 0.f) {
- onPause();
- // don't call audiosink's setPlaybackRate if pausing, as pitch does not
- // have to correspond to the any non-0 speed (e.g old speed). Keep
- // settings nonetheless, using the old speed, in case audiosink changes.
- AudioPlaybackRate newRate = rate;
- newRate.mSpeed = mPlaybackSettings.mSpeed;
- mPlaybackSettings = newRate;
- return OK;
+ if (rate.mSpeed <= 0.f) {
+ ALOGW("playback rate cannot be %f", rate.mSpeed);
+ return BAD_VALUE;
}
if (mAudioSink != NULL && mAudioSink->ready()) {
status_t err = mAudioSink->setPlaybackRate(rate);
if (err != OK) {
+ ALOGW("failed to get playback rate from audio sink, err(%d)", err);
return err;
}
}
mPlaybackSettings = rate;
- mPlaybackRate = rate.mSpeed;
- mMediaClock->setPlaybackRate(mPlaybackRate);
+ mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
return OK;
}
@@ -236,9 +229,6 @@
// get playback settings used by audiosink, as it may be
// slightly off due to audiosink not taking small changes.
mPlaybackSettings = *rate;
- if (mPaused) {
- rate->mSpeed = 0.f;
- }
}
return err;
}
@@ -560,8 +550,8 @@
int64_t delayUs =
mAudioSink->msecsPerFrame()
* numFramesPendingPlayout * 1000ll;
- if (mPlaybackRate > 1.0f) {
- delayUs /= mPlaybackRate;
+ if (mPlaybackSettings.mSpeed > 1.0f) {
+ delayUs /= mPlaybackSettings.mSpeed;
}
// Let's give it more data after about half that time
@@ -1773,7 +1763,7 @@
mAudioSink->setPlaybackRate(mPlaybackSettings);
}
- mMediaClock->setPlaybackRate(mPlaybackRate);
+ mMediaClock->setPlaybackRate(mPlaybackSettings.mSpeed);
if (!mAudioQueue.empty()) {
postDrainAudioQueue_l();
@@ -1928,7 +1918,6 @@
numChannels,
(audio_channel_mask_t)channelMask,
audioFormat,
- 0 /* bufferCount - unused */,
&NuPlayer2::Renderer::AudioSinkCallback,
this,
(audio_output_flags_t)offloadFlags,
@@ -2014,7 +2003,6 @@
numChannels,
(audio_channel_mask_t)channelMask,
AUDIO_FORMAT_PCM_16_BIT,
- 0 /* bufferCount - unused */,
mUseAudioCallback ? &NuPlayer2::Renderer::AudioSinkCallback : NULL,
mUseAudioCallback ? this : NULL,
(audio_output_flags_t)pcmFlags,
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
index 62cf0d8..305af68 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Renderer.h
@@ -167,7 +167,6 @@
int32_t mAudioEOSGeneration;
const sp<MediaClock> mMediaClock;
- float mPlaybackRate; // audio track rate
AudioPlaybackRate mPlaybackSettings;
AVSyncSettings mSyncSettings;
diff --git a/media/libnblog/Android.bp b/media/libnblog/Android.bp
index 4a4aac1..1188320 100644
--- a/media/libnblog/Android.bp
+++ b/media/libnblog/Android.bp
@@ -3,9 +3,13 @@
name: "libnblog",
srcs: [
- "NBLog.cpp",
+ "Entry.cpp",
+ "Merger.cpp",
"PerformanceAnalysis.cpp",
+ "Reader.cpp",
"ReportPerformance.cpp",
+ "Timeline.cpp",
+ "Writer.cpp",
],
shared_libs: [
diff --git a/media/libnblog/Entry.cpp b/media/libnblog/Entry.cpp
new file mode 100644
index 0000000..e875639
--- /dev/null
+++ b/media/libnblog/Entry.cpp
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2018 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_TAG "NBLog"
+//#define LOG_NDEBUG 0
+
+#include <memory>
+#include <stddef.h>
+#include <stdint.h>
+
+#include <audio_utils/fifo.h>
+#include <media/nblog/Entry.h>
+#include <media/nblog/Events.h>
+#include <utils/Log.h>
+
+namespace android {
+namespace NBLog {
+
+int Entry::copyEntryDataAt(size_t offset) const
+{
+ // FIXME This is too slow
+ if (offset == 0) {
+ return mEvent;
+ } else if (offset == 1) {
+ return mLength;
+ } else if (offset < (size_t) (mLength + 2)) {
+ return (int) ((char *) mData)[offset - 2];
+ } else if (offset == (size_t) (mLength + 2)) {
+ return mLength;
+ } else {
+ return 0; // FIXME is this an error?
+ }
+}
+
+EntryIterator::EntryIterator() // Dummy initialization.
+ : mPtr(nullptr)
+{
+}
+
+EntryIterator::EntryIterator(const uint8_t *entry)
+ : mPtr(entry)
+{
+}
+
+EntryIterator::EntryIterator(const EntryIterator &other)
+ : mPtr(other.mPtr)
+{
+}
+
+const entry& EntryIterator::operator*() const
+{
+ return *(entry*) mPtr;
+}
+
+const entry* EntryIterator::operator->() const
+{
+ return (entry*) mPtr;
+}
+
+EntryIterator& EntryIterator::operator++()
+{
+ mPtr += mPtr[offsetof(entry, length)] + Entry::kOverhead;
+ return *this;
+}
+
+EntryIterator& EntryIterator::operator--()
+{
+ mPtr -= mPtr[Entry::kPreviousLengthOffset] + Entry::kOverhead;
+ return *this;
+}
+
+EntryIterator EntryIterator::next() const
+{
+ EntryIterator aux(*this);
+ return ++aux;
+}
+
+EntryIterator EntryIterator::prev() const
+{
+ EntryIterator aux(*this);
+ return --aux;
+}
+
+bool EntryIterator::operator!=(const EntryIterator &other) const
+{
+ return mPtr != other.mPtr;
+}
+
+int EntryIterator::operator-(const EntryIterator &other) const
+{
+ return mPtr - other.mPtr;
+}
+
+bool EntryIterator::hasConsistentLength() const
+{
+ return mPtr[offsetof(entry, length)] == mPtr[mPtr[offsetof(entry, length)] +
+ Entry::kOverhead + Entry::kPreviousLengthOffset];
+}
+
+void EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const
+{
+ size_t length = mPtr[offsetof(entry, length)] + Entry::kOverhead;
+ dst->write(mPtr, length);
+}
+
+void EntryIterator::copyData(uint8_t *dst) const
+{
+ memcpy((void*) dst, mPtr + offsetof(entry, data), mPtr[offsetof(entry, length)]);
+}
+
+// ---------------------------------------------------------------------------
+
+std::unique_ptr<AbstractEntry> AbstractEntry::buildEntry(const uint8_t *ptr)
+{
+ if (ptr == nullptr) {
+ return nullptr;
+ }
+ const uint8_t type = EntryIterator(ptr)->type;
+ switch (type) {
+ case EVENT_FMT_START:
+ return std::make_unique<FormatEntry>(FormatEntry(ptr));
+ case EVENT_AUDIO_STATE:
+ case EVENT_HISTOGRAM_ENTRY_TS:
+ return std::make_unique<HistogramEntry>(HistogramEntry(ptr));
+ default:
+ ALOGW("Tried to create AbstractEntry of type %d", type);
+ return nullptr;
+ }
+}
+
+EntryIterator FormatEntry::begin() const
+{
+ return EntryIterator(mEntry);
+}
+
+const char *FormatEntry::formatString() const
+{
+ return (const char*) mEntry + offsetof(entry, data);
+}
+
+size_t FormatEntry::formatStringLength() const
+{
+ return mEntry[offsetof(entry, length)];
+}
+
+EntryIterator FormatEntry::args() const
+{
+ auto it = begin();
+ ++it; // skip start fmt
+ ++it; // skip timestamp
+ ++it; // skip hash
+ // Skip author if present
+ if (it->type == EVENT_FMT_AUTHOR) {
+ ++it;
+ }
+ return it;
+}
+
+int64_t FormatEntry::timestamp() const
+{
+ auto it = begin();
+ ++it; // skip start fmt
+ return it.payload<int64_t>();
+}
+
+log_hash_t FormatEntry::hash() const
+{
+ auto it = begin();
+ ++it; // skip start fmt
+ ++it; // skip timestamp
+ // unaligned 64-bit read not supported
+ log_hash_t hash;
+ memcpy(&hash, it->data, sizeof(hash));
+ return hash;
+}
+
+int FormatEntry::author() const
+{
+ auto it = begin();
+ ++it; // skip start fmt
+ ++it; // skip timestamp
+ ++it; // skip hash
+ // if there is an author entry, return it, return -1 otherwise
+ return it->type == EVENT_FMT_AUTHOR ? it.payload<int>() : -1;
+}
+
+EntryIterator FormatEntry::copyWithAuthor(
+ std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const
+{
+ auto it = begin();
+ it.copyTo(dst); // copy fmt start entry
+ (++it).copyTo(dst); // copy timestamp
+ (++it).copyTo(dst); // copy hash
+ // insert author entry
+ size_t authorEntrySize = Entry::kOverhead + sizeof(author);
+ uint8_t authorEntry[authorEntrySize];
+ authorEntry[offsetof(entry, type)] = EVENT_FMT_AUTHOR;
+ authorEntry[offsetof(entry, length)] =
+ authorEntry[authorEntrySize + Entry::kPreviousLengthOffset] =
+ sizeof(author);
+ *(int*) (&authorEntry[offsetof(entry, data)]) = author;
+ dst->write(authorEntry, authorEntrySize);
+ // copy rest of entries
+ while ((++it)->type != EVENT_FMT_END) {
+ it.copyTo(dst);
+ }
+ it.copyTo(dst);
+ ++it;
+ return it;
+}
+
+int64_t HistogramEntry::timestamp() const
+{
+ return EntryIterator(mEntry).payload<HistTsEntry>().ts;
+}
+
+log_hash_t HistogramEntry::hash() const
+{
+ return EntryIterator(mEntry).payload<HistTsEntry>().hash;
+}
+
+int HistogramEntry::author() const
+{
+ EntryIterator it(mEntry);
+ return it->length == sizeof(HistTsEntryWithAuthor)
+ ? it.payload<HistTsEntryWithAuthor>().author : -1;
+}
+
+EntryIterator HistogramEntry::copyWithAuthor(
+ std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const
+{
+ // Current histogram entry has {type, length, struct HistTsEntry, length}.
+ // We now want {type, length, struct HistTsEntryWithAuthor, length}
+ uint8_t buffer[Entry::kOverhead + sizeof(HistTsEntryWithAuthor)];
+ // Copy content until the point we want to add the author
+ memcpy(buffer, mEntry, sizeof(entry) + sizeof(HistTsEntry));
+ // Copy the author
+ *(int*) (buffer + sizeof(entry) + sizeof(HistTsEntry)) = author;
+ // Update lengths
+ buffer[offsetof(entry, length)] = sizeof(HistTsEntryWithAuthor);
+ buffer[offsetof(entry, data) + sizeof(HistTsEntryWithAuthor) + offsetof(ending, length)]
+ = sizeof(HistTsEntryWithAuthor);
+ // Write new buffer into FIFO
+ dst->write(buffer, sizeof(buffer));
+ return EntryIterator(mEntry).next();
+}
+
+} // namespace NBLog
+} // namespace android
diff --git a/media/libnblog/Merger.cpp b/media/libnblog/Merger.cpp
new file mode 100644
index 0000000..3ad6d6b
--- /dev/null
+++ b/media/libnblog/Merger.cpp
@@ -0,0 +1,322 @@
+/*
+ * Copyright (C) 2018 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_TAG "NBLog"
+//#define LOG_NDEBUG 0
+
+#include <memory>
+#include <queue>
+#include <stddef.h>
+#include <stdint.h>
+#include <vector>
+
+#include <audio_utils/fifo.h>
+#include <json/json.h>
+#include <media/nblog/Merger.h>
+#include <media/nblog/PerformanceAnalysis.h>
+#include <media/nblog/ReportPerformance.h>
+#include <media/nblog/Reader.h>
+#include <media/nblog/Timeline.h>
+#include <utils/Condition.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/String16.h>
+#include <utils/String8.h>
+#include <utils/Thread.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
+namespace android {
+namespace NBLog {
+
+Merger::Merger(const void *shared, size_t size):
+ mShared((Shared *) shared),
+ mFifo(mShared != NULL ?
+ new audio_utils_fifo(size, sizeof(uint8_t),
+ mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
+ mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL)
+{
+}
+
+void Merger::addReader(const sp<Reader> &reader)
+{
+ // FIXME This is called by binder thread in MediaLogService::registerWriter
+ // but the access to shared variable mReaders is not yet protected by a lock.
+ mReaders.push_back(reader);
+}
+
+// items placed in priority queue during merge
+// composed by a timestamp and the index of the snapshot where the timestamp came from
+struct MergeItem
+{
+ int64_t ts;
+ int index;
+ MergeItem(int64_t ts, int index): ts(ts), index(index) {}
+};
+
+bool operator>(const struct MergeItem &i1, const struct MergeItem &i2)
+{
+ return i1.ts > i2.ts || (i1.ts == i2.ts && i1.index > i2.index);
+}
+
+// Merge registered readers, sorted by timestamp, and write data to a single FIFO in local memory
+void Merger::merge()
+{
+ if (true) return; // Merging is not necessary at the moment, so this is to disable it
+ // and bypass compiler warnings about member variables not being used.
+ const int nLogs = mReaders.size();
+ std::vector<std::unique_ptr<Snapshot>> snapshots(nLogs);
+ std::vector<EntryIterator> offsets;
+ offsets.reserve(nLogs);
+ for (int i = 0; i < nLogs; ++i) {
+ snapshots[i] = mReaders[i]->getSnapshot();
+ offsets.push_back(snapshots[i]->begin());
+ }
+ // initialize offsets
+ // TODO custom heap implementation could allow to update top, improving performance
+ // for bursty buffers
+ std::priority_queue<MergeItem, std::vector<MergeItem>, std::greater<MergeItem>> timestamps;
+ for (int i = 0; i < nLogs; ++i)
+ {
+ if (offsets[i] != snapshots[i]->end()) {
+ std::unique_ptr<AbstractEntry> abstractEntry = AbstractEntry::buildEntry(offsets[i]);
+ if (abstractEntry == nullptr) {
+ continue;
+ }
+ timestamps.emplace(abstractEntry->timestamp(), i);
+ }
+ }
+
+ while (!timestamps.empty()) {
+ int index = timestamps.top().index; // find minimum timestamp
+ // copy it to the log, increasing offset
+ offsets[index] = AbstractEntry::buildEntry(offsets[index])->
+ copyWithAuthor(mFifoWriter, index);
+ // update data structures
+ timestamps.pop();
+ if (offsets[index] != snapshots[index]->end()) {
+ int64_t ts = AbstractEntry::buildEntry(offsets[index])->timestamp();
+ timestamps.emplace(ts, index);
+ }
+ }
+}
+
+const std::vector<sp<Reader>>& Merger::getReaders() const
+{
+ //AutoMutex _l(mLock);
+ return mReaders;
+}
+
+// ---------------------------------------------------------------------------
+
+MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
+ : Reader(shared, size, "MergeReader"), mReaders(merger.getReaders())
+{
+}
+
+// Takes raw content of the local merger FIFO, processes log entries, and
+// writes the data to a map of class PerformanceAnalysis, based on their thread ID.
+void MergeReader::processSnapshot(Snapshot &snapshot, int author)
+{
+ ReportPerformance::PerformanceData& data = mThreadPerformanceData[author];
+ // We don't do "auto it" because it reduces readability in this case.
+ for (EntryIterator it = snapshot.begin(); it != snapshot.end(); ++it) {
+ switch (it->type) {
+ case EVENT_HISTOGRAM_ENTRY_TS: {
+ const HistTsEntry payload = it.payload<HistTsEntry>();
+ // TODO: hash for histogram ts and audio state need to match
+ // and correspond to audio production source file location
+ mThreadPerformanceAnalysis[author][0 /*hash*/].logTsEntry(payload.ts);
+ } break;
+ case EVENT_AUDIO_STATE: {
+ mThreadPerformanceAnalysis[author][0 /*hash*/].handleStateChange();
+ } break;
+ case EVENT_THREAD_INFO: {
+ const thread_info_t info = it.payload<thread_info_t>();
+ data.threadInfo = info;
+ } break;
+ case EVENT_THREAD_PARAMS: {
+ const thread_params_t params = it.payload<thread_params_t>();
+ data.threadParams = params;
+ } break;
+ case EVENT_LATENCY: {
+ const double latencyMs = it.payload<double>();
+ data.latencyHist.add(latencyMs);
+ } break;
+ case EVENT_WORK_TIME: {
+ const int64_t monotonicNs = it.payload<int64_t>();
+ const double monotonicMs = monotonicNs * 1e-6;
+ data.workHist.add(monotonicMs);
+ data.active += monotonicNs;
+ } break;
+ case EVENT_WARMUP_TIME: {
+ const double timeMs = it.payload<double>();
+ data.warmupHist.add(timeMs);
+ } break;
+ case EVENT_UNDERRUN: {
+ const int64_t ts = it.payload<int64_t>();
+ data.underruns++;
+ data.snapshots.emplace_front(EVENT_UNDERRUN, ts);
+ // TODO have a data structure to automatically handle resizing
+ if (data.snapshots.size() > ReportPerformance::PerformanceData::kMaxSnapshotsToStore) {
+ data.snapshots.pop_back();
+ }
+ } break;
+ case EVENT_OVERRUN: {
+ const int64_t ts = it.payload<int64_t>();
+ data.overruns++;
+ data.snapshots.emplace_front(EVENT_UNDERRUN, ts);
+ // TODO have a data structure to automatically handle resizing
+ if (data.snapshots.size() > ReportPerformance::PerformanceData::kMaxSnapshotsToStore) {
+ data.snapshots.pop_back();
+ }
+ } break;
+ case EVENT_RESERVED:
+ case EVENT_UPPER_BOUND:
+ ALOGW("warning: unexpected event %d", it->type);
+ break;
+ default:
+ break;
+ }
+ }
+}
+
+void MergeReader::getAndProcessSnapshot()
+{
+ // get a snapshot of each reader and process them
+ // TODO insert lock here
+ const size_t nLogs = mReaders.size();
+ std::vector<std::unique_ptr<Snapshot>> snapshots(nLogs);
+ for (size_t i = 0; i < nLogs; i++) {
+ snapshots[i] = mReaders[i]->getSnapshot();
+ }
+ // TODO unlock lock here
+ for (size_t i = 0; i < nLogs; i++) {
+ if (snapshots[i] != nullptr) {
+ processSnapshot(*(snapshots[i]), i);
+ }
+ }
+ checkPushToMediaMetrics();
+}
+
+void MergeReader::checkPushToMediaMetrics()
+{
+ const nsecs_t now = systemTime();
+ for (auto& item : mThreadPerformanceData) {
+ ReportPerformance::PerformanceData& data = item.second;
+ if (now - data.start >= kPeriodicMediaMetricsPush) {
+ (void)ReportPerformance::sendToMediaMetrics(data);
+ data.reset(); // data is persistent per thread
+ }
+ }
+}
+
+void MergeReader::dump(int fd, const Vector<String16>& args)
+{
+ // TODO: add a mutex around media.log dump
+ // Options for dumpsys
+ bool pa = false, json = false, plots = false, retro = false;
+ for (const auto &arg : args) {
+ if (arg == String16("--pa")) {
+ pa = true;
+ } else if (arg == String16("--json")) {
+ json = true;
+ } else if (arg == String16("--plots")) {
+ plots = true;
+ } else if (arg == String16("--retro")) {
+ retro = true;
+ }
+ }
+ if (pa) {
+ ReportPerformance::dump(fd, 0 /*indent*/, mThreadPerformanceAnalysis);
+ }
+ if (json) {
+ ReportPerformance::dumpJson(fd, mThreadPerformanceData);
+ }
+ if (plots) {
+ ReportPerformance::dumpPlots(fd, mThreadPerformanceData);
+ }
+ if (retro) {
+ ReportPerformance::dumpRetro(fd, mThreadPerformanceData);
+ }
+}
+
+void MergeReader::handleAuthor(const AbstractEntry &entry, String8 *body)
+{
+ int author = entry.author();
+ if (author == -1) {
+ return;
+ }
+ // FIXME Needs a lock
+ const char* name = mReaders[author]->name().c_str();
+ body->appendFormat("%s: ", name);
+}
+
+// ---------------------------------------------------------------------------
+
+MergeThread::MergeThread(Merger &merger, MergeReader &mergeReader)
+ : mMerger(merger),
+ mMergeReader(mergeReader),
+ mTimeoutUs(0)
+{
+}
+
+MergeThread::~MergeThread()
+{
+ // set exit flag, set timeout to 0 to force threadLoop to exit and wait for the thread to join
+ requestExit();
+ setTimeoutUs(0);
+ join();
+}
+
+bool MergeThread::threadLoop()
+{
+ bool doMerge;
+ {
+ AutoMutex _l(mMutex);
+ // If mTimeoutUs is negative, wait on the condition variable until it's positive.
+ // If it's positive, merge. The minimum period between waking the condition variable
+ // is handled in AudioFlinger::MediaLogNotifier::threadLoop().
+ mCond.wait(mMutex);
+ doMerge = mTimeoutUs > 0;
+ mTimeoutUs -= kThreadSleepPeriodUs;
+ }
+ if (doMerge) {
+ // Merge data from all the readers
+ mMerger.merge();
+ // Process the data collected by mMerger and write it to PerformanceAnalysis
+ // FIXME: decide whether to call getAndProcessSnapshot every time
+ // or whether to have a separate thread that calls it with a lower frequency
+ mMergeReader.getAndProcessSnapshot();
+ }
+ return true;
+}
+
+void MergeThread::wakeup()
+{
+ setTimeoutUs(kThreadWakeupPeriodUs);
+}
+
+void MergeThread::setTimeoutUs(int time)
+{
+ AutoMutex _l(mMutex);
+ mTimeoutUs = time;
+ mCond.signal();
+}
+
+} // namespace NBLog
+} // namespace android
diff --git a/media/libnblog/NBLog.cpp b/media/libnblog/NBLog.cpp
deleted file mode 100644
index aee0ea3..0000000
--- a/media/libnblog/NBLog.cpp
+++ /dev/null
@@ -1,1246 +0,0 @@
-/*
- * Copyright (C) 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_TAG "NBLog"
-
-#include <algorithm>
-#include <climits>
-#include <math.h>
-#include <memory>
-#include <unordered_set>
-#include <vector>
-#include <stdarg.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <string.h>
-#include <sys/prctl.h>
-#include <time.h>
-#include <new>
-#include <audio_utils/roundup.h>
-#include <json/json.h>
-#include <media/nblog/NBLog.h>
-#include <media/nblog/PerformanceAnalysis.h>
-#include <media/nblog/ReportPerformance.h>
-#include <utils/CallStack.h>
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <utils/Timers.h>
-
-#include <queue>
-#include <utility>
-
-namespace android {
-
-int NBLog::Entry::copyEntryDataAt(size_t offset) const
-{
- // FIXME This is too slow
- if (offset == 0)
- return mEvent;
- else if (offset == 1)
- return mLength;
- else if (offset < (size_t) (mLength + 2))
- return ((char *) mData)[offset - 2];
- else if (offset == (size_t) (mLength + 2))
- return mLength;
- else
- return 0;
-}
-
-// ---------------------------------------------------------------------------
-
-/*static*/
-std::unique_ptr<NBLog::AbstractEntry> NBLog::AbstractEntry::buildEntry(const uint8_t *ptr)
-{
- if (ptr == nullptr) {
- return nullptr;
- }
- const uint8_t type = EntryIterator(ptr)->type;
- switch (type) {
- case EVENT_FMT_START:
- return std::make_unique<FormatEntry>(FormatEntry(ptr));
- case EVENT_AUDIO_STATE:
- case EVENT_HISTOGRAM_ENTRY_TS:
- return std::make_unique<HistogramEntry>(HistogramEntry(ptr));
- default:
- ALOGW("Tried to create AbstractEntry of type %d", type);
- return nullptr;
- }
-}
-
-NBLog::AbstractEntry::AbstractEntry(const uint8_t *entry) : mEntry(entry)
-{
-}
-
-// ---------------------------------------------------------------------------
-
-NBLog::EntryIterator NBLog::FormatEntry::begin() const
-{
- return EntryIterator(mEntry);
-}
-
-const char *NBLog::FormatEntry::formatString() const
-{
- return (const char*) mEntry + offsetof(entry, data);
-}
-
-size_t NBLog::FormatEntry::formatStringLength() const
-{
- return mEntry[offsetof(entry, length)];
-}
-
-NBLog::EntryIterator NBLog::FormatEntry::args() const
-{
- auto it = begin();
- ++it; // skip start fmt
- ++it; // skip timestamp
- ++it; // skip hash
- // Skip author if present
- if (it->type == EVENT_FMT_AUTHOR) {
- ++it;
- }
- return it;
-}
-
-int64_t NBLog::FormatEntry::timestamp() const
-{
- auto it = begin();
- ++it; // skip start fmt
- return it.payload<int64_t>();
-}
-
-NBLog::log_hash_t NBLog::FormatEntry::hash() const
-{
- auto it = begin();
- ++it; // skip start fmt
- ++it; // skip timestamp
- // unaligned 64-bit read not supported
- log_hash_t hash;
- memcpy(&hash, it->data, sizeof(hash));
- return hash;
-}
-
-int NBLog::FormatEntry::author() const
-{
- auto it = begin();
- ++it; // skip start fmt
- ++it; // skip timestamp
- ++it; // skip hash
- // if there is an author entry, return it, return -1 otherwise
- return it->type == EVENT_FMT_AUTHOR ? it.payload<int>() : -1;
-}
-
-NBLog::EntryIterator NBLog::FormatEntry::copyWithAuthor(
- std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const
-{
- auto it = begin();
- it.copyTo(dst); // copy fmt start entry
- (++it).copyTo(dst); // copy timestamp
- (++it).copyTo(dst); // copy hash
- // insert author entry
- size_t authorEntrySize = Entry::kOverhead + sizeof(author);
- uint8_t authorEntry[authorEntrySize];
- authorEntry[offsetof(entry, type)] = EVENT_FMT_AUTHOR;
- authorEntry[offsetof(entry, length)] =
- authorEntry[authorEntrySize + Entry::kPreviousLengthOffset] =
- sizeof(author);
- *(int*) (&authorEntry[offsetof(entry, data)]) = author;
- dst->write(authorEntry, authorEntrySize);
- // copy rest of entries
- while ((++it)->type != EVENT_FMT_END) {
- it.copyTo(dst);
- }
- it.copyTo(dst);
- ++it;
- return it;
-}
-
-void NBLog::EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const
-{
- size_t length = mPtr[offsetof(entry, length)] + Entry::kOverhead;
- dst->write(mPtr, length);
-}
-
-void NBLog::EntryIterator::copyData(uint8_t *dst) const
-{
- memcpy((void*) dst, mPtr + offsetof(entry, data), mPtr[offsetof(entry, length)]);
-}
-
-NBLog::EntryIterator::EntryIterator() // Dummy initialization.
- : mPtr(nullptr)
-{
-}
-
-NBLog::EntryIterator::EntryIterator(const uint8_t *entry)
- : mPtr(entry)
-{
-}
-
-NBLog::EntryIterator::EntryIterator(const NBLog::EntryIterator &other)
- : mPtr(other.mPtr)
-{
-}
-
-const NBLog::entry& NBLog::EntryIterator::operator*() const
-{
- return *(entry*) mPtr;
-}
-
-const NBLog::entry* NBLog::EntryIterator::operator->() const
-{
- return (entry*) mPtr;
-}
-
-NBLog::EntryIterator& NBLog::EntryIterator::operator++()
-{
- mPtr += mPtr[offsetof(entry, length)] + Entry::kOverhead;
- return *this;
-}
-
-NBLog::EntryIterator& NBLog::EntryIterator::operator--()
-{
- mPtr -= mPtr[Entry::kPreviousLengthOffset] + Entry::kOverhead;
- return *this;
-}
-
-NBLog::EntryIterator NBLog::EntryIterator::next() const
-{
- EntryIterator aux(*this);
- return ++aux;
-}
-
-NBLog::EntryIterator NBLog::EntryIterator::prev() const
-{
- EntryIterator aux(*this);
- return --aux;
-}
-
-int NBLog::EntryIterator::operator-(const NBLog::EntryIterator &other) const
-{
- return mPtr - other.mPtr;
-}
-
-bool NBLog::EntryIterator::operator!=(const EntryIterator &other) const
-{
- return mPtr != other.mPtr;
-}
-
-bool NBLog::EntryIterator::hasConsistentLength() const
-{
- return mPtr[offsetof(entry, length)] == mPtr[mPtr[offsetof(entry, length)] +
- Entry::kOverhead + Entry::kPreviousLengthOffset];
-}
-
-// ---------------------------------------------------------------------------
-
-int64_t NBLog::HistogramEntry::timestamp() const
-{
- return EntryIterator(mEntry).payload<HistTsEntry>().ts;
-}
-
-NBLog::log_hash_t NBLog::HistogramEntry::hash() const
-{
- return EntryIterator(mEntry).payload<HistTsEntry>().hash;
-}
-
-int NBLog::HistogramEntry::author() const
-{
- EntryIterator it(mEntry);
- return it->length == sizeof(HistTsEntryWithAuthor)
- ? it.payload<HistTsEntryWithAuthor>().author : -1;
-}
-
-NBLog::EntryIterator NBLog::HistogramEntry::copyWithAuthor(
- std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const
-{
- // Current histogram entry has {type, length, struct HistTsEntry, length}.
- // We now want {type, length, struct HistTsEntryWithAuthor, length}
- uint8_t buffer[Entry::kOverhead + sizeof(HistTsEntryWithAuthor)];
- // Copy content until the point we want to add the author
- memcpy(buffer, mEntry, sizeof(entry) + sizeof(HistTsEntry));
- // Copy the author
- *(int*) (buffer + sizeof(entry) + sizeof(HistTsEntry)) = author;
- // Update lengths
- buffer[offsetof(entry, length)] = sizeof(HistTsEntryWithAuthor);
- buffer[offsetof(entry, data) + sizeof(HistTsEntryWithAuthor) + offsetof(ending, length)]
- = sizeof(HistTsEntryWithAuthor);
- // Write new buffer into FIFO
- dst->write(buffer, sizeof(buffer));
- return EntryIterator(mEntry).next();
-}
-
-// ---------------------------------------------------------------------------
-
-#if 0 // FIXME see note in NBLog.h
-NBLog::Timeline::Timeline(size_t size, void *shared)
- : mSize(roundup(size)), mOwn(shared == NULL),
- mShared((Shared *) (mOwn ? new char[sharedSize(size)] : shared))
-{
- new (mShared) Shared;
-}
-
-NBLog::Timeline::~Timeline()
-{
- mShared->~Shared();
- if (mOwn) {
- delete[] (char *) mShared;
- }
-}
-#endif
-
-/*static*/
-size_t NBLog::Timeline::sharedSize(size_t size)
-{
- // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
- return sizeof(Shared) + roundup(size);
-}
-
-// ---------------------------------------------------------------------------
-
-NBLog::Writer::Writer()
- : mShared(NULL), mFifo(NULL), mFifoWriter(NULL), mEnabled(false), mPidTag(NULL), mPidTagSize(0)
-{
-}
-
-NBLog::Writer::Writer(void *shared, size_t size)
- : mShared((Shared *) shared),
- mFifo(mShared != NULL ?
- new audio_utils_fifo(size, sizeof(uint8_t),
- mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
- mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL),
- mEnabled(mFifoWriter != NULL)
-{
- // caching pid and process name
- pid_t id = ::getpid();
- char procName[16];
- int status = prctl(PR_GET_NAME, procName);
- if (status) { // error getting process name
- procName[0] = '\0';
- }
- size_t length = strlen(procName);
- mPidTagSize = length + sizeof(pid_t);
- mPidTag = new char[mPidTagSize];
- memcpy(mPidTag, &id, sizeof(pid_t));
- memcpy(mPidTag + sizeof(pid_t), procName, length);
-}
-
-NBLog::Writer::Writer(const sp<IMemory>& iMemory, size_t size)
- : Writer(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
-{
- mIMemory = iMemory;
-}
-
-NBLog::Writer::~Writer()
-{
- delete mFifoWriter;
- delete mFifo;
- delete[] mPidTag;
-}
-
-void NBLog::Writer::log(const char *string)
-{
- if (!mEnabled) {
- return;
- }
- LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
- size_t length = strlen(string);
- if (length > Entry::kMaxLength) {
- length = Entry::kMaxLength;
- }
- log(EVENT_STRING, string, length);
-}
-
-void NBLog::Writer::logf(const char *fmt, ...)
-{
- if (!mEnabled) {
- return;
- }
- va_list ap;
- va_start(ap, fmt);
- Writer::logvf(fmt, ap); // the Writer:: is needed to avoid virtual dispatch for LockedWriter
- va_end(ap);
-}
-
-void NBLog::Writer::logvf(const char *fmt, va_list ap)
-{
- if (!mEnabled) {
- return;
- }
- char buffer[Entry::kMaxLength + 1 /*NUL*/];
- int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
- if (length >= (int) sizeof(buffer)) {
- length = sizeof(buffer) - 1;
- // NUL termination is not required
- // buffer[length] = '\0';
- }
- if (length >= 0) {
- log(EVENT_STRING, buffer, length);
- }
-}
-
-void NBLog::Writer::logTimestamp()
-{
- if (!mEnabled) {
- return;
- }
- struct timespec ts;
- if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
- log(EVENT_TIMESTAMP, &ts, sizeof(ts));
- }
-}
-
-void NBLog::Writer::logStart(const char *fmt)
-{
- if (!mEnabled) {
- return;
- }
- size_t length = strlen(fmt);
- if (length > Entry::kMaxLength) {
- length = Entry::kMaxLength;
- }
- log(EVENT_FMT_START, fmt, length);
-}
-
-void NBLog::Writer::logTimestampFormat()
-{
- if (!mEnabled) {
- return;
- }
- const nsecs_t ts = systemTime();
- if (ts > 0) {
- log(EVENT_FMT_TIMESTAMP, &ts, sizeof(ts));
- } else {
- ALOGE("Failed to get timestamp");
- }
-}
-
-void NBLog::Writer::logEventHistTs(Event event, log_hash_t hash)
-{
- if (!mEnabled) {
- return;
- }
- HistTsEntry data;
- data.hash = hash;
- data.ts = systemTime();
- if (data.ts > 0) {
- log(event, &data, sizeof(data));
- } else {
- ALOGE("Failed to get timestamp");
- }
-}
-
-void NBLog::Writer::logFormat(const char *fmt, log_hash_t hash, ...)
-{
- if (!mEnabled) {
- return;
- }
- va_list ap;
- va_start(ap, hash);
- Writer::logVFormat(fmt, hash, ap);
- va_end(ap);
-}
-
-void NBLog::Writer::logVFormat(const char *fmt, log_hash_t hash, va_list argp)
-{
- if (!mEnabled) {
- return;
- }
- Writer::logStart(fmt);
- int i;
- double d;
- float f;
- char* s;
- size_t length;
- int64_t t;
- Writer::logTimestampFormat();
- log(EVENT_FMT_HASH, &hash, sizeof(hash));
- for (const char *p = fmt; *p != '\0'; p++) {
- // TODO: implement more complex formatting such as %.3f
- if (*p != '%') {
- continue;
- }
- switch(*++p) {
- case 's': // string
- s = va_arg(argp, char *);
- length = strlen(s);
- if (length > Entry::kMaxLength) {
- length = Entry::kMaxLength;
- }
- log(EVENT_FMT_STRING, s, length);
- break;
-
- case 't': // timestamp
- t = va_arg(argp, int64_t);
- log(EVENT_FMT_TIMESTAMP, &t, sizeof(t));
- break;
-
- case 'd': // integer
- i = va_arg(argp, int);
- log(EVENT_FMT_INTEGER, &i, sizeof(i));
- break;
-
- case 'f': // float
- d = va_arg(argp, double); // float arguments are promoted to double in vararg lists
- f = (float)d;
- log(EVENT_FMT_FLOAT, &f, sizeof(f));
- break;
-
- case 'p': // pid
- log(EVENT_FMT_PID, mPidTag, mPidTagSize);
- break;
-
- // the "%\0" case finishes parsing
- case '\0':
- --p;
- break;
-
- case '%':
- break;
-
- default:
- ALOGW("NBLog Writer parsed invalid format specifier: %c", *p);
- break;
- }
- }
- Entry etr(EVENT_FMT_END, nullptr, 0);
- log(etr, true);
-}
-
-void NBLog::Writer::log(Event event, const void *data, size_t length)
-{
- if (!mEnabled) {
- return;
- }
- if (data == NULL || length > Entry::kMaxLength) {
- // TODO Perhaps it makes sense to display truncated data or at least a
- // message that the data is too long? The current behavior can create
- // a confusion for a programmer debugging their code.
- return;
- }
- // Ignore if invalid event
- if (event == EVENT_RESERVED || event >= EVENT_UPPER_BOUND) {
- return;
- }
- Entry etr(event, data, length);
- log(etr, true /*trusted*/);
-}
-
-void NBLog::Writer::log(const NBLog::Entry &etr, bool trusted)
-{
- if (!mEnabled) {
- return;
- }
- if (!trusted) {
- log(etr.mEvent, etr.mData, etr.mLength);
- return;
- }
- const size_t need = etr.mLength + Entry::kOverhead; // mEvent, mLength, data[mLength], mLength
- // need = number of bytes written to FIFO
-
- // FIXME optimize this using memcpy for the data part of the Entry.
- // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
- // checks size of a single log Entry: type, length, data pointer and ending
- uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
- // write this data to temp array
- for (size_t i = 0; i < need; i++) {
- temp[i] = etr.copyEntryDataAt(i);
- }
- // write to circular buffer
- mFifoWriter->write(temp, need);
-}
-
-bool NBLog::Writer::isEnabled() const
-{
- return mEnabled;
-}
-
-bool NBLog::Writer::setEnabled(bool enabled)
-{
- bool old = mEnabled;
- mEnabled = enabled && mShared != NULL;
- return old;
-}
-
-// ---------------------------------------------------------------------------
-
-NBLog::LockedWriter::LockedWriter()
- : Writer()
-{
-}
-
-NBLog::LockedWriter::LockedWriter(void *shared, size_t size)
- : Writer(shared, size)
-{
-}
-
-bool NBLog::LockedWriter::isEnabled() const
-{
- Mutex::Autolock _l(mLock);
- return Writer::isEnabled();
-}
-
-bool NBLog::LockedWriter::setEnabled(bool enabled)
-{
- Mutex::Autolock _l(mLock);
- return Writer::setEnabled(enabled);
-}
-
-void NBLog::LockedWriter::log(const Entry &entry, bool trusted) {
- Mutex::Autolock _l(mLock);
- Writer::log(entry, trusted);
-}
-
-// ---------------------------------------------------------------------------
-
-// We make a set of the invalid types rather than the valid types when aligning
-// Snapshot EntryIterators to valid entries during log corruption checking.
-// This is done in order to avoid the maintenance overhead of adding a new NBLog::Event
-// type to the two sets below whenever a new NBLog::Event type is created, as it is
-// very likely that new types added will be valid types.
-// Currently, invalidBeginTypes and invalidEndTypes are used to handle the special
-// case of a Format Entry, which consists of a variable number of simple log entries.
-// If a new NBLog::Event is added that consists of a variable number of simple log entries,
-// then these sets need to be updated.
-
-// We want the beginning of a Snapshot to point to an entry that is not in
-// the middle of a formatted entry and not an FMT_END.
-const std::unordered_set<NBLog::Event> NBLog::Reader::invalidBeginTypes {
- NBLog::Event::EVENT_FMT_TIMESTAMP,
- NBLog::Event::EVENT_FMT_HASH,
- NBLog::Event::EVENT_FMT_STRING,
- NBLog::Event::EVENT_FMT_INTEGER,
- NBLog::Event::EVENT_FMT_FLOAT,
- NBLog::Event::EVENT_FMT_PID,
- NBLog::Event::EVENT_FMT_AUTHOR,
- NBLog::Event::EVENT_FMT_END
-};
-
-// We want the end of a Snapshot to point to an entry that is not in
-// the middle of a formatted entry and not a FMT_START.
-const std::unordered_set<NBLog::Event> NBLog::Reader::invalidEndTypes {
- NBLog::Event::EVENT_FMT_START,
- NBLog::Event::EVENT_FMT_TIMESTAMP,
- NBLog::Event::EVENT_FMT_HASH,
- NBLog::Event::EVENT_FMT_STRING,
- NBLog::Event::EVENT_FMT_INTEGER,
- NBLog::Event::EVENT_FMT_FLOAT,
- NBLog::Event::EVENT_FMT_PID,
- NBLog::Event::EVENT_FMT_AUTHOR
-};
-
-NBLog::Reader::Reader(const void *shared, size_t size, const std::string &name)
- : mName(name),
- mShared((/*const*/ Shared *) shared), /*mIMemory*/
- mFifo(mShared != NULL ?
- new audio_utils_fifo(size, sizeof(uint8_t),
- mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
- mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
-{
-}
-
-NBLog::Reader::Reader(const sp<IMemory>& iMemory, size_t size, const std::string &name)
- : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size, name)
-{
- mIMemory = iMemory;
-}
-
-NBLog::Reader::~Reader()
-{
- delete mFifoReader;
- delete mFifo;
-}
-
-const uint8_t *NBLog::Reader::findLastValidEntry(const uint8_t *front, const uint8_t *back,
- const std::unordered_set<Event> &invalidTypes) {
- if (front == nullptr || back == nullptr) {
- return nullptr;
- }
- while (back + Entry::kPreviousLengthOffset >= front) {
- const uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
- const Event type = (const Event)prev[offsetof(entry, type)];
- if (prev < front
- || prev + prev[offsetof(entry, length)] + Entry::kOverhead != back
- || type <= NBLog::EVENT_RESERVED || type >= NBLog::EVENT_UPPER_BOUND) {
- // prev points to an out of limits or inconsistent entry
- return nullptr;
- }
- // if invalidTypes does not contain the type, then the type is valid.
- if (invalidTypes.find(type) == invalidTypes.end()) {
- return prev;
- }
- back = prev;
- }
- return nullptr; // no entry found
-}
-
-// Copies content of a Reader FIFO into its Snapshot
-// The Snapshot has the same raw data, but represented as a sequence of entries
-// and an EntryIterator making it possible to process the data.
-std::unique_ptr<NBLog::Snapshot> NBLog::Reader::getSnapshot()
-{
- if (mFifoReader == NULL) {
- return std::unique_ptr<Snapshot>(new Snapshot());
- }
-
- // This emulates the behaviour of audio_utils_fifo_reader::read, but without incrementing the
- // reader index. The index is incremented after handling corruption, to after the last complete
- // entry of the buffer
- size_t lost = 0;
- audio_utils_iovec iovec[2];
- const size_t capacity = mFifo->capacity();
- ssize_t availToRead;
- // A call to audio_utils_fifo_reader::obtain() places the read pointer one buffer length
- // before the writer's pointer (since mFifoReader was constructed with flush=false). The
- // do while loop is an attempt to read all of the FIFO's contents regardless of how behind
- // the reader is with respect to the writer. However, the following scheduling sequence is
- // possible and can lead to a starvation situation:
- // - Writer T1 writes, overrun with respect to Reader T2
- // - T2 calls obtain() and gets EOVERFLOW, T2 ptr placed one buffer size behind T1 ptr
- // - T1 write, overrun
- // - T2 obtain(), EOVERFLOW (and so on...)
- // To address this issue, we limit the number of tries for the reader to catch up with
- // the writer.
- int tries = 0;
- size_t lostTemp;
- do {
- availToRead = mFifoReader->obtain(iovec, capacity, NULL /*timeout*/, &lostTemp);
- lost += lostTemp;
- } while (availToRead < 0 || ++tries <= kMaxObtainTries);
-
- if (availToRead <= 0) {
- ALOGW_IF(availToRead < 0, "NBLog Reader %s failed to catch up with Writer", mName.c_str());
- return std::unique_ptr<Snapshot>(new Snapshot());
- }
-
- // Change to #if 1 for debugging. This statement is useful for checking buffer fullness levels
- // (as seen by reader) and how much data was lost. If you find that the fullness level is
- // getting close to full, or that data loss is happening to often, then you should
- // probably try some of the following:
- // - log less data
- // - log less often
- // - increase the initial shared memory allocation for the buffer
-#if 0
- ALOGD("getSnapshot name=%s, availToRead=%zd, capacity=%zu, fullness=%.3f, lost=%zu",
- name().c_str(), availToRead, capacity, (double)availToRead / (double)capacity, lost);
-#endif
- std::unique_ptr<Snapshot> snapshot(new Snapshot(availToRead));
- memcpy(snapshot->mData, (const char *) mFifo->buffer() + iovec[0].mOffset, iovec[0].mLength);
- if (iovec[1].mLength > 0) {
- memcpy(snapshot->mData + (iovec[0].mLength),
- (const char *) mFifo->buffer() + iovec[1].mOffset, iovec[1].mLength);
- }
-
- // Handle corrupted buffer
- // Potentially, a buffer has corrupted data on both beginning (due to overflow) and end
- // (due to incomplete format entry). But even if the end format entry is incomplete,
- // it ends in a complete entry (which is not an FMT_END). So is safe to traverse backwards.
- // TODO: handle client corruption (in the middle of a buffer)
-
- const uint8_t *back = snapshot->mData + availToRead;
- const uint8_t *front = snapshot->mData;
-
- // Find last FMT_END. <back> is sitting on an entry which might be the middle of a FormatEntry.
- // We go backwards until we find an EVENT_FMT_END.
- const uint8_t *lastEnd = findLastValidEntry(front, back, invalidEndTypes);
- if (lastEnd == nullptr) {
- snapshot->mEnd = snapshot->mBegin = EntryIterator(front);
- } else {
- // end of snapshot points to after last FMT_END entry
- snapshot->mEnd = EntryIterator(lastEnd).next();
- // find first FMT_START
- const uint8_t *firstStart = nullptr;
- const uint8_t *firstStartTmp = snapshot->mEnd;
- while ((firstStartTmp = findLastValidEntry(front, firstStartTmp, invalidBeginTypes))
- != nullptr) {
- firstStart = firstStartTmp;
- }
- // firstStart is null if no FMT_START entry was found before lastEnd
- if (firstStart == nullptr) {
- snapshot->mBegin = snapshot->mEnd;
- } else {
- snapshot->mBegin = EntryIterator(firstStart);
- }
- }
-
- // advance fifo reader index to after last entry read.
- mFifoReader->release(snapshot->mEnd - front);
-
- snapshot->mLost = lost;
- return snapshot;
-}
-
-// TODO separate this method from the rest of NBLog
-// Takes raw content of the local merger FIFO, processes log entries, and
-// writes the data to a map of class PerformanceAnalysis, based on their thread ID.
-void NBLog::MergeReader::processSnapshot(NBLog::Snapshot &snapshot, int author)
-{
- ReportPerformance::PerformanceData& data = mThreadPerformanceData[author];
- // We don't do "auto it" because it reduces readability in this case.
- for (EntryIterator it = snapshot.begin(); it != snapshot.end(); ++it) {
- switch (it->type) {
- case EVENT_HISTOGRAM_ENTRY_TS: {
- const HistTsEntry payload = it.payload<HistTsEntry>();
- // TODO: hash for histogram ts and audio state need to match
- // and correspond to audio production source file location
- mThreadPerformanceAnalysis[author][0 /*hash*/].logTsEntry(payload.ts);
- } break;
- case EVENT_AUDIO_STATE: {
- mThreadPerformanceAnalysis[author][0 /*hash*/].handleStateChange();
- } break;
- case EVENT_THREAD_INFO: {
- const thread_info_t info = it.payload<thread_info_t>();
- // TODO make PerformanceData hold a type of thread_info_t.
- // Currently, thread_info_t is defined in NBLog.h, which includes
- // PerformanceAnalysis.h. PerformanceData is defined in PerformanceAnalysis.h,
- // where including NBLog.h would result in circular includes. The organization
- // of files will need to change to avoid this problem.
- data.type = info.type;
- data.frameCount = info.frameCount;
- data.sampleRate = info.sampleRate;
- } break;
- case EVENT_LATENCY: {
- const double latencyMs = it.payload<double>();
- data.latencyHist.add(latencyMs);
- } break;
- case EVENT_WORK_TIME: {
- const int64_t monotonicNs = it.payload<int64_t>();
- const double monotonicMs = monotonicNs * 1e-6;
- data.workHist.add(monotonicMs);
- data.active += monotonicNs;
- } break;
- case EVENT_WARMUP_TIME: {
- const double timeMs = it.payload<double>();
- data.warmupHist.add(timeMs);
- } break;
- case EVENT_UNDERRUN:
- data.underruns++;
- break;
- case EVENT_OVERRUN:
- data.overruns++;
- break;
- case EVENT_RESERVED:
- case EVENT_UPPER_BOUND:
- ALOGW("warning: unexpected event %d", it->type);
- default:
- break;
- }
- }
-}
-
-void NBLog::MergeReader::getAndProcessSnapshot()
-{
- // get a snapshot of each reader and process them
- // TODO insert lock here
- const size_t nLogs = mReaders.size();
- std::vector<std::unique_ptr<Snapshot>> snapshots(nLogs);
- for (size_t i = 0; i < nLogs; i++) {
- snapshots[i] = mReaders[i]->getSnapshot();
- }
- // TODO unlock lock here
- for (size_t i = 0; i < nLogs; i++) {
- if (snapshots[i] != nullptr) {
- processSnapshot(*(snapshots[i]), i);
- }
- }
- checkPushToMediaMetrics();
-}
-
-void NBLog::MergeReader::checkPushToMediaMetrics()
-{
- const nsecs_t now = systemTime();
- for (auto& item : mThreadPerformanceData) {
- ReportPerformance::PerformanceData& data = item.second;
- if (now - data.start >= kPeriodicMediaMetricsPush) {
- (void)ReportPerformance::sendToMediaMetrics(data);
- data.reset(); // data is persistent per thread
- }
- }
-}
-
-void NBLog::MergeReader::dump(int fd, int indent)
-{
- // TODO: add a mutex around media.log dump
- ReportPerformance::dump(fd, indent, mThreadPerformanceAnalysis);
- Json::Value root(Json::arrayValue);
- for (const auto& item : mThreadPerformanceData) {
- const ReportPerformance::PerformanceData& data = item.second;
- std::unique_ptr<Json::Value> threadData = ReportPerformance::dumpToJson(data);
- if (threadData == nullptr) {
- continue;
- }
- (*threadData)["threadNum"] = item.first;
- root.append(*threadData);
- }
- Json::StyledWriter writer;
- std::string rootStr = writer.write(root);
- dprintf(fd, "%s", rootStr.c_str());
-}
-
-// TODO for future compatibility, would prefer to have a dump() go to string, and then go
-// to fd only when invoked through binder.
-void NBLog::DumpReader::dump(int fd, size_t indent)
-{
- if (fd < 0) return;
- std::unique_ptr<Snapshot> snapshot = getSnapshot();
- if (snapshot == nullptr) {
- return;
- }
- String8 timestamp, body;
-
- // TODO all logged types should have a printable format.
- for (EntryIterator it = snapshot->begin(); it != snapshot->end(); ++it) {
- switch (it->type) {
- case EVENT_FMT_START:
- it = handleFormat(FormatEntry(it), ×tamp, &body);
- break;
- case EVENT_WORK_TIME: {
- const int64_t monotonicNs = it.payload<int64_t>();
- body.appendFormat("Thread cycle: %ld ns", (long)monotonicNs);
- } break;
- case EVENT_LATENCY: {
- const double latencyMs = it.payload<double>();
- body.appendFormat("latency: %.3f ms", latencyMs);
- } break;
- case EVENT_WARMUP_TIME: {
- const double timeMs = it.payload<double>();
- body.appendFormat("warmup time: %.3f ms", timeMs);
- } break;
- case EVENT_UNDERRUN:
- body.appendFormat("underrun");
- break;
- case EVENT_OVERRUN:
- body.appendFormat("overrun");
- break;
- case EVENT_FMT_END:
- case EVENT_RESERVED:
- case EVENT_UPPER_BOUND:
- body.appendFormat("warning: unexpected event %d", it->type);
- default:
- break;
- }
- if (!body.isEmpty()) {
- dprintf(fd, "%.*s%s %s\n", (int)indent, "", timestamp.string(), body.string());
- body.clear();
- }
- timestamp.clear();
- }
-}
-
-bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
-{
- return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
-}
-
-void NBLog::DumpReader::appendTimestamp(String8 *body, const void *data)
-{
- if (body == nullptr || data == nullptr) {
- return;
- }
- int64_t ts;
- memcpy(&ts, data, sizeof(ts));
- body->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
- (int) ((ts / (1000 * 1000)) % 1000));
-}
-
-void NBLog::DumpReader::appendInt(String8 *body, const void *data)
-{
- if (body == nullptr || data == nullptr) {
- return;
- }
- int x = *((int*) data);
- body->appendFormat("<%d>", x);
-}
-
-void NBLog::DumpReader::appendFloat(String8 *body, const void *data)
-{
- if (body == nullptr || data == nullptr) {
- return;
- }
- float f;
- memcpy(&f, data, sizeof(f));
- body->appendFormat("<%f>", f);
-}
-
-void NBLog::DumpReader::appendPID(String8 *body, const void* data, size_t length)
-{
- if (body == nullptr || data == nullptr) {
- return;
- }
- pid_t id = *((pid_t*) data);
- char * name = &((char*) data)[sizeof(pid_t)];
- body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
-}
-
-String8 NBLog::DumpReader::bufferDump(const uint8_t *buffer, size_t size)
-{
- String8 str;
- if (buffer == nullptr) {
- return str;
- }
- str.append("[ ");
- for(size_t i = 0; i < size; i++) {
- str.appendFormat("%d ", buffer[i]);
- }
- str.append("]");
- return str;
-}
-
-String8 NBLog::DumpReader::bufferDump(const EntryIterator &it)
-{
- return bufferDump(it, it->length + Entry::kOverhead);
-}
-
-NBLog::EntryIterator NBLog::DumpReader::handleFormat(const FormatEntry &fmtEntry,
- String8 *timestamp,
- String8 *body)
-{
- // log timestamp
- const int64_t ts = fmtEntry.timestamp();
- timestamp->clear();
- timestamp->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
- (int) ((ts / (1000 * 1000)) % 1000));
-
- // log unique hash
- log_hash_t hash = fmtEntry.hash();
- // print only lower 16bit of hash as hex and line as int to reduce spam in the log
- body->appendFormat("%.4X-%d ", (int)(hash >> 16) & 0xFFFF, (int) hash & 0xFFFF);
-
- // log author (if present)
- handleAuthor(fmtEntry, body);
-
- // log string
- EntryIterator arg = fmtEntry.args();
-
- const char* fmt = fmtEntry.formatString();
- size_t fmt_length = fmtEntry.formatStringLength();
-
- for (size_t fmt_offset = 0; fmt_offset < fmt_length; ++fmt_offset) {
- if (fmt[fmt_offset] != '%') {
- body->append(&fmt[fmt_offset], 1); // TODO optimize to write consecutive strings at once
- continue;
- }
- // case "%%""
- if (fmt[++fmt_offset] == '%') {
- body->append("%");
- continue;
- }
- // case "%\0"
- if (fmt_offset == fmt_length) {
- continue;
- }
-
- NBLog::Event event = (NBLog::Event) arg->type;
- size_t length = arg->length;
-
- // TODO check length for event type is correct
-
- if (event == EVENT_FMT_END) {
- break;
- }
-
- // TODO: implement more complex formatting such as %.3f
- const uint8_t *datum = arg->data; // pointer to the current event args
- switch(fmt[fmt_offset])
- {
- case 's': // string
- ALOGW_IF(event != EVENT_FMT_STRING,
- "NBLog Reader incompatible event for string specifier: %d", event);
- body->append((const char*) datum, length);
- break;
-
- case 't': // timestamp
- ALOGW_IF(event != EVENT_FMT_TIMESTAMP,
- "NBLog Reader incompatible event for timestamp specifier: %d", event);
- appendTimestamp(body, datum);
- break;
-
- case 'd': // integer
- ALOGW_IF(event != EVENT_FMT_INTEGER,
- "NBLog Reader incompatible event for integer specifier: %d", event);
- appendInt(body, datum);
- break;
-
- case 'f': // float
- ALOGW_IF(event != EVENT_FMT_FLOAT,
- "NBLog Reader incompatible event for float specifier: %d", event);
- appendFloat(body, datum);
- break;
-
- case 'p': // pid
- ALOGW_IF(event != EVENT_FMT_PID,
- "NBLog Reader incompatible event for pid specifier: %d", event);
- appendPID(body, datum, length);
- break;
-
- default:
- ALOGW("NBLog Reader encountered unknown character %c", fmt[fmt_offset]);
- }
- ++arg;
- }
- ALOGW_IF(arg->type != EVENT_FMT_END, "Expected end of format, got %d", arg->type);
- return arg;
-}
-
-NBLog::Merger::Merger(const void *shared, size_t size):
- mShared((Shared *) shared),
- mFifo(mShared != NULL ?
- new audio_utils_fifo(size, sizeof(uint8_t),
- mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
- mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL)
-{
-}
-
-void NBLog::Merger::addReader(const sp<NBLog::Reader> &reader)
-{
- // FIXME This is called by binder thread in MediaLogService::registerWriter
- // but the access to shared variable mReaders is not yet protected by a lock.
- mReaders.push_back(reader);
-}
-
-// items placed in priority queue during merge
-// composed by a timestamp and the index of the snapshot where the timestamp came from
-struct MergeItem
-{
- int64_t ts;
- int index;
- MergeItem(int64_t ts, int index): ts(ts), index(index) {}
-};
-
-bool operator>(const struct MergeItem &i1, const struct MergeItem &i2)
-{
- return i1.ts > i2.ts || (i1.ts == i2.ts && i1.index > i2.index);
-}
-
-// Merge registered readers, sorted by timestamp, and write data to a single FIFO in local memory
-void NBLog::Merger::merge()
-{
- if (true) return; // Merging is not necessary at the moment, so this is to disable it
- // and bypass compiler warnings about member variables not being used.
- const int nLogs = mReaders.size();
- std::vector<std::unique_ptr<Snapshot>> snapshots(nLogs);
- std::vector<EntryIterator> offsets;
- offsets.reserve(nLogs);
- for (int i = 0; i < nLogs; ++i) {
- snapshots[i] = mReaders[i]->getSnapshot();
- offsets.push_back(snapshots[i]->begin());
- }
- // initialize offsets
- // TODO custom heap implementation could allow to update top, improving performance
- // for bursty buffers
- std::priority_queue<MergeItem, std::vector<MergeItem>, std::greater<MergeItem>> timestamps;
- for (int i = 0; i < nLogs; ++i)
- {
- if (offsets[i] != snapshots[i]->end()) {
- std::unique_ptr<AbstractEntry> abstractEntry = AbstractEntry::buildEntry(offsets[i]);
- if (abstractEntry == nullptr) {
- continue;
- }
- timestamps.emplace(abstractEntry->timestamp(), i);
- }
- }
-
- while (!timestamps.empty()) {
- int index = timestamps.top().index; // find minimum timestamp
- // copy it to the log, increasing offset
- offsets[index] = AbstractEntry::buildEntry(offsets[index])->
- copyWithAuthor(mFifoWriter, index);
- // update data structures
- timestamps.pop();
- if (offsets[index] != snapshots[index]->end()) {
- int64_t ts = AbstractEntry::buildEntry(offsets[index])->timestamp();
- timestamps.emplace(ts, index);
- }
- }
-}
-
-const std::vector<sp<NBLog::Reader>>& NBLog::Merger::getReaders() const
-{
- //AutoMutex _l(mLock);
- return mReaders;
-}
-
-// ---------------------------------------------------------------------------
-
-NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
- : Reader(shared, size, "MergeReader"), mReaders(merger.getReaders())
-{
-}
-
-void NBLog::MergeReader::handleAuthor(const NBLog::AbstractEntry &entry, String8 *body)
-{
- int author = entry.author();
- if (author == -1) {
- return;
- }
- // FIXME Needs a lock
- const char* name = mReaders[author]->name().c_str();
- body->appendFormat("%s: ", name);
-}
-
-// ---------------------------------------------------------------------------
-
-NBLog::MergeThread::MergeThread(NBLog::Merger &merger, NBLog::MergeReader &mergeReader)
- : mMerger(merger),
- mMergeReader(mergeReader),
- mTimeoutUs(0)
-{
-}
-
-NBLog::MergeThread::~MergeThread()
-{
- // set exit flag, set timeout to 0 to force threadLoop to exit and wait for the thread to join
- requestExit();
- setTimeoutUs(0);
- join();
-}
-
-bool NBLog::MergeThread::threadLoop()
-{
- bool doMerge;
- {
- AutoMutex _l(mMutex);
- // If mTimeoutUs is negative, wait on the condition variable until it's positive.
- // If it's positive, merge. The minimum period between waking the condition variable
- // is handled in AudioFlinger::MediaLogNotifier::threadLoop().
- mCond.wait(mMutex);
- doMerge = mTimeoutUs > 0;
- mTimeoutUs -= kThreadSleepPeriodUs;
- }
- if (doMerge) {
- // Merge data from all the readers
- mMerger.merge();
- // Process the data collected by mMerger and write it to PerformanceAnalysis
- // FIXME: decide whether to call getAndProcessSnapshot every time
- // or whether to have a separate thread that calls it with a lower frequency
- mMergeReader.getAndProcessSnapshot();
- }
- return true;
-}
-
-void NBLog::MergeThread::wakeup()
-{
- setTimeoutUs(kThreadWakeupPeriodUs);
-}
-
-void NBLog::MergeThread::setTimeoutUs(int time)
-{
- AutoMutex _l(mMutex);
- mTimeoutUs = time;
- mCond.signal();
-}
-
-} // namespace android
diff --git a/media/libnblog/PerformanceAnalysis.cpp b/media/libnblog/PerformanceAnalysis.cpp
index 94ad114..e91a511 100644
--- a/media/libnblog/PerformanceAnalysis.cpp
+++ b/media/libnblog/PerformanceAnalysis.cpp
@@ -22,6 +22,7 @@
#include <algorithm>
#include <climits>
#include <deque>
+#include <iomanip>
#include <math.h>
#include <numeric>
#include <sstream>
@@ -47,28 +48,25 @@
#include <utility>
namespace android {
-
namespace ReportPerformance {
void Histogram::add(double value)
{
- // TODO Handle domain and range error exceptions?
- const int binIndex = lround((value - mLow) / mBinSize);
- if (binIndex < 0) {
- mLowCount++;
- } else if (binIndex >= mNumBins) {
- mHighCount++;
- } else {
- mBins[binIndex]++;
+ if (mBinSize <= 0 || mBins.size() < 2) {
+ return;
}
+ // TODO Handle domain and range error exceptions?
+ const int unboundedIndex = lround((value - mLow) / mBinSize) + 1;
+ // std::clamp is introduced in C++17
+ //const int index = std::clamp(unboundedIndex, 0, (int)(mBins.size() - 1));
+ const int index = std::max(0, std::min((int)(mBins.size() - 1), unboundedIndex));
+ mBins[index]++;
mTotalCount++;
}
void Histogram::clear()
{
std::fill(mBins.begin(), mBins.end(), 0);
- mLowCount = 0;
- mHighCount = 0;
mTotalCount = 0;
}
@@ -82,31 +80,79 @@
static constexpr char kDivider = '|';
ss << kVersion << "," << mBinSize << "," << mNumBins << "," << mLow << ",{";
bool first = true;
- if (mLowCount != 0) {
- ss << "-1" << kDivider << mLowCount;
- first = false;
- }
- for (size_t i = 0; i < mNumBins; i++) {
+ for (size_t i = 0; i < mBins.size(); i++) {
if (mBins[i] != 0) {
if (!first) {
ss << ",";
}
- ss << i << kDivider << mBins[i];
+ ss << static_cast<int>(i) - 1 << kDivider << mBins[i];
first = false;
}
}
- if (mHighCount != 0) {
- if (!first) {
- ss << ",";
- }
- ss << mNumBins << kDivider << mHighCount;
- first = false;
- }
ss << "}";
return ss.str();
}
+std::string Histogram::asciiArtString(size_t indent) const {
+ if (totalCount() == 0 || mBinSize <= 0 || mBins.size() < 2) {
+ return "";
+ }
+
+ static constexpr char kMarker = '-';
+ // One increment is considered one step of a bin's height.
+ static constexpr size_t kMarkersPerIncrement = 2;
+ static constexpr size_t kMaxIncrements = 64 + 1;
+ static constexpr size_t kMaxNumberWidth = 7;
+ static const std::string kMarkers(kMarkersPerIncrement * kMaxIncrements, kMarker);
+ static const std::string kSpaces(kMarkersPerIncrement * kMaxIncrements, ' ');
+ // get the last n characters of s, or the whole string if it is shorter
+ auto getTail = [](const size_t n, const std::string &s) {
+ return s.c_str() + s.size() - std::min(n, s.size());
+ };
+
+ // Since totalCount() > 0, mBins is not empty and maxCount > 0.
+ const unsigned maxCount = *std::max_element(mBins.begin(), mBins.end());
+ const size_t maxIncrements = log2(maxCount) + 1;
+
+ std::stringstream ss;
+
+ // Non-zero bins must exist at this point because totalCount() > 0.
+ size_t firstNonZeroBin = 0;
+ // If firstNonZeroBin reaches mBins.size() - 1, then it must be a nonzero bin.
+ for (; firstNonZeroBin < mBins.size() - 1 && mBins[firstNonZeroBin] == 0; firstNonZeroBin++) {}
+ const size_t firstBinToPrint = firstNonZeroBin == 0 ? 0 : firstNonZeroBin - 1;
+
+ size_t lastNonZeroBin = mBins.size() - 1;
+ // If lastNonZeroBin reaches 0, then it must be a nonzero bin.
+ for (; lastNonZeroBin > 0 && mBins[lastNonZeroBin] == 0; lastNonZeroBin--) {}
+ const size_t lastBinToPrint = lastNonZeroBin == mBins.size() - 1 ? lastNonZeroBin
+ : lastNonZeroBin + 1;
+
+ for (size_t bin = firstBinToPrint; bin <= lastBinToPrint; bin++) {
+ ss << std::setw(indent + kMaxNumberWidth);
+ if (bin == 0) {
+ ss << "<";
+ } else if (bin == mBins.size() - 1) {
+ ss << ">";
+ } else {
+ ss << mLow + (bin - 1) * mBinSize;
+ }
+ ss << " |";
+ size_t increments = 0;
+ const uint64_t binCount = mBins[bin];
+ if (binCount > 0) {
+ increments = log2(binCount) + 1;
+ ss << getTail(increments * kMarkersPerIncrement, kMarkers);
+ }
+ ss << getTail((maxIncrements - increments + 1) * kMarkersPerIncrement, kSpaces)
+ << binCount << "\n";
+ }
+ ss << "\n";
+
+ return ss.str();
+}
+
//------------------------------------------------------------------------------
// Given an audio processing wakeup timestamp, buckets the time interval
@@ -367,5 +413,4 @@
}
} // namespace ReportPerformance
-
} // namespace android
diff --git a/media/libnblog/Reader.cpp b/media/libnblog/Reader.cpp
new file mode 100644
index 0000000..fd53090
--- /dev/null
+++ b/media/libnblog/Reader.cpp
@@ -0,0 +1,436 @@
+/*
+ * Copyright (C) 2018 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_TAG "NBLog"
+//#define LOG_NDEBUG 0
+
+#include <memory>
+#include <stddef.h>
+#include <string>
+#include <unordered_set>
+
+#include <audio_utils/fifo.h>
+#include <binder/IMemory.h>
+#include <media/nblog/Entry.h>
+#include <media/nblog/Events.h>
+#include <media/nblog/Reader.h>
+#include <media/nblog/Timeline.h>
+#include <utils/Log.h>
+#include <utils/String8.h>
+
+namespace android {
+namespace NBLog {
+
+Reader::Reader(const void *shared, size_t size, const std::string &name)
+ : mName(name),
+ mShared((/*const*/ Shared *) shared), /*mIMemory*/
+ mFifo(mShared != NULL ?
+ new audio_utils_fifo(size, sizeof(uint8_t),
+ mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
+ mFifoReader(mFifo != NULL ? new audio_utils_fifo_reader(*mFifo) : NULL)
+{
+}
+
+Reader::Reader(const sp<IMemory>& iMemory, size_t size, const std::string &name)
+ : Reader(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size, name)
+{
+ mIMemory = iMemory;
+}
+
+Reader::~Reader()
+{
+ delete mFifoReader;
+ delete mFifo;
+}
+
+// Copies content of a Reader FIFO into its Snapshot
+// The Snapshot has the same raw data, but represented as a sequence of entries
+// and an EntryIterator making it possible to process the data.
+std::unique_ptr<Snapshot> Reader::getSnapshot(bool flush)
+{
+ if (mFifoReader == NULL) {
+ return std::unique_ptr<Snapshot>(new Snapshot());
+ }
+
+ // This emulates the behaviour of audio_utils_fifo_reader::read, but without incrementing the
+ // reader index. The index is incremented after handling corruption, to after the last complete
+ // entry of the buffer
+ size_t lost = 0;
+ audio_utils_iovec iovec[2];
+ const size_t capacity = mFifo->capacity();
+ ssize_t availToRead;
+ // A call to audio_utils_fifo_reader::obtain() places the read pointer one buffer length
+ // before the writer's pointer (since mFifoReader was constructed with flush=false). The
+ // do while loop is an attempt to read all of the FIFO's contents regardless of how behind
+ // the reader is with respect to the writer. However, the following scheduling sequence is
+ // possible and can lead to a starvation situation:
+ // - Writer T1 writes, overrun with respect to Reader T2
+ // - T2 calls obtain() and gets EOVERFLOW, T2 ptr placed one buffer size behind T1 ptr
+ // - T1 write, overrun
+ // - T2 obtain(), EOVERFLOW (and so on...)
+ // To address this issue, we limit the number of tries for the reader to catch up with
+ // the writer.
+ int tries = 0;
+ size_t lostTemp;
+ do {
+ availToRead = mFifoReader->obtain(iovec, capacity, NULL /*timeout*/, &lostTemp);
+ lost += lostTemp;
+ } while (availToRead < 0 || ++tries <= kMaxObtainTries);
+
+ if (availToRead <= 0) {
+ ALOGW_IF(availToRead < 0, "NBLog Reader %s failed to catch up with Writer", mName.c_str());
+ return std::unique_ptr<Snapshot>(new Snapshot());
+ }
+
+ // Change to #if 1 for debugging. This statement is useful for checking buffer fullness levels
+ // (as seen by reader) and how much data was lost. If you find that the fullness level is
+ // getting close to full, or that data loss is happening to often, then you should
+ // probably try some of the following:
+ // - log less data
+ // - log less often
+ // - increase the initial shared memory allocation for the buffer
+#if 0
+ ALOGD("getSnapshot name=%s, availToRead=%zd, capacity=%zu, fullness=%.3f, lost=%zu",
+ name().c_str(), availToRead, capacity, (double)availToRead / (double)capacity, lost);
+#endif
+ std::unique_ptr<Snapshot> snapshot(new Snapshot(availToRead));
+ memcpy(snapshot->mData, (const char *) mFifo->buffer() + iovec[0].mOffset, iovec[0].mLength);
+ if (iovec[1].mLength > 0) {
+ memcpy(snapshot->mData + (iovec[0].mLength),
+ (const char *) mFifo->buffer() + iovec[1].mOffset, iovec[1].mLength);
+ }
+
+ // Handle corrupted buffer
+ // Potentially, a buffer has corrupted data on both beginning (due to overflow) and end
+ // (due to incomplete format entry). But even if the end format entry is incomplete,
+ // it ends in a complete entry (which is not an FMT_END). So is safe to traverse backwards.
+ // TODO: handle client corruption (in the middle of a buffer)
+
+ const uint8_t *back = snapshot->mData + availToRead;
+ const uint8_t *front = snapshot->mData;
+
+ // Find last FMT_END. <back> is sitting on an entry which might be the middle of a FormatEntry.
+ // We go backwards until we find an EVENT_FMT_END.
+ const uint8_t *lastEnd = findLastValidEntry(front, back, invalidEndTypes);
+ if (lastEnd == nullptr) {
+ snapshot->mEnd = snapshot->mBegin = EntryIterator(front);
+ } else {
+ // end of snapshot points to after last FMT_END entry
+ snapshot->mEnd = EntryIterator(lastEnd).next();
+ // find first FMT_START
+ const uint8_t *firstStart = nullptr;
+ const uint8_t *firstStartTmp = snapshot->mEnd;
+ while ((firstStartTmp = findLastValidEntry(front, firstStartTmp, invalidBeginTypes))
+ != nullptr) {
+ firstStart = firstStartTmp;
+ }
+ // firstStart is null if no FMT_START entry was found before lastEnd
+ if (firstStart == nullptr) {
+ snapshot->mBegin = snapshot->mEnd;
+ } else {
+ snapshot->mBegin = EntryIterator(firstStart);
+ }
+ }
+
+ // advance fifo reader index to after last entry read.
+ if (flush) {
+ mFifoReader->release(snapshot->mEnd - front);
+ }
+
+ snapshot->mLost = lost;
+ return snapshot;
+}
+
+bool Reader::isIMemory(const sp<IMemory>& iMemory) const
+{
+ return iMemory != 0 && mIMemory != 0 && iMemory->pointer() == mIMemory->pointer();
+}
+
+// We make a set of the invalid types rather than the valid types when aligning
+// Snapshot EntryIterators to valid entries during log corruption checking.
+// This is done in order to avoid the maintenance overhead of adding a new Event
+// type to the two sets below whenever a new Event type is created, as it is
+// very likely that new types added will be valid types.
+// Currently, invalidBeginTypes and invalidEndTypes are used to handle the special
+// case of a Format Entry, which consists of a variable number of simple log entries.
+// If a new Event is added that consists of a variable number of simple log entries,
+// then these sets need to be updated.
+
+// We want the beginning of a Snapshot to point to an entry that is not in
+// the middle of a formatted entry and not an FMT_END.
+const std::unordered_set<Event> Reader::invalidBeginTypes {
+ EVENT_FMT_AUTHOR,
+ EVENT_FMT_END,
+ EVENT_FMT_FLOAT,
+ EVENT_FMT_HASH,
+ EVENT_FMT_INTEGER,
+ EVENT_FMT_PID,
+ EVENT_FMT_STRING,
+ EVENT_FMT_TIMESTAMP,
+};
+
+// We want the end of a Snapshot to point to an entry that is not in
+// the middle of a formatted entry and not a FMT_START.
+const std::unordered_set<Event> Reader::invalidEndTypes {
+ EVENT_FMT_AUTHOR,
+ EVENT_FMT_FLOAT,
+ EVENT_FMT_HASH,
+ EVENT_FMT_INTEGER,
+ EVENT_FMT_PID,
+ EVENT_FMT_START,
+ EVENT_FMT_STRING,
+ EVENT_FMT_TIMESTAMP,
+};
+
+const uint8_t *Reader::findLastValidEntry(const uint8_t *front, const uint8_t *back,
+ const std::unordered_set<Event> &invalidTypes) {
+ if (front == nullptr || back == nullptr) {
+ return nullptr;
+ }
+ while (back + Entry::kPreviousLengthOffset >= front) {
+ const uint8_t *prev = back - back[Entry::kPreviousLengthOffset] - Entry::kOverhead;
+ const Event type = (const Event)prev[offsetof(entry, type)];
+ if (prev < front
+ || prev + prev[offsetof(entry, length)] + Entry::kOverhead != back
+ || type <= EVENT_RESERVED || type >= EVENT_UPPER_BOUND) {
+ // prev points to an out of limits or inconsistent entry
+ return nullptr;
+ }
+ // if invalidTypes does not contain the type, then the type is valid.
+ if (invalidTypes.find(type) == invalidTypes.end()) {
+ return prev;
+ }
+ back = prev;
+ }
+ return nullptr; // no entry found
+}
+
+// TODO for future compatibility, would prefer to have a dump() go to string, and then go
+// to fd only when invoked through binder.
+void DumpReader::dump(int fd, size_t indent)
+{
+ if (fd < 0) return;
+ std::unique_ptr<Snapshot> snapshot = getSnapshot(false /*flush*/);
+ if (snapshot == nullptr) {
+ return;
+ }
+ String8 timestamp, body;
+
+ // TODO all logged types should have a printable format.
+ // TODO can we make the printing generic?
+ for (EntryIterator it = snapshot->begin(); it != snapshot->end(); ++it) {
+ switch (it->type) {
+ case EVENT_FMT_START:
+ it = handleFormat(FormatEntry(it), ×tamp, &body);
+ break;
+ case EVENT_LATENCY: {
+ const double latencyMs = it.payload<double>();
+ body.appendFormat("EVENT_LATENCY,%.3f", latencyMs);
+ } break;
+ case EVENT_OVERRUN: {
+ const int64_t ts = it.payload<int64_t>();
+ body.appendFormat("EVENT_OVERRUN,%lld", static_cast<long long>(ts));
+ } break;
+ case EVENT_THREAD_INFO: {
+ const thread_info_t info = it.payload<thread_info_t>();
+ body.appendFormat("EVENT_THREAD_INFO,%d,%s", static_cast<int>(info.id),
+ threadTypeToString(info.type));
+ } break;
+ case EVENT_UNDERRUN: {
+ const int64_t ts = it.payload<int64_t>();
+ body.appendFormat("EVENT_UNDERRUN,%lld", static_cast<long long>(ts));
+ } break;
+ case EVENT_WARMUP_TIME: {
+ const double timeMs = it.payload<double>();
+ body.appendFormat("EVENT_WARMUP_TIME,%.3f", timeMs);
+ } break;
+ case EVENT_WORK_TIME: {
+ const int64_t monotonicNs = it.payload<int64_t>();
+ body.appendFormat("EVENT_WORK_TIME,%lld", static_cast<long long>(monotonicNs));
+ } break;
+ case EVENT_THREAD_PARAMS: {
+ const thread_params_t params = it.payload<thread_params_t>();
+ body.appendFormat("EVENT_THREAD_PARAMS,%zu,%u", params.frameCount, params.sampleRate);
+ } break;
+ case EVENT_FMT_END:
+ case EVENT_RESERVED:
+ case EVENT_UPPER_BOUND:
+ body.appendFormat("warning: unexpected event %d", it->type);
+ break;
+ default:
+ break;
+ }
+ if (!body.isEmpty()) {
+ dprintf(fd, "%.*s%s %s\n", (int)indent, "", timestamp.string(), body.string());
+ body.clear();
+ }
+ timestamp.clear();
+ }
+}
+
+EntryIterator DumpReader::handleFormat(const FormatEntry &fmtEntry,
+ String8 *timestamp, String8 *body)
+{
+ // log timestamp
+ const int64_t ts = fmtEntry.timestamp();
+ timestamp->clear();
+ timestamp->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
+ (int) ((ts / (1000 * 1000)) % 1000));
+
+ // log unique hash
+ log_hash_t hash = fmtEntry.hash();
+ // print only lower 16bit of hash as hex and line as int to reduce spam in the log
+ body->appendFormat("%.4X-%d ", (int)(hash >> 16) & 0xFFFF, (int) hash & 0xFFFF);
+
+ // log author (if present)
+ handleAuthor(fmtEntry, body);
+
+ // log string
+ EntryIterator arg = fmtEntry.args();
+
+ const char* fmt = fmtEntry.formatString();
+ size_t fmt_length = fmtEntry.formatStringLength();
+
+ for (size_t fmt_offset = 0; fmt_offset < fmt_length; ++fmt_offset) {
+ if (fmt[fmt_offset] != '%') {
+ body->append(&fmt[fmt_offset], 1); // TODO optimize to write consecutive strings at once
+ continue;
+ }
+ // case "%%""
+ if (fmt[++fmt_offset] == '%') {
+ body->append("%");
+ continue;
+ }
+ // case "%\0"
+ if (fmt_offset == fmt_length) {
+ continue;
+ }
+
+ Event event = (Event) arg->type;
+ size_t length = arg->length;
+
+ // TODO check length for event type is correct
+
+ if (event == EVENT_FMT_END) {
+ break;
+ }
+
+ // TODO: implement more complex formatting such as %.3f
+ const uint8_t *datum = arg->data; // pointer to the current event args
+ switch(fmt[fmt_offset])
+ {
+ case 's': // string
+ ALOGW_IF(event != EVENT_FMT_STRING,
+ "NBLog Reader incompatible event for string specifier: %d", event);
+ body->append((const char*) datum, length);
+ break;
+
+ case 't': // timestamp
+ ALOGW_IF(event != EVENT_FMT_TIMESTAMP,
+ "NBLog Reader incompatible event for timestamp specifier: %d", event);
+ appendTimestamp(body, datum);
+ break;
+
+ case 'd': // integer
+ ALOGW_IF(event != EVENT_FMT_INTEGER,
+ "NBLog Reader incompatible event for integer specifier: %d", event);
+ appendInt(body, datum);
+ break;
+
+ case 'f': // float
+ ALOGW_IF(event != EVENT_FMT_FLOAT,
+ "NBLog Reader incompatible event for float specifier: %d", event);
+ appendFloat(body, datum);
+ break;
+
+ case 'p': // pid
+ ALOGW_IF(event != EVENT_FMT_PID,
+ "NBLog Reader incompatible event for pid specifier: %d", event);
+ appendPID(body, datum, length);
+ break;
+
+ default:
+ ALOGW("NBLog Reader encountered unknown character %c", fmt[fmt_offset]);
+ }
+ ++arg;
+ }
+ ALOGW_IF(arg->type != EVENT_FMT_END, "Expected end of format, got %d", arg->type);
+ return arg;
+}
+
+void DumpReader::appendInt(String8 *body, const void *data)
+{
+ if (body == nullptr || data == nullptr) {
+ return;
+ }
+ //int x = *((int*) data);
+ int x;
+ memcpy(&x, data, sizeof(x));
+ body->appendFormat("<%d>", x);
+}
+
+void DumpReader::appendFloat(String8 *body, const void *data)
+{
+ if (body == nullptr || data == nullptr) {
+ return;
+ }
+ float f;
+ memcpy(&f, data, sizeof(f));
+ body->appendFormat("<%f>", f);
+}
+
+void DumpReader::appendPID(String8 *body, const void* data, size_t length)
+{
+ if (body == nullptr || data == nullptr) {
+ return;
+ }
+ pid_t id = *((pid_t*) data);
+ char * name = &((char*) data)[sizeof(pid_t)];
+ body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
+}
+
+void DumpReader::appendTimestamp(String8 *body, const void *data)
+{
+ if (body == nullptr || data == nullptr) {
+ return;
+ }
+ int64_t ts;
+ memcpy(&ts, data, sizeof(ts));
+ body->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
+ (int) ((ts / (1000 * 1000)) % 1000));
+}
+
+String8 DumpReader::bufferDump(const uint8_t *buffer, size_t size)
+{
+ String8 str;
+ if (buffer == nullptr) {
+ return str;
+ }
+ str.append("[ ");
+ for(size_t i = 0; i < size; i++) {
+ str.appendFormat("%d ", buffer[i]);
+ }
+ str.append("]");
+ return str;
+}
+
+String8 DumpReader::bufferDump(const EntryIterator &it)
+{
+ return bufferDump(it, it->length + Entry::kOverhead);
+}
+
+} // namespace NBLog
+} // namespace android
diff --git a/media/libnblog/ReportPerformance.cpp b/media/libnblog/ReportPerformance.cpp
index aab67c6..f632e40 100644
--- a/media/libnblog/ReportPerformance.cpp
+++ b/media/libnblog/ReportPerformance.cpp
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "ReportPerformance"
+//#define LOG_NDEBUG 0
#include <fstream>
#include <iostream>
@@ -30,23 +31,23 @@
#include <utility>
#include <json/json.h>
#include <media/MediaAnalyticsItem.h>
-#include <media/nblog/NBLog.h>
+#include <media/nblog/Events.h>
#include <media/nblog/PerformanceAnalysis.h>
#include <media/nblog/ReportPerformance.h>
#include <utils/Log.h>
#include <utils/String8.h>
namespace android {
-
namespace ReportPerformance {
-std::unique_ptr<Json::Value> dumpToJson(const PerformanceData& data)
+static std::unique_ptr<Json::Value> dumpToJson(const PerformanceData& data)
{
std::unique_ptr<Json::Value> rootPtr = std::make_unique<Json::Value>(Json::objectValue);
Json::Value& root = *rootPtr;
- root["type"] = data.type;
- root["frameCount"] = (Json::Value::Int)data.frameCount;
- root["sampleRate"] = (Json::Value::Int)data.sampleRate;
+ root["ioHandle"] = data.threadInfo.id;
+ root["type"] = NBLog::threadTypeToString(data.threadInfo.type);
+ root["frameCount"] = (Json::Value::Int)data.threadParams.frameCount;
+ root["sampleRate"] = (Json::Value::Int)data.threadParams.sampleRate;
root["workMsHist"] = data.workHist.toString();
root["latencyMsHist"] = data.latencyHist.toString();
root["warmupMsHist"] = data.warmupHist.toString();
@@ -57,6 +58,96 @@
return rootPtr;
}
+static std::string dumpHistogramsToString(const PerformanceData& data)
+{
+ std::stringstream ss;
+ ss << "==========================================\n";
+ ss << "Thread type=" << NBLog::threadTypeToString(data.threadInfo.type)
+ << " handle=" << data.threadInfo.id
+ << " sampleRate=" << data.threadParams.sampleRate
+ << " frameCount=" << data.threadParams.frameCount << "\n";
+ ss << " Thread work times in ms:\n" << data.workHist.asciiArtString(4 /*indent*/);
+ ss << " Thread latencies in ms:\n" << data.latencyHist.asciiArtString(4 /*indent*/);
+ ss << " Thread warmup times in ms:\n" << data.warmupHist.asciiArtString(4 /*indent*/);
+ return ss.str();
+}
+
+void dumpJson(int fd, const std::map<int, PerformanceData>& threadDataMap)
+{
+ if (fd < 0) {
+ return;
+ }
+
+ Json::Value root(Json::arrayValue);
+ for (const auto& item : threadDataMap) {
+ const ReportPerformance::PerformanceData& data = item.second;
+ // Skip threads that do not have performance data recorded yet.
+ if (data.empty()) {
+ continue;
+ }
+ std::unique_ptr<Json::Value> dataJson = ReportPerformance::dumpToJson(data);
+ if (dataJson == nullptr) {
+ continue;
+ }
+ (*dataJson)["threadNum"] = item.first;
+ root.append(*dataJson);
+ }
+ Json::StyledWriter writer;
+ std::string rootStr = writer.write(root);
+ write(fd, rootStr.c_str(), rootStr.size());
+}
+
+void dumpPlots(int fd, const std::map<int, PerformanceData>& threadDataMap)
+{
+ if (fd < 0) {
+ return;
+ }
+
+ for (const auto &item : threadDataMap) {
+ const ReportPerformance::PerformanceData& data = item.second;
+ if (data.empty()) {
+ continue;
+ }
+ std::string hists = ReportPerformance::dumpHistogramsToString(data);
+ write(fd, hists.c_str(), hists.size());
+ }
+}
+
+static std::string dumpRetroString(const PerformanceData& data, int64_t now)
+{
+ std::stringstream ss;
+ ss << NBLog::threadTypeToString(data.threadInfo.type) << "," << data.threadInfo.id << "\n";
+ for (const auto &item : data.snapshots) {
+ // TODO use an enum to string conversion method. One good idea:
+ // https://stackoverflow.com/a/238157
+ if (item.first == NBLog::EVENT_UNDERRUN) {
+ ss << "EVENT_UNDERRUN,";
+ } else if (item.first == NBLog::EVENT_OVERRUN) {
+ ss << "EVENT_OVERRUN,";
+ }
+ ss << now - item.second << "\n";
+ }
+ ss << "\n";
+ return ss.str();
+}
+
+void dumpRetro(int fd, const std::map<int, PerformanceData>& threadDataMap)
+{
+ if (fd < 0) {
+ return;
+ }
+
+ const nsecs_t now = systemTime();
+ for (const auto &item : threadDataMap) {
+ const ReportPerformance::PerformanceData& data = item.second;
+ if (data.snapshots.empty()) {
+ continue;
+ }
+ const std::string retroStr = dumpRetroString(data, now);
+ write(fd, retroStr.c_str(), retroStr.size());
+ }
+}
+
bool sendToMediaMetrics(const PerformanceData& data)
{
// See documentation for these metrics here:
@@ -72,6 +163,11 @@
static constexpr char kThreadActive[] = "android.media.audiothread.activeMs";
static constexpr char kThreadDuration[] = "android.media.audiothread.durationMs";
+ // Currently, we only allow FastMixer thread data to be sent to Media Metrics.
+ if (data.threadInfo.type != NBLog::FASTMIXER) {
+ return false;
+ }
+
std::unique_ptr<MediaAnalyticsItem> item(new MediaAnalyticsItem("audiothread"));
const Histogram &workHist = data.workHist;
@@ -102,15 +198,10 @@
// we want to send them only if there are performance metrics to send.
if (item->count() > 0) {
// Add thread info fields.
- const int type = data.type;
- // TODO have a int-to-string mapping defined somewhere else for other thread types.
- if (type == 2) {
- item->setCString(kThreadType, "FASTMIXER");
- } else {
- item->setCString(kThreadType, "UNKNOWN");
- }
- item->setInt32(kThreadFrameCount, data.frameCount);
- item->setInt32(kThreadSampleRate, data.sampleRate);
+ const char * const typeString = NBLog::threadTypeToString(data.threadInfo.type);
+ item->setCString(kThreadType, typeString);
+ item->setInt32(kThreadFrameCount, data.threadParams.frameCount);
+ item->setInt32(kThreadSampleRate, data.threadParams.sampleRate);
// Add time info fields.
item->setInt64(kThreadActive, data.active / 1000000);
item->setInt64(kThreadDuration, (systemTime() - data.start) / 1000000);
@@ -211,6 +302,5 @@
pfs.close();
}
-} // namespace ReportPerformance
-
+} // namespace ReportPerformance
} // namespace android
diff --git a/media/libnblog/Timeline.cpp b/media/libnblog/Timeline.cpp
new file mode 100644
index 0000000..c09b03b
--- /dev/null
+++ b/media/libnblog/Timeline.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <stddef.h>
+
+#include <audio_utils/roundup.h>
+#include <media/nblog/Timeline.h>
+
+namespace android {
+namespace NBLog {
+
+#if 0 // FIXME see note in Timeline.h
+NBLog::Timeline::Timeline(size_t size, void *shared)
+ : mSize(roundup(size)), mOwn(shared == NULL),
+ mShared((Shared *) (mOwn ? new char[sharedSize(size)] : shared))
+{
+ new (mShared) Shared;
+}
+
+NBLog::Timeline::~Timeline()
+{
+ mShared->~Shared();
+ if (mOwn) {
+ delete[] (char *) mShared;
+ }
+}
+#endif
+
+/*static*/
+size_t Timeline::sharedSize(size_t size)
+{
+ // TODO fifo now supports non-power-of-2 buffer sizes, so could remove the roundup
+ return sizeof(Shared) + roundup(size);
+}
+
+} // namespace NBLog
+} // namespace android
diff --git a/media/libnblog/Writer.cpp b/media/libnblog/Writer.cpp
new file mode 100644
index 0000000..da3bd52
--- /dev/null
+++ b/media/libnblog/Writer.cpp
@@ -0,0 +1,320 @@
+/*
+ * Copyright (C) 2018 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_TAG "NBLog"
+//#define LOG_NDEBUG 0
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <sys/prctl.h>
+
+#include <audio_utils/fifo.h>
+#include <binder/IMemory.h>
+#include <media/nblog/Entry.h>
+#include <media/nblog/Events.h>
+#include <media/nblog/Timeline.h>
+#include <media/nblog/Writer.h>
+#include <utils/Log.h>
+#include <utils/Mutex.h>
+
+namespace android {
+namespace NBLog {
+
+Writer::Writer(void *shared, size_t size)
+ : mShared((Shared *) shared),
+ mFifo(mShared != NULL ?
+ new audio_utils_fifo(size, sizeof(uint8_t),
+ mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
+ mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL),
+ mEnabled(mFifoWriter != NULL)
+{
+ // caching pid and process name
+ pid_t id = ::getpid();
+ char procName[16];
+ int status = prctl(PR_GET_NAME, procName);
+ if (status) { // error getting process name
+ procName[0] = '\0';
+ }
+ size_t length = strlen(procName);
+ mPidTagSize = length + sizeof(pid_t);
+ mPidTag = new char[mPidTagSize];
+ memcpy(mPidTag, &id, sizeof(pid_t));
+ memcpy(mPidTag + sizeof(pid_t), procName, length);
+}
+
+Writer::Writer(const sp<IMemory>& iMemory, size_t size)
+ : Writer(iMemory != 0 ? (Shared *) iMemory->pointer() : NULL, size)
+{
+ mIMemory = iMemory;
+}
+
+Writer::~Writer()
+{
+ delete mFifoWriter;
+ delete mFifo;
+ delete[] mPidTag;
+}
+
+void Writer::log(const char *string)
+{
+ if (!mEnabled) {
+ return;
+ }
+ LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
+ size_t length = strlen(string);
+ if (length > Entry::kMaxLength) {
+ length = Entry::kMaxLength;
+ }
+ log(EVENT_STRING, string, length);
+}
+
+void Writer::logf(const char *fmt, ...)
+{
+ if (!mEnabled) {
+ return;
+ }
+ va_list ap;
+ va_start(ap, fmt);
+ Writer::logvf(fmt, ap); // the Writer:: is needed to avoid virtual dispatch for LockedWriter
+ va_end(ap);
+}
+
+void Writer::logTimestamp()
+{
+ if (!mEnabled) {
+ return;
+ }
+ struct timespec ts;
+ if (!clock_gettime(CLOCK_MONOTONIC, &ts)) {
+ log(EVENT_TIMESTAMP, &ts, sizeof(ts));
+ }
+}
+
+void Writer::logFormat(const char *fmt, log_hash_t hash, ...)
+{
+ if (!mEnabled) {
+ return;
+ }
+ va_list ap;
+ va_start(ap, hash);
+ Writer::logVFormat(fmt, hash, ap);
+ va_end(ap);
+}
+
+void Writer::logEventHistTs(Event event, log_hash_t hash)
+{
+ if (!mEnabled) {
+ return;
+ }
+ HistTsEntry data;
+ data.hash = hash;
+ data.ts = systemTime();
+ if (data.ts > 0) {
+ log(event, &data, sizeof(data));
+ } else {
+ ALOGE("Failed to get timestamp");
+ }
+}
+
+bool Writer::isEnabled() const
+{
+ return mEnabled;
+}
+
+bool Writer::setEnabled(bool enabled)
+{
+ bool old = mEnabled;
+ mEnabled = enabled && mShared != NULL;
+ return old;
+}
+
+void Writer::log(const Entry &etr, bool trusted)
+{
+ if (!mEnabled) {
+ return;
+ }
+ if (!trusted) {
+ log(etr.mEvent, etr.mData, etr.mLength);
+ return;
+ }
+ const size_t need = etr.mLength + Entry::kOverhead; // mEvent, mLength, data[mLength], mLength
+ // need = number of bytes written to FIFO
+
+ // FIXME optimize this using memcpy for the data part of the Entry.
+ // The Entry could have a method copyTo(ptr, offset, size) to optimize the copy.
+ // checks size of a single log Entry: type, length, data pointer and ending
+ uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
+ // write this data to temp array
+ for (size_t i = 0; i < need; i++) {
+ temp[i] = etr.copyEntryDataAt(i);
+ }
+ // write to circular buffer
+ mFifoWriter->write(temp, need);
+}
+
+void Writer::log(Event event, const void *data, size_t length)
+{
+ if (!mEnabled) {
+ return;
+ }
+ if (data == NULL || length > Entry::kMaxLength) {
+ // TODO Perhaps it makes sense to display truncated data or at least a
+ // message that the data is too long? The current behavior can create
+ // a confusion for a programmer debugging their code.
+ return;
+ }
+ // Ignore if invalid event
+ if (event == EVENT_RESERVED || event >= EVENT_UPPER_BOUND) {
+ return;
+ }
+ Entry etr(event, data, length);
+ log(etr, true /*trusted*/);
+}
+
+void Writer::logvf(const char *fmt, va_list ap)
+{
+ if (!mEnabled) {
+ return;
+ }
+ char buffer[Entry::kMaxLength + 1 /*NUL*/];
+ int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
+ if (length >= (int) sizeof(buffer)) {
+ length = sizeof(buffer) - 1;
+ // NUL termination is not required
+ // buffer[length] = '\0';
+ }
+ if (length >= 0) {
+ log(EVENT_STRING, buffer, length);
+ }
+}
+
+void Writer::logStart(const char *fmt)
+{
+ if (!mEnabled) {
+ return;
+ }
+ size_t length = strlen(fmt);
+ if (length > Entry::kMaxLength) {
+ length = Entry::kMaxLength;
+ }
+ log(EVENT_FMT_START, fmt, length);
+}
+
+void Writer::logTimestampFormat()
+{
+ if (!mEnabled) {
+ return;
+ }
+ const nsecs_t ts = systemTime();
+ if (ts > 0) {
+ log(EVENT_FMT_TIMESTAMP, &ts, sizeof(ts));
+ } else {
+ ALOGE("Failed to get timestamp");
+ }
+}
+
+void Writer::logVFormat(const char *fmt, log_hash_t hash, va_list argp)
+{
+ if (!mEnabled) {
+ return;
+ }
+ Writer::logStart(fmt);
+ int i;
+ double d;
+ float f;
+ char* s;
+ size_t length;
+ int64_t t;
+ Writer::logTimestampFormat();
+ log(EVENT_FMT_HASH, &hash, sizeof(hash));
+ for (const char *p = fmt; *p != '\0'; p++) {
+ // TODO: implement more complex formatting such as %.3f
+ if (*p != '%') {
+ continue;
+ }
+ switch(*++p) {
+ case 's': // string
+ s = va_arg(argp, char *);
+ length = strlen(s);
+ if (length > Entry::kMaxLength) {
+ length = Entry::kMaxLength;
+ }
+ log(EVENT_FMT_STRING, s, length);
+ break;
+
+ case 't': // timestamp
+ t = va_arg(argp, int64_t);
+ log(EVENT_FMT_TIMESTAMP, &t, sizeof(t));
+ break;
+
+ case 'd': // integer
+ i = va_arg(argp, int);
+ log(EVENT_FMT_INTEGER, &i, sizeof(i));
+ break;
+
+ case 'f': // float
+ d = va_arg(argp, double); // float arguments are promoted to double in vararg lists
+ f = (float)d;
+ log(EVENT_FMT_FLOAT, &f, sizeof(f));
+ break;
+
+ case 'p': // pid
+ log(EVENT_FMT_PID, mPidTag, mPidTagSize);
+ break;
+
+ // the "%\0" case finishes parsing
+ case '\0':
+ --p;
+ break;
+
+ case '%':
+ break;
+
+ default:
+ ALOGW("NBLog Writer parsed invalid format specifier: %c", *p);
+ break;
+ }
+ }
+ Entry etr(EVENT_FMT_END, nullptr, 0);
+ log(etr, true);
+}
+
+// ---------------------------------------------------------------------------
+
+LockedWriter::LockedWriter(void *shared, size_t size)
+ : Writer(shared, size)
+{
+}
+
+bool LockedWriter::isEnabled() const
+{
+ Mutex::Autolock _l(mLock);
+ return Writer::isEnabled();
+}
+
+bool LockedWriter::setEnabled(bool enabled)
+{
+ Mutex::Autolock _l(mLock);
+ return Writer::setEnabled(enabled);
+}
+
+void LockedWriter::log(const Entry &entry, bool trusted) {
+ Mutex::Autolock _l(mLock);
+ Writer::log(entry, trusted);
+}
+
+} // namespace NBLog
+} // namespace android
diff --git a/media/libnblog/include/media/nblog/Entry.h b/media/libnblog/include/media/nblog/Entry.h
new file mode 100644
index 0000000..53f00b6
--- /dev/null
+++ b/media/libnblog/include/media/nblog/Entry.h
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_NBLOG_ENTRY_H
+#define ANDROID_MEDIA_NBLOG_ENTRY_H
+
+#include <memory>
+#include <stddef.h>
+#include <stdint.h>
+#include <type_traits>
+
+#include <media/nblog/Events.h>
+
+class audio_utils_fifo_writer;
+
+namespace android {
+namespace NBLog {
+
+// entry representation in memory
+struct entry {
+ const uint8_t type;
+ const uint8_t length;
+ const uint8_t data[0];
+};
+
+// entry tail representation (after data)
+struct ending {
+ uint8_t length;
+ uint8_t next[0];
+};
+
+// representation of a single log entry in shared memory
+// byte[0] mEvent
+// byte[1] mLength
+// byte[2] mData[0]
+// ...
+// byte[2+i] mData[i]
+// ...
+// byte[2+mLength-1] mData[mLength-1]
+// byte[2+mLength] duplicate copy of mLength to permit reverse scan
+// byte[3+mLength] start of next log entry
+class Entry {
+public:
+ Entry(Event event, const void *data, size_t length)
+ : mEvent(event), mLength(length), mData(data) {}
+ ~Entry() {}
+
+ // used during writing to format Entry information as follows:
+ // [type][length][data ... ][length]
+ int copyEntryDataAt(size_t offset) const;
+
+private:
+ friend class Writer;
+ Event mEvent; // event type
+ uint8_t mLength; // length of additional data, 0 <= mLength <= kMaxLength
+ const void *mData; // event type-specific data
+ static const size_t kMaxLength = 255;
+public:
+ // mEvent, mLength, mData[...], duplicate mLength
+ static const size_t kOverhead = sizeof(entry) + sizeof(ending);
+ // endind length of previous entry
+ static const ssize_t kPreviousLengthOffset = - sizeof(ending) +
+ offsetof(ending, length);
+};
+
+// entry iterator
+class EntryIterator {
+public:
+ // Used for dummy initialization. Performing operations on a default-constructed
+ // EntryIterator other than assigning it to another valid EntryIterator
+ // is undefined behavior.
+ EntryIterator();
+ // Caller's responsibility to make sure entry is not nullptr.
+ // Passing in nullptr can result in undefined behavior.
+ explicit EntryIterator(const uint8_t *entry);
+ EntryIterator(const EntryIterator &other);
+
+ // dereference underlying entry
+ const entry& operator*() const;
+ const entry* operator->() const;
+ // advance to next entry
+ EntryIterator& operator++(); // ++i
+ // back to previous entry
+ EntryIterator& operator--(); // --i
+ // returns an EntryIterator corresponding to the next entry
+ EntryIterator next() const;
+ // returns an EntryIterator corresponding to the previous entry
+ EntryIterator prev() const;
+ bool operator!=(const EntryIterator &other) const;
+ int operator-(const EntryIterator &other) const;
+
+ bool hasConsistentLength() const;
+ void copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
+ void copyData(uint8_t *dst) const;
+
+ // memcpy preferred to reinterpret_cast to avoid potentially unsupported
+ // unaligned memory access.
+#if 0
+ template<typename T>
+ inline const T& payload() {
+ return *reinterpret_cast<const T *>(mPtr + offsetof(entry, data));
+ }
+#else
+ template<typename T>
+ inline T payload() const {
+ static_assert(std::is_trivially_copyable<T>::value
+ && !std::is_pointer<T>::value,
+ "NBLog::EntryIterator payload must be trivially copyable, non-pointer type.");
+ T payload;
+ memcpy(&payload, mPtr + offsetof(entry, data), sizeof(payload));
+ return payload;
+ }
+#endif
+
+ inline operator const uint8_t*() const {
+ return mPtr;
+ }
+
+private:
+ const uint8_t *mPtr; // Should not be nullptr except for dummy initialization
+};
+
+// ---------------------------------------------------------------------------
+// The following classes are used for merging into the Merger's buffer.
+
+class AbstractEntry {
+public:
+ virtual ~AbstractEntry() {}
+
+ // build concrete entry of appropriate class from ptr.
+ static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
+
+ // get format entry timestamp
+ virtual int64_t timestamp() const = 0;
+
+ // get format entry's unique id
+ virtual log_hash_t hash() const = 0;
+
+ // entry's author index (-1 if none present)
+ // a Merger has a vector of Readers, author simply points to the index of the
+ // Reader that originated the entry
+ // TODO consider changing to uint32_t
+ virtual int author() const = 0;
+
+ // copy entry, adding author before timestamp, returns iterator to end of entry
+ virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+ int author) const = 0;
+
+protected:
+ // Entry starting in the given pointer, which shall not be nullptr.
+ explicit AbstractEntry(const uint8_t *entry) : mEntry(entry) {}
+ // copies ordinary entry from src to dst, and returns length of entry
+ // size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
+ const uint8_t * const mEntry;
+};
+
+// API for handling format entry operations
+
+// a formatted entry has the following structure:
+// * FMT_START entry, containing the format string
+// * TIMESTAMP entry
+// * HASH entry
+// * author entry of the thread that generated it (optional, present in merged log)
+// * format arg1
+// * format arg2
+// * ...
+// * FMT_END entry
+class FormatEntry : public AbstractEntry {
+public:
+ // explicit FormatEntry(const EntryIterator &it);
+ explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
+ ~FormatEntry() override = default;
+
+ EntryIterator begin() const;
+
+ // Entry's format string
+ const char* formatString() const;
+
+ // Enrty's format string length
+ size_t formatStringLength() const;
+
+ // Format arguments (excluding format string, timestamp and author)
+ EntryIterator args() const;
+
+ // get format entry timestamp
+ int64_t timestamp() const override;
+
+ // get format entry's unique id
+ log_hash_t hash() const override;
+
+ // entry's author index (-1 if none present)
+ // a Merger has a vector of Readers, author simply points to the index of the
+ // Reader that originated the entry
+ int author() const override;
+
+ // copy entry, adding author before timestamp, returns size of original entry
+ EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+ int author) const override;
+};
+
+class HistogramEntry : public AbstractEntry {
+public:
+ explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
+ ~HistogramEntry() override = default;
+
+ int64_t timestamp() const override;
+
+ log_hash_t hash() const override;
+
+ int author() const override;
+
+ EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
+ int author) const override;
+};
+
+} // namespace NBLog
+} // namespace android
+
+#endif // ANDROID_MEDIA_NBLOG_ENTRY_H
diff --git a/media/libnblog/include/media/nblog/Events.h b/media/libnblog/include/media/nblog/Events.h
new file mode 100644
index 0000000..aca4fe8
--- /dev/null
+++ b/media/libnblog/include/media/nblog/Events.h
@@ -0,0 +1,156 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_NBLOG_EVENTS_H
+#define ANDROID_MEDIA_NBLOG_EVENTS_H
+
+#include <stddef.h>
+#include <stdint.h>
+#include <system/audio.h>
+#include <type_traits>
+
+namespace android {
+namespace NBLog {
+
+// TODO have a comment somewhere explaining the whole process for adding a new EVENT_
+
+// NBLog Event types. The Events are named to provide contextual meaning for what is logged.
+// If adding a new standalone Event here, update the event-to-type mapping by adding a
+// MAP_EVENT_TO_TYPE statement below.
+// XXX Note that as of the current design, Events should not be renumbered (i.e. reordered)
+// if they ever leave memory (for example, written to file, uploaded to cloud, etc.).
+// TODO make some sort of interface to keep these "contract" constants.
+enum Event : uint8_t {
+ EVENT_RESERVED,
+ EVENT_STRING, // ASCII string, not NUL-terminated
+ // TODO: make timestamp optional
+ EVENT_TIMESTAMP, // clock_gettime(CLOCK_MONOTONIC)
+
+ // Types for Format Entry, i.e. formatted entry
+ EVENT_FMT_START, // logFormat start event: entry includes format string,
+ // following entries contain format arguments
+ // format arguments
+ EVENT_FMT_AUTHOR, // author index (present in merged logs) tracks entry's
+ // original log
+ EVENT_FMT_FLOAT, // floating point value entry
+ EVENT_FMT_HASH, // unique HASH of log origin, originates from hash of file name
+ // and line number
+ EVENT_FMT_INTEGER, // integer value entry
+ EVENT_FMT_PID, // process ID and process name
+ EVENT_FMT_STRING, // string value entry
+ EVENT_FMT_TIMESTAMP, // timestamp value entry
+ // end of format arguments
+ EVENT_FMT_END, // end of logFormat argument list
+
+ // Types for wakeup timestamp histograms
+ EVENT_AUDIO_STATE, // audio on/off event: logged on FastMixer::onStateChange call
+ EVENT_HISTOGRAM_ENTRY_TS, // single datum for timestamp histogram
+
+ // Types representing audio performance metrics
+ EVENT_LATENCY, // difference between frames presented by HAL and frames
+ // written to HAL output sink, divided by sample rate.
+ EVENT_OVERRUN, // predicted thread overrun event timestamp
+ EVENT_THREAD_INFO, // see thread_info_t below
+ EVENT_UNDERRUN, // predicted thread underrun event timestamp
+ EVENT_WARMUP_TIME, // thread warmup time
+ EVENT_WORK_TIME, // the time a thread takes to do work, e.g. read, write, etc.
+ EVENT_THREAD_PARAMS, // see thread_params_t below
+
+ EVENT_UPPER_BOUND, // to check for invalid events
+};
+
+// NBLog custom-defined structs. Some NBLog Event types map to these structs.
+
+using log_hash_t = uint64_t;
+
+// used for EVENT_HISTOGRAM_ENTRY_TS (not mapped)
+struct HistTsEntry {
+ log_hash_t hash;
+ int64_t ts;
+}; //TODO __attribute__((packed));
+
+// used for EVENT_HISTOGRAM_ENTRY_TS (not mapped)
+struct HistTsEntryWithAuthor {
+ log_hash_t hash;
+ int64_t ts;
+ int author;
+}; //TODO __attribute__((packed));
+
+enum ThreadType {
+ UNKNOWN,
+ MIXER,
+ CAPTURE,
+ FASTMIXER,
+ FASTCAPTURE,
+};
+
+inline const char *threadTypeToString(ThreadType type) {
+ switch (type) {
+ case MIXER:
+ return "MIXER";
+ case CAPTURE:
+ return "CAPTURE";
+ case FASTMIXER:
+ return "FASTMIXER";
+ case FASTCAPTURE:
+ return "FASTCAPTURE";
+ case UNKNOWN:
+ default:
+ return "UNKNOWN";
+ }
+}
+
+// mapped from EVENT_THREAD_INFO
+// These fields always stay the same throughout a thread's lifetime and
+// should only need to be logged once upon thread initialization.
+// There is currently no recovery mechanism if the log event corresponding
+// to this type is lost.
+// TODO add this information when adding a reader to MediaLogService?
+struct thread_info_t {
+ audio_io_handle_t id = -1; // Thread I/O handle
+ ThreadType type = UNKNOWN; // See enum ThreadType above
+};
+
+// mapped from EVENT_THREAD_PARAMS
+// These fields are not necessarily constant throughout a thread's lifetime and
+// can be logged whenever a thread receives new configurations or parameters.
+struct thread_params_t {
+ size_t frameCount = 0; // number of frames per read or write buffer
+ unsigned sampleRate = 0; // in frames per second
+};
+
+template <Event E> struct get_mapped;
+#define MAP_EVENT_TO_TYPE(E, T) \
+template<> struct get_mapped<E> { \
+ static_assert(std::is_trivially_copyable<T>::value \
+ && !std::is_pointer<T>::value, \
+ "NBLog::Event must map to trivially copyable, non-pointer type."); \
+ typedef T type; \
+}
+
+// Maps an NBLog Event type to a C++ POD type.
+MAP_EVENT_TO_TYPE(EVENT_LATENCY, double);
+MAP_EVENT_TO_TYPE(EVENT_OVERRUN, int64_t);
+MAP_EVENT_TO_TYPE(EVENT_THREAD_INFO, thread_info_t);
+MAP_EVENT_TO_TYPE(EVENT_UNDERRUN, int64_t);
+MAP_EVENT_TO_TYPE(EVENT_WARMUP_TIME, double);
+MAP_EVENT_TO_TYPE(EVENT_WORK_TIME, int64_t);
+MAP_EVENT_TO_TYPE(EVENT_THREAD_PARAMS, thread_params_t);
+
+} // namespace NBLog
+} // namespace android
+
+#endif // ANDROID_MEDIA_NBLOG_EVENTS_H
diff --git a/media/libnblog/include/media/nblog/Merger.h b/media/libnblog/include/media/nblog/Merger.h
new file mode 100644
index 0000000..7da8521
--- /dev/null
+++ b/media/libnblog/include/media/nblog/Merger.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_NBLOG_MERGER_H
+#define ANDROID_MEDIA_NBLOG_MERGER_H
+
+#include <memory>
+#include <stddef.h>
+#include <stdint.h>
+#include <vector>
+
+#include <audio_utils/fifo.h>
+#include <media/nblog/PerformanceAnalysis.h>
+#include <media/nblog/Reader.h>
+#include <utils/Condition.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+#include <utils/Thread.h>
+#include <utils/Timers.h>
+#include <utils/Vector.h>
+
+namespace android {
+
+class String16;
+class String8;
+
+namespace NBLog {
+
+struct Shared;
+
+// TODO update comments to reflect current functionalities
+
+// This class is used to read data from each thread's individual FIFO in shared memory
+// and write it to a single FIFO in local memory.
+class Merger : public RefBase {
+public:
+ Merger(const void *shared, size_t size);
+
+ ~Merger() override = default;
+
+ void addReader(const sp<NBLog::Reader> &reader);
+ // TODO add removeReader
+ void merge();
+
+ // FIXME This is returning a reference to a shared variable that needs a lock
+ const std::vector<sp<Reader>>& getReaders() const;
+
+private:
+ // vector of the readers the merger is supposed to merge from.
+ // every reader reads from a writer's buffer
+ // FIXME Needs to be protected by a lock
+ std::vector<sp<Reader>> mReaders;
+
+ Shared * const mShared; // raw pointer to shared memory
+ std::unique_ptr<audio_utils_fifo> mFifo; // FIFO itself
+ std::unique_ptr<audio_utils_fifo_writer> mFifoWriter; // used to write to FIFO
+};
+
+// This class has a pointer to the FIFO in local memory which stores the merged
+// data collected by NBLog::Merger from all Readers. It is used to process
+// this data and write the result to PerformanceAnalysis.
+class MergeReader : public Reader {
+public:
+ MergeReader(const void *shared, size_t size, Merger &merger);
+
+ // process a particular snapshot of the reader
+ void processSnapshot(Snapshot &snap, int author);
+
+ // call getSnapshot of the content of the reader's buffer and process the data
+ void getAndProcessSnapshot();
+
+ // check for periodic push of performance data to media metrics, and perform
+ // the send if it is time to do so.
+ void checkPushToMediaMetrics();
+
+ void dump(int fd, const Vector<String16>& args);
+
+private:
+ // FIXME Needs to be protected by a lock,
+ // because even though our use of it is read-only there may be asynchronous updates
+ // The object is owned by the Merger class.
+ const std::vector<sp<Reader>>& mReaders;
+
+ // analyzes, compresses and stores the merged data
+ // contains a separate instance for every author (thread), and for every source file
+ // location within each author
+ ReportPerformance::PerformanceAnalysisMap mThreadPerformanceAnalysis;
+
+ // compresses and stores audio performance data from each thread's buffers.
+ // first parameter is author, i.e. thread index.
+ std::map<int, ReportPerformance::PerformanceData> mThreadPerformanceData;
+
+ // how often to push data to Media Metrics
+ static constexpr nsecs_t kPeriodicMediaMetricsPush = s2ns((nsecs_t)2 * 60 * 60); // 2 hours
+
+ // handle author entry by looking up the author's name and appending it to the body
+ // returns number of bytes read from fmtEntry
+ void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
+};
+
+// MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
+// when triggered, it awakes for a lapse of time, during which it periodically merges; if
+// retriggered, the timeout is reset.
+// The thread is triggered on AudioFlinger binder activity.
+class MergeThread : public Thread {
+public:
+ MergeThread(Merger &merger, MergeReader &mergeReader);
+ ~MergeThread() override;
+
+ // Reset timeout and activate thread to merge periodically if it's idle
+ void wakeup();
+
+ // Set timeout period until the merging thread goes idle again
+ void setTimeoutUs(int time);
+
+private:
+ bool threadLoop() override;
+
+ // the merger who actually does the work of merging the logs
+ Merger& mMerger;
+
+ // the mergereader used to process data merged by mMerger
+ MergeReader& mMergeReader;
+
+ // mutex for the condition variable
+ Mutex mMutex;
+
+ // condition variable to activate merging on timeout >= 0
+ Condition mCond;
+
+ // time left until the thread blocks again (in microseconds)
+ int mTimeoutUs;
+
+ // merging period when the thread is awake
+ static const int kThreadSleepPeriodUs = 1000000 /*1s*/;
+
+ // initial timeout value when triggered
+ static const int kThreadWakeupPeriodUs = 3000000 /*3s*/;
+};
+
+} // namespace NBLog
+} // namespace android
+
+#endif // ANDROID_MEDIA_NBLOG_MERGER_H
diff --git a/media/libnblog/include/media/nblog/NBLog.h b/media/libnblog/include/media/nblog/NBLog.h
index e43b026..fd73538 100644
--- a/media/libnblog/include/media/nblog/NBLog.h
+++ b/media/libnblog/include/media/nblog/NBLog.h
@@ -19,670 +19,10 @@
#ifndef ANDROID_MEDIA_NBLOG_H
#define ANDROID_MEDIA_NBLOG_H
-#include <map>
-#include <memory>
-#include <type_traits>
-#include <unordered_set>
-#include <vector>
-
-#include <audio_utils/fifo.h>
-#include <binder/IMemory.h>
-#include <media/nblog/PerformanceAnalysis.h>
-#include <media/nblog/ReportPerformance.h>
-#include <utils/Mutex.h>
-#include <utils/threads.h>
-#include <utils/Timers.h>
-
-namespace android {
-
-class String8;
-
-class NBLog {
-
-public:
-
- using log_hash_t = uint64_t;
-
- // FIXME Everything needed for client (writer API and registration) should be isolated
- // from the rest of the implementation.
- class Writer;
- class Reader;
-
- // TODO have a comment somewhere explaining the whole process for adding a new EVENT_
-
- // NBLog Event types. The Events are named to provide contextual meaning for what is logged.
- // If adding a new standalone Event here, update the event-to-type mapping by adding a
- // MAP_EVENT_TO_TYPE statement below.
- enum Event : uint8_t {
- EVENT_RESERVED,
- EVENT_STRING, // ASCII string, not NUL-terminated
- // TODO: make timestamp optional
- EVENT_TIMESTAMP, // clock_gettime(CLOCK_MONOTONIC)
-
- // Types for Format Entry, i.e. formatted entry
- EVENT_FMT_START, // logFormat start event: entry includes format string,
- // following entries contain format arguments
- // format arguments
- EVENT_FMT_TIMESTAMP, // timestamp value entry
- EVENT_FMT_HASH, // unique HASH of log origin, originates from hash of file name
- // and line number
- EVENT_FMT_STRING, // string value entry
- EVENT_FMT_INTEGER, // integer value entry
- EVENT_FMT_FLOAT, // floating point value entry
- EVENT_FMT_PID, // process ID and process name
- EVENT_FMT_AUTHOR, // author index (present in merged logs) tracks entry's
- // original log
- // end of format arguments
- EVENT_FMT_END, // end of logFormat argument list
-
- // Types for wakeup timestamp histograms
- EVENT_HISTOGRAM_ENTRY_TS, // single datum for timestamp histogram
- EVENT_AUDIO_STATE, // audio on/off event: logged on FastMixer::onStateChange call
-
- // Types representing audio performance metrics
- EVENT_THREAD_INFO, // thread type, frameCount and sampleRate, which give context
- // for the metrics below.
- EVENT_LATENCY, // difference between frames presented by HAL and frames
- // written to HAL output sink, divided by sample rate.
- EVENT_WORK_TIME, // the time a thread takes to do work, e.g. read, write, etc.
- EVENT_WARMUP_TIME, // thread warmup time
- EVENT_UNDERRUN, // predicted thread underrun event timestamp
- EVENT_OVERRUN, // predicted thread overrun event timestamp
-
- EVENT_UPPER_BOUND, // to check for invalid events
- };
-
- // NBLog custom-defined structs. Some NBLog Event types map to these structs.
-
- // mapped from EVENT_THREAD_INFO
- struct thread_info_t {
- // TODO make type an enum
- int type; // Thread type: 0 for MIXER, 1 for CAPTURE,
- // 2 for FASTMIXER, 3 for FASTCAPTURE
- size_t frameCount; // number of frames per read or write buffer
- unsigned sampleRate; // in frames per second
- };
-
- template <Event E> struct get_mapped;
-#define MAP_EVENT_TO_TYPE(E, T) \
- template<> struct get_mapped<E> { \
- static_assert(std::is_trivially_copyable<T>::value \
- && !std::is_pointer<T>::value, \
- "NBLog::Event must map to trivially copyable, non-pointer type."); \
- typedef T type; \
- }
-
- // Maps an NBLog Event type to a C++ POD type.
- MAP_EVENT_TO_TYPE(EVENT_THREAD_INFO, thread_info_t);
- MAP_EVENT_TO_TYPE(EVENT_LATENCY, double);
- MAP_EVENT_TO_TYPE(EVENT_WORK_TIME, int64_t);
- MAP_EVENT_TO_TYPE(EVENT_WARMUP_TIME, double);
- MAP_EVENT_TO_TYPE(EVENT_UNDERRUN, int64_t);
- MAP_EVENT_TO_TYPE(EVENT_OVERRUN, int64_t);
-
-private:
-
- // ---------------------------------------------------------------------------
-
- // entry representation in memory
- struct entry {
- const uint8_t type;
- const uint8_t length;
- const uint8_t data[0];
- };
-
- // entry tail representation (after data)
- struct ending {
- uint8_t length;
- uint8_t next[0];
- };
-
- // entry iterator
- class EntryIterator {
- public:
- // Used for dummy initialization. Performing operations on a default-constructed
- // EntryIterator other than assigning it to another valid EntryIterator
- // is undefined behavior.
- EntryIterator();
- // Caller's responsibility to make sure entry is not nullptr.
- // Passing in nullptr can result in undefined behavior.
- explicit EntryIterator(const uint8_t *entry);
- EntryIterator(const EntryIterator &other);
-
- // dereference underlying entry
- const entry& operator*() const;
- const entry* operator->() const;
- // advance to next entry
- EntryIterator& operator++(); // ++i
- // back to previous entry
- EntryIterator& operator--(); // --i
- // returns an EntryIterator corresponding to the next entry
- EntryIterator next() const;
- // returns an EntryIterator corresponding to the previous entry
- EntryIterator prev() const;
- bool operator!=(const EntryIterator &other) const;
- int operator-(const EntryIterator &other) const;
-
- bool hasConsistentLength() const;
- void copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const;
- void copyData(uint8_t *dst) const;
-
- // memcpy preferred to reinterpret_cast to avoid potentially unsupported
- // unaligned memory access.
-#if 0
- template<typename T>
- inline const T& payload() {
- return *reinterpret_cast<const T *>(mPtr + offsetof(entry, data));
- }
-#else
- template<typename T>
- inline T payload() const {
- static_assert(std::is_trivially_copyable<T>::value
- && !std::is_pointer<T>::value,
- "NBLog::EntryIterator payload must be trivially copyable, non-pointer type.");
- T payload;
- memcpy(&payload, mPtr + offsetof(entry, data), sizeof(payload));
- return payload;
- }
-#endif
-
- inline operator const uint8_t*() const {
- return mPtr;
- }
-
- private:
- const uint8_t *mPtr; // Should not be nullptr except for dummy initialization
- };
-
- // ---------------------------------------------------------------------------
- // The following classes are used for merging into the Merger's buffer.
-
- class AbstractEntry {
- public:
- virtual ~AbstractEntry() {}
-
- // build concrete entry of appropriate class from ptr.
- static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
-
- // get format entry timestamp
- virtual int64_t timestamp() const = 0;
-
- // get format entry's unique id
- virtual log_hash_t hash() const = 0;
-
- // entry's author index (-1 if none present)
- // a Merger has a vector of Readers, author simply points to the index of the
- // Reader that originated the entry
- // TODO consider changing to uint32_t
- virtual int author() const = 0;
-
- // copy entry, adding author before timestamp, returns iterator to end of entry
- virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
- int author) const = 0;
-
- protected:
- // Entry starting in the given pointer, which shall not be nullptr.
- explicit AbstractEntry(const uint8_t *entry);
- // copies ordinary entry from src to dst, and returns length of entry
- // size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
- const uint8_t *mEntry;
- };
-
- // API for handling format entry operations
-
- // a formatted entry has the following structure:
- // * FMT_START entry, containing the format string
- // * TIMESTAMP entry
- // * HASH entry
- // * author entry of the thread that generated it (optional, present in merged log)
- // * format arg1
- // * format arg2
- // * ...
- // * FMT_END entry
- class FormatEntry : public AbstractEntry {
- public:
- // explicit FormatEntry(const EntryIterator &it);
- explicit FormatEntry(const uint8_t *ptr) : AbstractEntry(ptr) {}
- virtual ~FormatEntry() {}
-
- EntryIterator begin() const;
-
- // Entry's format string
- const char* formatString() const;
-
- // Enrty's format string length
- size_t formatStringLength() const;
-
- // Format arguments (excluding format string, timestamp and author)
- EntryIterator args() const;
-
- // get format entry timestamp
- virtual int64_t timestamp() const override;
-
- // get format entry's unique id
- virtual log_hash_t hash() const override;
-
- // entry's author index (-1 if none present)
- // a Merger has a vector of Readers, author simply points to the index of the
- // Reader that originated the entry
- virtual int author() const override;
-
- // copy entry, adding author before timestamp, returns size of original entry
- virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
- int author) const override;
- };
-
- class HistogramEntry : public AbstractEntry {
- public:
- explicit HistogramEntry(const uint8_t *ptr) : AbstractEntry(ptr) {
- }
- virtual ~HistogramEntry() {}
-
- virtual int64_t timestamp() const override;
-
- virtual log_hash_t hash() const override;
-
- virtual int author() const override;
-
- virtual EntryIterator copyWithAuthor(std::unique_ptr<audio_utils_fifo_writer> &dst,
- int author) const override;
- };
-
- // ---------------------------------------------------------------------------
-
- // representation of a single log entry in shared memory
- // byte[0] mEvent
- // byte[1] mLength
- // byte[2] mData[0]
- // ...
- // byte[2+i] mData[i]
- // ...
- // byte[2+mLength-1] mData[mLength-1]
- // byte[2+mLength] duplicate copy of mLength to permit reverse scan
- // byte[3+mLength] start of next log entry
- class Entry {
- public:
- Entry(Event event, const void *data, size_t length)
- : mEvent(event), mLength(length), mData(data) { }
- /*virtual*/ ~Entry() { }
-
- // used during writing to format Entry information as follows:
- // [type][length][data ... ][length]
- int copyEntryDataAt(size_t offset) const;
-
- private:
- friend class Writer;
- Event mEvent; // event type
- uint8_t mLength; // length of additional data, 0 <= mLength <= kMaxLength
- const void *mData; // event type-specific data
- static const size_t kMaxLength = 255;
- public:
- // mEvent, mLength, mData[...], duplicate mLength
- static const size_t kOverhead = sizeof(entry) + sizeof(ending);
- // endind length of previous entry
- static const ssize_t kPreviousLengthOffset = - sizeof(ending) +
- offsetof(ending, length);
- };
-
- // TODO move these somewhere else
- struct HistTsEntry {
- log_hash_t hash;
- int64_t ts;
- }; //TODO __attribute__((packed));
-
- struct HistTsEntryWithAuthor {
- log_hash_t hash;
- int64_t ts;
- int author;
- }; //TODO __attribute__((packed));
-
- struct HistIntEntry {
- log_hash_t hash;
- int value;
- }; //TODO __attribute__((packed));
-
-public:
-
- // Located in shared memory, must be POD.
- // Exactly one process must explicitly call the constructor or use placement new.
- // Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
- struct Shared {
- Shared() /* mRear initialized via default constructor */ { }
- /*virtual*/ ~Shared() { }
-
- audio_utils_fifo_index mRear; // index one byte past the end of most recent Entry
- char mBuffer[0]; // circular buffer for entries
- };
-
-public:
-
- // ---------------------------------------------------------------------------
-
- // FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
- // For now it is just a namespace for sharedSize().
- class Timeline : public RefBase {
- public:
-#if 0
- Timeline(size_t size, void *shared = NULL);
- virtual ~Timeline();
-#endif
-
- // Input parameter 'size' is the desired size of the timeline in byte units.
- // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
- static size_t sharedSize(size_t size);
-
-#if 0
- private:
- friend class Writer;
- friend class Reader;
-
- const size_t mSize; // circular buffer size in bytes, must be a power of 2
- bool mOwn; // whether I own the memory at mShared
- Shared* const mShared; // pointer to shared memory
-#endif
- };
-
- // ---------------------------------------------------------------------------
- // NBLog Writer API
- // ---------------------------------------------------------------------------
-
- // Writer is thread-safe with respect to Reader, but not with respect to multiple threads
- // calling Writer methods. If you need multi-thread safety for writing, use LockedWriter.
- class Writer : public RefBase {
- public:
- Writer(); // dummy nop implementation without shared memory
-
- // Input parameter 'size' is the desired size of the timeline in byte units.
- // The size of the shared memory must be at least Timeline::sharedSize(size).
- Writer(void *shared, size_t size);
- Writer(const sp<IMemory>& iMemory, size_t size);
-
- virtual ~Writer();
-
- // FIXME needs comments, and some should be private
- void log(const char *string);
- void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
- void logTimestamp();
- void logFormat(const char *fmt, log_hash_t hash, ...);
- void logEventHistTs(Event event, log_hash_t hash);
-
- // Log data related to Event E. See the event-to-type mapping for the type of data
- // corresponding to the event. For example, if you see a mapping statement:
- // MAP_TYPE_TO_EVENT(E, T);
- // then the usage of this method would be:
- // T data = doComputation();
- // tlNBLogWriter->log<NBLog::E>(data);
- template<Event E>
- void log(typename get_mapped<E>::type data) {
- log(E, &data, sizeof(data));
- }
-
- virtual bool isEnabled() const;
-
- // return value for all of these is the previous isEnabled()
- virtual bool setEnabled(bool enabled); // but won't enable if no shared memory
- bool enable() { return setEnabled(true); }
- bool disable() { return setEnabled(false); }
-
- sp<IMemory> getIMemory() const { return mIMemory; }
-
- // Public logging function implementations should always use one of the
- // two log() function calls below to write to shared memory.
- protected:
- // Writes a single Entry to the FIFO if the writer is enabled.
- // This is protected and virtual because LockedWriter uses a lock to protect
- // writing to the FIFO before writing to this function.
- virtual void log(const Entry &entry, bool trusted = false);
-
- private:
- // 0 <= length <= kMaxLength
- // Log a single Entry with corresponding event, data, and length.
- void log(Event event, const void *data, size_t length);
-
- void logvf(const char *fmt, va_list ap);
-
- // helper functions for logging parts of a formatted entry
- void logStart(const char *fmt);
- void logTimestampFormat();
- void logVFormat(const char *fmt, log_hash_t hash, va_list ap);
-
- Shared* const mShared; // raw pointer to shared memory
- sp<IMemory> mIMemory; // ref-counted version, initialized in constructor
- // and then const
- audio_utils_fifo * const mFifo; // FIFO itself, non-NULL
- // unless constructor fails
- audio_utils_fifo_writer * const mFifoWriter; // used to write to FIFO, non-NULL
- // unless dummy constructor used
- bool mEnabled; // whether to actually log
-
- // cached pid and process name to use in %p format specifier
- // total tag length is mPidTagSize and process name is not zero terminated
- char *mPidTag;
- size_t mPidTagSize;
- };
-
- // ---------------------------------------------------------------------------
-
- // Similar to Writer, but safe for multiple threads to call concurrently
- class LockedWriter : public Writer {
- public:
- LockedWriter();
- LockedWriter(void *shared, size_t size);
-
- bool isEnabled() const override;
- bool setEnabled(bool enabled) override;
-
- private:
- // Lock needs to be obtained before writing to FIFO.
- void log(const Entry &entry, bool trusted = false) override;
- mutable Mutex mLock;
- };
-
- // ---------------------------------------------------------------------------
- // NBLog Reader API
- // ---------------------------------------------------------------------------
-
- class Snapshot; // Forward declaration needed for Reader::getSnapshot()
-
- class Reader : public RefBase {
- public:
- // Input parameter 'size' is the desired size of the timeline in byte units.
- // The size of the shared memory must be at least Timeline::sharedSize(size).
- Reader(const void *shared, size_t size, const std::string &name);
- Reader(const sp<IMemory>& iMemory, size_t size, const std::string &name);
- virtual ~Reader();
-
- // get snapshot of readers fifo buffer, effectively consuming the buffer
- std::unique_ptr<Snapshot> getSnapshot();
- bool isIMemory(const sp<IMemory>& iMemory) const;
- const std::string &name() const { return mName; }
-
- private:
- // Amount of tries for reader to catch up with writer in getSnapshot().
- static constexpr int kMaxObtainTries = 3;
-
- // invalidBeginTypes and invalidEndTypes are used to align the Snapshot::begin() and
- // Snapshot::end() EntryIterators to valid entries.
- static const std::unordered_set<Event> invalidBeginTypes;
- static const std::unordered_set<Event> invalidEndTypes;
-
- // declared as const because audio_utils_fifo() constructor
- sp<IMemory> mIMemory; // ref-counted version, assigned only in constructor
-
- const std::string mName; // name of reader (actually name of writer)
- /*const*/ Shared* const mShared; // raw pointer to shared memory, actually const but not
- audio_utils_fifo * const mFifo; // FIFO itself,
- // non-NULL unless constructor fails
- audio_utils_fifo_reader * const mFifoReader; // used to read from FIFO,
- // non-NULL unless constructor fails
-
- // Searches for the last valid entry in the range [front, back)
- // back has to be entry-aligned. Returns nullptr if none enconuntered.
- static const uint8_t *findLastValidEntry(const uint8_t *front, const uint8_t *back,
- const std::unordered_set<Event> &invalidTypes);
- };
-
- // A snapshot of a readers buffer
- // This is raw data. No analysis has been done on it
- class Snapshot {
- public:
- ~Snapshot() { delete[] mData; }
-
- // amount of data lost (given by audio_utils_fifo_reader)
- size_t lost() const { return mLost; }
-
- // iterator to beginning of readable segment of snapshot
- // data between begin and end has valid entries
- EntryIterator begin() const { return mBegin; }
-
- // iterator to end of readable segment of snapshot
- EntryIterator end() const { return mEnd; }
-
- private:
- Snapshot() = default;
- explicit Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
- friend std::unique_ptr<Snapshot> Reader::getSnapshot();
- uint8_t * const mData = nullptr;
- size_t mLost = 0;
- EntryIterator mBegin;
- EntryIterator mEnd;
- };
-
- // TODO move this to MediaLogService?
- class DumpReader : public Reader {
- public:
- DumpReader(const void *shared, size_t size, const std::string &name)
- : Reader(shared, size, name) {}
- DumpReader(const sp<IMemory>& iMemory, size_t size, const std::string &name)
- : Reader(iMemory, size, name) {}
- void dump(int fd, size_t indent = 0);
- private:
- void handleAuthor(const AbstractEntry& fmtEntry __unused, String8* body __unused) {}
- EntryIterator handleFormat(const FormatEntry &fmtEntry, String8 *timestamp, String8 *body);
-
- static void appendInt(String8 *body, const void *data);
- static void appendFloat(String8 *body, const void *data);
- static void appendPID(String8 *body, const void *data, size_t length);
- static void appendTimestamp(String8 *body, const void *data);
-
- // The bufferDump functions are used for debugging only.
- static String8 bufferDump(const uint8_t *buffer, size_t size);
- static String8 bufferDump(const EntryIterator &it);
- };
-
- // ---------------------------------------------------------------------------
- // TODO move Merger, MergeReader, and MergeThread to a separate file.
-
- // This class is used to read data from each thread's individual FIFO in shared memory
- // and write it to a single FIFO in local memory.
- class Merger : public RefBase {
- public:
- Merger(const void *shared, size_t size);
-
- virtual ~Merger() {}
-
- void addReader(const sp<NBLog::Reader> &reader);
- // TODO add removeReader
- void merge();
-
- // FIXME This is returning a reference to a shared variable that needs a lock
- const std::vector<sp<Reader>>& getReaders() const;
-
- private:
- // vector of the readers the merger is supposed to merge from.
- // every reader reads from a writer's buffer
- // FIXME Needs to be protected by a lock
- std::vector<sp<Reader>> mReaders;
-
- Shared * const mShared; // raw pointer to shared memory
- std::unique_ptr<audio_utils_fifo> mFifo; // FIFO itself
- std::unique_ptr<audio_utils_fifo_writer> mFifoWriter; // used to write to FIFO
- };
-
- // This class has a pointer to the FIFO in local memory which stores the merged
- // data collected by NBLog::Merger from all Readers. It is used to process
- // this data and write the result to PerformanceAnalysis.
- class MergeReader : public Reader {
- public:
- MergeReader(const void *shared, size_t size, Merger &merger);
-
- void dump(int fd, int indent = 0);
-
- // process a particular snapshot of the reader
- void processSnapshot(Snapshot &snap, int author);
-
- // call getSnapshot of the content of the reader's buffer and process the data
- void getAndProcessSnapshot();
-
- // check for periodic push of performance data to media metrics, and perform
- // the send if it is time to do so.
- void checkPushToMediaMetrics();
-
- private:
- // FIXME Needs to be protected by a lock,
- // because even though our use of it is read-only there may be asynchronous updates
- // The object is owned by the Merger class.
- const std::vector<sp<Reader>>& mReaders;
-
- // analyzes, compresses and stores the merged data
- // contains a separate instance for every author (thread), and for every source file
- // location within each author
- ReportPerformance::PerformanceAnalysisMap mThreadPerformanceAnalysis;
-
- // compresses and stores audio performance data from each thread's buffers.
- // first parameter is author, i.e. thread index.
- std::map<int, ReportPerformance::PerformanceData> mThreadPerformanceData;
-
- // how often to push data to Media Metrics
- static constexpr nsecs_t kPeriodicMediaMetricsPush = s2ns((nsecs_t)2 * 60 * 60); // 2 hours
-
- // handle author entry by looking up the author's name and appending it to the body
- // returns number of bytes read from fmtEntry
- void handleAuthor(const AbstractEntry &fmtEntry, String8 *body);
- };
-
- // MergeThread is a thread that contains a Merger. It works as a retriggerable one-shot:
- // when triggered, it awakes for a lapse of time, during which it periodically merges; if
- // retriggered, the timeout is reset.
- // The thread is triggered on AudioFlinger binder activity.
- class MergeThread : public Thread {
- public:
- MergeThread(Merger &merger, MergeReader &mergeReader);
- virtual ~MergeThread() override;
-
- // Reset timeout and activate thread to merge periodically if it's idle
- void wakeup();
-
- // Set timeout period until the merging thread goes idle again
- void setTimeoutUs(int time);
-
- private:
- virtual bool threadLoop() override;
-
- // the merger who actually does the work of merging the logs
- Merger& mMerger;
-
- // the mergereader used to process data merged by mMerger
- MergeReader& mMergeReader;
-
- // mutex for the condition variable
- Mutex mMutex;
-
- // condition variable to activate merging on timeout >= 0
- Condition mCond;
-
- // time left until the thread blocks again (in microseconds)
- int mTimeoutUs;
-
- // merging period when the thread is awake
- static const int kThreadSleepPeriodUs = 1000000 /*1s*/;
-
- // initial timeout value when triggered
- static const int kThreadWakeupPeriodUs = 3000000 /*3s*/;
- };
-
-}; // class NBLog
-
-} // namespace android
+#include <media/nblog/Entry.h>
+#include <media/nblog/Events.h>
+#include <media/nblog/Reader.h>
+#include <media/nblog/Timeline.h>
+#include <media/nblog/Writer.h>
#endif // ANDROID_MEDIA_NBLOG_H
diff --git a/media/libnblog/include/media/nblog/PerformanceAnalysis.h b/media/libnblog/include/media/nblog/PerformanceAnalysis.h
index 6893fee..d7c16b6 100644
--- a/media/libnblog/include/media/nblog/PerformanceAnalysis.h
+++ b/media/libnblog/include/media/nblog/PerformanceAnalysis.h
@@ -19,9 +19,11 @@
#include <deque>
#include <map>
+#include <string>
#include <utility>
#include <vector>
+#include <media/nblog/Events.h>
#include <media/nblog/ReportPerformance.h>
#include <utils/Timers.h>
@@ -57,16 +59,16 @@
/**
* \brief Creates a Histogram object.
*
- * \param binSize the width of each bin of the histogram.
+ * \param binSize the width of each bin of the histogram, must be greater than 0.
* Units are whatever data the caller decides to store.
- * \param numBins the number of bins desired in the histogram range.
+ * \param numBins the number of bins desired in the histogram range, must be greater than 0.
* \param low the lower bound of the histogram bucket values.
* Units are whatever data the caller decides to store.
* Note that the upper bound can be calculated by the following:
* upper = lower + binSize * numBins.
*/
Histogram(double binSize, size_t numBins, double low = 0.)
- : mBinSize(binSize), mNumBins(numBins), mLow(low), mBins(mNumBins) {}
+ : mBinSize(binSize), mNumBins(numBins), mLow(low), mBins(mNumBins + 2) {}
Histogram(const Config &c)
: Histogram(c.binSize, c.numBins, c.low) {}
@@ -111,24 +113,33 @@
*/
std::string toString() const;
+ // Draw log scale sideways histogram as ASCII art and store as a std::string.
+ // Empty string is returned if totalCount() == 0.
+ std::string asciiArtString(size_t indent = 0) const;
+
private:
// Histogram version number.
static constexpr int kVersion = 1;
- const double mBinSize; // Size of each bucket
- const size_t mNumBins; // Number of buckets in histogram range
- const double mLow; // Lower bound of values
- std::vector<int> mBins; // Data structure to store the actual histogram
+ const double mBinSize; // Size of each bucket
+ const size_t mNumBins; // Number of buckets in range (excludes low and high)
+ const double mLow; // Lower bound of values
- int mLowCount = 0; // Number of values less than mLow
- int mHighCount = 0; // Number of values >= mLow + mBinSize * mNumBins
- uint64_t mTotalCount = 0; // Total number of values recorded
+ // Data structure to store the actual histogram. Counts of bin values less than mLow
+ // are stored in mBins[0]. Bin index i corresponds to mBins[i+1]. Counts of bin values
+ // >= high are stored in mBins[mNumBins + 1].
+ std::vector<uint64_t> mBins;
+
+ uint64_t mTotalCount = 0; // Total number of values recorded
};
// This is essentially the same as class PerformanceAnalysis, but PerformanceAnalysis
// also does some additional analyzing of data, while the purpose of this struct is
// to hold data.
struct PerformanceData {
+ // TODO the Histogram::Config numbers below are for FastMixer.
+ // Specify different numbers for other thread types.
+
// Values based on mUnderrunNs and mOverrunNs in FastMixer.cpp for frameCount = 192
// and mSampleRate = 48000, which correspond to 2 and 7 seconds.
static constexpr Histogram::Config kWorkConfig = { 0.25, 20, 2.};
@@ -141,18 +152,16 @@
// bin size and lower/upper limits.
static constexpr Histogram::Config kWarmupConfig = { 5., 10, 10.};
- // Thread Info
- // TODO make type an enum
- int type = -1; // Thread type: 0 for MIXER, 1 for CAPTURE,
- // 2 for FASTMIXER, 3 for FASTCAPTURE
- size_t frameCount = 0;
- unsigned sampleRate = 0;
+ NBLog::thread_info_t threadInfo{};
+ NBLog::thread_params_t threadParams{};
// Performance Data
Histogram workHist{kWorkConfig};
Histogram latencyHist{kLatencyConfig};
Histogram warmupHist{kWarmupConfig};
int64_t underruns = 0;
+ static constexpr size_t kMaxSnapshotsToStore = 256;
+ std::deque<std::pair<NBLog::Event, int64_t /*timestamp*/>> snapshots;
int64_t overruns = 0;
nsecs_t active = 0;
nsecs_t start{systemTime()};
@@ -169,6 +178,13 @@
active = 0;
start = systemTime();
}
+
+ // Return true if performance data has not been recorded yet, false otherwise.
+ bool empty() const {
+ return workHist.totalCount() == 0 && latencyHist.totalCount() == 0
+ && warmupHist.totalCount() == 0 && underruns == 0 && overruns == 0
+ && active == 0;
+ }
};
//------------------------------------------------------------------------------
@@ -265,8 +281,7 @@
void dump(int fd, int indent, PerformanceAnalysisMap &threadPerformanceAnalysis);
void dumpLine(int fd, int indent, const String8 &body);
-} // namespace ReportPerformance
-
+} // namespace ReportPerformance
} // namespace android
#endif // ANDROID_MEDIA_PERFORMANCEANALYSIS_H
diff --git a/media/libnblog/include/media/nblog/Reader.h b/media/libnblog/include/media/nblog/Reader.h
new file mode 100644
index 0000000..2495e8c
--- /dev/null
+++ b/media/libnblog/include/media/nblog/Reader.h
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_NBLOG_READER_H
+#define ANDROID_MEDIA_NBLOG_READER_H
+
+#include <memory>
+#include <stddef.h>
+#include <string>
+#include <unordered_set>
+
+#include <media/nblog/Entry.h>
+#include <media/nblog/Events.h>
+#include <utils/RefBase.h>
+
+class audio_utils_fifo;
+class audio_utils_fifo_reader;
+
+namespace android {
+
+class IMemory;
+class String8;
+
+namespace NBLog {
+
+struct Shared;
+
+// NBLog Reader API
+
+class Snapshot; // Forward declaration needed for Reader::getSnapshot()
+
+class Reader : public RefBase {
+public:
+ // Input parameter 'size' is the desired size of the timeline in byte units.
+ // The size of the shared memory must be at least Timeline::sharedSize(size).
+ Reader(const void *shared, size_t size, const std::string &name);
+ Reader(const sp<IMemory>& iMemory, size_t size, const std::string &name);
+ ~Reader() override;
+
+ // get snapshot of readers fifo buffer, effectively consuming the buffer
+ std::unique_ptr<Snapshot> getSnapshot(bool flush = true);
+ bool isIMemory(const sp<IMemory>& iMemory) const;
+ const std::string &name() const { return mName; }
+
+private:
+ // Amount of tries for reader to catch up with writer in getSnapshot().
+ static constexpr int kMaxObtainTries = 3;
+
+ // invalidBeginTypes and invalidEndTypes are used to align the Snapshot::begin() and
+ // Snapshot::end() EntryIterators to valid entries.
+ static const std::unordered_set<Event> invalidBeginTypes;
+ static const std::unordered_set<Event> invalidEndTypes;
+
+ // declared as const because audio_utils_fifo() constructor
+ sp<IMemory> mIMemory; // ref-counted version, assigned only in constructor
+
+ const std::string mName; // name of reader (actually name of writer)
+ /*const*/ Shared* const mShared; // raw pointer to shared memory, actually const but not
+ audio_utils_fifo * const mFifo; // FIFO itself,
+ // non-NULL unless constructor fails
+ audio_utils_fifo_reader * const mFifoReader; // used to read from FIFO,
+ // non-NULL unless constructor fails
+
+ // Searches for the last valid entry in the range [front, back)
+ // back has to be entry-aligned. Returns nullptr if none enconuntered.
+ static const uint8_t *findLastValidEntry(const uint8_t *front, const uint8_t *back,
+ const std::unordered_set<Event> &invalidTypes);
+};
+
+// A snapshot of a readers buffer
+// This is raw data. No analysis has been done on it
+class Snapshot {
+public:
+ ~Snapshot() { delete[] mData; }
+
+ // amount of data lost (given by audio_utils_fifo_reader)
+ size_t lost() const { return mLost; }
+
+ // iterator to beginning of readable segment of snapshot
+ // data between begin and end has valid entries
+ EntryIterator begin() const { return mBegin; }
+
+ // iterator to end of readable segment of snapshot
+ EntryIterator end() const { return mEnd; }
+
+private:
+ Snapshot() = default;
+ explicit Snapshot(size_t bufferSize) : mData(new uint8_t[bufferSize]) {}
+ friend std::unique_ptr<Snapshot> Reader::getSnapshot(bool flush);
+
+ uint8_t * const mData = nullptr;
+ size_t mLost = 0;
+ EntryIterator mBegin;
+ EntryIterator mEnd;
+};
+
+// TODO move this to MediaLogService?
+class DumpReader : public NBLog::Reader {
+public:
+ DumpReader(const void *shared, size_t size, const std::string &name)
+ : Reader(shared, size, name) {}
+ DumpReader(const sp<IMemory>& iMemory, size_t size, const std::string &name)
+ : Reader(iMemory, size, name) {}
+ void dump(int fd, size_t indent = 0);
+private:
+ void handleAuthor(const AbstractEntry& fmtEntry __unused, String8* body __unused) {}
+ EntryIterator handleFormat(const FormatEntry &fmtEntry, String8 *timestamp, String8 *body);
+
+ static void appendInt(String8 *body, const void *data);
+ static void appendFloat(String8 *body, const void *data);
+ static void appendPID(String8 *body, const void *data, size_t length);
+ static void appendTimestamp(String8 *body, const void *data);
+
+ // The bufferDump functions are used for debugging only.
+ static String8 bufferDump(const uint8_t *buffer, size_t size);
+ static String8 bufferDump(const EntryIterator &it);
+};
+
+} // namespace NBLog
+} // namespace android
+
+#endif // ANDROID_MEDIA_NBLOG_READER_H
diff --git a/media/libnblog/include/media/nblog/ReportPerformance.h b/media/libnblog/include/media/nblog/ReportPerformance.h
index 09bb2a0..64a5701 100644
--- a/media/libnblog/include/media/nblog/ReportPerformance.h
+++ b/media/libnblog/include/media/nblog/ReportPerformance.h
@@ -19,23 +19,21 @@
#include <deque>
#include <map>
-#include <memory>
#include <vector>
-namespace Json {
-class Value;
-}
-
namespace android {
-
namespace ReportPerformance {
struct PerformanceData;
-// Dumps performance data to a JSON format.
-// Return by pointer instead of by value to avoid dependency side effects of including
-// the header of an external library.
-std::unique_ptr<Json::Value> dumpToJson(const PerformanceData& data);
+// Dumps performance data in a JSON format.
+void dumpJson(int fd, const std::map<int, PerformanceData>& threadDataMap);
+
+//Dumps performance data as visualized plots.
+void dumpPlots(int fd, const std::map<int, PerformanceData>& threadDataMap);
+
+// Dumps snapshots at important events in the past.
+void dumpRetro(int fd, const std::map<int, PerformanceData>& threadDataMap);
// Send one thread's data to media metrics, if the performance data is nontrivial (i.e. not
// all zero values). Return true if data was sent, false if there is nothing to write
@@ -78,8 +76,7 @@
const std::deque<timestamp> &peakTimestamps,
const char * kDirectory, bool append, int author, log_hash_t hash);
-} // namespace ReportPerformance
-
+} // namespace ReportPerformance
} // namespace android
#endif // ANDROID_MEDIA_REPORTPERFORMANCE_H
diff --git a/media/libnblog/include/media/nblog/Timeline.h b/media/libnblog/include/media/nblog/Timeline.h
new file mode 100644
index 0000000..d4f0cff
--- /dev/null
+++ b/media/libnblog/include/media/nblog/Timeline.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_NBLOG_TIMELINE_H
+#define ANDROID_MEDIA_NBLOG_TIMELINE_H
+
+#include <stddef.h>
+
+#include <audio_utils/fifo_index.h>
+#include <utils/RefBase.h>
+
+namespace android {
+namespace NBLog {
+
+// Located in shared memory, must be POD.
+// Exactly one process must explicitly call the constructor or use placement new.
+// Since this is a POD, the destructor is empty and unnecessary to call it explicitly.
+struct Shared {
+ Shared() /* mRear initialized via default constructor */ {}
+ ~Shared() {}
+
+ audio_utils_fifo_index mRear; // index one byte past the end of most recent Entry
+ char mBuffer[0]; // circular buffer for entries
+};
+
+// FIXME Timeline was intended to wrap Writer and Reader, but isn't actually used yet.
+// For now it is just a namespace for sharedSize().
+class Timeline : public RefBase {
+public:
+#if 0
+ Timeline(size_t size, void *shared = NULL);
+ virtual ~Timeline();
+#endif
+
+ // Input parameter 'size' is the desired size of the timeline in byte units.
+ // Returns the size rounded up to a power-of-2, plus the constant size overhead for indices.
+ static size_t sharedSize(size_t size);
+
+#if 0
+private:
+ friend class Writer;
+ friend class Reader;
+
+ const size_t mSize; // circular buffer size in bytes, must be a power of 2
+ bool mOwn; // whether I own the memory at mShared
+ Shared* const mShared; // pointer to shared memory
+#endif
+};
+
+} // namespace NBLog
+} // namespace android
+
+#endif // ANDROID_MEDIA_NBLOG_TIMELINE_H
diff --git a/media/libnblog/include/media/nblog/Writer.h b/media/libnblog/include/media/nblog/Writer.h
new file mode 100644
index 0000000..7fcd396
--- /dev/null
+++ b/media/libnblog/include/media/nblog/Writer.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_MEDIA_NBLOG_WRITER_H
+#define ANDROID_MEDIA_NBLOG_WRITER_H
+
+#include <stdarg.h>
+#include <stddef.h>
+
+#include <binder/IMemory.h>
+#include <media/nblog/Events.h>
+#include <utils/Mutex.h>
+#include <utils/RefBase.h>
+
+class audio_utils_fifo;
+class audio_utils_fifo_writer;
+
+namespace android {
+
+class IMemory;
+
+namespace NBLog {
+
+class Entry;
+struct Shared;
+
+// NBLog Writer Interface
+
+// Writer is thread-safe with respect to Reader, but not with respect to multiple threads
+// calling Writer methods. If you need multi-thread safety for writing, use LockedWriter.
+class Writer : public RefBase {
+public:
+ Writer() = default; // dummy nop implementation without shared memory
+
+ // Input parameter 'size' is the desired size of the timeline in byte units.
+ // The size of the shared memory must be at least Timeline::sharedSize(size).
+ Writer(void *shared, size_t size);
+ Writer(const sp<IMemory>& iMemory, size_t size);
+
+ ~Writer() override;
+
+ // FIXME needs comments, and some should be private
+ void log(const char *string);
+ void logf(const char *fmt, ...) __attribute__ ((format (printf, 2, 3)));
+ void logTimestamp();
+ void logFormat(const char *fmt, log_hash_t hash, ...);
+ void logEventHistTs(Event event, log_hash_t hash);
+
+ // Log data related to Event E. See the event-to-type mapping for the type of data
+ // corresponding to the event. For example, if you see a mapping statement:
+ // MAP_TYPE_TO_EVENT(E, T);
+ // then the usage of this method would be:
+ // T data = doComputation();
+ // tlNBLogWriter->log<NBLog::E>(data);
+ template<Event E>
+ void log(typename get_mapped<E>::type data) {
+ log(E, &data, sizeof(data));
+ }
+
+ virtual bool isEnabled() const;
+
+ // return value for all of these is the previous isEnabled()
+ virtual bool setEnabled(bool enabled); // but won't enable if no shared memory
+ bool enable() { return setEnabled(true); }
+ bool disable() { return setEnabled(false); }
+
+ sp<IMemory> getIMemory() const { return mIMemory; }
+
+ // Public logging function implementations should always use one of the
+ // two log() function calls below to write to shared memory.
+protected:
+ // Writes a single Entry to the FIFO if the writer is enabled.
+ // This is protected and virtual because LockedWriter uses a lock to protect
+ // writing to the FIFO before writing to this function.
+ virtual void log(const Entry &entry, bool trusted = false);
+
+private:
+ // 0 <= length <= kMaxLength
+ // Log a single Entry with corresponding event, data, and length.
+ void log(Event event, const void *data, size_t length);
+
+ void logvf(const char *fmt, va_list ap);
+
+ // helper functions for logging parts of a formatted entry
+ void logStart(const char *fmt);
+ void logTimestampFormat();
+ void logVFormat(const char *fmt, log_hash_t hash, va_list ap);
+
+ Shared* const mShared{}; // raw pointer to shared memory
+ sp<IMemory> mIMemory{}; // ref-counted version, initialized in constructor
+ // and then const
+ audio_utils_fifo * const mFifo{}; // FIFO itself, non-NULL
+ // unless constructor fails
+ // or dummy constructor used
+ audio_utils_fifo_writer * const mFifoWriter{}; // used to write to FIFO, non-NULL
+ // unless dummy constructor used
+ bool mEnabled = false; // whether to actually log
+
+ // cached pid and process name to use in %p format specifier
+ // total tag length is mPidTagSize and process name is not zero terminated
+ char *mPidTag{};
+ size_t mPidTagSize = 0;
+};
+
+// ---------------------------------------------------------------------------
+
+// Similar to Writer, but safe for multiple threads to call concurrently
+class LockedWriter : public Writer {
+public:
+ LockedWriter() = default;
+ LockedWriter(void *shared, size_t size);
+
+ bool isEnabled() const override;
+ bool setEnabled(bool enabled) override;
+
+private:
+ // Lock needs to be obtained before writing to FIFO.
+ void log(const Entry &entry, bool trusted = false) override;
+
+ mutable Mutex mLock;
+};
+
+} // namespace NBLog
+} // namespace android
+
+#endif // ANDROID_MEDIA_NBLOG_WRITER_H
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index 3526047..b058552 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -1619,7 +1619,7 @@
if (portIndex == kPortIndexOutput && mNativeWindow != NULL) {
(void)cancelBufferToNativeWindow(info);
}
- // fall through
+ FALLTHROUGH_INTENDED;
case BufferInfo::OWNED_BY_NATIVE_WINDOW:
err = mOMXNode->freeBuffer(portIndex, info->mBufferID);
@@ -5019,6 +5019,7 @@
}
}
// Fall through to set up mime.
+ FALLTHROUGH_INTENDED;
}
default:
@@ -5123,6 +5124,7 @@
notify->setString("mime", MEDIA_MIMETYPE_AUDIO_AAC);
notify->setInt32("channel-count", params.nChannels);
notify->setInt32("sample-rate", params.nSampleRate);
+ notify->setInt32("bitrate", params.nBitRate);
break;
}
@@ -5383,7 +5385,7 @@
AudioEncoding pcmEncoding = kAudioEncodingPcm16bit;
(void)mConfigFormat->findInt32("pcm-encoding", (int32_t*)&pcmEncoding);
AudioEncoding codecPcmEncoding = kAudioEncodingPcm16bit;
- (void)mOutputFormat->findInt32("pcm-encoding", (int32_t*)&pcmEncoding);
+ (void)mOutputFormat->findInt32("pcm-encoding", (int32_t*)&codecPcmEncoding);
mConverter[kPortIndexOutput] = AudioConverter::Create(codecPcmEncoding, pcmEncoding);
if (mConverter[kPortIndexOutput] != NULL) {
@@ -7854,7 +7856,7 @@
msg->setInt32("generation", mCodec->mStateGeneration);
msg->post(3000000);
}
- // fall-through
+ FALLTHROUGH_INTENDED;
}
case kWhatResume:
case kWhatSetParameters:
diff --git a/media/libstagefright/Android.bp b/media/libstagefright/Android.bp
index ae2f61b..5eae2b3 100644
--- a/media/libstagefright/Android.bp
+++ b/media/libstagefright/Android.bp
@@ -45,7 +45,7 @@
},
},
- shared_libs: ["libmedia"],
+ shared_libs: ["libmedia", "libmediandk"],
}
cc_library_shared {
@@ -124,6 +124,7 @@
"MediaExtractor.cpp",
"MediaExtractorFactory.cpp",
"MediaSync.cpp",
+ "MediaTrack.cpp",
"http/ClearMediaHTTP.cpp",
"http/MediaHTTP.cpp",
"MediaMuxer.cpp",
@@ -230,7 +231,7 @@
},
}
-cc_library {
+cc_library_static {
name: "libstagefright_player2",
srcs: [
@@ -259,7 +260,6 @@
"libcutils",
"libgui",
"liblog",
- "libmedia_player2_util",
"libaudioclient",
"libmediaextractor",
"libmediametrics",
@@ -274,16 +274,13 @@
static_libs: [
"libstagefright_esds",
+ "libmedia_player2_util",
],
header_libs:[
"media_plugin_headers",
],
- export_shared_lib_headers: [
- "libmedia_player2_util",
- ],
-
export_include_dirs: [
"include",
],
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index c0e65e8..c62c05a 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -501,10 +501,15 @@
return ERROR_MALFORMED;
}
- int32_t width, height, stride;
- CHECK(outputFormat->findInt32("width", &width));
- CHECK(outputFormat->findInt32("height", &height));
- CHECK(outputFormat->findInt32("stride", &stride));
+ int32_t width, height, stride, srcFormat;
+ if (!outputFormat->findInt32("width", &width) ||
+ !outputFormat->findInt32("height", &height) ||
+ !outputFormat->findInt32("stride", &stride) ||
+ !outputFormat->findInt32("color-format", &srcFormat)) {
+ ALOGE("format missing dimension or color: %s",
+ outputFormat->debugString().c_str());
+ return ERROR_MALFORMED;
+ }
int32_t crop_left, crop_top, crop_right, crop_bottom;
if (!outputFormat->findRect("crop", &crop_left, &crop_top, &crop_right, &crop_bottom)) {
@@ -523,9 +528,6 @@
addFrame(frameMem);
VideoFrame* frame = static_cast<VideoFrame*>(frameMem->pointer());
- int32_t srcFormat;
- CHECK(outputFormat->findInt32("color-format", &srcFormat));
-
ColorConverter converter((OMX_COLOR_FORMATTYPE)srcFormat, dstFormat());
uint32_t standard, range, transfer;
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index f91c543..70064ea 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -1829,8 +1829,8 @@
// the shutdown complete notification. If we
// don't, we'll timeout and force release.
sendErrorResponse = false;
+ FALLTHROUGH_INTENDED;
}
- // fall-thru
case STOPPING:
{
if (mFlags & kFlagSawMediaServerDie) {
diff --git a/media/libstagefright/MediaExtractor.cpp b/media/libstagefright/MediaExtractor.cpp
index 5e1dc77..e00c3c8 100644
--- a/media/libstagefright/MediaExtractor.cpp
+++ b/media/libstagefright/MediaExtractor.cpp
@@ -22,6 +22,8 @@
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/MediaExtractor.h>
#include <media/stagefright/MetaData.h>
+#include <media/stagefright/Utils.h>
+#include <media/NdkMediaFormatPriv.h>
namespace android {
@@ -40,42 +42,95 @@
}
// --------------------------------------------------------------------------------
-MediaExtractorCUnwrapper::MediaExtractorCUnwrapper(CMediaExtractor *wrapper) {
- this->wrapper = wrapper;
+MediaExtractorCUnwrapperV1::MediaExtractorCUnwrapperV1(CMediaExtractor *plugin) {
+ this->plugin = plugin;
}
-MediaExtractorCUnwrapper::~MediaExtractorCUnwrapper() {
- wrapper->free(wrapper->data);
- free(wrapper);
+MediaExtractorCUnwrapperV1::~MediaExtractorCUnwrapperV1() {
+ plugin->free(plugin->data);
+ free(plugin);
}
-size_t MediaExtractorCUnwrapper::countTracks() {
- return wrapper->countTracks(wrapper->data);
+size_t MediaExtractorCUnwrapperV1::countTracks() {
+ return plugin->countTracks(plugin->data);
}
-MediaTrack *MediaExtractorCUnwrapper::getTrack(size_t index) {
- return wrapper->getTrack(wrapper->data, index);
+MediaTrack *MediaExtractorCUnwrapperV1::getTrack(size_t index) {
+ return new MediaTrackCUnwrapper(plugin->getTrack(plugin->data, index));
}
-status_t MediaExtractorCUnwrapper::getTrackMetaData(
+status_t MediaExtractorCUnwrapperV1::getTrackMetaData(
MetaDataBase& meta, size_t index, uint32_t flags) {
- return wrapper->getTrackMetaData(wrapper->data, meta, index, flags);
+ return plugin->getTrackMetaData(plugin->data, meta, index, flags);
}
-status_t MediaExtractorCUnwrapper::getMetaData(MetaDataBase& meta) {
- return wrapper->getMetaData(wrapper->data, meta);
+status_t MediaExtractorCUnwrapperV1::getMetaData(MetaDataBase& meta) {
+ return plugin->getMetaData(plugin->data, meta);
}
-const char * MediaExtractorCUnwrapper::name() {
- return wrapper->name(wrapper->data);
+const char * MediaExtractorCUnwrapperV1::name() {
+ return plugin->name(plugin->data);
}
-uint32_t MediaExtractorCUnwrapper::flags() const {
- return wrapper->flags(wrapper->data);
+uint32_t MediaExtractorCUnwrapperV1::flags() const {
+ return plugin->flags(plugin->data);
}
-status_t MediaExtractorCUnwrapper::setMediaCas(const uint8_t* casToken, size_t size) {
- return wrapper->setMediaCas(wrapper->data, casToken, size);
+status_t MediaExtractorCUnwrapperV1::setMediaCas(const uint8_t* casToken, size_t size) {
+ return plugin->setMediaCas(plugin->data, casToken, size);
+}
+
+// --------------------------------------------------------------------------------
+MediaExtractorCUnwrapperV2::MediaExtractorCUnwrapperV2(CMediaExtractorV2 *plugin) {
+ this->plugin = plugin;
+}
+
+MediaExtractorCUnwrapperV2::~MediaExtractorCUnwrapperV2() {
+ plugin->free(plugin->data);
+ free(plugin);
+}
+
+size_t MediaExtractorCUnwrapperV2::countTracks() {
+ return plugin->countTracks(plugin->data);
+}
+
+MediaTrack *MediaExtractorCUnwrapperV2::getTrack(size_t index) {
+ return new MediaTrackCUnwrapperV2(plugin->getTrack(plugin->data, index));
+}
+
+status_t MediaExtractorCUnwrapperV2::getTrackMetaData(
+ MetaDataBase& meta, size_t index, uint32_t flags) {
+ sp<AMessage> msg = new AMessage();
+ AMediaFormat *format = AMediaFormat_fromMsg(&msg);
+ status_t ret = plugin->getTrackMetaData(plugin->data, format, index, flags);
+ sp<MetaData> newMeta = new MetaData();
+ convertMessageToMetaData(msg, newMeta);
+ delete format;
+ meta = *newMeta;
+ return ret;
+}
+
+status_t MediaExtractorCUnwrapperV2::getMetaData(MetaDataBase& meta) {
+ sp<AMessage> msg = new AMessage();
+ AMediaFormat *format = AMediaFormat_fromMsg(&msg);
+ status_t ret = plugin->getMetaData(plugin->data, format);
+ sp<MetaData> newMeta = new MetaData();
+ convertMessageToMetaData(msg, newMeta);
+ delete format;
+ meta = *newMeta;
+ return ret;
+}
+
+const char * MediaExtractorCUnwrapperV2::name() {
+ return plugin->name(plugin->data);
+}
+
+uint32_t MediaExtractorCUnwrapperV2::flags() const {
+ return plugin->flags(plugin->data);
+}
+
+status_t MediaExtractorCUnwrapperV2::setMediaCas(const uint8_t* casToken, size_t size) {
+ return plugin->setMediaCas(plugin->data, casToken, size);
}
} // namespace android
diff --git a/media/libstagefright/MediaExtractorFactory.cpp b/media/libstagefright/MediaExtractorFactory.cpp
index a0a3a75..8f1dd36 100644
--- a/media/libstagefright/MediaExtractorFactory.cpp
+++ b/media/libstagefright/MediaExtractorFactory.cpp
@@ -74,22 +74,32 @@
source->DrmInitialization(nullptr /* mime */);
void *meta = nullptr;
- CreatorFunc creator = NULL;
+ void *creator = NULL;
FreeMetaFunc freeMeta = nullptr;
float confidence;
sp<ExtractorPlugin> plugin;
- creator = sniff(source, &confidence, &meta, &freeMeta, plugin);
+ uint32_t creatorVersion = 0;
+ creator = sniff(source, &confidence, &meta, &freeMeta, plugin, &creatorVersion);
if (!creator) {
ALOGV("FAILED to autodetect media content.");
return NULL;
}
- CMediaExtractor *ret = creator(source->wrap(), meta);
- if (meta != nullptr && freeMeta != nullptr) {
- freeMeta(meta);
+ MediaExtractor *ex = nullptr;
+ if (creatorVersion == 1) {
+ CMediaExtractor *ret = ((CreatorFuncV1)creator)(source->wrap(), meta);
+ if (meta != nullptr && freeMeta != nullptr) {
+ freeMeta(meta);
+ }
+ ex = ret != nullptr ? new MediaExtractorCUnwrapperV1(ret) : nullptr;
+ } else if (creatorVersion == 2) {
+ CMediaExtractorV2 *ret = ((CreatorFuncV2)creator)(source->wrap(), meta);
+ if (meta != nullptr && freeMeta != nullptr) {
+ freeMeta(meta);
+ }
+ ex = ret != nullptr ? new MediaExtractorCUnwrapperV2(ret) : nullptr;
}
- MediaExtractor *ex = ret != nullptr ? new MediaExtractorCUnwrapper(ret) : nullptr;
ALOGV("Created an extractor '%s' with confidence %.2f",
ex != nullptr ? ex->name() : "<null>", confidence);
@@ -129,9 +139,9 @@
bool MediaExtractorFactory::gIgnoreVersion = false;
// static
-CreatorFunc MediaExtractorFactory::sniff(
+void *MediaExtractorFactory::sniff(
const sp<DataSource> &source, float *confidence, void **meta,
- FreeMetaFunc *freeMeta, sp<ExtractorPlugin> &plugin) {
+ FreeMetaFunc *freeMeta, sp<ExtractorPlugin> &plugin, uint32_t *creatorVersion) {
*confidence = 0.0f;
*meta = nullptr;
@@ -144,15 +154,23 @@
plugins = gPlugins;
}
- CreatorFunc curCreator = NULL;
- CreatorFunc bestCreator = NULL;
+ void *bestCreator = NULL;
for (auto it = plugins->begin(); it != plugins->end(); ++it) {
ALOGV("sniffing %s", (*it)->def.extractor_name);
float newConfidence;
void *newMeta = nullptr;
FreeMetaFunc newFreeMeta = nullptr;
- if ((curCreator = (*it)->def.sniff(
- source->wrap(), &newConfidence, &newMeta, &newFreeMeta))) {
+
+ void *curCreator = NULL;
+ if ((*it)->def.def_version == 1) {
+ curCreator = (void*) (*it)->def.sniff.v1(
+ source->wrap(), &newConfidence, &newMeta, &newFreeMeta);
+ } else if ((*it)->def.def_version == 2) {
+ curCreator = (void*) (*it)->def.sniff.v2(
+ source->wrap(), &newConfidence, &newMeta, &newFreeMeta);
+ }
+
+ if (curCreator) {
if (newConfidence > *confidence) {
*confidence = newConfidence;
if (*meta != nullptr && *freeMeta != nullptr) {
@@ -162,6 +180,7 @@
*freeMeta = newFreeMeta;
plugin = *it;
bestCreator = curCreator;
+ *creatorVersion = (*it)->def.def_version;
} else {
if (newMeta != nullptr && newFreeMeta != nullptr) {
newFreeMeta(newMeta);
@@ -178,7 +197,7 @@
std::list<sp<ExtractorPlugin>> &pluginList) {
// sanity check check struct version, uuid, name
if (plugin->def.def_version == 0
- || plugin->def.def_version > EXTRACTORDEF_VERSION) {
+ || plugin->def.def_version > EXTRACTORDEF_VERSION_CURRENT) {
ALOGE("don't understand extractor format %u, ignoring.", plugin->def.def_version);
return;
}
@@ -271,6 +290,9 @@
if (libDir) {
struct dirent* libEntry;
while ((libEntry = readdir(libDir))) {
+ if (libEntry->d_name[0] == '.') {
+ continue;
+ }
String8 libPath = String8(libDirPath) + "/" + libEntry->d_name;
void *libHandle = dlopen(libPath.string(), RTLD_NOW | RTLD_LOCAL);
if (libHandle) {
@@ -334,8 +356,9 @@
out.append("Available extractors:\n");
if (gPluginsRegistered) {
for (auto it = gPlugins->begin(); it != gPlugins->end(); ++it) {
- out.appendFormat(" %25s: uuid(%s), version(%u), path(%s)\n",
+ out.appendFormat(" %25s: plugin_version(%d), uuid(%s), version(%u), path(%s)\n",
(*it)->def.extractor_name,
+ (*it)->def.def_version,
(*it)->uuidString.c_str(),
(*it)->def.extractor_version,
(*it)->libPath.c_str());
diff --git a/media/libstagefright/MediaTrack.cpp b/media/libstagefright/MediaTrack.cpp
new file mode 100644
index 0000000..4bd8a51
--- /dev/null
+++ b/media/libstagefright/MediaTrack.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (C) 2009 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.
+ */
+
+#include <mutex>
+
+#include <media/stagefright/foundation/AMessage.h>
+#include <media/stagefright/Utils.h>
+
+#include <media/MediaTrack.h>
+#include <media/MediaExtractorPluginApi.h>
+#include <media/NdkMediaFormatPriv.h>
+
+namespace android {
+
+MediaTrack::MediaTrack() {}
+
+MediaTrack::~MediaTrack() {}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void MediaTrack::ReadOptions::setNonBlocking() {
+ mNonBlocking = true;
+}
+
+void MediaTrack::ReadOptions::clearNonBlocking() {
+ mNonBlocking = false;
+}
+
+bool MediaTrack::ReadOptions::getNonBlocking() const {
+ return mNonBlocking;
+}
+
+void MediaTrack::ReadOptions::setSeekTo(int64_t time_us, SeekMode mode) {
+ mOptions |= kSeekTo_Option;
+ mSeekTimeUs = time_us;
+ mSeekMode = mode;
+}
+
+bool MediaTrack::ReadOptions::getSeekTo(
+ int64_t *time_us, SeekMode *mode) const {
+ *time_us = mSeekTimeUs;
+ *mode = mSeekMode;
+ return (mOptions & kSeekTo_Option) != 0;
+}
+
+/* -------------- unwrapper v1 --------------- */
+
+MediaTrackCUnwrapper::MediaTrackCUnwrapper(CMediaTrack *cmediatrack) {
+ wrapper = cmediatrack;
+}
+
+MediaTrackCUnwrapper::~MediaTrackCUnwrapper() {
+ wrapper->free(wrapper->data);
+ free(wrapper);
+}
+
+status_t MediaTrackCUnwrapper::start() {
+ return wrapper->start(wrapper->data);
+}
+
+status_t MediaTrackCUnwrapper::stop() {
+ return wrapper->stop(wrapper->data);
+}
+
+status_t MediaTrackCUnwrapper::getFormat(MetaDataBase& format) {
+ return wrapper->getFormat(wrapper->data, format);
+}
+
+status_t MediaTrackCUnwrapper::read(MediaBufferBase **buffer, const ReadOptions *options) {
+
+ uint32_t opts = 0;
+
+ if (options && options->getNonBlocking()) {
+ opts |= CMediaTrackReadOptions::NONBLOCKING;
+ }
+
+ int64_t seekPosition = 0;
+ MediaTrack::ReadOptions::SeekMode seekMode;
+ if (options && options->getSeekTo(&seekPosition, &seekMode)) {
+ opts |= SEEK;
+ opts |= (uint32_t) seekMode;
+ }
+
+
+ return wrapper->read(wrapper->data, buffer, opts, seekPosition);
+}
+
+bool MediaTrackCUnwrapper::supportNonblockingRead() {
+ return wrapper->supportsNonBlockingRead(wrapper->data);
+}
+
+/* -------------- unwrapper v2 --------------- */
+
+MediaTrackCUnwrapperV2::MediaTrackCUnwrapperV2(CMediaTrackV2 *cmediatrack2) {
+ wrapper = cmediatrack2;
+}
+
+MediaTrackCUnwrapperV2::~MediaTrackCUnwrapperV2() {
+}
+
+status_t MediaTrackCUnwrapperV2::start() {
+ return wrapper->start(wrapper->data);
+}
+
+status_t MediaTrackCUnwrapperV2::stop() {
+ return wrapper->stop(wrapper->data);
+}
+
+status_t MediaTrackCUnwrapperV2::getFormat(MetaDataBase& format) {
+ sp<AMessage> msg = new AMessage();
+ AMediaFormat *tmpFormat = AMediaFormat_fromMsg(&msg);
+ status_t ret = wrapper->getFormat(wrapper->data, tmpFormat);
+ sp<MetaData> newMeta = new MetaData();
+ convertMessageToMetaData(msg, newMeta);
+ delete tmpFormat;
+ format = *newMeta;
+ return ret;
+}
+
+status_t MediaTrackCUnwrapperV2::read(MediaBufferBase **buffer, const ReadOptions *options) {
+
+ uint32_t opts = 0;
+
+ if (options->getNonBlocking()) {
+ opts |= CMediaTrackReadOptions::NONBLOCKING;
+ }
+
+ int64_t seekPosition = 0;
+ MediaTrack::ReadOptions::SeekMode seekMode;
+ if (options->getSeekTo(&seekPosition, &seekMode)) {
+ opts |= SEEK;
+ opts |= (uint32_t) seekMode;
+ }
+
+ return wrapper->read(wrapper->data, buffer, opts, seekPosition);
+}
+
+bool MediaTrackCUnwrapperV2::supportNonblockingRead() {
+ return wrapper->supportsNonBlockingRead(wrapper->data);
+}
+
+} // namespace android
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
index 2475e7b..5672145 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -23,6 +23,8 @@
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataUtils.h>
+#include <media/stagefright/Utils.h>
+#include <media/NdkMediaFormat.h>
namespace android {
@@ -91,20 +93,21 @@
}
bool MakeAACCodecSpecificData(
- MetaDataBase &meta,
- unsigned profile, unsigned sampling_freq_index,
- unsigned channel_configuration) {
+ uint8_t *csd, /* out */
+ size_t *esds_size, /* in/out */
+ unsigned profile, /* in */
+ unsigned sampling_freq_index, /* in */
+ unsigned channel_configuration, /* in */
+ int32_t *sampling_rate /* out */
+) {
if(sampling_freq_index > 11u) {
return false;
}
- int32_t sampleRate;
- int32_t channelCount;
static const int32_t kSamplingFreq[] = {
96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
16000, 12000, 11025, 8000
};
- sampleRate = kSamplingFreq[sampling_freq_index];
- channelCount = channel_configuration;
+ *sampling_rate = kSamplingFreq[sampling_freq_index];
static const uint8_t kStaticESDS[] = {
0x03, 22,
@@ -127,7 +130,9 @@
};
size_t csdSize = sizeof(kStaticESDS) + 2;
- uint8_t *csd = new uint8_t[csdSize];
+ if (csdSize > *esds_size) {
+ return false;
+ }
memcpy(csd, kStaticESDS, sizeof(kStaticESDS));
csd[sizeof(kStaticESDS)] =
@@ -136,13 +141,54 @@
csd[sizeof(kStaticESDS) + 1] =
((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
+ *esds_size = csdSize;
+ return true;
+}
+
+bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
+ unsigned channel_configuration) {
+
+ if(sampling_freq_index > 11u) {
+ return false;
+ }
+
+ uint8_t csd[2];
+ csd[0] = ((profile + 1) << 3) | (sampling_freq_index >> 1);
+ csd[1] = ((sampling_freq_index << 7) & 0x80) | (channel_configuration << 3);
+
+ static const int32_t kSamplingFreq[] = {
+ 96000, 88200, 64000, 48000, 44100, 32000, 24000, 22050,
+ 16000, 12000, 11025, 8000
+ };
+ int32_t sampleRate = kSamplingFreq[sampling_freq_index];
+
+ AMediaFormat_setBuffer(meta, AMEDIAFORMAT_KEY_CSD_0, csd, sizeof(csd));
+ AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_AUDIO_AAC);
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_SAMPLE_RATE, sampleRate);
+ AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, channel_configuration);
+
+ return true;
+}
+
+bool MakeAACCodecSpecificData(
+ MetaDataBase &meta,
+ unsigned profile, unsigned sampling_freq_index,
+ unsigned channel_configuration) {
+
+ uint8_t csd[24];
+ size_t csdSize = sizeof(csd);
+ int32_t sampleRate;
+
+ if (!MakeAACCodecSpecificData(csd, &csdSize, profile, sampling_freq_index,
+ channel_configuration, &sampleRate)) {
+ return false;
+ }
+
meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AAC);
meta.setInt32(kKeySampleRate, sampleRate);
- meta.setInt32(kKeyChannelCount, channelCount);
-
+ meta.setInt32(kKeyChannelCount, channel_configuration);
meta.setData(kKeyESDS, 0, csd, csdSize);
- delete [] csd;
return true;
}
diff --git a/media/libstagefright/NuCachedSource2.cpp b/media/libstagefright/NuCachedSource2.cpp
index 18f4b12..7025af7 100644
--- a/media/libstagefright/NuCachedSource2.cpp
+++ b/media/libstagefright/NuCachedSource2.cpp
@@ -256,6 +256,10 @@
return ERROR_UNSUPPORTED;
}
+void NuCachedSource2::close() {
+ disconnect();
+}
+
void NuCachedSource2::disconnect() {
if (mSource->flags() & kIsHTTPBasedSource) {
ALOGV("disconnecting HTTPBasedSource");
@@ -567,12 +571,19 @@
return mCacheOffset + mCache->totalSize();
}
-size_t NuCachedSource2::approxDataRemaining(status_t *finalStatus) const {
+status_t NuCachedSource2::getAvailableSize(off64_t offset, off64_t *size) {
Mutex::Autolock autoLock(mLock);
- return approxDataRemaining_l(finalStatus);
+ status_t finalStatus = UNKNOWN_ERROR;
+ *size = approxDataRemaining_l(offset, &finalStatus);
+ return finalStatus;
}
-size_t NuCachedSource2::approxDataRemaining_l(status_t *finalStatus) const {
+size_t NuCachedSource2::approxDataRemaining(status_t *finalStatus) const {
+ Mutex::Autolock autoLock(mLock);
+ return approxDataRemaining_l(mLastAccessPos, finalStatus);
+}
+
+size_t NuCachedSource2::approxDataRemaining_l(off64_t offset, status_t *finalStatus) const {
*finalStatus = mFinalStatus;
if (mFinalStatus != OK && mNumRetriesLeft > 0) {
@@ -580,9 +591,10 @@
*finalStatus = OK;
}
+ offset = offset >= 0 ? offset : mLastAccessPos;
off64_t lastBytePosCached = mCacheOffset + mCache->totalSize();
- if (mLastAccessPos < lastBytePosCached) {
- return lastBytePosCached - mLastAccessPos;
+ if (offset < lastBytePosCached) {
+ return lastBytePosCached - offset;
}
return 0;
}
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 8e8c77c..f94648c 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -21,7 +21,6 @@
#include <media/stagefright/NuMediaExtractor.h>
#include "include/ESDS.h"
-#include "include/NuCachedSource2.h"
#include <media/DataSource.h>
#include <media/MediaSource.h>
@@ -205,15 +204,6 @@
return OK;
}
-void NuMediaExtractor::disconnect() {
- if (mDataSource != NULL) {
- // disconnect data source
- if (mDataSource->flags() & DataSource::kIsCachingDataSource) {
- static_cast<NuCachedSource2 *>(mDataSource.get())->disconnect();
- }
- }
-}
-
status_t NuMediaExtractor::updateDurationAndBitrate() {
if (mImpl->countTracks() > kMaxTrackCount) {
return ERROR_UNSUPPORTED;
@@ -790,16 +780,12 @@
int64_t *durationUs, bool *eos) const {
Mutex::Autolock autoLock(mLock);
+ off64_t cachedDataRemaining = -1;
+ status_t finalStatus = mDataSource->getAvailableSize(-1, &cachedDataRemaining);
+
int64_t bitrate;
- if ((mDataSource->flags() & DataSource::kIsCachingDataSource)
+ if (cachedDataRemaining >= 0
&& getTotalBitrate(&bitrate)) {
- sp<NuCachedSource2> cachedSource =
- static_cast<NuCachedSource2 *>(mDataSource.get());
-
- status_t finalStatus;
- size_t cachedDataRemaining =
- cachedSource->approxDataRemaining(&finalStatus);
-
*durationUs = cachedDataRemaining * 8000000ll / bitrate;
*eos = (finalStatus != OK);
return true;
diff --git a/media/libstagefright/RemoteMediaSource.cpp b/media/libstagefright/RemoteMediaSource.cpp
index e549fcf..db31af2 100644
--- a/media/libstagefright/RemoteMediaSource.cpp
+++ b/media/libstagefright/RemoteMediaSource.cpp
@@ -25,25 +25,29 @@
MediaTrack *source,
const sp<RefBase> &plugin)
: mExtractor(extractor),
- mSource(source),
+ mTrack(source),
mExtractorPlugin(plugin) {}
RemoteMediaSource::~RemoteMediaSource() {
- delete mSource;
+ delete mTrack;
mExtractorPlugin = nullptr;
}
status_t RemoteMediaSource::start(MetaData *params) {
- return mSource->start(params);
+ if (params) {
+ ALOGW("dropping start parameters:");
+ params->dumpToLog();
+ }
+ return mTrack->start();
}
status_t RemoteMediaSource::stop() {
- return mSource->stop();
+ return mTrack->stop();
}
sp<MetaData> RemoteMediaSource::getFormat() {
sp<MetaData> meta = new MetaData();
- if (mSource->getFormat(*meta.get()) == OK) {
+ if (mTrack->getFormat(*meta.get()) == OK) {
return meta;
}
return nullptr;
@@ -51,11 +55,11 @@
status_t RemoteMediaSource::read(
MediaBufferBase **buffer, const MediaSource::ReadOptions *options) {
- return mSource->read(buffer, reinterpret_cast<const MediaSource::ReadOptions*>(options));
+ return mTrack->read(buffer, reinterpret_cast<const MediaSource::ReadOptions*>(options));
}
bool RemoteMediaSource::supportNonblockingRead() {
- return mSource->supportNonblockingRead();
+ return mTrack->supportNonblockingRead();
}
status_t RemoteMediaSource::pause() {
diff --git a/media/libstagefright/StagefrightMetadataRetriever.cpp b/media/libstagefright/StagefrightMetadataRetriever.cpp
index be01a7d..231d540 100644
--- a/media/libstagefright/StagefrightMetadataRetriever.cpp
+++ b/media/libstagefright/StagefrightMetadataRetriever.cpp
@@ -342,15 +342,15 @@
for (size_t i = 0; i < matchingCodecs.size(); ++i) {
const AString &componentName = matchingCodecs[i];
- VideoFrameDecoder decoder(componentName, trackMeta, source);
- if (decoder.init(timeUs, numFrames, option, colorFormat) == OK) {
+ sp<VideoFrameDecoder> decoder = new VideoFrameDecoder(componentName, trackMeta, source);
+ if (decoder->init(timeUs, numFrames, option, colorFormat) == OK) {
if (outFrame != NULL) {
- *outFrame = decoder.extractFrame();
+ *outFrame = decoder->extractFrame();
if (*outFrame != NULL) {
return OK;
}
} else if (outFrames != NULL) {
- status_t err = decoder.extractFrames(outFrames);
+ status_t err = decoder->extractFrames(outFrames);
if (err == OK) {
return OK;
}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index ada37a6..ebc3b33 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -74,7 +74,7 @@
}
#endif
-static void convertMetaDataToMessageColorAspects(const sp<MetaData> &meta, sp<AMessage> &msg) {
+static void convertMetaDataToMessageColorAspects(const MetaDataBase *meta, sp<AMessage> &msg) {
// 0 values are unspecified
int32_t range = 0;
int32_t primaries = 0;
@@ -568,8 +568,14 @@
}
}
+
status_t convertMetaDataToMessage(
const sp<MetaData> &meta, sp<AMessage> *format) {
+ return convertMetaDataToMessage(meta.get(), format);
+}
+
+status_t convertMetaDataToMessage(
+ const MetaDataBase *meta, sp<AMessage> *format) {
format->clear();
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
index bc0a69f..d393c7a 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.cpp
@@ -147,7 +147,7 @@
mEndOfOutput = false;
mOutputDelayCompensated = 0;
mOutputDelayRingBufferSize = 2048 * MAX_CHANNEL_COUNT * kNumDelayBlocksMax;
- mOutputDelayRingBuffer = new short[mOutputDelayRingBufferSize];
+ mOutputDelayRingBuffer = new int16_t[mOutputDelayRingBufferSize];
mOutputDelayRingBufferWritePos = 0;
mOutputDelayRingBufferReadPos = 0;
mOutputDelayRingBufferFilled = 0;
diff --git a/media/libstagefright/codecs/aacdec/SoftAAC2.h b/media/libstagefright/codecs/aacdec/SoftAAC2.h
index 73a3965..5bee710 100644
--- a/media/libstagefright/codecs/aacdec/SoftAAC2.h
+++ b/media/libstagefright/codecs/aacdec/SoftAAC2.h
@@ -81,7 +81,7 @@
bool mEndOfOutput;
int32_t mOutputDelayCompensated;
int32_t mOutputDelayRingBufferSize;
- short *mOutputDelayRingBuffer;
+ int16_t *mOutputDelayRingBuffer;
int32_t mOutputDelayRingBufferWritePos;
int32_t mOutputDelayRingBufferReadPos;
int32_t mOutputDelayRingBufferFilled;
diff --git a/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp b/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp
index b8cfefa..ddc818e 100644
--- a/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp
+++ b/media/libstagefright/codecs/amrwb/src/pvamrwbdecoder.cpp
@@ -455,7 +455,7 @@
&exc2[i_subfr],
0,
&synth16k[i_subfr *5/4],
- (short) 1,
+ 1,
HfIsf,
nb_bits,
newDTXState,
diff --git a/media/libstagefright/codecs/common/include/voType.h b/media/libstagefright/codecs/common/include/voType.h
index da208d4..73f24d0 100644
--- a/media/libstagefright/codecs/common/include/voType.h
+++ b/media/libstagefright/codecs/common/include/voType.h
@@ -22,6 +22,8 @@
#ifndef __voType_H__
#define __voType_H__
+#include <stdint.h>
+
#ifdef __cplusplus
extern "C" {
#endif /* __cplusplus */
@@ -62,28 +64,28 @@
typedef void VO_VOID;
/** VO_U8 is an 8 bit unsigned quantity that is byte aligned */
-typedef unsigned char VO_U8;
+typedef uint8_t VO_U8;
/** VO_BYTE is an 8 bit unsigned quantity that is byte aligned */
-typedef unsigned char VO_BYTE;
+typedef uint8_t VO_BYTE;
/** VO_S8 is an 8 bit signed quantity that is byte aligned */
-typedef signed char VO_S8;
+typedef int8_t VO_S8;
/** VO_CHAR is an 8 bit signed quantity that is byte aligned */
-typedef char VO_CHAR;
+typedef int8_t VO_CHAR;
/** VO_U16 is a 16 bit unsigned quantity that is 16 bit word aligned */
-typedef unsigned short VO_U16;
+typedef uint16_t VO_U16;
/** VO_S16 is a 16 bit signed quantity that is 16 bit word aligned */
-typedef signed short VO_S16;
+typedef int16_t VO_S16;
/** VO_U32 is a 32 bit unsigned quantity that is 32 bit word aligned */
-typedef unsigned long VO_U32;
+typedef uint32_t VO_U32;
/** VO_S32 is a 32 bit signed quantity that is 32 bit word aligned */
-typedef signed long VO_S32;
+typedef int32_t VO_S32;
/* Users with compilers that cannot accept the "long long" designation should
define the VO_SKIP64BIT macro. It should be noted that this may cause
@@ -94,14 +96,14 @@
#ifndef VO_SKIP64BIT
#ifdef _MSC_VER
/** VO_U64 is a 64 bit unsigned quantity that is 64 bit word aligned */
-typedef unsigned __int64 VO_U64;
+typedef uint64_t VO_U64;
/** VO_S64 is a 64 bit signed quantity that is 64 bit word aligned */
-typedef signed __int64 VO_S64;
+typedef int64_t VO_S64;
#else // WIN32
/** VO_U64 is a 64 bit unsigned quantity that is 64 bit word aligned */
-typedef unsigned long long VO_U64;
+typedef uint64_t VO_U64;
/** VO_S64 is a 64 bit signed quantity that is 64 bit word aligned */
-typedef signed long long VO_S64;
+typedef int64_t VO_S64;
#endif // WIN32
#endif // VO_SKIP64BIT
diff --git a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
index 2c0f224..4db0060 100644
--- a/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
+++ b/media/libstagefright/codecs/flac/dec/SoftFlacDecoder.cpp
@@ -305,7 +305,7 @@
while ((!inQueue.empty() || mSawInputEOS) && !outQueue.empty() && !mFinishedDecoder) {
BufferInfo *outInfo = *outQueue.begin();
OMX_BUFFERHEADERTYPE *outHeader = outInfo->mHeader;
- short *outBuffer = reinterpret_cast<short *>(outHeader->pBuffer + outHeader->nOffset);
+ int16_t *outBuffer = reinterpret_cast<int16_t *>(outHeader->pBuffer + outHeader->nOffset);
size_t outBufferSize = outHeader->nAllocLen - outHeader->nOffset;
int64_t timeStamp = 0;
diff --git a/media/libstagefright/codecs/flac/enc/Android.bp b/media/libstagefright/codecs/flac/enc/Android.bp
index 46b974d..73f0dac 100644
--- a/media/libstagefright/codecs/flac/enc/Android.bp
+++ b/media/libstagefright/codecs/flac/enc/Android.bp
@@ -30,6 +30,7 @@
"liblog",
],
+ header_libs: ["libbase_headers"],
static_libs: ["libFLAC"],
name: "libstagefright_soft_flacenc",
diff --git a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
index fdc8975..955f211 100644
--- a/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
+++ b/media/libstagefright/codecs/flac/enc/SoftFlacEncoder.cpp
@@ -16,6 +16,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "SoftFlacEncoder"
+#include <android-base/macros.h>
#include <utils/Log.h>
#include "SoftFlacEncoder.h"
@@ -335,7 +336,7 @@
}
}
- // fall through
+ FALLTHROUGH_INTENDED;
}
default:
diff --git a/media/libstagefright/codecs/m4v_h263/enc/include/mp4enc_api.h b/media/libstagefright/codecs/m4v_h263/enc/include/mp4enc_api.h
index 9451479..d5a3ff1 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/include/mp4enc_api.h
+++ b/media/libstagefright/codecs/m4v_h263/enc/include/mp4enc_api.h
@@ -18,16 +18,17 @@
#ifndef _MP4ENC_API_H_
#define _MP4ENC_API_H_
+#include <stdint.h>
#include <string.h>
#ifndef _PV_TYPES_
#define _PV_TYPES_
-typedef unsigned char UChar;
-typedef char Char;
+typedef uint8_t UChar;
+typedef int8_t Char;
typedef unsigned int UInt;
typedef int Int;
-typedef unsigned short UShort;
-typedef short Short;
+typedef uint16_t UShort;
+typedef int16_t Short;
typedef unsigned int Bool;
typedef uint32_t ULong;
diff --git a/media/libstagefright/codecs/m4v_h263/enc/src/mp4def.h b/media/libstagefright/codecs/m4v_h263/enc/src/mp4def.h
index 2d44482..dbd70dc 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/src/mp4def.h
+++ b/media/libstagefright/codecs/m4v_h263/enc/src/mp4def.h
@@ -52,13 +52,13 @@
#ifndef _PV_TYPES_
#define _PV_TYPES_
-typedef unsigned char UChar;
-typedef char Char;
+typedef uint8_t UChar;
+typedef int8_t Char;
typedef unsigned int UInt;
typedef int Int;
-typedef unsigned short UShort;
-typedef short Short;
-typedef short int SInt;
+typedef uint16_t UShort;
+typedef int16_t Short;
+typedef int16_t SInt;
typedef unsigned int Bool;
typedef uint32_t ULong;
typedef void Void;
diff --git a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
index f6257b1..2dfba13 100644
--- a/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
+++ b/media/libstagefright/codecs/on2/enc/SoftVPXEncoder.cpp
@@ -21,6 +21,7 @@
#include "SoftVP8Encoder.h"
#include "SoftVP9Encoder.h"
+#include <android-base/macros.h>
#include <utils/Log.h>
#include <utils/misc.h>
@@ -557,7 +558,7 @@
break;
case kTemporalUpdateGoldenWithoutDependency:
flags |= VP8_EFLAG_NO_REF_GF;
- // Deliberately no break here.
+ FALLTHROUGH_INTENDED;
case kTemporalUpdateGolden:
flags |= VP8_EFLAG_NO_REF_ARF;
flags |= VP8_EFLAG_NO_UPD_ARF;
@@ -566,14 +567,14 @@
case kTemporalUpdateAltrefWithoutDependency:
flags |= VP8_EFLAG_NO_REF_ARF;
flags |= VP8_EFLAG_NO_REF_GF;
- // Deliberately no break here.
+ FALLTHROUGH_INTENDED;
case kTemporalUpdateAltref:
flags |= VP8_EFLAG_NO_UPD_GF;
flags |= VP8_EFLAG_NO_UPD_LAST;
break;
case kTemporalUpdateNoneNoRefAltref:
flags |= VP8_EFLAG_NO_REF_ARF;
- // Deliberately no break here.
+ FALLTHROUGH_INTENDED;
case kTemporalUpdateNone:
flags |= VP8_EFLAG_NO_UPD_GF;
flags |= VP8_EFLAG_NO_UPD_ARF;
diff --git a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
index 8912f8a..d534f64 100644
--- a/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
+++ b/media/libstagefright/codecs/vorbis/dec/SoftVorbis.cpp
@@ -548,11 +548,21 @@
// Make sure that the next buffer output does not still
// depend on fragments from the last one decoded.
+ mInputBufferCount = 0;
mNumFramesOutput = 0;
+ if (mState != NULL) {
+ vorbis_dsp_clear(mState);
+ delete mState;
+ mState = NULL;
+ }
+ if (mVi != NULL) {
+ vorbis_info_clear(mVi);
+ delete mVi;
+ mVi = NULL;
+ }
mSawInputEos = false;
mSignalledOutputEos = false;
mNumFramesLeftOnPage = -1;
- vorbis_dsp_restart(mState);
}
}
diff --git a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
index 06b15b3..f352fba 100644
--- a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
+++ b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
@@ -79,7 +79,7 @@
static const OMX_U32 kSupportedProfiles[] = {
OMX_AUDIO_AACObjectLC, OMX_AUDIO_AACObjectHE, OMX_AUDIO_AACObjectHE_PS,
- OMX_AUDIO_AACObjectLD, OMX_AUDIO_AACObjectELD,
+ OMX_AUDIO_AACObjectLD, OMX_AUDIO_AACObjectELD, OMX_AUDIO_AACObjectXHE
};
SoftXAAC::SoftXAAC(const char* name, const OMX_CALLBACKTYPE* callbacks, OMX_PTR appData,
diff --git a/media/libstagefright/colorconversion/ColorConverter.cpp b/media/libstagefright/colorconversion/ColorConverter.cpp
index 862cc63..86bd9d6 100644
--- a/media/libstagefright/colorconversion/ColorConverter.cpp
+++ b/media/libstagefright/colorconversion/ColorConverter.cpp
@@ -16,6 +16,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "ColorConverter"
+#include <android-base/macros.h>
#include <utils/Log.h>
#include <media/stagefright/foundation/ADebug.h>
@@ -82,7 +83,7 @@
if (mDstFormat == OMX_COLOR_FormatYUV444Y410) {
return true;
}
- // fall-thru
+ FALLTHROUGH_INTENDED;
case OMX_COLOR_FormatYUV420Planar:
return mDstFormat == OMX_COLOR_Format16bitRGB565
|| mDstFormat == OMX_COLOR_Format32BitRGBA8888
diff --git a/media/libstagefright/flac/dec/FLACDecoder.cpp b/media/libstagefright/flac/dec/FLACDecoder.cpp
index a2b6ab7..dfdc41c 100644
--- a/media/libstagefright/flac/dec/FLACDecoder.cpp
+++ b/media/libstagefright/flac/dec/FLACDecoder.cpp
@@ -120,7 +120,7 @@
// Copy samples from FLAC native 32-bit non-interleaved to 16-bit interleaved.
// These are candidates for optimization if needed.
static void copyMono8(
- short *dst,
+ int16_t *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -130,7 +130,7 @@
}
static void copyStereo8(
- short *dst,
+ int16_t *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -141,7 +141,7 @@
}
static void copyMultiCh8(
- short *dst,
+ int16_t *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned nChannels) {
@@ -153,7 +153,7 @@
}
static void copyMono16(
- short *dst,
+ int16_t *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -163,7 +163,7 @@
}
static void copyStereo16(
- short *dst,
+ int16_t *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -174,7 +174,7 @@
}
static void copyMultiCh16(
- short *dst,
+ int16_t *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned nChannels) {
@@ -187,7 +187,7 @@
// TODO: 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
static void copyMono24(
- short *dst,
+ int16_t *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -197,7 +197,7 @@
}
static void copyStereo24(
- short *dst,
+ int16_t *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -208,7 +208,7 @@
}
static void copyMultiCh24(
- short *dst,
+ int16_t *dst,
const int * src[FLACDecoder::kMaxChannels],
unsigned nSamples,
unsigned nChannels) {
@@ -391,7 +391,7 @@
static const struct {
unsigned mChannels;
unsigned mBitsPerSample;
- void (*mCopy)(short *dst, const int * src[kMaxChannels],
+ void (*mCopy)(int16_t *dst, const int * src[kMaxChannels],
unsigned nSamples, unsigned nChannels);
} table[] = {
{ 1, 8, copyMono8 },
@@ -420,7 +420,7 @@
}
status_t FLACDecoder::decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen,
- short *outBuffer, size_t *outBufferLen) {
+ int16_t *outBuffer, size_t *outBufferLen) {
ALOGV("decodeOneFrame: input size(%zu)", inBufferLen);
if (!mStreamInfoValid) {
@@ -469,12 +469,12 @@
return ERROR_MALFORMED;
}
- size_t bufferSize = blocksize * getChannels() * sizeof(short);
+ size_t bufferSize = blocksize * getChannels() * sizeof(int16_t);
if (bufferSize > *outBufferLen) {
ALOGW("decodeOneFrame: output buffer holds only partial frame %zu:%zu",
*outBufferLen, bufferSize);
- blocksize = *outBufferLen / (getChannels() * sizeof(short));
- bufferSize = blocksize * getChannels() * sizeof(short);
+ blocksize = *outBufferLen / (getChannels() * sizeof(int16_t));
+ bufferSize = blocksize * getChannels() * sizeof(int16_t);
}
if (mCopy == nullptr) {
diff --git a/media/libstagefright/flac/dec/FLACDecoder.h b/media/libstagefright/flac/dec/FLACDecoder.h
index 1a33cae..af419a2 100644
--- a/media/libstagefright/flac/dec/FLACDecoder.h
+++ b/media/libstagefright/flac/dec/FLACDecoder.h
@@ -41,7 +41,7 @@
status_t parseMetadata(const uint8_t *inBuffer, size_t inBufferLen);
status_t decodeOneFrame(const uint8_t *inBuffer, size_t inBufferLen,
- short *outBuffer, size_t *outBufferLen);
+ int16_t *outBuffer, size_t *outBufferLen);
void flush();
virtual ~FLACDecoder();
@@ -89,7 +89,7 @@
// most recent error reported by libFLAC decoder
FLAC__StreamDecoderErrorStatus mErrorStatus;
- void (*mCopy)(short *dst, const int *src[kMaxChannels], unsigned nSamples, unsigned nChannels);
+ void (*mCopy)(int16_t *dst, const int *src[kMaxChannels], unsigned nSamples, unsigned nChannels);
status_t init();
diff --git a/media/libstagefright/foundation/AString.cpp b/media/libstagefright/foundation/AString.cpp
index c6ef75f..a8adff5 100644
--- a/media/libstagefright/foundation/AString.cpp
+++ b/media/libstagefright/foundation/AString.cpp
@@ -125,12 +125,10 @@
}
void AString::clear() {
- if (mData && mData != kEmptyString) {
+ if (mData != kEmptyString) {
free(mData);
- mData = NULL;
+ mData = (char *)kEmptyString;
}
-
- mData = (char *)kEmptyString;
mSize = 0;
mAllocSize = 1;
}
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
index 85e4378..c6c12ff 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/AData.h
@@ -774,7 +774,7 @@
/**
* Move assignment operator.
*/
- Custom& operator=(Custom &&o) {
+ Custom& operator=(Custom &&o) noexcept {
if (&o != this) {
if (this->used() && !this->clear()) {
__builtin_trap();
@@ -795,7 +795,7 @@
/**
* Move constructor.
*/
- Custom(Custom &&o) : Custom() {
+ Custom(Custom &&o) noexcept : Custom() {
*this = std::move(o);
}
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h b/media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h
index bac8fa9..a8b88fd 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/ADebug.h
@@ -63,38 +63,21 @@
__FILE__ ":" LITERAL_TO_STRING(__LINE__) \
" CHECK(" #condition ") failed.")
-#define MAKE_COMPARATOR(suffix,op) \
- template<class A, class B> \
- AString Compare_##suffix(const A &a, const B &b) { \
- AString res; \
- if (!(a op b)) { \
- res.append(a); \
- res.append(" vs. "); \
- res.append(b); \
- } \
- return res; \
- }
-
-MAKE_COMPARATOR(EQ,==)
-MAKE_COMPARATOR(NE,!=)
-MAKE_COMPARATOR(LE,<=)
-MAKE_COMPARATOR(GE,>=)
-MAKE_COMPARATOR(LT,<)
-MAKE_COMPARATOR(GT,>)
-
#ifdef CHECK_OP
#undef CHECK_OP
#endif
#define CHECK_OP(x,y,suffix,op) \
do { \
- AString ___res = Compare_##suffix(x, y); \
- if (!___res.empty()) { \
+ const auto &a = x; \
+ const auto &b = y; \
+ if (!(a op b)) { \
AString ___full = \
__FILE__ ":" LITERAL_TO_STRING(__LINE__) \
" CHECK_" #suffix "( " #x "," #y ") failed: "; \
- ___full.append(___res); \
- \
+ ___full.append(a); \
+ ___full.append(" vs. "); \
+ ___full.append(b); \
LOG_ALWAYS_FATAL("%s", ___full.c_str()); \
} \
} while (false)
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h b/media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h
index 143b140..03720fd 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/Mutexed.h
@@ -103,7 +103,7 @@
class Locked {
public:
inline Locked(Mutexed<T> &mParent);
- inline Locked(Locked &&from) :
+ inline Locked(Locked &&from) noexcept :
mLock(from.mLock),
mTreasure(from.mTreasure),
mLocked(from.mLocked) {}
diff --git a/media/libstagefright/http/ClearMediaHTTP.cpp b/media/libstagefright/http/ClearMediaHTTP.cpp
index bfbad1e..9557c8a 100644
--- a/media/libstagefright/http/ClearMediaHTTP.cpp
+++ b/media/libstagefright/http/ClearMediaHTTP.cpp
@@ -74,6 +74,10 @@
return success ? OK : UNKNOWN_ERROR;
}
+void ClearMediaHTTP::close() {
+ disconnect();
+}
+
void ClearMediaHTTP::disconnect() {
mName = String8("ClearMediaHTTP(<disconnected>)");
if (mInitCheck != OK) {
diff --git a/media/libstagefright/httplive/Android.bp b/media/libstagefright/httplive/Android.bp
index 8a77401..2907751 100644
--- a/media/libstagefright/httplive/Android.bp
+++ b/media/libstagefright/httplive/Android.bp
@@ -37,6 +37,7 @@
"libcutils",
"libmedia",
"libmediaextractor",
+ "libmediandk",
"libstagefright",
"libstagefright_foundation",
"libutils",
@@ -46,6 +47,10 @@
"android.hardware.cas.native@1.0",
],
+ header_libs: [
+ "libbase_headers",
+ ],
+
static_libs: [
"libstagefright_id3",
"libstagefright_metadatautils",
diff --git a/media/libstagefright/httplive/LiveSession.cpp b/media/libstagefright/httplive/LiveSession.cpp
index 7eff8eb..86872c5 100644
--- a/media/libstagefright/httplive/LiveSession.cpp
+++ b/media/libstagefright/httplive/LiveSession.cpp
@@ -445,7 +445,7 @@
return -EAGAIN;
};
(*accessUnit)->meta()->setInt32(
- "trackIndex", mPlaylist->getSelectedIndex());
+ "track-index", mPlaylist->getSelectedIndex());
(*accessUnit)->meta()->setInt64("baseUs", mRealTimeBaseUs);
} else if (stream == STREAMTYPE_METADATA) {
HLSTime mdTime((*accessUnit)->meta());
diff --git a/media/libstagefright/httplive/PlaylistFetcher.cpp b/media/libstagefright/httplive/PlaylistFetcher.cpp
index 9f39b5e..823f90e 100644
--- a/media/libstagefright/httplive/PlaylistFetcher.cpp
+++ b/media/libstagefright/httplive/PlaylistFetcher.cpp
@@ -16,6 +16,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "PlaylistFetcher"
+#include <android-base/macros.h>
#include <utils/Log.h>
#include <utils/misc.h>
@@ -267,7 +268,7 @@
break;
}
- // fall through
+ FALLTHROUGH_INTENDED;
}
case FIRST_UNCHANGED_RELOAD_ATTEMPT:
diff --git a/media/libstagefright/include/NuCachedSource2.h b/media/libstagefright/include/NuCachedSource2.h
index f439a1c..596efb8 100644
--- a/media/libstagefright/include/NuCachedSource2.h
+++ b/media/libstagefright/include/NuCachedSource2.h
@@ -37,6 +37,8 @@
virtual ssize_t readAt(off64_t offset, void *data, size_t size);
+ virtual void close();
+
virtual void disconnect();
virtual status_t getSize(off64_t *size);
@@ -51,6 +53,8 @@
return mName;
}
+ status_t getAvailableSize(off64_t offset, off64_t *size);
+
////////////////////////////////////////////////////////////////////////////
size_t cachedSize();
@@ -135,7 +139,7 @@
ssize_t readInternal(off64_t offset, void *data, size_t size);
status_t seekInternal_l(off64_t offset);
- size_t approxDataRemaining_l(status_t *finalStatus) const;
+ size_t approxDataRemaining_l(off64_t offset, status_t *finalStatus) const;
void restartPrefetcherIfNecessary_l(
bool ignoreLowWaterThreshold = false, bool force = false);
diff --git a/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h b/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
index 7fe9c74..72907a9 100644
--- a/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
+++ b/media/libstagefright/include/media/stagefright/ClearMediaHTTP.h
@@ -34,6 +34,8 @@
const KeyedVector<String8, String8> *headers,
off64_t offset);
+ virtual void close();
+
virtual void disconnect();
virtual status_t initCheck() const;
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractor.h b/media/libstagefright/include/media/stagefright/MediaExtractor.h
index d9456ab..71343d5 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractor.h
@@ -90,7 +90,22 @@
class MediaExtractorCUnwrapper : public MediaExtractor {
public:
- explicit MediaExtractorCUnwrapper(CMediaExtractor *wrapper);
+ MediaExtractorCUnwrapper() {};
+ virtual size_t countTracks() = 0;
+ virtual MediaTrack *getTrack(size_t index) = 0;
+ virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags = 0) = 0;
+ virtual status_t getMetaData(MetaDataBase& meta) = 0;
+ virtual const char * name() = 0;
+ virtual uint32_t flags() const = 0;
+ virtual status_t setMediaCas(const uint8_t* casToken, size_t size) = 0;
+protected:
+ virtual ~MediaExtractorCUnwrapper() {};
+};
+
+
+class MediaExtractorCUnwrapperV1 : public MediaExtractorCUnwrapper {
+public:
+ explicit MediaExtractorCUnwrapperV1(CMediaExtractor *plugin);
virtual size_t countTracks();
virtual MediaTrack *getTrack(size_t index);
virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags = 0);
@@ -99,11 +114,26 @@
virtual uint32_t flags() const;
virtual status_t setMediaCas(const uint8_t* casToken, size_t size);
protected:
- virtual ~MediaExtractorCUnwrapper();
+ virtual ~MediaExtractorCUnwrapperV1();
private:
- CMediaExtractor *wrapper;
+ CMediaExtractor *plugin;
};
+class MediaExtractorCUnwrapperV2 : public MediaExtractorCUnwrapper {
+public:
+ explicit MediaExtractorCUnwrapperV2(CMediaExtractorV2 *plugin);
+ virtual size_t countTracks();
+ virtual MediaTrack *getTrack(size_t index);
+ virtual status_t getTrackMetaData(MetaDataBase& meta, size_t index, uint32_t flags = 0);
+ virtual status_t getMetaData(MetaDataBase& meta);
+ virtual const char * name();
+ virtual uint32_t flags() const;
+ virtual status_t setMediaCas(const uint8_t* casToken, size_t size);
+protected:
+ virtual ~MediaExtractorCUnwrapperV2();
+private:
+ CMediaExtractorV2 *plugin;
+};
} // namespace android
diff --git a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
index e603176..ef9f7ed 100644
--- a/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
+++ b/media/libstagefright/include/media/stagefright/MediaExtractorFactory.h
@@ -49,9 +49,9 @@
static void RegisterExtractor(
const sp<ExtractorPlugin> &plugin, std::list<sp<ExtractorPlugin>> &pluginList);
- static CreatorFunc sniff(const sp<DataSource> &source,
+ static void *sniff(const sp<DataSource> &source,
float *confidence, void **meta, FreeMetaFunc *freeMeta,
- sp<ExtractorPlugin> &plugin);
+ sp<ExtractorPlugin> &plugin, uint32_t *creatorVersion);
static void UpdateExtractors(const char *newUpdateApkPath);
};
diff --git a/media/libstagefright/include/media/stagefright/MetaDataUtils.h b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
index 4a7107d..fd79a9e 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataUtils.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
@@ -20,14 +20,20 @@
#include <media/stagefright/MetaData.h>
+struct AMediaFormat;
+
namespace android {
struct ABuffer;
bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
+
bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
bool MakeAACCodecSpecificData(MetaDataBase &meta, unsigned profile, unsigned sampling_freq_index,
unsigned channel_configuration);
+bool MakeAACCodecSpecificData(AMediaFormat *meta, unsigned profile, unsigned sampling_freq_index,
+ unsigned channel_configuration);
+
} // namespace android
#endif // META_DATA_UTILS_H_
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 54a7095..641ccfa 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -64,8 +64,6 @@
status_t setMediaCas(const HInterfaceToken &casToken);
- void disconnect();
-
size_t countTracks() const;
status_t getTrackFormat(size_t index, sp<AMessage> *format, uint32_t flags = 0) const;
diff --git a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
index d1ec1ed..03d3869 100644
--- a/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
+++ b/media/libstagefright/include/media/stagefright/RemoteMediaSource.h
@@ -43,7 +43,7 @@
private:
sp<RemoteMediaExtractor> mExtractor;
- MediaTrack *mSource;
+ MediaTrack *mTrack;
sp<RefBase> mExtractorPlugin;
explicit RemoteMediaSource(
diff --git a/media/libstagefright/include/media/stagefright/Utils.h b/media/libstagefright/include/media/stagefright/Utils.h
index 6a28e0b..46a419d 100644
--- a/media/libstagefright/include/media/stagefright/Utils.h
+++ b/media/libstagefright/include/media/stagefright/Utils.h
@@ -30,6 +30,8 @@
struct AMessage;
status_t convertMetaDataToMessage(
+ const MetaDataBase *meta, sp<AMessage> *format);
+status_t convertMetaDataToMessage(
const sp<MetaData> &meta, sp<AMessage> *format);
void convertMessageToMetaData(
const sp<AMessage> &format, sp<MetaData> &meta);
diff --git a/media/libstagefright/omx/Android.bp b/media/libstagefright/omx/Android.bp
index 3e6942b..6250045 100644
--- a/media/libstagefright/omx/Android.bp
+++ b/media/libstagefright/omx/Android.bp
@@ -29,6 +29,7 @@
],
header_libs: [
+ "libbase_headers",
"media_plugin_headers",
],
diff --git a/media/libstagefright/omx/OMXNodeInstance.cpp b/media/libstagefright/omx/OMXNodeInstance.cpp
index 32113c2..99762b9 100644
--- a/media/libstagefright/omx/OMXNodeInstance.cpp
+++ b/media/libstagefright/omx/OMXNodeInstance.cpp
@@ -16,6 +16,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "OMXNodeInstance"
+#include <android-base/macros.h>
#include <utils/Log.h>
#include <inttypes.h>
@@ -459,7 +460,7 @@
break;
}
- // fall through
+ FALLTHROUGH_INTENDED;
}
case OMX_StateIdle:
@@ -486,7 +487,7 @@
}
CHECK_EQ(err, OMX_ErrorNone);
- // fall through
+ FALLTHROUGH_INTENDED;
}
case OMX_StateLoaded:
@@ -2196,8 +2197,8 @@
// bump internal-state debug level for 2 input and output frames
Mutex::Autolock _l(mDebugLock);
bumpDebugLevel_l(2 /* numInputBuffers */, 2 /* numOutputBuffers */);
+ FALLTHROUGH_INTENDED;
}
- // fall through
default:
arg2String = portString(arg2);
}
@@ -2208,7 +2209,7 @@
break;
case OMX_EventPortSettingsChanged:
arg2String = asString((OMX_INDEXEXTTYPE)arg2);
- // fall through
+ FALLTHROUGH_INTENDED;
default:
arg1String = portString(arg1);
}
diff --git a/media/libstagefright/omx/OMXUtils.cpp b/media/libstagefright/omx/OMXUtils.cpp
index f7b569d..9ed4a99 100644
--- a/media/libstagefright/omx/OMXUtils.cpp
+++ b/media/libstagefright/omx/OMXUtils.cpp
@@ -19,6 +19,7 @@
#include <string.h>
+#include <android-base/macros.h>
#include <media/stagefright/omx/OMXUtils.h>
#include <media/stagefright/foundation/ADebug.h>
#include <media/stagefright/foundation/AUtils.h>
@@ -273,6 +274,7 @@
break;
} else {
// fall through as YV12 is used for YUV420Planar by some codecs
+ FALLTHROUGH_INTENDED;
}
case OMX_COLOR_FormatYUV420Planar:
diff --git a/media/libstagefright/omx/tests/Android.bp b/media/libstagefright/omx/tests/Android.bp
index 3b521ab..ef36982 100644
--- a/media/libstagefright/omx/tests/Android.bp
+++ b/media/libstagefright/omx/tests/Android.bp
@@ -27,6 +27,10 @@
"frameworks/native/include/media/openmax",
],
+ header_libs: [
+ "libbase_headers",
+ ],
+
cflags: [
"-Werror",
"-Wall",
diff --git a/media/libstagefright/omx/tests/OMXHarness.cpp b/media/libstagefright/omx/tests/OMXHarness.cpp
index 5388ba7..c2f1072 100644
--- a/media/libstagefright/omx/tests/OMXHarness.cpp
+++ b/media/libstagefright/omx/tests/OMXHarness.cpp
@@ -17,6 +17,7 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "OMXHarness"
#include <inttypes.h>
+#include <android-base/macros.h>
#include <utils/Log.h>
#include "OMXHarness.h"
@@ -843,7 +844,7 @@
case '?':
fprintf(stderr, "\n");
- // fall through
+ FALLTHROUGH_INTENDED;
case 'h':
default:
diff --git a/media/libstagefright/xmlparser/Android.bp b/media/libstagefright/xmlparser/Android.bp
index a4fa342..5737ac2 100644
--- a/media/libstagefright/xmlparser/Android.bp
+++ b/media/libstagefright/xmlparser/Android.bp
@@ -19,6 +19,10 @@
"libstagefright_omx_utils",
],
+ header_libs: [
+ "libbase_headers",
+ ],
+
cflags: [
"-Werror",
"-Wall",
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index ffd30ea..0832944 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -19,6 +19,7 @@
#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
+#include <android-base/macros.h>
#include <utils/Log.h>
#include <media/stagefright/MediaErrors.h>
#include <media/stagefright/omx/OMXUtils.h>
@@ -340,7 +341,7 @@
}
}
inType = false;
- // fall through
+ FALLTHROUGH_INTENDED;
case SECTION_DECODER_TYPE:
case SECTION_ENCODER_TYPE:
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index f25fc71..ad3c068 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -212,7 +212,6 @@
uint16_t value = setup->wValue;
std::vector<char> buf;
buf.resize(length);
- int ret = 0;
if (!(type & USB_DIR_IN)) {
if (::read(mControl, buf.data(), length) != length) {
@@ -225,8 +224,8 @@
case MTP_REQ_RESET:
case MTP_REQ_CANCEL:
errno = ECANCELED;
- ret = -1;
- break;
+ return -1;
+ // break;
case MTP_REQ_GET_DEVICE_STATUS:
{
if (length < sizeof(struct mtp_device_status) + 4) {
diff --git a/media/mtp/MtpServer.cpp b/media/mtp/MtpServer.cpp
index cff2803..ca8cb78 100644
--- a/media/mtp/MtpServer.cpp
+++ b/media/mtp/MtpServer.cpp
@@ -448,6 +448,9 @@
break;
}
+ if (response != MTP_RESPONSE_OK)
+ ALOGW("[MTP] got response 0x%X in command %s (%x)", response,
+ MtpDebug::getOperationCodeName(operation), operation);
if (response == MTP_RESPONSE_TRANSACTION_CANCELLED)
return false;
mResponse.setResponseCode(response);
@@ -658,8 +661,8 @@
return MTP_RESPONSE_INVALID_PARAMETER;
MtpObjectHandle handle = mRequest.getParameter(1);
MtpObjectProperty property = mRequest.getParameter(2);
- ALOGV("GetObjectPropValue %d %s\n", handle,
- MtpDebug::getObjectPropCodeName(property));
+ ALOGV("GetObjectPropValue %d %s (0x%04X)\n", handle,
+ MtpDebug::getObjectPropCodeName(property), property);
return mDatabase->getObjectPropertyValue(handle, property, mData);
}
@@ -952,7 +955,8 @@
if (!mData.getString(modified)) return MTP_RESPONSE_INVALID_PARAMETER; // date modified
// keywords follow
- ALOGV("name: %s format: %04X\n", (const char *)name, format);
+ ALOGV("name: %s format: 0x%04X (%s)\n", (const char*)name, format,
+ MtpDebug::getFormatCodeName(format));
time_t modifiedTime;
if (!parseDateTime(modified, modifiedTime))
modifiedTime = 0;
@@ -973,9 +977,10 @@
return MTP_RESPONSE_OBJECT_TOO_LARGE;
}
- ALOGD("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
+ ALOGV("path: %s parent: %d storageID: %08X", (const char*)path, parent, storageID);
MtpObjectHandle handle = mDatabase->beginSendObject((const char*)path, format,
parent, storageID);
+ ALOGD("handle: %d, parent: %d, storageID: %08X", handle, parent, storageID);
if (handle == kInvalidObjectHandle) {
return MTP_RESPONSE_GENERAL_ERROR;
}
diff --git a/media/mtp/OWNERS b/media/mtp/OWNERS
index 219307b..1928ba8 100644
--- a/media/mtp/OWNERS
+++ b/media/mtp/OWNERS
@@ -1 +1,7 @@
-zhangjerry@google.com
+set noparent
+
+marcone@google.com
+jsharkey@android.com
+jameswei@google.com
+rmojumder@google.com
+
diff --git a/media/ndk/Android.bp b/media/ndk/Android.bp
index 4a36681..05c8582 100644
--- a/media/ndk/Android.bp
+++ b/media/ndk/Android.bp
@@ -39,6 +39,7 @@
"NdkMediaCrypto.cpp",
"NdkMediaDataSource.cpp",
"NdkMediaExtractor.cpp",
+ "NdkMediaError.cpp",
"NdkMediaFormat.cpp",
"NdkMediaMuxer.cpp",
"NdkMediaDrm.cpp",
@@ -82,6 +83,8 @@
"libbinder",
"libgui",
"libui",
+ "libmedia2_jni_core",
+ "libmediandk_utils",
],
export_include_dirs: ["include"],
@@ -98,3 +101,45 @@
symbol_file: "libmediandk.map.txt",
export_include_dirs: ["include"],
}
+
+cc_library {
+ name: "libmediandk_utils",
+
+ srcs: [
+ "NdkMediaDataSourceCallbacks.cpp",
+ "NdkMediaError.cpp",
+ ],
+
+ include_dirs: [
+ "frameworks/av/media/libstagefright/include",
+ "frameworks/av/media/ndk/include",
+ ],
+
+ export_include_dirs: [
+ "include",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+
+ shared_libs: [
+ "libstagefright_foundation",
+ "liblog",
+ "libutils",
+ "libcutils",
+ ],
+
+ sanitize: {
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ cfi: true,
+ diag: {
+ cfi: true,
+ },
+ },
+}
diff --git a/media/ndk/NdkMediaDataSource.cpp b/media/ndk/NdkMediaDataSource.cpp
index 9d00e5e..43c89bb 100644
--- a/media/ndk/NdkMediaDataSource.cpp
+++ b/media/ndk/NdkMediaDataSource.cpp
@@ -23,16 +23,23 @@
#include <jni.h>
#include <unistd.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <android_util_Binder.h>
#include <binder/IServiceManager.h>
#include <cutils/properties.h>
#include <utils/Log.h>
#include <utils/StrongPointer.h>
+#include <media/IMediaHTTPService.h>
#include <media/NdkMediaError.h>
#include <media/NdkMediaDataSource.h>
+#include <media/stagefright/DataSourceFactory.h>
#include <media/stagefright/InterfaceUtils.h>
+#include <mediaplayer2/JavaVMHelper.h>
+#include <mediaplayer2/JMedia2HTTPService.h>
#include "../../libstagefright/include/HTTPBase.h"
#include "../../libstagefright/include/NuCachedSource2.h"
+#include "NdkMediaDataSourceCallbacksPriv.h"
using namespace android;
@@ -41,14 +48,19 @@
AMediaDataSourceReadAt readAt;
AMediaDataSourceGetSize getSize;
AMediaDataSourceClose close;
+ AMediaDataSourceGetAvailableSize getAvailableSize;
+ sp<DataSource> mImpl;
+ uint32_t mFlags;
};
NdkDataSource::NdkDataSource(AMediaDataSource *dataSource)
: mDataSource(AMediaDataSource_new()) {
- AMediaDataSource_setReadAt(mDataSource, dataSource->readAt);
- AMediaDataSource_setGetSize(mDataSource, dataSource->getSize);
- AMediaDataSource_setClose(mDataSource, dataSource->close);
- AMediaDataSource_setUserdata(mDataSource, dataSource->userdata);
+ AMediaDataSource_setReadAt(mDataSource, dataSource->readAt);
+ AMediaDataSource_setGetSize(mDataSource, dataSource->getSize);
+ AMediaDataSource_setClose(mDataSource, dataSource->close);
+ AMediaDataSource_setUserdata(mDataSource, dataSource->userdata);
+ mDataSource->mImpl = dataSource->mImpl;
+ mDataSource->mFlags = dataSource->mFlags;
}
NdkDataSource::~NdkDataSource() {
@@ -59,9 +71,13 @@
return OK;
}
+uint32_t NdkDataSource::flags() {
+ return mDataSource->mFlags;
+}
+
ssize_t NdkDataSource::readAt(off64_t offset, void *data, size_t size) {
Mutex::Autolock l(mLock);
- if (mDataSource->getSize == NULL || mDataSource->userdata == NULL) {
+ if (mDataSource->readAt == NULL || mDataSource->userdata == NULL) {
return -1;
}
return mDataSource->readAt(mDataSource->userdata, offset, data, size);
@@ -92,6 +108,95 @@
}
}
+status_t NdkDataSource::getAvailableSize(off64_t offset, off64_t *sizeptr) {
+ off64_t size = -1;
+ if (mDataSource->getAvailableSize != NULL
+ && mDataSource->userdata != NULL
+ && sizeptr != NULL) {
+ size = mDataSource->getAvailableSize(mDataSource->userdata, offset);
+ *sizeptr = size;
+ }
+ return size >= 0 ? OK : UNKNOWN_ERROR;
+}
+
+static sp<MediaHTTPService> createMediaHttpServiceFromJavaObj(JNIEnv *env, jobject obj, int version) {
+ if (obj == NULL) {
+ return NULL;
+ }
+ switch (version) {
+ case 1:
+ return interface_cast<IMediaHTTPService>(ibinderForJavaObject(env, obj));
+ case 2:
+ return new JMedia2HTTPService(env, obj);
+ default:
+ return NULL;
+ }
+}
+
+static sp<MediaHTTPService> createMediaHttpServiceTemplate(
+ JNIEnv *env,
+ const char *uri,
+ const char *clazz,
+ const char *method,
+ const char *signature,
+ int version) {
+ jobject service = NULL;
+ if (env == NULL) {
+ ALOGE("http service must be created from Java thread");
+ return NULL;
+ }
+
+ jclass mediahttpclass = env->FindClass(clazz);
+ if (mediahttpclass == NULL) {
+ ALOGE("can't find Media(2)HttpService");
+ env->ExceptionClear();
+ return NULL;
+ }
+
+ jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass, method, signature);
+ if (mediaHttpCreateMethod == NULL) {
+ ALOGE("can't find method");
+ env->ExceptionClear();
+ return NULL;
+ }
+
+ jstring juri = env->NewStringUTF(uri);
+
+ service = env->CallStaticObjectMethod(mediahttpclass, mediaHttpCreateMethod, juri);
+ env->DeleteLocalRef(juri);
+
+ env->ExceptionClear();
+ sp<MediaHTTPService> httpService = createMediaHttpServiceFromJavaObj(env, service, version);
+ return httpService;
+
+}
+
+sp<MediaHTTPService> createMediaHttpService(const char *uri, int version) {
+
+ JNIEnv *env;
+ const char *clazz, *method, *signature;
+
+ switch (version) {
+ case 1:
+ env = AndroidRuntime::getJNIEnv();
+ clazz = "android/media/MediaHTTPService";
+ method = "createHttpServiceBinderIfNecessary";
+ signature = "(Ljava/lang/String;)Landroid/os/IBinder;";
+ break;
+ case 2:
+ env = JavaVMHelper::getJNIEnv();
+ clazz = "android/media/Media2HTTPService";
+ method = "createHTTPService";
+ signature = "(Ljava/lang/String;)Landroid/media/Media2HTTPService;";
+ break;
+ default:
+ return NULL;
+ }
+
+ return createMediaHttpServiceTemplate(env, uri, clazz, method, signature, version);
+
+}
+
extern "C" {
EXPORT
@@ -105,6 +210,27 @@
}
EXPORT
+AMediaDataSource* AMediaDataSource_newUri(
+ const char *uri,
+ int numheaders,
+ const char * const *key_values) {
+
+ sp<MediaHTTPService> service = createMediaHttpService(uri, /* version = */ 1);
+ KeyedVector<String8, String8> headers;
+ for (int i = 0; i < numheaders; ++i) {
+ String8 key8(key_values[i * 2]);
+ String8 value8(key_values[i * 2 + 1]);
+ headers.add(key8, value8);
+ }
+
+ sp<DataSource> source = DataSourceFactory::CreateFromURI(service, uri, &headers);
+ AMediaDataSource* aSource = convertDataSourceToAMediaDataSource(source);
+ aSource->mImpl = source;
+ aSource->mFlags = source->flags();
+ return aSource;
+}
+
+EXPORT
void AMediaDataSource_delete(AMediaDataSource *mSource) {
ALOGV("dtor");
if (mSource != NULL) {
@@ -132,5 +258,16 @@
mSource->close = close;
}
+EXPORT
+void AMediaDataSource_close(AMediaDataSource *mSource) {
+ return mSource->close(mSource->userdata);
+}
+
+EXPORT
+void AMediaDataSource_setGetAvailableSize(AMediaDataSource *mSource,
+ AMediaDataSourceGetAvailableSize getAvailableSize) {
+ mSource->getAvailableSize = getAvailableSize;
+}
+
} // extern "C"
diff --git a/media/ndk/NdkMediaDataSourceCallbacks.cpp b/media/ndk/NdkMediaDataSourceCallbacks.cpp
new file mode 100644
index 0000000..796c11b
--- /dev/null
+++ b/media/ndk/NdkMediaDataSourceCallbacks.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+//#define LOG_NDEBUG 0
+#define LOG_TAG "NdkMediaDataSourceCallbacks"
+
+#include "NdkMediaErrorPriv.h"
+#include "NdkMediaDataSourceCallbacksPriv.h"
+#include <media/DataSource.h>
+
+namespace android {
+
+ssize_t DataSource_getSize(void *userdata) {
+ DataSource *source = static_cast<DataSource *>(userdata);
+ off64_t size = -1;
+ source->getSize(&size);
+ return size;
+}
+
+ssize_t DataSource_readAt(void *userdata, off64_t offset, void * buf, size_t size) {
+ DataSource *source = static_cast<DataSource *>(userdata);
+ return source->readAt(offset, buf, size);
+}
+
+void DataSource_close(void *userdata) {
+ DataSource *source = static_cast<DataSource *>(userdata);
+ source->close();
+}
+
+ssize_t DataSource_getAvailableSize(void *userdata, off64_t offset) {
+ off64_t size = -1;
+ DataSource *source = static_cast<DataSource *>(userdata);
+ status_t err = source->getAvailableSize(offset, &size);
+ return err == OK ? size : -1;
+}
+
+} // namespace android
diff --git a/media/ndk/NdkMediaDataSourceCallbacksPriv.h b/media/ndk/NdkMediaDataSourceCallbacksPriv.h
new file mode 100644
index 0000000..6503305
--- /dev/null
+++ b/media/ndk/NdkMediaDataSourceCallbacksPriv.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2018, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef A_MEDIA_DATA_SOURCE_CALLBACKS_H
+
+#define A_MEDIA_DATA_SOURCE_CALLBACKS_H
+
+#include <media/DataSource.h>
+#include <media/NdkMediaDataSource.h>
+#include <media/NdkMediaError.h>
+#include <sys/types.h>
+
+namespace android {
+
+ssize_t DataSource_getSize(void *userdata);
+
+ssize_t DataSource_readAt(void *userdata, off64_t offset, void * buf, size_t size);
+
+void DataSource_close(void *userdata);
+
+ssize_t DataSource_getAvailableSize(void *userdata, off64_t offset);
+
+static inline AMediaDataSource* convertDataSourceToAMediaDataSource(const sp<DataSource> &source) {
+ if (source == NULL) {
+ return NULL;
+ }
+ AMediaDataSource *mSource = AMediaDataSource_new();
+ AMediaDataSource_setUserdata(mSource, source.get());
+ AMediaDataSource_setReadAt(mSource, DataSource_readAt);
+ AMediaDataSource_setGetSize(mSource, DataSource_getSize);
+ AMediaDataSource_setClose(mSource, DataSource_close);
+ AMediaDataSource_setGetAvailableSize(mSource, DataSource_getAvailableSize);
+ return mSource;
+}
+
+} // namespace android
+
+#endif // A_MEDIA_DATA_SOURCE_CALLBACKS_H
diff --git a/media/ndk/NdkMediaDataSourcePriv.h b/media/ndk/NdkMediaDataSourcePriv.h
index ea9c865..16ff974 100644
--- a/media/ndk/NdkMediaDataSourcePriv.h
+++ b/media/ndk/NdkMediaDataSourcePriv.h
@@ -32,6 +32,7 @@
#include <sys/types.h>
#include <media/DataSource.h>
+#include <media/MediaHTTPService.h>
#include <media/NdkMediaDataSource.h>
#include <utils/Mutex.h>
#include <utils/String8.h>
@@ -43,11 +44,13 @@
NdkDataSource(AMediaDataSource *);
virtual status_t initCheck() const;
+ virtual uint32_t flags();
virtual ssize_t readAt(off64_t offset, void *data, size_t size);
virtual status_t getSize(off64_t *);
virtual String8 toString();
virtual String8 getMIMEType() const;
virtual void close();
+ virtual status_t getAvailableSize(off64_t offset, off64_t *size);
protected:
virtual ~NdkDataSource();
@@ -59,5 +62,7 @@
};
+sp<MediaHTTPService> createMediaHttpService(const char *uri, int version);
+
#endif // _NDK_MEDIA_DATASOURCE_PRIV_H
diff --git a/media/ndk/NdkMediaDrm.cpp b/media/ndk/NdkMediaDrm.cpp
index 2552073..55afb33 100644
--- a/media/ndk/NdkMediaDrm.cpp
+++ b/media/ndk/NdkMediaDrm.cpp
@@ -698,7 +698,7 @@
Vector<uint8_t> byteArray;
byteArray.appendArray(value, valueSize);
- return translateStatus(mObj->mDrm->getPropertyByteArray(String8(propertyName),
+ return translateStatus(mObj->mDrm->setPropertyByteArray(String8(propertyName),
byteArray));
}
diff --git a/media/ndk/NdkMediaError.cpp b/media/ndk/NdkMediaError.cpp
new file mode 100644
index 0000000..2facd8c
--- /dev/null
+++ b/media/ndk/NdkMediaError.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <media/NdkMediaError.h>
+#include <media/stagefright/MediaErrors.h>
+#include <utils/Errors.h>
+#include <utils/Log.h>
+
+using namespace android;
+
+media_status_t translate_error(status_t err) {
+
+ if (err == OK) {
+ return AMEDIA_OK;
+ } else if (err == ERROR_END_OF_STREAM) {
+ return AMEDIA_ERROR_END_OF_STREAM;
+ } else if (err == ERROR_IO) {
+ return AMEDIA_ERROR_IO;
+ }
+
+ ALOGE("sf error code: %d", err);
+ return AMEDIA_ERROR_UNKNOWN;
+}
+
+status_t reverse_translate_error(media_status_t err) {
+
+ if (err == AMEDIA_OK) {
+ return OK;
+ } else if (err == AMEDIA_ERROR_END_OF_STREAM) {
+ return ERROR_END_OF_STREAM;
+ } else if (err == AMEDIA_ERROR_IO) {
+ return ERROR_IO;
+ }
+
+ ALOGE("ndk error code: %d", err);
+ return UNKNOWN_ERROR;
+}
diff --git a/media/ndk/NdkMediaErrorPriv.h b/media/ndk/NdkMediaErrorPriv.h
new file mode 100644
index 0000000..f5e2f02
--- /dev/null
+++ b/media/ndk/NdkMediaErrorPriv.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef _NDK_MEDIA_ERROR_PRIV_H
+#define _NDK_MEDIA_ERROR_PRIV_H
+
+#include <media/NdkMediaError.h>
+#include <utils/Errors.h>
+
+using namespace android;
+
+media_status_t translate_error(status_t);
+
+status_t reverse_translate_error(media_status_t);
+
+#endif // _NDK_MEDIA_ERROR_PRIV_H
diff --git a/media/ndk/NdkMediaExtractor.cpp b/media/ndk/NdkMediaExtractor.cpp
index c66cd50..a6adee4 100644
--- a/media/ndk/NdkMediaExtractor.cpp
+++ b/media/ndk/NdkMediaExtractor.cpp
@@ -21,6 +21,7 @@
#include <media/NdkMediaError.h>
#include <media/NdkMediaExtractor.h>
#include <media/NdkMediaFormatPriv.h>
+#include "NdkMediaErrorPriv.h"
#include "NdkMediaDataSourcePriv.h"
@@ -40,19 +41,6 @@
using namespace android;
-static media_status_t translate_error(status_t err) {
- if (err == OK) {
- return AMEDIA_OK;
- } else if (err == ERROR_END_OF_STREAM) {
- return AMEDIA_ERROR_END_OF_STREAM;
- } else if (err == ERROR_IO) {
- return AMEDIA_ERROR_IO;
- }
-
- ALOGE("sf error code: %d", err);
- return AMEDIA_ERROR_UNKNOWN;
-}
-
struct AMediaExtractor {
sp<NuMediaExtractor> mImpl;
sp<ABuffer> mPsshBuf;
@@ -82,12 +70,6 @@
return translate_error(mData->mImpl->setDataSource(fd, offset, length));
}
-EXPORT
-media_status_t AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) {
- return AMediaExtractor_setDataSourceWithHeaders(mData, location, 0, NULL, NULL);
-}
-
-EXPORT
media_status_t AMediaExtractor_setDataSourceWithHeaders(AMediaExtractor *mData,
const char *uri,
int numheaders,
@@ -96,39 +78,12 @@
ALOGV("setDataSource(%s)", uri);
- JNIEnv *env = AndroidRuntime::getJNIEnv();
- jobject service = NULL;
- if (env == NULL) {
- ALOGE("setDataSource(path) must be called from Java thread");
+ sp<MediaHTTPService> httpService = createMediaHttpService(uri, /* version = */ 1);
+ if (httpService == NULL) {
+ ALOGE("can't create http service");
return AMEDIA_ERROR_UNSUPPORTED;
}
- jclass mediahttpclass = env->FindClass("android/media/MediaHTTPService");
- if (mediahttpclass == NULL) {
- ALOGE("can't find MediaHttpService");
- env->ExceptionClear();
- return AMEDIA_ERROR_UNSUPPORTED;
- }
-
- jmethodID mediaHttpCreateMethod = env->GetStaticMethodID(mediahttpclass,
- "createHttpServiceBinderIfNecessary", "(Ljava/lang/String;)Landroid/os/IBinder;");
- if (mediaHttpCreateMethod == NULL) {
- ALOGE("can't find method");
- env->ExceptionClear();
- return AMEDIA_ERROR_UNSUPPORTED;
- }
-
- jstring jloc = env->NewStringUTF(uri);
-
- service = env->CallStaticObjectMethod(mediahttpclass, mediaHttpCreateMethod, jloc);
- env->DeleteLocalRef(jloc);
-
- sp<IMediaHTTPService> httpService;
- if (service != NULL) {
- sp<IBinder> binder = ibinderForJavaObject(env, service);
- httpService = interface_cast<IMediaHTTPService>(binder);
- }
-
KeyedVector<String8, String8> headers;
for (int i = 0; i < numheaders; ++i) {
String8 key8(keys[i]);
@@ -138,11 +93,15 @@
status_t err;
err = mData->mImpl->setDataSource(httpService, uri, numheaders > 0 ? &headers : NULL);
- env->ExceptionClear();
return translate_error(err);
}
EXPORT
+media_status_t AMediaExtractor_setDataSource(AMediaExtractor *mData, const char *location) {
+ return AMediaExtractor_setDataSourceWithHeaders(mData, location, 0, NULL, NULL);
+}
+
+EXPORT
media_status_t AMediaExtractor_setDataSourceCustom(AMediaExtractor* mData, AMediaDataSource *src) {
return translate_error(mData->mImpl->setDataSource(new NdkDataSource(src)));
}
@@ -492,11 +451,5 @@
return AMEDIA_OK;
}
-EXPORT
-media_status_t AMediaExtractor_disconnect(AMediaExtractor * ex) {
- ex->mImpl->disconnect();
- return AMEDIA_OK;
-}
-
} // extern "C"
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index a66f3b3..503f726 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -35,23 +35,6 @@
extern "C" {
-// private functions for conversion to/from AMessage
-AMediaFormat* AMediaFormat_fromMsg(const void* data) {
- ALOGV("private ctor");
- AMediaFormat* mData = new AMediaFormat();
- mData->mFormat = *((sp<AMessage>*)data);
- if (mData->mFormat == NULL) {
- ALOGW("got NULL format");
- mData->mFormat = new AMessage;
- }
- return mData;
-}
-
-void AMediaFormat_getFormat(const AMediaFormat* mData, void* dest) {
- *((sp<AMessage>*)dest) = mData->mFormat;
-}
-
-
/*
* public function follow
*/
@@ -76,6 +59,9 @@
EXPORT
media_status_t AMediaFormat_copy(AMediaFormat *to, AMediaFormat *from) {
+ if (!to || !from) {
+ return AMEDIA_ERROR_INVALID_PARAMETER;
+ }
to->mFormat->clear();
to->mFormat->extend(from->mFormat);
return AMEDIA_OK;
diff --git a/media/ndk/NdkMediaMuxer.cpp b/media/ndk/NdkMediaMuxer.cpp
index b213fa9..ab709ac 100644
--- a/media/ndk/NdkMediaMuxer.cpp
+++ b/media/ndk/NdkMediaMuxer.cpp
@@ -21,6 +21,7 @@
#include <media/NdkMediaMuxer.h>
#include <media/NdkMediaCodec.h>
#include <media/NdkMediaFormatPriv.h>
+#include "NdkMediaErrorPriv.h"
#include <utils/Log.h>
@@ -36,14 +37,6 @@
using namespace android;
-static media_status_t translate_error(status_t err) {
- if (err == OK) {
- return AMEDIA_OK;
- }
- ALOGE("sf error code: %d", err);
- return AMEDIA_ERROR_UNKNOWN;
-}
-
struct AMediaMuxer {
sp<MediaMuxer> mImpl;
diff --git a/media/ndk/include/media/NdkMediaDataSource.h b/media/ndk/include/media/NdkMediaDataSource.h
index ea5ba0c..16b1eb3 100644
--- a/media/ndk/include/media/NdkMediaDataSource.h
+++ b/media/ndk/include/media/NdkMediaDataSource.h
@@ -43,14 +43,9 @@
/*
* AMediaDataSource's callbacks will be invoked on an implementation-defined thread
* or thread pool. No guarantees are provided about which thread(s) will be used for
- * callbacks. However, it is guaranteed that AMediaDataSource's callbacks will only
- * ever be invoked by a single thread at a time.
- *
- * There will be a thread synchronization point between each call to ensure that
- * modifications to the state of your AMediaDataSource are visible to future
- * calls. This means you don't need to do your own synchronization unless you're
- * modifying the AMediaDataSource from another thread while it's being used by the
- * framework.
+ * callbacks. For example, |close| can be invoked from a different thread than the
+ * thread invoking |readAt|. As such, the Implementations of AMediaDataSource callbacks
+ * must be threadsafe.
*/
/**
@@ -74,9 +69,19 @@
typedef ssize_t (*AMediaDataSourceGetSize)(void *userdata);
/**
- * Called to close the data source and release associated resources.
- * The NDK media framework guarantees that after |close| is called
- * no future callbacks will be invoked on the data source.
+ * Called to close the data source, unblock reads, and release associated
+ * resources.
+ *
+ * The NDK media framework guarantees that after the first |close| is
+ * called, no future callbacks will be invoked on the data source except
+ * for |close| itself.
+ *
+ * Closing a data source allows readAt calls that were blocked waiting
+ * for I/O data to return promptly.
+ *
+ * When using AMediaDataSource as input to AMediaExtractor, closing
+ * has the effect of unblocking slow reads inside of setDataSource
+ * and readSampleData.
*/
typedef void (*AMediaDataSourceClose)(void *userdata);
@@ -86,6 +91,38 @@
*/
AMediaDataSource* AMediaDataSource_new() __INTRODUCED_IN(28);
+#if __ANDROID_API__ >= 29
+
+/**
+ * Called to get an estimate of the number of bytes that can be read from this data source
+ * starting at |offset| without blocking for I/O.
+ *
+ * Return -1 when such an estimate is not possible.
+ */
+typedef ssize_t (*AMediaDataSourceGetAvailableSize)(void *userdata, off64_t offset);
+
+/**
+ * Create new media data source. Returns NULL if memory allocation
+ * for the new data source object fails.
+ *
+ * Set the |uri| from which the data source will read,
+ * plus additional http headers when initiating the request.
+ *
+ * Headers will contain corresponding items from |key_values|
+ * in the following fashion:
+ *
+ * key_values[0]:key_values[1]
+ * key_values[2]:key_values[3]
+ * ...
+ * key_values[(numheaders - 1) * 2]:key_values[(numheaders - 1) * 2 + 1]
+ *
+ */
+AMediaDataSource* AMediaDataSource_newUri(const char *uri,
+ int numheaders,
+ const char * const *key_values) __INTRODUCED_IN(29);
+
+#endif /*__ANDROID_API__ >= 29 */
+
/**
* Delete a previously created media data source.
*/
@@ -137,6 +174,30 @@
#endif /*__ANDROID_API__ >= 28 */
+#if __ANDROID_API__ >= 29
+
+/**
+ * Close the data source, unblock reads, and release associated resources.
+ *
+ * Please refer to the definition of AMediaDataSourceClose for
+ * additional details.
+ */
+void AMediaDataSource_close(AMediaDataSource*) __INTRODUCED_IN(29);
+
+/**
+ * Set a custom callback for supplying the estimated number of bytes
+ * that can be read from this data source starting at an offset without
+ * blocking for I/O.
+ *
+ * Please refer to the definition of AMediaDataSourceGetAvailableSize
+ * for additional details.
+ */
+void AMediaDataSource_setGetAvailableSize(
+ AMediaDataSource*,
+ AMediaDataSourceGetAvailableSize) __INTRODUCED_IN(29);
+
+#endif /*__ANDROID_API__ >= 29 */
+
__END_DECLS
#endif // _NDK_MEDIA_DATASOURCE_H
diff --git a/media/ndk/include/media/NdkMediaExtractor.h b/media/ndk/include/media/NdkMediaExtractor.h
index 413bc1a..e3d9fe6 100644
--- a/media/ndk/include/media/NdkMediaExtractor.h
+++ b/media/ndk/include/media/NdkMediaExtractor.h
@@ -73,27 +73,6 @@
media_status_t AMediaExtractor_setDataSource(AMediaExtractor*,
const char *location) __INTRODUCED_IN(21);
-#if __ANDROID_API__ >= 29
-/**
- * Set the |uri| from which the extractor will read,
- * plus additional http headers when initiating the request.
- *
- * Headers will contain corresponding items from |keys| & |values|
- * from indices 0 (inclusive) to numheaders-1 (inclusive):
- *
- * keys[0]:values[0]
- * ...
- * keys[numheaders - 1]:values[numheaders - 1]
- *
- */
-media_status_t AMediaExtractor_setDataSourceWithHeaders(AMediaExtractor*,
- const char *uri,
- int numheaders,
- const char * const *keys,
- const char * const *values) __INTRODUCED_IN(29);
-
-#endif /* __ANDROID_API__ >= 29 */
-
#if __ANDROID_API__ >= 28
/**
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index 1fd69a2..224329a 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -141,6 +141,9 @@
AMediaDataSource_setGetSize; # introduced=28
AMediaDataSource_setReadAt; # introduced=28
AMediaDataSource_setUserdata; # introduced=28
+ AMediaDataSource_newUri; # introduced=29
+ AMediaDataSource_close; # introduced=29
+ AMediaDataSource_setGetAvailableSize; # introduced=29
AMediaDrm_closeSession;
AMediaDrm_createByUUID;
AMediaDrm_decrypt;
@@ -184,7 +187,6 @@
AMediaExtractor_setDataSource;
AMediaExtractor_setDataSourceCustom; # introduced=28
AMediaExtractor_setDataSourceFd;
- AMediaExtractor_setDataSourceWithHeaders; # introduced=29
AMediaExtractor_unselectTrack;
AMediaFormat_clear; # introduced=29
AMediaFormat_copy; # introduced=29
diff --git a/packages/MediaComponents/Android.mk b/packages/MediaComponents/Android.mk
index 55a5424..fff3a62 100644
--- a/packages/MediaComponents/Android.mk
+++ b/packages/MediaComponents/Android.mk
@@ -14,59 +14,57 @@
# limitations under the License.
#
-# This package is excluded from build for now since APIs using this apk became hidden.
-#
-#LOCAL_PATH := $(call my-dir)
-#ifneq ($(TARGET_BUILD_PDK),true) # Build MediaComponents only if this is not a PDK build. MediaComponents won't
-## build in PDK builds because frameworks/base/core/java is not available but
-## IMediaSession2.aidl and IMediaController2.aidl are using classes from
-## frameworks/base/core/java.
-#
-#include $(CLEAR_VARS)
-#
-#LOCAL_PACKAGE_NAME := MediaComponents
-#LOCAL_MODULE_OWNER := google
-#
-## TODO: create a separate key for this package.
-#LOCAL_CERTIFICATE := platform
-#
-## TODO: Use System SDK once public APIs are approved
-## LOCAL_SDK_VERSION := system_current
-#LOCAL_PRIVATE_PLATFORM_APIS := true
-#
-#LOCAL_SRC_FILES := \
-# $(call all-java-files-under, src) \
-# $(call all-Iaidl-files-under, src)
-#
-#LOCAL_PROGUARD_FLAG_FILES := proguard.cfg
-#
-#LOCAL_MULTILIB := first
-#
-#LOCAL_JAVA_LIBRARIES += androidx.annotation_annotation
-#
-## To embed native libraries in package, uncomment the lines below.
-##LOCAL_MODULE_TAGS := samples
-##LOCAL_JNI_SHARED_LIBRARIES := \
-## libaacextractor \
-## libamrextractor \
-## libflacextractor \
-## libmidiextractor \
-## libmkvextractor \
-## libmp3extractor \
-## libmp4extractor \
-## libmpeg2extractor \
-## liboggextractor \
-## libwavextractor \
-#
-## TODO: Remove dependency with other support libraries.
-#LOCAL_STATIC_ANDROID_LIBRARIES += \
-# androidx.legacy_legacy-support-v4 \
-# androidx.appcompat_appcompat \
-# androidx.palette_palette
-#LOCAL_USE_AAPT2 := true
-#
-#include $(BUILD_PACKAGE)
-#
-#endif # ifneq ($(TARGET_BUILD_PDK),true)
-#
-#include $(call all-makefiles-under,$(LOCAL_PATH))
+LOCAL_PATH := $(call my-dir)
+ifneq ($(TARGET_BUILD_PDK),true) # Build MediaComponents only if this is not a PDK build. MediaComponents won't
+# build in PDK builds because frameworks/base/core/java is not available but
+# IMediaSession2.aidl and IMediaController2.aidl are using classes from
+# frameworks/base/core/java.
+
+include $(CLEAR_VARS)
+
+LOCAL_PACKAGE_NAME := MediaComponents
+LOCAL_MODULE_OWNER := google
+
+# TODO: create a separate key for this package.
+LOCAL_CERTIFICATE := platform
+
+# TODO: Use System SDK once public APIs are approved
+# LOCAL_SDK_VERSION := system_current
+LOCAL_PRIVATE_PLATFORM_APIS := true
+
+LOCAL_SRC_FILES := \
+ $(call all-java-files-under, src) \
+ $(call all-Iaidl-files-under, src)
+
+LOCAL_PROGUARD_FLAG_FILES := proguard.cfg
+
+LOCAL_MULTILIB := first
+
+LOCAL_JAVA_LIBRARIES += androidx.annotation_annotation
+
+# To embed native libraries in package, uncomment the lines below.
+#LOCAL_MODULE_TAGS := samples
+#LOCAL_JNI_SHARED_LIBRARIES := \
+# libaacextractor \
+# libamrextractor \
+# libflacextractor \
+# libmidiextractor \
+# libmkvextractor \
+# libmp3extractor \
+# libmp4extractor \
+# libmpeg2extractor \
+# liboggextractor \
+# libwavextractor \
+
+# TODO: Remove dependency with other support libraries.
+LOCAL_STATIC_ANDROID_LIBRARIES += \
+ androidx.legacy_legacy-support-v4 \
+ androidx.appcompat_appcompat \
+ androidx.palette_palette
+LOCAL_USE_AAPT2 := true
+
+include $(BUILD_PACKAGE)
+
+endif # ifneq ($(TARGET_BUILD_PDK),true)
+
+include $(call all-makefiles-under,$(LOCAL_PATH))
diff --git a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
index ffb145a..7f16289 100644
--- a/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
+++ b/packages/MediaComponents/src/com/android/widget/VideoView2Impl.java
@@ -33,8 +33,7 @@
import android.media.MediaMetadata2;
import android.media.MediaMetadataRetriever;
import android.media.MediaPlayer2;
-import android.media.MediaPlayer2.MediaPlayer2EventCallback;
-import android.media.MediaPlayer2.OnSubtitleDataListener;
+import android.media.MediaPlayer2.EventCallback;
import android.media.MediaPlayer2Impl;
import android.media.Metadata;
import android.media.PlaybackParams;
@@ -716,13 +715,14 @@
}
try {
+ final Context context = mInstance.getContext();
+
Log.d(TAG, "openVideo(): creating new MediaPlayer2 instance.");
- mMediaPlayer = new MediaPlayer2Impl();
+ mMediaPlayer = new MediaPlayer2Impl(context);
mSurfaceView.setMediaPlayer(mMediaPlayer);
mTextureView.setMediaPlayer(mMediaPlayer);
mCurrentView.assignSurfaceToMediaPlayer(mMediaPlayer);
- final Context context = mInstance.getContext();
// TODO: Add timely firing logic for more accurate sync between CC and video frame
mSubtitleController = new SubtitleController(context);
mSubtitleController.registerRenderer(new ClosedCaptionRenderer(context));
@@ -733,12 +733,11 @@
runnable.run();
}
};
- mMediaPlayer.setMediaPlayer2EventCallback(executor, mMediaPlayer2Callback);
+ mMediaPlayer.registerEventCallback(executor, mMediaPlayer2Callback);
mCurrentBufferPercentage = -1;
mMediaPlayer.setDataSource(dsd);
mMediaPlayer.setAudioAttributes(mAudioAttributes);
- mMediaPlayer.setOnSubtitleDataListener(mSubtitleListener);
// we don't set the target state here either, but preserve the
// target state that was there before.
mCurrentState = STATE_PREPARING;
@@ -1106,10 +1105,10 @@
mInstance.addView(mMusicView, 0);
}
- OnSubtitleDataListener mSubtitleListener =
- new OnSubtitleDataListener() {
+ EventCallback mMediaPlayer2Callback =
+ new EventCallback() {
@Override
- public void onSubtitleData(MediaPlayer2 mp, SubtitleData data) {
+ public void onSubtitleData(MediaPlayer2 mp, DataSourceDesc dsd, SubtitleData data) {
if (DEBUG) {
Log.d(TAG, "onSubtitleData(): getTrackIndex: " + data.getTrackIndex()
+ ", getCurrentPosition: " + mp.getCurrentPosition()
@@ -1133,10 +1132,7 @@
}
}
}
- };
- MediaPlayer2EventCallback mMediaPlayer2Callback =
- new MediaPlayer2EventCallback() {
@Override
public void onVideoSizeChanged(
MediaPlayer2 mp, DataSourceDesc dsd, int width, int height) {
@@ -1169,7 +1165,7 @@
extractTracks();
} else if (what == MediaPlayer2.MEDIA_INFO_PREPARED) {
this.onPrepared(mp, dsd);
- } else if (what == MediaPlayer2.MEDIA_INFO_PLAYBACK_COMPLETE) {
+ } else if (what == MediaPlayer2.MEDIA_INFO_DATA_SOURCE_END) {
this.onCompletion(mp, dsd);
} else if (what == MediaPlayer2.MEDIA_INFO_BUFFERING_UPDATE) {
this.onBufferingUpdate(mp, dsd, extra);
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index 2c26ba4..c0aa477 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -42,7 +42,6 @@
LOCAL_STATIC_LIBRARIES := \
libcpustats \
- libjsoncpp \
libsndfile \
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 7db7d9f..06975ac 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -20,7 +20,6 @@
//#define LOG_NDEBUG 0
#include "Configuration.h"
-#include <algorithm> // std::any_of
#include <dirent.h>
#include <math.h>
#include <signal.h>
@@ -56,11 +55,8 @@
#include <system/audio_effects/effect_ns.h>
#include <system/audio_effects/effect_aec.h>
-#include <audio_utils/FdToString.h>
#include <audio_utils/primitives.h>
-#include <json/json.h>
-
#include <powermanager/PowerManager.h>
#include <media/IMediaLogService.h>
@@ -438,18 +434,6 @@
if (!dumpAllowed()) {
dumpPermissionDenial(fd, args);
} else {
- // XXX This is sort of hacky for now.
- const bool formatJson = std::any_of(args.begin(), args.end(),
- [](const String16 &arg) { return arg == String16("--json"); });
- if (formatJson) {
- Json::Value root = getJsonDump();
- Json::FastWriter writer;
- std::string rootStr = writer.write(root);
- // XXX consider buffering if the string happens to be too long.
- dprintf(fd, "%s", rootStr.c_str());
- return NO_ERROR;
- }
-
// get state of hardware lock
bool hardwareLocked = dumpTryLock(mHardwareLock);
if (!hardwareLocked) {
@@ -576,32 +560,6 @@
return NO_ERROR;
}
-Json::Value AudioFlinger::getJsonDump()
-{
- Json::Value root(Json::objectValue);
- const bool locked = dumpTryLock(mLock);
-
- // failed to lock - AudioFlinger is probably deadlocked
- if (!locked) {
- root["deadlock_message"] = kDeadlockedString;
- }
- // FIXME risky to access data structures without a lock held?
-
- Json::Value playbackThreads = Json::arrayValue;
- // dump playback threads
- for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- playbackThreads.append(mPlaybackThreads.valueAt(i)->getJsonDump());
- }
-
- if (locked) {
- mLock.unlock();
- }
-
- root["playback_threads"] = playbackThreads;
-
- return root;
-}
-
sp<AudioFlinger::Client> AudioFlinger::registerPid(pid_t pid)
{
Mutex::Autolock _cl(mClientLock);
@@ -788,7 +746,7 @@
output.afFrameCount = thread->frameCount();
output.afSampleRate = thread->sampleRate();
output.afLatencyMs = thread->latency();
- output.trackId = track->id();
+ output.trackId = track == nullptr ? -1 : track->id();
// move effect chain to this output thread if an effect on same session was waiting
// for a track to be created
@@ -2300,15 +2258,7 @@
if (playbackThread != NULL) {
ALOGV("closeOutput() %d", output);
- {
- // Dump thread before deleting for history
- audio_utils::FdToString fdToString;
- const int fd = fdToString.fd();
- if (fd >= 0) {
- playbackThread->dump(fd, {} /* args */);
- mThreadLog.logs(-1 /* time */, fdToString.getStringAndClose());
- }
- }
+ dumpToThreadLog_l(playbackThread);
if (playbackThread->type() == ThreadBase::MIXER) {
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
@@ -2341,6 +2291,7 @@
if (mmapThread == 0) {
return BAD_VALUE;
}
+ dumpToThreadLog_l(mmapThread);
mMmapThreads.removeItem(output);
ALOGD("closing mmapThread %p", mmapThread.get());
}
@@ -2549,6 +2500,8 @@
if (recordThread != 0) {
ALOGV("closeInput() %d", input);
+ dumpToThreadLog_l(recordThread);
+
// If we still have effect chains, it means that a client still holds a handle
// on at least one effect. We must either move the chain to an existing thread with the
// same session ID or put it aside in case a new record thread is opened for a
@@ -2591,6 +2544,7 @@
if (mmapThread == 0) {
return BAD_VALUE;
}
+ dumpToThreadLog_l(mmapThread);
mMmapThreads.removeItem(input);
}
const sp<AudioIoDescriptor> ioDesc = new AudioIoDescriptor();
@@ -2789,6 +2743,17 @@
return;
}
+// dumpToThreadLog_l() must be called with AudioFlinger::mLock held
+void AudioFlinger::dumpToThreadLog_l(const sp<ThreadBase> &thread)
+{
+ audio_utils::FdToString fdToString;
+ const int fd = fdToString.fd();
+ if (fd >= 0) {
+ thread->dump(fd, {} /* args */);
+ mThreadLog.logs(-1 /* time */, fdToString.getStringAndClose());
+ }
+}
+
// checkThread_l() must be called with AudioFlinger::mLock held
AudioFlinger::ThreadBase *AudioFlinger::checkThread_l(audio_io_handle_t ioHandle) const
{
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 53a7a8f..b6b3815 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -23,7 +23,6 @@
#include <mutex>
#include <deque>
#include <map>
-#include <memory>
#include <set>
#include <string>
#include <vector>
@@ -66,6 +65,7 @@
#include <media/VolumeShaper.h>
#include <audio_utils/clock.h>
+#include <audio_utils/FdToString.h>
#include <audio_utils/SimpleLog.h>
#include <audio_utils/TimestampVerifier.h>
@@ -80,7 +80,6 @@
#include <powermanager/IPowerManager.h>
-#include <json/json.h>
#include <media/nblog/NBLog.h>
#include <private/media/AudioEffectShared.h>
#include <private/media/AudioTrackShared.h>
@@ -116,7 +115,6 @@
static const char* getServiceName() ANDROID_API { return "media.audio_flinger"; }
virtual status_t dump(int fd, const Vector<String16>& args);
- Json::Value getJsonDump();
// IAudioFlinger interface, in binder opcode order
virtual sp<IAudioTrack> createTrack(const CreateTrackInput& input,
@@ -426,7 +424,10 @@
void dumpClients(int fd, const Vector<String16>& args);
void dumpInternals(int fd, const Vector<String16>& args);
- SimpleLog mThreadLog{10}; // 10 Thread history limit
+ SimpleLog mThreadLog{16}; // 16 Thread history limit
+
+ class ThreadBase;
+ void dumpToThreadLog_l(const sp<ThreadBase> &thread);
// --- Client ---
class Client : public RefBase {
diff --git a/services/audioflinger/Configuration.h b/services/audioflinger/Configuration.h
index 34cd821..ede8e3f 100644
--- a/services/audioflinger/Configuration.h
+++ b/services/audioflinger/Configuration.h
@@ -27,7 +27,7 @@
//#define AUDIO_WATCHDOG
// uncomment to display CPU load adjusted for CPU frequency
-//define CPU_FREQUENCY_STATISTICS
+//#define CPU_FREQUENCY_STATISTICS
// uncomment to enable fast threads to take performance samples for later statistical analysis
#define FAST_THREAD_STATISTICS
diff --git a/services/audioflinger/Effects.cpp b/services/audioflinger/Effects.cpp
index 6cab441..1ce48a9 100644
--- a/services/audioflinger/Effects.cpp
+++ b/services/audioflinger/Effects.cpp
@@ -248,7 +248,7 @@
switch (mState) {
case RESTART:
reset_l();
- // FALL THROUGH
+ FALLTHROUGH_INTENDED;
case STARTING:
// clear auxiliary effect input buffer for next accumulation
diff --git a/services/audioflinger/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index f650b66..d15841f 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -195,9 +195,10 @@
// to avoid blocking here and to prevent possible priority inversion
mMixer = new AudioMixer(frameCount, mSampleRate);
// FIXME See the other FIXME at FastMixer::setNBLogWriter()
- // TODO define an int to thread type mapping for the "2" below.
- const NBLog::thread_info_t info = { 2 /*FastMixer*/, frameCount, mSampleRate };
- LOG_THREAD_INFO(info);
+ NBLog::thread_params_t params;
+ params.frameCount = frameCount;
+ params.sampleRate = mSampleRate;
+ LOG_THREAD_PARAMS(params);
const size_t mixerFrameSize = mSinkChannelCount
* audio_bytes_per_sample(mMixerBufferFormat);
mMixerBufferSize = mixerFrameSize * frameCount;
diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
index 2abfbfb..a42e09c 100644
--- a/services/audioflinger/FastMixerDumpState.cpp
+++ b/services/audioflinger/FastMixerDumpState.cpp
@@ -24,8 +24,6 @@
#include <cpustats/ThreadCpuUsage.h>
#endif
#endif
-#include <json/json.h>
-#include <string>
#include <utils/Debug.h>
#include <utils/Log.h>
#include "FastMixerDumpState.h"
@@ -206,49 +204,4 @@
}
}
-Json::Value FastMixerDumpState::getJsonDump() const
-{
- Json::Value root(Json::objectValue);
- if (mCommand == FastMixerState::INITIAL) {
- root["status"] = "uninitialized";
- return root;
- }
-#ifdef FAST_THREAD_STATISTICS
- // find the interval of valid samples
- const uint32_t bounds = mBounds;
- const uint32_t newestOpen = bounds & 0xFFFF;
- uint32_t oldestClosed = bounds >> 16;
-
- //uint32_t n = (newestOpen - oldestClosed) & 0xFFFF;
- uint32_t n;
- __builtin_sub_overflow(newestOpen, oldestClosed, &n);
- n &= 0xFFFF;
-
- if (n > mSamplingN) {
- ALOGE("too many samples %u", n);
- n = mSamplingN;
- }
- // statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
- // and adjusted CPU load in MHz normalized for CPU clock frequency
- Json::Value jsonWall(Json::arrayValue);
- Json::Value jsonLoadNs(Json::arrayValue);
- // loop over all the samples
- for (uint32_t j = 0; j < n; ++j) {
- size_t i = oldestClosed++ & (mSamplingN - 1);
- uint32_t wallNs = mMonotonicNs[i];
- jsonWall.append(wallNs);
- uint32_t sampleLoadNs = mLoadNs[i];
- jsonLoadNs.append(sampleLoadNs);
- }
- if (n) {
- root["wall_clock_time_ns"] = jsonWall;
- root["raw_cpu_load_ns"] = jsonLoadNs;
- root["status"] = "ok";
- } else {
- root["status"] = "unavailable";
- }
-#endif
- return root;
-}
-
} // android
diff --git a/services/audioflinger/FastMixerDumpState.h b/services/audioflinger/FastMixerDumpState.h
index 69c2e4e..9b91cbc 100644
--- a/services/audioflinger/FastMixerDumpState.h
+++ b/services/audioflinger/FastMixerDumpState.h
@@ -18,9 +18,7 @@
#define ANDROID_AUDIO_FAST_MIXER_DUMP_STATE_H
#include <stdint.h>
-#include <string>
#include <audio_utils/TimestampVerifier.h>
-#include <json/json.h>
#include "Configuration.h"
#include "FastThreadDumpState.h"
#include "FastMixerState.h"
@@ -67,8 +65,7 @@
FastMixerDumpState();
/*virtual*/ ~FastMixerDumpState();
- void dump(int fd) const; // should only be called on a stable copy, not the original
- Json::Value getJsonDump() const; // should only be called on a stable copy, not the original
+ void dump(int fd) const; // should only be called on a stable copy, not the original
double mLatencyMs = 0.; // measured latency, default of 0 if no valid timestamp read.
uint32_t mWriteSequence; // incremented before and after each write()
diff --git a/services/audioflinger/FastThread.cpp b/services/audioflinger/FastThread.cpp
index 09101d9..04b32c2 100644
--- a/services/audioflinger/FastThread.cpp
+++ b/services/audioflinger/FastThread.cpp
@@ -66,8 +66,6 @@
/* mMeasuredWarmupTs({0, 0}), */
mWarmupCycles(0),
mWarmupConsecutiveInRangeCycles(0),
- // mDummyNBLogWriter
- mNBLogWriter(&mDummyNBLogWriter),
mTimestampStatus(INVALID_OPERATION),
mCommand(FastThreadState::INITIAL),
@@ -94,7 +92,7 @@
{
// LOGT now works even if tlNBLogWriter is nullptr, but we're considering changing that,
// so this initialization permits a future change to remove the check for nullptr.
- tlNBLogWriter = &mDummyNBLogWriter;
+ tlNBLogWriter = mDummyNBLogWriter.get();
for (;;) {
// either nanosleep, sched_yield, or busy wait
@@ -124,9 +122,9 @@
// As soon as possible of learning of a new dump area, start using it
mDumpState = next->mDumpState != NULL ? next->mDumpState : mDummyDumpState;
- mNBLogWriter = next->mNBLogWriter != NULL ? next->mNBLogWriter : &mDummyNBLogWriter;
- setNBLogWriter(mNBLogWriter); // FastMixer informs its AudioMixer, FastCapture ignores
- tlNBLogWriter = mNBLogWriter;
+ tlNBLogWriter = next->mNBLogWriter != NULL ?
+ next->mNBLogWriter : mDummyNBLogWriter.get();
+ setNBLogWriter(tlNBLogWriter); // FastMixer informs its AudioMixer, FastCapture ignores
// We want to always have a valid reference to the previous (non-idle) state.
// However, the state queue only guarantees access to current and previous states.
diff --git a/services/audioflinger/FastThread.h b/services/audioflinger/FastThread.h
index 2a71414..3f6b206 100644
--- a/services/audioflinger/FastThread.h
+++ b/services/audioflinger/FastThread.h
@@ -78,12 +78,11 @@
unsigned mColdGen; // last observed mColdGen
bool mIsWarm; // true means ready to mix,
// false means wait for warmup before mixing
- struct timespec mMeasuredWarmupTs; // how long did it take for warmup to complete
- uint32_t mWarmupCycles; // counter of number of loop cycles during warmup phase
- uint32_t mWarmupConsecutiveInRangeCycles; // number of consecutive cycles in range
- NBLog::Writer mDummyNBLogWriter;
- NBLog::Writer* mNBLogWriter; // always non-nullptr: real NBLog::Writer* or &mDummyNBLogWriter
- status_t mTimestampStatus;
+ struct timespec mMeasuredWarmupTs; // how long did it take for warmup to complete
+ uint32_t mWarmupCycles; // counter of number of loop cycles during warmup phase
+ uint32_t mWarmupConsecutiveInRangeCycles; // number of consecutive cycles in range
+ const sp<NBLog::Writer> mDummyNBLogWriter{new NBLog::Writer()};
+ status_t mTimestampStatus;
FastThreadState::Command mCommand;
bool mAttemptedWrite;
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 811f09a..01c5ea2 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -42,7 +42,6 @@
#include <audio_utils/primitives.h>
#include <audio_utils/format.h>
#include <audio_utils/minifloat.h>
-#include <json/json.h>
#include <system/audio_effects/effect_ns.h>
#include <system/audio_effects/effect_aec.h>
#include <system/audio.h>
@@ -1776,11 +1775,6 @@
mLocalLog.dump(fd, " " /* prefix */, 40 /* lines */);
}
-Json::Value AudioFlinger::PlaybackThread::getJsonDump() const
-{
- return Json::Value(Json::objectValue);
-}
-
void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args __unused)
{
String8 result;
@@ -2800,22 +2794,18 @@
void AudioFlinger::PlaybackThread::threadLoop_removeTracks(
const Vector< sp<Track> >& tracksToRemove)
{
- size_t count = tracksToRemove.size();
- if (count > 0) {
- for (size_t i = 0 ; i < count ; i++) {
- const sp<Track>& track = tracksToRemove.itemAt(i);
- if (track->isExternalTrack()) {
- AudioSystem::stopOutput(track->portId());
+ // Miscellaneous track cleanup when removed from the active list,
+ // called without Thread lock but synchronized with threadLoop processing.
#ifdef ADD_BATTERY_DATA
- // to track the speaker usage
- addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop);
-#endif
- if (track->isTerminated()) {
- AudioSystem::releaseOutput(track->portId());
- }
- }
+ for (const auto& track : tracksToRemove) {
+ if (track->isExternalTrack()) {
+ // to track the speaker usage
+ addBatteryData(IMediaPlayerService::kBatteryDataAudioFlingerStop);
}
}
+#else
+ (void)tracksToRemove; // suppress unused warning
+#endif
}
void AudioFlinger::PlaybackThread::checkSilentMode_l()
@@ -3716,24 +3706,28 @@
// removeTracks_l() must be called with ThreadBase::mLock held
void AudioFlinger::PlaybackThread::removeTracks_l(const Vector< sp<Track> >& tracksToRemove)
{
- size_t count = tracksToRemove.size();
- if (count > 0) {
- for (size_t i=0 ; i<count ; i++) {
- const sp<Track>& track = tracksToRemove.itemAt(i);
- mActiveTracks.remove(track);
- ALOGV("removeTracks_l removing track on session %d", track->sessionId());
- sp<EffectChain> chain = getEffectChain_l(track->sessionId());
- if (chain != 0) {
- ALOGV("stopping track on chain %p for session Id: %d", chain.get(),
- track->sessionId());
- chain->decActiveTrackCnt();
- }
+ for (const auto& track : tracksToRemove) {
+ mActiveTracks.remove(track);
+ ALOGV("%s(%d): removing track on session %d", __func__, track->id(), track->sessionId());
+ sp<EffectChain> chain = getEffectChain_l(track->sessionId());
+ if (chain != 0) {
+ ALOGV("%s(%d): stopping track on chain %p for session Id: %d",
+ __func__, track->id(), chain.get(), track->sessionId());
+ chain->decActiveTrackCnt();
+ }
+ // If an external client track, inform APM we're no longer active, and remove if needed.
+ // We do this under lock so that the state is consistent if the Track is destroyed.
+ if (track->isExternalTrack()) {
+ AudioSystem::stopOutput(track->portId());
if (track->isTerminated()) {
- removeTrack_l(track);
+ AudioSystem::releaseOutput(track->portId());
}
}
+ if (track->isTerminated()) {
+ // remove from our tracks vector
+ removeTrack_l(track);
+ }
}
-
}
status_t AudioFlinger::PlaybackThread::getTimestamp_l(AudioTimestamp& timestamp)
@@ -4033,6 +4027,11 @@
sq->end();
sq->push(FastMixerStateQueue::BLOCK_UNTIL_PUSHED);
+ NBLog::thread_info_t info;
+ info.id = mId;
+ info.type = NBLog::FASTMIXER;
+ mFastMixerNBLogWriter->log<NBLog::EVENT_THREAD_INFO>(info);
+
// start the fast mixer
mFastMixer->run("FastMixer", PRIORITY_URGENT_AUDIO);
pid_t tid = mFastMixer->getTid();
@@ -4116,12 +4115,6 @@
return latency;
}
-
-void AudioFlinger::MixerThread::threadLoop_removeTracks(const Vector< sp<Track> >& tracksToRemove)
-{
- PlaybackThread::threadLoop_removeTracks(tracksToRemove);
-}
-
ssize_t AudioFlinger::MixerThread::threadLoop_write()
{
// FIXME we should only do one push per cycle; confirm this is true
@@ -4487,7 +4480,7 @@
isActive = false;
break;
}
- // fall through
+ FALLTHROUGH_INTENDED;
case TrackBase::STOPPING_2:
case TrackBase::PAUSED:
case TrackBase::STOPPED:
@@ -5177,7 +5170,8 @@
// while we are dumping it. It may be inconsistent, but it won't mutate!
// This is a large object so we place it on the heap.
// FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
- const std::unique_ptr<FastMixerDumpState> copy(new FastMixerDumpState(mFastMixerDumpState));
+ const std::unique_ptr<FastMixerDumpState> copy =
+ std::make_unique<FastMixerDumpState>(mFastMixerDumpState);
copy->dump(fd);
#ifdef STATE_QUEUE_DUMP
@@ -5201,22 +5195,6 @@
}
}
-Json::Value AudioFlinger::MixerThread::getJsonDump() const
-{
- Json::Value root;
- if (hasFastMixer()) {
- // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
- // while we are dumping it. It may be inconsistent, but it won't mutate!
- // This is a large object so we place it on the heap.
- // FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
- const std::unique_ptr<FastMixerDumpState> copy(new FastMixerDumpState(mFastMixerDumpState));
- root["fastmixer_stats"] = copy->getJsonDump();
- } else {
- root["fastmixer_stats"] = "no_fastmixer";
- }
- return root;
-}
-
uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const
{
return (uint32_t)(((mNormalFrameCount * 1000) / mSampleRate) * 1000) / 2;
@@ -6979,7 +6957,7 @@
framesIn, mSampleRate, activeTrack->mSampleRate));
if (activeTrack->isDirect()) {
- // No RecordBufferConverter used for compressed formats. Pass
+ // No RecordBufferConverter used for direct streams. Pass
// straight from RecordThread buffer to RecordTrack buffer.
AudioBufferProvider::Buffer buffer;
buffer.frameCount = framesOut;
@@ -6989,7 +6967,7 @@
"%s() read less than expected (%zu vs %zu)",
__func__, buffer.frameCount, framesOut);
framesOut = buffer.frameCount;
- memcpy(activeTrack->mSink.raw, buffer.raw, buffer.frameCount);
+ memcpy(activeTrack->mSink.raw, buffer.raw, buffer.frameCount * mFrameSize);
activeTrack->mResamplerBufferProvider->releaseBuffer(&buffer);
} else {
framesOut = 0;
@@ -7565,7 +7543,8 @@
// while we are dumping it. It may be inconsistent, but it won't mutate!
// This is a large object so we place it on the heap.
// FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
- std::unique_ptr<FastCaptureDumpState> copy(new FastCaptureDumpState(mFastCaptureDumpState));
+ const std::unique_ptr<FastCaptureDumpState> copy =
+ std::make_unique<FastCaptureDumpState>(mFastCaptureDumpState);
copy->dump(fd);
}
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index b6e8abf..61f7baf 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -397,6 +397,8 @@
bool isMsdDevice() const { return mIsMsdDevice; }
+ virtual void dump(int fd, const Vector<String16>& args) = 0;
+
mutable Mutex mLock;
protected:
@@ -665,9 +667,7 @@
audio_io_handle_t id, audio_devices_t device, type_t type, bool systemReady);
virtual ~PlaybackThread();
- void dump(int fd, const Vector<String16>& args);
- // returns a string of audio performance related data in JSON format.
- virtual Json::Value getJsonDump() const;
+ void dump(int fd, const Vector<String16>& args) override;
// Thread virtuals
virtual bool threadLoop();
@@ -1114,7 +1114,6 @@
virtual bool checkForNewParameter_l(const String8& keyValuePair,
status_t& status);
virtual void dumpInternals(int fd, const Vector<String16>& args);
- Json::Value getJsonDump() const override;
virtual bool isTrackAllowed_l(
audio_channel_mask_t channelMask, audio_format_t format,
@@ -1138,7 +1137,6 @@
virtual void threadLoop_standby();
virtual void threadLoop_mix();
virtual void threadLoop_sleepTime();
- virtual void threadLoop_removeTracks(const Vector< sp<Track> >& tracksToRemove);
virtual uint32_t correctLatency_l(uint32_t latency) const;
virtual status_t createAudioPatch_l(const struct audio_patch *patch,
@@ -1480,7 +1478,7 @@
// return true if the caller should then do it's part of the stopping process
bool stop(RecordTrack* recordTrack);
- void dump(int fd, const Vector<String16>& args);
+ void dump(int fd, const Vector<String16>& args) override;
AudioStreamIn* clearInput();
virtual sp<StreamHalInterface> stream() const;
@@ -1689,7 +1687,7 @@
// Sets the UID records silence
virtual void setRecordSilenced(uid_t uid __unused, bool silenced __unused) {}
- void dump(int fd, const Vector<String16>& args);
+ void dump(int fd, const Vector<String16>& args) override;
virtual void dumpInternals(int fd, const Vector<String16>& args);
void dumpTracks(int fd, const Vector<String16>& args);
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 6a3b06d..a99bbe1 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -857,7 +857,7 @@
// Offloaded track was draining, we need to carry on draining when resumed
mResumeToStopping = true;
- // fall through...
+ FALLTHROUGH_INTENDED;
case ACTIVE:
case RESUMING:
mState = PAUSING;
diff --git a/services/audioflinger/TypedLogger.h b/services/audioflinger/TypedLogger.h
index dd2e7c9..6ef19bf 100644
--- a/services/audioflinger/TypedLogger.h
+++ b/services/audioflinger/TypedLogger.h
@@ -97,24 +97,11 @@
#define LOG_AUDIO_STATE() do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
x->logEventHistTs(NBLog::EVENT_AUDIO_STATE, hash(__FILE__, __LINE__)); } while(0)
-// Record a typed entry that represents a thread's work time in nanoseconds.
-// Parameter ns should be of type uint32_t.
-#define LOG_WORK_TIME(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
- x->log<NBLog::EVENT_WORK_TIME>(ns); } while (0)
-
// Log the difference bewteen frames presented by HAL and frames written to HAL output sink,
// divided by the sample rate. Parameter ms is of type double.
#define LOG_LATENCY(ms) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
x->log<NBLog::EVENT_LATENCY>(ms); } while (0)
-// Record thread warmup time in milliseconds. Parameter ms is of type double.
-#define LOG_WARMUP_TIME(ms) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
- x->log<NBLog::EVENT_WARMUP_TIME>(ms); } while (0)
-
-// Record thread underrun event nanosecond timestamp. Parameter ns is an int64_t.
-#define LOG_UNDERRUN(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
- x->log<NBLog::EVENT_UNDERRUN>(ns); } while (0)
-
// Record thread overrun event nanosecond timestamp. Parameter ns is an int64_t.
#define LOG_OVERRUN(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
x->log<NBLog::EVENT_OVERRUN>(ns); } while (0)
@@ -124,8 +111,28 @@
#define LOG_THREAD_INFO(info) do { NBLog::Writer *x = tlNBLogWriter; \
if (x != nullptr) x->log<NBLog::EVENT_THREAD_INFO>(info); } while (0)
+#define LOG_THREAD_PARAMS(params) do {NBLog::Writer *x = tlNBLogWriter; \
+ if (x != nullptr) x->log<NBLog::EVENT_THREAD_PARAMS>(params); } while (0)
+
+// Record thread underrun event nanosecond timestamp. Parameter ns is an int64_t.
+#define LOG_UNDERRUN(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+ x->log<NBLog::EVENT_UNDERRUN>(ns); } while (0)
+
+// Record thread warmup time in milliseconds. Parameter ms is of type double.
+#define LOG_WARMUP_TIME(ms) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+ x->log<NBLog::EVENT_WARMUP_TIME>(ms); } while (0)
+
+// Record a typed entry that represents a thread's work time in nanoseconds.
+// Parameter ns should be of type uint32_t.
+#define LOG_WORK_TIME(ns) do { NBLog::Writer *x = tlNBLogWriter; if (x != nullptr) \
+ x->log<NBLog::EVENT_WORK_TIME>(ns); } while (0)
+
namespace android {
extern "C" {
+// TODO consider adding a thread_local NBLog::Writer tlDummyNBLogWriter and then
+// initialize below tlNBLogWriter to &tlDummyNBLogWriter to remove the need to
+// check for nullptr every time. Also reduces the need to add a new logging macro above
+// each time we want to log a new type.
extern thread_local NBLog::Writer *tlNBLogWriter;
}
} // namespace android
diff --git a/services/audiopolicy/Android.mk b/services/audiopolicy/Android.mk
index b75e957..f23e426 100644
--- a/services/audiopolicy/Android.mk
+++ b/services/audiopolicy/Android.mk
@@ -73,6 +73,7 @@
LOCAL_C_INCLUDES += \
frameworks/av/services/audiopolicy/common/include \
frameworks/av/services/audiopolicy/engine/interface \
+ $(call include-path-for, audio-utils) \
LOCAL_STATIC_LIBRARIES := \
libaudiopolicycomponents
@@ -81,7 +82,7 @@
LOCAL_SHARED_LIBRARIES += libmediametrics
ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
-LOCAL_SHARED_LIBRARIES += libicuuc libxml2
+LOCAL_SHARED_LIBRARIES += libhidlbase libicuuc libxml2
LOCAL_CFLAGS += -DUSE_XML_AUDIO_POLICY_CONF
endif #ifeq ($(USE_XML_AUDIO_POLICY_CONF), 1)
@@ -109,7 +110,8 @@
LOCAL_C_INCLUDES += \
frameworks/av/services/audiopolicy/common/include \
- frameworks/av/services/audiopolicy/engine/interface
+ frameworks/av/services/audiopolicy/engine/interface \
+ $(call include-path-for, audio-utils) \
LOCAL_CFLAGS := -Wall -Werror
diff --git a/services/audiopolicy/common/include/Volume.h b/services/audiopolicy/common/include/Volume.h
index fc012a2..5ccc8fd 100644
--- a/services/audiopolicy/common/include/Volume.h
+++ b/services/audiopolicy/common/include/Volume.h
@@ -134,6 +134,7 @@
case AUDIO_DEVICE_OUT_USB_DEVICE:
return DEVICE_CATEGORY_EXT_MEDIA;
case AUDIO_DEVICE_OUT_SPEAKER:
+ case AUDIO_DEVICE_OUT_SPEAKER_SAFE:
case AUDIO_DEVICE_OUT_BLUETOOTH_SCO_CARKIT:
case AUDIO_DEVICE_OUT_BLUETOOTH_A2DP_SPEAKER:
case AUDIO_DEVICE_OUT_USB_ACCESSORY:
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index bacb780..3336b79 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -39,7 +39,7 @@
LOCAL_SRC_FILES += src/Serializer.cpp
-LOCAL_SHARED_LIBRARIES += libicuuc libxml2
+LOCAL_SHARED_LIBRARIES += libhidlbase libicuuc libxml2
LOCAL_C_INCLUDES += \
external/libxml2/include \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
index f86e75a..a948ea9 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioCollections.h
@@ -38,7 +38,7 @@
class AudioRouteVector : public Vector<sp<AudioRoute> >
{
public:
- status_t dump(int fd, int spaces) const;
+ void dump(String8 *dst, int spaces) const;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
index 4ac508f..996347b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioGain.h
@@ -18,6 +18,7 @@
#include <utils/Errors.h>
#include <utils/RefBase.h>
+#include <utils/String8.h>
#include <system/audio.h>
namespace android {
@@ -53,7 +54,7 @@
int getMaxRampInMs() const { return mGain.max_ramp_ms; }
// TODO: remove dump from here (split serialization)
- void dump(int fd, int spaces, int index) const;
+ void dump(String8 *dst, int spaces, int index) const;
void getDefaultConfig(struct audio_gain_config *config);
status_t checkConfig(const struct audio_gain_config *config);
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index 72d5a8c..6e4c044 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -33,6 +33,7 @@
// descriptor for audio inputs. Used to maintain current configuration of each opened audio input
// and keep track of the usage of this input.
class AudioInputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
+ , public ClientMapHandler<RecordClientDescriptor>
{
public:
explicit AudioInputDescriptor(const sp<IOProfile>& profile,
@@ -40,12 +41,12 @@
audio_port_handle_t getId() const;
audio_module_handle_t getModuleHandle() const;
- status_t dump(int fd);
+ void dump(String8 *dst) const override;
- audio_io_handle_t mIoHandle; // input handle
- audio_devices_t mDevice; // current device this input is routed to
- AudioMix *mPolicyMix; // non NULL when used by a dynamic policy
- const sp<IOProfile> mProfile; // I/O profile this output derives from
+ audio_io_handle_t mIoHandle = AUDIO_IO_HANDLE_NONE; // input handle
+ audio_devices_t mDevice = AUDIO_DEVICE_NONE; // current device this input is routed to
+ AudioMix *mPolicyMix = nullptr; // non NULL when used by a dynamic policy
+ const sp<IOProfile> mProfile; // I/O profile this output derives from
virtual void toAudioPortConfig(struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig = NULL) const;
@@ -82,7 +83,6 @@
void stop();
void close();
- RecordClientMap& clientsMap() { return mClients; }
RecordClientVector getClientsForSession(audio_session_t session);
RecordClientVector clientsList(bool activeOnly = false,
audio_source_t source = AUDIO_SOURCE_DEFAULT, bool preferredDeviceOnly = false) const;
@@ -91,8 +91,8 @@
void updateClientRecordingConfiguration(int event, const sp<RecordClientDescriptor>& client);
- audio_patch_handle_t mPatchHandle;
- audio_port_handle_t mId;
+ audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
// Because a preemptible capture session can preempt another one, we end up in an endless loop
// situation were each session is allowed to restart after being preempted,
// thus preempting the other one which restarts and so on.
@@ -100,10 +100,8 @@
// a particular input started and prevent preemption of this active input by this session.
// We also inherit sessions from the preempted input to avoid a 3 way preemption loop etc...
SortedVector<audio_session_t> mPreemptedSessions;
- AudioPolicyClientInterface *mClientInterface;
- int32_t mGlobalActiveCount; // non-client-specific activity ref count
-
- RecordClientMap mClients;
+ AudioPolicyClientInterface * const mClientInterface;
+ int32_t mGlobalActiveCount = 0; // non-client-specific activity ref count
};
class AudioInputCollection :
@@ -129,7 +127,7 @@
sp<AudioInputDescriptor> getInputForClient(audio_port_handle_t portId);
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 27b1c93..ed995e0 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -17,6 +17,7 @@
#pragma once
#include <sys/types.h>
+
#include <utils/Errors.h>
#include <utils/Timers.h>
#include <utils/KeyedVector.h>
@@ -36,13 +37,14 @@
// descriptor for audio outputs. Used to maintain current configuration of each opened audio output
// and keep track of the usage of this output by each audio stream type.
class AudioOutputDescriptor: public AudioPortConfig, public AudioIODescriptorInterface
+ , public ClientMapHandler<TrackClientDescriptor>
{
public:
AudioOutputDescriptor(const sp<AudioPort>& port,
AudioPolicyClientInterface *clientInterface);
virtual ~AudioOutputDescriptor() {}
- status_t dump(int fd);
+ void dump(String8 *dst) const override;
void log(const char* indent);
audio_port_handle_t getId() const;
@@ -59,9 +61,21 @@
audio_devices_t device,
uint32_t delayMs,
bool force);
- virtual void changeStreamActiveCount(audio_stream_type_t stream, int delta);
+
+ /**
+ * Changes the stream active count and mActiveClients only.
+ * This does not change the client->active() state or the output descriptor's
+ * global active count.
+ */
+ virtual void changeStreamActiveCount(const sp<TrackClientDescriptor>& client, int delta);
uint32_t streamActiveCount(audio_stream_type_t stream) const
{ return mActiveCount[stream]; }
+
+ /**
+ * Changes the client->active() state and the output descriptor's global active count,
+ * along with the stream active count and mActiveClients.
+ * The client must be previously added by the base class addClient().
+ */
void setClientActive(const sp<TrackClientDescriptor>& client, bool active);
bool isActive(uint32_t inPastMs = 0) const;
@@ -81,26 +95,51 @@
audio_patch_handle_t getPatchHandle() const override;
void setPatchHandle(audio_patch_handle_t handle) override;
- TrackClientMap& clientsMap() { return mClients; }
TrackClientVector clientsList(bool activeOnly = false,
routing_strategy strategy = STRATEGY_NONE, bool preferredDeviceOnly = false) const;
- sp<AudioPort> mPort;
- audio_devices_t mDevice; // current device this output is routed to
+ // override ClientMapHandler to abort when removing a client when active.
+ void removeClient(audio_port_handle_t portId) override {
+ auto client = getClient(portId);
+ LOG_ALWAYS_FATAL_IF(client.get() == nullptr,
+ "%s(%d): nonexistent client portId %d", __func__, mId, portId);
+ // it is possible that when a client is removed, we could remove its
+ // associated active count by calling changeStreamActiveCount(),
+ // but that would be hiding a problem, so we log fatal instead.
+ auto it2 = mActiveClients.find(client);
+ LOG_ALWAYS_FATAL_IF(it2 != mActiveClients.end(),
+ "%s(%d) removing client portId %d which is active (count %zu)",
+ __func__, mId, portId, it2->second);
+ ClientMapHandler<TrackClientDescriptor>::removeClient(portId);
+ }
+
+ using ActiveClientMap = std::map<sp<TrackClientDescriptor>, size_t /* count */>;
+ // required for duplicating thread
+ const ActiveClientMap& getActiveClients() const {
+ return mActiveClients;
+ }
+
+ audio_devices_t mDevice = AUDIO_DEVICE_NONE; // current device this output is routed to
nsecs_t mStopTime[AUDIO_STREAM_CNT];
- float mCurVolume[AUDIO_STREAM_CNT]; // current stream volume in dB
- int mMuteCount[AUDIO_STREAM_CNT]; // mute request counter
+ int mMuteCount[AUDIO_STREAM_CNT]; // mute request counter
bool mStrategyMutedByDevice[NUM_STRATEGIES]; // strategies muted because of incompatible
// device selection. See checkDeviceMuteStrategies()
- AudioPolicyClientInterface *mClientInterface;
- AudioMix *mPolicyMix; // non NULL when used by a dynamic policy
+ AudioMix *mPolicyMix = nullptr; // non NULL when used by a dynamic policy
protected:
+ const sp<AudioPort> mPort;
+ AudioPolicyClientInterface * const mClientInterface;
+ float mCurVolume[AUDIO_STREAM_CNT]; // current stream volume in dB
uint32_t mActiveCount[AUDIO_STREAM_CNT]; // number of streams of each type active on this output
- uint32_t mGlobalActiveCount; // non-client-specific active count
- audio_patch_handle_t mPatchHandle;
- audio_port_handle_t mId;
- TrackClientMap mClients;
+ uint32_t mGlobalActiveCount = 0; // non-client-specific active count
+ audio_patch_handle_t mPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ audio_port_handle_t mId = AUDIO_PORT_HANDLE_NONE;
+
+ // The ActiveClientMap shows the clients that contribute to the streams counts
+ // and may include upstream clients from a duplicating thread.
+ // Compare with the ClientMap (mClients) which are external AudioTrack clients of the
+ // output descriptor (and do not count internal PatchTracks).
+ ActiveClientMap mActiveClients;
};
// Audio output driven by a software mixer in audio flinger.
@@ -111,8 +150,7 @@
AudioPolicyClientInterface *clientInterface);
virtual ~SwAudioOutputDescriptor() {}
- status_t dump(int fd);
-
+ void dump(String8 *dst) const override;
virtual audio_devices_t device() const;
virtual bool sharesHwModuleWith(const sp<AudioOutputDescriptor>& outputDesc);
virtual audio_devices_t supportedDevices();
@@ -121,7 +159,8 @@
virtual bool isFixedVolume(audio_devices_t device);
virtual sp<AudioOutputDescriptor> subOutput1() { return mOutput1; }
virtual sp<AudioOutputDescriptor> subOutput2() { return mOutput2; }
- virtual void changeStreamActiveCount(audio_stream_type_t stream, int delta);
+ void changeStreamActiveCount(
+ const sp<TrackClientDescriptor>& client, int delta) override;
virtual bool setVolume(float volume,
audio_stream_type_t stream,
audio_devices_t device,
@@ -167,7 +206,7 @@
AudioPolicyClientInterface *clientInterface);
virtual ~HwAudioOutputDescriptor() {}
- status_t dump(int fd);
+ void dump(String8 *dst) const override;
virtual audio_devices_t supportedDevices();
virtual bool setVolume(float volume,
@@ -236,7 +275,7 @@
sp<SwAudioOutputDescriptor> getOutputForClient(audio_port_handle_t portId);
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
class HwAudioOutputCollection :
@@ -250,7 +289,7 @@
*/
bool isAnyOutputActive(audio_stream_type_t streamToIgnore) const;
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h b/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
index c1c3f3c..0843fea 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPatch.h
@@ -22,6 +22,7 @@
#include <utils/RefBase.h>
#include <utils/Errors.h>
#include <utils/KeyedVector.h>
+#include <utils/String8.h>
namespace android {
@@ -30,7 +31,7 @@
public:
AudioPatch(const struct audio_patch *patch, uid_t uid);
- status_t dump(int fd, int spaces, int index) const;
+ void dump(String8 *dst, int spaces, int index) const;
audio_patch_handle_t mHandle;
struct audio_patch mPatch;
@@ -47,7 +48,7 @@
status_t listAudioPatches(unsigned int *num_patches, struct audio_patch *patches) const;
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
index 78e7ec9..d1a0f9b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyConfig.h
@@ -16,6 +16,9 @@
#pragma once
+#include <unordered_map>
+#include <unordered_set>
+
#include <AudioGain.h>
#include <VolumeCurve.h>
#include <AudioPort.h>
@@ -145,6 +148,35 @@
inProfile->addAudioProfile(micProfile);
inProfile->addSupportedDevice(defaultInputDevice);
module->addInputProfile(inProfile);
+
+ setDefaultSurroundFormats();
+ }
+
+ // Surround formats, with an optional list of subformats that are equivalent from users' POV.
+ using SurroundFormats = std::unordered_map<audio_format_t, std::unordered_set<audio_format_t>>;
+
+ const SurroundFormats &getSurroundFormats() const
+ {
+ return mSurroundFormats;
+ }
+
+ void setSurroundFormats(const SurroundFormats &surroundFormats)
+ {
+ mSurroundFormats = surroundFormats;
+ }
+
+ void setDefaultSurroundFormats()
+ {
+ mSurroundFormats = {
+ {AUDIO_FORMAT_AC3, {}},
+ {AUDIO_FORMAT_E_AC3, {}},
+ {AUDIO_FORMAT_DTS, {}},
+ {AUDIO_FORMAT_DTS_HD, {}},
+ {AUDIO_FORMAT_AAC_LC, {
+ AUDIO_FORMAT_AAC_HE_V1, AUDIO_FORMAT_AAC_HE_V2, AUDIO_FORMAT_AAC_ELD,
+ AUDIO_FORMAT_AAC_XHE}},
+ {AUDIO_FORMAT_DOLBY_TRUEHD, {}},
+ {AUDIO_FORMAT_E_AC3_JOC, {}}};
}
private:
@@ -158,6 +190,7 @@
// DEVICE_CATEGORY_SPEAKER path to boost soft sounds, used to adjust volume curves accordingly.
// Note: remove also speaker_drc_enabled from global configuration of XML config file.
bool mIsSpeakerDrcEnabled;
+ SurroundFormats mSurroundFormats;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
index 8fc6fe9..96c00ea 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPolicyMix.h
@@ -43,7 +43,7 @@
void setMix(AudioMix &mix);
- status_t dump(int fd, int spaces, int index) const;
+ void dump(String8 *dst, int spaces, int index) const;
private:
AudioMix mMix; // Audio policy mix descriptor
@@ -80,7 +80,7 @@
status_t getInputMixForAttr(audio_attributes_t attr, AudioMix **policyMix);
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
index bd7517f..ebb9352 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioPort.h
@@ -132,7 +132,8 @@
void addRoute(const sp<AudioRoute> &route) { mRoutes.add(route); }
const AudioRouteVector &getRoutes() const { return mRoutes; }
- void dump(int fd, int spaces, bool verbose = true) const;
+ void dump(String8 *dst, int spaces, bool verbose = true) const;
+
void log(const char* indent) const;
AudioGainCollection mGains; // gain controllers
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
index a1ee708..b588d57 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
@@ -112,7 +112,7 @@
bool isDynamic() { return mIsDynamicFormat || mIsDynamicChannels || mIsDynamicRate; }
- void dump(int fd, int spaces) const;
+ void dump(String8 *dst, int spaces) const;
private:
String8 mName;
@@ -165,7 +165,7 @@
// One audio profile will be added for each format supported by Audio HAL
void setFormats(const FormatVector &formats);
- void dump(int fd, int spaces) const;
+ void dump(String8 *dst, int spaces) const;
private:
sp<AudioProfile> getProfileFor(audio_format_t format) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
index 6b24fde..330f1d4 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioRoute.h
@@ -46,7 +46,7 @@
audio_route_type_t getType() const { return mType; }
- void dump(int fd, int spaces) const;
+ void dump(String8 *dst, int spaces) const;
private:
AudioPortVector mSources;
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index 1a3300d..030bf4b 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -45,8 +45,8 @@
mConfig(config), mPreferredDeviceId(preferredDeviceId), mActive(false) {}
~ClientDescriptor() override = default;
- status_t dump(int fd, int spaces, int index);
- virtual status_t dump(String8& dst, int spaces, int index);
+ virtual void dump(String8 *dst, int spaces, int index) const;
+ virtual std::string toShortString() const;
audio_port_handle_t portId() const { return mPortId; }
uid_t uid() const { return mUid; }
@@ -71,10 +71,6 @@
const audio_config_base_t mConfig;
audio_port_handle_t mPreferredDeviceId; // selected input device port ID
bool mActive;
-
-protected:
- // FIXME: use until other descriptor classes have a dump to String8 method
- int mDumpFd;
};
class TrackClientDescriptor: public ClientDescriptor
@@ -89,7 +85,8 @@
~TrackClientDescriptor() override = default;
using ClientDescriptor::dump;
- status_t dump(String8& dst, int spaces, int index) override;
+ void dump(String8 *dst, int spaces, int index) const override;
+ std::string toShortString() const override;
audio_output_flags_t flags() const { return mFlags; }
audio_stream_type_t stream() const { return mStream; }
@@ -113,7 +110,7 @@
~RecordClientDescriptor() override = default;
using ClientDescriptor::dump;
- status_t dump(String8& dst, int spaces, int index) override;
+ void dump(String8 *dst, int spaces, int index) const override;
audio_source_t source() const { return mSource; }
audio_input_flags_t flags() const { return mFlags; }
@@ -144,7 +141,7 @@
void setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput);
using ClientDescriptor::dump;
- status_t dump(String8& dst, int spaces, int index) override;
+ void dump(String8 *dst, int spaces, int index) const override;
private:
const sp<AudioPatch> mPatchDesc;
@@ -157,12 +154,93 @@
public DefaultKeyedVector< audio_port_handle_t, sp<SourceClientDescriptor> >
{
public:
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
typedef std::vector< sp<TrackClientDescriptor> > TrackClientVector;
-typedef std::map< audio_port_handle_t, sp<TrackClientDescriptor> > TrackClientMap;
typedef std::vector< sp<RecordClientDescriptor> > RecordClientVector;
-typedef std::map< audio_port_handle_t, sp<RecordClientDescriptor> > RecordClientMap;
+
+// A Map that associates a portId with a client (type T)
+// which is either TrackClientDescriptor or RecordClientDescriptor.
+
+template<typename T>
+class ClientMapHandler {
+public:
+ virtual ~ClientMapHandler() = default;
+
+ // Track client management
+ void addClient(const sp<T> &client) {
+ const audio_port_handle_t portId = client->portId();
+ LOG_ALWAYS_FATAL_IF(!mClients.emplace(portId, client).second,
+ "%s(%d): attempting to add client that already exists", __func__, portId);
+ }
+ sp<T> getClient(audio_port_handle_t portId) const {
+ auto it = mClients.find(portId);
+ if (it == mClients.end()) return nullptr;
+ return it->second;
+ }
+ virtual void removeClient(audio_port_handle_t portId) {
+ auto it = mClients.find(portId);
+ LOG_ALWAYS_FATAL_IF(it == mClients.end(),
+ "%s(%d): client does not exist", __func__, portId);
+ LOG_ALWAYS_FATAL_IF(it->second->active(),
+ "%s(%d): removing client still active!", __func__, portId);
+ (void)mClients.erase(it);
+ }
+ size_t getClientCount() const {
+ return mClients.size();
+ }
+ virtual void dump(String8 *dst) const {
+ size_t index = 0;
+ for (const auto& client: getClientIterable()) {
+ client->dump(dst, 2, index++);
+ }
+ }
+
+ // helper types
+ using ClientMap = std::map<audio_port_handle_t, sp<T>>;
+ using ClientMapIterator = typename ClientMap::const_iterator; // ClientMap is const qualified
+ class ClientIterable {
+ public:
+ explicit ClientIterable(const ClientMapHandler<T> &ref) : mClientMapHandler(ref) { }
+
+ class iterator {
+ public:
+ // traits
+ using iterator_category = std::forward_iterator_tag;
+ using value_type = sp<T>;
+ using difference_type = ptrdiff_t;
+ using pointer = const sp<T>*; // Note: const
+ using reference = const sp<T>&; // Note: const
+
+ // implementation
+ explicit iterator(const ClientMapIterator &it) : mIt(it) { }
+ iterator& operator++() /* prefix */ { ++mIt; return *this; }
+ reference operator* () const { return mIt->second; }
+ reference operator->() const { return mIt->second; } // as if sp<>
+ difference_type operator-(const iterator& rhs) {return mIt - rhs.mIt; }
+ bool operator==(const iterator& rhs) const { return mIt == rhs.mIt; }
+ bool operator!=(const iterator& rhs) const { return mIt != rhs.mIt; }
+ private:
+ ClientMapIterator mIt;
+ };
+
+ iterator begin() const { return iterator{mClientMapHandler.mClients.begin()}; }
+ iterator end() const { return iterator{mClientMapHandler.mClients.end()}; }
+
+ private:
+ const ClientMapHandler<T>& mClientMapHandler; // iterating does not modify map.
+ };
+
+ // return an iterable object that can be used in a range-based-for to enumerate clients.
+ // this iterable does not allow modification, it should be used as a temporary.
+ ClientIterable getClientIterable() const {
+ return ClientIterable{*this};
+ }
+
+private:
+ // ClientMap maps a portId to a client descriptor (both uniquely identify each other).
+ ClientMap mClients;
+};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index c08e752..83fb10c 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -51,7 +51,7 @@
virtual void importAudioPort(const sp<AudioPort>& port, bool force = false);
audio_port_handle_t getId() const;
- status_t dump(int fd, int spaces, int index, bool verbose = true) const;
+ void dump(String8 *dst, int spaces, int index, bool verbose = true) const;
void log() const;
String8 mAddress;
@@ -85,7 +85,7 @@
DeviceVector getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
audio_devices_t getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const;
- status_t dump(int fd, const String8 &tag, int spaces = 0, bool verbose = true) const;
+ void dump(String8 *dst, const String8 &tag, int spaces = 0, bool verbose = true) const;
private:
void refreshTypes();
diff --git a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
index 04831c6..9fa7486 100644
--- a/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/EffectDescriptor.h
@@ -21,6 +21,7 @@
#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
#include <utils/Errors.h>
+#include <utils/String8.h>
namespace android {
@@ -28,7 +29,7 @@
class EffectDescriptor : public RefBase
{
public:
- status_t dump(int fd);
+ void dump(String8 *dst) const;
int mIo; // io the effect is attached to
routing_strategy mStrategy; // routing strategy the effect is associated to
@@ -50,7 +51,7 @@
uint32_t getMaxEffectsMemory() const;
bool isNonOffloadableEffectEnabled();
- status_t dump(int fd);
+ void dump(String8 *dst) const;
private:
status_t setEffectEnabled(const sp<EffectDescriptor> &effectDesc, bool enabled);
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index 05cfc31..6560431 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -82,7 +82,7 @@
}
// TODO remove from here (split serialization)
- void dump(int fd);
+ void dump(String8 *dst) const;
private:
void refreshSupportedDevices();
@@ -109,7 +109,7 @@
const char *device_name,
bool matchAddress = true) const;
- status_t dump(int fd) const;
+ void dump(String8 *dst) const;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index 67ac9bc..eb32959 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -73,7 +73,7 @@
uint32_t flags,
bool exactMatchRequiredForInputFlags = false) const;
- void dump(int fd);
+ void dump(String8 *dst) const;
void log();
bool hasSupportedDevices() const { return !mSupportedDevices.isEmpty(); }
diff --git a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
index e1f6b08..750da55 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IVolumeCurvesCollection.h
@@ -19,6 +19,7 @@
#include <system/audio.h>
#include <Volume.h>
#include <utils/Errors.h>
+#include <utils/String8.h>
namespace android {
@@ -47,7 +48,7 @@
virtual bool hasVolumeIndexForDevice(audio_stream_type_t stream,
audio_devices_t device) const = 0;
- virtual status_t dump(int fd) const = 0;
+ virtual void dump(String8 *dst) const = 0;
};
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/Serializer.h b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
index 29de848..48c4147 100644
--- a/services/audiopolicy/common/managerdefinitions/include/Serializer.h
+++ b/services/audiopolicy/common/managerdefinitions/include/Serializer.h
@@ -17,223 +17,9 @@
#pragma once
#include "AudioPolicyConfig.h"
-#include <utils/StrongPointer.h>
-#include <utils/Errors.h>
-#include <utils/RefBase.h>
-#include <string>
-#include <sstream>
-#include <fstream>
-
-struct _xmlNode;
-struct _xmlDoc;
namespace android {
-struct AudioGainTraits
-{
- static const char *const tag;
- static const char *const collectionTag;
-
- struct Attributes
- {
- static const char mode[]; /**< gain modes supported, e.g. AUDIO_GAIN_MODE_CHANNELS. */
- /** controlled channels, needed if mode AUDIO_GAIN_MODE_CHANNELS. */
- static const char channelMask[];
- static const char minValueMB[]; /**< min value in millibel. */
- static const char maxValueMB[]; /**< max value in millibel. */
- static const char defaultValueMB[]; /**< default value in millibel. */
- static const char stepValueMB[]; /**< step value in millibel. */
- static const char minRampMs[]; /**< needed if mode AUDIO_GAIN_MODE_RAMP. */
- static const char maxRampMs[]; /**< .needed if mode AUDIO_GAIN_MODE_RAMP */
- };
-
- typedef AudioGain Element;
- typedef sp<Element> PtrElement;
- typedef AudioGainCollection Collection;
- typedef void *PtrSerializingCtx;
-
- static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
- PtrSerializingCtx serializingContext);
-
- // Gain has no child
-};
-
-// A profile section contains a name, one audio format and the list of supported sampling rates
-// and channel masks for this format
-struct AudioProfileTraits
-{
- static const char *const tag;
- static const char *const collectionTag;
-
- struct Attributes
- {
- static const char name[];
- static const char samplingRates[];
- static const char format[];
- static const char channelMasks[];
- };
-
- typedef AudioProfile Element;
- typedef sp<AudioProfile> PtrElement;
- typedef AudioProfileVector Collection;
- typedef void *PtrSerializingCtx;
-
- static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
- PtrSerializingCtx serializingContext);
-};
-
-struct MixPortTraits
-{
- static const char *const tag;
- static const char *const collectionTag;
-
- struct Attributes
- {
- static const char name[];
- static const char role[];
- static const char flags[];
- static const char maxOpenCount[];
- static const char maxActiveCount[];
- };
-
- typedef IOProfile Element;
- typedef sp<Element> PtrElement;
- typedef IOProfileCollection Collection;
- typedef void *PtrSerializingCtx;
-
- static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
- PtrSerializingCtx serializingContext);
-
- // Children are: GainTraits
-};
-
-struct DevicePortTraits
-{
- static const char *const tag;
- static const char *const collectionTag;
-
- struct Attributes
- {
- static const char tagName[]; /**< <device tag name>: any string without space. */
- static const char type[]; /**< <device type>. */
- static const char role[]; /**< <device role: sink or source>. */
- static const char roleSource[]; /**< <attribute role source value>. */
- static const char address[]; /**< optional: device address, char string less than 64. */
- };
- typedef DeviceDescriptor Element;
- typedef sp<DeviceDescriptor> PtrElement;
- typedef DeviceVector Collection;
- typedef void *PtrSerializingCtx;
-
- static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
- PtrSerializingCtx serializingContext);
- // Children are: GainTraits (optionnal)
-};
-
-struct RouteTraits
-{
- static const char *const tag;
- static const char *const collectionTag;
-
- struct Attributes
- {
- static const char type[]; /**< <route type>: mix or mux. */
- static const char typeMix[]; /**< type attribute mix value. */
- static const char sink[]; /**< <sink: involved in this route>. */
- static const char sources[]; /**< sources: all source that can be involved in this route. */
- };
- typedef AudioRoute Element;
- typedef sp<AudioRoute> PtrElement;
- typedef AudioRouteVector Collection;
- typedef HwModule *PtrSerializingCtx;
-
- static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
- PtrSerializingCtx ctx);
-};
-
-struct ModuleTraits
-{
- static const char *const tag;
- static const char *const collectionTag;
-
- static const char *const childAttachedDevicesTag;
- static const char *const childAttachedDeviceTag;
- static const char *const childDefaultOutputDeviceTag;
-
- struct Attributes
- {
- static const char name[];
- static const char version[];
- };
-
- typedef HwModule Element;
- typedef sp<Element> PtrElement;
- typedef HwModuleCollection Collection;
- typedef AudioPolicyConfig *PtrSerializingCtx;
-
- static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
- PtrSerializingCtx serializingContext);
-
- // Children are: mixPortTraits, devicePortTraits and routeTraits
- // Need to call deserialize on each child
-};
-
-struct GlobalConfigTraits
-{
- static const char *const tag;
-
- struct Attributes
- {
- static const char speakerDrcEnabled[];
- };
-
- static status_t deserialize(const _xmlNode *root, AudioPolicyConfig &config);
-};
-
-struct VolumeTraits
-{
- static const char *const tag;
- static const char *const collectionTag;
- static const char *const volumePointTag;
-
- struct Attributes
- {
- static const char stream[];
- static const char deviceCategory[];
- static const char reference[];
- };
-
- typedef VolumeCurve Element;
- typedef sp<VolumeCurve> PtrElement;
- typedef VolumeCurvesCollection Collection;
- typedef void *PtrSerializingCtx;
-
- static status_t deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
- PtrSerializingCtx serializingContext);
-
- // No Child
-};
-
-class PolicySerializer
-{
-private:
- static const char *const rootName;
-
- static const char *const versionAttribute;
- static const uint32_t gMajor; /**< the major number of the policy xml format version. */
- static const uint32_t gMinor; /**< the minor number of the policy xml format version. */
-
-public:
- PolicySerializer();
- status_t deserialize(const char *str, AudioPolicyConfig &config);
-
-private:
- typedef AudioPolicyConfig Element;
-
- std::string mRootElementName;
- std::string mVersion;
-
- // Children are: ModulesTraits, VolumeTraits
-};
+status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config);
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
index 3e6b2b4..76ec198 100644
--- a/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
+++ b/services/audiopolicy/common/managerdefinitions/include/VolumeCurve.h
@@ -59,7 +59,7 @@
float volIndexToDb(int indexInUi, int volIndexMin, int volIndexMax) const;
- void dump(int fd) const;
+ void dump(String8 *result) const;
private:
SortedVector<CurvePoint> mCurvePoints;
@@ -144,7 +144,7 @@
}
}
- void dump(int fd, int spaces, bool curvePoints = false) const;
+ void dump(String8 *dst, int spaces, bool curvePoints = false) const;
private:
KeyedVector<device_category, sp<VolumeCurve> > mOriginVolumeCurves;
@@ -217,7 +217,7 @@
return getCurvesFor(stream).hasVolumeIndexForDevice(device);
}
- virtual status_t dump(int fd) const;
+ void dump(String8 *dst) const override;
ssize_t add(const sp<VolumeCurve> &volumeCurve)
{
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
index ca67b87..c90a582 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioCollections.cpp
@@ -35,22 +35,16 @@
return nullptr;
}
-status_t AudioRouteVector::dump(int fd, int spaces) const
+void AudioRouteVector::dump(String8 *dst, int spaces) const
{
if (isEmpty()) {
- return NO_ERROR;
+ return;
}
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\n%*sAudio Routes (%zu):\n", spaces, "", size());
- write(fd, buffer, strlen(buffer));
+ dst->appendFormat("\n%*sAudio Routes (%zu):\n", spaces, "", size());
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "%*s- Route %zu:\n", spaces, "", i + 1);
- write(fd, buffer, strlen(buffer));
- itemAt(i)->dump(fd, 4);
+ dst->appendFormat("%*s- Route %zu:\n", spaces, "", i + 1);
+ itemAt(i)->dump(dst, 4);
}
- return NO_ERROR;
}
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
index 193d4a6..2725870 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioGain.cpp
@@ -98,32 +98,17 @@
return NO_ERROR;
}
-void AudioGain::dump(int fd, int spaces, int index) const
+void AudioGain::dump(String8 *dst, int spaces, int index) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%*sGain %d:\n", spaces, "", index+1);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- mode: %08x\n", spaces, "", mGain.mode);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
- result.append(buffer);
-
- write(fd, result.string(), result.size());
+ dst->appendFormat("%*sGain %d:\n", spaces, "", index+1);
+ dst->appendFormat("%*s- mode: %08x\n", spaces, "", mGain.mode);
+ dst->appendFormat("%*s- channel_mask: %08x\n", spaces, "", mGain.channel_mask);
+ dst->appendFormat("%*s- min_value: %d mB\n", spaces, "", mGain.min_value);
+ dst->appendFormat("%*s- max_value: %d mB\n", spaces, "", mGain.max_value);
+ dst->appendFormat("%*s- default_value: %d mB\n", spaces, "", mGain.default_value);
+ dst->appendFormat("%*s- step_value: %d mB\n", spaces, "", mGain.step_value);
+ dst->appendFormat("%*s- min_ramp_ms: %d ms\n", spaces, "", mGain.min_ramp_ms);
+ dst->appendFormat("%*s- max_ramp_ms: %d ms\n", spaces, "", mGain.max_ramp_ms);
}
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index e25b0fe..1f29874 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -29,10 +29,8 @@
AudioInputDescriptor::AudioInputDescriptor(const sp<IOProfile>& profile,
AudioPolicyClientInterface *clientInterface)
- : mIoHandle(0),
- mDevice(AUDIO_DEVICE_NONE), mPolicyMix(NULL),
- mProfile(profile), mPatchHandle(AUDIO_PATCH_HANDLE_NONE), mId(0),
- mClientInterface(clientInterface), mGlobalActiveCount(0)
+ : mProfile(profile)
+ , mClientInterface(clientInterface)
{
if (profile != NULL) {
profile->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
@@ -115,12 +113,12 @@
bool AudioInputDescriptor::isSourceActive(audio_source_t source) const
{
- for (const auto &client : mClients) {
- if (client.second->active() &&
- ((client.second->source() == source) ||
+ for (const auto &client : getClientIterable()) {
+ if (client->active() &&
+ ((client->source() == source) ||
((source == AUDIO_SOURCE_VOICE_RECOGNITION) &&
- (client.second->source() == AUDIO_SOURCE_HOTWORD) &&
- client.second->isSoundTrigger()))) {
+ (client->source() == AUDIO_SOURCE_HOTWORD) &&
+ client->isSoundTrigger()))) {
return true;
}
}
@@ -132,14 +130,14 @@
audio_source_t source = AUDIO_SOURCE_DEFAULT;
int32_t priority = -1;
- for (const auto &client : mClients) {
- if (activeOnly && !client.second->active() ) {
+ for (const auto &client : getClientIterable()) {
+ if (activeOnly && !client->active() ) {
continue;
}
- int32_t curPriority = source_priority(client.second->source());
+ int32_t curPriority = source_priority(client->source());
if (curPriority > priority) {
priority = curPriority;
- source = client.second->source();
+ source = client->source();
}
}
return source;
@@ -148,10 +146,10 @@
bool AudioInputDescriptor::isSoundTrigger() const {
// sound trigger and non sound trigger clients are not mixed on a given input
// so check only first client
- if (mClients.size() == 0) {
+ if (getClientCount() == 0) {
return false;
}
- return mClients.cbegin()->second->isSoundTrigger();
+ return getClientIterable().begin()->isSoundTrigger();
}
audio_patch_handle_t AudioInputDescriptor::getPatchHandle() const
@@ -162,9 +160,9 @@
void AudioInputDescriptor::setPatchHandle(audio_patch_handle_t handle)
{
mPatchHandle = handle;
- for (const auto &client : mClients) {
- if (client.second->active()) {
- updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client.second);
+ for (const auto &client : getClientIterable()) {
+ if (client->active()) {
+ updateClientRecordingConfiguration(RECORD_CONFIG_EVENT_START, client);
}
}
}
@@ -259,24 +257,30 @@
mProfile->curActiveCount--;
}
mProfile->curOpenCount--;
+ LOG_ALWAYS_FATAL_IF(mProfile->curOpenCount < mProfile->curActiveCount,
+ "%s(%d): mProfile->curOpenCount %d < mProfile->curActiveCount %d.",
+ __func__, mId, mProfile->curOpenCount, mProfile->curActiveCount);
mIoHandle = AUDIO_IO_HANDLE_NONE;
}
}
void AudioInputDescriptor::setClientActive(const sp<RecordClientDescriptor>& client, bool active)
{
- if (mClients.find(client->portId()) == mClients.end()
- || active == client->active()) {
+ LOG_ALWAYS_FATAL_IF(getClient(client->portId()) == nullptr,
+ "%s(%d) does not exist on input descriptor", __func__, client->portId());
+ if (active == client->active()) {
return;
}
// Handle non-client-specific activity ref count
int32_t oldGlobalActiveCount = mGlobalActiveCount;
if (!active && mGlobalActiveCount < 1) {
- ALOGW("%s invalid deactivation with globalRefCount %d", __FUNCTION__, mGlobalActiveCount);
- mGlobalActiveCount = 1;
+ LOG_ALWAYS_FATAL("%s(%d) invalid deactivation with globalActiveCount %d",
+ __func__, client->portId(), mGlobalActiveCount);
+ // mGlobalActiveCount = 1;
}
- mGlobalActiveCount += active ? 1 : -1;
+ const int delta = active ? 1 : -1;
+ mGlobalActiveCount += delta;
if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
@@ -314,9 +318,9 @@
audio_session_t session)
{
RecordClientVector clients;
- for (const auto &client : mClients) {
- if (client.second->session() == session) {
- clients.push_back(client.second);
+ for (const auto &client : getClientIterable()) {
+ if (client->session() == session) {
+ clients.push_back(client);
}
}
return clients;
@@ -326,43 +330,26 @@
bool preferredDeviceOnly) const
{
RecordClientVector clients;
- for (const auto &client : mClients) {
- if ((!activeOnly || client.second->active())
- && (source == AUDIO_SOURCE_DEFAULT || source == client.second->source())
- && (!preferredDeviceOnly || client.second->hasPreferredDevice())) {
- clients.push_back(client.second);
+ for (const auto &client : getClientIterable()) {
+ if ((!activeOnly || client->active())
+ && (source == AUDIO_SOURCE_DEFAULT || source == client->source())
+ && (!preferredDeviceOnly || client->hasPreferredDevice())) {
+ clients.push_back(client);
}
}
return clients;
}
-status_t AudioInputDescriptor::dump(int fd)
+void AudioInputDescriptor::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, " ID: %d\n", getId());
- result.append(buffer);
- snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
- result.append(buffer);
- snprintf(buffer, SIZE, " Format: %d\n", mFormat);
- result.append(buffer);
- snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
- result.append(buffer);
- snprintf(buffer, SIZE, " Devices %08x\n", mDevice);
- result.append(buffer);
-
- write(fd, result.string(), result.size());
-
- size_t index = 0;
- result = " AudioRecord clients:\n";
- for (const auto& client: mClients) {
- client.second->dump(result, 2, index++);
- }
- result.append(" \n");
- write(fd, result.string(), result.size());
- return NO_ERROR;
+ dst->appendFormat(" ID: %d\n", getId());
+ dst->appendFormat(" Sampling rate: %d\n", mSamplingRate);
+ dst->appendFormat(" Format: %d\n", mFormat);
+ dst->appendFormat(" Channels: %08x\n", mChannelMask);
+ dst->appendFormat(" Devices %08x\n", mDevice);
+ dst->append(" AudioRecord Clients:\n");
+ ClientMapHandler<RecordClientDescriptor>::dump(dst);
+ dst->append("\n");
}
bool AudioInputCollection::isSourceActive(audio_source_t source) const
@@ -378,14 +365,13 @@
sp<AudioInputDescriptor> AudioInputCollection::getInputFromId(audio_port_handle_t id) const
{
- sp<AudioInputDescriptor> inputDesc = NULL;
for (size_t i = 0; i < size(); i++) {
- inputDesc = valueAt(i);
- if (inputDesc->getId() == id) {
- break;
+ const sp<AudioInputDescriptor> inputDescriptor = valueAt(i);
+ if (inputDescriptor->getId() == id) {
+ return inputDescriptor;
}
}
- return inputDesc;
+ return NULL;
}
uint32_t AudioInputCollection::activeInputsCountOnDevices(audio_devices_t devices) const
@@ -428,29 +414,20 @@
{
for (size_t i = 0; i < size(); i++) {
sp<AudioInputDescriptor> inputDesc = valueAt(i);
- for (const auto& client : inputDesc->clientsMap()) {
- if (client.second->portId() == portId) {
- return inputDesc;
- }
+ if (inputDesc->getClient(portId) != nullptr) {
+ return inputDesc;
}
}
return 0;
}
-status_t AudioInputCollection::dump(int fd) const
+void AudioInputCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\nInputs dump:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("\nInputs dump:\n");
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "- Input %d dump:\n", keyAt(i));
- write(fd, buffer, strlen(buffer));
- valueAt(i)->dump(fd);
+ dst->appendFormat("- Input %d dump:\n", keyAt(i));
+ valueAt(i)->dump(dst);
}
-
- return NO_ERROR;
}
}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index b6ff6ea..4ce6b08 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -34,8 +34,8 @@
AudioOutputDescriptor::AudioOutputDescriptor(const sp<AudioPort>& port,
AudioPolicyClientInterface *clientInterface)
- : mPort(port), mDevice(AUDIO_DEVICE_NONE), mClientInterface(clientInterface),
- mPolicyMix(NULL), mGlobalActiveCount(0), mPatchHandle(AUDIO_PATCH_HANDLE_NONE), mId(0)
+ : mPort(port)
+ , mClientInterface(clientInterface)
{
// clear usage count for all stream types
for (int i = 0; i < AUDIO_STREAM_CNT; i++) {
@@ -103,35 +103,62 @@
}
}
-void AudioOutputDescriptor::changeStreamActiveCount(audio_stream_type_t stream,
- int delta)
+void AudioOutputDescriptor::changeStreamActiveCount(const sp<TrackClientDescriptor>& client,
+ int delta)
{
+ if (delta == 0) return;
+ const audio_stream_type_t stream = client->stream();
if ((delta + (int)mActiveCount[stream]) < 0) {
- ALOGW("%s invalid delta %d for stream %d, active count %d",
- __FUNCTION__, delta, stream, mActiveCount[stream]);
- mActiveCount[stream] = 0;
- return;
+ // any mismatched active count will abort.
+ LOG_ALWAYS_FATAL("%s(%s) invalid delta %d, active stream count %d",
+ __func__, client->toShortString().c_str(), delta, mActiveCount[stream]);
+ // mActiveCount[stream] = 0;
+ // return;
}
mActiveCount[stream] += delta;
+
+ if (delta > 0) {
+ mActiveClients[client] += delta;
+ } else {
+ auto it = mActiveClients.find(client);
+ if (it == mActiveClients.end()) { // client not found!
+ LOG_ALWAYS_FATAL("%s(%s) invalid delta %d, inactive client",
+ __func__, client->toShortString().c_str(), delta);
+ } else if (it->second < -delta) { // invalid delta!
+ LOG_ALWAYS_FATAL("%s(%s) invalid delta %d, active client count %zu",
+ __func__, client->toShortString().c_str(), delta, it->second);
+ }
+ it->second += delta;
+ if (it->second == 0) {
+ (void)mActiveClients.erase(it);
+ }
+ }
+
ALOGV("%s stream %d, count %d", __FUNCTION__, stream, mActiveCount[stream]);
}
void AudioOutputDescriptor::setClientActive(const sp<TrackClientDescriptor>& client, bool active)
{
- if (mClients.find(client->portId()) == mClients.end()
- || active == client->active()) {
+ LOG_ALWAYS_FATAL_IF(getClient(client->portId()) == nullptr,
+ "%s(%d) does not exist on output descriptor", __func__, client->portId());
+
+ if (active == client->active()) {
+ ALOGW("%s(%s): ignored active: %d, current stream count %d",
+ __func__, client->toShortString().c_str(),
+ active, mActiveCount[client->stream()]);
return;
}
-
- changeStreamActiveCount(client->stream(), active ? 1 : -1);
+ const int delta = active ? 1 : -1;
+ changeStreamActiveCount(client, delta);
// Handle non-client-specific activity ref count
int32_t oldGlobalActiveCount = mGlobalActiveCount;
if (!active && mGlobalActiveCount < 1) {
- ALOGW("%s invalid deactivation with globalRefCount %d", __FUNCTION__, mGlobalActiveCount);
+ ALOGW("%s(%s): invalid deactivation with globalRefCount %d",
+ __func__, client->toShortString().c_str(), mGlobalActiveCount);
mGlobalActiveCount = 1;
}
- mGlobalActiveCount += active ? 1 : -1;
+ mGlobalActiveCount += delta;
if ((oldGlobalActiveCount == 0) && (mGlobalActiveCount > 0)) {
if ((mPolicyMix != NULL) && ((mPolicyMix->mCbFlags & AudioMix::kCbFlagNotifyActivity) != 0))
@@ -239,49 +266,41 @@
bool preferredDeviceOnly) const
{
TrackClientVector clients;
- for (const auto &client : mClients) {
- if ((!activeOnly || client.second->active())
- && (strategy == STRATEGY_NONE || strategy == client.second->strategy())
- && (!preferredDeviceOnly || client.second->hasPreferredDevice())) {
- clients.push_back(client.second);
+ for (const auto &client : getClientIterable()) {
+ if ((!activeOnly || client->active())
+ && (strategy == STRATEGY_NONE || strategy == client->strategy())
+ && (!preferredDeviceOnly || client->hasPreferredDevice())) {
+ clients.push_back(client);
}
}
return clients;
}
-status_t AudioOutputDescriptor::dump(int fd)
+void AudioOutputDescriptor::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, " ID: %d\n", mId);
- result.append(buffer);
- snprintf(buffer, SIZE, " Sampling rate: %d\n", mSamplingRate);
- result.append(buffer);
- snprintf(buffer, SIZE, " Format: %08x\n", mFormat);
- result.append(buffer);
- snprintf(buffer, SIZE, " Channels: %08x\n", mChannelMask);
- result.append(buffer);
- snprintf(buffer, SIZE, " Devices %08x\n", device());
- result.append(buffer);
- snprintf(buffer, SIZE, " Stream volume activeCount muteCount\n");
- result.append(buffer);
+ dst->appendFormat(" ID: %d\n", mId);
+ dst->appendFormat(" Sampling rate: %d\n", mSamplingRate);
+ dst->appendFormat(" Format: %08x\n", mFormat);
+ dst->appendFormat(" Channels: %08x\n", mChannelMask);
+ dst->appendFormat(" Devices: %08x\n", device());
+ dst->appendFormat(" Global active count: %u\n", mGlobalActiveCount);
+ dst->append(" Stream volume activeCount muteCount\n");
for (int i = 0; i < (int)AUDIO_STREAM_CNT; i++) {
- snprintf(buffer, SIZE, " %02d %.03f %02d %02d\n",
+ dst->appendFormat(" %02d %.03f %02d %02d\n",
i, mCurVolume[i], streamActiveCount((audio_stream_type_t)i), mMuteCount[i]);
- result.append(buffer);
}
-
- result.append(" AudioTrack clients:\n");
- size_t index = 0;
- for (const auto& client : mClients) {
- client.second->dump(result, 2, index++);
+ dst->append(" AudioTrack Clients:\n");
+ ClientMapHandler<TrackClientDescriptor>::dump(dst);
+ dst->append("\n");
+ if (mActiveClients.size() > 0) {
+ dst->append(" AudioTrack active (stream) clients:\n");
+ size_t index = 0;
+ for (const auto& clientPair : mActiveClients) {
+ dst->appendFormat(" Refcount: %zu", clientPair.second);
+ clientPair.first->dump(dst, 2, index++);
+ }
+ dst->append(" \n");
}
- result.append(" \n");
- write(fd, result.string(), result.size());
-
- return NO_ERROR;
}
void AudioOutputDescriptor::log(const char* indent)
@@ -304,21 +323,11 @@
}
}
-status_t SwAudioOutputDescriptor::dump(int fd)
+void SwAudioOutputDescriptor::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, " Latency: %d\n", mLatency);
- result.append(buffer);
- snprintf(buffer, SIZE, " Flags %08x\n", mFlags);
- result.append(buffer);
- write(fd, result.string(), result.size());
-
- AudioOutputDescriptor::dump(fd);
-
- return NO_ERROR;
+ dst->appendFormat(" Latency: %d\n", mLatency);
+ dst->appendFormat(" Flags %08x\n", mFlags);
+ AudioOutputDescriptor::dump(dst);
}
audio_devices_t SwAudioOutputDescriptor::device() const
@@ -361,15 +370,15 @@
}
}
-void SwAudioOutputDescriptor::changeStreamActiveCount(audio_stream_type_t stream,
- int delta)
+void SwAudioOutputDescriptor::changeStreamActiveCount(const sp<TrackClientDescriptor>& client,
+ int delta)
{
// forward usage count change to attached outputs
if (isDuplicated()) {
- mOutput1->changeStreamActiveCount(stream, delta);
- mOutput2->changeStreamActiveCount(stream, delta);
+ mOutput1->changeStreamActiveCount(client, delta);
+ mOutput2->changeStreamActiveCount(client, delta);
}
- AudioOutputDescriptor::changeStreamActiveCount(stream, delta);
+ AudioOutputDescriptor::changeStreamActiveCount(client, delta);
}
bool SwAudioOutputDescriptor::isFixedVolume(audio_devices_t device)
@@ -589,20 +598,11 @@
{
}
-status_t HwAudioOutputDescriptor::dump(int fd)
+void HwAudioOutputDescriptor::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- AudioOutputDescriptor::dump(fd);
-
- snprintf(buffer, SIZE, "Source:\n");
- result.append(buffer);
- write(fd, result.string(), result.size());
- mSource->dump(fd, 0, 0);
-
- return NO_ERROR;
+ AudioOutputDescriptor::dump(dst);
+ dst->append("Source:\n");
+ mSource->dump(dst, 0, 0);
}
audio_devices_t HwAudioOutputDescriptor::supportedDevices()
@@ -729,14 +729,13 @@
sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getOutputFromId(audio_port_handle_t id) const
{
- sp<SwAudioOutputDescriptor> outputDesc = NULL;
for (size_t i = 0; i < size(); i++) {
- outputDesc = valueAt(i);
+ const sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
if (outputDesc->getId() == id) {
- break;
+ return outputDesc;
}
}
- return outputDesc;
+ return NULL;
}
bool SwAudioOutputCollection::isAnyOutputActive(audio_stream_type_t streamToIgnore) const
@@ -766,29 +765,20 @@
{
for (size_t i = 0; i < size(); i++) {
sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
- for (const auto& client : outputDesc->clientsMap()) {
- if (client.second->portId() == portId) {
- return outputDesc;
- }
+ if (outputDesc->getClient(portId) != nullptr) {
+ return outputDesc;
}
}
return 0;
}
-status_t SwAudioOutputCollection::dump(int fd) const
+void SwAudioOutputCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\nOutputs dump:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("\nOutputs dump:\n");
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "- Output %d dump:\n", keyAt(i));
- write(fd, buffer, strlen(buffer));
- valueAt(i)->dump(fd);
+ dst->appendFormat("- Output %d dump:\n", keyAt(i));
+ valueAt(i)->dump(dst);
}
-
- return NO_ERROR;
}
// HwAudioOutputCollection implementation
@@ -820,20 +810,13 @@
return false;
}
-status_t HwAudioOutputCollection::dump(int fd) const
+void HwAudioOutputCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\nOutputs dump:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("\nOutputs dump:\n");
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "- Output %d dump:\n", keyAt(i));
- write(fd, buffer, strlen(buffer));
- valueAt(i)->dump(fd);
+ dst->appendFormat("- Output %d dump:\n", keyAt(i));
+ valueAt(i)->dump(dst);
}
-
- return NO_ERROR;
}
}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
index e78e121..cd1c2f2 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPatch.cpp
@@ -34,34 +34,29 @@
{
}
-static String8 dumpPatchEndpoints(
- int spaces, const char *prefix, int count, const audio_port_config *cfgs)
+static void dumpPatchEndpoints(
+ String8 *dst, int spaces, const char *prefix, int count, const audio_port_config *cfgs)
{
- String8 result;
for (int i = 0; i < count; ++i) {
const audio_port_config &cfg = cfgs[i];
- result.appendFormat("%*s [%s %d] ", spaces, "", prefix, i + 1);
+ dst->appendFormat("%*s [%s %d] ", spaces, "", prefix, i + 1);
if (cfg.type == AUDIO_PORT_TYPE_DEVICE) {
std::string device;
deviceToString(cfg.ext.device.type, device);
- result.appendFormat("Device ID %d %s", cfg.id, device.c_str());
+ dst->appendFormat("Device ID %d %s", cfg.id, device.c_str());
} else {
- result.appendFormat("Mix ID %d I/O handle %d", cfg.id, cfg.ext.mix.handle);
+ dst->appendFormat("Mix ID %d I/O handle %d", cfg.id, cfg.ext.mix.handle);
}
- result.append("\n");
+ dst->append("\n");
}
- return result;
}
-status_t AudioPatch::dump(int fd, int spaces, int index) const
+void AudioPatch::dump(String8 *dst, int spaces, int index) const
{
- String8 result;
- result.appendFormat("%*sPatch %d: owner uid %4d, handle %2d, af handle %2d\n",
+ dst->appendFormat("%*sPatch %d: owner uid %4d, handle %2d, af handle %2d\n",
spaces, "", index + 1, mUid, mHandle, mAfPatchHandle);
- result.append(dumpPatchEndpoints(spaces, "src ", mPatch.num_sources, mPatch.sources));
- result.append(dumpPatchEndpoints(spaces, "sink", mPatch.num_sinks, mPatch.sinks));
- write(fd, result.string(), result.size());
- return NO_ERROR;
+ dumpPatchEndpoints(dst, spaces, "src ", mPatch.num_sources, mPatch.sources);
+ dumpPatchEndpoints(dst, spaces, "sink", mPatch.num_sinks, mPatch.sinks);
}
status_t AudioPatchCollection::addAudioPatch(audio_patch_handle_t handle,
@@ -142,16 +137,12 @@
return NO_ERROR;
}
-status_t AudioPatchCollection::dump(int fd) const
+void AudioPatchCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- snprintf(buffer, SIZE, "\nAudio Patches:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("\nAudio Patches:\n");
for (size_t i = 0; i < size(); i++) {
- valueAt(i)->dump(fd, 2, i);
+ valueAt(i)->dump(dst, 2, i);
}
- return NO_ERROR;
}
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
index 08930f1..3cf8014 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPolicyMix.cpp
@@ -52,64 +52,55 @@
return &mMix;
}
-status_t AudioPolicyMix::dump(int fd, int spaces, int index) const
+void AudioPolicyMix::dump(String8 *dst, int spaces, int index) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%*sAudio Policy Mix %d:\n", spaces, "", index+1);
- result.append(buffer);
+ dst->appendFormat("%*sAudio Policy Mix %d:\n", spaces, "", index + 1);
std::string mixTypeLiteral;
if (!MixTypeConverter::toString(mMix.mMixType, mixTypeLiteral)) {
ALOGE("%s: failed to convert mix type %d", __FUNCTION__, mMix.mMixType);
- return BAD_VALUE;
+ return;
}
- snprintf(buffer, SIZE, "%*s- mix type: %s\n", spaces, "", mixTypeLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- mix type: %s\n", spaces, "", mixTypeLiteral.c_str());
+
std::string routeFlagLiteral;
RouteFlagTypeConverter::maskToString(mMix.mRouteFlags, routeFlagLiteral);
- snprintf(buffer, SIZE, "%*s- Route Flags: %s\n", spaces, "", routeFlagLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- Route Flags: %s\n", spaces, "", routeFlagLiteral.c_str());
+
std::string deviceLiteral;
deviceToString(mMix.mDeviceType, deviceLiteral);
- snprintf(buffer, SIZE, "%*s- device type: %s\n", spaces, "", deviceLiteral.c_str());
- result.append(buffer);
- snprintf(buffer, SIZE, "%*s- device address: %s\n", spaces, "", mMix.mDeviceAddress.string());
- result.append(buffer);
+ dst->appendFormat("%*s- device type: %s\n", spaces, "", deviceLiteral.c_str());
+
+ dst->appendFormat("%*s- device address: %s\n", spaces, "", mMix.mDeviceAddress.string());
int indexCriterion = 0;
for (const auto &criterion : mMix.mCriteria) {
- snprintf(buffer, SIZE, "%*s- Criterion %d:\n", spaces + 2, "", indexCriterion++);
- result.append(buffer);
+ dst->appendFormat("%*s- Criterion %d:\n", spaces + 2, "", indexCriterion++);
+
std::string usageLiteral;
if (!UsageTypeConverter::toString(criterion.mValue.mUsage, usageLiteral)) {
ALOGE("%s: failed to convert usage %d", __FUNCTION__, criterion.mValue.mUsage);
- return BAD_VALUE;
+ return;
}
- snprintf(buffer, SIZE, "%*s- Usage:%s\n", spaces + 4, "", usageLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- Usage:%s\n", spaces + 4, "", usageLiteral.c_str());
+
if (mMix.mMixType == MIX_TYPE_RECORDERS) {
std::string sourceLiteral;
if (!SourceTypeConverter::toString(criterion.mValue.mSource, sourceLiteral)) {
ALOGE("%s: failed to convert source %d", __FUNCTION__, criterion.mValue.mSource);
- return BAD_VALUE;
+ return;
}
- snprintf(buffer, SIZE, "%*s- Source:%s\n", spaces + 4, "", sourceLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- Source:%s\n", spaces + 4, "", sourceLiteral.c_str());
+
}
- snprintf(buffer, SIZE, "%*s- Uid:%d\n", spaces + 4, "", criterion.mValue.mUid);
- result.append(buffer);
+ dst->appendFormat("%*s- Uid:%d\n", spaces + 4, "", criterion.mValue.mUid);
+
std::string ruleLiteral;
if (!RuleTypeConverter::toString(criterion.mRule, ruleLiteral)) {
ALOGE("%s: failed to convert source %d", __FUNCTION__,criterion.mRule);
- return BAD_VALUE;
+ return;
}
- snprintf(buffer, SIZE, "%*s- Rule:%s\n", spaces + 4, "", ruleLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- Rule:%s\n", spaces + 4, "", ruleLiteral.c_str());
}
- write(fd, result.string(), result.size());
- return NO_ERROR;
}
status_t AudioPolicyMixCollection::registerMix(const String8& address, AudioMix mix,
@@ -349,14 +340,12 @@
return NO_ERROR;
}
-status_t AudioPolicyMixCollection::dump(int fd) const
+void AudioPolicyMixCollection::dump(String8 *dst) const
{
- std::string log("\nAudio Policy Mix:\n");
- write(fd, log.c_str(), log.size());
+ dst->append("\nAudio Policy Mix:\n");
for (size_t i = 0; i < size(); i++) {
- valueAt(i)->dump(fd, 2, i);
+ valueAt(i)->dump(dst, 2, i);
}
- return NO_ERROR;
}
}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
index 3fe37ab..19dde6a 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioPort.cpp
@@ -354,26 +354,18 @@
return mGains[index]->checkConfig(gainConfig);
}
-void AudioPort::dump(int fd, int spaces, bool verbose) const
+void AudioPort::dump(String8 *dst, int spaces, bool verbose) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
if (!mName.isEmpty()) {
- snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
- result.append(buffer);
- write(fd, result.string(), result.size());
+ dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
}
if (verbose) {
- mProfiles.dump(fd, spaces);
+ mProfiles.dump(dst, spaces);
if (mGains.size() != 0) {
- snprintf(buffer, SIZE, "%*s- gains:\n", spaces, "");
- result = buffer;
- write(fd, result.string(), result.size());
+ dst->appendFormat("%*s- gains:\n", spaces, "");
for (size_t i = 0; i < mGains.size(); i++) {
- mGains[i]->dump(fd, spaces + 2, i);
+ mGains[i]->dump(dst, spaces + 2, i);
}
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
index d04beec..a645e02 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
@@ -253,47 +253,35 @@
return bestMatch > 0 ? NO_ERROR : BAD_VALUE;
}
-void AudioProfile::dump(int fd, int spaces) const
+void AudioProfile::dump(String8 *dst, int spaces) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
+ dst->appendFormat("%s%s%s\n", mIsDynamicFormat ? "[dynamic format]" : "",
mIsDynamicChannels ? "[dynamic channels]" : "",
mIsDynamicRate ? "[dynamic rates]" : "");
- result.append(buffer);
if (mName.length() != 0) {
- snprintf(buffer, SIZE, "%*s- name: %s\n", spaces, "", mName.string());
- result.append(buffer);
+ dst->appendFormat("%*s- name: %s\n", spaces, "", mName.string());
}
std::string formatLiteral;
if (FormatConverter::toString(mFormat, formatLiteral)) {
- snprintf(buffer, SIZE, "%*s- format: %s\n", spaces, "", formatLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- format: %s\n", spaces, "", formatLiteral.c_str());
}
if (!mSamplingRates.isEmpty()) {
- snprintf(buffer, SIZE, "%*s- sampling rates:", spaces, "");
- result.append(buffer);
+ dst->appendFormat("%*s- sampling rates:", spaces, "");
for (size_t i = 0; i < mSamplingRates.size(); i++) {
- snprintf(buffer, SIZE, "%d", mSamplingRates[i]);
- result.append(buffer);
- result.append(i == (mSamplingRates.size() - 1) ? "" : ", ");
+ dst->appendFormat("%d", mSamplingRates[i]);
+ dst->append(i == (mSamplingRates.size() - 1) ? "" : ", ");
}
- result.append("\n");
+ dst->append("\n");
}
if (!mChannelMasks.isEmpty()) {
- snprintf(buffer, SIZE, "%*s- channel masks:", spaces, "");
- result.append(buffer);
+ dst->appendFormat("%*s- channel masks:", spaces, "");
for (size_t i = 0; i < mChannelMasks.size(); i++) {
- snprintf(buffer, SIZE, "0x%04x", mChannelMasks[i]);
- result.append(buffer);
- result.append(i == (mChannelMasks.size() - 1) ? "" : ", ");
+ dst->appendFormat("0x%04x", mChannelMasks[i]);
+ dst->append(i == (mChannelMasks.size() - 1) ? "" : ", ");
}
- result.append("\n");
+ dst->append("\n");
}
- write(fd, result.string(), result.size());
}
ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
@@ -559,17 +547,12 @@
}
}
-void AudioProfileVector::dump(int fd, int spaces) const
+void AudioProfileVector::dump(String8 *dst, int spaces) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "%*s- Profiles:\n", spaces, "");
- write(fd, buffer, strlen(buffer));
+ dst->appendFormat("%*s- Profiles:\n", spaces, "");
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "%*sProfile %zu:", spaces + 4, "", i);
- write(fd, buffer, strlen(buffer));
- itemAt(i)->dump(fd, spaces + 8);
+ dst->appendFormat("%*sProfile %zu:", spaces + 4, "", i);
+ itemAt(i)->dump(dst, spaces + 8);
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
index 79ad1f7..c1fe5b0 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
@@ -24,29 +24,17 @@
namespace android
{
-void AudioRoute::dump(int fd, int spaces) const
+void AudioRoute::dump(String8 *dst, int spaces) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
- result.append(buffer);
-
- snprintf(buffer, SIZE, "%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
- result.append(buffer);
-
+ dst->appendFormat("%*s- Type: %s\n", spaces, "", mType == AUDIO_ROUTE_MUX ? "Mux" : "Mix");
+ dst->appendFormat("%*s- Sink: %s\n", spaces, "", mSink->getTagName().string());
if (mSources.size() != 0) {
- snprintf(buffer, SIZE, "%*s- Sources: \n", spaces, "");
- result.append(buffer);
+ dst->appendFormat("%*s- Sources: \n", spaces, "");
for (size_t i = 0; i < mSources.size(); i++) {
- snprintf(buffer, SIZE, "%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
- result.append(buffer);
+ dst->appendFormat("%*s%s \n", spaces + 4, "", mSources[i]->getTagName().string());
}
}
- result.append("\n");
-
- write(fd, result.string(), result.size());
+ dst->append("\n");
}
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 0d65a31..815612d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -17,6 +17,7 @@
#define LOG_TAG "APM_ClientDescriptor"
//#define LOG_NDEBUG 0
+#include <sstream>
#include <utils/Log.h>
#include <utils/String8.h>
#include "AudioGain.h"
@@ -29,49 +30,43 @@
namespace android {
-status_t ClientDescriptor::dump(int fd, int spaces, int index)
+std::string ClientDescriptor::toShortString() const
{
- String8 out;
+ std::stringstream ss;
- // FIXME: use until other descriptor classes have a dump to String8 method
- mDumpFd = fd;
-
- status_t status = dump(out, spaces, index);
- if (status == NO_ERROR) {
- write(fd, out.string(), out.size());
- }
-
- return status;
+ ss << "PortId: " << mPortId << " SessionId: " << mSessionId << " Uid: " << mUid;
+ return ss.str();
}
-status_t ClientDescriptor::dump(String8& out, int spaces, int index)
+void ClientDescriptor::dump(String8 *dst, int spaces, int index) const
{
- out.appendFormat("%*sClient %d:\n", spaces, "", index+1);
- out.appendFormat("%*s- Port ID: %d Session Id: %d UID: %d\n", spaces, "",
+ dst->appendFormat("%*sClient %d:\n", spaces, "", index+1);
+ dst->appendFormat("%*s- Port Id: %d Session Id: %d UID: %d\n", spaces, "",
mPortId, mSessionId, mUid);
- out.appendFormat("%*s- Format: %08x Sampling rate: %d Channels: %08x\n", spaces, "",
+ dst->appendFormat("%*s- Format: %08x Sampling rate: %d Channels: %08x\n", spaces, "",
mConfig.format, mConfig.sample_rate, mConfig.channel_mask);
- out.appendFormat("%*s- Preferred Device Id: %08x\n", spaces, "", mPreferredDeviceId);
- out.appendFormat("%*s- State: %s\n", spaces, "", mActive ? "Active" : "Inactive");
- return NO_ERROR;
+ dst->appendFormat("%*s- Preferred Device Id: %08x\n", spaces, "", mPreferredDeviceId);
+ dst->appendFormat("%*s- State: %s\n", spaces, "", mActive ? "Active" : "Inactive");
}
-status_t TrackClientDescriptor::dump(String8& out, int spaces, int index)
+void TrackClientDescriptor::dump(String8 *dst, int spaces, int index) const
{
- ClientDescriptor::dump(out, spaces, index);
-
- out.appendFormat("%*s- Stream: %d flags: %08x\n", spaces, "", mStream, mFlags);
-
- return NO_ERROR;
+ ClientDescriptor::dump(dst, spaces, index);
+ dst->appendFormat("%*s- Stream: %d flags: %08x\n", spaces, "", mStream, mFlags);
}
-status_t RecordClientDescriptor::dump(String8& out, int spaces, int index)
+std::string TrackClientDescriptor::toShortString() const
{
- ClientDescriptor::dump(out, spaces, index);
+ std::stringstream ss;
- out.appendFormat("%*s- Source: %d flags: %08x\n", spaces, "", mSource, mFlags);
+ ss << ClientDescriptor::toShortString() << " Stream: " << mStream;
+ return ss.str();
+}
- return NO_ERROR;
+void RecordClientDescriptor::dump(String8 *dst, int spaces, int index) const
+{
+ ClientDescriptor::dump(dst, spaces, index);
+ dst->appendFormat("%*s- Source: %d flags: %08x\n", spaces, "", mSource, mFlags);
}
SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
@@ -95,31 +90,19 @@
mHwOutput = hwOutput;
}
-status_t SourceClientDescriptor::dump(String8& out, int spaces, int index)
+void SourceClientDescriptor::dump(String8 *dst, int spaces, int index) const
{
- TrackClientDescriptor::dump(out, spaces, index);
-
- if (mDumpFd >= 0) {
- out.appendFormat("%*s- Device:\n", spaces, "");
- write(mDumpFd, out.string(), out.size());
-
- mSrcDevice->dump(mDumpFd, 2, 0);
- mDumpFd = -1;
- }
-
- return NO_ERROR;
+ TrackClientDescriptor::dump(dst, spaces, index);
+ dst->appendFormat("%*s- Device:\n", spaces, "");
+ mSrcDevice->dump(dst, 2, 0);
}
-status_t SourceClientCollection::dump(int fd) const
+void SourceClientCollection::dump(String8 *dst) const
{
- String8 out;
- out.append("\nAudio sources:\n");
- write(fd, out.string(), out.size());
+ dst->append("\nAudio sources:\n");
for (size_t i = 0; i < size(); i++) {
- valueAt(i)->dump(fd, 2, i);
+ valueAt(i)->dump(dst, 2, i);
}
-
- return NO_ERROR;
}
}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
index 19eac26..59db81c 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ConfigParsingUtils.cpp
@@ -407,6 +407,8 @@
config.setHwModules(hwModules);
+ config.setDefaultSurroundFormats();
+
config_free(root);
free(root);
free(data);
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index 1638645..a9f7220 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -199,20 +199,15 @@
return nullptr;
}
-status_t DeviceVector::dump(int fd, const String8 &tag, int spaces, bool verbose) const
+void DeviceVector::dump(String8 *dst, const String8 &tag, int spaces, bool verbose) const
{
if (isEmpty()) {
- return NO_ERROR;
+ return;
}
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "%*s- %s devices:\n", spaces, "", tag.string());
- write(fd, buffer, strlen(buffer));
+ dst->appendFormat("%*s- %s devices:\n", spaces, "", tag.string());
for (size_t i = 0; i < size(); i++) {
- itemAt(i)->dump(fd, spaces + 2, i, verbose);
+ itemAt(i)->dump(dst, spaces + 2, i, verbose);
}
- return NO_ERROR;
}
void DeviceDescriptor::toAudioPortConfig(struct audio_port_config *dstConfig,
@@ -269,35 +264,23 @@
port->pickAudioProfile(mSamplingRate, mChannelMask, mFormat);
}
-status_t DeviceDescriptor::dump(int fd, int spaces, int index, bool verbose) const
+void DeviceDescriptor::dump(String8 *dst, int spaces, int index, bool verbose) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "%*sDevice %d:\n", spaces, "", index+1);
- result.append(buffer);
+ dst->appendFormat("%*sDevice %d:\n", spaces, "", index + 1);
if (mId != 0) {
- snprintf(buffer, SIZE, "%*s- id: %2d\n", spaces, "", mId);
- result.append(buffer);
+ dst->appendFormat("%*s- id: %2d\n", spaces, "", mId);
}
if (!mTagName.isEmpty()) {
- snprintf(buffer, SIZE, "%*s- tag name: %s\n", spaces, "", mTagName.string());
- result.append(buffer);
+ dst->appendFormat("%*s- tag name: %s\n", spaces, "", mTagName.string());
}
std::string deviceLiteral;
if (deviceToString(mDeviceType, deviceLiteral)) {
- snprintf(buffer, SIZE, "%*s- type: %-48s\n", spaces, "", deviceLiteral.c_str());
- result.append(buffer);
+ dst->appendFormat("%*s- type: %-48s\n", spaces, "", deviceLiteral.c_str());
}
if (mAddress.size() != 0) {
- snprintf(buffer, SIZE, "%*s- address: %-32s\n", spaces, "", mAddress.string());
- result.append(buffer);
+ dst->appendFormat("%*s- address: %-32s\n", spaces, "", mAddress.string());
}
- write(fd, result.string(), result.size());
- AudioPort::dump(fd, spaces, verbose);
-
- return NO_ERROR;
+ AudioPort::dump(dst, spaces, verbose);
}
void DeviceDescriptor::log() const
diff --git a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
index 7b2341e..8bbb798 100644
--- a/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/EffectDescriptor.cpp
@@ -22,25 +22,13 @@
namespace android {
-status_t EffectDescriptor::dump(int fd)
+void EffectDescriptor::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, " I/O: %d\n", mIo);
- result.append(buffer);
- snprintf(buffer, SIZE, " Strategy: %d\n", mStrategy);
- result.append(buffer);
- snprintf(buffer, SIZE, " Session: %d\n", mSession);
- result.append(buffer);
- snprintf(buffer, SIZE, " Name: %s\n", mDesc.name);
- result.append(buffer);
- snprintf(buffer, SIZE, " %s\n", mEnabled ? "Enabled" : "Disabled");
- result.append(buffer);
- write(fd, result.string(), result.size());
-
- return NO_ERROR;
+ dst->appendFormat(" I/O: %d\n", mIo);
+ dst->appendFormat(" Strategy: %d\n", mStrategy);
+ dst->appendFormat(" Session: %d\n", mSession);
+ dst->appendFormat(" Name: %s\n", mDesc.name);
+ dst->appendFormat(" %s\n", mEnabled ? "Enabled" : "Disabled");
}
EffectDescriptorCollection::EffectDescriptorCollection() :
@@ -174,24 +162,16 @@
return MAX_EFFECTS_MEMORY;
}
-status_t EffectDescriptorCollection::dump(int fd)
+void EffectDescriptorCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE,
+ dst->appendFormat(
"\nTotal Effects CPU: %f MIPS, Total Effects memory: %d KB, Max memory used: %d KB\n",
(float)mTotalEffectsCpuLoad/10, mTotalEffectsMemory, mTotalEffectsMemoryMaxUsed);
- write(fd, buffer, strlen(buffer));
-
- snprintf(buffer, SIZE, "Registered effects:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("Registered effects:\n");
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "- Effect %d dump:\n", keyAt(i));
- write(fd, buffer, strlen(buffer));
- valueAt(i)->dump(fd);
+ dst->appendFormat("- Effect %d dump:\n", keyAt(i));
+ valueAt(i)->dump(dst);
}
- return NO_ERROR;
}
}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index dcc0ec8..92bc595 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -218,37 +218,27 @@
mHandle = handle;
}
-void HwModule::dump(int fd)
+void HwModule::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, " - name: %s\n", getName());
- result.append(buffer);
- snprintf(buffer, SIZE, " - handle: %d\n", mHandle);
- result.append(buffer);
- snprintf(buffer, SIZE, " - version: %u.%u\n", getHalVersionMajor(), getHalVersionMinor());
- result.append(buffer);
- write(fd, result.string(), result.size());
+ dst->appendFormat(" - name: %s\n", getName());
+ dst->appendFormat(" - handle: %d\n", mHandle);
+ dst->appendFormat(" - version: %u.%u\n", getHalVersionMajor(), getHalVersionMinor());
if (mOutputProfiles.size()) {
- write(fd, " - outputs:\n", strlen(" - outputs:\n"));
+ dst->append(" - outputs:\n");
for (size_t i = 0; i < mOutputProfiles.size(); i++) {
- snprintf(buffer, SIZE, " output %zu:\n", i);
- write(fd, buffer, strlen(buffer));
- mOutputProfiles[i]->dump(fd);
+ dst->appendFormat(" output %zu:\n", i);
+ mOutputProfiles[i]->dump(dst);
}
}
if (mInputProfiles.size()) {
- write(fd, " - inputs:\n", strlen(" - inputs:\n"));
+ dst->append(" - inputs:\n");
for (size_t i = 0; i < mInputProfiles.size(); i++) {
- snprintf(buffer, SIZE, " input %zu:\n", i);
- write(fd, buffer, strlen(buffer));
- mInputProfiles[i]->dump(fd);
+ dst->appendFormat(" input %zu:\n", i);
+ mInputProfiles[i]->dump(dst);
}
}
- mDeclaredDevices.dump(fd, String8("Declared"), 2, true);
- mRoutes.dump(fd, 2);
+ mDeclaredDevices.dump(dst, String8("Declared"), 2, true);
+ mRoutes.dump(dst, 2);
}
sp <HwModule> HwModuleCollection::getModuleFromName(const char *name) const
@@ -301,19 +291,13 @@
return devDesc;
}
-status_t HwModuleCollection::dump(int fd) const
+void HwModuleCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\nHW Modules dump:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("\nHW Modules dump:\n");
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "- HW Module %zu:\n", i + 1);
- write(fd, buffer, strlen(buffer));
- itemAt(i)->dump(fd);
+ dst->appendFormat("- HW Module %zu:\n", i + 1);
+ itemAt(i)->dump(dst);
}
- return NO_ERROR;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
index fbc2384..8660624 100644
--- a/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/IOProfile.cpp
@@ -108,16 +108,11 @@
return true;
}
-void IOProfile::dump(int fd)
+void IOProfile::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
+ AudioPort::dump(dst, 4);
- AudioPort::dump(fd, 4);
-
- snprintf(buffer, SIZE, " - flags: 0x%04x", getFlags());
- result.append(buffer);
+ dst->appendFormat(" - flags: 0x%04x", getFlags());
std::string flagsLiteral;
if (getRole() == AUDIO_PORT_ROLE_SINK) {
InputFlagConverter::maskToString(getFlags(), flagsLiteral);
@@ -125,21 +120,14 @@
OutputFlagConverter::maskToString(getFlags(), flagsLiteral);
}
if (!flagsLiteral.empty()) {
- result.appendFormat(" (%s)", flagsLiteral.c_str());
+ dst->appendFormat(" (%s)", flagsLiteral.c_str());
}
- result.append("\n");
- write(fd, result.string(), result.size());
- mSupportedDevices.dump(fd, String8("Supported"), 4, false);
-
- result.clear();
- snprintf(buffer, SIZE, "\n - maxOpenCount: %u - curOpenCount: %u\n",
+ dst->append("\n");
+ mSupportedDevices.dump(dst, String8("Supported"), 4, false);
+ dst->appendFormat("\n - maxOpenCount: %u - curOpenCount: %u\n",
maxOpenCount, curOpenCount);
- result.append(buffer);
- snprintf(buffer, SIZE, " - maxActiveCount: %u - curActiveCount: %u\n",
+ dst->appendFormat(" - maxActiveCount: %u - curActiveCount: %u\n",
maxActiveCount, curActiveCount);
- result.append(buffer);
-
- write(fd, result.string(), result.size());
}
void IOProfile::log()
diff --git a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
index 8008a7c..179a678 100644
--- a/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/Serializer.cpp
@@ -17,236 +17,441 @@
#define LOG_TAG "APM::Serializer"
//#define LOG_NDEBUG 0
-#include "Serializer.h"
-#include <media/convert.h>
-#include "TypeConverter.h"
+#include <memory>
+#include <string>
+#include <utility>
+
+#include <hidl/Status.h>
#include <libxml/parser.h>
#include <libxml/xinclude.h>
-#include <string>
-#include <sstream>
-#include <istream>
-
-using std::string;
+#include <media/convert.h>
+#include <utils/Log.h>
+#include <utils/StrongPointer.h>
+#include <utils/Errors.h>
+#include <utils/RefBase.h>
+#include "Serializer.h"
+#include "TypeConverter.h"
namespace android {
-string getXmlAttribute(const xmlNode *cur, const char *attribute)
+namespace {
+
+// TODO(mnaganov): Consider finding an alternative for using HIDL code.
+using hardware::Return;
+using hardware::Status;
+using utilities::convertTo;
+
+template<typename E, typename C>
+struct AndroidCollectionTraits {
+ typedef sp<E> Element;
+ typedef C Collection;
+ typedef void* PtrSerializingCtx;
+
+ static status_t addElementToCollection(const Element &element, Collection *collection) {
+ return collection->add(element) >= 0 ? NO_ERROR : BAD_VALUE;
+ }
+};
+
+template<typename C>
+struct StdCollectionTraits {
+ typedef C Collection;
+ typedef typename C::value_type Element;
+ typedef void* PtrSerializingCtx;
+
+ static status_t addElementToCollection(const Element &element, Collection *collection) {
+ auto pair = collection->insert(element);
+ return pair.second ? NO_ERROR : BAD_VALUE;
+ }
+};
+
+struct AudioGainTraits : public AndroidCollectionTraits<AudioGain, AudioGainCollection>
{
- xmlChar *xmlValue = xmlGetProp(cur, (const xmlChar*)attribute);
- if (xmlValue == NULL) {
+ static constexpr const char *tag = "gain";
+ static constexpr const char *collectionTag = "gains";
+
+ struct Attributes
+ {
+ /** gain modes supported, e.g. AUDIO_GAIN_MODE_CHANNELS. */
+ static constexpr const char *mode = "mode";
+ /** controlled channels, needed if mode AUDIO_GAIN_MODE_CHANNELS. */
+ static constexpr const char *channelMask = "channel_mask";
+ static constexpr const char *minValueMB = "minValueMB"; /**< min value in millibel. */
+ static constexpr const char *maxValueMB = "maxValueMB"; /**< max value in millibel. */
+ /** default value in millibel. */
+ static constexpr const char *defaultValueMB = "defaultValueMB";
+ static constexpr const char *stepValueMB = "stepValueMB"; /**< step value in millibel. */
+ /** needed if mode AUDIO_GAIN_MODE_RAMP. */
+ static constexpr const char *minRampMs = "minRampMs";
+ /** needed if mode AUDIO_GAIN_MODE_RAMP. */
+ static constexpr const char *maxRampMs = "maxRampMs";
+ };
+
+ static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+ // No children
+};
+
+// A profile section contains a name, one audio format and the list of supported sampling rates
+// and channel masks for this format
+struct AudioProfileTraits : public AndroidCollectionTraits<AudioProfile, AudioProfileVector>
+{
+ static constexpr const char *tag = "profile";
+ static constexpr const char *collectionTag = "profiles";
+
+ struct Attributes
+ {
+ static constexpr const char *samplingRates = "samplingRates";
+ static constexpr const char *format = "format";
+ static constexpr const char *channelMasks = "channelMasks";
+ };
+
+ static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+};
+
+struct MixPortTraits : public AndroidCollectionTraits<IOProfile, IOProfileCollection>
+{
+ static constexpr const char *tag = "mixPort";
+ static constexpr const char *collectionTag = "mixPorts";
+
+ struct Attributes
+ {
+ static constexpr const char *name = "name";
+ static constexpr const char *role = "role";
+ static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
+ static constexpr const char *flags = "flags";
+ static constexpr const char *maxOpenCount = "maxOpenCount";
+ static constexpr const char *maxActiveCount = "maxActiveCount";
+ };
+
+ static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+ // Children: GainTraits
+};
+
+struct DevicePortTraits : public AndroidCollectionTraits<DeviceDescriptor, DeviceVector>
+{
+ static constexpr const char *tag = "devicePort";
+ static constexpr const char *collectionTag = "devicePorts";
+
+ struct Attributes
+ {
+ /** <device tag name>: any string without space. */
+ static constexpr const char *tagName = "tagName";
+ static constexpr const char *type = "type"; /**< <device type>. */
+ static constexpr const char *role = "role"; /**< <device role: sink or source>. */
+ static constexpr const char *roleSource = "source"; /**< <attribute role source value>. */
+ /** optional: device address, char string less than 64. */
+ static constexpr const char *address = "address";
+ };
+
+ static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+ // Children: GainTraits (optional)
+};
+
+struct RouteTraits : public AndroidCollectionTraits<AudioRoute, AudioRouteVector>
+{
+ static constexpr const char *tag = "route";
+ static constexpr const char *collectionTag = "routes";
+
+ struct Attributes
+ {
+ static constexpr const char *type = "type"; /**< <route type>: mix or mux. */
+ static constexpr const char *typeMix = "mix"; /**< type attribute mix value. */
+ static constexpr const char *sink = "sink"; /**< <sink: involved in this route>. */
+ /** sources: all source that can be involved in this route. */
+ static constexpr const char *sources = "sources";
+ };
+
+ typedef HwModule *PtrSerializingCtx;
+
+ static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+};
+
+struct ModuleTraits : public AndroidCollectionTraits<HwModule, HwModuleCollection>
+{
+ static constexpr const char *tag = "module";
+ static constexpr const char *collectionTag = "modules";
+
+ static constexpr const char *childAttachedDevicesTag = "attachedDevices";
+ static constexpr const char *childAttachedDeviceTag = "item";
+ static constexpr const char *childDefaultOutputDeviceTag = "defaultOutputDevice";
+
+ struct Attributes
+ {
+ static constexpr const char *name = "name";
+ static constexpr const char *version = "halVersion";
+ };
+
+ typedef AudioPolicyConfig *PtrSerializingCtx;
+
+ static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+ // Children: mixPortTraits, devicePortTraits, and routeTraits
+ // Need to call deserialize on each child
+};
+
+struct GlobalConfigTraits
+{
+ static constexpr const char *tag = "globalConfiguration";
+
+ struct Attributes
+ {
+ static constexpr const char *speakerDrcEnabled = "speaker_drc_enabled";
+ };
+
+ static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
+};
+
+struct VolumeTraits : public AndroidCollectionTraits<VolumeCurve, VolumeCurvesCollection>
+{
+ static constexpr const char *tag = "volume";
+ static constexpr const char *collectionTag = "volumes";
+ static constexpr const char *volumePointTag = "point";
+ static constexpr const char *referenceTag = "reference";
+
+ struct Attributes
+ {
+ static constexpr const char *stream = "stream";
+ static constexpr const char *deviceCategory = "deviceCategory";
+ static constexpr const char *reference = "ref";
+ static constexpr const char *referenceName = "name";
+ };
+
+ static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+ // No Children
+};
+
+struct SurroundSoundTraits
+{
+ static constexpr const char *tag = "surroundSound";
+
+ static status_t deserialize(const xmlNode *root, AudioPolicyConfig *config);
+ // Children: SurroundSoundFormatTraits
+};
+
+struct SurroundSoundFormatTraits : public StdCollectionTraits<AudioPolicyConfig::SurroundFormats>
+{
+ static constexpr const char *tag = "format";
+ static constexpr const char *collectionTag = "formats";
+
+ struct Attributes
+ {
+ static constexpr const char *name = "name";
+ static constexpr const char *subformats = "subformats";
+ };
+
+ static Return<Element> deserialize(const xmlNode *cur, PtrSerializingCtx serializingContext);
+};
+
+class PolicySerializer
+{
+public:
+ PolicySerializer() : mVersion{std::to_string(gMajor) + "." + std::to_string(gMinor)}
+ {
+ ALOGV("%s: Version=%s Root=%s", __func__, mVersion.c_str(), rootName);
+ }
+ status_t deserialize(const char *configFile, AudioPolicyConfig *config);
+
+private:
+ static constexpr const char *rootName = "audioPolicyConfiguration";
+ static constexpr const char *versionAttribute = "version";
+ static constexpr uint32_t gMajor = 1; /**< the major number of the policy xml format version. */
+ static constexpr uint32_t gMinor = 0; /**< the minor number of the policy xml format version. */
+
+ typedef AudioPolicyConfig Element;
+
+ const std::string mVersion;
+
+ // Children: ModulesTraits, VolumeTraits, SurroundSoundTraits (optional)
+};
+
+template <class T>
+constexpr void (*xmlDeleter)(T* t);
+template <>
+constexpr auto xmlDeleter<xmlDoc> = xmlFreeDoc;
+// http://b/111067277 - Add back constexpr when we switch to C++17.
+template <>
+auto xmlDeleter<xmlChar> = [](xmlChar *s) { xmlFree(s); };
+
+/** @return a unique_ptr with the correct deleter for the libxml2 object. */
+template <class T>
+constexpr auto make_xmlUnique(T *t) {
+ // Wrap deleter in lambda to enable empty base optimization
+ auto deleter = [](T *t) { xmlDeleter<T>(t); };
+ return std::unique_ptr<T, decltype(deleter)>{t, deleter};
+}
+
+std::string getXmlAttribute(const xmlNode *cur, const char *attribute)
+{
+ auto xmlValue = make_xmlUnique(xmlGetProp(cur, reinterpret_cast<const xmlChar*>(attribute)));
+ if (xmlValue == nullptr) {
return "";
}
- string value((const char*)xmlValue);
- xmlFree(xmlValue);
+ std::string value(reinterpret_cast<const char*>(xmlValue.get()));
return value;
}
-using utilities::convertTo;
-
-const char *const PolicySerializer::rootName = "audioPolicyConfiguration";
-const char *const PolicySerializer::versionAttribute = "version";
-const uint32_t PolicySerializer::gMajor = 1;
-const uint32_t PolicySerializer::gMinor = 0;
-static const char *const gReferenceElementName = "reference";
-static const char *const gReferenceAttributeName = "name";
-
template <class Trait>
-static void getReference(const _xmlNode *root, const _xmlNode *&refNode, const string &refName)
+const xmlNode* getReference(const xmlNode *cur, const std::string &refName)
{
- const _xmlNode *col = root;
- while (col != NULL) {
- if (!xmlStrcmp(col->name, (const xmlChar *)Trait::collectionTag)) {
- const xmlNode *cur = col->children;
- while (cur != NULL) {
- if ((!xmlStrcmp(cur->name, (const xmlChar *)gReferenceElementName))) {
- string name = getXmlAttribute(cur, gReferenceAttributeName);
+ for (; cur != NULL; cur = cur->next) {
+ if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
+ for (const xmlNode *child = cur->children; child != NULL; child = child->next) {
+ if ((!xmlStrcmp(child->name,
+ reinterpret_cast<const xmlChar*>(Trait::referenceTag)))) {
+ std::string name = getXmlAttribute(child, Trait::Attributes::referenceName);
if (refName == name) {
- refNode = cur;
- return;
+ return child;
}
}
- cur = cur->next;
}
}
- col = col->next;
}
- return;
+ return NULL;
}
template <class Trait>
-static status_t deserializeCollection(_xmlDoc *doc, const _xmlNode *cur,
- typename Trait::Collection &collection,
- typename Trait::PtrSerializingCtx serializingContext)
+status_t deserializeCollection(const xmlNode *cur,
+ typename Trait::Collection *collection,
+ typename Trait::PtrSerializingCtx serializingContext)
{
- const xmlNode *root = cur->xmlChildrenNode;
- while (root != NULL) {
- if (xmlStrcmp(root->name, (const xmlChar *)Trait::collectionTag) &&
- xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
- root = root->next;
- continue;
+ for (cur = cur->xmlChildrenNode; cur != NULL; cur = cur->next) {
+ const xmlNode *child = NULL;
+ if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::collectionTag))) {
+ child = cur->xmlChildrenNode;
+ } else if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
+ child = cur;
}
- const xmlNode *child = root;
- if (!xmlStrcmp(child->name, (const xmlChar *)Trait::collectionTag)) {
- child = child->xmlChildrenNode;
- }
- while (child != NULL) {
- if (!xmlStrcmp(child->name, (const xmlChar *)Trait::tag)) {
- typename Trait::PtrElement element;
- status_t status = Trait::deserialize(doc, child, element, serializingContext);
- if (status != NO_ERROR) {
- return status;
- }
- if (collection.add(element) < 0) {
- ALOGE("%s: could not add element to %s collection", __FUNCTION__,
- Trait::collectionTag);
+ for (; child != NULL; child = child->next) {
+ if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
+ auto element = Trait::deserialize(child, serializingContext);
+ if (element.isOk()) {
+ status_t status = Trait::addElementToCollection(element, collection);
+ if (status != NO_ERROR) {
+ ALOGE("%s: could not add element to %s collection", __func__,
+ Trait::collectionTag);
+ return status;
+ }
+ } else {
+ return BAD_VALUE;
}
}
- child = child->next;
}
- if (!xmlStrcmp(root->name, (const xmlChar *)Trait::tag)) {
+ if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(Trait::tag))) {
return NO_ERROR;
}
- root = root->next;
}
return NO_ERROR;
}
-const char *const AudioGainTraits::tag = "gain";
-const char *const AudioGainTraits::collectionTag = "gains";
-
-const char AudioGainTraits::Attributes::mode[] = "mode";
-const char AudioGainTraits::Attributes::channelMask[] = "channel_mask";
-const char AudioGainTraits::Attributes::minValueMB[] = "minValueMB";
-const char AudioGainTraits::Attributes::maxValueMB[] = "maxValueMB";
-const char AudioGainTraits::Attributes::defaultValueMB[] = "defaultValueMB";
-const char AudioGainTraits::Attributes::stepValueMB[] = "stepValueMB";
-const char AudioGainTraits::Attributes::minRampMs[] = "minRampMs";
-const char AudioGainTraits::Attributes::maxRampMs[] = "maxRampMs";
-
-status_t AudioGainTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &gain,
- PtrSerializingCtx /*serializingContext*/)
+Return<AudioGainTraits::Element> AudioGainTraits::deserialize(const xmlNode *cur,
+ PtrSerializingCtx /*serializingContext*/)
{
static uint32_t index = 0;
- gain = new Element(index++, true);
+ Element gain = new AudioGain(index++, true);
- string mode = getXmlAttribute(root, Attributes::mode);
+ std::string mode = getXmlAttribute(cur, Attributes::mode);
if (!mode.empty()) {
gain->setMode(GainModeConverter::maskFromString(mode));
}
- string channelsLiteral = getXmlAttribute(root, Attributes::channelMask);
+ std::string channelsLiteral = getXmlAttribute(cur, Attributes::channelMask);
if (!channelsLiteral.empty()) {
gain->setChannelMask(channelMaskFromString(channelsLiteral));
}
- string minValueMBLiteral = getXmlAttribute(root, Attributes::minValueMB);
+ std::string minValueMBLiteral = getXmlAttribute(cur, Attributes::minValueMB);
int32_t minValueMB;
if (!minValueMBLiteral.empty() && convertTo(minValueMBLiteral, minValueMB)) {
gain->setMinValueInMb(minValueMB);
}
- string maxValueMBLiteral = getXmlAttribute(root, Attributes::maxValueMB);
+ std::string maxValueMBLiteral = getXmlAttribute(cur, Attributes::maxValueMB);
int32_t maxValueMB;
if (!maxValueMBLiteral.empty() && convertTo(maxValueMBLiteral, maxValueMB)) {
gain->setMaxValueInMb(maxValueMB);
}
- string defaultValueMBLiteral = getXmlAttribute(root, Attributes::defaultValueMB);
+ std::string defaultValueMBLiteral = getXmlAttribute(cur, Attributes::defaultValueMB);
int32_t defaultValueMB;
if (!defaultValueMBLiteral.empty() && convertTo(defaultValueMBLiteral, defaultValueMB)) {
gain->setDefaultValueInMb(defaultValueMB);
}
- string stepValueMBLiteral = getXmlAttribute(root, Attributes::stepValueMB);
+ std::string stepValueMBLiteral = getXmlAttribute(cur, Attributes::stepValueMB);
uint32_t stepValueMB;
if (!stepValueMBLiteral.empty() && convertTo(stepValueMBLiteral, stepValueMB)) {
gain->setStepValueInMb(stepValueMB);
}
- string minRampMsLiteral = getXmlAttribute(root, Attributes::minRampMs);
+ std::string minRampMsLiteral = getXmlAttribute(cur, Attributes::minRampMs);
uint32_t minRampMs;
if (!minRampMsLiteral.empty() && convertTo(minRampMsLiteral, minRampMs)) {
gain->setMinRampInMs(minRampMs);
}
- string maxRampMsLiteral = getXmlAttribute(root, Attributes::maxRampMs);
+ std::string maxRampMsLiteral = getXmlAttribute(cur, Attributes::maxRampMs);
uint32_t maxRampMs;
if (!maxRampMsLiteral.empty() && convertTo(maxRampMsLiteral, maxRampMs)) {
gain->setMaxRampInMs(maxRampMs);
}
- ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d", __FUNCTION__,
+ ALOGV("%s: adding new gain mode %08x channel mask %08x min mB %d max mB %d", __func__,
gain->getMode(), gain->getChannelMask(), gain->getMinValueInMb(),
gain->getMaxValueInMb());
- if (gain->getMode() == 0) {
- return BAD_VALUE;
+ if (gain->getMode() != 0) {
+ return gain;
+ } else {
+ return Status::fromStatusT(BAD_VALUE);
}
- return NO_ERROR;
}
-const char *const AudioProfileTraits::collectionTag = "profiles";
-const char *const AudioProfileTraits::tag = "profile";
-
-const char AudioProfileTraits::Attributes::name[] = "name";
-const char AudioProfileTraits::Attributes::samplingRates[] = "samplingRates";
-const char AudioProfileTraits::Attributes::format[] = "format";
-const char AudioProfileTraits::Attributes::channelMasks[] = "channelMasks";
-
-status_t AudioProfileTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &profile,
- PtrSerializingCtx /*serializingContext*/)
+Return<AudioProfileTraits::Element> AudioProfileTraits::deserialize(const xmlNode *cur,
+ PtrSerializingCtx /*serializingContext*/)
{
- string samplingRates = getXmlAttribute(root, Attributes::samplingRates);
- string format = getXmlAttribute(root, Attributes::format);
- string channels = getXmlAttribute(root, Attributes::channelMasks);
+ std::string samplingRates = getXmlAttribute(cur, Attributes::samplingRates);
+ std::string format = getXmlAttribute(cur, Attributes::format);
+ std::string channels = getXmlAttribute(cur, Attributes::channelMasks);
- profile = new Element(formatFromString(format, gDynamicFormat),
- channelMasksFromString(channels, ","),
- samplingRatesFromString(samplingRates, ","));
+ Element profile = new AudioProfile(formatFromString(format, gDynamicFormat),
+ channelMasksFromString(channels, ","),
+ samplingRatesFromString(samplingRates, ","));
profile->setDynamicFormat(profile->getFormat() == gDynamicFormat);
profile->setDynamicChannels(profile->getChannels().isEmpty());
profile->setDynamicRate(profile->getSampleRates().isEmpty());
- return NO_ERROR;
+ return profile;
}
-
-const char *const MixPortTraits::collectionTag = "mixPorts";
-const char *const MixPortTraits::tag = "mixPort";
-
-const char MixPortTraits::Attributes::name[] = "name";
-const char MixPortTraits::Attributes::role[] = "role";
-const char MixPortTraits::Attributes::flags[] = "flags";
-const char MixPortTraits::Attributes::maxOpenCount[] = "maxOpenCount";
-const char MixPortTraits::Attributes::maxActiveCount[] = "maxActiveCount";
-
-status_t MixPortTraits::deserialize(_xmlDoc *doc, const _xmlNode *child, PtrElement &mixPort,
- PtrSerializingCtx /*serializingContext*/)
+Return<MixPortTraits::Element> MixPortTraits::deserialize(const xmlNode *child,
+ PtrSerializingCtx /*serializingContext*/)
{
- string name = getXmlAttribute(child, Attributes::name);
+ std::string name = getXmlAttribute(child, Attributes::name);
if (name.empty()) {
- ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
- return BAD_VALUE;
+ ALOGE("%s: No %s found", __func__, Attributes::name);
+ return Status::fromStatusT(BAD_VALUE);
}
- ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
- string role = getXmlAttribute(child, Attributes::role);
+ ALOGV("%s: %s %s=%s", __func__, tag, Attributes::name, name.c_str());
+ std::string role = getXmlAttribute(child, Attributes::role);
if (role.empty()) {
- ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
- return BAD_VALUE;
+ ALOGE("%s: No %s found", __func__, Attributes::role);
+ return Status::fromStatusT(BAD_VALUE);
}
- ALOGV("%s: Role=%s", __FUNCTION__, role.c_str());
- audio_port_role_t portRole = role == "source" ? AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
+ ALOGV("%s: Role=%s", __func__, role.c_str());
+ audio_port_role_t portRole = (role == Attributes::roleSource) ?
+ AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
- mixPort = new Element(String8(name.c_str()), portRole);
+ Element mixPort = new IOProfile(String8(name.c_str()), portRole);
AudioProfileTraits::Collection profiles;
- deserializeCollection<AudioProfileTraits>(doc, child, profiles, NULL);
+ status_t status = deserializeCollection<AudioProfileTraits>(child, &profiles, NULL);
+ if (status != NO_ERROR) {
+ return Status::fromStatusT(status);
+ }
if (profiles.isEmpty()) {
profiles.add(AudioProfile::createFullDynamic());
}
mixPort->setAudioProfiles(profiles);
- string flags = getXmlAttribute(child, Attributes::flags);
+ std::string flags = getXmlAttribute(child, Attributes::flags);
if (!flags.empty()) {
// Source role
if (portRole == AUDIO_PORT_ROLE_SOURCE) {
@@ -256,52 +461,46 @@
mixPort->setFlags(InputFlagConverter::maskFromString(flags));
}
}
- string maxOpenCount = getXmlAttribute(child, Attributes::maxOpenCount);
+ std::string maxOpenCount = getXmlAttribute(child, Attributes::maxOpenCount);
if (!maxOpenCount.empty()) {
convertTo(maxOpenCount, mixPort->maxOpenCount);
}
- string maxActiveCount = getXmlAttribute(child, Attributes::maxActiveCount);
+ std::string maxActiveCount = getXmlAttribute(child, Attributes::maxActiveCount);
if (!maxActiveCount.empty()) {
convertTo(maxActiveCount, mixPort->maxActiveCount);
}
// Deserialize children
AudioGainTraits::Collection gains;
- deserializeCollection<AudioGainTraits>(doc, child, gains, NULL);
+ status = deserializeCollection<AudioGainTraits>(child, &gains, NULL);
+ if (status != NO_ERROR) {
+ return Status::fromStatusT(status);
+ }
mixPort->setGains(gains);
- return NO_ERROR;
+ return mixPort;
}
-const char *const DevicePortTraits::tag = "devicePort";
-const char *const DevicePortTraits::collectionTag = "devicePorts";
-
-const char DevicePortTraits::Attributes::tagName[] = "tagName";
-const char DevicePortTraits::Attributes::type[] = "type";
-const char DevicePortTraits::Attributes::role[] = "role";
-const char DevicePortTraits::Attributes::address[] = "address";
-const char DevicePortTraits::Attributes::roleSource[] = "source";
-
-status_t DevicePortTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &deviceDesc,
- PtrSerializingCtx /*serializingContext*/)
+Return<DevicePortTraits::Element> DevicePortTraits::deserialize(const xmlNode *cur,
+ PtrSerializingCtx /*serializingContext*/)
{
- string name = getXmlAttribute(root, Attributes::tagName);
+ std::string name = getXmlAttribute(cur, Attributes::tagName);
if (name.empty()) {
- ALOGE("%s: No %s found", __FUNCTION__, Attributes::tagName);
- return BAD_VALUE;
+ ALOGE("%s: No %s found", __func__, Attributes::tagName);
+ return Status::fromStatusT(BAD_VALUE);
}
- ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::tagName, name.c_str());
- string typeName = getXmlAttribute(root, Attributes::type);
+ ALOGV("%s: %s %s=%s", __func__, tag, Attributes::tagName, name.c_str());
+ std::string typeName = getXmlAttribute(cur, Attributes::type);
if (typeName.empty()) {
- ALOGE("%s: no type for %s", __FUNCTION__, name.c_str());
- return BAD_VALUE;
+ ALOGE("%s: no type for %s", __func__, name.c_str());
+ return Status::fromStatusT(BAD_VALUE);
}
- ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, typeName.c_str());
- string role = getXmlAttribute(root, Attributes::role);
+ ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, typeName.c_str());
+ std::string role = getXmlAttribute(cur, Attributes::role);
if (role.empty()) {
- ALOGE("%s: No %s found", __FUNCTION__, Attributes::role);
- return BAD_VALUE;
+ ALOGE("%s: No %s found", __func__, Attributes::role);
+ return Status::fromStatusT(BAD_VALUE);
}
- ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::role, role.c_str());
+ ALOGV("%s: %s %s=%s", __func__, tag, Attributes::role, role.c_str());
audio_port_role_t portRole = (role == Attributes::roleSource) ?
AUDIO_PORT_ROLE_SOURCE : AUDIO_PORT_ROLE_SINK;
@@ -309,333 +508,364 @@
if (!deviceFromString(typeName, type) ||
(!audio_is_input_device(type) && portRole == AUDIO_PORT_ROLE_SOURCE) ||
(!audio_is_output_devices(type) && portRole == AUDIO_PORT_ROLE_SINK)) {
- ALOGW("%s: bad type %08x", __FUNCTION__, type);
- return BAD_VALUE;
+ ALOGW("%s: bad type %08x", __func__, type);
+ return Status::fromStatusT(BAD_VALUE);
}
- deviceDesc = new Element(type, String8(name.c_str()));
+ Element deviceDesc = new DeviceDescriptor(type, String8(name.c_str()));
- string address = getXmlAttribute(root, Attributes::address);
+ std::string address = getXmlAttribute(cur, Attributes::address);
if (!address.empty()) {
- ALOGV("%s: address=%s for %s", __FUNCTION__, address.c_str(), name.c_str());
+ ALOGV("%s: address=%s for %s", __func__, address.c_str(), name.c_str());
deviceDesc->mAddress = String8(address.c_str());
}
AudioProfileTraits::Collection profiles;
- deserializeCollection<AudioProfileTraits>(doc, root, profiles, NULL);
+ status_t status = deserializeCollection<AudioProfileTraits>(cur, &profiles, NULL);
+ if (status != NO_ERROR) {
+ return Status::fromStatusT(status);
+ }
if (profiles.isEmpty()) {
profiles.add(AudioProfile::createFullDynamic());
}
deviceDesc->setAudioProfiles(profiles);
// Deserialize AudioGain children
- deserializeCollection<AudioGainTraits>(doc, root, deviceDesc->mGains, NULL);
- ALOGV("%s: adding device tag %s type %08x address %s", __FUNCTION__,
+ status = deserializeCollection<AudioGainTraits>(cur, &deviceDesc->mGains, NULL);
+ if (status != NO_ERROR) {
+ return Status::fromStatusT(status);
+ }
+ ALOGV("%s: adding device tag %s type %08x address %s", __func__,
deviceDesc->getName().string(), type, deviceDesc->mAddress.string());
- return NO_ERROR;
+ return deviceDesc;
}
-const char *const RouteTraits::tag = "route";
-const char *const RouteTraits::collectionTag = "routes";
-
-const char RouteTraits::Attributes::type[] = "type";
-const char RouteTraits::Attributes::typeMix[] = "mix";
-const char RouteTraits::Attributes::sink[] = "sink";
-const char RouteTraits::Attributes::sources[] = "sources";
-
-
-status_t RouteTraits::deserialize(_xmlDoc */*doc*/, const _xmlNode *root, PtrElement &element,
- PtrSerializingCtx ctx)
+Return<RouteTraits::Element> RouteTraits::deserialize(const xmlNode *cur, PtrSerializingCtx ctx)
{
- string type = getXmlAttribute(root, Attributes::type);
+ std::string type = getXmlAttribute(cur, Attributes::type);
if (type.empty()) {
- ALOGE("%s: No %s found", __FUNCTION__, Attributes::type);
- return BAD_VALUE;
+ ALOGE("%s: No %s found", __func__, Attributes::type);
+ return Status::fromStatusT(BAD_VALUE);
}
audio_route_type_t routeType = (type == Attributes::typeMix) ?
AUDIO_ROUTE_MIX : AUDIO_ROUTE_MUX;
- ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::type, type.c_str());
- element = new Element(routeType);
+ ALOGV("%s: %s %s=%s", __func__, tag, Attributes::type, type.c_str());
+ Element route = new AudioRoute(routeType);
- string sinkAttr = getXmlAttribute(root, Attributes::sink);
+ std::string sinkAttr = getXmlAttribute(cur, Attributes::sink);
if (sinkAttr.empty()) {
- ALOGE("%s: No %s found", __FUNCTION__, Attributes::sink);
- return BAD_VALUE;
+ ALOGE("%s: No %s found", __func__, Attributes::sink);
+ return Status::fromStatusT(BAD_VALUE);
}
// Convert Sink name to port pointer
sp<AudioPort> sink = ctx->findPortByTagName(String8(sinkAttr.c_str()));
if (sink == NULL) {
- ALOGE("%s: no sink found with name=%s", __FUNCTION__, sinkAttr.c_str());
- return BAD_VALUE;
+ ALOGE("%s: no sink found with name=%s", __func__, sinkAttr.c_str());
+ return Status::fromStatusT(BAD_VALUE);
}
- element->setSink(sink);
+ route->setSink(sink);
- string sourcesAttr = getXmlAttribute(root, Attributes::sources);
+ std::string sourcesAttr = getXmlAttribute(cur, Attributes::sources);
if (sourcesAttr.empty()) {
- ALOGE("%s: No %s found", __FUNCTION__, Attributes::sources);
- return BAD_VALUE;
+ ALOGE("%s: No %s found", __func__, Attributes::sources);
+ return Status::fromStatusT(BAD_VALUE);
}
// Tokenize and Convert Sources name to port pointer
AudioPortVector sources;
- char *sourcesLiteral = strndup(sourcesAttr.c_str(), strlen(sourcesAttr.c_str()));
- char *devTag = strtok(sourcesLiteral, ",");
+ std::unique_ptr<char[]> sourcesLiteral{strndup(
+ sourcesAttr.c_str(), strlen(sourcesAttr.c_str()))};
+ char *devTag = strtok(sourcesLiteral.get(), ",");
while (devTag != NULL) {
if (strlen(devTag) != 0) {
sp<AudioPort> source = ctx->findPortByTagName(String8(devTag));
if (source == NULL) {
- ALOGE("%s: no source found with name=%s", __FUNCTION__, devTag);
- free(sourcesLiteral);
- return BAD_VALUE;
+ ALOGE("%s: no source found with name=%s", __func__, devTag);
+ return Status::fromStatusT(BAD_VALUE);
}
sources.add(source);
}
devTag = strtok(NULL, ",");
}
- free(sourcesLiteral);
- sink->addRoute(element);
+ sink->addRoute(route);
for (size_t i = 0; i < sources.size(); i++) {
sp<AudioPort> source = sources.itemAt(i);
- source->addRoute(element);
+ source->addRoute(route);
}
- element->setSources(sources);
- return NO_ERROR;
+ route->setSources(sources);
+ return route;
}
-const char *const ModuleTraits::childAttachedDevicesTag = "attachedDevices";
-const char *const ModuleTraits::childAttachedDeviceTag = "item";
-const char *const ModuleTraits::childDefaultOutputDeviceTag = "defaultOutputDevice";
-
-const char *const ModuleTraits::tag = "module";
-const char *const ModuleTraits::collectionTag = "modules";
-
-const char ModuleTraits::Attributes::name[] = "name";
-const char ModuleTraits::Attributes::version[] = "halVersion";
-
-status_t ModuleTraits::deserialize(xmlDocPtr doc, const xmlNode *root, PtrElement &module,
- PtrSerializingCtx ctx)
+Return<ModuleTraits::Element> ModuleTraits::deserialize(const xmlNode *cur, PtrSerializingCtx ctx)
{
- string name = getXmlAttribute(root, Attributes::name);
+ std::string name = getXmlAttribute(cur, Attributes::name);
if (name.empty()) {
- ALOGE("%s: No %s found", __FUNCTION__, Attributes::name);
- return BAD_VALUE;
+ ALOGE("%s: No %s found", __func__, Attributes::name);
+ return Status::fromStatusT(BAD_VALUE);
}
uint32_t versionMajor = 0, versionMinor = 0;
- string versionLiteral = getXmlAttribute(root, Attributes::version);
+ std::string versionLiteral = getXmlAttribute(cur, Attributes::version);
if (!versionLiteral.empty()) {
sscanf(versionLiteral.c_str(), "%u.%u", &versionMajor, &versionMinor);
- ALOGV("%s: mHalVersion = major %u minor %u", __FUNCTION__,
+ ALOGV("%s: mHalVersion = major %u minor %u", __func__,
versionMajor, versionMajor);
}
- ALOGV("%s: %s %s=%s", __FUNCTION__, tag, Attributes::name, name.c_str());
+ ALOGV("%s: %s %s=%s", __func__, tag, Attributes::name, name.c_str());
- module = new Element(name.c_str(), versionMajor, versionMinor);
+ Element module = new HwModule(name.c_str(), versionMajor, versionMinor);
// Deserialize childrens: Audio Mix Port, Audio Device Ports (Source/Sink), Audio Routes
MixPortTraits::Collection mixPorts;
- deserializeCollection<MixPortTraits>(doc, root, mixPorts, NULL);
+ status_t status = deserializeCollection<MixPortTraits>(cur, &mixPorts, NULL);
+ if (status != NO_ERROR) {
+ return Status::fromStatusT(status);
+ }
module->setProfiles(mixPorts);
DevicePortTraits::Collection devicePorts;
- deserializeCollection<DevicePortTraits>(doc, root, devicePorts, NULL);
+ status = deserializeCollection<DevicePortTraits>(cur, &devicePorts, NULL);
+ if (status != NO_ERROR) {
+ return Status::fromStatusT(status);
+ }
module->setDeclaredDevices(devicePorts);
RouteTraits::Collection routes;
- deserializeCollection<RouteTraits>(doc, root, routes, module.get());
+ status = deserializeCollection<RouteTraits>(cur, &routes, module.get());
+ if (status != NO_ERROR) {
+ return Status::fromStatusT(status);
+ }
module->setRoutes(routes);
- const xmlNode *children = root->xmlChildrenNode;
- while (children != NULL) {
- if (!xmlStrcmp(children->name, (const xmlChar *)childAttachedDevicesTag)) {
- ALOGV("%s: %s %s found", __FUNCTION__, tag, childAttachedDevicesTag);
- const xmlNode *child = children->xmlChildrenNode;
- while (child != NULL) {
- if (!xmlStrcmp(child->name, (const xmlChar *)childAttachedDeviceTag)) {
- xmlChar *attachedDevice = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);
- if (attachedDevice != NULL) {
- ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childAttachedDeviceTag,
- (const char*)attachedDevice);
- sp<DeviceDescriptor> device =
- module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)attachedDevice));
+ for (const xmlNode *children = cur->xmlChildrenNode; children != NULL;
+ children = children->next) {
+ if (!xmlStrcmp(children->name, reinterpret_cast<const xmlChar*>(childAttachedDevicesTag))) {
+ ALOGV("%s: %s %s found", __func__, tag, childAttachedDevicesTag);
+ for (const xmlNode *child = children->xmlChildrenNode; child != NULL;
+ child = child->next) {
+ if (!xmlStrcmp(child->name,
+ reinterpret_cast<const xmlChar*>(childAttachedDeviceTag))) {
+ auto attachedDevice = make_xmlUnique(xmlNodeListGetString(
+ child->doc, child->xmlChildrenNode, 1));
+ if (attachedDevice != nullptr) {
+ ALOGV("%s: %s %s=%s", __func__, tag, childAttachedDeviceTag,
+ reinterpret_cast<const char*>(attachedDevice.get()));
+ sp<DeviceDescriptor> device = module->getDeclaredDevices().
+ getDeviceFromTagName(String8(reinterpret_cast<const char*>(
+ attachedDevice.get())));
ctx->addAvailableDevice(device);
- xmlFree(attachedDevice);
}
}
- child = child->next;
}
}
- if (!xmlStrcmp(children->name, (const xmlChar *)childDefaultOutputDeviceTag)) {
- xmlChar *defaultOutputDevice = xmlNodeListGetString(doc, children->xmlChildrenNode, 1);;
- if (defaultOutputDevice != NULL) {
- ALOGV("%s: %s %s=%s", __FUNCTION__, tag, childDefaultOutputDeviceTag,
- (const char*)defaultOutputDevice);
- sp<DeviceDescriptor> device =
- module->getDeclaredDevices().getDeviceFromTagName(String8((const char*)defaultOutputDevice));
+ if (!xmlStrcmp(children->name,
+ reinterpret_cast<const xmlChar*>(childDefaultOutputDeviceTag))) {
+ auto defaultOutputDevice = make_xmlUnique(xmlNodeListGetString(
+ children->doc, children->xmlChildrenNode, 1));
+ if (defaultOutputDevice != nullptr) {
+ ALOGV("%s: %s %s=%s", __func__, tag, childDefaultOutputDeviceTag,
+ reinterpret_cast<const char*>(defaultOutputDevice.get()));
+ sp<DeviceDescriptor> device = module->getDeclaredDevices().getDeviceFromTagName(
+ String8(reinterpret_cast<const char*>(defaultOutputDevice.get())));
if (device != 0 && ctx->getDefaultOutputDevice() == 0) {
ctx->setDefaultOutputDevice(device);
- ALOGV("%s: default is %08x", __FUNCTION__, ctx->getDefaultOutputDevice()->type());
+ ALOGV("%s: default is %08x",
+ __func__, ctx->getDefaultOutputDevice()->type());
}
- xmlFree(defaultOutputDevice);
}
}
- children = children->next;
}
- return NO_ERROR;
+ return module;
}
-const char *const GlobalConfigTraits::tag = "globalConfiguration";
-
-const char GlobalConfigTraits::Attributes::speakerDrcEnabled[] = "speaker_drc_enabled";
-
-
-status_t GlobalConfigTraits::deserialize(const xmlNode *cur, AudioPolicyConfig &config)
+status_t GlobalConfigTraits::deserialize(const xmlNode *root, AudioPolicyConfig *config)
{
- const xmlNode *root = cur->xmlChildrenNode;
- while (root != NULL) {
- if (!xmlStrcmp(root->name, (const xmlChar *)tag)) {
- string speakerDrcEnabled =
- getXmlAttribute(root, Attributes::speakerDrcEnabled);
+ for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
+ if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(tag))) {
+ std::string speakerDrcEnabled =
+ getXmlAttribute(cur, Attributes::speakerDrcEnabled);
bool isSpeakerDrcEnabled;
if (!speakerDrcEnabled.empty() &&
- convertTo<string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
- config.setSpeakerDrcEnabled(isSpeakerDrcEnabled);
+ convertTo<std::string, bool>(speakerDrcEnabled, isSpeakerDrcEnabled)) {
+ config->setSpeakerDrcEnabled(isSpeakerDrcEnabled);
}
return NO_ERROR;
}
- root = root->next;
}
return NO_ERROR;
}
-
-const char *const VolumeTraits::tag = "volume";
-const char *const VolumeTraits::collectionTag = "volumes";
-const char *const VolumeTraits::volumePointTag = "point";
-
-const char VolumeTraits::Attributes::stream[] = "stream";
-const char VolumeTraits::Attributes::deviceCategory[] = "deviceCategory";
-const char VolumeTraits::Attributes::reference[] = "ref";
-
-status_t VolumeTraits::deserialize(_xmlDoc *doc, const _xmlNode *root, PtrElement &element,
- PtrSerializingCtx /*serializingContext*/)
+Return<VolumeTraits::Element> VolumeTraits::deserialize(const xmlNode *cur,
+ PtrSerializingCtx /*serializingContext*/)
{
- string streamTypeLiteral = getXmlAttribute(root, Attributes::stream);
+ std::string streamTypeLiteral = getXmlAttribute(cur, Attributes::stream);
if (streamTypeLiteral.empty()) {
- ALOGE("%s: No %s found", __FUNCTION__, Attributes::stream);
- return BAD_VALUE;
+ ALOGE("%s: No %s found", __func__, Attributes::stream);
+ return Status::fromStatusT(BAD_VALUE);
}
audio_stream_type_t streamType;
if (!StreamTypeConverter::fromString(streamTypeLiteral, streamType)) {
- ALOGE("%s: Invalid %s", __FUNCTION__, Attributes::stream);
- return BAD_VALUE;
+ ALOGE("%s: Invalid %s", __func__, Attributes::stream);
+ return Status::fromStatusT(BAD_VALUE);
}
- string deviceCategoryLiteral = getXmlAttribute(root, Attributes::deviceCategory);
+ std::string deviceCategoryLiteral = getXmlAttribute(cur, Attributes::deviceCategory);
if (deviceCategoryLiteral.empty()) {
- ALOGE("%s: No %s found", __FUNCTION__, Attributes::deviceCategory);
- return BAD_VALUE;
+ ALOGE("%s: No %s found", __func__, Attributes::deviceCategory);
+ return Status::fromStatusT(BAD_VALUE);
}
device_category deviceCategory;
if (!DeviceCategoryConverter::fromString(deviceCategoryLiteral, deviceCategory)) {
- ALOGE("%s: Invalid %s=%s", __FUNCTION__, Attributes::deviceCategory,
+ ALOGE("%s: Invalid %s=%s", __func__, Attributes::deviceCategory,
deviceCategoryLiteral.c_str());
- return BAD_VALUE;
+ return Status::fromStatusT(BAD_VALUE);
}
- string referenceName = getXmlAttribute(root, Attributes::reference);
- const _xmlNode *ref = NULL;
+ std::string referenceName = getXmlAttribute(cur, Attributes::reference);
+ const xmlNode *ref = NULL;
if (!referenceName.empty()) {
- getReference<VolumeTraits>(root->parent, ref, referenceName);
+ ref = getReference<VolumeTraits>(cur->parent, referenceName);
if (ref == NULL) {
- ALOGE("%s: No reference Ptr found for %s", __FUNCTION__, referenceName.c_str());
- return BAD_VALUE;
+ ALOGE("%s: No reference Ptr found for %s", __func__, referenceName.c_str());
+ return Status::fromStatusT(BAD_VALUE);
}
}
- element = new Element(deviceCategory, streamType);
+ Element volCurve = new VolumeCurve(deviceCategory, streamType);
- const xmlNode *child = referenceName.empty() ? root->xmlChildrenNode : ref->xmlChildrenNode;
- while (child != NULL) {
- if (!xmlStrcmp(child->name, (const xmlChar *)volumePointTag)) {
- xmlChar *pointDefinition = xmlNodeListGetString(doc, child->xmlChildrenNode, 1);;
- if (pointDefinition == NULL) {
- return BAD_VALUE;
+ for (const xmlNode *child = referenceName.empty() ? cur->xmlChildrenNode : ref->xmlChildrenNode;
+ child != NULL; child = child->next) {
+ if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>(volumePointTag))) {
+ auto pointDefinition = make_xmlUnique(xmlNodeListGetString(
+ child->doc, child->xmlChildrenNode, 1));
+ if (pointDefinition == nullptr) {
+ return Status::fromStatusT(BAD_VALUE);
}
- ALOGV("%s: %s=%s", __FUNCTION__, tag, (const char*)pointDefinition);
+ ALOGV("%s: %s=%s",
+ __func__, tag, reinterpret_cast<const char*>(pointDefinition.get()));
Vector<int32_t> point;
- collectionFromString<DefaultTraits<int32_t> >((const char*)pointDefinition, point, ",");
+ collectionFromString<DefaultTraits<int32_t>>(
+ reinterpret_cast<const char*>(pointDefinition.get()), point, ",");
if (point.size() != 2) {
- ALOGE("%s: Invalid %s: %s", __FUNCTION__, volumePointTag,
- (const char*)pointDefinition);
- return BAD_VALUE;
+ ALOGE("%s: Invalid %s: %s", __func__, volumePointTag,
+ reinterpret_cast<const char*>(pointDefinition.get()));
+ return Status::fromStatusT(BAD_VALUE);
}
- element->add(CurvePoint(point[0], point[1]));
- xmlFree(pointDefinition);
+ volCurve->add(CurvePoint(point[0], point[1]));
}
- child = child->next;
+ }
+ return volCurve;
+}
+
+status_t SurroundSoundTraits::deserialize(const xmlNode *root, AudioPolicyConfig *config)
+{
+ config->setDefaultSurroundFormats();
+
+ for (const xmlNode *cur = root->xmlChildrenNode; cur != NULL; cur = cur->next) {
+ if (!xmlStrcmp(cur->name, reinterpret_cast<const xmlChar*>(tag))) {
+ AudioPolicyConfig::SurroundFormats formats;
+ status_t status = deserializeCollection<SurroundSoundFormatTraits>(
+ cur, &formats, nullptr);
+ if (status == NO_ERROR) {
+ config->setSurroundFormats(formats);
+ }
+ return NO_ERROR;
+ }
}
return NO_ERROR;
}
-PolicySerializer::PolicySerializer() : mRootElementName(rootName)
+Return<SurroundSoundFormatTraits::Element> SurroundSoundFormatTraits::deserialize(
+ const xmlNode *cur, PtrSerializingCtx /*serializingContext*/)
{
- std::ostringstream oss;
- oss << gMajor << "." << gMinor;
- mVersion = oss.str();
- ALOGV("%s: Version=%s Root=%s", __FUNCTION__, mVersion.c_str(), mRootElementName.c_str());
+ std::string formatLiteral = getXmlAttribute(cur, Attributes::name);
+ if (formatLiteral.empty()) {
+ ALOGE("%s: No %s found for a surround format", __func__, Attributes::name);
+ return Status::fromStatusT(BAD_VALUE);
+ }
+ audio_format_t format = formatFromString(formatLiteral);
+ if (format == AUDIO_FORMAT_DEFAULT) {
+ ALOGE("%s: Unrecognized format %s", __func__, formatLiteral.c_str());
+ return Status::fromStatusT(BAD_VALUE);
+ }
+ Element pair = std::make_pair(format, Collection::mapped_type{});
+
+ std::string subformatsLiteral = getXmlAttribute(cur, Attributes::subformats);
+ if (subformatsLiteral.empty()) return pair;
+ FormatVector subformats = formatsFromString(subformatsLiteral, " ");
+ for (const auto& subformat : subformats) {
+ auto result = pair.second.insert(subformat);
+ if (!result.second) {
+ ALOGE("%s: could not add subformat %x to collection", __func__, subformat);
+ return Status::fromStatusT(BAD_VALUE);
+ }
+ }
+ return pair;
}
-status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig &config)
+status_t PolicySerializer::deserialize(const char *configFile, AudioPolicyConfig *config)
{
- xmlDocPtr doc;
- doc = xmlParseFile(configFile);
- if (doc == NULL) {
- ALOGE("%s: Could not parse %s document.", __FUNCTION__, configFile);
+ auto doc = make_xmlUnique(xmlParseFile(configFile));
+ if (doc == nullptr) {
+ ALOGE("%s: Could not parse %s document.", __func__, configFile);
return BAD_VALUE;
}
- xmlNodePtr cur = xmlDocGetRootElement(doc);
- if (cur == NULL) {
- ALOGE("%s: Could not parse %s document: empty.", __FUNCTION__, configFile);
- xmlFreeDoc(doc);
+ xmlNodePtr root = xmlDocGetRootElement(doc.get());
+ if (root == NULL) {
+ ALOGE("%s: Could not parse %s document: empty.", __func__, configFile);
return BAD_VALUE;
}
- if (xmlXIncludeProcess(doc) < 0) {
- ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __FUNCTION__, configFile);
+ if (xmlXIncludeProcess(doc.get()) < 0) {
+ ALOGE("%s: libxml failed to resolve XIncludes on %s document.", __func__, configFile);
}
- if (xmlStrcmp(cur->name, (const xmlChar *) mRootElementName.c_str())) {
- ALOGE("%s: No %s root element found in xml data %s.", __FUNCTION__, mRootElementName.c_str(),
- (const char *)cur->name);
- xmlFreeDoc(doc);
+ if (xmlStrcmp(root->name, reinterpret_cast<const xmlChar*>(rootName))) {
+ ALOGE("%s: No %s root element found in xml data %s.", __func__, rootName,
+ reinterpret_cast<const char*>(root->name));
return BAD_VALUE;
}
- string version = getXmlAttribute(cur, versionAttribute);
+ std::string version = getXmlAttribute(root, versionAttribute);
if (version.empty()) {
- ALOGE("%s: No version found in root node %s", __FUNCTION__, mRootElementName.c_str());
+ ALOGE("%s: No version found in root node %s", __func__, rootName);
return BAD_VALUE;
}
if (version != mVersion) {
- ALOGE("%s: Version does not match; expect %s got %s", __FUNCTION__, mVersion.c_str(),
+ ALOGE("%s: Version does not match; expect %s got %s", __func__, mVersion.c_str(),
version.c_str());
return BAD_VALUE;
}
// Lets deserialize children
// Modules
ModuleTraits::Collection modules;
- deserializeCollection<ModuleTraits>(doc, cur, modules, &config);
- config.setHwModules(modules);
+ status_t status = deserializeCollection<ModuleTraits>(root, &modules, config);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ config->setHwModules(modules);
// deserialize volume section
VolumeTraits::Collection volumes;
- deserializeCollection<VolumeTraits>(doc, cur, volumes, &config);
- config.setVolumes(volumes);
+ status = deserializeCollection<VolumeTraits>(root, &volumes, config);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ config->setVolumes(volumes);
// Global Configuration
- GlobalConfigTraits::deserialize(cur, config);
+ GlobalConfigTraits::deserialize(root, config);
- xmlFreeDoc(doc);
+ // Surround configuration
+ SurroundSoundTraits::deserialize(root, config);
+
return android::OK;
}
+} // namespace
+
+status_t deserializeAudioPolicyFile(const char *fileName, AudioPolicyConfig *config)
+{
+ PolicySerializer serializer;
+ return serializer.deserialize(fileName, config);
+}
+
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp b/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
index ac3f1bc..620f361 100644
--- a/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/VolumeCurve.cpp
@@ -68,81 +68,56 @@
return decibels;
}
-void VolumeCurve::dump(int fd) const
+void VolumeCurve::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
- snprintf(buffer, SIZE, " {");
- result.append(buffer);
+ dst->append(" {");
for (size_t i = 0; i < mCurvePoints.size(); i++) {
- snprintf(buffer, SIZE, "(%3d, %5d)",
+ dst->appendFormat("(%3d, %5d)",
mCurvePoints[i].mIndex, mCurvePoints[i].mAttenuationInMb);
- result.append(buffer);
- result.append(i == (mCurvePoints.size() - 1) ? " }\n" : ", ");
+ dst->append(i == (mCurvePoints.size() - 1) ? " }\n" : ", ");
}
- write(fd, result.string(), result.size());
}
-void VolumeCurvesForStream::dump(int fd, int spaces = 0, bool curvePoints) const
+void VolumeCurvesForStream::dump(String8 *dst, int spaces = 0, bool curvePoints) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
if (!curvePoints) {
- snprintf(buffer, SIZE, "%s %02d %02d ",
+ dst->appendFormat("%s %02d %02d ",
mCanBeMuted ? "true " : "false", mIndexMin, mIndexMax);
- result.append(buffer);
for (size_t i = 0; i < mIndexCur.size(); i++) {
- snprintf(buffer, SIZE, "%04x : %02d, ", mIndexCur.keyAt(i), mIndexCur.valueAt(i));
- result.append(buffer);
+ dst->appendFormat("%04x : %02d, ", mIndexCur.keyAt(i), mIndexCur.valueAt(i));
}
- result.append("\n");
- write(fd, result.string(), result.size());
+ dst->append("\n");
return;
}
for (size_t i = 0; i < size(); i++) {
std::string deviceCatLiteral;
DeviceCategoryConverter::toString(keyAt(i), deviceCatLiteral);
- snprintf(buffer, SIZE, "%*s %s :",
+ dst->appendFormat("%*s %s :",
spaces, "", deviceCatLiteral.c_str());
- write(fd, buffer, strlen(buffer));
- valueAt(i)->dump(fd);
+ valueAt(i)->dump(dst);
}
- result.append("\n");
- write(fd, result.string(), result.size());
+ dst->append("\n");
}
-status_t VolumeCurvesCollection::dump(int fd) const
+void VolumeCurvesCollection::dump(String8 *dst) const
{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\nStreams dump:\n");
- write(fd, buffer, strlen(buffer));
- snprintf(buffer, SIZE,
+ dst->append("\nStreams dump:\n");
+ dst->append(
" Stream Can be muted Index Min Index Max Index Cur [device : index]...\n");
- write(fd, buffer, strlen(buffer));
for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, " %02zu ", i);
- write(fd, buffer, strlen(buffer));
- valueAt(i).dump(fd);
+ dst->appendFormat(" %02zu ", i);
+ valueAt(i).dump(dst);
}
- snprintf(buffer, SIZE, "\nVolume Curves for Use Cases (aka Stream types) dump:\n");
- write(fd, buffer, strlen(buffer));
+ dst->append("\nVolume Curves for Use Cases (aka Stream types) dump:\n");
for (size_t i = 0; i < size(); i++) {
std::string streamTypeLiteral;
StreamTypeConverter::toString(keyAt(i), streamTypeLiteral);
- snprintf(buffer, SIZE,
+ dst->appendFormat(
" %s (%02zu): Curve points for device category (index, attenuation in millibel)\n",
streamTypeLiteral.c_str(), i);
- write(fd, buffer, strlen(buffer));
- valueAt(i).dump(fd, 2, true);
+ valueAt(i).dump(dst, 2, true);
}
-
- return NO_ERROR;
}
} // namespace android
diff --git a/services/audiopolicy/config/audio_policy_configuration.xml b/services/audiopolicy/config/audio_policy_configuration.xml
index 9381f1f..1d037c3 100644
--- a/services/audiopolicy/config/audio_policy_configuration.xml
+++ b/services/audiopolicy/config/audio_policy_configuration.xml
@@ -198,4 +198,26 @@
<!-- End of Volume section -->
+ <?disabledUntilHalV4_1
+ <!-- Surround configuration -->
+
+ <surroundSound>
+ <!-- Each of the listed formats gets an entry in Surround Settings dialog.
+ There must be a corresponding Java ENCODING_... contant defined in AudioFormat.java,
+ and a display name defined in AudioFormat.toDisplayName. For the formats that don't
+ need a dedicated Surrond Settings dialog entry, a subformats list should be used. -->
+ <formats>
+ <format name="AUDIO_FORMAT_AC3" />
+ <format name="AUDIO_FORMAT_E_AC3" />
+ <format name="AUDIO_FORMAT_E_AC3_JOC" />
+ <format name="AUDIO_FORMAT_DOLBY_TRUEHD" />
+ <format name="AUDIO_FORMAT_DTS" />
+ <format name="AUDIO_FORMAT_DTS_HD" />
+ <format name="AUDIO_FORMAT_AAC_LC" subformats="AUDIO_FORMAT_AAC_HE_V1 AUDIO_FORMAT_AAC_HE_V2 AUDIO_FORMAT_AAC_ELD AUDIO_FORMAT_AAC_XHE" />
+ </formats>
+ </surroundSound>
+
+ <!-- End of Surround configuration -->
+ ?>
+
</audioPolicyConfiguration>
diff --git a/services/audiopolicy/enginedefault/Android.mk b/services/audiopolicy/enginedefault/Android.mk
index cbbe306..837d5bb 100644
--- a/services/audiopolicy/enginedefault/Android.mk
+++ b/services/audiopolicy/enginedefault/Android.mk
@@ -34,6 +34,8 @@
LOCAL_MODULE := libaudiopolicyenginedefault
LOCAL_MODULE_TAGS := optional
+LOCAL_HEADER_LIBRARIES := libbase_headers
+
LOCAL_STATIC_LIBRARIES := \
libaudiopolicycomponents \
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index 30f275f..69395f3 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -25,6 +25,7 @@
#endif
#include "Engine.h"
+#include <android-base/macros.h>
#include <AudioPolicyManagerObserver.h>
#include <AudioPort.h>
#include <IOProfile.h>
@@ -185,6 +186,7 @@
return STRATEGY_DTMF;
default:
ALOGE("unknown stream type %d", stream);
+ FALLTHROUGH_INTENDED;
case AUDIO_STREAM_SYSTEM:
// NOTE: SYSTEM stream uses MEDIA strategy because muting music and switching outputs
// while key clicks are played produces a poor result
@@ -302,7 +304,7 @@
break;
}
// when in call, DTMF and PHONE strategies follow the same rules
- // FALL THROUGH
+ FALLTHROUGH_INTENDED;
case STRATEGY_PHONE:
// Force use of only devices on primary output if:
@@ -343,7 +345,7 @@
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_BLUETOOTH_SCO;
if (device) break;
// if SCO device is requested but no SCO device is available, fall back to default case
- // FALL THROUGH
+ FALLTHROUGH_INTENDED;
default: // FORCE_NONE
device = availableOutputDevicesType & AUDIO_DEVICE_OUT_HEARING_AID;
@@ -415,7 +417,7 @@
outputDeviceTypesToIgnore);
break;
}
- // FALL THROUGH
+ FALLTHROUGH_INTENDED;
case STRATEGY_ENFORCED_AUDIBLE:
// strategy STRATEGY_ENFORCED_AUDIBLE uses same routing policy as STRATEGY_SONIFICATION
@@ -465,7 +467,7 @@
}
}
// The second device used for sonification is the same as the device used by media strategy
- // FALL THROUGH
+ FALLTHROUGH_INTENDED;
case STRATEGY_ACCESSIBILITY:
if (strategy == STRATEGY_ACCESSIBILITY) {
@@ -495,7 +497,7 @@
}
}
// For other cases, STRATEGY_ACCESSIBILITY behaves like STRATEGY_MEDIA
- // FALL THROUGH
+ FALLTHROUGH_INTENDED;
// FIXME: STRATEGY_REROUTING follow STRATEGY_MEDIA for now
case STRATEGY_REROUTING:
@@ -679,7 +681,7 @@
device = AUDIO_DEVICE_IN_BLUETOOTH_SCO_HEADSET;
break;
}
- // FALL THROUGH
+ FALLTHROUGH_INTENDED;
default: // FORCE_NONE
if (availableDeviceTypes & AUDIO_DEVICE_IN_WIRED_HEADSET) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index dd2158b..58acad3 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -62,26 +62,6 @@
// media / notification / system volume.
constexpr float IN_CALL_EARPIECE_HEADROOM_DB = 3.f;
-#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
-// Array of all surround formats.
-static const audio_format_t SURROUND_FORMATS[] = {
- AUDIO_FORMAT_AC3,
- AUDIO_FORMAT_E_AC3,
- AUDIO_FORMAT_DTS,
- AUDIO_FORMAT_DTS_HD,
- AUDIO_FORMAT_AAC_LC,
- AUDIO_FORMAT_DOLBY_TRUEHD,
- AUDIO_FORMAT_E_AC3_JOC,
-};
-// Array of all AAC formats. When AAC is enabled by users, all AAC formats should be enabled.
-static const audio_format_t AAC_FORMATS[] = {
- AUDIO_FORMAT_AAC_LC,
- AUDIO_FORMAT_AAC_HE_V1,
- AUDIO_FORMAT_AAC_HE_V2,
- AUDIO_FORMAT_AAC_ELD,
- AUDIO_FORMAT_AAC_XHE,
-};
-
// Compressed formats for MSD module, ordered from most preferred to least preferred.
static const std::vector<audio_format_t> compressedFormatsOrder = {{
AUDIO_FORMAT_MAT_2_1, AUDIO_FORMAT_MAT_2_0, AUDIO_FORMAT_E_AC3,
@@ -910,7 +890,7 @@
getStrategyForAttr(&attributes),
*flags);
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
- outputDesc->clientsMap().emplace(*portId, clientDesc);
+ outputDesc->addClient(clientDesc);
ALOGV(" getOutputForAttr() returns output %d selectedDeviceId %d for port ID %d",
*output, *selectedDeviceId, *portId);
@@ -1013,6 +993,23 @@
String8 address = outputDevices.size() > 0 ? outputDevices.itemAt(0)->mAddress
: String8("");
+ // MSD patch may be using the only output stream that can service this request. Release
+ // MSD patch to prioritize this request over any active output on MSD.
+ AudioPatchCollection msdPatches = getMsdPatches();
+ for (size_t i = 0; i < msdPatches.size(); i++) {
+ const auto& patch = msdPatches[i];
+ for (size_t j = 0; j < patch->mPatch.num_sinks; ++j) {
+ const struct audio_port_config *sink = &patch->mPatch.sinks[j];
+ if (sink->type == AUDIO_PORT_TYPE_DEVICE &&
+ (sink->ext.device.type & device) != AUDIO_DEVICE_NONE &&
+ (address.isEmpty() || strncmp(sink->ext.device.address, address.string(),
+ AUDIO_DEVICE_MAX_ADDRESS_LEN) == 0)) {
+ releaseAudioPatch(patch->mHandle, mUidCached);
+ break;
+ }
+ }
+ }
+
status = outputDesc->open(config, device, address, stream, *flags, &output);
// only accept an output with the requested parameters
@@ -1093,16 +1090,16 @@
const AudioPatchCollection AudioPolicyManager::getMsdPatches() const {
AudioPatchCollection msdPatches;
- audio_module_handle_t msdModuleHandle = mHwModules.getModuleFromName(
- AUDIO_HARDWARE_MODULE_ID_MSD)->getHandle();
- if (msdModuleHandle == AUDIO_MODULE_HANDLE_NONE) return msdPatches;
- for (size_t i = 0; i < mAudioPatches.size(); ++i) {
- sp<AudioPatch> patch = mAudioPatches.valueAt(i);
- for (size_t j = 0; j < patch->mPatch.num_sources; ++j) {
- const struct audio_port_config *source = &patch->mPatch.sources[j];
- if (source->type == AUDIO_PORT_TYPE_DEVICE &&
- source->ext.device.hw_module == msdModuleHandle) {
- msdPatches.addAudioPatch(patch->mHandle, patch);
+ sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+ if (msdModule != 0) {
+ for (size_t i = 0; i < mAudioPatches.size(); ++i) {
+ sp<AudioPatch> patch = mAudioPatches.valueAt(i);
+ for (size_t j = 0; j < patch->mPatch.num_sources; ++j) {
+ const struct audio_port_config *source = &patch->mPatch.sources[j];
+ if (source->type == AUDIO_PORT_TYPE_DEVICE &&
+ source->ext.device.hw_module == msdModule->getHandle()) {
+ msdPatches.addAudioPatch(patch->mHandle, patch);
+ }
}
}
}
@@ -1320,7 +1317,7 @@
ALOGW("startOutput() no output for client %d", portId);
return BAD_VALUE;
}
- sp<TrackClientDescriptor> client = outputDesc->clientsMap()[portId];
+ sp<TrackClientDescriptor> client = outputDesc->getClient(portId);
ALOGV("startOutput() output %d, stream %d, session %d",
outputDesc->mIoHandle, client->stream(), client->session());
@@ -1513,7 +1510,7 @@
ALOGW("stopOutput() no output for client %d", portId);
return BAD_VALUE;
}
- sp<TrackClientDescriptor> client = outputDesc->clientsMap()[portId];
+ sp<TrackClientDescriptor> client = outputDesc->getClient(portId);
ALOGV("stopOutput() output %d, stream %d, session %d",
outputDesc->mIoHandle, client->stream(), client->session());
@@ -1614,10 +1611,15 @@
sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
if (outputDesc == 0) {
+ // If an output descriptor is closed due to a device routing change,
+ // then there are race conditions with releaseOutput from tracks
+ // that may be destroyed (with no PlaybackThread) or a PlaybackThread
+ // destroyed shortly thereafter.
+ //
+ // Here we just log a warning, instead of a fatal error.
ALOGW("releaseOutput() no output for client %d", portId);
return;
}
- sp<TrackClientDescriptor> client = outputDesc->clientsMap()[portId];
ALOGV("releaseOutput() %d", outputDesc->mIoHandle);
@@ -1632,10 +1634,12 @@
mpClientInterface->onAudioPortListUpdate();
}
}
- outputDesc->clientsMap().erase(portId);
+ // stopOutput() needs to be successfully called before releaseOutput()
+ // otherwise there may be inaccurate stream reference counts.
+ // This is checked in outputDesc->removeClient below.
+ outputDesc->removeClient(portId);
}
-
status_t AudioPolicyManager::getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
@@ -1793,7 +1797,7 @@
*attr, *config, requestedDeviceId,
inputSource,flags, isSoundTrigger);
inputDesc = mInputs.valueFor(*input);
- inputDesc->clientsMap().emplace(*portId, clientDesc);
+ inputDesc->addClient(clientDesc);
ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
*input, *inputType, *selectedDeviceId, *portId);
@@ -1968,7 +1972,7 @@
return BAD_VALUE;
}
audio_io_handle_t input = inputDesc->mIoHandle;
- sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
+ sp<RecordClientDescriptor> client = inputDesc->getClient(portId);
if (client->active()) {
ALOGW("%s input %d client %d already started", __FUNCTION__, input, client->portId());
return INVALID_OPERATION;
@@ -2137,7 +2141,7 @@
return BAD_VALUE;
}
audio_io_handle_t input = inputDesc->mIoHandle;
- sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
+ sp<RecordClientDescriptor> client = inputDesc->getClient(portId);
if (!client->active()) {
ALOGW("%s input %d client %d already stopped", __FUNCTION__, input, client->portId());
return INVALID_OPERATION;
@@ -2196,15 +2200,15 @@
ALOGW("%s no input for client %d", __FUNCTION__, portId);
return;
}
- sp<RecordClientDescriptor> client = inputDesc->clientsMap()[portId];
+ sp<RecordClientDescriptor> client = inputDesc->getClient(portId);
audio_io_handle_t input = inputDesc->mIoHandle;
ALOGV("%s %d", __FUNCTION__, input);
- inputDesc->clientsMap().erase(portId);
+ inputDesc->removeClient(portId);
- if (inputDesc->clientsMap().size() > 0) {
- ALOGV("%s %zu clients remaining", __FUNCTION__, inputDesc->clientsMap().size());
+ if (inputDesc->getClientCount() > 0) {
+ ALOGV("%s(%d) %zu clients remaining", __func__, portId, inputDesc->getClientCount());
return;
}
@@ -2662,53 +2666,53 @@
return res;
}
-
-status_t AudioPolicyManager::dump(int fd)
+void AudioPolicyManager::dump(String8 *dst) const
{
- String8 result;
- result.appendFormat("\nAudioPolicyManager Dump: %p\n", this);
- result.appendFormat(" Primary Output: %d\n",
+ dst->appendFormat("\nAudioPolicyManager Dump: %p\n", this);
+ dst->appendFormat(" Primary Output: %d\n",
hasPrimaryOutput() ? mPrimaryOutput->mIoHandle : AUDIO_IO_HANDLE_NONE);
std::string stateLiteral;
AudioModeConverter::toString(mEngine->getPhoneState(), stateLiteral);
- result.appendFormat(" Phone state: %s\n", stateLiteral.c_str());
+ dst->appendFormat(" Phone state: %s\n", stateLiteral.c_str());
const char* forceUses[AUDIO_POLICY_FORCE_USE_CNT] = {
"communications", "media", "record", "dock", "system",
"HDMI system audio", "encoded surround output", "vibrate ringing" };
for (audio_policy_force_use_t i = AUDIO_POLICY_FORCE_FOR_COMMUNICATION;
i < AUDIO_POLICY_FORCE_USE_CNT; i = (audio_policy_force_use_t)((int)i + 1)) {
- result.appendFormat(" Force use for %s: %d\n",
+ dst->appendFormat(" Force use for %s: %d\n",
forceUses[i], mEngine->getForceUse(i));
}
- result.appendFormat(" TTS output %savailable\n", mTtsOutputAvailable ? "" : "not ");
- result.appendFormat(" Master mono: %s\n", mMasterMono ? "on" : "off");
- result.appendFormat(" Config source: %s\n", getConfig().getSource().c_str());
- write(fd, result.string(), result.size());
-
- mAvailableOutputDevices.dump(fd, String8("Available output"));
- mAvailableInputDevices.dump(fd, String8("Available input"));
- mHwModulesAll.dump(fd);
- mOutputs.dump(fd);
- mInputs.dump(fd);
- mVolumeCurves->dump(fd);
- mEffects.dump(fd);
- mAudioPatches.dump(fd);
- mPolicyMixes.dump(fd);
- mAudioSources.dump(fd);
-
+ dst->appendFormat(" TTS output %savailable\n", mTtsOutputAvailable ? "" : "not ");
+ dst->appendFormat(" Master mono: %s\n", mMasterMono ? "on" : "off");
+ dst->appendFormat(" Config source: %s\n", mConfig.getSource().c_str()); // getConfig not const
+ mAvailableOutputDevices.dump(dst, String8("Available output"));
+ mAvailableInputDevices.dump(dst, String8("Available input"));
+ mHwModulesAll.dump(dst);
+ mOutputs.dump(dst);
+ mInputs.dump(dst);
+ mVolumeCurves->dump(dst);
+ mEffects.dump(dst);
+ mAudioPatches.dump(dst);
+ mPolicyMixes.dump(dst);
+ mAudioSources.dump(dst);
if (!mSurroundFormats.empty()) {
- result = String8("\nManually Enabled Surround Formats:\n");
+ dst->append("\nEnabled Surround Formats:\n");
size_t i = 0;
for (const auto& fmt : mSurroundFormats) {
- result.append(i++ == 0 ? " " : ", ");
+ dst->append(i++ == 0 ? " " : ", ");
std::string sfmt;
FormatConverter::toString(fmt, sfmt);
- result.appendFormat("%s", sfmt.c_str());
+ dst->append(sfmt.c_str());
}
- result.append("\n");
- write(fd, result.string(), result.size());
+ dst->append("\n");
}
+}
+status_t AudioPolicyManager::dump(int fd)
+{
+ String8 result;
+ dump(&result);
+ write(fd, result.string(), result.size());
return NO_ERROR;
}
@@ -3311,11 +3315,10 @@
SortedVector<routing_strategy> affectedStrategies;
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<AudioOutputDescriptor> outputDesc = mOutputs.valueAt(i);
- TrackClientMap clients = outputDesc->clientsMap();
- for (const auto& client : clients) {
- if (client.second->hasPreferredDevice() && client.second->uid() == uid) {
- client.second->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
- affectedStrategies.add(getStrategy(client.second->stream()));
+ for (const auto& client : outputDesc->getClientIterable()) {
+ if (client->hasPreferredDevice() && client->uid() == uid) {
+ client->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+ affectedStrategies.add(getStrategy(client->stream()));
}
}
}
@@ -3328,11 +3331,10 @@
SortedVector<audio_source_t> affectedSources;
for (size_t i = 0; i < mInputs.size(); i++) {
sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(i);
- RecordClientMap clients = inputDesc->clientsMap();
- for (const auto& client : clients) {
- if (client.second->hasPreferredDevice() && client.second->uid() == uid) {
- client.second->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
- affectedSources.add(client.second->source());
+ for (const auto& client : inputDesc->getClientIterable()) {
+ if (client->hasPreferredDevice() && client->uid() == uid) {
+ client->setPreferredDeviceId(AUDIO_PORT_HANDLE_NONE);
+ affectedSources.add(client->source());
}
}
}
@@ -3554,50 +3556,6 @@
return computeVolume(stream, index, device);
}
-status_t AudioPolicyManager::getSupportedFormats(audio_io_handle_t ioHandle,
- FormatVector& formats) {
- if (ioHandle == AUDIO_IO_HANDLE_NONE) {
- return BAD_VALUE;
- }
- String8 reply;
- reply = mpClientInterface->getParameters(
- ioHandle, String8(AudioParameter::keyStreamSupportedFormats));
- ALOGV("%s: supported formats %s", __FUNCTION__, reply.string());
- AudioParameter repliedParameters(reply);
- if (repliedParameters.get(
- String8(AudioParameter::keyStreamSupportedFormats), reply) != NO_ERROR) {
- ALOGE("%s: failed to retrieve format, bailing out", __FUNCTION__);
- return BAD_VALUE;
- }
- for (auto format : formatsFromString(reply.string())) {
- // Only AUDIO_FORMAT_AAC_LC will be used in Settings UI for all AAC formats.
- for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
- if (format == AAC_FORMATS[i]) {
- format = AUDIO_FORMAT_AAC_LC;
- break;
- }
- }
- bool exist = false;
- for (size_t i = 0; i < formats.size(); i++) {
- if (format == formats[i]) {
- exist = true;
- break;
- }
- }
- bool isSurroundFormat = false;
- for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
- if (SURROUND_FORMATS[i] == format) {
- isSurroundFormat = true;
- break;
- }
- }
- if (!exist && isSurroundFormat) {
- formats.add(format);
- }
- }
- return NO_ERROR;
-}
-
status_t AudioPolicyManager::getSurroundFormats(unsigned int *numSurroundFormats,
audio_format_t *surroundFormats,
bool *surroundFormatsEnabled,
@@ -3618,89 +3576,48 @@
size_t formatsWritten = 0;
size_t formatsMax = *numSurroundFormats;
*numSurroundFormats = 0;
- FormatVector formats;
+ std::unordered_set<audio_format_t> formats;
if (reported) {
- // Only get surround formats which are reported by device.
- // First list already open outputs that can be routed to this device
- audio_devices_t device = AUDIO_DEVICE_OUT_HDMI;
- SortedVector<audio_io_handle_t> outputs;
- bool reportedFormatFound = false;
- status_t status;
- sp<SwAudioOutputDescriptor> desc;
- for (size_t i = 0; i < mOutputs.size(); i++) {
- desc = mOutputs.valueAt(i);
- if (!desc->isDuplicated() && (desc->supportedDevices() & device)) {
- outputs.add(mOutputs.keyAt(i));
- }
- }
- // Open an output to query dynamic parameters.
- DeviceVector hdmiOutputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(
- AUDIO_DEVICE_OUT_HDMI);
- for (size_t i = 0; i < hdmiOutputDevices.size(); i++) {
- String8 address = hdmiOutputDevices[i]->mAddress;
- for (const auto& hwModule : mHwModules) {
- for (size_t i = 0; i < hwModule->getOutputProfiles().size(); i++) {
- sp<IOProfile> profile = hwModule->getOutputProfiles()[i];
- if (profile->supportDevice(AUDIO_DEVICE_OUT_HDMI) &&
- profile->supportDeviceAddress(address)) {
- size_t j;
- for (j = 0; j < outputs.size(); j++) {
- desc = mOutputs.valueFor(outputs.itemAt(j));
- if (!desc->isDuplicated() && desc->mProfile == profile) {
- break;
- }
- }
- if (j != outputs.size()) {
- status = getSupportedFormats(outputs.itemAt(j), formats);
- reportedFormatFound |= (status == NO_ERROR);
- continue;
- }
-
- if (!profile->canOpenNewIo()) {
- ALOGW("Max Output number %u already opened for this profile %s",
- profile->maxOpenCount, profile->getTagName().c_str());
- continue;
- }
-
- ALOGV("opening output for device %08x with params %s profile %p name %s",
- device, address.string(), profile.get(), profile->getName().string());
- desc = new SwAudioOutputDescriptor(profile, mpClientInterface);
- audio_io_handle_t output = AUDIO_IO_HANDLE_NONE;
- status_t status = desc->open(nullptr, device, address,
- AUDIO_STREAM_DEFAULT, AUDIO_OUTPUT_FLAG_NONE,
- &output);
-
- if (status == NO_ERROR) {
- status = getSupportedFormats(output, formats);
- reportedFormatFound |= (status == NO_ERROR);
- desc->close();
- output = AUDIO_IO_HANDLE_NONE;
- }
- }
- }
- }
- }
-
- if (!reportedFormatFound) {
- return UNKNOWN_ERROR;
+ // Return formats from HDMI profiles, that have already been resolved by
+ // checkOutputsForDevice().
+ DeviceVector hdmiOutputDevs = mAvailableOutputDevices.getDevicesFromTypeMask(
+ AUDIO_DEVICE_OUT_HDMI);
+ for (size_t i = 0; i < hdmiOutputDevs.size(); i++) {
+ FormatVector supportedFormats =
+ hdmiOutputDevs[i]->getAudioPort()->getAudioProfiles().getSupportedFormats();
+ for (size_t j = 0; j < supportedFormats.size(); j++) {
+ if (mConfig.getSurroundFormats().count(supportedFormats[j]) != 0) {
+ formats.insert(supportedFormats[j]);
+ } else {
+ for (const auto& pair : mConfig.getSurroundFormats()) {
+ if (pair.second.count(supportedFormats[j]) != 0) {
+ formats.insert(pair.first);
+ break;
+ }
+ }
+ }
+ }
}
} else {
- for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
- formats.add(SURROUND_FORMATS[i]);
+ for (const auto& pair : mConfig.getSurroundFormats()) {
+ formats.insert(pair.first);
}
}
- for (size_t i = 0; i < formats.size(); i++) {
+ for (const auto& format: formats) {
if (formatsWritten < formatsMax) {
- surroundFormats[formatsWritten] = formats[i];
+ surroundFormats[formatsWritten] = format;
bool formatEnabled = false;
- if (formats[i] == AUDIO_FORMAT_AAC_LC) {
- for (size_t j = 0; j < ARRAY_SIZE(AAC_FORMATS); j++) {
- formatEnabled =
- mSurroundFormats.find(AAC_FORMATS[i]) != mSurroundFormats.end();
- break;
+ if (mConfig.getSurroundFormats().count(format) == 0) {
+ // Check sub-formats
+ for (const auto& pair : mConfig.getSurroundFormats()) {
+ for (const auto& subformat : pair.second) {
+ formatEnabled = mSurroundFormats.count(subformat) != 0;
+ if (formatEnabled) break;
+ }
+ if (formatEnabled) break;
}
} else {
- formatEnabled = mSurroundFormats.find(formats[i]) != mSurroundFormats.end();
+ formatEnabled = mSurroundFormats.count(format) != 0;
}
surroundFormatsEnabled[formatsWritten++] = formatEnabled;
}
@@ -3713,14 +3630,8 @@
{
ALOGV("%s() format 0x%X enabled %d", __func__, audioFormat, enabled);
// Check if audio format is a surround formats.
- bool isSurroundFormat = false;
- for (size_t i = 0; i < ARRAY_SIZE(SURROUND_FORMATS); i++) {
- if (audioFormat == SURROUND_FORMATS[i]) {
- isSurroundFormat = true;
- break;
- }
- }
- if (!isSurroundFormat) {
+ const auto& formatIter = mConfig.getSurroundFormats().find(audioFormat);
+ if (formatIter == mConfig.getSurroundFormats().end()) {
ALOGW("%s() format 0x%X is not a known surround format", __func__, audioFormat);
return BAD_VALUE;
}
@@ -3733,8 +3644,7 @@
return INVALID_OPERATION;
}
- if ((mSurroundFormats.find(audioFormat) != mSurroundFormats.end() && enabled)
- || (mSurroundFormats.find(audioFormat) == mSurroundFormats.end() && !enabled)) {
+ if ((mSurroundFormats.count(audioFormat) != 0) == enabled) {
return NO_ERROR;
}
@@ -3744,21 +3654,16 @@
return INVALID_OPERATION;
}
+ std::unordered_set<audio_format_t> surroundFormatsBackup(mSurroundFormats);
if (enabled) {
- if (audioFormat == AUDIO_FORMAT_AAC_LC) {
- for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
- mSurroundFormats.insert(AAC_FORMATS[i]);
- }
- } else {
- mSurroundFormats.insert(audioFormat);
+ mSurroundFormats.insert(audioFormat);
+ for (const auto& subFormat : formatIter->second) {
+ mSurroundFormats.insert(subFormat);
}
} else {
- if (audioFormat == AUDIO_FORMAT_AAC_LC) {
- for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
- mSurroundFormats.erase(AAC_FORMATS[i]);
- }
- } else {
- mSurroundFormats.erase(audioFormat);
+ mSurroundFormats.erase(audioFormat);
+ for (const auto& subFormat : formatIter->second) {
+ mSurroundFormats.erase(subFormat);
}
}
@@ -3803,26 +3708,9 @@
profileUpdated |= (status == NO_ERROR);
}
- // Undo the surround formats change due to no audio profiles updated.
if (!profileUpdated) {
ALOGW("%s() no audio profiles updated, undoing surround formats change", __func__);
- if (enabled) {
- if (audioFormat == AUDIO_FORMAT_AAC_LC) {
- for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
- mSurroundFormats.erase(AAC_FORMATS[i]);
- }
- } else {
- mSurroundFormats.erase(audioFormat);
- }
- } else {
- if (audioFormat == AUDIO_FORMAT_AAC_LC) {
- for (size_t i = 0; i < ARRAY_SIZE(AAC_FORMATS); i++) {
- mSurroundFormats.insert(AAC_FORMATS[i]);
- }
- } else {
- mSurroundFormats.insert(audioFormat);
- }
- }
+ mSurroundFormats = std::move(surroundFormatsBackup);
}
return profileUpdated ? NO_ERROR : INVALID_OPERATION;
@@ -3921,10 +3809,9 @@
for (const char* fileName : fileNames) {
for (int i = 0; i < kConfigLocationListSize; i++) {
- PolicySerializer serializer;
snprintf(audioPolicyXmlConfigFile, sizeof(audioPolicyXmlConfigFile),
"%s/%s", kConfigLocationList[i], fileName);
- ret = serializer.deserialize(audioPolicyXmlConfigFile, config);
+ ret = deserializeAudioPolicyFile(audioPolicyXmlConfigFile, &config);
if (ret == NO_ERROR) {
config.setSource(audioPolicyXmlConfigFile);
return ret;
@@ -4633,10 +4520,9 @@
// and as they were also referenced on the other output, the reference
// count for their stream type must be adjusted accordingly on
// the other output.
- bool wasActive = outputDesc2->isActive();
- for (int j = 0; j < AUDIO_STREAM_CNT; j++) {
- int activeCount = dupOutputDesc->streamActiveCount((audio_stream_type_t)j);
- outputDesc2->changeStreamActiveCount((audio_stream_type_t)j,-activeCount);
+ const bool wasActive = outputDesc2->isActive();
+ for (const auto &clientPair : dupOutputDesc->getActiveClients()) {
+ outputDesc2->changeStreamActiveCount(clientPair.first, -clientPair.second);
}
// stop() will be a no op if the output is still active but is needed in case all
// active streams refcounts where cleared above
@@ -4665,6 +4551,22 @@
removeOutput(output);
mPreviousOutputs = mOutputs;
+
+ // MSD patches may have been released to support a non-MSD direct output. Reset MSD patch if
+ // no direct outputs are open.
+ if (getMsdAudioOutDeviceTypes() != AUDIO_DEVICE_NONE) {
+ bool directOutputOpen = false;
+ for (size_t i = 0; i < mOutputs.size(); i++) {
+ if (mOutputs[i]->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
+ directOutputOpen = true;
+ break;
+ }
+ }
+ if (!directOutputOpen) {
+ ALOGV("no direct outputs open, reset MSD patch");
+ setMsdPatch();
+ }
+ }
}
void AudioPolicyManager::closeInput(audio_io_handle_t input)
@@ -5995,6 +5897,7 @@
case AUDIO_FORMAT_DOLBY_TRUEHD:
case AUDIO_FORMAT_E_AC3_JOC:
mSurroundFormats.insert(format);
+ break;
default:
break;
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 6f4cce1..f559b7f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -186,7 +186,9 @@
virtual bool isSourceActive(audio_source_t source) const;
- virtual status_t dump(int fd);
+ void dump(String8 *dst) const; // helper for dump(int fd)
+
+ status_t dump(int fd) override;
virtual bool isOffloadSupported(const audio_offload_info_t& offloadInfo);
@@ -613,8 +615,6 @@
void filterSurroundFormats(FormatVector *formatsPtr);
void filterSurroundChannelMasks(ChannelsVector *channelMasksPtr);
- status_t getSupportedFormats(audio_io_handle_t ioHandle, FormatVector& formats);
-
// Support for Multi-Stream Decoder (MSD) module
sp<DeviceDescriptor> getMsdAudioInDevice() const;
audio_devices_t getMsdAudioOutDeviceTypes() const;
diff --git a/services/audiopolicy/service/AudioPolicyService.cpp b/services/audiopolicy/service/AudioPolicyService.cpp
index 8bca221..b1ed522 100644
--- a/services/audiopolicy/service/AudioPolicyService.cpp
+++ b/services/audiopolicy/service/AudioPolicyService.cpp
@@ -677,21 +677,27 @@
VolumeData *data = (VolumeData *)command->mParam.get();
ALOGV("AudioCommandThread() processing set volume stream %d, \
volume %f, output %d", data->mStream, data->mVolume, data->mIO);
+ mLock.unlock();
command->mStatus = AudioSystem::setStreamVolume(data->mStream,
data->mVolume,
data->mIO);
+ mLock.lock();
}break;
case SET_PARAMETERS: {
ParametersData *data = (ParametersData *)command->mParam.get();
ALOGV("AudioCommandThread() processing set parameters string %s, io %d",
data->mKeyValuePairs.string(), data->mIO);
+ mLock.unlock();
command->mStatus = AudioSystem::setParameters(data->mIO, data->mKeyValuePairs);
+ mLock.lock();
}break;
case SET_VOICE_VOLUME: {
VoiceVolumeData *data = (VoiceVolumeData *)command->mParam.get();
ALOGV("AudioCommandThread() processing set voice volume volume %f",
data->mVolume);
+ mLock.unlock();
command->mStatus = AudioSystem::setVoiceVolume(data->mVolume);
+ mLock.lock();
}break;
case STOP_OUTPUT: {
StopOutputData *data = (StopOutputData *)command->mParam.get();
@@ -724,7 +730,9 @@
if (af == 0) {
command->mStatus = PERMISSION_DENIED;
} else {
+ mLock.unlock();
command->mStatus = af->createAudioPatch(&data->mPatch, &data->mHandle);
+ mLock.lock();
}
} break;
case RELEASE_AUDIO_PATCH: {
@@ -734,7 +742,9 @@
if (af == 0) {
command->mStatus = PERMISSION_DENIED;
} else {
+ mLock.unlock();
command->mStatus = af->releaseAudioPatch(data->mHandle);
+ mLock.lock();
}
} break;
case UPDATE_AUDIOPORT_LIST: {
@@ -764,7 +774,9 @@
if (af == 0) {
command->mStatus = PERMISSION_DENIED;
} else {
+ mLock.unlock();
command->mStatus = af->setAudioPortConfig(&data->mConfig);
+ mLock.lock();
}
} break;
case DYN_POLICY_MIX_STATE_UPDATE: {
diff --git a/services/audiopolicy/tests/Android.mk b/services/audiopolicy/tests/Android.mk
index b739b88..513312e 100644
--- a/services/audiopolicy/tests/Android.mk
+++ b/services/audiopolicy/tests/Android.mk
@@ -6,6 +6,7 @@
frameworks/av/services/audiopolicy \
frameworks/av/services/audiopolicy/common/include \
frameworks/av/services/audiopolicy/engine/interface \
+ $(call include-path-for, audio-utils) \
LOCAL_SHARED_LIBRARIES := \
libaudiopolicymanagerdefault \
diff --git a/services/camera/libcameraservice/Android.bp b/services/camera/libcameraservice/Android.bp
index 706ce3a..a1163ed 100644
--- a/services/camera/libcameraservice/Android.bp
+++ b/services/camera/libcameraservice/Android.bp
@@ -52,6 +52,7 @@
"device3/Camera3StreamSplitter.cpp",
"device3/DistortionMapper.cpp",
"gui/RingBufferConsumer.cpp",
+ "utils/CameraThreadState.cpp",
"utils/CameraTraces.cpp",
"utils/AutoConditionLock.cpp",
"utils/TagMonitor.cpp",
@@ -72,6 +73,7 @@
"libfmq",
"libgui",
"libhardware",
+ "libhwbinder",
"libhidlbase",
"libhidltransport",
"libjpeg",
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index fbd80e6..e69ce1f 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -69,6 +69,7 @@
#include "api2/CameraDeviceClient.h"
#include "utils/CameraTraces.h"
#include "utils/TagMonitor.h"
+#include "utils/CameraThreadState.h"
namespace {
const char* kPermissionServiceName = "permission";
@@ -325,7 +326,7 @@
hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISCONNECTED,
CaptureResultExtras{});
// Ensure not in binder RPC so client disconnect PID checks work correctly
- LOG_ALWAYS_FATAL_IF(getCallingPid() != getpid(),
+ LOG_ALWAYS_FATAL_IF(CameraThreadState::getCallingPid() != getpid(),
"onDeviceStatusChanged must be called from the camera service process!");
clientToDisconnect->disconnect();
}
@@ -491,8 +492,8 @@
strerror(-res), res);
}
- int callingPid = getCallingPid();
- int callingUid = getCallingUid();
+ int callingPid = CameraThreadState::getCallingPid();
+ int callingUid = CameraThreadState::getCallingUid();
std::vector<int32_t> tagsRemoved;
// If it's not calling from cameraserver, check the permission.
if ((callingPid != getpid()) &&
@@ -522,14 +523,6 @@
return ret;
}
-int CameraService::getCallingPid() {
- return IPCThreadState::self()->getCallingPid();
-}
-
-int CameraService::getCallingUid() {
- return IPCThreadState::self()->getCallingUid();
-}
-
String8 CameraService::getFormattedCurrentTime() {
time_t now = time(nullptr);
char formattedTime[64];
@@ -754,7 +747,7 @@
}
Status CameraService::initializeShimMetadata(int cameraId) {
- int uid = getCallingUid();
+ int uid = CameraThreadState::getCallingUid();
String16 internalPackageName("cameraserver");
String8 id = String8::format("%d", cameraId);
@@ -803,9 +796,9 @@
}
}
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ int64_t token = CameraThreadState::clearCallingIdentity();
ret = initializeShimMetadata(cameraId);
- IPCThreadState::self()->restoreCallingIdentity(token);
+ CameraThreadState::restoreCallingIdentity(token);
if (!ret.isOk()) {
// Error already logged by callee
return ret;
@@ -862,7 +855,7 @@
}
#endif // __BRILLO__
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
if (!mInitialized) {
ALOGE("CameraService::connect X (PID %d) rejected (camera HAL module not loaded)",
@@ -896,8 +889,8 @@
Status CameraService::validateClientPermissionsLocked(const String8& cameraId,
const String8& clientName8, int& clientUid, int& clientPid,
/*out*/int& originalClientPid) const {
- int callingPid = getCallingPid();
- int callingUid = getCallingUid();
+ int callingPid = CameraThreadState::getCallingPid();
+ int callingUid = CameraThreadState::getCallingUid();
// Check if we can trust clientUid
if (clientUid == USE_CALLING_UID) {
@@ -966,7 +959,7 @@
status_t CameraService::checkIfDeviceIsUsable(const String8& cameraId) const {
auto cameraState = getCameraState(cameraId);
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
if (cameraState == nullptr) {
ALOGE("CameraService::connect X (PID %d) rejected (invalid camera ID %s)", callingPid,
cameraId.string());
@@ -1170,7 +1163,7 @@
mServiceLock.unlock();
// Clear caller identity temporarily so client disconnect PID checks work correctly
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ int64_t token = CameraThreadState::clearCallingIdentity();
// Destroy evicted clients
for (auto& i : evictedClients) {
@@ -1178,7 +1171,7 @@
i->getValue()->disconnect(); // Clients will remove themselves from the active client list
}
- IPCThreadState::self()->restoreCallingIdentity(token);
+ CameraThreadState::restoreCallingIdentity(token);
for (const auto& i : evictedClients) {
ALOGV("%s: Waiting for disconnect to complete for client for device %s (PID %" PRId32 ")",
@@ -1231,7 +1224,7 @@
/*shimUpdateOnly*/ false, /*out*/client);
if(!ret.isOk()) {
- logRejected(id, getCallingPid(), String8(clientPackageName),
+ logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
ret.toString8());
return ret;
}
@@ -1258,7 +1251,7 @@
/*out*/client);
if(!ret.isOk()) {
- logRejected(id, getCallingPid(), String8(clientPackageName),
+ logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
ret.toString8());
return ret;
}
@@ -1285,7 +1278,7 @@
clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, /*out*/client);
if(!ret.isOk()) {
- logRejected(id, getCallingPid(), String8(clientPackageName),
+ logRejected(id, CameraThreadState::getCallingPid(), String8(clientPackageName),
ret.toString8());
return ret;
}
@@ -1466,7 +1459,7 @@
}
String8 id = String8(cameraId.string());
- int uid = getCallingUid();
+ int uid = CameraThreadState::getCallingUid();
// verify id is valid.
auto state = getCameraState(id);
@@ -1913,13 +1906,13 @@
mServiceLock.unlock();
// Clear caller identity temporarily so client disconnect PID checks work correctly
- int64_t token = IPCThreadState::self()->clearCallingIdentity();
+ int64_t token = CameraThreadState::clearCallingIdentity();
for (auto& i : evicted) {
i->disconnect();
}
- IPCThreadState::self()->restoreCallingIdentity(token);
+ CameraThreadState::restoreCallingIdentity(token);
// Reacquire mServiceLock
mServiceLock.lock();
@@ -1987,7 +1980,7 @@
status_t CameraService::onTransact(uint32_t code, const Parcel& data, Parcel* reply,
uint32_t flags) {
- const int pid = getCallingPid();
+ const int pid = CameraThreadState::getCallingPid();
const int selfPid = getpid();
// Permission checks
@@ -2022,7 +2015,7 @@
// permissions to notify the camera service about system events
if (!checkCallingPermission(
String16("android.permission.CAMERA_SEND_SYSTEM_EVENTS"))) {
- const int uid = getCallingUid();
+ const int uid = CameraThreadState::getCallingUid();
ALOGE("Permission Denial: cannot send updates to camera service about system"
" events from pid=%d, uid=%d", pid, uid);
return PERMISSION_DENIED;
@@ -2119,7 +2112,7 @@
servicePid),
mCameraId(api1CameraId)
{
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
LOG1("Client::Client E (pid %d, id %d)", callingPid, mCameraId);
mRemoteCallback = cameraClient;
@@ -2228,7 +2221,7 @@
// No dumping of clients directly over Binder,
// must go through CameraService::dump
android_errorWriteWithInfoLog(SN_EVENT_LOG_ID, "26265403",
- IPCThreadState::self()->getCallingUid(), NULL, 0);
+ CameraThreadState::getCallingUid(), NULL, 0);
return OK;
}
@@ -2365,7 +2358,7 @@
// Reset the client PID to allow server-initiated disconnect,
// and to prevent further calls by client.
- mClientPid = getCallingPid();
+ mClientPid = CameraThreadState::getCallingPid();
CaptureResultExtras resultExtras; // a dummy result (invalid)
notifyError(hardware::camera2::ICameraDeviceCallbacks::ERROR_CAMERA_DISABLED, resultExtras);
disconnect();
@@ -2726,8 +2719,8 @@
if (checkCallingPermission(String16("android.permission.DUMP")) == false) {
dprintf(fd, "Permission Denial: can't dump CameraService from pid=%d, uid=%d\n",
- getCallingPid(),
- getCallingUid());
+ CameraThreadState::getCallingPid(),
+ CameraThreadState::getCallingUid());
return NO_ERROR;
}
bool locked = tryLock(mServiceLock);
@@ -2900,7 +2893,7 @@
* binder driver
*/
// PID here is approximate and can be wrong.
- logClientDied(getCallingPid(), String8("Binder died unexpectedly"));
+ logClientDied(CameraThreadState::getCallingPid(), String8("Binder died unexpectedly"));
// check torch client
handleTorchClientBinderDied(who);
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 47ad8af..80d9ef4 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -836,10 +836,6 @@
// Prints the shell command help
status_t printHelp(int out);
- static int getCallingPid();
-
- static int getCallingUid();
-
/**
* Get the current system time as a formatted string.
*/
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index bf18c48..c250628 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -33,6 +33,7 @@
#include "api1/client2/CaptureSequencer.h"
#include "api1/client2/CallbackProcessor.h"
#include "api1/client2/ZslProcessor.h"
+#include "utils/CameraThreadState.h"
#define ALOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
#define ALOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
@@ -40,10 +41,6 @@
namespace android {
using namespace camera2;
-static int getCallingPid() {
- return IPCThreadState::self()->getCallingPid();
-}
-
// Interface used by CameraService
Camera2Client::Camera2Client(const sp<CameraService>& cameraService,
@@ -398,7 +395,7 @@
binder::Status res = binder::Status::ok();
// Allow both client and the cameraserver to disconnect at all times
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
if (callingPid != mClientPid && callingPid != mServicePid) return res;
if (mDevice == 0) return res;
@@ -463,14 +460,14 @@
ALOGV("%s: E", __FUNCTION__);
Mutex::Autolock icl(mBinderSerializationLock);
- if (mClientPid != 0 && getCallingPid() != mClientPid) {
+ if (mClientPid != 0 && CameraThreadState::getCallingPid() != mClientPid) {
ALOGE("%s: Camera %d: Connection attempt from pid %d; "
"current locked to pid %d", __FUNCTION__,
- mCameraId, getCallingPid(), mClientPid);
+ mCameraId, CameraThreadState::getCallingPid(), mClientPid);
return BAD_VALUE;
}
- mClientPid = getCallingPid();
+ mClientPid = CameraThreadState::getCallingPid();
mRemoteCallback = client;
mSharedCameraCallbacks = client;
@@ -483,16 +480,16 @@
ALOGV("%s: E", __FUNCTION__);
Mutex::Autolock icl(mBinderSerializationLock);
ALOGV("%s: Camera %d: Lock call from pid %d; current client pid %d",
- __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+ __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
if (mClientPid == 0) {
- mClientPid = getCallingPid();
+ mClientPid = CameraThreadState::getCallingPid();
return OK;
}
- if (mClientPid != getCallingPid()) {
+ if (mClientPid != CameraThreadState::getCallingPid()) {
ALOGE("%s: Camera %d: Lock call from pid %d; currently locked to pid %d",
- __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+ __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
return EBUSY;
}
@@ -504,9 +501,9 @@
ALOGV("%s: E", __FUNCTION__);
Mutex::Autolock icl(mBinderSerializationLock);
ALOGV("%s: Camera %d: Unlock call from pid %d; current client pid %d",
- __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+ __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
- if (mClientPid == getCallingPid()) {
+ if (mClientPid == CameraThreadState::getCallingPid()) {
SharedParameters::Lock l(mParameters);
if (l.mParameters.state == Parameters::RECORD ||
l.mParameters.state == Parameters::VIDEO_SNAPSHOT) {
@@ -520,7 +517,7 @@
}
ALOGE("%s: Camera %d: Unlock call from pid %d; currently locked to pid %d",
- __FUNCTION__, mCameraId, getCallingPid(), mClientPid);
+ __FUNCTION__, mCameraId, CameraThreadState::getCallingPid(), mClientPid);
return EBUSY;
}
@@ -1574,7 +1571,7 @@
ALOGV("%s: Camera %d", __FUNCTION__, mCameraId);
Mutex::Autolock icl(mBinderSerializationLock);
// The camera service can unconditionally get the parameters at all times
- if (getCallingPid() != mServicePid && checkPid(__FUNCTION__) != OK) return String8();
+ if (CameraThreadState::getCallingPid() != mServicePid && checkPid(__FUNCTION__) != OK) return String8();
SharedParameters::ReadLock l(mParameters);
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index ce44efe..d65ac7b 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -25,16 +25,13 @@
#include "api1/CameraClient.h"
#include "device1/CameraHardwareInterface.h"
#include "CameraService.h"
+#include "utils/CameraThreadState.h"
namespace android {
#define LOG1(...) ALOGD_IF(gLogLevel >= 1, __VA_ARGS__);
#define LOG2(...) ALOGD_IF(gLogLevel >= 2, __VA_ARGS__);
-static int getCallingPid() {
- return IPCThreadState::self()->getCallingPid();
-}
-
CameraClient::CameraClient(const sp<CameraService>& cameraService,
const sp<hardware::ICameraClient>& cameraClient,
const String16& clientPackageName,
@@ -45,7 +42,7 @@
String8::format("%d", cameraId), cameraId, cameraFacing, clientPid,
clientUid, servicePid)
{
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
LOG1("CameraClient::CameraClient E (pid %d, id %d)", callingPid, cameraId);
mHardware = NULL;
@@ -63,7 +60,7 @@
status_t CameraClient::initialize(sp<CameraProviderManager> manager,
const String8& /*monitorTags*/) {
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
status_t res;
LOG1("CameraClient::initialize E (pid %d, id %d)", callingPid, mCameraId);
@@ -104,7 +101,7 @@
// tear down the client
CameraClient::~CameraClient() {
mDestructionStarted = true;
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
LOG1("CameraClient::~CameraClient E (pid %d, this %p)", callingPid, this);
disconnect();
@@ -147,7 +144,7 @@
// ----------------------------------------------------------------------------
status_t CameraClient::checkPid() const {
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
if (callingPid == mClientPid) return NO_ERROR;
ALOGW("attempt to use a locked camera from a different process"
@@ -157,7 +154,8 @@
status_t CameraClient::checkPidAndHardware() const {
if (mHardware == 0) {
- ALOGE("attempt to use a camera after disconnect() (pid %d)", getCallingPid());
+ ALOGE("attempt to use a camera after disconnect() (pid %d)",
+ CameraThreadState::getCallingPid());
return INVALID_OPERATION;
}
status_t result = checkPid();
@@ -166,7 +164,7 @@
}
status_t CameraClient::lock() {
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
LOG1("lock (pid %d)", callingPid);
Mutex::Autolock lock(mLock);
@@ -181,7 +179,7 @@
}
status_t CameraClient::unlock() {
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
LOG1("unlock (pid %d)", callingPid);
Mutex::Autolock lock(mLock);
@@ -203,7 +201,7 @@
// connect a new client to the camera
status_t CameraClient::connect(const sp<hardware::ICameraClient>& client) {
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
LOG1("connect E (pid %d)", callingPid);
Mutex::Autolock lock(mLock);
@@ -239,7 +237,7 @@
}
binder::Status CameraClient::disconnect() {
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
LOG1("disconnect E (pid %d)", callingPid);
Mutex::Autolock lock(mLock);
@@ -333,7 +331,7 @@
status_t CameraClient::setPreviewTarget(
const sp<IGraphicBufferProducer>& bufferProducer) {
LOG1("setPreviewTarget(%p) (pid %d)", bufferProducer.get(),
- getCallingPid());
+ CameraThreadState::getCallingPid());
sp<IBinder> binder;
sp<ANativeWindow> window;
@@ -350,7 +348,7 @@
// set the preview callback flag to affect how the received frames from
// preview are handled.
void CameraClient::setPreviewCallbackFlag(int callback_flag) {
- LOG1("setPreviewCallbackFlag(%d) (pid %d)", callback_flag, getCallingPid());
+ LOG1("setPreviewCallbackFlag(%d) (pid %d)", callback_flag, CameraThreadState::getCallingPid());
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return;
@@ -371,13 +369,13 @@
// start preview mode
status_t CameraClient::startPreview() {
- LOG1("startPreview (pid %d)", getCallingPid());
+ LOG1("startPreview (pid %d)", CameraThreadState::getCallingPid());
return startCameraMode(CAMERA_PREVIEW_MODE);
}
// start recording mode
status_t CameraClient::startRecording() {
- LOG1("startRecording (pid %d)", getCallingPid());
+ LOG1("startRecording (pid %d)", CameraThreadState::getCallingPid());
return startCameraMode(CAMERA_RECORDING_MODE);
}
@@ -460,7 +458,7 @@
// stop preview mode
void CameraClient::stopPreview() {
- LOG1("stopPreview (pid %d)", getCallingPid());
+ LOG1("stopPreview (pid %d)", CameraThreadState::getCallingPid());
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return;
@@ -476,7 +474,7 @@
// stop recording mode
void CameraClient::stopRecording() {
- LOG1("stopRecording (pid %d)", getCallingPid());
+ LOG1("stopRecording (pid %d)", CameraThreadState::getCallingPid());
{
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return;
@@ -502,7 +500,7 @@
if (checkPidAndHardware() != NO_ERROR) return;
if (mem == nullptr) {
android_errorWriteWithInfoLog(CameraService::SN_EVENT_LOG_ID, "26164272",
- IPCThreadState::self()->getCallingUid(), nullptr, 0);
+ CameraThreadState::getCallingUid(), nullptr, 0);
return;
}
@@ -614,7 +612,7 @@
}
bool CameraClient::previewEnabled() {
- LOG1("previewEnabled (pid %d)", getCallingPid());
+ LOG1("previewEnabled (pid %d)", CameraThreadState::getCallingPid());
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return false;
@@ -622,7 +620,7 @@
}
bool CameraClient::recordingEnabled() {
- LOG1("recordingEnabled (pid %d)", getCallingPid());
+ LOG1("recordingEnabled (pid %d)", CameraThreadState::getCallingPid());
Mutex::Autolock lock(mLock);
if (checkPidAndHardware() != NO_ERROR) return false;
@@ -630,7 +628,7 @@
}
status_t CameraClient::autoFocus() {
- LOG1("autoFocus (pid %d)", getCallingPid());
+ LOG1("autoFocus (pid %d)", CameraThreadState::getCallingPid());
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
@@ -640,7 +638,7 @@
}
status_t CameraClient::cancelAutoFocus() {
- LOG1("cancelAutoFocus (pid %d)", getCallingPid());
+ LOG1("cancelAutoFocus (pid %d)", CameraThreadState::getCallingPid());
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
@@ -651,7 +649,7 @@
// take a picture - image is returned in callback
status_t CameraClient::takePicture(int msgType) {
- LOG1("takePicture (pid %d): 0x%x", getCallingPid(), msgType);
+ LOG1("takePicture (pid %d): 0x%x", CameraThreadState::getCallingPid(), msgType);
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
@@ -680,7 +678,7 @@
// set preview/capture parameters - key/value pairs
status_t CameraClient::setParameters(const String8& params) {
- LOG1("setParameters (pid %d) (%s)", getCallingPid(), params.string());
+ LOG1("setParameters (pid %d) (%s)", CameraThreadState::getCallingPid(), params.string());
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
@@ -695,16 +693,18 @@
String8 CameraClient::getParameters() const {
Mutex::Autolock lock(mLock);
// The camera service can unconditionally get the parameters at all times
- if (getCallingPid() != mServicePid && checkPidAndHardware() != NO_ERROR) return String8();
+ if (CameraThreadState::getCallingPid() != mServicePid && checkPidAndHardware() != NO_ERROR) {
+ return String8();
+ }
String8 params(mHardware->getParameters().flatten());
- LOG1("getParameters (pid %d) (%s)", getCallingPid(), params.string());
+ LOG1("getParameters (pid %d) (%s)", CameraThreadState::getCallingPid(), params.string());
return params;
}
// enable shutter sound
status_t CameraClient::enableShutterSound(bool enable) {
- LOG1("enableShutterSound (pid %d)", getCallingPid());
+ LOG1("enableShutterSound (pid %d)", CameraThreadState::getCallingPid());
status_t result = checkPidAndHardware();
if (result != NO_ERROR) return result;
@@ -719,7 +719,7 @@
}
status_t CameraClient::sendCommand(int32_t cmd, int32_t arg1, int32_t arg2) {
- LOG1("sendCommand (pid %d)", getCallingPid());
+ LOG1("sendCommand (pid %d)", CameraThreadState::getCallingPid());
int orientation;
Mutex::Autolock lock(mLock);
status_t result = checkPidAndHardware();
diff --git a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
index b9e07f3..6da05c3 100644
--- a/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
+++ b/services/camera/libcameraservice/api2/CameraDeviceClient.cpp
@@ -19,6 +19,7 @@
//#define LOG_NDEBUG 0
#include <cutils/properties.h>
+#include <utils/CameraThreadState.h>
#include <utils/Log.h>
#include <utils/Trace.h>
#include <gui/Surface.h>
@@ -1724,7 +1725,7 @@
// TODO: move to Camera2ClientBase
bool CameraDeviceClient::enforceRequestPermissions(CameraMetadata& metadata) {
- const int pid = IPCThreadState::self()->getCallingPid();
+ const int pid = CameraThreadState::getCallingPid();
const int selfPid = getpid();
camera_metadata_entry_t entry;
@@ -1763,7 +1764,7 @@
String16 permissionString =
String16("android.permission.CAMERA_DISABLE_TRANSMIT_LED");
if (!checkCallingPermission(permissionString)) {
- const int uid = IPCThreadState::self()->getCallingUid();
+ const int uid = CameraThreadState::getCallingUid();
ALOGE("Permission Denial: "
"can't disable transmit LED pid=%d, uid=%d", pid, uid);
return false;
diff --git a/services/camera/libcameraservice/common/Camera2ClientBase.cpp b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
index aeea473..78feb3e 100644
--- a/services/camera/libcameraservice/common/Camera2ClientBase.cpp
+++ b/services/camera/libcameraservice/common/Camera2ClientBase.cpp
@@ -32,14 +32,11 @@
#include "api2/CameraDeviceClient.h"
#include "device3/Camera3Device.h"
+#include "utils/CameraThreadState.h"
namespace android {
using namespace camera2;
-static int getCallingPid() {
- return IPCThreadState::self()->getCallingPid();
-}
-
// Interface used by CameraService
template <typename TClientBase>
@@ -71,7 +68,7 @@
status_t Camera2ClientBase<TClientBase>::checkPid(const char* checkLocation)
const {
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
if (callingPid == TClientBase::mClientPid) return NO_ERROR;
ALOGE("%s: attempt to use a locked camera from a different process"
@@ -186,7 +183,7 @@
binder::Status res = binder::Status::ok();
// Allow both client and the media server to disconnect at all times
- int callingPid = getCallingPid();
+ int callingPid = CameraThreadState::getCallingPid();
if (callingPid != TClientBase::mClientPid &&
callingPid != TClientBase::mServicePid) return res;
@@ -217,18 +214,18 @@
Mutex::Autolock icl(mBinderSerializationLock);
if (TClientBase::mClientPid != 0 &&
- getCallingPid() != TClientBase::mClientPid) {
+ CameraThreadState::getCallingPid() != TClientBase::mClientPid) {
ALOGE("%s: Camera %s: Connection attempt from pid %d; "
"current locked to pid %d",
__FUNCTION__,
TClientBase::mCameraIdStr.string(),
- getCallingPid(),
+ CameraThreadState::getCallingPid(),
TClientBase::mClientPid);
return BAD_VALUE;
}
- TClientBase::mClientPid = getCallingPid();
+ TClientBase::mClientPid = CameraThreadState::getCallingPid();
TClientBase::mRemoteCallback = client;
mSharedCameraCallbacks = client;
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 664e7dc..b8c80c8 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -56,6 +56,7 @@
#include "device3/Camera3DummyStream.h"
#include "device3/Camera3SharedOutputStream.h"
#include "CameraService.h"
+#include "utils/CameraThreadState.h"
using namespace android::camera3;
using namespace android::hardware::camera;
@@ -281,7 +282,6 @@
status_t Camera3Device::disconnectImpl() {
ATRACE_CALL();
Mutex::Autolock il(mInterfaceLock);
- Mutex::Autolock stLock(mTrackerLock);
ALOGI("%s: E", __FUNCTION__);
@@ -346,6 +346,7 @@
{
Mutex::Autolock l(mLock);
mRequestThread.clear();
+ Mutex::Autolock stLock(mTrackerLock);
mStatusTracker.clear();
interface = mInterface.get();
}
@@ -1701,7 +1702,7 @@
if (templateId <= 0 || templateId >= CAMERA3_TEMPLATE_COUNT) {
android_errorWriteWithInfoLog(CameraService::SN_EVENT_LOG_ID, "26866110",
- IPCThreadState::self()->getCallingUid(), nullptr, 0);
+ CameraThreadState::getCallingUid(), nullptr, 0);
return BAD_VALUE;
}
@@ -2014,6 +2015,13 @@
{
Mutex::Autolock l(mLock);
+
+ // b/116514106 "disconnect()" can get called twice for the same device. The
+ // camera device will not be initialized during the second run.
+ if (mStatus == STATUS_UNINITIALIZED) {
+ return OK;
+ }
+
mRequestThread->clear(/*out*/frameNumber);
}
diff --git a/services/camera/libcameraservice/utils/CameraThreadState.cpp b/services/camera/libcameraservice/utils/CameraThreadState.cpp
new file mode 100644
index 0000000..b9e344b
--- /dev/null
+++ b/services/camera/libcameraservice/utils/CameraThreadState.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include "CameraThreadState.h"
+#include <binder/IPCThreadState.h>
+#include <hwbinder/IPCThreadState.h>
+#include <unistd.h>
+
+namespace android {
+
+int CameraThreadState::getCallingUid() {
+ if (hardware::IPCThreadState::self()->isServingCall()) {
+ return hardware::IPCThreadState::self()->getCallingUid();
+ }
+ return IPCThreadState::self()->getCallingUid();
+}
+
+int CameraThreadState::getCallingPid() {
+ if (hardware::IPCThreadState::self()->isServingCall()) {
+ return hardware::IPCThreadState::self()->getCallingPid();
+ }
+ return IPCThreadState::self()->getCallingPid();
+}
+
+int64_t CameraThreadState::clearCallingIdentity() {
+ if (hardware::IPCThreadState::self()->isServingCall()) {
+ return hardware::IPCThreadState::self()->clearCallingIdentity();
+ }
+ return IPCThreadState::self()->clearCallingIdentity();
+}
+
+void CameraThreadState::restoreCallingIdentity(int64_t token) {
+ if (hardware::IPCThreadState::self()->isServingCall()) {
+ hardware::IPCThreadState::self()->restoreCallingIdentity(token);
+ } else {
+ IPCThreadState::self()->restoreCallingIdentity(token);
+ }
+ return;
+}
+
+} // android
diff --git a/services/camera/libcameraservice/utils/CameraThreadState.h b/services/camera/libcameraservice/utils/CameraThreadState.h
new file mode 100644
index 0000000..e1a70de
--- /dev/null
+++ b/services/camera/libcameraservice/utils/CameraThreadState.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2018 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.
+ */
+
+#include <stdint.h>
+
+namespace android {
+class CameraThreadState {
+public:
+ static int64_t clearCallingIdentity();
+
+ static void restoreCallingIdentity(int64_t token);
+
+ static int getCallingUid();
+
+ static int getCallingPid();
+};
+
+} // android
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index 45da56a..ae832ba 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -26,6 +26,7 @@
#include <sys/stat.h>
#include <sys/time.h>
#include <dirent.h>
+#include <pthread.h>
#include <unistd.h>
#include <string.h>
@@ -80,11 +81,18 @@
using namespace android::content::pm;
// individual records kept in memory: age or count
-// age: <= 36 hours (1.5 days)
+// age: <= 28 hours (1 1/6 days)
// count: hard limit of # records
// (0 for either of these disables that threshold)
-static const nsecs_t kMaxRecordAgeNs = 36 * 3600 * (1000*1000*1000ll);
-static const int kMaxRecords = 0;
+//
+static constexpr nsecs_t kMaxRecordAgeNs = 28 * 3600 * (1000*1000*1000ll);
+static constexpr int kMaxRecords = 0;
+
+// max we expire in a single call, to constrain how long we hold the
+// mutex, which also constrains how long a client might wait.
+static constexpr int kMaxExpiredAtOnce = 50;
+
+// TODO: need to look at tuning kMaxRecords and friends for low-memory devices
static const char *kServiceName = "media.metrics";
@@ -96,6 +104,7 @@
MediaAnalyticsService::MediaAnalyticsService()
: mMaxRecords(kMaxRecords),
mMaxRecordAgeNs(kMaxRecordAgeNs),
+ mMaxRecordsExpiredAtOnce(kMaxExpiredAtOnce),
mDumpProto(MediaAnalyticsItem::PROTO_V1),
mDumpProtoDefault(MediaAnalyticsItem::PROTO_V1) {
@@ -432,23 +441,29 @@
//
// Our Cheap in-core, non-persistent records management.
-// insert appropriately into queue
-void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
+
+// we hold mLock when we get here
+// if item != NULL, it's the item we just inserted
+// true == more items eligible to be recovered
+bool MediaAnalyticsService::expirations_l(MediaAnalyticsItem *item)
{
-
- Mutex::Autolock _l(mLock);
- // mutex between insertion and dumping the contents
-
- // we want to dump 'in FIFO order', so insert at the end
- mItems.push_back(item);
+ bool more = false;
+ int handled = 0;
// keep removing old records the front until we're in-bounds (count)
+ // since we invoke this with each insertion, it should be 0/1 iterations.
if (mMaxRecords > 0) {
while (mItems.size() > (size_t) mMaxRecords) {
MediaAnalyticsItem * oitem = *(mItems.begin());
if (oitem == item) {
break;
}
+ if (handled >= mMaxRecordsExpiredAtOnce) {
+ // unlikely in this loop
+ more = true;
+ break;
+ }
+ handled++;
mItems.erase(mItems.begin());
delete oitem;
mItemsDiscarded++;
@@ -456,8 +471,8 @@
}
}
- // keep removing old records the front until we're in-bounds (count)
- // NB: expired entries aren't removed until the next insertion, which could be a while
+ // keep removing old records the front until we're in-bounds (age)
+ // limited to mMaxRecordsExpiredAtOnce items per invocation.
if (mMaxRecordAgeNs > 0) {
nsecs_t now = systemTime(SYSTEM_TIME_REALTIME);
while (mItems.size() > 0) {
@@ -471,12 +486,65 @@
// this (and the rest) are recent enough to keep
break;
}
+ if (handled >= mMaxRecordsExpiredAtOnce) {
+ // this represents "one too many"; tell caller there are
+ // more to be reclaimed.
+ more = true;
+ break;
+ }
+ handled++;
mItems.erase(mItems.begin());
delete oitem;
mItemsDiscarded++;
mItemsDiscardedExpire++;
}
}
+
+ // we only indicate whether there's more to clean;
+ // caller chooses whether to schedule further cleanup.
+ return more;
+}
+
+// process expirations in bite sized chunks, allowing new insertions through
+// runs in a pthread specifically started for this (which then exits)
+bool MediaAnalyticsService::processExpirations()
+{
+ bool more;
+ do {
+ sleep(1);
+ {
+ Mutex::Autolock _l(mLock);
+ more = expirations_l(NULL);
+ if (!more) {
+ break;
+ }
+ }
+ } while (more);
+ return true; // value is for std::future thread synchronization
+}
+
+// insert appropriately into queue
+void MediaAnalyticsService::saveItem(MediaAnalyticsItem * item)
+{
+
+ Mutex::Autolock _l(mLock);
+ // mutex between insertion and dumping the contents
+
+ // we want to dump 'in FIFO order', so insert at the end
+ mItems.push_back(item);
+
+ // clean old stuff from the queue
+ bool more = expirations_l(item);
+
+ // consider scheduling some asynchronous cleaning, if not running
+ if (more) {
+ if (!mExpireFuture.valid()
+ || mExpireFuture.wait_for(std::chrono::seconds(0)) == std::future_status::ready) {
+
+ mExpireFuture = std::async(std::launch::async, [this]()
+ {return this->processExpirations();});
+ }
+ }
}
static std::string allowedKeys[] =
diff --git a/services/mediaanalytics/MediaAnalyticsService.h b/services/mediaanalytics/MediaAnalyticsService.h
index b3c902a..632c692 100644
--- a/services/mediaanalytics/MediaAnalyticsService.h
+++ b/services/mediaanalytics/MediaAnalyticsService.h
@@ -26,6 +26,8 @@
#include <utils/String8.h>
#include <utils/List.h>
+#include <future>
+
#include <media/IMediaAnalyticsService.h>
namespace android {
@@ -44,6 +46,8 @@
MediaAnalyticsService();
virtual ~MediaAnalyticsService();
+ bool processExpirations();
+
private:
MediaAnalyticsItem::SessionID_t generateUniqueSessionID();
@@ -65,6 +69,8 @@
int32_t mMaxRecords;
// by time (none older than this long agan
nsecs_t mMaxRecordAgeNs;
+ // max to expire per expirations_l() invocation
+ int32_t mMaxRecordsExpiredAtOnce;
//
// # of sets of summaries
int32_t mMaxRecordSets;
@@ -79,6 +85,9 @@
List<MediaAnalyticsItem *> mItems;
void saveItem(MediaAnalyticsItem *);
+ bool expirations_l(MediaAnalyticsItem *);
+ std::future<bool> mExpireFuture;
+
// support for generating output
int mDumpProto;
int mDumpProtoDefault;
diff --git a/services/medialog/MediaLogService.cpp b/services/medialog/MediaLogService.cpp
index b23832e..902af66 100644
--- a/services/medialog/MediaLogService.cpp
+++ b/services/medialog/MediaLogService.cpp
@@ -20,6 +20,7 @@
#include <sys/mman.h>
#include <utils/Log.h>
#include <binder/PermissionCache.h>
+#include <media/nblog/Merger.h>
#include <media/nblog/NBLog.h>
#include <mediautils/ServiceUtilities.h>
#include "MediaLogService.h"
@@ -118,7 +119,6 @@
} else {
ALOGW("%s:", result.string());
}
- // TODO should we instead proceed to mMergeReader.dump? does it need lock?
return NO_ERROR;
}
@@ -131,9 +131,10 @@
}
}
mLock.unlock();
+ } else {
+ mMergeReader.dump(fd, args);
}
}
- mMergeReader.dump(fd);
return NO_ERROR;
}
diff --git a/services/medialog/MediaLogService.h b/services/medialog/MediaLogService.h
index a1572f9..21df898 100644
--- a/services/medialog/MediaLogService.h
+++ b/services/medialog/MediaLogService.h
@@ -19,6 +19,7 @@
#include <binder/BinderService.h>
#include <media/IMediaLogService.h>
+#include <media/nblog/Merger.h>
#include <media/nblog/NBLog.h>
namespace android {