Merge "GenericSource: enable autonomous buffering"
diff --git a/Android.bp b/Android.bp
index a3679b1..e4f12c8 100644
--- a/Android.bp
+++ b/Android.bp
@@ -2,5 +2,6 @@
"camera",
"drm/*",
"media/*",
+ "services/*",
"soundtrigger",
]
diff --git a/media/libaaudio/Android.bp b/media/libaaudio/Android.bp
index 6e60f24..f00f7a8 100644
--- a/media/libaaudio/Android.bp
+++ b/media/libaaudio/Android.bp
@@ -28,3 +28,10 @@
first_version: "26",
unversioned_until: "current",
}
+
+cc_library_headers {
+ name: "libaaudio_headers",
+ export_include_dirs: ["include"],
+}
+
+subdirs = ["*"]
diff --git a/media/libaaudio/Android.mk b/media/libaaudio/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/Android.bp b/media/libaaudio/examples/Android.bp
new file mode 100644
index 0000000..f2e00a7
--- /dev/null
+++ b/media/libaaudio/examples/Android.bp
@@ -0,0 +1,4 @@
+cc_library_headers {
+ name: "libaaudio_example_utils",
+ export_include_dirs: ["."],
+}
diff --git a/media/libaaudio/examples/Android.mk b/media/libaaudio/examples/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/input_monitor/Android.mk b/media/libaaudio/examples/input_monitor/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/input_monitor/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/loopback/Android.mk b/media/libaaudio/examples/loopback/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/loopback/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/examples/write_sine/Android.mk b/media/libaaudio/examples/write_sine/Android.mk
deleted file mode 100644
index 5053e7d..0000000
--- a/media/libaaudio/examples/write_sine/Android.mk
+++ /dev/null
@@ -1 +0,0 @@
-include $(call all-subdir-makefiles)
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
new file mode 100644
index 0000000..788833b
--- /dev/null
+++ b/media/libaaudio/src/Android.bp
@@ -0,0 +1,66 @@
+cc_library {
+ name: "libaaudio",
+
+ local_include_dirs: [
+ "binding",
+ "client",
+ "core",
+ "fifo",
+ "legacy",
+ "utility",
+ ],
+ export_include_dirs: ["."],
+ header_libs: ["libaaudio_headers"],
+ export_header_lib_headers: ["libaaudio_headers"],
+
+ srcs: [
+ "core/AudioStream.cpp",
+ "core/AudioStreamBuilder.cpp",
+ "core/AAudioAudio.cpp",
+ "core/AAudioStreamParameters.cpp",
+ "legacy/AudioStreamLegacy.cpp",
+ "legacy/AudioStreamRecord.cpp",
+ "legacy/AudioStreamTrack.cpp",
+ "utility/AAudioUtilities.cpp",
+ "utility/FixedBlockAdapter.cpp",
+ "utility/FixedBlockReader.cpp",
+ "utility/FixedBlockWriter.cpp",
+ "utility/LinearRamp.cpp",
+ "fifo/FifoBuffer.cpp",
+ "fifo/FifoControllerBase.cpp",
+ "client/AudioEndpoint.cpp",
+ "client/AudioStreamInternal.cpp",
+ "client/AudioStreamInternalCapture.cpp",
+ "client/AudioStreamInternalPlay.cpp",
+ "client/IsochronousClockModel.cpp",
+ "binding/AudioEndpointParcelable.cpp",
+ "binding/AAudioBinderClient.cpp",
+ "binding/AAudioStreamRequest.cpp",
+ "binding/AAudioStreamConfiguration.cpp",
+ "binding/IAAudioClient.cpp",
+ "binding/IAAudioService.cpp",
+ "binding/RingBufferParcelable.cpp",
+ "binding/SharedMemoryParcelable.cpp",
+ "binding/SharedRegionParcelable.cpp",
+ ],
+
+ cflags: [
+ "-Wno-unused-parameter",
+ "-Wall",
+ "-Werror",
+
+ // By default, all symbols are hidden.
+ // "-fvisibility=hidden",
+ // AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
+ "-DAAUDIO_API=__attribute__((visibility(\"default\")))",
+ ],
+
+ shared_libs: [
+ "libaudioclient",
+ "liblog",
+ "libcutils",
+ "libutils",
+ "libbinder",
+ "libaudiomanager",
+ ],
+}
diff --git a/media/libaaudio/src/Android.mk b/media/libaaudio/src/Android.mk
deleted file mode 100644
index f7a5f9b..0000000
--- a/media/libaaudio/src/Android.mk
+++ /dev/null
@@ -1,132 +0,0 @@
-LOCAL_PATH:= $(call my-dir)
-
-# ======================= STATIC LIBRARY ==========================
-# This is being built because it make AAudio testing very easy with a complete executable.
-# TODO Remove this target later, when not needed.
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libaaudio
-LOCAL_MODULE_TAGS := optional
-
-LIBAAUDIO_DIR := $(TOP)/frameworks/av/media/libaaudio
-LIBAAUDIO_SRC_DIR := $(LIBAAUDIO_DIR)/src
-
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/native/include \
- system/core/base/include \
- frameworks/native/media/libaaudio/include/include \
- frameworks/av/media/libaaudio/include \
- frameworks/native/include \
- frameworks/av/media/libaudioclient/include \
- $(LOCAL_PATH) \
- $(LOCAL_PATH)/binding \
- $(LOCAL_PATH)/client \
- $(LOCAL_PATH)/core \
- $(LOCAL_PATH)/fifo \
- $(LOCAL_PATH)/legacy \
- $(LOCAL_PATH)/utility
-
-LOCAL_AIDL_INCLUDES := frameworks/av/media/libaudioclient/aidl
-
-# If you add a file here then also add it below in the SHARED target
-LOCAL_SRC_FILES = \
- core/AudioStream.cpp \
- core/AudioStreamBuilder.cpp \
- core/AAudioAudio.cpp \
- core/AAudioStreamParameters.cpp \
- legacy/AudioStreamLegacy.cpp \
- legacy/AudioStreamRecord.cpp \
- legacy/AudioStreamTrack.cpp \
- utility/AAudioUtilities.cpp \
- utility/FixedBlockAdapter.cpp \
- utility/FixedBlockReader.cpp \
- utility/FixedBlockWriter.cpp \
- utility/LinearRamp.cpp \
- fifo/FifoBuffer.cpp \
- fifo/FifoControllerBase.cpp \
- client/AudioEndpoint.cpp \
- client/AudioStreamInternal.cpp \
- client/AudioStreamInternalCapture.cpp \
- client/AudioStreamInternalPlay.cpp \
- client/IsochronousClockModel.cpp \
- binding/AudioEndpointParcelable.cpp \
- binding/AAudioBinderClient.cpp \
- binding/AAudioStreamRequest.cpp \
- binding/AAudioStreamConfiguration.cpp \
- binding/IAAudioClient.cpp \
- binding/IAAudioService.cpp \
- binding/RingBufferParcelable.cpp \
- binding/SharedMemoryParcelable.cpp \
- binding/SharedRegionParcelable.cpp \
- ../../libaudioclient/aidl/android/media/IAudioRecord.aidl \
- ../../libaudioclient/aidl/android/media/IPlayer.aidl
-
-LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
-
-# By default, all symbols are hidden.
-# LOCAL_CFLAGS += -fvisibility=hidden
-# AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
-LOCAL_CFLAGS += -DAAUDIO_API='__attribute__((visibility("default")))'
-
-include $(BUILD_STATIC_LIBRARY)
-
-# ======================= SHARED LIBRARY ==========================
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libaaudio
-LOCAL_MODULE_TAGS := optional
-
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/native/include \
- system/core/base/include \
- frameworks/native/media/libaaudio/include/include \
- frameworks/av/media/libaaudio/include \
- $(LOCAL_PATH) \
- $(LOCAL_PATH)/binding \
- $(LOCAL_PATH)/client \
- $(LOCAL_PATH)/core \
- $(LOCAL_PATH)/fifo \
- $(LOCAL_PATH)/legacy \
- $(LOCAL_PATH)/utility
-
-LOCAL_SRC_FILES = core/AudioStream.cpp \
- core/AudioStreamBuilder.cpp \
- core/AAudioAudio.cpp \
- core/AAudioStreamParameters.cpp \
- legacy/AudioStreamLegacy.cpp \
- legacy/AudioStreamRecord.cpp \
- legacy/AudioStreamTrack.cpp \
- utility/AAudioUtilities.cpp \
- utility/FixedBlockAdapter.cpp \
- utility/FixedBlockReader.cpp \
- utility/FixedBlockWriter.cpp \
- utility/LinearRamp.cpp \
- fifo/FifoBuffer.cpp \
- fifo/FifoControllerBase.cpp \
- client/AudioEndpoint.cpp \
- client/AudioStreamInternal.cpp \
- client/AudioStreamInternalCapture.cpp \
- client/AudioStreamInternalPlay.cpp \
- client/IsochronousClockModel.cpp \
- binding/AudioEndpointParcelable.cpp \
- binding/AAudioBinderClient.cpp \
- binding/AAudioStreamRequest.cpp \
- binding/AAudioStreamConfiguration.cpp \
- binding/IAAudioClient.cpp \
- binding/IAAudioService.cpp \
- binding/RingBufferParcelable.cpp \
- binding/SharedMemoryParcelable.cpp \
- binding/SharedRegionParcelable.cpp
-
-LOCAL_CFLAGS += -Wno-unused-parameter -Wall -Werror
-
-# By default, all symbols are hidden.
-# LOCAL_CFLAGS += -fvisibility=hidden
-# AAUDIO_API is used to explicitly export a function or a variable as a visible symbol.
-LOCAL_CFLAGS += -DAAUDIO_API='__attribute__((visibility("default")))'
-
-LOCAL_SHARED_LIBRARIES := libaudioclient liblog libcutils libutils libbinder libaudiomanager
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/media/libaaudio/tests/Android.bp b/media/libaaudio/tests/Android.bp
new file mode 100644
index 0000000..099f416
--- /dev/null
+++ b/media/libaaudio/tests/Android.bp
@@ -0,0 +1,84 @@
+cc_test {
+ name: "test_aaudio_marshalling",
+ srcs: ["test_marshalling.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_block_adapter",
+ srcs: ["test_block_adapter.cpp"],
+ shared_libs: ["libaaudio"],
+}
+
+cc_test {
+ name: "test_timestamps",
+ srcs: ["test_timestamps.cpp"],
+ header_libs: ["libaaudio_example_utils"],
+ shared_libs: ["libaaudio"],
+}
+
+cc_test {
+ name: "test_linear_ramp",
+ srcs: ["test_linear_ramp.cpp"],
+ shared_libs: ["libaaudio"],
+}
+
+cc_test {
+ name: "test_open_params",
+ srcs: ["test_open_params.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_no_close",
+ srcs: ["test_no_close.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_aaudio_recovery",
+ srcs: ["test_recovery.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_n_streams",
+ srcs: ["test_n_streams.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
+
+cc_test {
+ name: "test_bad_disconnect",
+ srcs: ["test_bad_disconnect.cpp"],
+ shared_libs: [
+ "libaaudio",
+ "libbinder",
+ "libcutils",
+ "libutils",
+ ],
+}
diff --git a/media/libaaudio/tests/Android.mk b/media/libaaudio/tests/Android.mk
deleted file mode 100644
index 4120f7f..0000000
--- a/media/libaaudio/tests/Android.mk
+++ /dev/null
@@ -1,92 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_marshalling.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_aaudio_marshalling
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_block_adapter.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_block_adapter
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src \
- frameworks/av/media/libaaudio/examples
-LOCAL_SRC_FILES:= test_timestamps.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_timestamps
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_linear_ramp.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio
-LOCAL_MODULE := test_linear_ramp
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_open_params.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_open_params
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_no_close.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_no_close
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_recovery.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_aaudio_recovery
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_n_streams.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_n_streams
-include $(BUILD_NATIVE_TEST)
-
-include $(CLEAR_VARS)
-LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-utils) \
- frameworks/av/media/libaaudio/include \
- frameworks/av/media/libaaudio/src
-LOCAL_SRC_FILES:= test_bad_disconnect.cpp
-LOCAL_SHARED_LIBRARIES := libaaudio libbinder libcutils libutils
-LOCAL_MODULE := test_bad_disconnect
-include $(BUILD_NATIVE_TEST)
diff --git a/media/libmedia/IMediaExtractor.cpp b/media/libmedia/IMediaExtractor.cpp
index 3c43a72..a8a7b82 100644
--- a/media/libmedia/IMediaExtractor.cpp
+++ b/media/libmedia/IMediaExtractor.cpp
@@ -23,6 +23,7 @@
#include <binder/IPCThreadState.h>
#include <binder/Parcel.h>
+#include <binder/PermissionCache.h>
#include <media/IMediaExtractor.h>
#include <media/stagefright/MetaData.h>
@@ -323,13 +324,21 @@
status_t dumpExtractors(int fd, const Vector<String16>&) {
String8 out;
- out.append("Recent extractors, most recent first:\n");
- {
- Mutex::Autolock lock(sExtractorsLock);
- for (size_t i = 0; i < sExtractors.size(); i++) {
- const ExtractorInstance &instance = sExtractors.itemAt(i);
- out.append(" ");
- out.append(instance.toString());
+ const IPCThreadState* ipc = IPCThreadState::self();
+ const int pid = ipc->getCallingPid();
+ const int uid = ipc->getCallingUid();
+ if (!PermissionCache::checkPermission(String16("android.permission.DUMP"), pid, uid)) {
+ out.appendFormat("Permission Denial: "
+ "can't dump MediaExtractor from pid=%d, uid=%d\n", pid, uid);
+ } else {
+ out.append("Recent extractors, most recent first:\n");
+ {
+ Mutex::Autolock lock(sExtractorsLock);
+ for (size_t i = 0; i < sExtractors.size(); i++) {
+ const ExtractorInstance &instance = sExtractors.itemAt(i);
+ out.append(" ");
+ out.append(instance.toString());
+ }
}
}
write(fd, out.string(), out.size());
diff --git a/media/libmediametrics/MediaAnalyticsItem.cpp b/media/libmediametrics/MediaAnalyticsItem.cpp
index f968c09..f7df2b4 100644
--- a/media/libmediametrics/MediaAnalyticsItem.cpp
+++ b/media/libmediametrics/MediaAnalyticsItem.cpp
@@ -279,8 +279,10 @@
prop = &mProps[i];
} else {
if (i == mPropSize) {
- growProps();
- // XXX: verify success
+ if (growProps() == false) {
+ ALOGE("failed allocation for new props");
+ return NULL;
+ }
}
i = mPropCount++;
prop = &mProps[i];
@@ -312,41 +314,54 @@
// set the values
void MediaAnalyticsItem::setInt32(MediaAnalyticsItem::Attr name, int32_t value) {
Prop *prop = allocateProp(name);
- prop->mType = kTypeInt32;
- prop->u.int32Value = value;
+ if (prop != NULL) {
+ prop->mType = kTypeInt32;
+ prop->u.int32Value = value;
+ }
}
void MediaAnalyticsItem::setInt64(MediaAnalyticsItem::Attr name, int64_t value) {
Prop *prop = allocateProp(name);
- prop->mType = kTypeInt64;
- prop->u.int64Value = value;
+ if (prop != NULL) {
+ prop->mType = kTypeInt64;
+ prop->u.int64Value = value;
+ }
}
void MediaAnalyticsItem::setDouble(MediaAnalyticsItem::Attr name, double value) {
Prop *prop = allocateProp(name);
- prop->mType = kTypeDouble;
- prop->u.doubleValue = value;
+ if (prop != NULL) {
+ prop->mType = kTypeDouble;
+ prop->u.doubleValue = value;
+ }
}
void MediaAnalyticsItem::setCString(MediaAnalyticsItem::Attr name, const char *value) {
Prop *prop = allocateProp(name);
// any old value will be gone
- prop->mType = kTypeCString;
- prop->u.CStringValue = strdup(value);
+ if (prop != NULL) {
+ prop->mType = kTypeCString;
+ prop->u.CStringValue = strdup(value);
+ }
}
void MediaAnalyticsItem::setRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
Prop *prop = allocateProp(name);
- prop->mType = kTypeRate;
- prop->u.rate.count = count;
- prop->u.rate.duration = duration;
+ if (prop != NULL) {
+ prop->mType = kTypeRate;
+ prop->u.rate.count = count;
+ prop->u.rate.duration = duration;
+ }
}
// find/add/set fused into a single operation
void MediaAnalyticsItem::addInt32(MediaAnalyticsItem::Attr name, int32_t value) {
Prop *prop = allocateProp(name);
+ if (prop == NULL) {
+ return;
+ }
switch (prop->mType) {
case kTypeInt32:
prop->u.int32Value += value;
@@ -361,6 +376,9 @@
void MediaAnalyticsItem::addInt64(MediaAnalyticsItem::Attr name, int64_t value) {
Prop *prop = allocateProp(name);
+ if (prop == NULL) {
+ return;
+ }
switch (prop->mType) {
case kTypeInt64:
prop->u.int64Value += value;
@@ -375,6 +393,9 @@
void MediaAnalyticsItem::addRate(MediaAnalyticsItem::Attr name, int64_t count, int64_t duration) {
Prop *prop = allocateProp(name);
+ if (prop == NULL) {
+ return;
+ }
switch (prop->mType) {
case kTypeRate:
prop->u.rate.count += count;
@@ -391,6 +412,9 @@
void MediaAnalyticsItem::addDouble(MediaAnalyticsItem::Attr name, double value) {
Prop *prop = allocateProp(name);
+ if (prop == NULL) {
+ return;
+ }
switch (prop->mType) {
case kTypeDouble:
prop->u.doubleValue += value;
@@ -585,7 +609,7 @@
}
}
-void MediaAnalyticsItem::growProps(int increment)
+bool MediaAnalyticsItem::growProps(int increment)
{
if (increment <= 0) {
increment = kGrowProps;
@@ -599,6 +623,10 @@
}
mProps = ni;
mPropSize = nsize;
+ return true;
+ } else {
+ ALOGW("MediaAnalyticsItem::growProps fails");
+ return false;
}
}
@@ -963,32 +991,26 @@
int nattr = incoming->mPropCount;
for (int i = 0 ; i < nattr; i++ ) {
Prop *iprop = &incoming->mProps[i];
- Prop *oprop = findProp(iprop->mName);
const char *p = iprop->mName;
size_t len = strlen(p);
- char semantic = p[len-1];
+
+ // should ignore a zero length name...
+ if (len == 0) {
+ continue;
+ }
+
+ Prop *oprop = findProp(iprop->mName);
if (oprop == NULL) {
// no oprop, so we insert the new one
oprop = allocateProp(p);
- copyProp(oprop, iprop);
- } else {
- // merge iprop into oprop
- switch (semantic) {
- case '<': // first aka keep old)
- /* nop */
- break;
-
- default: // default is 'last'
- case '>': // last (aka keep new)
- copyProp(oprop, iprop);
- break;
-
- case '+': /* sum */
- // XXX validate numeric types, sum in place
- break;
-
+ if (oprop != NULL) {
+ copyProp(oprop, iprop);
+ } else {
+ ALOGW("dropped property '%s'", iprop->mName);
}
+ } else {
+ copyProp(oprop, iprop);
}
}
diff --git a/media/libmediametrics/include/MediaAnalyticsItem.h b/media/libmediametrics/include/MediaAnalyticsItem.h
index dd7452f..5f9b916 100644
--- a/media/libmediametrics/include/MediaAnalyticsItem.h
+++ b/media/libmediametrics/include/MediaAnalyticsItem.h
@@ -243,7 +243,7 @@
enum {
kGrowProps = 10
};
- void growProps(int increment = kGrowProps);
+ bool growProps(int increment = kGrowProps);
size_t findPropIndex(const char *name, size_t len);
Prop *findProp(const char *name);
Prop *allocateProp(const char *name);
diff --git a/media/libstagefright/NuMediaExtractor.cpp b/media/libstagefright/NuMediaExtractor.cpp
index 25656c3..648aa77 100644
--- a/media/libstagefright/NuMediaExtractor.cpp
+++ b/media/libstagefright/NuMediaExtractor.cpp
@@ -40,13 +40,23 @@
namespace android {
+NuMediaExtractor::Sample::Sample()
+ : mBuffer(NULL),
+ mSampleTimeUs(-1ll) {
+}
+
+NuMediaExtractor::Sample::Sample(MediaBuffer *buffer, int64_t timeUs)
+ : mBuffer(buffer),
+ mSampleTimeUs(timeUs) {
+}
+
NuMediaExtractor::NuMediaExtractor()
: mTotalBitrate(-1ll),
mDurationUs(-1ll) {
}
NuMediaExtractor::~NuMediaExtractor() {
- releaseTrackSamples();
+ releaseAllTrackSamples();
for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
TrackInfo *info = &mSelectedTracks.editItemAt(i);
@@ -288,7 +298,8 @@
return OK;
}
-status_t NuMediaExtractor::selectTrack(size_t index) {
+status_t NuMediaExtractor::selectTrack(size_t index,
+ int64_t startTimeUs, MediaSource::ReadOptions::SeekMode mode) {
Mutex::Autolock autoLock(mLock);
if (mImpl == NULL) {
@@ -311,31 +322,56 @@
sp<IMediaSource> source = mImpl->getTrack(index);
if (source == nullptr) {
+ ALOGE("track %zu is empty", index);
return ERROR_MALFORMED;
}
status_t ret = source->start();
if (ret != OK) {
+ ALOGE("track %zu failed to start", index);
return ret;
}
+ sp<MetaData> meta = source->getFormat();
+ if (meta == NULL) {
+ ALOGE("track %zu has no meta data", index);
+ return ERROR_MALFORMED;
+ }
+
+ const char *mime;
+ if (!meta->findCString(kKeyMIMEType, &mime)) {
+ ALOGE("track %zu has no mime type in meta data", index);
+ return ERROR_MALFORMED;
+ }
+ ALOGV("selectTrack, track[%zu]: %s", index, mime);
+
mSelectedTracks.push();
TrackInfo *info = &mSelectedTracks.editItemAt(mSelectedTracks.size() - 1);
info->mSource = source;
info->mTrackIndex = index;
+ if (!strncasecmp(mime, "audio/", 6)) {
+ info->mTrackType = MEDIA_TRACK_TYPE_AUDIO;
+ info->mMaxFetchCount = 64;
+ } else if (!strncasecmp(mime, "video/", 6)) {
+ info->mTrackType = MEDIA_TRACK_TYPE_VIDEO;
+ info->mMaxFetchCount = 8;
+ } else {
+ info->mTrackType = MEDIA_TRACK_TYPE_UNKNOWN;
+ info->mMaxFetchCount = 1;
+ }
info->mFinalResult = OK;
- info->mSample = NULL;
- info->mSampleTimeUs = -1ll;
+ releaseTrackSamples(info);
info->mTrackFlags = 0;
- const char *mime;
- CHECK(source->getFormat()->findCString(kKeyMIMEType, &mime));
-
if (!strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_VORBIS)) {
info->mTrackFlags |= kIsVorbis;
}
+ if (startTimeUs >= 0) {
+ fetchTrackSamples(info, startTimeUs, mode);
+ }
+
return OK;
}
@@ -366,12 +402,7 @@
TrackInfo *info = &mSelectedTracks.editItemAt(i);
- if (info->mSample != NULL) {
- info->mSample->release();
- info->mSample = NULL;
-
- info->mSampleTimeUs = -1ll;
- }
+ releaseTrackSamples(info);
CHECK_EQ((status_t)OK, info->mSource->stop());
@@ -380,79 +411,136 @@
return OK;
}
-void NuMediaExtractor::releaseTrackSamples() {
- for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
- TrackInfo *info = &mSelectedTracks.editItemAt(i);
+void NuMediaExtractor::releaseOneSample(TrackInfo *info) {
+ if (info == NULL || info->mSamples.empty()) {
+ return;
+ }
- if (info->mSample != NULL) {
- info->mSample->release();
- info->mSample = NULL;
+ auto it = info->mSamples.begin();
+ if (it->mBuffer != NULL) {
+ it->mBuffer->release();
+ }
+ info->mSamples.erase(it);
+}
- info->mSampleTimeUs = -1ll;
+void NuMediaExtractor::releaseTrackSamples(TrackInfo *info) {
+ if (info == NULL) {
+ return;
+ }
+
+ auto it = info->mSamples.begin();
+ while (it != info->mSamples.end()) {
+ if (it->mBuffer != NULL) {
+ it->mBuffer->release();
}
+ it = info->mSamples.erase(it);
}
}
-ssize_t NuMediaExtractor::fetchTrackSamples(
+void NuMediaExtractor::releaseAllTrackSamples() {
+ for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
+ releaseTrackSamples(&mSelectedTracks.editItemAt(i));
+ }
+}
+
+ssize_t NuMediaExtractor::fetchAllTrackSamples(
int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
TrackInfo *minInfo = NULL;
ssize_t minIndex = -1;
for (size_t i = 0; i < mSelectedTracks.size(); ++i) {
TrackInfo *info = &mSelectedTracks.editItemAt(i);
+ fetchTrackSamples(info, seekTimeUs, mode);
- if (seekTimeUs >= 0ll) {
- info->mFinalResult = OK;
-
- if (info->mSample != NULL) {
- info->mSample->release();
- info->mSample = NULL;
- info->mSampleTimeUs = -1ll;
- }
- } else if (info->mFinalResult != OK) {
+ if (info->mSamples.empty()) {
continue;
}
- if (info->mSample == NULL) {
- MediaSource::ReadOptions options;
- if (seekTimeUs >= 0ll) {
- options.setSeekTo(seekTimeUs, mode);
- }
- status_t err = info->mSource->read(&info->mSample, &options);
-
- if (err != OK) {
- CHECK(info->mSample == NULL);
-
- info->mFinalResult = err;
-
- if (info->mFinalResult != ERROR_END_OF_STREAM) {
- ALOGW("read on track %zu failed with error %d",
- info->mTrackIndex, err);
- }
-
- info->mSampleTimeUs = -1ll;
- continue;
- } else {
- CHECK(info->mSample != NULL);
- CHECK(info->mSample->meta_data()->findInt64(
- kKeyTime, &info->mSampleTimeUs));
- }
- }
-
- if (minInfo == NULL || info->mSampleTimeUs < minInfo->mSampleTimeUs) {
+ if (minInfo == NULL) {
minInfo = info;
minIndex = i;
+ } else {
+ auto it = info->mSamples.begin();
+ auto itMin = minInfo->mSamples.begin();
+ if (it->mSampleTimeUs < itMin->mSampleTimeUs) {
+ minInfo = info;
+ minIndex = i;
+ }
}
}
return minIndex;
}
+void NuMediaExtractor::fetchTrackSamples(TrackInfo *info,
+ int64_t seekTimeUs, MediaSource::ReadOptions::SeekMode mode) {
+ if (info == NULL) {
+ return;
+ }
+
+ MediaSource::ReadOptions options;
+ if (seekTimeUs >= 0ll) {
+ options.setSeekTo(seekTimeUs, mode);
+ info->mFinalResult = OK;
+ releaseTrackSamples(info);
+ } else if (info->mFinalResult != OK || !info->mSamples.empty()) {
+ return;
+ }
+
+ status_t err = OK;
+ Vector<MediaBuffer *> mediaBuffers;
+ if (info->mSource->supportReadMultiple()) {
+ options.setNonBlocking();
+ err = info->mSource->readMultiple(&mediaBuffers, info->mMaxFetchCount, &options);
+ } else {
+ MediaBuffer *mbuf = NULL;
+ err = info->mSource->read(&mbuf, &options);
+ if (err == OK && mbuf != NULL) {
+ mediaBuffers.push_back(mbuf);
+ }
+ }
+
+ info->mFinalResult = err;
+ if (err != OK && err != ERROR_END_OF_STREAM) {
+ ALOGW("read on track %zu failed with error %d", info->mTrackIndex, err);
+ size_t count = mediaBuffers.size();
+ for (size_t id = 0; id < count; ++id) {
+ MediaBuffer *mbuf = mediaBuffers[id];
+ if (mbuf != NULL) {
+ mbuf->release();
+ }
+ }
+ return;
+ }
+
+ size_t count = mediaBuffers.size();
+ bool releaseRemaining = false;
+ for (size_t id = 0; id < count; ++id) {
+ int64_t timeUs;
+ MediaBuffer *mbuf = mediaBuffers[id];
+ if (mbuf == NULL) {
+ continue;
+ }
+ if (releaseRemaining) {
+ mbuf->release();
+ continue;
+ }
+ if (mbuf->meta_data()->findInt64(kKeyTime, &timeUs)) {
+ info->mSamples.emplace_back(mbuf, timeUs);
+ } else {
+ mbuf->meta_data()->dumpToLog();
+ info->mFinalResult = ERROR_MALFORMED;
+ mbuf->release();
+ releaseRemaining = true;
+ }
+ }
+}
+
status_t NuMediaExtractor::seekTo(
int64_t timeUs, MediaSource::ReadOptions::SeekMode mode) {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples(timeUs, mode);
+ ssize_t minIndex = fetchAllTrackSamples(timeUs, mode);
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
@@ -464,7 +552,7 @@
status_t NuMediaExtractor::advance() {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
@@ -472,28 +560,26 @@
TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
- info->mSample->release();
- info->mSample = NULL;
- info->mSampleTimeUs = -1ll;
+ releaseOneSample(info);
return OK;
}
-status_t NuMediaExtractor::appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer) {
+status_t NuMediaExtractor::appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer) {
int32_t numPageSamples;
- if (!info->mSample->meta_data()->findInt32(
+ if (!mbuf->meta_data()->findInt32(
kKeyValidSamples, &numPageSamples)) {
numPageSamples = -1;
}
- memcpy((uint8_t *)buffer->data() + info->mSample->range_length(),
+ memcpy((uint8_t *)buffer->data() + mbuf->range_length(),
&numPageSamples,
sizeof(numPageSamples));
uint32_t type;
const void *data;
size_t size, size2;
- if (info->mSample->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) {
+ if (mbuf->meta_data()->findData(kKeyEncryptedSizes, &type, &data, &size)) {
// Signal numPageSamples (a plain int32_t) is appended at the end,
// i.e. sizeof(numPageSamples) plain bytes + 0 encrypted bytes
if (SIZE_MAX - size < sizeof(int32_t)) {
@@ -511,9 +597,9 @@
int32_t zero = 0;
memcpy(adata, data, size);
memcpy(adata + size, &zero, sizeof(zero));
- info->mSample->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize);
+ mbuf->meta_data()->setData(kKeyEncryptedSizes, type, adata, newSize);
- if (info->mSample->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) {
+ if (mbuf->meta_data()->findData(kKeyPlainSizes, &type, &data, &size2)) {
if (size2 != size) {
return ERROR_MALFORMED;
}
@@ -526,7 +612,7 @@
// append sizeof(numPageSamples) to plain sizes.
int32_t int32Size = sizeof(numPageSamples);
memcpy(adata + size, &int32Size, sizeof(int32Size));
- info->mSample->meta_data()->setData(kKeyPlainSizes, type, adata, newSize);
+ mbuf->meta_data()->setData(kKeyPlainSizes, type, adata, newSize);
}
return OK;
@@ -535,7 +621,7 @@
status_t NuMediaExtractor::readSampleData(const sp<ABuffer> &buffer) {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
@@ -543,7 +629,8 @@
TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
- size_t sampleSize = info->mSample->range_length();
+ auto it = info->mSamples.begin();
+ size_t sampleSize = it->mBuffer->range_length();
if (info->mTrackFlags & kIsVorbis) {
// Each sample's data is suffixed by the number of page samples
@@ -556,14 +643,14 @@
}
const uint8_t *src =
- (const uint8_t *)info->mSample->data()
- + info->mSample->range_offset();
+ (const uint8_t *)it->mBuffer->data()
+ + it->mBuffer->range_offset();
- memcpy((uint8_t *)buffer->data(), src, info->mSample->range_length());
+ memcpy((uint8_t *)buffer->data(), src, it->mBuffer->range_length());
status_t err = OK;
if (info->mTrackFlags & kIsVorbis) {
- err = appendVorbisNumPageSamples(info, buffer);
+ err = appendVorbisNumPageSamples(it->mBuffer, buffer);
}
if (err == OK) {
@@ -576,7 +663,7 @@
status_t NuMediaExtractor::getSampleTrackIndex(size_t *trackIndex) {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
@@ -591,14 +678,14 @@
status_t NuMediaExtractor::getSampleTime(int64_t *sampleTimeUs) {
Mutex::Autolock autoLock(mLock);
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
}
TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
- *sampleTimeUs = info->mSampleTimeUs;
+ *sampleTimeUs = info->mSamples.begin()->mSampleTimeUs;
return OK;
}
@@ -608,14 +695,14 @@
*sampleMeta = NULL;
- ssize_t minIndex = fetchTrackSamples();
+ ssize_t minIndex = fetchAllTrackSamples();
if (minIndex < 0) {
return ERROR_END_OF_STREAM;
}
TrackInfo *info = &mSelectedTracks.editItemAt(minIndex);
- *sampleMeta = info->mSample->meta_data();
+ *sampleMeta = info->mSamples.begin()->mBuffer->meta_data();
return OK;
}
diff --git a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
index 2902682..5af0745 100644
--- a/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
+++ b/media/libstagefright/include/media/stagefright/NuMediaExtractor.h
@@ -17,6 +17,8 @@
#ifndef NU_MEDIA_EXTRACTOR_H_
#define NU_MEDIA_EXTRACTOR_H_
+#include <list>
+#include <media/mediaplayer.h>
#include <media/stagefright/foundation/ABase.h>
#include <media/IMediaExtractor.h>
#include <media/MediaSource.h>
@@ -67,7 +69,9 @@
status_t getFileFormat(sp<AMessage> *format) const;
- status_t selectTrack(size_t index);
+ status_t selectTrack(size_t index, int64_t startTimeUs = -1ll,
+ MediaSource::ReadOptions::SeekMode mode =
+ MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
status_t unselectTrack(size_t index);
status_t seekTo(
@@ -75,8 +79,12 @@
MediaSource::ReadOptions::SeekMode mode =
MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
+ // Each selected track has a read pointer.
+ // advance() advances the read pointer with the lowest timestamp.
status_t advance();
+ // readSampleData() reads the sample with the lowest timestamp.
status_t readSampleData(const sp<ABuffer> &buffer);
+
status_t getSampleTrackIndex(size_t *trackIndex);
status_t getSampleTime(int64_t *sampleTimeUs);
status_t getSampleMeta(sp<MetaData> *sampleMeta);
@@ -96,12 +104,20 @@
kMaxTrackCount = 16384,
};
+ struct Sample {
+ Sample();
+ Sample(MediaBuffer *buffer, int64_t timeUs);
+ MediaBuffer *mBuffer;
+ int64_t mSampleTimeUs;
+ };
+
struct TrackInfo {
sp<IMediaSource> mSource;
size_t mTrackIndex;
+ media_track_type mTrackType;
+ size_t mMaxFetchCount;
status_t mFinalResult;
- MediaBuffer *mSample;
- int64_t mSampleTimeUs;
+ std::list<Sample> mSamples;
uint32_t mTrackFlags; // bitmask of "TrackFlags"
};
@@ -117,16 +133,23 @@
int64_t mTotalBitrate; // in bits/sec
int64_t mDurationUs;
- ssize_t fetchTrackSamples(
+ ssize_t fetchAllTrackSamples(
+ int64_t seekTimeUs = -1ll,
+ MediaSource::ReadOptions::SeekMode mode =
+ MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
+ void fetchTrackSamples(
+ TrackInfo *info,
int64_t seekTimeUs = -1ll,
MediaSource::ReadOptions::SeekMode mode =
MediaSource::ReadOptions::SEEK_CLOSEST_SYNC);
- void releaseTrackSamples();
+ void releaseOneSample(TrackInfo *info);
+ void releaseTrackSamples(TrackInfo *info);
+ void releaseAllTrackSamples();
bool getTotalBitrate(int64_t *bitRate) const;
status_t updateDurationAndBitrate();
- status_t appendVorbisNumPageSamples(TrackInfo *info, const sp<ABuffer> &buffer);
+ status_t appendVorbisNumPageSamples(MediaBuffer *mbuf, const sp<ABuffer> &buffer);
DISALLOW_EVIL_CONSTRUCTORS(NuMediaExtractor);
};
diff --git a/media/mtp/Android.bp b/media/mtp/Android.bp
index 543ad5c..acea373 100644
--- a/media/mtp/Android.bp
+++ b/media/mtp/Android.bp
@@ -19,6 +19,7 @@
srcs: [
"MtpDataPacket.cpp",
"MtpDebug.cpp",
+ "MtpDescriptors.cpp",
"MtpDevHandle.cpp",
"MtpDevice.cpp",
"MtpDeviceInfo.cpp",
diff --git a/media/mtp/MtpDescriptors.cpp b/media/mtp/MtpDescriptors.cpp
new file mode 100644
index 0000000..d9b6060
--- /dev/null
+++ b/media/mtp/MtpDescriptors.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 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.
+ */
+
+#include "MtpDescriptors.h"
+
+namespace android {
+
+const struct usb_interface_descriptor mtp_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 3,
+ .bInterfaceClass = USB_CLASS_STILL_IMAGE,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1,
+ .iInterface = 1,
+};
+
+const struct usb_interface_descriptor ptp_interface_desc = {
+ .bLength = USB_DT_INTERFACE_SIZE,
+ .bDescriptorType = USB_DT_INTERFACE,
+ .bInterfaceNumber = 0,
+ .bNumEndpoints = 3,
+ .bInterfaceClass = USB_CLASS_STILL_IMAGE,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 1,
+};
+
+const struct usb_endpoint_descriptor_no_audio fs_sink = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+};
+
+const struct usb_endpoint_descriptor_no_audio fs_source = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_FS,
+};
+
+const struct usb_endpoint_descriptor_no_audio intr = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 3 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_INT,
+ .wMaxPacketSize = MAX_PACKET_SIZE_EV,
+ .bInterval = 6,
+};
+
+const struct usb_endpoint_descriptor_no_audio hs_sink = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+};
+
+const struct usb_endpoint_descriptor_no_audio hs_source = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_HS,
+};
+
+const struct usb_endpoint_descriptor_no_audio ss_sink = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 1 | USB_DIR_IN,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+};
+
+const struct usb_endpoint_descriptor_no_audio ss_source = {
+ .bLength = USB_DT_ENDPOINT_SIZE,
+ .bDescriptorType = USB_DT_ENDPOINT,
+ .bEndpointAddress = 2 | USB_DIR_OUT,
+ .bmAttributes = USB_ENDPOINT_XFER_BULK,
+ .wMaxPacketSize = MAX_PACKET_SIZE_SS,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
+ .bLength = sizeof(ss_sink_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 6,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_source_comp = {
+ .bLength = sizeof(ss_source_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+ .bMaxBurst = 6,
+};
+
+const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
+ .bLength = sizeof(ss_intr_comp),
+ .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
+};
+
+const struct func_desc mtp_fs_descriptors = {
+ .intf = mtp_interface_desc,
+ .sink = fs_sink,
+ .source = fs_source,
+ .intr = intr,
+};
+
+const struct func_desc mtp_hs_descriptors = {
+ .intf = mtp_interface_desc,
+ .sink = hs_sink,
+ .source = hs_source,
+ .intr = intr,
+};
+
+const struct ss_func_desc mtp_ss_descriptors = {
+ .intf = mtp_interface_desc,
+ .sink = ss_sink,
+ .sink_comp = ss_sink_comp,
+ .source = ss_source,
+ .source_comp = ss_source_comp,
+ .intr = intr,
+ .intr_comp = ss_intr_comp,
+};
+
+const struct func_desc ptp_fs_descriptors = {
+ .intf = ptp_interface_desc,
+ .sink = fs_sink,
+ .source = fs_source,
+ .intr = intr,
+};
+
+const struct func_desc ptp_hs_descriptors = {
+ .intf = ptp_interface_desc,
+ .sink = hs_sink,
+ .source = hs_source,
+ .intr = intr,
+};
+
+const struct ss_func_desc ptp_ss_descriptors = {
+ .intf = ptp_interface_desc,
+ .sink = ss_sink,
+ .sink_comp = ss_sink_comp,
+ .source = ss_source,
+ .source_comp = ss_source_comp,
+ .intr = intr,
+ .intr_comp = ss_intr_comp,
+};
+
+const struct functionfs_strings mtp_strings = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
+ .length = htole32(sizeof(mtp_strings)),
+ .str_count = htole32(1),
+ .lang_count = htole32(1),
+ },
+ .lang0 = {
+ .code = htole16(0x0409),
+ .str1 = STR_INTERFACE,
+ },
+};
+
+const struct usb_os_desc_header mtp_os_desc_header = {
+ .interface = htole32(1),
+ .dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
+ .bcdVersion = htole16(1),
+ .wIndex = htole16(4),
+ .bCount = htole16(1),
+ .Reserved = htole16(0),
+};
+
+const struct usb_ext_compat_desc mtp_os_desc_compat = {
+ .bFirstInterfaceNumber = 0,
+ .Reserved1 = htole32(1),
+ .CompatibleID = { 'M', 'T', 'P' },
+ .SubCompatibleID = {0},
+ .Reserved2 = {0},
+};
+
+const struct usb_ext_compat_desc ptp_os_desc_compat = {
+ .bFirstInterfaceNumber = 0,
+ .Reserved1 = htole32(1),
+ .CompatibleID = { 'P', 'T', 'P' },
+ .SubCompatibleID = {0},
+ .Reserved2 = {0},
+};
+
+const struct desc_v2 mtp_desc_v2 = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .length = htole32(sizeof(struct desc_v2)),
+ .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC,
+ },
+ .fs_count = 4,
+ .hs_count = 4,
+ .ss_count = 7,
+ .os_count = 1,
+ .fs_descs = mtp_fs_descriptors,
+ .hs_descs = mtp_hs_descriptors,
+ .ss_descs = mtp_ss_descriptors,
+ .os_header = mtp_os_desc_header,
+ .os_desc = mtp_os_desc_compat,
+};
+
+const struct desc_v2 ptp_desc_v2 = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2),
+ .length = htole32(sizeof(struct desc_v2)),
+ .flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
+ FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC,
+ },
+ .fs_count = 4,
+ .hs_count = 4,
+ .ss_count = 7,
+ .os_count = 1,
+ .fs_descs = ptp_fs_descriptors,
+ .hs_descs = ptp_hs_descriptors,
+ .ss_descs = ptp_ss_descriptors,
+ .os_header = mtp_os_desc_header,
+ .os_desc = ptp_os_desc_compat,
+};
+
+const struct desc_v1 mtp_desc_v1 = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+ .length = htole32(sizeof(struct desc_v1)),
+ .fs_count = 4,
+ .hs_count = 4,
+ },
+ .fs_descs = mtp_fs_descriptors,
+ .hs_descs = mtp_hs_descriptors,
+};
+
+const struct desc_v1 ptp_desc_v1 = {
+ .header = {
+ .magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC),
+ .length = htole32(sizeof(struct desc_v1)),
+ .fs_count = 4,
+ .hs_count = 4,
+ },
+ .fs_descs = ptp_fs_descriptors,
+ .hs_descs = ptp_hs_descriptors,
+};
+
+}; // namespace android
diff --git a/media/mtp/MtpDescriptors.h b/media/mtp/MtpDescriptors.h
new file mode 100644
index 0000000..cfc3930
--- /dev/null
+++ b/media/mtp/MtpDescriptors.h
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 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 MTP_DESCRIPTORS_H
+#define MTP_DESCRIPTORS_H
+
+#include <linux/usb/ch9.h>
+#include <linux/usb/functionfs.h>
+#include <sys/endian.h>
+
+namespace android {
+
+constexpr int MAX_PACKET_SIZE_FS = 64;
+constexpr int MAX_PACKET_SIZE_HS = 512;
+constexpr int MAX_PACKET_SIZE_SS = 1024;
+constexpr int MAX_PACKET_SIZE_EV = 28;
+
+struct func_desc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio sink;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_endpoint_descriptor_no_audio intr;
+} __attribute__((packed));
+
+struct ss_func_desc {
+ struct usb_interface_descriptor intf;
+ struct usb_endpoint_descriptor_no_audio sink;
+ struct usb_ss_ep_comp_descriptor sink_comp;
+ struct usb_endpoint_descriptor_no_audio source;
+ struct usb_ss_ep_comp_descriptor source_comp;
+ struct usb_endpoint_descriptor_no_audio intr;
+ struct usb_ss_ep_comp_descriptor intr_comp;
+} __attribute__((packed));
+
+struct desc_v1 {
+ struct usb_functionfs_descs_head_v1 {
+ __le32 magic;
+ __le32 length;
+ __le32 fs_count;
+ __le32 hs_count;
+ } __attribute__((packed)) header;
+ struct func_desc fs_descs, hs_descs;
+} __attribute__((packed));
+
+struct desc_v2 {
+ struct usb_functionfs_descs_head_v2 header;
+ // The rest of the structure depends on the flags in the header.
+ __le32 fs_count;
+ __le32 hs_count;
+ __le32 ss_count;
+ __le32 os_count;
+ struct func_desc fs_descs, hs_descs;
+ struct ss_func_desc ss_descs;
+ struct usb_os_desc_header os_header;
+ struct usb_ext_compat_desc os_desc;
+} __attribute__((packed));
+
+// OS descriptor contents should not be changed. See b/64790536.
+static_assert(sizeof(struct desc_v2) == sizeof(usb_functionfs_descs_head_v2) +
+ 16 + 2 * sizeof(struct func_desc) + sizeof(struct ss_func_desc) +
+ sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc),
+ "Size of mtp descriptor is incorrect!");
+
+#define STR_INTERFACE "MTP"
+struct functionfs_lang {
+ __le16 code;
+ char str1[sizeof(STR_INTERFACE)];
+} __attribute__((packed));
+
+struct functionfs_strings {
+ struct usb_functionfs_strings_head header;
+ struct functionfs_lang lang0;
+} __attribute__((packed));
+
+extern const struct desc_v2 mtp_desc_v2;
+extern const struct desc_v2 ptp_desc_v2;
+extern const struct desc_v1 mtp_desc_v1;
+extern const struct desc_v1 ptp_desc_v1;
+extern const struct functionfs_strings mtp_strings;
+
+}; // namespace android
+
+#endif // MTP_DESCRIPTORS_H
diff --git a/media/mtp/MtpFfsHandle.cpp b/media/mtp/MtpFfsHandle.cpp
index 965985d..cb9827f 100644
--- a/media/mtp/MtpFfsHandle.cpp
+++ b/media/mtp/MtpFfsHandle.cpp
@@ -20,13 +20,10 @@
#include <dirent.h>
#include <errno.h>
#include <fcntl.h>
-#include <linux/usb/ch9.h>
-#include <linux/usb/functionfs.h>
#include <memory>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <sys/endian.h>
#include <sys/eventfd.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
@@ -36,6 +33,7 @@
#include <unistd.h>
#include "PosixAsyncIO.h"
+#include "MtpDescriptors.h"
#include "MtpFfsHandle.h"
#include "mtp.h"
@@ -45,11 +43,6 @@
constexpr char FFS_MTP_EP_OUT[] = "/dev/usb-ffs/mtp/ep2";
constexpr char FFS_MTP_EP_INTR[] = "/dev/usb-ffs/mtp/ep3";
-constexpr int MAX_PACKET_SIZE_FS = 64;
-constexpr int MAX_PACKET_SIZE_HS = 512;
-constexpr int MAX_PACKET_SIZE_SS = 1024;
-constexpr int MAX_PACKET_SIZE_EV = 28;
-
constexpr unsigned AIO_BUFS_MAX = 128;
constexpr unsigned AIO_BUF_LEN = 16384;
@@ -61,234 +54,6 @@
struct timespec ZERO_TIMEOUT = { 0, 0 };
-struct func_desc {
- struct usb_interface_descriptor intf;
- struct usb_endpoint_descriptor_no_audio sink;
- struct usb_endpoint_descriptor_no_audio source;
- struct usb_endpoint_descriptor_no_audio intr;
-} __attribute__((packed));
-
-struct ss_func_desc {
- struct usb_interface_descriptor intf;
- struct usb_endpoint_descriptor_no_audio sink;
- struct usb_ss_ep_comp_descriptor sink_comp;
- struct usb_endpoint_descriptor_no_audio source;
- struct usb_ss_ep_comp_descriptor source_comp;
- struct usb_endpoint_descriptor_no_audio intr;
- struct usb_ss_ep_comp_descriptor intr_comp;
-} __attribute__((packed));
-
-struct desc_v1 {
- struct usb_functionfs_descs_head_v1 {
- __le32 magic;
- __le32 length;
- __le32 fs_count;
- __le32 hs_count;
- } __attribute__((packed)) header;
- struct func_desc fs_descs, hs_descs;
-} __attribute__((packed));
-
-struct desc_v2 {
- struct usb_functionfs_descs_head_v2 header;
- // The rest of the structure depends on the flags in the header.
- __le32 fs_count;
- __le32 hs_count;
- __le32 ss_count;
- __le32 os_count;
- struct func_desc fs_descs, hs_descs;
- struct ss_func_desc ss_descs;
- struct usb_os_desc_header os_header;
- struct usb_ext_compat_desc os_desc;
-} __attribute__((packed));
-
-const struct usb_interface_descriptor mtp_interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = USB_CLASS_STILL_IMAGE,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 1,
- .iInterface = 1,
-};
-
-const struct usb_interface_descriptor ptp_interface_desc = {
- .bLength = USB_DT_INTERFACE_SIZE,
- .bDescriptorType = USB_DT_INTERFACE,
- .bInterfaceNumber = 0,
- .bNumEndpoints = 3,
- .bInterfaceClass = USB_CLASS_STILL_IMAGE,
- .bInterfaceSubClass = 1,
- .bInterfaceProtocol = 1,
-};
-
-const struct usb_endpoint_descriptor_no_audio fs_sink = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 1 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-};
-
-const struct usb_endpoint_descriptor_no_audio fs_source = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 2 | USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_FS,
-};
-
-const struct usb_endpoint_descriptor_no_audio intr = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 3 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_INT,
- .wMaxPacketSize = MAX_PACKET_SIZE_EV,
- .bInterval = 6,
-};
-
-const struct usb_endpoint_descriptor_no_audio hs_sink = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 1 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-};
-
-const struct usb_endpoint_descriptor_no_audio hs_source = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 2 | USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_HS,
-};
-
-const struct usb_endpoint_descriptor_no_audio ss_sink = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 1 | USB_DIR_IN,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_SS,
-};
-
-const struct usb_endpoint_descriptor_no_audio ss_source = {
- .bLength = USB_DT_ENDPOINT_SIZE,
- .bDescriptorType = USB_DT_ENDPOINT,
- .bEndpointAddress = 2 | USB_DIR_OUT,
- .bmAttributes = USB_ENDPOINT_XFER_BULK,
- .wMaxPacketSize = MAX_PACKET_SIZE_SS,
-};
-
-const struct usb_ss_ep_comp_descriptor ss_sink_comp = {
- .bLength = sizeof(ss_sink_comp),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bMaxBurst = 6,
-};
-
-const struct usb_ss_ep_comp_descriptor ss_source_comp = {
- .bLength = sizeof(ss_source_comp),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
- .bMaxBurst = 6,
-};
-
-const struct usb_ss_ep_comp_descriptor ss_intr_comp = {
- .bLength = sizeof(ss_intr_comp),
- .bDescriptorType = USB_DT_SS_ENDPOINT_COMP,
-};
-
-const struct func_desc mtp_fs_descriptors = {
- .intf = mtp_interface_desc,
- .sink = fs_sink,
- .source = fs_source,
- .intr = intr,
-};
-
-const struct func_desc mtp_hs_descriptors = {
- .intf = mtp_interface_desc,
- .sink = hs_sink,
- .source = hs_source,
- .intr = intr,
-};
-
-const struct ss_func_desc mtp_ss_descriptors = {
- .intf = mtp_interface_desc,
- .sink = ss_sink,
- .sink_comp = ss_sink_comp,
- .source = ss_source,
- .source_comp = ss_source_comp,
- .intr = intr,
- .intr_comp = ss_intr_comp,
-};
-
-const struct func_desc ptp_fs_descriptors = {
- .intf = ptp_interface_desc,
- .sink = fs_sink,
- .source = fs_source,
- .intr = intr,
-};
-
-const struct func_desc ptp_hs_descriptors = {
- .intf = ptp_interface_desc,
- .sink = hs_sink,
- .source = hs_source,
- .intr = intr,
-};
-
-const struct ss_func_desc ptp_ss_descriptors = {
- .intf = ptp_interface_desc,
- .sink = ss_sink,
- .sink_comp = ss_sink_comp,
- .source = ss_source,
- .source_comp = ss_source_comp,
- .intr = intr,
- .intr_comp = ss_intr_comp,
-};
-
-#define STR_INTERFACE "MTP"
-const struct {
- struct usb_functionfs_strings_head header;
- struct {
- __le16 code;
- const char str1[sizeof(STR_INTERFACE)];
- } __attribute__((packed)) lang0;
-} __attribute__((packed)) strings = {
- .header = {
- .magic = htole32(FUNCTIONFS_STRINGS_MAGIC),
- .length = htole32(sizeof(strings)),
- .str_count = htole32(1),
- .lang_count = htole32(1),
- },
- .lang0 = {
- .code = htole16(0x0409),
- .str1 = STR_INTERFACE,
- },
-};
-
-struct usb_os_desc_header mtp_os_desc_header = {
- .interface = htole32(1),
- .dwLength = htole32(sizeof(usb_os_desc_header) + sizeof(usb_ext_compat_desc)),
- .bcdVersion = htole16(1),
- .wIndex = htole16(4),
- .bCount = htole16(1),
- .Reserved = htole16(0),
-};
-
-struct usb_ext_compat_desc mtp_os_desc_compat = {
- .bFirstInterfaceNumber = 0,
- .Reserved1 = htole32(1),
- .CompatibleID = { 'M', 'T', 'P' },
- .SubCompatibleID = {0},
- .Reserved2 = {0},
-};
-
-struct usb_ext_compat_desc ptp_os_desc_compat = {
- .bFirstInterfaceNumber = 0,
- .Reserved1 = htole32(1),
- .CompatibleID = { 'P', 'T', 'P' },
- .SubCompatibleID = {0},
- .Reserved2 = {0},
-};
-
struct mtp_device_status {
uint16_t wLength;
uint16_t wCode;
@@ -357,58 +122,38 @@
}
bool MtpFfsHandle::initFunctionfs() {
- ssize_t ret;
- struct desc_v1 v1_descriptor;
- struct desc_v2 v2_descriptor;
-
- v2_descriptor.header.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC_V2);
- v2_descriptor.header.length = htole32(sizeof(v2_descriptor));
- v2_descriptor.header.flags = FUNCTIONFS_HAS_FS_DESC | FUNCTIONFS_HAS_HS_DESC |
- FUNCTIONFS_HAS_SS_DESC | FUNCTIONFS_HAS_MS_OS_DESC;
- v2_descriptor.fs_count = 4;
- v2_descriptor.hs_count = 4;
- v2_descriptor.ss_count = 7;
- v2_descriptor.os_count = 1;
- v2_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
- v2_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
- v2_descriptor.ss_descs = mPtp ? ptp_ss_descriptors : mtp_ss_descriptors;
- v2_descriptor.os_header = mtp_os_desc_header;
- v2_descriptor.os_desc = mPtp ? ptp_os_desc_compat : mtp_os_desc_compat;
-
if (mControl < 0) { // might have already done this before
mControl.reset(TEMP_FAILURE_RETRY(open(FFS_MTP_EP0, O_RDWR)));
if (mControl < 0) {
PLOG(ERROR) << FFS_MTP_EP0 << ": cannot open control endpoint";
- goto err;
+ return false;
}
-
- ret = TEMP_FAILURE_RETRY(::write(mControl, &v2_descriptor, sizeof(v2_descriptor)));
- if (ret < 0) {
- v1_descriptor.header.magic = htole32(FUNCTIONFS_DESCRIPTORS_MAGIC);
- v1_descriptor.header.length = htole32(sizeof(v1_descriptor));
- v1_descriptor.header.fs_count = 4;
- v1_descriptor.header.hs_count = 4;
- v1_descriptor.fs_descs = mPtp ? ptp_fs_descriptors : mtp_fs_descriptors;
- v1_descriptor.hs_descs = mPtp ? ptp_hs_descriptors : mtp_hs_descriptors;
- PLOG(ERROR) << FFS_MTP_EP0 << "Switching to V1 descriptor format";
- ret = TEMP_FAILURE_RETRY(::write(mControl, &v1_descriptor, sizeof(v1_descriptor)));
- if (ret < 0) {
- PLOG(ERROR) << FFS_MTP_EP0 << "Writing descriptors failed";
- goto err;
- }
- }
- ret = TEMP_FAILURE_RETRY(::write(mControl, &strings, sizeof(strings)));
- if (ret < 0) {
- PLOG(ERROR) << FFS_MTP_EP0 << "Writing strings failed";
- goto err;
+ if (!writeDescriptors()) {
+ closeConfig();
+ return false;
}
}
-
return true;
+}
-err:
- closeConfig();
- return false;
+bool MtpFfsHandle::writeDescriptors() {
+ ssize_t ret = TEMP_FAILURE_RETRY(::write(mControl,
+ &(mPtp ? ptp_desc_v2 : mtp_desc_v2), sizeof(desc_v2)));
+ if (ret < 0) {
+ PLOG(ERROR) << FFS_MTP_EP0 << "Switching to V1 descriptor format";
+ ret = TEMP_FAILURE_RETRY(::write(mControl,
+ &(mPtp ? ptp_desc_v1 : mtp_desc_v1), sizeof(desc_v1)));
+ if (ret < 0) {
+ PLOG(ERROR) << FFS_MTP_EP0 << "Writing descriptors failed";
+ return false;
+ }
+ }
+ ret = TEMP_FAILURE_RETRY(::write(mControl, &mtp_strings, sizeof(mtp_strings)));
+ if (ret < 0) {
+ PLOG(ERROR) << FFS_MTP_EP0 << "Writing strings failed";
+ return false;
+ }
+ return true;
}
void MtpFfsHandle::closeConfig() {
diff --git a/media/mtp/MtpFfsHandle.h b/media/mtp/MtpFfsHandle.h
index 2f90bd1..2347000 100644
--- a/media/mtp/MtpFfsHandle.h
+++ b/media/mtp/MtpFfsHandle.h
@@ -42,11 +42,14 @@
};
template <class T> class MtpFfsHandleTest;
+template <class T> class MtpFfsHandleTest_testControl_Test;
class MtpFfsHandle : public IMtpHandle {
- template <class T> friend class android::MtpFfsHandleTest;
+ template <class T> friend class MtpFfsHandleTest;
+ template <class T> friend class MtpFfsHandleTest_testControl_Test;
protected:
bool initFunctionfs();
+ bool writeDescriptors();
void closeConfig();
void closeEndpoints();
void advise(int fd);
diff --git a/media/mtp/OWNERS b/media/mtp/OWNERS
new file mode 100644
index 0000000..219307b
--- /dev/null
+++ b/media/mtp/OWNERS
@@ -0,0 +1 @@
+zhangjerry@google.com
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandle_test.cpp
index 8d7301d..9c916b7 100644
--- a/media/mtp/tests/MtpFfsHandle_test.cpp
+++ b/media/mtp/tests/MtpFfsHandle_test.cpp
@@ -25,6 +25,7 @@
#include <unistd.h>
#include <utils/Log.h>
+#include "MtpDescriptors.h"
#include "MtpFfsHandle.h"
#include "MtpFfsCompatHandle.h"
@@ -66,8 +67,8 @@
handle = std::make_unique<T>();
EXPECT_EQ(pipe(fd), 0);
- handle->mControl.reset(fd[0]);
- control.reset(fd[1]);
+ control.reset(fd[0]);
+ handle->mControl.reset(fd[1]);
EXPECT_EQ(pipe(fd), 0);
EXPECT_EQ(fcntl(fd[0], F_SETPIPE_SZ, 1048576), 1048576);
@@ -83,7 +84,7 @@
intr.reset(fd[0]);
handle->mIntr.reset(fd[1]);
- handle->start();
+ EXPECT_EQ(handle->start(), 0);
}
~MtpFfsHandleTest() {
@@ -94,6 +95,16 @@
typedef ::testing::Types<MtpFfsHandle, MtpFfsCompatHandle> mtpHandles;
TYPED_TEST_CASE(MtpFfsHandleTest, mtpHandles);
+TYPED_TEST(MtpFfsHandleTest, testControl) {
+ EXPECT_TRUE(this->handle->writeDescriptors());
+ struct desc_v2 desc;
+ struct functionfs_strings strings;
+ EXPECT_EQ(read(this->control, &desc, sizeof(desc)), (long)sizeof(desc));
+ EXPECT_EQ(read(this->control, &strings, sizeof(strings)), (long)sizeof(strings));
+ EXPECT_TRUE(std::memcmp(&desc, &mtp_desc_v2, sizeof(desc)) == 0);
+ EXPECT_TRUE(std::memcmp(&strings, &mtp_strings, sizeof(strings)) == 0);
+}
+
TYPED_TEST(MtpFfsHandleTest, testRead) {
EXPECT_EQ(write(this->bulk_out, dummyDataStr.c_str(), TEST_PACKET_SIZE), TEST_PACKET_SIZE);
char buf[TEST_PACKET_SIZE + 1];
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 906e05a..89e5d77 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1224,6 +1224,12 @@
bool force = !outputDesc->isActive() &&
(outputDesc->getPatchHandle() == AUDIO_PATCH_HANDLE_NONE);
+ // requiresMuteCheck is false when we can bypass mute strategy.
+ // It covers a common case when there is no materially active audio
+ // and muting would result in unnecessary delay and dropped audio.
+ const uint32_t outputLatencyMs = outputDesc->latency();
+ bool requiresMuteCheck = outputDesc->isActive(outputLatencyMs * 2); // account for drain
+
// increment usage count for this stream on the requested output:
// NOTE that the usage count is the same for duplicated output and hardware output which is
// necessary for a correct control of hardware output routing by startOutput() and stopOutput()
@@ -1247,29 +1253,44 @@
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<AudioOutputDescriptor> desc = mOutputs.valueAt(i);
if (desc != outputDesc) {
+ // An output has a shared device if
+ // - managed by the same hw module
+ // - supports the currently selected device
+ const bool sharedDevice = outputDesc->sharesHwModuleWith(desc)
+ && (desc->supportedDevices() & device) != AUDIO_DEVICE_NONE;
+
// force a device change if any other output is:
// - managed by the same hw module
- // - has a current device selection that differs from selected device.
// - supports currently selected device
+ // - has a current device selection that differs from selected device.
// - has an active audio patch
// In this case, the audio HAL must receive the new device selection so that it can
- // change the device currently selected by the other active output.
- if (outputDesc->sharesHwModuleWith(desc) &&
+ // change the device currently selected by the other output.
+ if (sharedDevice &&
desc->device() != device &&
- desc->supportedDevices() & device &&
desc->getPatchHandle() != AUDIO_PATCH_HANDLE_NONE) {
force = true;
}
// wait for audio on other active outputs to be presented when starting
// a notification so that audio focus effect can propagate, or that a mute/unmute
// event occurred for beacon
- uint32_t latency = desc->latency();
- if (shouldWait && desc->isActive(latency * 2) && (waitMs < latency)) {
- waitMs = latency;
+ const uint32_t latencyMs = desc->latency();
+ const bool isActive = desc->isActive(latencyMs * 2); // account for drain
+
+ if (shouldWait && isActive && (waitMs < latencyMs)) {
+ waitMs = latencyMs;
}
+
+ // Require mute check if another output is on a shared device
+ // and currently active to have proper drain and avoid pops.
+ // Note restoring AudioTracks onto this output needs to invoke
+ // a volume ramp if there is no mute.
+ requiresMuteCheck |= sharedDevice && isActive;
}
}
- uint32_t muteWaitMs = setOutputDevice(outputDesc, device, force, 0, NULL, address);
+
+ const uint32_t muteWaitMs =
+ setOutputDevice(outputDesc, device, force, 0, NULL, address, requiresMuteCheck);
// handle special case for sonification while in call
if (isInCall()) {
@@ -1294,6 +1315,14 @@
if (waitMs > muteWaitMs) {
*delayMs = waitMs - muteWaitMs;
}
+
+ // FIXME: A device change (muteWaitMs > 0) likely introduces a volume change.
+ // A volume change enacted by APM with 0 delay is not synchronous, as it goes
+ // via AudioCommandThread to AudioFlinger. Hence it is possible that the volume
+ // change occurs after the MixerThread starts and causes a stream volume
+ // glitch.
+ //
+ // We do not introduce additional delay here.
}
return NO_ERROR;
@@ -4812,21 +4841,24 @@
bool force,
int delayMs,
audio_patch_handle_t *patchHandle,
- const char* address)
+ const char *address,
+ bool requiresMuteCheck)
{
ALOGV("setOutputDevice() device %04x delayMs %d", device, delayMs);
AudioParameter param;
uint32_t muteWaitMs;
if (outputDesc->isDuplicated()) {
- muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs);
- muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs);
+ muteWaitMs = setOutputDevice(outputDesc->subOutput1(), device, force, delayMs,
+ nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
+ muteWaitMs += setOutputDevice(outputDesc->subOutput2(), device, force, delayMs,
+ nullptr /* patchHandle */, nullptr /* address */, requiresMuteCheck);
return muteWaitMs;
}
// no need to proceed if new device is not AUDIO_DEVICE_NONE and not supported by current
// output profile
if ((device != AUDIO_DEVICE_NONE) &&
- ((device & outputDesc->supportedDevices()) == 0)) {
+ ((device & outputDesc->supportedDevices()) == AUDIO_DEVICE_NONE)) {
return 0;
}
@@ -4840,7 +4872,14 @@
if (device != AUDIO_DEVICE_NONE) {
outputDesc->mDevice = device;
}
- muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+
+ // if the outputs are not materially active, there is no need to mute.
+ if (requiresMuteCheck) {
+ muteWaitMs = checkDeviceMuteStrategies(outputDesc, prevDevice, delayMs);
+ } else {
+ ALOGV("%s: suppressing checkDeviceMuteStrategies", __func__);
+ muteWaitMs = 0;
+ }
// Do not change the routing if:
// the requested device is AUDIO_DEVICE_NONE
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index 7ba0669..1b0c315 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -300,7 +300,8 @@
bool force = false,
int delayMs = 0,
audio_patch_handle_t *patchHandle = NULL,
- const char* address = NULL);
+ const char *address = nullptr,
+ bool requiresMuteCheck = true);
status_t resetOutputDevice(const sp<AudioOutputDescriptor>& outputDesc,
int delayMs = 0,
audio_patch_handle_t *patchHandle = NULL);
diff --git a/services/mediaanalytics/MediaAnalyticsService.cpp b/services/mediaanalytics/MediaAnalyticsService.cpp
index c7f9270..f08be50 100644
--- a/services/mediaanalytics/MediaAnalyticsService.cpp
+++ b/services/mediaanalytics/MediaAnalyticsService.cpp
@@ -299,6 +299,8 @@
bool finalizing = item->getFinalized();
+ Mutex::Autolock _l(mLock);
+
// if finalizing, we'll remove it
MediaAnalyticsItem *oitem = findItem(mOpen, item, finalizing | forcenew);
if (oitem != NULL) {
@@ -609,10 +611,9 @@
// XXX: rewrite this to manage persistence, etc.
// insert appropriately into queue
+// caller should hold mLock
void MediaAnalyticsService::saveItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem * item, int front) {
- Mutex::Autolock _l(mLock);
-
// adding at back of queue (fifo order)
if (front) {
l->push_front(item);
@@ -682,6 +683,7 @@
}
// find the incomplete record that this will overlay
+// caller should hold mLock
MediaAnalyticsItem *MediaAnalyticsService::findItem(List<MediaAnalyticsItem*> *theList, MediaAnalyticsItem *nitem, bool removeit) {
if (nitem == NULL) {
return NULL;
@@ -689,8 +691,6 @@
MediaAnalyticsItem *item = NULL;
- Mutex::Autolock _l(mLock);
-
for (List<MediaAnalyticsItem *>::iterator it = theList->begin();
it != theList->end(); it++) {
MediaAnalyticsItem *tmp = (*it);
@@ -711,10 +711,9 @@
// delete the indicated record
+// caller should hold mLock
void MediaAnalyticsService::deleteItem(List<MediaAnalyticsItem *> *l, MediaAnalyticsItem *item) {
- Mutex::Autolock _l(mLock);
-
for (List<MediaAnalyticsItem *>::iterator it = l->begin();
it != l->end(); it++) {
if ((*it)->getSessionID() != item->getSessionID())
diff --git a/services/medialog/Android.bp b/services/medialog/Android.bp
new file mode 100644
index 0000000..29e6dfc
--- /dev/null
+++ b/services/medialog/Android.bp
@@ -0,0 +1,22 @@
+cc_library_shared {
+ name: "libmedialogservice",
+
+ srcs: [
+ "IMediaLogService.cpp",
+ "MediaLogService.cpp",
+ ],
+
+ shared_libs: [
+ "libaudioutils",
+ "libbinder",
+ "liblog",
+ "libnbaio",
+ "libnblog",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
diff --git a/services/medialog/Android.mk b/services/medialog/Android.mk
deleted file mode 100644
index 4f2630e..0000000
--- a/services/medialog/Android.mk
+++ /dev/null
@@ -1,17 +0,0 @@
-LOCAL_PATH := $(call my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_SRC_FILES := MediaLogService.cpp IMediaLogService.cpp
-
-LOCAL_SHARED_LIBRARIES := libbinder libutils liblog libnbaio libnblog libaudioutils
-
-LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
-
-LOCAL_MODULE:= libmedialogservice
-
-LOCAL_C_INCLUDES := $(call include-path-for, audio-utils)
-
-LOCAL_CFLAGS := -Werror -Wall
-
-include $(BUILD_SHARED_LIBRARY)