Merge "Camera: Fix coordinate mapping within partial result"
diff --git a/Android.bp b/Android.bp
new file mode 100644
index 0000000..87a8f41
--- /dev/null
+++ b/Android.bp
@@ -0,0 +1,27 @@
+aidl_interface {
+ name: "av-types-aidl",
+ unstable: true,
+ host_supported: true,
+ vendor_available: true,
+ double_loadable: true,
+ local_include_dir: "aidl",
+ srcs: [
+ "aidl/android/media/InterpolatorConfig.aidl",
+ "aidl/android/media/InterpolatorType.aidl",
+ "aidl/android/media/VolumeShaperConfiguration.aidl",
+ "aidl/android/media/VolumeShaperConfigurationOptionFlag.aidl",
+ "aidl/android/media/VolumeShaperConfigurationType.aidl",
+ "aidl/android/media/VolumeShaperOperation.aidl",
+ "aidl/android/media/VolumeShaperOperationFlag.aidl",
+ "aidl/android/media/VolumeShaperState.aidl",
+ ],
+ backend: {
+ cpp: {
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
+ },
+ },
+}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/aidl/android/media/InterpolatorConfig.aidl
similarity index 66%
copy from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
copy to aidl/android/media/InterpolatorConfig.aidl
index d305c29..ef7486e 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/aidl/android/media/InterpolatorConfig.aidl
@@ -13,13 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.media;
-@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+import android.media.InterpolatorType;
+
+/**
+ * {@hide}
+ */
+parcelable InterpolatorConfig {
+ InterpolatorType type;
+ /** For cubic interpolation, the boundary conditions in slope. */
+ float firstSlope;
+ float lastSlope;
+ /** A flattened list of <x, y> pairs, monotonically increasing in x. */
+ float[] xy;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/aidl/android/media/InterpolatorType.aidl
similarity index 67%
copy from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
copy to aidl/android/media/InterpolatorType.aidl
index d305c29..b722cad 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/aidl/android/media/InterpolatorType.aidl
@@ -15,11 +15,20 @@
*/
package android.media;
+/**
+ * Polynomial spline interpolators.
+ *
+ * {@hide}
+ */
@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+enum InterpolatorType {
+ /** Not continuous. */
+ STEP,
+ /** C0. */
+ LINEAR,
+ /** C1. */
+ CUBIC,
+ /** C1 (to provide locally monotonic curves). */
+ CUBIC_MONOTONIC,
+ // CUBIC_C2, // TODO - requires global computation / cache
}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/aidl/android/media/VolumeShaperConfiguration.aidl
similarity index 60%
copy from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
copy to aidl/android/media/VolumeShaperConfiguration.aidl
index d305c29..6361851 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/aidl/android/media/VolumeShaperConfiguration.aidl
@@ -13,13 +13,21 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.media;
-@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+import android.media.InterpolatorConfig;
+import android.media.VolumeShaperConfigurationOptionFlag;
+import android.media.VolumeShaperConfigurationType;
+
+/**
+ * {@hide}
+ */
+parcelable VolumeShaperConfiguration {
+ VolumeShaperConfigurationType type;
+ int id;
+ /** Bitmask, indexed by VolumeShaperConfigurationOptionFlag. */
+ int optionFlags;
+ double durationMs;
+ InterpolatorConfig interpolatorConfig;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/aidl/android/media/VolumeShaperConfigurationOptionFlag.aidl
similarity index 84%
copy from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
copy to aidl/android/media/VolumeShaperConfigurationOptionFlag.aidl
index d305c29..f583cee 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/aidl/android/media/VolumeShaperConfigurationOptionFlag.aidl
@@ -16,10 +16,7 @@
package android.media;
@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+enum VolumeShaperConfigurationOptionFlag {
+ VOLUME_IN_DBFS,
+ CLOCK_TIME,
}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/aidl/android/media/VolumeShaperConfigurationType.aidl
similarity index 84%
copy from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
copy to aidl/android/media/VolumeShaperConfigurationType.aidl
index d305c29..aa6334e 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/aidl/android/media/VolumeShaperConfigurationType.aidl
@@ -16,10 +16,7 @@
package android.media;
@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+enum VolumeShaperConfigurationType {
+ ID,
+ SCALE,
}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/aidl/android/media/VolumeShaperOperation.aidl
similarity index 67%
copy from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
copy to aidl/android/media/VolumeShaperOperation.aidl
index d305c29..dd9a0e7 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/aidl/android/media/VolumeShaperOperation.aidl
@@ -13,13 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.media;
-@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+/**
+ * {@hide}
+ */
+parcelable VolumeShaperOperation {
+ /** Operations to do. Bitmask of VolumeShaperOperationFlag. */
+ int flags;
+ /** If >= 0 the id to remove in a replace operation. */
+ int replaceId;
+ /** Position in the curve to set if a valid number (not nan). */
+ float xOffset;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/aidl/android/media/VolumeShaperOperationFlag.aidl
similarity index 79%
copy from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
copy to aidl/android/media/VolumeShaperOperationFlag.aidl
index d305c29..8fe5275 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/aidl/android/media/VolumeShaperOperationFlag.aidl
@@ -16,10 +16,11 @@
package android.media;
@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+enum VolumeShaperOperationFlag {
+ /** The absence of this flag indicates "play". */
+ REVERSE,
+ TERMINATE,
+ JOIN,
+ DELAY,
+ CREATE_IF_NECESSARY,
}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/aidl/android/media/VolumeShaperState.aidl
similarity index 72%
copy from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
copy to aidl/android/media/VolumeShaperState.aidl
index d305c29..4085e2b 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/aidl/android/media/VolumeShaperState.aidl
@@ -13,13 +13,15 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.media;
-@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+/**
+ * {@hide}
+ */
+parcelable VolumeShaperState {
+ /** Linear volume in the range MIN_LINEAR_VOLUME to MAX_LINEAR_VOLUME. */
+ float volume;
+ /** Position on curve expressed from MIN_CURVE_TIME to MAX_CURVE_TIME. */
+ float xOffset;
}
diff --git a/apex/Android.bp b/apex/Android.bp
index 80e751c..fac3831 100644
--- a/apex/Android.bp
+++ b/apex/Android.bp
@@ -31,6 +31,8 @@
"libmpeg2extractor",
"liboggextractor",
"libwavextractor",
+ // JNI
+ "libmediaparser-jni"
],
},
},
diff --git a/camera/camera2/CaptureRequest.cpp b/camera/camera2/CaptureRequest.cpp
index 1843ec4..ebc09d7 100644
--- a/camera/camera2/CaptureRequest.cpp
+++ b/camera/camera2/CaptureRequest.cpp
@@ -94,12 +94,12 @@
// Do not distinguish null arrays from 0-sized arrays.
for (int32_t i = 0; i < size; ++i) {
// Parcel.writeParcelableArray
- size_t len;
- const char16_t* className = parcel->readString16Inplace(&len);
+ std::optional<std::string> className;
+ parcel->readUtf8FromUtf16(&className);
ALOGV("%s: Read surface class = %s", __FUNCTION__,
- className != NULL ? String8(className).string() : "<null>");
+ className.value_or("<null>").c_str());
- if (className == NULL) {
+ if (className == std::nullopt) {
continue;
}
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index a2c2ca7..2d54bd1 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -4881,7 +4881,7 @@
* rectangle, and cropping to the rectangle given in ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE.</p>
* <p>E.g. to calculate position of a pixel, (x,y), in a processed YUV output image with the
* dimensions in ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE given the position of a pixel,
- * (x', y'), in the raw pixel array with dimensions give in
+ * (x', y'), in the raw pixel array with dimensions given in
* ACAMERA_SENSOR_INFO_PIXEL_ARRAY_SIZE:</p>
* <ol>
* <li>Choose a pixel (x', y') within the active array region of the raw buffer given in
diff --git a/drm/libmediadrm/protos/Android.bp b/drm/libmediadrm/protos/Android.bp
new file mode 100644
index 0000000..b26cda4
--- /dev/null
+++ b/drm/libmediadrm/protos/Android.bp
@@ -0,0 +1,38 @@
+// Copyright (C) 2020 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.
+
+// This is the version of the drm metrics configured for protobuf full on host.
+// It is used by the metrics_dump tool.
+
+cc_library_host_shared {
+ name: "libdrm_metrics_protos_full_host",
+ vendor_available: true,
+
+ include_dirs: ["external/protobuf/src"],
+
+ srcs: [
+ "metrics.proto",
+ ],
+
+ proto: {
+ export_proto_headers: true,
+ type: "full",
+ },
+
+ cflags: [
+ // Suppress unused parameter error. This error occurs
+ // when using the map type in a proto definition.
+ "-Wno-unused-parameter",
+ ],
+}
diff --git a/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
index 2dcd00f..051a968 100644
--- a/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
+++ b/drm/mediadrm/plugins/clearkey/hidl/MemoryFileSystem.cpp
@@ -15,7 +15,7 @@
namespace clearkey {
std::string MemoryFileSystem::GetFileName(const std::string& path) {
- size_t index = path.find_last_of("/");
+ size_t index = path.find_last_of('/');
if (index != std::string::npos) {
return path.substr(index+1);
} else {
diff --git a/include/media/Interpolator.h b/include/media/Interpolator.h
index 703cf77..2004acb 100644
--- a/include/media/Interpolator.h
+++ b/include/media/Interpolator.h
@@ -21,6 +21,7 @@
#include <sstream>
#include <unordered_map>
+#include <android/media/InterpolatorConfig.h>
#include <binder/Parcel.h>
#include <utils/RefBase.h>
@@ -39,17 +40,10 @@
class Interpolator : public std::map<S, T> {
public:
// Polynomial spline interpolators
- // Extend only at the end of enum, as this must match order in VolumeShapers.java.
- enum InterpolatorType : int32_t {
- INTERPOLATOR_TYPE_STEP, // Not continuous
- INTERPOLATOR_TYPE_LINEAR, // C0
- INTERPOLATOR_TYPE_CUBIC, // C1
- INTERPOLATOR_TYPE_CUBIC_MONOTONIC, // C1 (to provide locally monotonic curves)
- // INTERPOLATOR_TYPE_CUBIC_C2, // TODO - requires global computation / cache
- };
+ using InterpolatorType = media::InterpolatorType;
explicit Interpolator(
- InterpolatorType interpolatorType = INTERPOLATOR_TYPE_LINEAR,
+ InterpolatorType interpolatorType = InterpolatorType::LINEAR,
bool cache = true)
: mCache(cache)
, mFirstSlope(0)
@@ -82,13 +76,13 @@
// now that we have two adjacent points:
switch (mInterpolatorType) {
- case INTERPOLATOR_TYPE_STEP:
+ case InterpolatorType::STEP:
return high->first == x ? high->second : low->second;
- case INTERPOLATOR_TYPE_LINEAR:
+ case InterpolatorType::LINEAR:
return ((high->first - x) * low->second + (x - low->first) * high->second)
/ (high->first - low->first);
- case INTERPOLATOR_TYPE_CUBIC:
- case INTERPOLATOR_TYPE_CUBIC_MONOTONIC:
+ case InterpolatorType::CUBIC:
+ case InterpolatorType::CUBIC_MONOTONIC:
default: {
// See https://en.wikipedia.org/wiki/Cubic_Hermite_spline
@@ -116,7 +110,7 @@
// non catmullRom (finite difference) with regular cubic;
// the choices here minimize computation.
bool monotonic, catmullRom;
- if (mInterpolatorType == INTERPOLATOR_TYPE_CUBIC_MONOTONIC) {
+ if (mInterpolatorType == InterpolatorType::CUBIC_MONOTONIC) {
monotonic = true;
catmullRom = false;
} else {
@@ -202,11 +196,11 @@
status_t setInterpolatorType(InterpolatorType interpolatorType) {
switch (interpolatorType) {
- case INTERPOLATOR_TYPE_STEP: // Not continuous
- case INTERPOLATOR_TYPE_LINEAR: // C0
- case INTERPOLATOR_TYPE_CUBIC: // C1
- case INTERPOLATOR_TYPE_CUBIC_MONOTONIC: // C1 + other constraints
- // case INTERPOLATOR_TYPE_CUBIC_C2:
+ case InterpolatorType::STEP: // Not continuous
+ case InterpolatorType::LINEAR: // C0
+ case InterpolatorType::CUBIC: // C1
+ case InterpolatorType::CUBIC_MONOTONIC: // C1 + other constraints
+ // case InterpolatorType::CUBIC_C2:
mInterpolatorType = interpolatorType;
return NO_ERROR;
default:
@@ -235,49 +229,50 @@
mMemo.clear();
}
+ // TODO(ytai): remove this method once it is not used.
status_t writeToParcel(Parcel *parcel) const {
- if (parcel == nullptr) {
- return BAD_VALUE;
- }
- status_t res = parcel->writeInt32(mInterpolatorType)
- ?: parcel->writeFloat(mFirstSlope)
- ?: parcel->writeFloat(mLastSlope)
- ?: parcel->writeUint32((uint32_t)this->size()); // silent truncation
- if (res != NO_ERROR) {
- return res;
- }
- for (const auto &pt : *this) {
- res = parcel->writeFloat(pt.first)
- ?: parcel->writeFloat(pt.second);
- if (res != NO_ERROR) {
- return res;
- }
- }
- return NO_ERROR;
+ media::InterpolatorConfig config;
+ writeToConfig(&config);
+ return config.writeToParcel(parcel);
}
+ void writeToConfig(media::InterpolatorConfig *config) const {
+ config->type = mInterpolatorType;
+ config->firstSlope = mFirstSlope;
+ config->lastSlope = mLastSlope;
+ for (const auto &pt : *this) {
+ config->xy.push_back(pt.first);
+ config->xy.push_back(pt.second);
+ }
+ }
+
+ // TODO(ytai): remove this method once it is not used.
status_t readFromParcel(const Parcel &parcel) {
- this->clear();
- int32_t type;
- uint32_t size;
- status_t res = parcel.readInt32(&type)
- ?: parcel.readFloat(&mFirstSlope)
- ?: parcel.readFloat(&mLastSlope)
- ?: parcel.readUint32(&size)
- ?: setInterpolatorType((InterpolatorType)type);
+ media::InterpolatorConfig config;
+ status_t res = config.readFromParcel(&parcel);
if (res != NO_ERROR) {
return res;
}
+ return readFromConfig(config);
+ }
+
+ status_t readFromConfig(const media::InterpolatorConfig &config) {
+ this->clear();
+ setInterpolatorType(config.type);
+ if ((config.xy.size() & 1) != 0) {
+ // xy size must be even.
+ return BAD_VALUE;
+ }
+ uint32_t size = config.xy.size() / 2;
+ mFirstSlope = config.firstSlope;
+ mLastSlope = config.lastSlope;
+
// Note: We don't need to check size is within some bounds as
// the Parcel read will fail if size is incorrectly specified too large.
float lastx;
for (uint32_t i = 0; i < size; ++i) {
- float x, y;
- res = parcel.readFloat(&x)
- ?: parcel.readFloat(&y);
- if (res != NO_ERROR) {
- return res;
- }
+ float x = config.xy[i * 2];
+ float y = config.xy[i * 2 + 1];
if ((i > 0 && !(x > lastx)) /* handle nan */
|| y != y /* handle nan */) {
// This is a std::map object which imposes sorted order
diff --git a/include/media/VolumeShaper.h b/include/media/VolumeShaper.h
index fe519bb..f8ead2f 100644
--- a/include/media/VolumeShaper.h
+++ b/include/media/VolumeShaper.h
@@ -22,6 +22,11 @@
#include <math.h>
#include <sstream>
+#include <android/media/VolumeShaperConfiguration.h>
+#include <android/media/VolumeShaperConfigurationOptionFlag.h>
+#include <android/media/VolumeShaperOperation.h>
+#include <android/media/VolumeShaperOperationFlag.h>
+#include <android/media/VolumeShaperState.h>
#include <binder/Parcel.h>
#include <media/Interpolator.h>
#include <utils/Mutex.h>
@@ -284,30 +289,38 @@
clampVolume();
}
- // The parcel layout must match VolumeShaper.java
status_t writeToParcel(Parcel *parcel) const override {
- if (parcel == nullptr) return BAD_VALUE;
- return parcel->writeInt32((int32_t)mType)
- ?: parcel->writeInt32(mId)
- ?: mType == TYPE_ID
- ? NO_ERROR
- : parcel->writeInt32((int32_t)mOptionFlags)
- ?: parcel->writeDouble(mDurationMs)
- ?: Interpolator<S, T>::writeToParcel(parcel);
+ VolumeShaperConfiguration parcelable;
+ writeToParcelable(&parcelable);
+ return parcelable.writeToParcel(parcel);
}
- status_t readFromParcel(const Parcel *parcel) override {
- int32_t type, optionFlags;
- return parcel->readInt32(&type)
- ?: setType((Type)type)
- ?: parcel->readInt32(&mId)
- ?: mType == TYPE_ID
- ? NO_ERROR
- : parcel->readInt32(&optionFlags)
- ?: setOptionFlags((OptionFlag)optionFlags)
- ?: parcel->readDouble(&mDurationMs)
- ?: Interpolator<S, T>::readFromParcel(*parcel)
- ?: checkCurve();
+ void writeToParcelable(VolumeShaperConfiguration *parcelable) const {
+ parcelable->id = getId();
+ parcelable->type = getTypeAsAidl();
+ parcelable->optionFlags = 0;
+ if (mType != TYPE_ID) {
+ parcelable->optionFlags = getOptionFlagsAsAidl();
+ parcelable->durationMs = getDurationMs();
+ Interpolator<S, T>::writeToConfig(&parcelable->interpolatorConfig);
+ }
+ }
+
+ status_t readFromParcel(const Parcel* parcel) override {
+ VolumeShaperConfiguration data;
+ return data.readFromParcel(parcel)
+ ?: readFromParcelable(data);
+ }
+
+ status_t readFromParcelable(const VolumeShaperConfiguration& parcelable) {
+ setId(parcelable.id);
+ return setTypeFromAidl(parcelable.type)
+ ?: mType == TYPE_ID
+ ? NO_ERROR
+ : setOptionFlagsFromAidl(parcelable.optionFlags)
+ ?: setDurationMs(parcelable.durationMs)
+ ?: Interpolator<S, T>::readFromConfig(parcelable.interpolatorConfig)
+ ?: checkCurve();
}
// Returns a string for debug printing.
@@ -329,6 +342,51 @@
int32_t mId; // A valid id is >= 0.
OptionFlag mOptionFlags; // option flags for the configuration.
double mDurationMs; // duration, must be > 0; default is 1000 ms.
+
+ int32_t getOptionFlagsAsAidl() const {
+ int32_t result = 0;
+ if (getOptionFlags() & OPTION_FLAG_VOLUME_IN_DBFS) {
+ result |=
+ 1 << static_cast<int>(VolumeShaperConfigurationOptionFlag::VOLUME_IN_DBFS);
+ }
+ if (getOptionFlags() & OPTION_FLAG_CLOCK_TIME) {
+ result |= 1 << static_cast<int>(VolumeShaperConfigurationOptionFlag::CLOCK_TIME);
+ }
+ return result;
+ }
+
+ status_t setOptionFlagsFromAidl(int32_t aidl) {
+ std::underlying_type_t<OptionFlag> options = 0;
+ if (aidl & (1 << static_cast<int>(VolumeShaperConfigurationOptionFlag::VOLUME_IN_DBFS))) {
+ options |= OPTION_FLAG_VOLUME_IN_DBFS;
+ }
+ if (aidl & (1 << static_cast<int>(VolumeShaperConfigurationOptionFlag::CLOCK_TIME))) {
+ options |= OPTION_FLAG_CLOCK_TIME;
+ }
+ return setOptionFlags(static_cast<OptionFlag>(options));
+ }
+
+ status_t setTypeFromAidl(VolumeShaperConfigurationType aidl) {
+ switch (aidl) {
+ case VolumeShaperConfigurationType::ID:
+ return setType(TYPE_ID);
+ case VolumeShaperConfigurationType::SCALE:
+ return setType(TYPE_SCALE);
+ default:
+ return BAD_VALUE;
+ }
+ }
+
+ VolumeShaperConfigurationType getTypeAsAidl() const {
+ switch (getType()) {
+ case TYPE_ID:
+ return VolumeShaperConfigurationType::ID;
+ case TYPE_SCALE:
+ return VolumeShaperConfigurationType::SCALE;
+ default:
+ LOG_ALWAYS_FATAL("Shouldn't get here");
+ }
+ }
}; // Configuration
/* VolumeShaper::Operation expresses an operation to perform on the
@@ -420,19 +478,29 @@
return NO_ERROR;
}
- status_t writeToParcel(Parcel *parcel) const override {
+ status_t writeToParcel(Parcel* parcel) const override {
if (parcel == nullptr) return BAD_VALUE;
- return parcel->writeInt32((int32_t)mFlags)
- ?: parcel->writeInt32(mReplaceId)
- ?: parcel->writeFloat(mXOffset);
+ VolumeShaperOperation op;
+ writeToParcelable(&op);
+ return op.writeToParcel(parcel);
}
- status_t readFromParcel(const Parcel *parcel) override {
- int32_t flags;
- return parcel->readInt32(&flags)
- ?: parcel->readInt32(&mReplaceId)
- ?: parcel->readFloat(&mXOffset)
- ?: setFlags((Flag)flags);
+ void writeToParcelable(VolumeShaperOperation* op) const {
+ op->flags = getFlagsAsAidl();
+ op->replaceId = mReplaceId;
+ op->xOffset = mXOffset;
+ }
+
+ status_t readFromParcel(const Parcel* parcel) override {
+ VolumeShaperOperation op;
+ return op.readFromParcel(parcel)
+ ?: readFromParcelable(op);
+ }
+
+ status_t readFromParcelable(const VolumeShaperOperation& op) {
+ mReplaceId = op.replaceId;
+ mXOffset = op.xOffset;
+ return setFlagsFromAidl(op.flags);
}
std::string toString() const {
@@ -445,6 +513,48 @@
}
private:
+ status_t setFlagsFromAidl(int32_t aidl) {
+ std::underlying_type_t<Flag> flags = 0;
+ if (aidl & (1 << static_cast<int>(VolumeShaperOperationFlag::REVERSE))) {
+ flags |= FLAG_REVERSE;
+ }
+ if (aidl & (1 << static_cast<int>(VolumeShaperOperationFlag::TERMINATE))) {
+ flags |= FLAG_TERMINATE;
+ }
+ if (aidl & (1 << static_cast<int>(VolumeShaperOperationFlag::JOIN))) {
+ flags |= FLAG_JOIN;
+ }
+ if (aidl & (1 << static_cast<int>(VolumeShaperOperationFlag::DELAY))) {
+ flags |= FLAG_DELAY;
+ }
+ if (aidl & (1 << static_cast<int>(VolumeShaperOperationFlag::CREATE_IF_NECESSARY))) {
+ flags |= FLAG_CREATE_IF_NECESSARY;
+ }
+ return setFlags(static_cast<Flag>(flags));
+ }
+
+ int32_t getFlagsAsAidl() const {
+ int32_t aidl = 0;
+ std::underlying_type_t<Flag> flags = getFlags();
+ if (flags & FLAG_REVERSE) {
+ aidl |= (1 << static_cast<int>(VolumeShaperOperationFlag::REVERSE));
+ }
+ if (flags & FLAG_TERMINATE) {
+ aidl |= (1 << static_cast<int>(VolumeShaperOperationFlag::TERMINATE));
+ }
+ if (flags & FLAG_JOIN) {
+ aidl |= (1 << static_cast<int>(VolumeShaperOperationFlag::JOIN));
+ }
+ if (flags & FLAG_DELAY) {
+ aidl |= (1 << static_cast<int>(VolumeShaperOperationFlag::DELAY));
+ }
+ if (flags & FLAG_CREATE_IF_NECESSARY) {
+ aidl |= (1 << static_cast<int>(VolumeShaperOperationFlag::CREATE_IF_NECESSARY));
+ }
+ return aidl;
+ }
+
+ private:
Flag mFlags; // operation to do
int32_t mReplaceId; // if >= 0 the id to remove in a replace operation.
S mXOffset; // position in the curve to set if a valid number (not nan)
@@ -483,15 +593,28 @@
mXOffset = xOffset;
}
- status_t writeToParcel(Parcel *parcel) const override {
+ status_t writeToParcel(Parcel* parcel) const override {
if (parcel == nullptr) return BAD_VALUE;
- return parcel->writeFloat(mVolume)
- ?: parcel->writeFloat(mXOffset);
+ VolumeShaperState state;
+ writeToParcelable(&state);
+ return state.writeToParcel(parcel);
}
- status_t readFromParcel(const Parcel *parcel) override {
- return parcel->readFloat(&mVolume)
- ?: parcel->readFloat(&mXOffset);
+ void writeToParcelable(VolumeShaperState* parcelable) const {
+ parcelable->volume = mVolume;
+ parcelable->xOffset = mXOffset;
+ }
+
+ status_t readFromParcel(const Parcel* parcel) override {
+ VolumeShaperState state;
+ return state.readFromParcel(parcel)
+ ?: readFromParcelable(state);
+ }
+
+ status_t readFromParcelable(const VolumeShaperState& parcelable) {
+ mVolume = parcelable.volume;
+ mXOffset = parcelable.xOffset;
+ return OK;
}
std::string toString() const {
diff --git a/media/codec2/sfplugin/CCodec.cpp b/media/codec2/sfplugin/CCodec.cpp
index 1405b97..f816778 100644
--- a/media/codec2/sfplugin/CCodec.cpp
+++ b/media/codec2/sfplugin/CCodec.cpp
@@ -2168,15 +2168,17 @@
return OK;
}
}
- uint64_t minUsage = usage.expected;
- uint64_t maxUsage = ~0ull;
std::set<C2Allocator::id_t> allocators;
GetCommonAllocatorIds(names, C2Allocator::LINEAR, &allocators);
if (allocators.empty()) {
*isCompatible = false;
return OK;
}
+
+ uint64_t minUsage = 0;
+ uint64_t maxUsage = ~0ull;
CalculateMinMaxUsage(names, &minUsage, &maxUsage);
+ minUsage |= usage.expected;
*isCompatible = ((maxUsage & minUsage) == minUsage);
return OK;
}
@@ -2203,14 +2205,16 @@
// static
std::shared_ptr<C2LinearBlock> CCodec::FetchLinearBlock(
size_t capacity, const C2MemoryUsage &usage, const std::vector<std::string> &names) {
- uint64_t minUsage = usage.expected;
- uint64_t maxUsage = ~0ull;
std::set<C2Allocator::id_t> allocators;
GetCommonAllocatorIds(names, C2Allocator::LINEAR, &allocators);
if (allocators.empty()) {
allocators.insert(C2PlatformAllocatorStore::DEFAULT_LINEAR);
}
+
+ uint64_t minUsage = 0;
+ uint64_t maxUsage = ~0ull;
CalculateMinMaxUsage(names, &minUsage, &maxUsage);
+ minUsage |= usage.expected;
if ((maxUsage & minUsage) != minUsage) {
allocators.clear();
allocators.insert(C2PlatformAllocatorStore::DEFAULT_LINEAR);
diff --git a/media/codec2/sfplugin/CCodecBufferChannel.cpp b/media/codec2/sfplugin/CCodecBufferChannel.cpp
index 97145c3..6e0c295 100644
--- a/media/codec2/sfplugin/CCodecBufferChannel.cpp
+++ b/media/codec2/sfplugin/CCodecBufferChannel.cpp
@@ -625,21 +625,19 @@
Mutexed<Output>::Locked output(mOutput);
if (!output->buffers ||
output->buffers->hasPending() ||
- output->buffers->numClientBuffers() >= output->numSlots) {
+ output->buffers->numActiveSlots() >= output->numSlots) {
return;
}
}
- size_t numInputSlots = mInput.lock()->numSlots;
- for (size_t i = 0; i < numInputSlots; ++i) {
- if (mPipelineWatcher.lock()->pipelineFull()) {
- return;
- }
+ size_t numActiveSlots = 0;
+ while (!mPipelineWatcher.lock()->pipelineFull()) {
sp<MediaCodecBuffer> inBuffer;
size_t index;
{
Mutexed<Input>::Locked input(mInput);
- if (input->buffers->numClientBuffers() >= input->numSlots) {
- return;
+ numActiveSlots = input->buffers->numActiveSlots();
+ if (numActiveSlots >= input->numSlots) {
+ break;
}
if (!input->buffers->requestNewBuffer(&index, &inBuffer)) {
ALOGV("[%s] no new buffer available", mName);
@@ -649,6 +647,7 @@
ALOGV("[%s] new input index = %zu [%p]", mName, index, inBuffer.get());
mCallback->onInputBufferAvailable(index, inBuffer);
}
+ ALOGV("[%s] # active slots after feedInputBufferIfAvailable = %zu", mName, numActiveSlots);
}
status_t CCodecBufferChannel::renderOutputBuffer(
@@ -817,6 +816,9 @@
status_t result = mComponent->queueToOutputSurface(block, qbi, &qbo);
if (result != OK) {
ALOGI("[%s] queueBuffer failed: %d", mName, result);
+ if (result == NO_INIT) {
+ mCCodecCallback->onError(UNKNOWN_ERROR, ACTION_CODE_FATAL);
+ }
return result;
}
ALOGV("[%s] queue buffer successful", mName);
diff --git a/media/codec2/sfplugin/CCodecBuffers.cpp b/media/codec2/sfplugin/CCodecBuffers.cpp
index 3c99bf6..692da58 100644
--- a/media/codec2/sfplugin/CCodecBuffers.cpp
+++ b/media/codec2/sfplugin/CCodecBuffers.cpp
@@ -495,11 +495,12 @@
mBuffers.clear();
}
-size_t FlexBuffersImpl::numClientBuffers() const {
+size_t FlexBuffersImpl::numActiveSlots() const {
return std::count_if(
mBuffers.begin(), mBuffers.end(),
[](const Entry &entry) {
- return (entry.clientBuffer != nullptr);
+ return (entry.clientBuffer != nullptr
+ || !entry.compBuffer.expired());
});
}
@@ -645,11 +646,11 @@
}
}
-size_t BuffersArrayImpl::numClientBuffers() const {
+size_t BuffersArrayImpl::numActiveSlots() const {
return std::count_if(
mBuffers.begin(), mBuffers.end(),
[](const Entry &entry) {
- return entry.ownedByClient;
+ return entry.ownedByClient || !entry.compBuffer.expired();
});
}
@@ -699,8 +700,8 @@
mImpl.flush();
}
-size_t InputBuffersArray::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t InputBuffersArray::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
sp<Codec2Buffer> InputBuffersArray::createNewBuffer() {
@@ -737,8 +738,8 @@
return nullptr;
}
-size_t SlotInputBuffers::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t SlotInputBuffers::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
sp<Codec2Buffer> SlotInputBuffers::createNewBuffer() {
@@ -789,8 +790,8 @@
return std::move(array);
}
-size_t LinearInputBuffers::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t LinearInputBuffers::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
// static
@@ -966,8 +967,8 @@
return std::move(array);
}
-size_t GraphicMetadataInputBuffers::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t GraphicMetadataInputBuffers::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
sp<Codec2Buffer> GraphicMetadataInputBuffers::createNewBuffer() {
@@ -1031,8 +1032,8 @@
return std::move(array);
}
-size_t GraphicInputBuffers::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t GraphicInputBuffers::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
sp<Codec2Buffer> GraphicInputBuffers::createNewBuffer() {
@@ -1121,8 +1122,8 @@
mImpl.getArray(array);
}
-size_t OutputBuffersArray::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t OutputBuffersArray::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
void OutputBuffersArray::realloc(const std::shared_ptr<C2Buffer> &c2buffer) {
@@ -1232,8 +1233,8 @@
return array;
}
-size_t FlexOutputBuffers::numClientBuffers() const {
- return mImpl.numClientBuffers();
+size_t FlexOutputBuffers::numActiveSlots() const {
+ return mImpl.numActiveSlots();
}
// LinearOutputBuffers
diff --git a/media/codec2/sfplugin/CCodecBuffers.h b/media/codec2/sfplugin/CCodecBuffers.h
index 0d4fa81..c383a7c 100644
--- a/media/codec2/sfplugin/CCodecBuffers.h
+++ b/media/codec2/sfplugin/CCodecBuffers.h
@@ -33,8 +33,8 @@
class SkipCutBuffer;
constexpr size_t kLinearBufferSize = 1048576;
-// This can fit 4K RGBA frame, and most likely client won't need more than this.
-constexpr size_t kMaxLinearBufferSize = 4096 * 2304 * 4;
+// This can fit an 8K frame.
+constexpr size_t kMaxLinearBufferSize = 7680 * 4320 * 2;
/**
* Base class for representation of buffers at one port.
@@ -72,7 +72,7 @@
/**
* Return number of buffers the client owns.
*/
- virtual size_t numClientBuffers() const = 0;
+ virtual size_t numActiveSlots() const = 0;
/**
* Examine image data from the buffer and update the format if necessary.
@@ -584,7 +584,7 @@
* Return the number of buffers that are sent to the client but not released
* yet.
*/
- size_t numClientBuffers() const;
+ size_t numActiveSlots() const;
/**
* Return the number of buffers that are sent to the component but not
@@ -705,7 +705,7 @@
* Return the number of buffers that are sent to the client but not released
* yet.
*/
- size_t numClientBuffers() const;
+ size_t numActiveSlots() const;
/**
* Return the size of the array.
@@ -765,7 +765,7 @@
void flush() override;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
protected:
sp<Codec2Buffer> createNewBuffer() override;
@@ -796,7 +796,7 @@
std::unique_ptr<InputBuffers> toArrayMode(size_t size) final;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
protected:
sp<Codec2Buffer> createNewBuffer() final;
@@ -826,7 +826,7 @@
std::unique_ptr<InputBuffers> toArrayMode(size_t size) override;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
protected:
sp<Codec2Buffer> createNewBuffer() override;
@@ -894,7 +894,7 @@
std::unique_ptr<InputBuffers> toArrayMode(size_t size) final;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
protected:
sp<Codec2Buffer> createNewBuffer() override;
@@ -924,7 +924,7 @@
std::unique_ptr<InputBuffers> toArrayMode(
size_t size) final;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
protected:
sp<Codec2Buffer> createNewBuffer() override;
@@ -965,7 +965,7 @@
array->clear();
}
- size_t numClientBuffers() const final {
+ size_t numActiveSlots() const final {
return 0u;
}
@@ -1019,7 +1019,7 @@
void getArray(Vector<sp<MediaCodecBuffer>> *array) const final;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
/**
* Reallocate the array, filled with buffers with the same size as given
@@ -1073,7 +1073,7 @@
std::unique_ptr<OutputBuffersArray> toArrayMode(size_t size) override;
- size_t numClientBuffers() const final;
+ size_t numActiveSlots() const final;
/**
* Return an appropriate Codec2Buffer object for the type of buffers.
diff --git a/media/extractors/mp4/ItemTable.cpp b/media/extractors/mp4/ItemTable.cpp
index 2599c2c..ded3d1a 100644
--- a/media/extractors/mp4/ItemTable.cpp
+++ b/media/extractors/mp4/ItemTable.cpp
@@ -76,6 +76,7 @@
size_t size;
sp<ABuffer> hvcc;
sp<ABuffer> icc;
+ sp<ABuffer> av1c;
Vector<uint32_t> thumbnails;
Vector<uint32_t> dimgRefs;
@@ -764,6 +765,39 @@
return OK;
}
+struct Av1cBox : public Box, public ItemProperty {
+ Av1cBox(DataSourceHelper *source) :
+ Box(source, FOURCC("av1C")) {}
+
+ status_t parse(off64_t offset, size_t size) override;
+
+ void attachTo(ImageItem &image) const override {
+ image.av1c = mAv1c;
+ }
+
+private:
+ sp<ABuffer> mAv1c;
+};
+
+status_t Av1cBox::parse(off64_t offset, size_t size) {
+ ALOGV("%s: offset %lld, size %zu", __FUNCTION__, (long long)offset, size);
+
+ mAv1c = new ABuffer(size);
+
+ if (mAv1c->data() == NULL) {
+ ALOGE("b/28471206");
+ return NO_MEMORY;
+ }
+
+ if (source()->readAt(offset, mAv1c->data(), size) < (ssize_t)size) {
+ return ERROR_IO;
+ }
+
+ ALOGV("property av1C");
+
+ return OK;
+}
+
struct IrotBox : public Box, public ItemProperty {
IrotBox(DataSourceHelper *source) :
Box(source, FOURCC("irot")), mAngle(0) {}
@@ -957,6 +991,11 @@
itemProperty = new ColrBox(source());
break;
}
+ case FOURCC("av1C"):
+ {
+ itemProperty = new Av1cBox(source());
+ break;
+ }
default:
{
// push dummy to maintain correct item property index
@@ -1203,8 +1242,9 @@
//////////////////////////////////////////////////////////////////
-ItemTable::ItemTable(DataSourceHelper *source)
+ItemTable::ItemTable(DataSourceHelper *source, bool isHeif)
: mDataSource(source),
+ mIsHeif(isHeif),
mPrimaryItemId(0),
mIdatOffset(0),
mIdatSize(0),
@@ -1363,7 +1403,8 @@
// 'Exif': EXIF metadata
if (info.itemType != FOURCC("grid") &&
info.itemType != FOURCC("hvc1") &&
- info.itemType != FOURCC("Exif")) {
+ info.itemType != FOURCC("Exif") &&
+ info.itemType != FOURCC("av01")) {
continue;
}
@@ -1509,7 +1550,9 @@
}
AMediaFormat *meta = AMediaFormat_new();
- AMediaFormat_setString(meta, AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
+ AMediaFormat_setString(
+ meta, AMEDIAFORMAT_KEY_MIME,
+ mIsHeif ? MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC : MEDIA_MIMETYPE_IMAGE_AVIF);
if (image->itemId == mPrimaryItemId) {
AMediaFormat_setInt32(meta, AMEDIAFORMAT_KEY_IS_DEFAULT, 1);
@@ -1539,15 +1582,24 @@
ssize_t thumbItemIndex = mItemIdToItemMap.indexOfKey(image->thumbnails[0]);
if (thumbItemIndex >= 0) {
const ImageItem &thumbnail = mItemIdToItemMap[thumbItemIndex];
-
- if (thumbnail.hvcc != NULL) {
+ if (thumbnail.hvcc != NULL || thumbnail.av1c != NULL) {
AMediaFormat_setInt32(meta,
AMEDIAFORMAT_KEY_THUMBNAIL_WIDTH, thumbnail.width);
AMediaFormat_setInt32(meta,
AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT, thumbnail.height);
- AMediaFormat_setBuffer(meta,
- AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC,
- thumbnail.hvcc->data(), thumbnail.hvcc->size());
+ if (thumbnail.hvcc != NULL) {
+ AMediaFormat_setBuffer(meta,
+ AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC,
+ thumbnail.hvcc->data(), thumbnail.hvcc->size());
+ } else {
+ // We use a hard-coded string here instead of
+ // AMEDIAFORMAT_KEY_THUMBNAIL_CSD_AV1C. The key is available only from SDK 31.
+ // The mp4 extractor is part of mainline and builds against SDK 29 as of
+ // writing. This hard-coded string can be replaced with the named constant once
+ // the mp4 extractor is built against SDK >= 31.
+ AMediaFormat_setBuffer(meta,
+ "thumbnail-csd-av1c", thumbnail.av1c->data(), thumbnail.av1c->size());
+ }
ALOGV("image[%u]: thumbnail: size %dx%d, item index %zd",
imageIndex, thumbnail.width, thumbnail.height, thumbItemIndex);
} else {
@@ -1574,12 +1626,21 @@
AMEDIAFORMAT_KEY_MAX_INPUT_SIZE, image->width * image->height * 3 / 2);
}
- if (image->hvcc == NULL) {
- ALOGE("%s: hvcc is missing for image[%u]!", __FUNCTION__, imageIndex);
- return NULL;
+ if (mIsHeif) {
+ if (image->hvcc == NULL) {
+ ALOGE("%s: hvcc is missing for image[%u]!", __FUNCTION__, imageIndex);
+ return NULL;
+ }
+ AMediaFormat_setBuffer(meta,
+ AMEDIAFORMAT_KEY_CSD_HEVC, image->hvcc->data(), image->hvcc->size());
+ } else {
+ if (image->av1c == NULL) {
+ ALOGE("%s: av1c is missing for image[%u]!", __FUNCTION__, imageIndex);
+ return NULL;
+ }
+ AMediaFormat_setBuffer(meta,
+ AMEDIAFORMAT_KEY_CSD_0, image->av1c->data(), image->av1c->size());
}
- AMediaFormat_setBuffer(meta,
- AMEDIAFORMAT_KEY_CSD_HEVC, image->hvcc->data(), image->hvcc->size());
if (image->icc != NULL) {
AMediaFormat_setBuffer(meta,
diff --git a/media/extractors/mp4/ItemTable.h b/media/extractors/mp4/ItemTable.h
index be81b59..b19dc18 100644
--- a/media/extractors/mp4/ItemTable.h
+++ b/media/extractors/mp4/ItemTable.h
@@ -42,12 +42,12 @@
/*
* ItemTable keeps track of all image items (including coded images, grids and
- * tiles) inside a HEIF still image (ISO/IEC FDIS 23008-12.2:2017(E)).
+ * tiles) inside a HEIF/AVIF still image (ISO/IEC FDIS 23008-12.2:2017(E)).
*/
class ItemTable : public RefBase {
public:
- explicit ItemTable(DataSourceHelper *source);
+ ItemTable(DataSourceHelper *source, bool isHeif);
status_t parse(uint32_t type, off64_t offset, size_t size);
@@ -65,6 +65,8 @@
private:
DataSourceHelper *mDataSource;
+ // If this is true, then this item table is for a HEIF image. Otherwise it is for an AVIF image.
+ bool mIsHeif;
KeyedVector<uint32_t, ItemLoc> mItemLocs;
Vector<ItemInfo> mItemInfos;
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index bd36403..7989d4b 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -149,6 +149,7 @@
uint8_t *mSrcBuffer;
bool mIsHeif;
+ bool mIsAvif;
bool mIsAudio;
bool mIsUsac = false;
sp<ItemTable> mItemTable;
@@ -202,8 +203,8 @@
uint32_t duration;
int32_t compositionOffset;
uint8_t iv[16];
- Vector<size_t> clearsizes;
- Vector<size_t> encryptedsizes;
+ Vector<uint32_t> clearsizes;
+ Vector<uint32_t> encryptedsizes;
};
Vector<Sample> mCurrentSamples;
std::map<off64_t, uint32_t> mDrmOffsets;
@@ -414,6 +415,7 @@
mIsHeif(false),
mHasMoovBox(false),
mPreferHeif(mime != NULL && !strcasecmp(mime, MEDIA_MIMETYPE_CONTAINER_HEIF)),
+ mIsAvif(false),
mFirstTrack(NULL),
mLastTrack(NULL) {
ALOGV("mime=%s, mPreferHeif=%d", mime, mPreferHeif);
@@ -670,7 +672,7 @@
}
}
- if (mIsHeif && (mItemTable != NULL) && (mItemTable->countImages() > 0)) {
+ if ((mIsAvif || mIsHeif) && (mItemTable != NULL) && (mItemTable->countImages() > 0)) {
off64_t exifOffset;
size_t exifSize;
if (mItemTable->getExifOffsetAndSize(&exifOffset, &exifSize) == OK) {
@@ -696,7 +698,7 @@
}
mInitCheck = OK;
- ALOGV("adding HEIF image track %u", imageIndex);
+ ALOGV("adding %s image track %u", mIsHeif ? "HEIF" : "AVIF", imageIndex);
Track *track = new Track;
if (mLastTrack != NULL) {
mLastTrack->next = track;
@@ -722,6 +724,10 @@
MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC) != NULL) {
AMediaFormat_setString(mFileMetaData,
AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_CONTAINER_HEIF);
+ } else if (findTrackByMimePrefix(
+ MEDIA_MIMETYPE_IMAGE_AVIF) != NULL) {
+ AMediaFormat_setString(mFileMetaData,
+ AMEDIAFORMAT_KEY_MIME, MEDIA_MIMETYPE_IMAGE_AVIF);
} else {
AMediaFormat_setString(mFileMetaData,
AMEDIAFORMAT_KEY_MIME, "application/octet-stream");
@@ -2576,9 +2582,9 @@
case FOURCC("iref"):
case FOURCC("ipro"):
{
- if (mIsHeif) {
+ if (mIsHeif || mIsAvif) {
if (mItemTable == NULL) {
- mItemTable = new ItemTable(mDataSource);
+ mItemTable = new ItemTable(mDataSource, mIsHeif);
}
status_t err = mItemTable->parse(
chunk_type, data_offset, chunk_data_size);
@@ -3019,14 +3025,20 @@
mIsHeif = true;
brandSet.erase(FOURCC("mif1"));
brandSet.erase(FOURCC("heic"));
+ } else if (brandSet.count(FOURCC("avif")) > 0 ||
+ brandSet.count(FOURCC("avis")) > 0) {
+ ALOGV("identified AVIF image");
+ mIsAvif = true;
+ brandSet.erase(FOURCC("avif"));
+ brandSet.erase(FOURCC("avis"));
}
if (!brandSet.empty()) {
// This means that the file should have moov box.
// It could be any iso files (mp4, heifs, etc.)
mHasMoovBox = true;
- if (mIsHeif) {
- ALOGV("identified HEIF image with other tracks");
+ if (mIsHeif || mIsAvif) {
+ ALOGV("identified %s image with other tracks", mIsHeif ? "HEIF" : "AVIF");
}
}
}
@@ -4364,7 +4376,8 @@
if (size != 24 || ((ptr[0] != 1 || ptr[1] != 0) && (ptr[0] != 2 || ptr[1] != 1))) {
return NULL;
}
- } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)) {
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)
+ || !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_AVIF)) {
void *data;
size_t size;
if (!AMediaFormat_getBuffer(track->meta, AMEDIAFORMAT_KEY_CSD_0, &data, &size)) {
@@ -4373,9 +4386,12 @@
const uint8_t *ptr = (const uint8_t *)data;
- if (size < 5 || ptr[0] != 0x81) { // configurationVersion == 1
+ if (size < 4 || ptr[0] != 0x81) { // configurationVersion == 1
return NULL;
}
+ if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_AVIF)) {
+ itemTable = mItemTable;
+ }
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_VP9)) {
void *data;
size_t size;
@@ -4937,7 +4953,6 @@
mStarted(false),
mBuffer(NULL),
mSrcBuffer(NULL),
- mIsHeif(itemTable != NULL),
mItemTable(itemTable),
mElstShiftStartTicks(elstShiftStartTicks),
mElstInitialEmptyEditTicks(elstInitialEmptyEditTicks) {
@@ -4972,6 +4987,8 @@
!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC);
mIsAC4 = !strcasecmp(mime, MEDIA_MIMETYPE_AUDIO_AC4);
mIsDolbyVision = !strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_DOLBY_VISION);
+ mIsHeif = !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC) && mItemTable != NULL;
+ mIsAvif = !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_AVIF) && mItemTable != NULL;
if (mIsAVC) {
void *data;
@@ -5966,7 +5983,7 @@
if (options && options->getSeekTo(&seekTimeUs, &mode)) {
ALOGV("seekTimeUs:%" PRId64, seekTimeUs);
- if (mIsHeif) {
+ if (mIsHeif || mIsAvif) {
CHECK(mSampleTable == NULL);
CHECK(mItemTable != NULL);
int32_t imageIndex;
@@ -6111,7 +6128,7 @@
newBuffer = true;
status_t err;
- if (!mIsHeif) {
+ if (!mIsHeif && !mIsAvif) {
err = mSampleTable->getMetaDataForSample(mCurrentSampleIndex, &offset, &size,
(uint64_t*)&cts, &isSyncSample, &stts);
if(err == OK) {
@@ -6539,9 +6556,9 @@
if (smpl->encryptedsizes.size()) {
// store clear/encrypted lengths in metadata
AMediaFormat_setBuffer(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_PLAIN_SIZES,
- smpl->clearsizes.array(), smpl->clearsizes.size() * 4);
+ smpl->clearsizes.array(), smpl->clearsizes.size() * sizeof(uint32_t));
AMediaFormat_setBuffer(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_ENCRYPTED_SIZES,
- smpl->encryptedsizes.array(), smpl->encryptedsizes.size() * 4);
+ smpl->encryptedsizes.array(), smpl->encryptedsizes.size() * sizeof(uint32_t));
AMediaFormat_setInt32(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_DEFAULT_IV_SIZE, mDefaultIVSize);
AMediaFormat_setInt32(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_MODE, mCryptoMode);
AMediaFormat_setBuffer(bufmeta, AMEDIAFORMAT_KEY_CRYPTO_KEY, mCryptoKey, 16);
@@ -6750,7 +6767,8 @@
|| !memcmp(header, "ftypM4A ", 8) || !memcmp(header, "ftypf4v ", 8)
|| !memcmp(header, "ftypkddi", 8) || !memcmp(header, "ftypM4VP", 8)
|| !memcmp(header, "ftypmif1", 8) || !memcmp(header, "ftypheic", 8)
- || !memcmp(header, "ftypmsf1", 8) || !memcmp(header, "ftyphevc", 8)) {
+ || !memcmp(header, "ftypmsf1", 8) || !memcmp(header, "ftyphevc", 8)
+ || !memcmp(header, "ftypavif", 8) || !memcmp(header, "ftypavis", 8)) {
*confidence = 0.4;
return true;
@@ -6786,6 +6804,8 @@
FOURCC("heic"), // HEIF image
FOURCC("msf1"), // HEIF image sequence
FOURCC("hevc"), // HEIF image sequence
+ FOURCC("avif"), // AVIF image
+ FOURCC("avis"), // AVIF image sequence
};
for (size_t i = 0;
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index bafc7f5..542a3e6 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -144,6 +144,7 @@
bool mIsHeif;
bool mHasMoovBox;
bool mPreferHeif;
+ bool mIsAvif;
Track *mFirstTrack, *mLastTrack;
diff --git a/media/extractors/wav/WAVExtractor.cpp b/media/extractors/wav/WAVExtractor.cpp
index d19447a..901b29d 100644
--- a/media/extractors/wav/WAVExtractor.cpp
+++ b/media/extractors/wav/WAVExtractor.cpp
@@ -95,9 +95,9 @@
AMediaFormat *mMeta;
uint16_t mWaveFormat;
const bool mOutputFloat;
- int32_t mSampleRate;
- int32_t mNumChannels;
- int32_t mBitsPerSample;
+ uint32_t mSampleRate;
+ uint32_t mNumChannels;
+ uint32_t mBitsPerSample;
off64_t mOffset;
size_t mSize;
bool mStarted;
@@ -379,9 +379,9 @@
mOffset(offset),
mSize(size),
mStarted(false) {
- CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, &mSampleRate));
- CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, &mNumChannels));
- CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, &mBitsPerSample));
+ CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_SAMPLE_RATE, (int32_t*) &mSampleRate));
+ CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_CHANNEL_COUNT, (int32_t*) &mNumChannels));
+ CHECK(AMediaFormat_getInt32(mMeta, AMEDIAFORMAT_KEY_BITS_PER_SAMPLE, (int32_t*) &mBitsPerSample));
}
WAVSource::~WAVSource() {
@@ -472,7 +472,7 @@
}
const size_t maxBytesAvailable =
- (mCurrentPos - mOffset >= (off64_t)mSize)
+ (mCurrentPos < mOffset || mCurrentPos - mOffset >= (off64_t)mSize)
? 0 : mSize - (mCurrentPos - mOffset);
if (maxBytesToRead > maxBytesAvailable) {
diff --git a/media/libaaudio/src/Android.bp b/media/libaaudio/src/Android.bp
index 328ceda..aafcccc 100644
--- a/media/libaaudio/src/Android.bp
+++ b/media/libaaudio/src/Android.bp
@@ -21,6 +21,7 @@
],
cflags: [
+ "-Wthread-safety",
"-Wno-unused-parameter",
"-Wall",
"-Werror",
diff --git a/media/libaaudio/src/client/AudioStreamInternal.cpp b/media/libaaudio/src/client/AudioStreamInternal.cpp
index c2dcd35..809c76e 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.cpp
+++ b/media/libaaudio/src/client/AudioStreamInternal.cpp
@@ -418,7 +418,6 @@
}
}
-// This must be called under mStreamLock.
aaudio_result_t AudioStreamInternal::requestStop_l() {
aaudio_result_t result = stopCallback_l();
if (result != AAUDIO_OK) {
@@ -428,7 +427,7 @@
// The stream may have been unlocked temporarily to let a callback finish
// and the callback may have stopped the stream.
// Check to make sure the stream still needs to be stopped.
- // See also AudioStream::safeStop().
+ // See also AudioStream::safeStop_l().
if (!(isActive() || getState() == AAUDIO_STREAM_STATE_DISCONNECTED)) {
ALOGD("%s() returning early, not active or disconnected", __func__);
return AAUDIO_OK;
@@ -810,15 +809,6 @@
return mBufferCapacityInFrames;
}
-aaudio_result_t AudioStreamInternal::joinThread(void** returnArg) {
- return AudioStream::joinThread(returnArg, calculateReasonableTimeout(getFramesPerBurst()));
-}
-
-// This must be called under mStreamLock.
-aaudio_result_t AudioStreamInternal::joinThread_l(void** returnArg) {
- return AudioStream::joinThread_l(returnArg, calculateReasonableTimeout(getFramesPerBurst()));
-}
-
bool AudioStreamInternal::isClockModelInControl() const {
return isActive() && mAudioEndpoint->isFreeRunning() && mClockModel.isRunning();
}
diff --git a/media/libaaudio/src/client/AudioStreamInternal.h b/media/libaaudio/src/client/AudioStreamInternal.h
index 1838b53..fbe4c13 100644
--- a/media/libaaudio/src/client/AudioStreamInternal.h
+++ b/media/libaaudio/src/client/AudioStreamInternal.h
@@ -44,10 +44,6 @@
AudioStreamInternal(AAudioServiceInterface &serviceInterface, bool inService);
virtual ~AudioStreamInternal();
- aaudio_result_t requestStart_l() override;
-
- aaudio_result_t requestStop_l() override;
-
aaudio_result_t getTimestamp(clockid_t clockId,
int64_t *framePosition,
int64_t *timeNanoseconds) override;
@@ -56,8 +52,6 @@
aaudio_result_t open(const AudioStreamBuilder &builder) override;
- aaudio_result_t release_l() override;
-
aaudio_result_t setBufferSize(int32_t requestedFrames) override;
int32_t getBufferSize() const override;
@@ -72,12 +66,9 @@
aaudio_result_t unregisterThread() override;
- aaudio_result_t joinThread(void** returnArg);
-
// Called internally from 'C'
virtual void *callbackLoop() = 0;
-
bool isMMap() override {
return true;
}
@@ -96,6 +87,10 @@
}
protected:
+ aaudio_result_t requestStart_l() REQUIRES(mStreamLock) override;
+ aaudio_result_t requestStop_l() REQUIRES(mStreamLock) override;
+
+ aaudio_result_t release_l() REQUIRES(mStreamLock) override;
aaudio_result_t processData(void *buffer,
int32_t numFrames,
@@ -119,8 +114,6 @@
aaudio_result_t stopCallback_l();
- aaudio_result_t joinThread_l(void** returnArg);
-
virtual void prepareBuffersForStart() {}
virtual void advanceClientToMatchServerPosition(int32_t serverMargin = 0) = 0;
diff --git a/media/libaaudio/src/core/AudioStream.cpp b/media/libaaudio/src/core/AudioStream.cpp
index ba86170..57c4c16 100644
--- a/media/libaaudio/src/core/AudioStream.cpp
+++ b/media/libaaudio/src/core/AudioStream.cpp
@@ -248,7 +248,7 @@
aaudio_result_t AudioStream::systemStopFromCallback() {
std::lock_guard<std::mutex> lock(mStreamLock);
- aaudio_result_t result = safeStop();
+ aaudio_result_t result = safeStop_l();
if (result == AAUDIO_OK) {
// We only call this for logging in "dumpsys audio". So ignore return code.
(void) mPlayerBase->stop();
@@ -262,7 +262,7 @@
ALOGE("stream cannot be stopped by calling from a callback!");
return AAUDIO_ERROR_INVALID_STATE;
}
- aaudio_result_t result = safeStop();
+ aaudio_result_t result = safeStop_l();
if (result == AAUDIO_OK) {
// We only call this for logging in "dumpsys audio". So ignore return code.
(void) mPlayerBase->stop();
@@ -270,8 +270,7 @@
return result;
}
-// This must be called under mStreamLock.
-aaudio_result_t AudioStream::safeStop() {
+aaudio_result_t AudioStream::safeStop_l() {
switch (getState()) {
// Proceed with stopping.
@@ -472,15 +471,14 @@
}
}
-aaudio_result_t AudioStream::joinThread(void** returnArg, int64_t timeoutNanoseconds) {
+aaudio_result_t AudioStream::joinThread(void** returnArg) {
// This may get temporarily unlocked in the MMAP release() when joining callback threads.
std::lock_guard<std::mutex> lock(mStreamLock);
- return joinThread_l(returnArg, timeoutNanoseconds);
+ return joinThread_l(returnArg);
}
// This must be called under mStreamLock.
-aaudio_result_t AudioStream::joinThread_l(void** returnArg, int64_t /* timeoutNanoseconds */)
-{
+aaudio_result_t AudioStream::joinThread_l(void** returnArg) {
if (!mHasThread) {
ALOGD("joinThread() - but has no thread");
return AAUDIO_ERROR_INVALID_STATE;
@@ -492,13 +490,7 @@
// Called from an app thread. Not the callback.
// Unlock because the callback may be trying to stop the stream but is blocked.
mStreamLock.unlock();
-#if 0
- // TODO implement equivalent of pthread_timedjoin_np()
- struct timespec abstime;
- int err = pthread_timedjoin_np(mThread, returnArg, &abstime);
-#else
int err = pthread_join(mThread, returnArg);
-#endif
mStreamLock.lock();
if (err) {
ALOGE("%s() pthread_join() returns err = %d", __func__, err);
@@ -614,7 +606,7 @@
}
if (audioStream) {
// No pan and only left volume is taken into account from IPLayer interface
- audioStream->setDuckAndMuteVolume(mVolumeMultiplierL /* * mPanMultiplierL */);
+ audioStream->setDuckAndMuteVolume(mVolumeMultiplierL /* mPanMultiplierL */);
}
return android::NO_ERROR;
}
diff --git a/media/libaaudio/src/core/AudioStream.h b/media/libaaudio/src/core/AudioStream.h
index d9a9d8e..510ead8 100644
--- a/media/libaaudio/src/core/AudioStream.h
+++ b/media/libaaudio/src/core/AudioStream.h
@@ -20,11 +20,13 @@
#include <atomic>
#include <mutex>
#include <stdint.h>
-#include <aaudio/AAudio.h>
+
+#include <android-base/thread_annotations.h>
#include <binder/IServiceManager.h>
#include <binder/Status.h>
#include <utils/StrongPointer.h>
+#include <aaudio/AAudio.h>
#include <media/AudioSystem.h>
#include <media/PlayerBase.h>
#include <media/VolumeShaper.h>
@@ -57,11 +59,6 @@
protected:
- /* Asynchronous requests.
- * Use waitForStateChange() to wait for completion.
- */
- virtual aaudio_result_t requestStart_l() = 0;
-
/**
* Check the state to see if Pause is currently legal.
*
@@ -80,17 +77,22 @@
return false;
}
- virtual aaudio_result_t requestPause_l() {
+ /* Asynchronous requests.
+ * Use waitForStateChange() to wait for completion.
+ */
+ virtual aaudio_result_t requestStart_l() REQUIRES(mStreamLock) = 0;
+
+ virtual aaudio_result_t requestPause_l() REQUIRES(mStreamLock) {
// Only implement this for OUTPUT streams.
return AAUDIO_ERROR_UNIMPLEMENTED;
}
- virtual aaudio_result_t requestFlush_l() {
+ virtual aaudio_result_t requestFlush_l() REQUIRES(mStreamLock) {
// Only implement this for OUTPUT streams.
return AAUDIO_ERROR_UNIMPLEMENTED;
}
- virtual aaudio_result_t requestStop_l() = 0;
+ virtual aaudio_result_t requestStop_l() REQUIRES(mStreamLock) = 0;
public:
virtual aaudio_result_t getTimestamp(clockid_t clockId,
@@ -130,11 +132,12 @@
* The AAudioStream_close() method releases if needed and then closes.
*/
+protected:
/**
* Free any hardware or system resources from the open() call.
* It is safe to call release_l() multiple times.
*/
- virtual aaudio_result_t release_l() {
+ virtual aaudio_result_t release_l() REQUIRES(mStreamLock) {
setState(AAUDIO_STREAM_STATE_CLOSING);
return AAUDIO_OK;
}
@@ -143,7 +146,7 @@
* Free any resources not already freed by release_l().
* Assume release_l() already called.
*/
- virtual void close_l() {
+ virtual void close_l() REQUIRES(mStreamLock) {
// Releasing the stream will set the state to CLOSING.
assert(getState() == AAUDIO_STREAM_STATE_CLOSING);
// setState() prevents a transition from CLOSING to any state other than CLOSED.
@@ -151,6 +154,7 @@
setState(AAUDIO_STREAM_STATE_CLOSED);
}
+public:
// This is only used to identify a stream in the logs without
// revealing any pointers.
aaudio_stream_id_t getId() {
@@ -163,7 +167,7 @@
aaudio_audio_thread_proc_t threadProc,
void *threadArg);
- aaudio_result_t joinThread(void **returnArg, int64_t timeoutNanoseconds);
+ aaudio_result_t joinThread(void **returnArg);
virtual aaudio_result_t registerThread() {
return AAUDIO_OK;
@@ -473,9 +477,8 @@
private:
// Use a weak pointer so the AudioStream can be deleted.
-
std::mutex mParentLock;
- android::wp<AudioStream> mParent;
+ android::wp<AudioStream> mParent GUARDED_BY(mParentLock);
aaudio_result_t mResult = AAUDIO_OK;
bool mRegistered = false;
};
@@ -533,7 +536,7 @@
mSessionId = sessionId;
}
- aaudio_result_t joinThread_l(void **returnArg, int64_t timeoutNanoseconds);
+ aaudio_result_t joinThread_l(void **returnArg) REQUIRES(mStreamLock);
std::atomic<bool> mCallbackEnabled{false};
@@ -601,14 +604,16 @@
std::string mMetricsId; // set once during open()
+ std::mutex mStreamLock;
+
private:
- aaudio_result_t safeStop();
+ aaudio_result_t safeStop_l() REQUIRES(mStreamLock);
/**
* Release then close the stream.
*/
- void releaseCloseFinal_l() {
+ void releaseCloseFinal_l() REQUIRES(mStreamLock) {
if (getState() != AAUDIO_STREAM_STATE_CLOSING) { // not already released?
// Ignore result and keep closing.
(void) release_l();
@@ -616,8 +621,6 @@
close_l();
}
- std::mutex mStreamLock;
-
const android::sp<MyPlayerBase> mPlayerBase;
// These do not change after open().
@@ -656,8 +659,8 @@
std::atomic<pid_t> mErrorCallbackThread{CALLBACK_THREAD_NONE};
// background thread ----------------------------------
- bool mHasThread = false;
- pthread_t mThread = {};
+ bool mHasThread GUARDED_BY(mStreamLock) = false;
+ pthread_t mThread GUARDED_BY(mStreamLock) = {};
// These are set by the application thread and then read by the audio pthread.
std::atomic<int64_t> mPeriodNanoseconds; // for tuning SCHED_FIFO threads
diff --git a/media/libaaudio/src/legacy/AudioStreamRecord.h b/media/libaaudio/src/legacy/AudioStreamRecord.h
index fe9689f..b2f8ba5 100644
--- a/media/libaaudio/src/legacy/AudioStreamRecord.h
+++ b/media/libaaudio/src/legacy/AudioStreamRecord.h
@@ -41,9 +41,6 @@
aaudio_result_t release_l() override;
void close_l() override;
- aaudio_result_t requestStart_l() override;
- aaudio_result_t requestStop_l() override;
-
virtual aaudio_result_t getTimestamp(clockid_t clockId,
int64_t *framePosition,
int64_t *timeNanoseconds) override;
@@ -77,6 +74,9 @@
protected:
+ aaudio_result_t requestStart_l() REQUIRES(mStreamLock) override;
+ aaudio_result_t requestStop_l() REQUIRES(mStreamLock) override;
+
int32_t getFramesPerBurstFromDevice() const override;
int32_t getBufferCapacityFromDevice() const override;
diff --git a/media/libaaudio/src/legacy/AudioStreamTrack.h b/media/libaaudio/src/legacy/AudioStreamTrack.h
index 654ea9b..f604871 100644
--- a/media/libaaudio/src/legacy/AudioStreamTrack.h
+++ b/media/libaaudio/src/legacy/AudioStreamTrack.h
@@ -44,11 +44,13 @@
aaudio_result_t release_l() override;
void close_l() override;
- aaudio_result_t requestStart_l() override;
- aaudio_result_t requestPause_l() override;
- aaudio_result_t requestFlush_l() override;
- aaudio_result_t requestStop_l() override;
+protected:
+ aaudio_result_t requestStart_l() REQUIRES(mStreamLock) override;
+ aaudio_result_t requestPause_l() REQUIRES(mStreamLock) override;
+ aaudio_result_t requestFlush_l() REQUIRES(mStreamLock) override;
+ aaudio_result_t requestStop_l() REQUIRES(mStreamLock) override;
+public:
bool isFlushSupported() const override {
// Only implement FLUSH for OUTPUT streams.
return true;
diff --git a/media/libaudioclient/AidlConversion.cpp b/media/libaudioclient/AidlConversion.cpp
index 95a6a4a..d362d8f 100644
--- a/media/libaudioclient/AidlConversion.cpp
+++ b/media/libaudioclient/AidlConversion.cpp
@@ -14,8 +14,6 @@
* limitations under the License.
*/
-#include <limits>
-
#define LOG_TAG "AidlConversion"
//#define LOG_NDEBUG 0
#include <system/audio.h>
@@ -23,12 +21,7 @@
#include "media/AidlConversion.h"
-#define VALUE_OR_RETURN(result) \
- ({ \
- auto _tmp = (result); \
- if (!_tmp.ok()) return unexpected(_tmp.error()); \
- _tmp.value(); \
- })
+#include <media/ShmemCompat.h>
////////////////////////////////////////////////////////////////////////////////////////////////////
// Utilities
@@ -118,27 +111,30 @@
}
////////////////////////////////////////////////////////////////////////////////////////////////////
+// Utilities for working with AIDL unions.
+// UNION_GET(obj, fieldname) returns a ConversionResult<T> containing either the strongly-typed
+// value of the respective field, or BAD_VALUE if the union is not set to the requested field.
+// UNION_SET(obj, fieldname, value) sets the requested field to the given value.
-template<typename To, typename From>
-ConversionResult<To> convertIntegral(From from) {
- // Special handling is required for signed / vs. unsigned comparisons, since otherwise we may
- // have the signed converted to unsigned and produce wrong results.
- if (std::is_signed_v<From> && !std::is_signed_v<To>) {
- if (from < 0 || from > std::numeric_limits<To>::max()) {
- return unexpected(BAD_VALUE);
- }
- } else if (std::is_signed_v<To> && !std::is_signed_v<From>) {
- if (from > std::numeric_limits<To>::max()) {
- return unexpected(BAD_VALUE);
- }
- } else {
- if (from < std::numeric_limits<To>::min() || from > std::numeric_limits<To>::max()) {
- return unexpected(BAD_VALUE);
- }
+template<typename T, typename T::Tag tag>
+using UnionFieldType = std::decay_t<decltype(std::declval<T>().template get<tag>())>;
+
+template<typename T, typename T::Tag tag>
+ConversionResult<UnionFieldType<T, tag>> unionGetField(const T& u) {
+ if (u.getTag() != tag) {
+ return unexpected(BAD_VALUE);
}
- return static_cast<To>(from);
+ return u.template get<tag>();
}
+#define UNION_GET(u, field) \
+ unionGetField<std::decay_t<decltype(u)>, std::decay_t<decltype(u)>::Tag::field>(u)
+
+#define UNION_SET(u, field, value) \
+ (u).set<std::decay_t<decltype(u)>::Tag::field>(value)
+
+////////////////////////////////////////////////////////////////////////////////////////////////////
+
template<typename To, typename From>
ConversionResult<To> convertReinterpret(From from) {
static_assert(sizeof(From) == sizeof(To));
@@ -210,6 +206,90 @@
////////////////////////////////////////////////////////////////////////////////////////////////////
// Converters
+status_t aidl2legacy_string(std::string_view aidl, char* dest, size_t maxSize) {
+ if (aidl.size() > maxSize - 1) {
+ return BAD_VALUE;
+ }
+ aidl.copy(dest, aidl.size());
+ dest[aidl.size()] = '\0';
+ return OK;
+}
+
+ConversionResult<std::string> legacy2aidl_string(const char* legacy, size_t maxSize) {
+ if (legacy == nullptr) {
+ return unexpected(BAD_VALUE);
+ }
+ if (strnlen(legacy, maxSize) == maxSize) {
+ // No null-terminator.
+ return unexpected(BAD_VALUE);
+ }
+ return std::string(legacy);
+}
+
+ConversionResult<audio_module_handle_t> aidl2legacy_int32_t_audio_module_handle_t(int32_t aidl) {
+ return convertReinterpret<audio_module_handle_t>(aidl);
+}
+
+ConversionResult<int32_t> legacy2aidl_audio_module_handle_t_int32_t(audio_module_handle_t legacy) {
+ return convertReinterpret<int32_t>(legacy);
+}
+
+ConversionResult<audio_io_handle_t> aidl2legacy_int32_t_audio_io_handle_t(int32_t aidl) {
+ return convertReinterpret<audio_io_handle_t>(aidl);
+}
+
+ConversionResult<int32_t> legacy2aidl_audio_io_handle_t_int32_t(audio_io_handle_t legacy) {
+ return convertReinterpret<int32_t>(legacy);
+}
+
+ConversionResult<audio_port_handle_t> aidl2legacy_int32_t_audio_port_handle_t(int32_t aidl) {
+ return convertReinterpret<audio_port_handle_t>(aidl);
+}
+
+ConversionResult<int32_t> legacy2aidl_audio_port_handle_t_int32_t(audio_port_handle_t legacy) {
+ return convertReinterpret<int32_t>(legacy);
+}
+
+ConversionResult<audio_patch_handle_t> aidl2legacy_int32_t_audio_patch_handle_t(int32_t aidl) {
+ return convertReinterpret<audio_patch_handle_t>(aidl);
+}
+
+ConversionResult<int32_t> legacy2aidl_audio_patch_handle_t_int32_t(audio_patch_handle_t legacy) {
+ return convertReinterpret<int32_t>(legacy);
+}
+
+ConversionResult<audio_unique_id_t> aidl2legacy_int32_t_audio_unique_id_t(int32_t aidl) {
+ return convertReinterpret<audio_unique_id_t>(aidl);
+}
+
+ConversionResult<int32_t> legacy2aidl_audio_unique_id_t_int32_t(audio_unique_id_t legacy) {
+ return convertReinterpret<int32_t>(legacy);
+}
+
+ConversionResult<pid_t> aidl2legacy_int32_t_pid_t(int32_t aidl) {
+ return convertReinterpret<pid_t>(aidl);
+}
+
+ConversionResult<int32_t> legacy2aidl_pid_t_int32_t(pid_t legacy) {
+ return convertReinterpret<int32_t>(legacy);
+}
+
+ConversionResult<uid_t> aidl2legacy_int32_t_uid_t(int32_t aidl) {
+ return convertReinterpret<uid_t>(aidl);
+}
+
+ConversionResult<int32_t> legacy2aidl_uid_t_int32_t(uid_t legacy) {
+ return convertReinterpret<int32_t>(legacy);
+}
+
+ConversionResult<String16> aidl2legacy_string_view_String16(std::string_view aidl) {
+ return String16(aidl.data(), aidl.size());
+}
+
+ConversionResult<std::string> legacy2aidl_String16_string(const String16& legacy) {
+ return std::string(String8(legacy).c_str());
+}
+
// The legacy enum is unnamed. Thus, we use int.
ConversionResult<int> aidl2legacy_AudioPortConfigType(media::AudioPortConfigType aidl) {
switch (aidl) {
@@ -642,14 +722,13 @@
}
ConversionResult<audio_output_flags_t> aidl2legacy_audio_output_flags_mask(int32_t aidl) {
- using LegacyMask = std::underlying_type_t<audio_output_flags_t>;
-
- LegacyMask converted = VALUE_OR_RETURN(
- (convertBitmask<LegacyMask, int32_t, audio_output_flags_t, media::AudioOutputFlags>(
- aidl, aidl2legacy_AudioOutputFlags_audio_output_flags_t,
- index2enum_index<media::AudioOutputFlags>,
- enumToMask_bitmask<LegacyMask, audio_output_flags_t>)));
- return convertReinterpret<audio_output_flags_t>(converted);
+ return convertBitmask<audio_output_flags_t,
+ int32_t,
+ audio_output_flags_t,
+ media::AudioOutputFlags>(
+ aidl, aidl2legacy_AudioOutputFlags_audio_output_flags_t,
+ index2enum_index<media::AudioOutputFlags>,
+ enumToMask_bitmask<audio_output_flags_t, audio_output_flags_t>);
}
ConversionResult<int32_t> legacy2aidl_audio_output_flags_mask(audio_output_flags_t legacy) {
@@ -665,27 +744,18 @@
ConversionResult<audio_io_flags> aidl2legacy_AudioIoFlags_audio_io_flags(
const media::AudioIoFlags& aidl, media::AudioPortRole role, media::AudioPortType type) {
audio_io_flags legacy;
- // Our way of representing a union in AIDL is to have multiple vectors and require that at most
- // one of the them has size 1 and the rest are empty.
- size_t totalSize = aidl.input.size() + aidl.output.size();
- if (totalSize > 1) {
- return unexpected(BAD_VALUE);
- }
-
Direction dir = VALUE_OR_RETURN(direction(role, type));
switch (dir) {
- case Direction::INPUT:
- if (aidl.input.empty()) {
- return unexpected(BAD_VALUE);
- }
- legacy.input = VALUE_OR_RETURN(aidl2legacy_audio_input_flags_mask(aidl.input[0]));
+ case Direction::INPUT: {
+ legacy.input = VALUE_OR_RETURN(
+ aidl2legacy_audio_input_flags_mask(VALUE_OR_RETURN(UNION_GET(aidl, input))));
+ }
break;
- case Direction::OUTPUT:
- if (aidl.output.empty()) {
- return unexpected(BAD_VALUE);
- }
- legacy.output = VALUE_OR_RETURN(aidl2legacy_audio_output_flags_mask(aidl.output[0]));
+ case Direction::OUTPUT: {
+ legacy.output = VALUE_OR_RETURN(
+ aidl2legacy_audio_output_flags_mask(VALUE_OR_RETURN(UNION_GET(aidl, output))));
+ }
break;
}
@@ -699,11 +769,12 @@
Direction dir = VALUE_OR_RETURN(direction(role, type));
switch (dir) {
case Direction::INPUT:
- aidl.input.push_back(VALUE_OR_RETURN(legacy2aidl_audio_input_flags_mask(legacy.input)));
+ UNION_SET(aidl, input,
+ VALUE_OR_RETURN(legacy2aidl_audio_input_flags_mask(legacy.input)));
break;
case Direction::OUTPUT:
- aidl.output.push_back(
- VALUE_OR_RETURN(legacy2aidl_audio_output_flags_mask(legacy.output)));
+ UNION_SET(aidl, output,
+ VALUE_OR_RETURN(legacy2aidl_audio_output_flags_mask(legacy.output)));
break;
}
return aidl;
@@ -712,26 +783,19 @@
ConversionResult<audio_port_config_device_ext> aidl2legacy_AudioPortConfigDeviceExt(
const media::AudioPortConfigDeviceExt& aidl) {
audio_port_config_device_ext legacy;
- legacy.hw_module = VALUE_OR_RETURN(convertReinterpret<audio_module_handle_t>(aidl.hwModule));
+ legacy.hw_module = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_module_handle_t(aidl.hwModule));
legacy.type = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_devices_t(aidl.type));
- if (aidl.address.size() > AUDIO_DEVICE_MAX_ADDRESS_LEN - 1) {
- return unexpected(BAD_VALUE);
- }
- std::strcpy(legacy.address, aidl.address.c_str());
+ RETURN_IF_ERROR(aidl2legacy_string(aidl.address, legacy.address, AUDIO_DEVICE_MAX_ADDRESS_LEN));
return legacy;
}
ConversionResult<media::AudioPortConfigDeviceExt> legacy2aidl_AudioPortConfigDeviceExt(
const audio_port_config_device_ext& legacy) {
media::AudioPortConfigDeviceExt aidl;
- aidl.hwModule = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy.hw_module));
+ aidl.hwModule = VALUE_OR_RETURN(legacy2aidl_audio_module_handle_t_int32_t(legacy.hw_module));
aidl.type = VALUE_OR_RETURN(legacy2aidl_audio_devices_t_int32_t(legacy.type));
-
- if (strnlen(legacy.address, AUDIO_DEVICE_MAX_ADDRESS_LEN) == AUDIO_DEVICE_MAX_ADDRESS_LEN) {
- // No null-terminator.
- return unexpected(BAD_VALUE);
- }
- aidl.address = legacy.address;
+ aidl.address = VALUE_OR_RETURN(
+ legacy2aidl_string(legacy.address, AUDIO_DEVICE_MAX_ADDRESS_LEN));
return aidl;
}
@@ -818,6 +882,9 @@
ConversionResult<audio_source_t> aidl2legacy_AudioSourceType_audio_source_t(
media::AudioSourceType aidl) {
switch (aidl) {
+ case media::AudioSourceType::INVALID:
+ // This value does not have an enum
+ return AUDIO_SOURCE_INVALID;
case media::AudioSourceType::DEFAULT:
return AUDIO_SOURCE_DEFAULT;
case media::AudioSourceType::MIC:
@@ -854,6 +921,8 @@
ConversionResult<media::AudioSourceType> legacy2aidl_audio_source_t_AudioSourceType(
audio_source_t legacy) {
switch (legacy) {
+ case AUDIO_SOURCE_INVALID:
+ return media::AudioSourceType::INVALID;
case AUDIO_SOURCE_DEFAULT:
return media::AudioSourceType::DEFAULT;
case AUDIO_SOURCE_MIC:
@@ -887,32 +956,12 @@
}
}
-ConversionResult<audio_session_t> aidl2legacy_AudioSessionType_audio_session_t(
- media::AudioSessionType aidl) {
- switch (aidl) {
- case media::AudioSessionType::DEVICE:
- return AUDIO_SESSION_DEVICE;
- case media::AudioSessionType::OUTPUT_STAGE:
- return AUDIO_SESSION_OUTPUT_STAGE;
- case media::AudioSessionType::OUTPUT_MIX:
- return AUDIO_SESSION_OUTPUT_MIX;
- default:
- return unexpected(BAD_VALUE);
- }
+ConversionResult<audio_session_t> aidl2legacy_int32_t_audio_session_t(int32_t aidl) {
+ return convertReinterpret<audio_session_t>(aidl);
}
-ConversionResult<media::AudioSessionType> legacy2aidl_audio_session_t_AudioSessionType(
- audio_session_t legacy) {
- switch (legacy) {
- case AUDIO_SESSION_DEVICE:
- return media::AudioSessionType::DEVICE;
- case AUDIO_SESSION_OUTPUT_STAGE:
- return media::AudioSessionType::OUTPUT_STAGE;
- case AUDIO_SESSION_OUTPUT_MIX:
- return media::AudioSessionType::OUTPUT_MIX;
- default:
- return unexpected(BAD_VALUE);
- }
+ConversionResult<int32_t> legacy2aidl_audio_session_t_int32_t(audio_session_t legacy) {
+ return convertReinterpret<int32_t>(legacy);
}
// This type is unnamed in the original definition, thus we name it here.
@@ -922,36 +971,22 @@
const media::AudioPortConfigMixExtUseCase& aidl, media::AudioPortRole role) {
audio_port_config_mix_ext_usecase legacy;
- // Our way of representing a union in AIDL is to have multiple vectors and require that exactly
- // one of the them has size 1 and the rest are empty.
- size_t totalSize = aidl.stream.size() + aidl.source.size();
- if (totalSize > 1) {
- return unexpected(BAD_VALUE);
- }
-
switch (role) {
case media::AudioPortRole::NONE:
- if (totalSize != 0) {
- return unexpected(BAD_VALUE);
- }
+ // Just verify that the union is empty.
+ VALUE_OR_RETURN(UNION_GET(aidl, nothing));
break;
case media::AudioPortRole::SOURCE:
// This is not a bug. A SOURCE role corresponds to the stream field.
- if (aidl.stream.empty()) {
- return unexpected(BAD_VALUE);
- }
- legacy.stream = VALUE_OR_RETURN(
- aidl2legacy_AudioStreamType_audio_stream_type_t(aidl.stream[0]));
+ legacy.stream = VALUE_OR_RETURN(aidl2legacy_AudioStreamType_audio_stream_type_t(
+ VALUE_OR_RETURN(UNION_GET(aidl, stream))));
break;
case media::AudioPortRole::SINK:
// This is not a bug. A SINK role corresponds to the source field.
- if (aidl.source.empty()) {
- return unexpected(BAD_VALUE);
- }
- legacy.source =
- VALUE_OR_RETURN(aidl2legacy_AudioSourceType_audio_source_t(aidl.source[0]));
+ legacy.source = VALUE_OR_RETURN(aidl2legacy_AudioSourceType_audio_source_t(
+ VALUE_OR_RETURN(UNION_GET(aidl, source))));
break;
default:
@@ -966,17 +1001,17 @@
switch (role) {
case AUDIO_PORT_ROLE_NONE:
+ UNION_SET(aidl, nothing, false);
break;
case AUDIO_PORT_ROLE_SOURCE:
// This is not a bug. A SOURCE role corresponds to the stream field.
- aidl.stream.push_back(VALUE_OR_RETURN(
- legacy2aidl_audio_stream_type_t_AudioStreamType(
- legacy.stream)));
+ UNION_SET(aidl, stream, VALUE_OR_RETURN(
+ legacy2aidl_audio_stream_type_t_AudioStreamType(legacy.stream)));
break;
case AUDIO_PORT_ROLE_SINK:
// This is not a bug. A SINK role corresponds to the source field.
- aidl.source.push_back(
- VALUE_OR_RETURN(legacy2aidl_audio_source_t_AudioSourceType(legacy.source)));
+ UNION_SET(aidl, source,
+ VALUE_OR_RETURN(legacy2aidl_audio_source_t_AudioSourceType(legacy.source)));
break;
default:
LOG_ALWAYS_FATAL("Shouldn't get here");
@@ -987,8 +1022,8 @@
ConversionResult<audio_port_config_mix_ext> aidl2legacy_AudioPortConfigMixExt(
const media::AudioPortConfigMixExt& aidl, media::AudioPortRole role) {
audio_port_config_mix_ext legacy;
- legacy.hw_module = VALUE_OR_RETURN(convertReinterpret<audio_module_handle_t>(aidl.hwModule));
- legacy.handle = VALUE_OR_RETURN(convertReinterpret<audio_io_handle_t>(aidl.handle));
+ legacy.hw_module = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_module_handle_t(aidl.hwModule));
+ legacy.handle = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_io_handle_t(aidl.handle));
legacy.usecase = VALUE_OR_RETURN(aidl2legacy_AudioPortConfigMixExtUseCase(aidl.usecase, role));
return legacy;
}
@@ -996,8 +1031,8 @@
ConversionResult<media::AudioPortConfigMixExt> legacy2aidl_AudioPortConfigMixExt(
const audio_port_config_mix_ext& legacy, audio_port_role_t role) {
media::AudioPortConfigMixExt aidl;
- aidl.hwModule = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy.hw_module));
- aidl.handle = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy.handle));
+ aidl.hwModule = VALUE_OR_RETURN(legacy2aidl_audio_module_handle_t_int32_t(legacy.hw_module));
+ aidl.handle = VALUE_OR_RETURN(legacy2aidl_audio_io_handle_t_int32_t(legacy.handle));
aidl.usecase = VALUE_OR_RETURN(legacy2aidl_AudioPortConfigMixExtUseCase(legacy.usecase, role));
return aidl;
}
@@ -1005,14 +1040,14 @@
ConversionResult<audio_port_config_session_ext> aidl2legacy_AudioPortConfigSessionExt(
const media::AudioPortConfigSessionExt& aidl) {
audio_port_config_session_ext legacy;
- legacy.session = VALUE_OR_RETURN(aidl2legacy_AudioSessionType_audio_session_t(aidl.session));
+ legacy.session = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_session_t(aidl.session));
return legacy;
}
ConversionResult<media::AudioPortConfigSessionExt> legacy2aidl_AudioPortConfigSessionExt(
const audio_port_config_session_ext& legacy) {
media::AudioPortConfigSessionExt aidl;
- aidl.session = VALUE_OR_RETURN(legacy2aidl_audio_session_t_AudioSessionType(legacy.session));
+ aidl.session = VALUE_OR_RETURN(legacy2aidl_audio_session_t_int32_t(legacy.session));
return aidl;
}
@@ -1025,34 +1060,22 @@
audio_port_config_ext legacy;
// Our way of representing a union in AIDL is to have multiple vectors and require that at most
// one of the them has size 1 and the rest are empty.
- size_t totalSize = aidl.device.size() + aidl.mix.size() + aidl.session.size();
- if (totalSize > 1) {
- return unexpected(BAD_VALUE);
- }
switch (type) {
case media::AudioPortType::NONE:
- if (totalSize != 0) {
- return unexpected(BAD_VALUE);
- }
+ // Just verify that the union is empty.
+ VALUE_OR_RETURN(UNION_GET(aidl, nothing));
break;
case media::AudioPortType::DEVICE:
- if (aidl.device.empty()) {
- return unexpected(BAD_VALUE);
- }
- legacy.device = VALUE_OR_RETURN(aidl2legacy_AudioPortConfigDeviceExt(aidl.device[0]));
+ legacy.device = VALUE_OR_RETURN(
+ aidl2legacy_AudioPortConfigDeviceExt(VALUE_OR_RETURN(UNION_GET(aidl, device))));
break;
case media::AudioPortType::MIX:
- if (aidl.mix.empty()) {
- return unexpected(BAD_VALUE);
- }
- legacy.mix = VALUE_OR_RETURN(aidl2legacy_AudioPortConfigMixExt(aidl.mix[0], role));
+ legacy.mix = VALUE_OR_RETURN(
+ aidl2legacy_AudioPortConfigMixExt(VALUE_OR_RETURN(UNION_GET(aidl, mix)), role));
break;
case media::AudioPortType::SESSION:
- if (aidl.session.empty()) {
- return unexpected(BAD_VALUE);
- }
- legacy.session =
- VALUE_OR_RETURN(aidl2legacy_AudioPortConfigSessionExt(aidl.session[0]));
+ legacy.session = VALUE_OR_RETURN(aidl2legacy_AudioPortConfigSessionExt(
+ VALUE_OR_RETURN(UNION_GET(aidl, session))));
break;
default:
LOG_ALWAYS_FATAL("Shouldn't get here");
@@ -1066,18 +1089,19 @@
switch (type) {
case AUDIO_PORT_TYPE_NONE:
+ UNION_SET(aidl, nothing, false);
break;
case AUDIO_PORT_TYPE_DEVICE:
- aidl.device.push_back(
- VALUE_OR_RETURN(legacy2aidl_AudioPortConfigDeviceExt(legacy.device)));
+ UNION_SET(aidl, device,
+ VALUE_OR_RETURN(legacy2aidl_AudioPortConfigDeviceExt(legacy.device)));
break;
case AUDIO_PORT_TYPE_MIX:
- aidl.mix.push_back(
- VALUE_OR_RETURN(legacy2aidl_AudioPortConfigMixExt(legacy.mix, role)));
+ UNION_SET(aidl, mix,
+ VALUE_OR_RETURN(legacy2aidl_AudioPortConfigMixExt(legacy.mix, role)));
break;
case AUDIO_PORT_TYPE_SESSION:
- aidl.session.push_back(
- VALUE_OR_RETURN(legacy2aidl_AudioPortConfigSessionExt(legacy.session)));
+ UNION_SET(aidl, session,
+ VALUE_OR_RETURN(legacy2aidl_AudioPortConfigSessionExt(legacy.session)));
break;
default:
LOG_ALWAYS_FATAL("Shouldn't get here");
@@ -1088,7 +1112,7 @@
ConversionResult<audio_port_config> aidl2legacy_AudioPortConfig_audio_port_config(
const media::AudioPortConfig& aidl) {
audio_port_config legacy;
- legacy.id = VALUE_OR_RETURN(convertReinterpret<audio_port_handle_t>(aidl.id));
+ legacy.id = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_port_handle_t(aidl.id));
legacy.role = VALUE_OR_RETURN(aidl2legacy_AudioPortRole_audio_port_role_t(aidl.role));
legacy.type = VALUE_OR_RETURN(aidl2legacy_AudioPortType_audio_port_type_t(aidl.type));
legacy.config_mask = VALUE_OR_RETURN(aidl2legacy_int32_t_config_mask(aidl.configMask));
@@ -1117,7 +1141,7 @@
ConversionResult<media::AudioPortConfig> legacy2aidl_audio_port_config_AudioPortConfig(
const audio_port_config& legacy) {
media::AudioPortConfig aidl;
- aidl.id = VALUE_OR_RETURN(convertReinterpret<audio_port_handle_t>(legacy.id));
+ aidl.id = VALUE_OR_RETURN(legacy2aidl_audio_port_handle_t_int32_t(legacy.id));
aidl.role = VALUE_OR_RETURN(legacy2aidl_audio_port_role_t_AudioPortRole(legacy.role));
aidl.type = VALUE_OR_RETURN(legacy2aidl_audio_port_type_t_AudioPortType(legacy.type));
aidl.configMask = VALUE_OR_RETURN(legacy2aidl_config_mask_int32_t(legacy.config_mask));
@@ -1147,7 +1171,7 @@
ConversionResult<struct audio_patch> aidl2legacy_AudioPatch_audio_patch(
const media::AudioPatch& aidl) {
struct audio_patch legacy;
- legacy.id = VALUE_OR_RETURN(convertReinterpret<audio_patch_handle_t>(aidl.id));
+ legacy.id = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_patch_handle_t(aidl.id));
legacy.num_sinks = VALUE_OR_RETURN(convertIntegral<unsigned int>(aidl.sinks.size()));
if (legacy.num_sinks > AUDIO_PATCH_PORTS_MAX) {
return unexpected(BAD_VALUE);
@@ -1170,7 +1194,7 @@
ConversionResult<media::AudioPatch> legacy2aidl_audio_patch_AudioPatch(
const struct audio_patch& legacy) {
media::AudioPatch aidl;
- aidl.id = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy.id));
+ aidl.id = VALUE_OR_RETURN(legacy2aidl_audio_patch_handle_t_int32_t(legacy.id));
if (legacy.num_sinks > AUDIO_PATCH_PORTS_MAX) {
return unexpected(BAD_VALUE);
@@ -1192,7 +1216,7 @@
ConversionResult<sp<AudioIoDescriptor>> aidl2legacy_AudioIoDescriptor_AudioIoDescriptor(
const media::AudioIoDescriptor& aidl) {
sp<AudioIoDescriptor> legacy(new AudioIoDescriptor());
- legacy->mIoHandle = VALUE_OR_RETURN(convertReinterpret<audio_io_handle_t>(aidl.ioHandle));
+ legacy->mIoHandle = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_io_handle_t(aidl.ioHandle));
legacy->mPatch = VALUE_OR_RETURN(aidl2legacy_AudioPatch_audio_patch(aidl.patch));
legacy->mSamplingRate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.samplingRate));
legacy->mFormat = VALUE_OR_RETURN(aidl2legacy_AudioFormat_audio_format_t(aidl.format));
@@ -1201,22 +1225,459 @@
legacy->mFrameCount = VALUE_OR_RETURN(convertIntegral<size_t>(aidl.frameCount));
legacy->mFrameCountHAL = VALUE_OR_RETURN(convertIntegral<size_t>(aidl.frameCountHAL));
legacy->mLatency = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.latency));
- legacy->mPortId = VALUE_OR_RETURN(convertReinterpret<audio_port_handle_t>(aidl.portId));
+ legacy->mPortId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_port_handle_t(aidl.portId));
return legacy;
}
ConversionResult<media::AudioIoDescriptor> legacy2aidl_AudioIoDescriptor_AudioIoDescriptor(
const sp<AudioIoDescriptor>& legacy) {
media::AudioIoDescriptor aidl;
- aidl.ioHandle = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy->mIoHandle));
+ aidl.ioHandle = VALUE_OR_RETURN(legacy2aidl_audio_io_handle_t_int32_t(legacy->mIoHandle));
aidl.patch = VALUE_OR_RETURN(legacy2aidl_audio_patch_AudioPatch(legacy->mPatch));
aidl.samplingRate = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy->mSamplingRate));
aidl.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormat(legacy->mFormat));
- aidl.channelMask = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy->mChannelMask));
+ aidl.channelMask = VALUE_OR_RETURN(
+ legacy2aidl_audio_channel_mask_t_int32_t(legacy->mChannelMask));
aidl.frameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(legacy->mFrameCount));
aidl.frameCountHAL = VALUE_OR_RETURN(convertIntegral<int64_t>(legacy->mFrameCountHAL));
aidl.latency = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy->mLatency));
- aidl.portId = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy->mPortId));
+ aidl.portId = VALUE_OR_RETURN(legacy2aidl_audio_port_handle_t_int32_t(legacy->mPortId));
+ return aidl;
+}
+
+ConversionResult<AudioClient> aidl2legacy_AudioClient(const media::AudioClient& aidl) {
+ AudioClient legacy;
+ legacy.clientUid = VALUE_OR_RETURN(aidl2legacy_int32_t_uid_t(aidl.clientUid));
+ legacy.clientPid = VALUE_OR_RETURN(aidl2legacy_int32_t_pid_t(aidl.clientPid));
+ legacy.clientTid = VALUE_OR_RETURN(aidl2legacy_int32_t_pid_t(aidl.clientTid));
+ legacy.packageName = VALUE_OR_RETURN(aidl2legacy_string_view_String16(aidl.packageName));
+ return legacy;
+}
+
+ConversionResult<media::AudioClient> legacy2aidl_AudioClient(const AudioClient& legacy) {
+ media::AudioClient aidl;
+ aidl.clientUid = VALUE_OR_RETURN(legacy2aidl_uid_t_int32_t(legacy.clientUid));
+ aidl.clientPid = VALUE_OR_RETURN(legacy2aidl_pid_t_int32_t(legacy.clientPid));
+ aidl.clientTid = VALUE_OR_RETURN(legacy2aidl_pid_t_int32_t(legacy.clientTid));
+ aidl.packageName = VALUE_OR_RETURN(legacy2aidl_String16_string(legacy.packageName));
+ return aidl;
+}
+
+ConversionResult<audio_content_type_t>
+aidl2legacy_AudioContentType_audio_content_type_t(media::AudioContentType aidl) {
+ switch (aidl) {
+ case media::AudioContentType::UNKNOWN:
+ return AUDIO_CONTENT_TYPE_UNKNOWN;
+ case media::AudioContentType::SPEECH:
+ return AUDIO_CONTENT_TYPE_SPEECH;
+ case media::AudioContentType::MUSIC:
+ return AUDIO_CONTENT_TYPE_MUSIC;
+ case media::AudioContentType::MOVIE:
+ return AUDIO_CONTENT_TYPE_MOVIE;
+ case media::AudioContentType::SONIFICATION:
+ return AUDIO_CONTENT_TYPE_SONIFICATION;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<media::AudioContentType>
+legacy2aidl_audio_content_type_t_AudioContentType(audio_content_type_t legacy) {
+ switch (legacy) {
+ case AUDIO_CONTENT_TYPE_UNKNOWN:
+ return media::AudioContentType::UNKNOWN;
+ case AUDIO_CONTENT_TYPE_SPEECH:
+ return media::AudioContentType::SPEECH;
+ case AUDIO_CONTENT_TYPE_MUSIC:
+ return media::AudioContentType::MUSIC;
+ case AUDIO_CONTENT_TYPE_MOVIE:
+ return media::AudioContentType::MOVIE;
+ case AUDIO_CONTENT_TYPE_SONIFICATION:
+ return media::AudioContentType::SONIFICATION;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_usage_t>
+aidl2legacy_AudioUsage_audio_usage_t(media::AudioUsage aidl) {
+ switch (aidl) {
+ case media::AudioUsage::UNKNOWN:
+ return AUDIO_USAGE_UNKNOWN;
+ case media::AudioUsage::MEDIA:
+ return AUDIO_USAGE_MEDIA;
+ case media::AudioUsage::VOICE_COMMUNICATION:
+ return AUDIO_USAGE_VOICE_COMMUNICATION;
+ case media::AudioUsage::VOICE_COMMUNICATION_SIGNALLING:
+ return AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING;
+ case media::AudioUsage::ALARM:
+ return AUDIO_USAGE_ALARM;
+ case media::AudioUsage::NOTIFICATION:
+ return AUDIO_USAGE_NOTIFICATION;
+ case media::AudioUsage::NOTIFICATION_TELEPHONY_RINGTONE:
+ return AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE;
+ case media::AudioUsage::NOTIFICATION_COMMUNICATION_REQUEST:
+ return AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST;
+ case media::AudioUsage::NOTIFICATION_COMMUNICATION_INSTANT:
+ return AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT;
+ case media::AudioUsage::NOTIFICATION_COMMUNICATION_DELAYED:
+ return AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED;
+ case media::AudioUsage::NOTIFICATION_EVENT:
+ return AUDIO_USAGE_NOTIFICATION_EVENT;
+ case media::AudioUsage::ASSISTANCE_ACCESSIBILITY:
+ return AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY;
+ case media::AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE:
+ return AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE;
+ case media::AudioUsage::ASSISTANCE_SONIFICATION:
+ return AUDIO_USAGE_ASSISTANCE_SONIFICATION;
+ case media::AudioUsage::GAME:
+ return AUDIO_USAGE_GAME;
+ case media::AudioUsage::VIRTUAL_SOURCE:
+ return AUDIO_USAGE_VIRTUAL_SOURCE;
+ case media::AudioUsage::ASSISTANT:
+ return AUDIO_USAGE_ASSISTANT;
+ case media::AudioUsage::CALL_ASSISTANT:
+ return AUDIO_USAGE_CALL_ASSISTANT;
+ case media::AudioUsage::EMERGENCY:
+ return AUDIO_USAGE_EMERGENCY;
+ case media::AudioUsage::SAFETY:
+ return AUDIO_USAGE_SAFETY;
+ case media::AudioUsage::VEHICLE_STATUS:
+ return AUDIO_USAGE_VEHICLE_STATUS;
+ case media::AudioUsage::ANNOUNCEMENT:
+ return AUDIO_USAGE_ANNOUNCEMENT;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<media::AudioUsage>
+legacy2aidl_audio_usage_t_AudioUsage(audio_usage_t legacy) {
+ switch (legacy) {
+ case AUDIO_USAGE_UNKNOWN:
+ return media::AudioUsage::UNKNOWN;
+ case AUDIO_USAGE_MEDIA:
+ return media::AudioUsage::MEDIA;
+ case AUDIO_USAGE_VOICE_COMMUNICATION:
+ return media::AudioUsage::VOICE_COMMUNICATION;
+ case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
+ return media::AudioUsage::VOICE_COMMUNICATION_SIGNALLING;
+ case AUDIO_USAGE_ALARM:
+ return media::AudioUsage::ALARM;
+ case AUDIO_USAGE_NOTIFICATION:
+ return media::AudioUsage::NOTIFICATION;
+ case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
+ return media::AudioUsage::NOTIFICATION_TELEPHONY_RINGTONE;
+ case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+ return media::AudioUsage::NOTIFICATION_COMMUNICATION_REQUEST;
+ case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+ return media::AudioUsage::NOTIFICATION_COMMUNICATION_INSTANT;
+ case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+ return media::AudioUsage::NOTIFICATION_COMMUNICATION_DELAYED;
+ case AUDIO_USAGE_NOTIFICATION_EVENT:
+ return media::AudioUsage::NOTIFICATION_EVENT;
+ case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
+ return media::AudioUsage::ASSISTANCE_ACCESSIBILITY;
+ case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+ return media::AudioUsage::ASSISTANCE_NAVIGATION_GUIDANCE;
+ case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
+ return media::AudioUsage::ASSISTANCE_SONIFICATION;
+ case AUDIO_USAGE_GAME:
+ return media::AudioUsage::GAME;
+ case AUDIO_USAGE_VIRTUAL_SOURCE:
+ return media::AudioUsage::VIRTUAL_SOURCE;
+ case AUDIO_USAGE_ASSISTANT:
+ return media::AudioUsage::ASSISTANT;
+ case AUDIO_USAGE_CALL_ASSISTANT:
+ return media::AudioUsage::CALL_ASSISTANT;
+ case AUDIO_USAGE_EMERGENCY:
+ return media::AudioUsage::EMERGENCY;
+ case AUDIO_USAGE_SAFETY:
+ return media::AudioUsage::SAFETY;
+ case AUDIO_USAGE_VEHICLE_STATUS:
+ return media::AudioUsage::VEHICLE_STATUS;
+ case AUDIO_USAGE_ANNOUNCEMENT:
+ return media::AudioUsage::ANNOUNCEMENT;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_flags_mask_t>
+aidl2legacy_AudioFlag_audio_flags_mask_t(media::AudioFlag aidl) {
+ switch (aidl) {
+ case media::AudioFlag::AUDIBILITY_ENFORCED:
+ return AUDIO_FLAG_AUDIBILITY_ENFORCED;
+ case media::AudioFlag::SECURE:
+ return AUDIO_FLAG_SECURE;
+ case media::AudioFlag::SCO:
+ return AUDIO_FLAG_SCO;
+ case media::AudioFlag::BEACON:
+ return AUDIO_FLAG_BEACON;
+ case media::AudioFlag::HW_AV_SYNC:
+ return AUDIO_FLAG_HW_AV_SYNC;
+ case media::AudioFlag::HW_HOTWORD:
+ return AUDIO_FLAG_HW_HOTWORD;
+ case media::AudioFlag::BYPASS_INTERRUPTION_POLICY:
+ return AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY;
+ case media::AudioFlag::BYPASS_MUTE:
+ return AUDIO_FLAG_BYPASS_MUTE;
+ case media::AudioFlag::LOW_LATENCY:
+ return AUDIO_FLAG_LOW_LATENCY;
+ case media::AudioFlag::DEEP_BUFFER:
+ return AUDIO_FLAG_DEEP_BUFFER;
+ case media::AudioFlag::NO_MEDIA_PROJECTION:
+ return AUDIO_FLAG_NO_MEDIA_PROJECTION;
+ case media::AudioFlag::MUTE_HAPTIC:
+ return AUDIO_FLAG_MUTE_HAPTIC;
+ case media::AudioFlag::NO_SYSTEM_CAPTURE:
+ return AUDIO_FLAG_NO_SYSTEM_CAPTURE;
+ case media::AudioFlag::CAPTURE_PRIVATE:
+ return AUDIO_FLAG_CAPTURE_PRIVATE;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<media::AudioFlag>
+legacy2aidl_audio_flags_mask_t_AudioFlag(audio_flags_mask_t legacy) {
+ switch (legacy) {
+ case AUDIO_FLAG_NONE:
+ return unexpected(BAD_VALUE);
+ case AUDIO_FLAG_AUDIBILITY_ENFORCED:
+ return media::AudioFlag::AUDIBILITY_ENFORCED;
+ case AUDIO_FLAG_SECURE:
+ return media::AudioFlag::SECURE;
+ case AUDIO_FLAG_SCO:
+ return media::AudioFlag::SCO;
+ case AUDIO_FLAG_BEACON:
+ return media::AudioFlag::BEACON;
+ case AUDIO_FLAG_HW_AV_SYNC:
+ return media::AudioFlag::HW_AV_SYNC;
+ case AUDIO_FLAG_HW_HOTWORD:
+ return media::AudioFlag::HW_HOTWORD;
+ case AUDIO_FLAG_BYPASS_INTERRUPTION_POLICY:
+ return media::AudioFlag::BYPASS_INTERRUPTION_POLICY;
+ case AUDIO_FLAG_BYPASS_MUTE:
+ return media::AudioFlag::BYPASS_MUTE;
+ case AUDIO_FLAG_LOW_LATENCY:
+ return media::AudioFlag::LOW_LATENCY;
+ case AUDIO_FLAG_DEEP_BUFFER:
+ return media::AudioFlag::DEEP_BUFFER;
+ case AUDIO_FLAG_NO_MEDIA_PROJECTION:
+ return media::AudioFlag::NO_MEDIA_PROJECTION;
+ case AUDIO_FLAG_MUTE_HAPTIC:
+ return media::AudioFlag::MUTE_HAPTIC;
+ case AUDIO_FLAG_NO_SYSTEM_CAPTURE:
+ return media::AudioFlag::NO_SYSTEM_CAPTURE;
+ case AUDIO_FLAG_CAPTURE_PRIVATE:
+ return media::AudioFlag::CAPTURE_PRIVATE;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_flags_mask_t>
+aidl2legacy_int32_t_audio_flags_mask_t_mask(int32_t aidl) {
+ return convertBitmask<audio_flags_mask_t, int32_t, audio_flags_mask_t, media::AudioFlag>(
+ aidl, aidl2legacy_AudioFlag_audio_flags_mask_t, index2enum_index<media::AudioFlag>,
+ enumToMask_bitmask<audio_flags_mask_t, audio_flags_mask_t>);
+}
+
+ConversionResult<int32_t>
+legacy2aidl_audio_flags_mask_t_int32_t_mask(audio_flags_mask_t legacy) {
+ return convertBitmask<int32_t, audio_flags_mask_t, media::AudioFlag, audio_flags_mask_t>(
+ legacy, legacy2aidl_audio_flags_mask_t_AudioFlag,
+ index2enum_bitmask<audio_flags_mask_t>,
+ enumToMask_index<int32_t, media::AudioFlag>);
+}
+
+ConversionResult<audio_attributes_t>
+aidl2legacy_AudioAttributesInternal_audio_attributes_t(const media::AudioAttributesInternal& aidl) {
+ audio_attributes_t legacy;
+ legacy.content_type = VALUE_OR_RETURN(
+ aidl2legacy_AudioContentType_audio_content_type_t(aidl.contentType));
+ legacy.usage = VALUE_OR_RETURN(aidl2legacy_AudioUsage_audio_usage_t(aidl.usage));
+ legacy.source = VALUE_OR_RETURN(aidl2legacy_AudioSourceType_audio_source_t(aidl.source));
+ legacy.flags = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_flags_mask_t_mask(aidl.flags));
+ RETURN_IF_ERROR(aidl2legacy_string(aidl.tags, legacy.tags, sizeof(legacy.tags)));
+ return legacy;
+}
+
+ConversionResult<media::AudioAttributesInternal>
+legacy2aidl_audio_attributes_t_AudioAttributesInternal(const audio_attributes_t& legacy) {
+ media::AudioAttributesInternal aidl;
+ aidl.contentType = VALUE_OR_RETURN(
+ legacy2aidl_audio_content_type_t_AudioContentType(legacy.content_type));
+ aidl.usage = VALUE_OR_RETURN(legacy2aidl_audio_usage_t_AudioUsage(legacy.usage));
+ aidl.source = VALUE_OR_RETURN(legacy2aidl_audio_source_t_AudioSourceType(legacy.source));
+ aidl.flags = VALUE_OR_RETURN(legacy2aidl_audio_flags_mask_t_int32_t_mask(legacy.flags));
+ aidl.tags = VALUE_OR_RETURN(legacy2aidl_string(legacy.tags, sizeof(legacy.tags)));
+ return aidl;
+}
+
+ConversionResult<audio_encapsulation_mode_t>
+aidl2legacy_audio_encapsulation_mode_t_AudioEncapsulationMode(media::AudioEncapsulationMode aidl) {
+ switch (aidl) {
+ case media::AudioEncapsulationMode::NONE:
+ return AUDIO_ENCAPSULATION_MODE_NONE;
+ case media::AudioEncapsulationMode::ELEMENTARY_STREAM:
+ return AUDIO_ENCAPSULATION_MODE_ELEMENTARY_STREAM;
+ case media::AudioEncapsulationMode::HANDLE:
+ return AUDIO_ENCAPSULATION_MODE_HANDLE;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<media::AudioEncapsulationMode>
+legacy2aidl_AudioEncapsulationMode_audio_encapsulation_mode_t(audio_encapsulation_mode_t legacy) {
+ switch (legacy) {
+ case AUDIO_ENCAPSULATION_MODE_NONE:
+ return media::AudioEncapsulationMode::NONE;
+ case AUDIO_ENCAPSULATION_MODE_ELEMENTARY_STREAM:
+ return media::AudioEncapsulationMode::ELEMENTARY_STREAM;
+ case AUDIO_ENCAPSULATION_MODE_HANDLE:
+ return media::AudioEncapsulationMode::HANDLE;
+ }
+ return unexpected(BAD_VALUE);
+}
+
+ConversionResult<audio_offload_info_t>
+aidl2legacy_AudioOffloadInfo_audio_offload_info_t(const media::AudioOffloadInfo& aidl) {
+ audio_offload_info_t legacy;
+ legacy.version = VALUE_OR_RETURN(convertIntegral<uint16_t>(aidl.version));
+ legacy.size = sizeof(audio_offload_info_t);
+ audio_config_base_t config = VALUE_OR_RETURN(
+ aidl2legacy_AudioConfigBase_audio_config_base_t(aidl.config));
+ legacy.sample_rate = config.sample_rate;
+ legacy.channel_mask = config.channel_mask;
+ legacy.format = config.format;
+ legacy.stream_type = VALUE_OR_RETURN(
+ aidl2legacy_AudioStreamType_audio_stream_type_t(aidl.streamType));
+ legacy.bit_rate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.bitRate));
+ legacy.duration_us = VALUE_OR_RETURN(convertIntegral<int64_t>(aidl.durationUs));
+ legacy.has_video = aidl.hasVideo;
+ legacy.is_streaming = aidl.isStreaming;
+ legacy.bit_width = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.bitWidth));
+ legacy.offload_buffer_size = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.offloadBufferSize));
+ legacy.usage = VALUE_OR_RETURN(aidl2legacy_AudioUsage_audio_usage_t(aidl.usage));
+ legacy.encapsulation_mode = VALUE_OR_RETURN(
+ aidl2legacy_audio_encapsulation_mode_t_AudioEncapsulationMode(aidl.encapsulationMode));
+ legacy.content_id = VALUE_OR_RETURN(convertReinterpret<int32_t>(aidl.contentId));
+ legacy.sync_id = VALUE_OR_RETURN(convertReinterpret<int32_t>(aidl.syncId));
+ return legacy;
+}
+
+ConversionResult<media::AudioOffloadInfo>
+legacy2aidl_audio_offload_info_t_AudioOffloadInfo(const audio_offload_info_t& legacy) {
+ media::AudioOffloadInfo aidl;
+ // Version 0.1 fields.
+ if (legacy.size < offsetof(audio_offload_info_t, usage) + sizeof(audio_offload_info_t::usage)) {
+ return unexpected(BAD_VALUE);
+ }
+ aidl.version = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.version));
+ aidl.config.sampleRate = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.sample_rate));
+ aidl.config.channelMask = VALUE_OR_RETURN(
+ legacy2aidl_audio_channel_mask_t_int32_t(legacy.channel_mask));
+ aidl.config.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormat(legacy.format));
+ aidl.streamType = VALUE_OR_RETURN(
+ legacy2aidl_audio_stream_type_t_AudioStreamType(legacy.stream_type));
+ aidl.bitRate = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.bit_rate));
+ aidl.durationUs = VALUE_OR_RETURN(convertIntegral<int64_t>(legacy.duration_us));
+ aidl.hasVideo = legacy.has_video;
+ aidl.isStreaming = legacy.is_streaming;
+ aidl.bitWidth = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.bit_width));
+ aidl.offloadBufferSize = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.offload_buffer_size));
+ aidl.usage = VALUE_OR_RETURN(legacy2aidl_audio_usage_t_AudioUsage(legacy.usage));
+
+ // Version 0.2 fields.
+ if (legacy.version >= AUDIO_OFFLOAD_INFO_VERSION_0_2) {
+ if (legacy.size <
+ offsetof(audio_offload_info_t, sync_id) + sizeof(audio_offload_info_t::sync_id)) {
+ return unexpected(BAD_VALUE);
+ }
+ aidl.encapsulationMode = VALUE_OR_RETURN(
+ legacy2aidl_AudioEncapsulationMode_audio_encapsulation_mode_t(
+ legacy.encapsulation_mode));
+ aidl.contentId = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy.content_id));
+ aidl.syncId = VALUE_OR_RETURN(convertReinterpret<int32_t>(legacy.sync_id));
+ }
+ return aidl;
+}
+
+ConversionResult<audio_config_t>
+aidl2legacy_AudioConfig_audio_config_t(const media::AudioConfig& aidl) {
+ audio_config_t legacy;
+ legacy.sample_rate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.sampleRate));
+ legacy.channel_mask = VALUE_OR_RETURN(
+ aidl2legacy_int32_t_audio_channel_mask_t(aidl.channelMask));
+ legacy.format = VALUE_OR_RETURN(aidl2legacy_AudioFormat_audio_format_t(aidl.format));
+ legacy.offload_info = VALUE_OR_RETURN(
+ aidl2legacy_AudioOffloadInfo_audio_offload_info_t(aidl.offloadInfo));
+ legacy.frame_count = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.frameCount));
+ return legacy;
+}
+
+ConversionResult<media::AudioConfig>
+legacy2aidl_audio_config_t_AudioConfig(const audio_config_t& legacy) {
+ media::AudioConfig aidl;
+ aidl.sampleRate = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.sample_rate));
+ aidl.channelMask = VALUE_OR_RETURN(
+ legacy2aidl_audio_channel_mask_t_int32_t(legacy.channel_mask));
+ aidl.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormat(legacy.format));
+ aidl.offloadInfo = VALUE_OR_RETURN(
+ legacy2aidl_audio_offload_info_t_AudioOffloadInfo(legacy.offload_info));
+ aidl.frameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(legacy.frame_count));
+ return aidl;
+}
+
+ConversionResult<audio_config_base_t>
+aidl2legacy_AudioConfigBase_audio_config_base_t(const media::AudioConfigBase& aidl) {
+ audio_config_base_t legacy;
+ legacy.sample_rate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.sampleRate));
+ legacy.channel_mask = VALUE_OR_RETURN(
+ aidl2legacy_int32_t_audio_channel_mask_t(aidl.channelMask));
+ legacy.format = VALUE_OR_RETURN(aidl2legacy_AudioFormat_audio_format_t(aidl.format));
+ return legacy;
+}
+
+ConversionResult<media::AudioConfigBase>
+legacy2aidl_audio_config_base_t_AudioConfigBase(const audio_config_base_t& legacy) {
+ media::AudioConfigBase aidl;
+ aidl.sampleRate = VALUE_OR_RETURN(convertIntegral<int32_t>(legacy.sample_rate));
+ aidl.channelMask = VALUE_OR_RETURN(
+ legacy2aidl_audio_channel_mask_t_int32_t(legacy.channel_mask));
+ aidl.format = VALUE_OR_RETURN(legacy2aidl_audio_format_t_AudioFormat(legacy.format));
+ return aidl;
+}
+
+ConversionResult<sp<IMemory>>
+aidl2legacy_SharedFileRegion_IMemory(const media::SharedFileRegion& aidl) {
+ sp<IMemory> legacy;
+ if (!convertSharedFileRegionToIMemory(aidl, &legacy)) {
+ return unexpected(BAD_VALUE);
+ }
+ return legacy;
+}
+
+ConversionResult<media::SharedFileRegion>
+legacy2aidl_IMemory_SharedFileRegion(const sp<IMemory>& legacy) {
+ media::SharedFileRegion aidl;
+ if (!convertIMemoryToSharedFileRegion(legacy, &aidl)) {
+ return unexpected(BAD_VALUE);
+ }
+ return aidl;
+}
+
+ConversionResult<sp<IMemory>>
+aidl2legacy_NullableSharedFileRegion_IMemory(const std::optional<media::SharedFileRegion>& aidl) {
+ sp<IMemory> legacy;
+ if (!convertNullableSharedFileRegionToIMemory(aidl, &legacy)) {
+ return unexpected(BAD_VALUE);
+ }
+ return legacy;
+}
+
+ConversionResult<std::optional<media::SharedFileRegion>>
+legacy2aidl_NullableIMemory_SharedFileRegion(const sp<IMemory>& legacy) {
+ std::optional<media::SharedFileRegion> aidl;
+ if (!convertNullableIMemoryToSharedFileRegion(legacy, &aidl)) {
+ return unexpected(BAD_VALUE);
+ }
return aidl;
}
diff --git a/media/libaudioclient/Android.bp b/media/libaudioclient/Android.bp
index fef0ca9..c23c38c 100644
--- a/media/libaudioclient/Android.bp
+++ b/media/libaudioclient/Android.bp
@@ -15,9 +15,11 @@
],
static_libs: [
"audioflinger-aidl-unstable-cpp",
+ "av-types-aidl-unstable-cpp",
],
export_static_lib_headers: [
"audioflinger-aidl-unstable-cpp",
+ "av-types-aidl-unstable-cpp",
],
target: {
darwin: {
@@ -63,7 +65,7 @@
export_aidl_headers: true,
local_include_dirs: ["aidl"],
include_dirs: [
- "frameworks/av/media/libaudioclient/aidl",
+ "frameworks/av/aidl",
],
},
@@ -71,7 +73,6 @@
// AIDL files for audioclient interfaces
// The headers for these interfaces will be available to any modules that
// include libaudioclient, at the path "aidl/package/path/BnFoo.h"
- ":libaudioclient_aidl_callback",
":libaudioclient_aidl_private",
":libaudioclient_aidl",
@@ -90,7 +91,9 @@
"TrackPlayerBase.cpp",
],
shared_libs: [
+ "audioclient-types-aidl-unstable-cpp",
"audioflinger-aidl-unstable-cpp",
+ "av-types-aidl-unstable-cpp",
"capture_state_listener-aidl-cpp",
"libaudioclient_aidl_conversion",
"libaudiofoundation",
@@ -159,11 +162,16 @@
shared_libs: [
"audioclient-types-aidl-unstable-cpp",
"libbase",
+ "libbinder",
"liblog",
+ "libshmemcompat",
"libutils",
+ "shared-file-region-aidl-unstable-cpp",
],
export_shared_lib_headers: [
"audioclient-types-aidl-unstable-cpp",
+ "libbase",
+ "shared-file-region-aidl-unstable-cpp",
],
cflags: [
"-Wall",
@@ -197,15 +205,6 @@
path: "aidl",
}
-// AIDL interface for audio track callback
-filegroup {
- name: "libaudioclient_aidl_callback",
- srcs: [
- "aidl/android/media/IAudioTrackCallback.aidl",
- ],
- path: "aidl",
-}
-
aidl_interface {
name: "capture_state_listener-aidl",
unstable: true,
@@ -236,12 +235,20 @@
double_loadable: true,
local_include_dir: "aidl",
srcs: [
+ "aidl/android/media/AudioAttributesInternal.aidl",
+ "aidl/android/media/AudioClient.aidl",
+ "aidl/android/media/AudioConfig.aidl",
+ "aidl/android/media/AudioConfigBase.aidl",
+ "aidl/android/media/AudioContentType.aidl",
+ "aidl/android/media/AudioEncapsulationMode.aidl",
+ "aidl/android/media/AudioFlag.aidl",
"aidl/android/media/AudioGainConfig.aidl",
"aidl/android/media/AudioGainMode.aidl",
"aidl/android/media/AudioInputFlags.aidl",
"aidl/android/media/AudioIoConfigEvent.aidl",
"aidl/android/media/AudioIoDescriptor.aidl",
"aidl/android/media/AudioIoFlags.aidl",
+ "aidl/android/media/AudioOffloadInfo.aidl",
"aidl/android/media/AudioOutputFlags.aidl",
"aidl/android/media/AudioPatch.aidl",
"aidl/android/media/AudioPortConfig.aidl",
@@ -253,13 +260,22 @@
"aidl/android/media/AudioPortConfigSessionExt.aidl",
"aidl/android/media/AudioPortRole.aidl",
"aidl/android/media/AudioPortType.aidl",
- "aidl/android/media/AudioSessionType.aidl",
"aidl/android/media/AudioSourceType.aidl",
"aidl/android/media/AudioStreamType.aidl",
- ],
+ "aidl/android/media/AudioUsage.aidl",
+ ],
imports: [
"audio_common-aidl",
],
+ backend: {
+ cpp: {
+ min_sdk_version: "29",
+ apex_available: [
+ "//apex_available:platform",
+ "com.android.media",
+ ],
+ },
+ },
}
aidl_interface {
@@ -269,10 +285,17 @@
host_supported: true,
vendor_available: true,
srcs: [
+ "aidl/android/media/CreateRecordRequest.aidl",
+ "aidl/android/media/CreateRecordResponse.aidl",
+ "aidl/android/media/CreateTrackRequest.aidl",
+ "aidl/android/media/CreateTrackResponse.aidl",
+
"aidl/android/media/IAudioFlingerClient.aidl",
+ "aidl/android/media/IAudioTrackCallback.aidl",
],
imports: [
"audioclient-types-aidl",
+ "shared-file-region-aidl",
],
double_loadable: true,
backend: {
diff --git a/media/libaudioclient/AudioRecord.cpp b/media/libaudioclient/AudioRecord.cpp
index 55b836f..4d9fbb0 100644
--- a/media/libaudioclient/AudioRecord.cpp
+++ b/media/libaudioclient/AudioRecord.cpp
@@ -35,6 +35,15 @@
#include <media/MediaMetricsItem.h>
#include <media/TypeConverter.h>
+#define VALUE_OR_FATAL(result) \
+ ({ \
+ auto _tmp = (result); \
+ LOG_ALWAYS_FATAL_IF(!_tmp.ok(), \
+ "Failed result (%d)", \
+ _tmp.error()); \
+ std::move(_tmp.value()); \
+ })
+
#define WAIT_PERIOD_MS 10
namespace android {
@@ -807,7 +816,9 @@
originalSessionId = mSessionId;
do {
- record = audioFlinger->createRecord(input, output, &status);
+ media::CreateRecordResponse response;
+ record = audioFlinger->createRecord(VALUE_OR_FATAL(input.toAidl()), response, &status);
+ output = VALUE_OR_FATAL(IAudioFlinger::CreateRecordOutput::fromAidl(response));
if (status == NO_ERROR) {
break;
}
diff --git a/media/libaudioclient/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index 0507879..cfe5f3a 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -33,10 +33,10 @@
#include <system/audio.h>
-#define VALUE_OR_RETURN(x) \
+#define VALUE_OR_RETURN_STATUS(x) \
({ auto _tmp = (x); \
if (!_tmp.ok()) return Status::fromStatusT(_tmp.error()); \
- _tmp.value(); })
+ std::move(_tmp.value()); })
// ----------------------------------------------------------------------------
@@ -532,10 +532,10 @@
Status AudioSystem::AudioFlingerClient::ioConfigChanged(
media::AudioIoConfigEvent _event,
const media::AudioIoDescriptor& _ioDesc) {
- audio_io_config_event event = VALUE_OR_RETURN(
+ audio_io_config_event event = VALUE_OR_RETURN_STATUS(
aidl2legacy_AudioIoConfigEvent_audio_io_config_event(_event));
sp<AudioIoDescriptor> ioDesc(
- VALUE_OR_RETURN(aidl2legacy_AudioIoDescriptor_AudioIoDescriptor(_ioDesc)));
+ VALUE_OR_RETURN_STATUS(aidl2legacy_AudioIoDescriptor_AudioIoDescriptor(_ioDesc)));
ALOGV("ioConfigChanged() event %d", event);
diff --git a/media/libaudioclient/AudioTrack.cpp b/media/libaudioclient/AudioTrack.cpp
index 2c40fbb..14950a8 100644
--- a/media/libaudioclient/AudioTrack.cpp
+++ b/media/libaudioclient/AudioTrack.cpp
@@ -38,6 +38,15 @@
#include <media/MediaMetricsItem.h>
#include <media/TypeConverter.h>
+#define VALUE_OR_FATAL(result) \
+ ({ \
+ auto _tmp = (result); \
+ LOG_ALWAYS_FATAL_IF(!_tmp.ok(), \
+ "Failed result (%d)", \
+ _tmp.error()); \
+ std::move(_tmp.value()); \
+ })
+
#define WAIT_PERIOD_MS 10
#define WAIT_STREAM_END_TIMEOUT_SEC 120
static const int kMaxLoopCountNotifications = 32;
@@ -538,6 +547,7 @@
} else {
mOffloadInfo = NULL;
memset(&mOffloadInfoCopy, 0, sizeof(audio_offload_info_t));
+ mOffloadInfoCopy = AUDIO_INFO_INITIALIZER;
}
mVolume[AUDIO_INTERLEAVE_LEFT] = 1.0f;
@@ -1596,11 +1606,13 @@
input.audioTrackCallback = mAudioTrackCallback;
input.opPackageName = mOpPackageName;
- IAudioFlinger::CreateTrackOutput output;
-
- sp<IAudioTrack> track = audioFlinger->createTrack(input,
- output,
+ media::CreateTrackResponse response;
+ sp<IAudioTrack> track = audioFlinger->createTrack(VALUE_OR_FATAL(input.toAidl()),
+ response,
&status);
+ IAudioFlinger::CreateTrackOutput output = VALUE_OR_FATAL(
+ IAudioFlinger::CreateTrackOutput::fromAidl(
+ response));
if (status != NO_ERROR || output.outputId == AUDIO_IO_HANDLE_NONE) {
ALOGE("%s(%d): AudioFlinger could not create track, status: %d output %d",
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index d86182e..57142b0 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -97,6 +97,156 @@
#define MAX_ITEMS_PER_LIST 1024
+ConversionResult<media::CreateTrackRequest> IAudioFlinger::CreateTrackInput::toAidl() const {
+ media::CreateTrackRequest aidl;
+ aidl.attr = VALUE_OR_RETURN(legacy2aidl_audio_attributes_t_AudioAttributesInternal(attr));
+ aidl.config = VALUE_OR_RETURN(legacy2aidl_audio_config_t_AudioConfig(config));
+ aidl.clientInfo = VALUE_OR_RETURN(legacy2aidl_AudioClient(clientInfo));
+ aidl.sharedBuffer = VALUE_OR_RETURN(legacy2aidl_NullableIMemory_SharedFileRegion(sharedBuffer));
+ aidl.notificationsPerBuffer = VALUE_OR_RETURN(convertIntegral<int32_t>(notificationsPerBuffer));
+ aidl.speed = speed;
+ aidl.audioTrackCallback = audioTrackCallback;
+ aidl.opPackageName = opPackageName;
+ aidl.flags = VALUE_OR_RETURN(legacy2aidl_audio_output_flags_mask(flags));
+ aidl.frameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(frameCount));
+ aidl.notificationFrameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(notificationFrameCount));
+ aidl.selectedDeviceId = VALUE_OR_RETURN(
+ legacy2aidl_audio_port_handle_t_int32_t(selectedDeviceId));
+ aidl.sessionId = VALUE_OR_RETURN(legacy2aidl_audio_session_t_int32_t(sessionId));
+ return aidl;
+}
+
+ConversionResult<IAudioFlinger::CreateTrackInput>
+IAudioFlinger::CreateTrackInput::fromAidl(const media::CreateTrackRequest& aidl) {
+ IAudioFlinger::CreateTrackInput legacy;
+ legacy.attr = VALUE_OR_RETURN(aidl2legacy_AudioAttributesInternal_audio_attributes_t(aidl.attr));
+ legacy.config = VALUE_OR_RETURN(aidl2legacy_AudioConfig_audio_config_t(aidl.config));
+ legacy.clientInfo = VALUE_OR_RETURN(aidl2legacy_AudioClient(aidl.clientInfo));
+ legacy.sharedBuffer = VALUE_OR_RETURN(aidl2legacy_NullableSharedFileRegion_IMemory(aidl.sharedBuffer));
+ legacy.notificationsPerBuffer = VALUE_OR_RETURN(
+ convertIntegral<uint32_t>(aidl.notificationsPerBuffer));
+ legacy.speed = aidl.speed;
+ legacy.audioTrackCallback = aidl.audioTrackCallback;
+ legacy.opPackageName = aidl.opPackageName;
+ legacy.flags = VALUE_OR_RETURN(aidl2legacy_audio_output_flags_mask(aidl.flags));
+ legacy.frameCount = VALUE_OR_RETURN(convertIntegral<size_t>(aidl.frameCount));
+ legacy.notificationFrameCount = VALUE_OR_RETURN(
+ convertIntegral<size_t>(aidl.notificationFrameCount));
+ legacy.selectedDeviceId = VALUE_OR_RETURN(
+ aidl2legacy_int32_t_audio_port_handle_t(aidl.selectedDeviceId));
+ legacy.sessionId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_session_t(aidl.sessionId));
+ return legacy;
+}
+
+ConversionResult<media::CreateTrackResponse>
+IAudioFlinger::CreateTrackOutput::toAidl() const {
+ media::CreateTrackResponse aidl;
+ aidl.flags = VALUE_OR_RETURN(legacy2aidl_audio_output_flags_mask(flags));
+ aidl.frameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(frameCount));
+ aidl.notificationFrameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(notificationFrameCount));
+ aidl.selectedDeviceId = VALUE_OR_RETURN(
+ legacy2aidl_audio_port_handle_t_int32_t(selectedDeviceId));
+ aidl.sessionId = VALUE_OR_RETURN(legacy2aidl_audio_session_t_int32_t(sessionId));
+ aidl.sampleRate = VALUE_OR_RETURN(convertIntegral<int32_t>(sampleRate));
+ aidl.afFrameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(afFrameCount));
+ aidl.afSampleRate = VALUE_OR_RETURN(convertIntegral<int32_t>(afSampleRate));
+ aidl.afLatencyMs = VALUE_OR_RETURN(convertIntegral<int32_t>(afLatencyMs));
+ aidl.outputId = VALUE_OR_RETURN(legacy2aidl_audio_io_handle_t_int32_t(outputId));
+ aidl.portId = VALUE_OR_RETURN(legacy2aidl_audio_port_handle_t_int32_t(portId));
+ return aidl;
+}
+
+ConversionResult<IAudioFlinger::CreateTrackOutput>
+IAudioFlinger::CreateTrackOutput::fromAidl(
+ const media::CreateTrackResponse& aidl) {
+ IAudioFlinger::CreateTrackOutput legacy;
+ legacy.flags = VALUE_OR_RETURN(aidl2legacy_audio_output_flags_mask(aidl.flags));
+ legacy.frameCount = VALUE_OR_RETURN(convertIntegral<size_t>(aidl.frameCount));
+ legacy.notificationFrameCount = VALUE_OR_RETURN(
+ convertIntegral<size_t>(aidl.notificationFrameCount));
+ legacy.selectedDeviceId = VALUE_OR_RETURN(
+ aidl2legacy_int32_t_audio_port_handle_t(aidl.selectedDeviceId));
+ legacy.sessionId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_session_t(aidl.sessionId));
+ legacy.sampleRate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.sampleRate));
+ legacy.afFrameCount = VALUE_OR_RETURN(convertIntegral<size_t>(aidl.afFrameCount));
+ legacy.afSampleRate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.afSampleRate));
+ legacy.afLatencyMs = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.afLatencyMs));
+ legacy.outputId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_io_handle_t(aidl.outputId));
+ legacy.portId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_port_handle_t(aidl.portId));
+ return legacy;
+}
+
+ConversionResult<media::CreateRecordRequest>
+IAudioFlinger::CreateRecordInput::toAidl() const {
+ media::CreateRecordRequest aidl;
+ aidl.attr = VALUE_OR_RETURN(legacy2aidl_audio_attributes_t_AudioAttributesInternal(attr));
+ aidl.config = VALUE_OR_RETURN(legacy2aidl_audio_config_base_t_AudioConfigBase(config));
+ aidl.clientInfo = VALUE_OR_RETURN(legacy2aidl_AudioClient(clientInfo));
+ aidl.opPackageName = VALUE_OR_RETURN(legacy2aidl_String16_string(opPackageName));
+ aidl.riid = VALUE_OR_RETURN(legacy2aidl_audio_unique_id_t_int32_t(riid));
+ aidl.flags = VALUE_OR_RETURN(legacy2aidl_audio_input_flags_mask(flags));
+ aidl.frameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(frameCount));
+ aidl.notificationFrameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(notificationFrameCount));
+ aidl.selectedDeviceId = VALUE_OR_RETURN(
+ legacy2aidl_audio_port_handle_t_int32_t(selectedDeviceId));
+ aidl.sessionId = VALUE_OR_RETURN(legacy2aidl_audio_session_t_int32_t(sessionId));
+ return aidl;
+}
+
+ConversionResult<IAudioFlinger::CreateRecordInput>
+IAudioFlinger::CreateRecordInput::fromAidl(
+ const media::CreateRecordRequest& aidl) {
+ IAudioFlinger::CreateRecordInput legacy;
+ legacy.attr = VALUE_OR_RETURN(aidl2legacy_AudioAttributesInternal_audio_attributes_t(aidl.attr));
+ legacy.config = VALUE_OR_RETURN(aidl2legacy_AudioConfigBase_audio_config_base_t(aidl.config));
+ legacy.clientInfo = VALUE_OR_RETURN(aidl2legacy_AudioClient(aidl.clientInfo));
+ legacy.opPackageName = VALUE_OR_RETURN(aidl2legacy_string_view_String16(aidl.opPackageName));
+ legacy.riid = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_unique_id_t(aidl.riid));
+ legacy.flags = VALUE_OR_RETURN(aidl2legacy_audio_input_flags_mask(aidl.flags));
+ legacy.frameCount = VALUE_OR_RETURN(convertIntegral<size_t>(aidl.frameCount));
+ legacy.notificationFrameCount = VALUE_OR_RETURN(
+ convertIntegral<size_t>(aidl.notificationFrameCount));
+ legacy.selectedDeviceId = VALUE_OR_RETURN(
+ aidl2legacy_int32_t_audio_port_handle_t(aidl.selectedDeviceId));
+ legacy.sessionId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_session_t(aidl.sessionId));
+ return legacy;
+}
+
+ConversionResult<media::CreateRecordResponse>
+IAudioFlinger::CreateRecordOutput::toAidl() const {
+ media::CreateRecordResponse aidl;
+ aidl.flags = VALUE_OR_RETURN(legacy2aidl_audio_input_flags_mask(flags));
+ aidl.frameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(frameCount));
+ aidl.notificationFrameCount = VALUE_OR_RETURN(convertIntegral<int64_t>(notificationFrameCount));
+ aidl.selectedDeviceId = VALUE_OR_RETURN(
+ legacy2aidl_audio_port_handle_t_int32_t(selectedDeviceId));
+ aidl.sessionId = VALUE_OR_RETURN(legacy2aidl_audio_session_t_int32_t(sessionId));
+ aidl.sampleRate = VALUE_OR_RETURN(convertIntegral<int32_t>(sampleRate));
+ aidl.inputId = VALUE_OR_RETURN(legacy2aidl_audio_io_handle_t_int32_t(inputId));
+ aidl.cblk = VALUE_OR_RETURN(legacy2aidl_NullableIMemory_SharedFileRegion(cblk));
+ aidl.buffers = VALUE_OR_RETURN(legacy2aidl_NullableIMemory_SharedFileRegion(buffers));
+ aidl.portId = VALUE_OR_RETURN(legacy2aidl_audio_port_handle_t_int32_t(portId));
+ return aidl;
+}
+
+ConversionResult<IAudioFlinger::CreateRecordOutput>
+IAudioFlinger::CreateRecordOutput::fromAidl(
+ const media::CreateRecordResponse& aidl) {
+ IAudioFlinger::CreateRecordOutput legacy;
+ legacy.flags = VALUE_OR_RETURN(aidl2legacy_audio_input_flags_mask(aidl.flags));
+ legacy.frameCount = VALUE_OR_RETURN(convertIntegral<size_t>(aidl.frameCount));
+ legacy.notificationFrameCount = VALUE_OR_RETURN(
+ convertIntegral<size_t>(aidl.notificationFrameCount));
+ legacy.selectedDeviceId = VALUE_OR_RETURN(
+ aidl2legacy_int32_t_audio_port_handle_t(aidl.selectedDeviceId));
+ legacy.sessionId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_session_t(aidl.sessionId));
+ legacy.sampleRate = VALUE_OR_RETURN(convertIntegral<uint32_t>(aidl.sampleRate));
+ legacy.inputId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_io_handle_t(aidl.inputId));
+ legacy.cblk = VALUE_OR_RETURN(aidl2legacy_NullableSharedFileRegion_IMemory(aidl.cblk));
+ legacy.buffers = VALUE_OR_RETURN(aidl2legacy_NullableSharedFileRegion_IMemory(aidl.buffers));
+ legacy.portId = VALUE_OR_RETURN(aidl2legacy_int32_t_audio_port_handle_t(aidl.portId));
+ return legacy;
+}
class BpAudioFlinger : public BpInterface<IAudioFlinger>
{
@@ -106,9 +256,9 @@
{
}
- virtual sp<IAudioTrack> createTrack(const CreateTrackInput& input,
- CreateTrackOutput& output,
- status_t *status)
+ virtual sp<IAudioTrack> createTrack(const media::CreateTrackRequest& input,
+ media::CreateTrackResponse& output,
+ status_t* status)
{
Parcel data, reply;
sp<IAudioTrack> track;
@@ -118,7 +268,7 @@
return track;
}
- input.writeToParcel(&data);
+ data.writeParcelable(input);
status_t lStatus = remote()->transact(CREATE_TRACK, data, &reply);
if (lStatus != NO_ERROR) {
@@ -141,9 +291,9 @@
return track;
}
- virtual sp<media::IAudioRecord> createRecord(const CreateRecordInput& input,
- CreateRecordOutput& output,
- status_t *status)
+ virtual sp<media::IAudioRecord> createRecord(const media::CreateRecordRequest& input,
+ media::CreateRecordResponse& output,
+ status_t* status)
{
Parcel data, reply;
sp<media::IAudioRecord> record;
@@ -153,7 +303,7 @@
return record;
}
- input.writeToParcel(&data);
+ data.writeParcelable(input);
status_t lStatus = remote()->transact(CREATE_RECORD, data, &reply);
if (lStatus != NO_ERROR) {
@@ -1040,14 +1190,14 @@
case CREATE_TRACK: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- CreateTrackInput input;
- if (input.readFromParcel((Parcel*)&data) != NO_ERROR) {
+ media::CreateTrackRequest input;
+ if (data.readParcelable(&input) != NO_ERROR) {
reply->writeInt32(DEAD_OBJECT);
return NO_ERROR;
}
status_t status;
- CreateTrackOutput output;
+ media::CreateTrackResponse output;
sp<IAudioTrack> track= createTrack(input,
output,
@@ -1065,14 +1215,14 @@
case CREATE_RECORD: {
CHECK_INTERFACE(IAudioFlinger, data, reply);
- CreateRecordInput input;
- if (input.readFromParcel((Parcel*)&data) != NO_ERROR) {
+ media::CreateRecordRequest input;
+ if (data.readParcelable(&input) != NO_ERROR) {
reply->writeInt32(DEAD_OBJECT);
return NO_ERROR;
}
status_t status;
- CreateRecordOutput output;
+ media::CreateRecordResponse output;
sp<media::IAudioRecord> record = createRecord(input,
output,
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 81f9dff..cd098b5 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -1614,6 +1614,7 @@
// case SET_FORCE_USE:
case INIT_STREAM_VOLUME:
case SET_STREAM_VOLUME:
+ case SET_VOLUME_ATTRIBUTES:
case REGISTER_POLICY_MIXES:
case SET_MASTER_MONO:
case GET_SURROUND_FORMATS:
diff --git a/media/libaudioclient/PlayerBase.cpp b/media/libaudioclient/PlayerBase.cpp
index b0c68e5..c443865 100644
--- a/media/libaudioclient/PlayerBase.cpp
+++ b/media/libaudioclient/PlayerBase.cpp
@@ -22,7 +22,8 @@
namespace android {
-using media::VolumeShaper;
+using media::VolumeShaperConfiguration;
+using media::VolumeShaperOperation;
//--------------------------------------------------------------------------------------------------
PlayerBase::PlayerBase() : BnPlayer(),
@@ -178,8 +179,8 @@
}
binder::Status PlayerBase::applyVolumeShaper(
- const VolumeShaper::Configuration& configuration __unused,
- const VolumeShaper::Operation& operation __unused) {
+ const VolumeShaperConfiguration& configuration __unused,
+ const VolumeShaperOperation& operation __unused) {
ALOGW("applyVolumeShaper() is not supported");
return binder::Status::ok();
}
diff --git a/media/libaudioclient/TrackPlayerBase.cpp b/media/libaudioclient/TrackPlayerBase.cpp
index 0a914fc..e571838 100644
--- a/media/libaudioclient/TrackPlayerBase.cpp
+++ b/media/libaudioclient/TrackPlayerBase.cpp
@@ -106,11 +106,17 @@
binder::Status TrackPlayerBase::applyVolumeShaper(
- const VolumeShaper::Configuration& configuration,
- const VolumeShaper::Operation& operation) {
+ const media::VolumeShaperConfiguration& configuration,
+ const media::VolumeShaperOperation& operation) {
- sp<VolumeShaper::Configuration> spConfiguration = new VolumeShaper::Configuration(configuration);
- sp<VolumeShaper::Operation> spOperation = new VolumeShaper::Operation(operation);
+ sp<VolumeShaper::Configuration> spConfiguration = new VolumeShaper::Configuration();
+ sp<VolumeShaper::Operation> spOperation = new VolumeShaper::Operation();
+
+ status_t s = spConfiguration->readFromParcelable(configuration)
+ ?: spOperation->readFromParcelable(operation);
+ if (s != OK) {
+ return binder::Status::fromStatusT(s);
+ }
if (mAudioTrack != 0) {
ALOGD("TrackPlayerBase::applyVolumeShaper() from IPlayer");
diff --git a/media/libaudioclient/aidl/android/media/AudioAttributesInternal.aidl b/media/libaudioclient/aidl/android/media/AudioAttributesInternal.aidl
new file mode 100644
index 0000000..699df0a
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioAttributesInternal.aidl
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.media;
+
+import android.media.AudioContentType;
+import android.media.AudioSourceType;
+import android.media.AudioUsage;
+
+/**
+ * The "Internal" suffix of this type name is to disambiguate it from the
+ * android.media.AudioAttributes SDK type.
+ * {@hide}
+ */
+parcelable AudioAttributesInternal {
+ AudioContentType contentType;
+ AudioUsage usage;
+ AudioSourceType source;
+ // Bitmask, indexed by AudioFlag.
+ int flags;
+ @utf8InCpp String tags; /* UTF8 */
+}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/media/libaudioclient/aidl/android/media/AudioClient.aidl
similarity index 73%
copy from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
copy to media/libaudioclient/aidl/android/media/AudioClient.aidl
index d305c29..7bff0d6 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioClient.aidl
@@ -13,13 +13,18 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.media;
-@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+/**
+ * {@hide}
+ */
+parcelable AudioClient {
+ /** Interpreted as uid_t. */
+ int clientUid;
+ /** Interpreted as pid_t. */
+ int clientPid;
+ /** Interpreted as pid_t. */
+ int clientTid;
+ @utf8InCpp String packageName;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/media/libaudioclient/aidl/android/media/AudioConfig.aidl
similarity index 64%
copy from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
copy to media/libaudioclient/aidl/android/media/AudioConfig.aidl
index d305c29..8dc97d3 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioConfig.aidl
@@ -13,13 +13,23 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.media;
-@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+import android.media.AudioOffloadInfo;
+import android.media.audio.common.AudioFormat;
+
+/**
+ * {@hide}
+ */
+parcelable AudioConfig {
+ int sampleRate;
+ /**
+ * Interpreted as audio_channel_mask_t.
+ * TODO(ytai): Create a designated type.
+ */
+ int channelMask;
+ AudioFormat format;
+ AudioOffloadInfo offloadInfo;
+ long frameCount;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/media/libaudioclient/aidl/android/media/AudioConfigBase.aidl
similarity index 75%
copy from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
copy to media/libaudioclient/aidl/android/media/AudioConfigBase.aidl
index d305c29..8353c0d 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioConfigBase.aidl
@@ -13,13 +13,17 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
+
package android.media;
-@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+import android.media.audio.common.AudioFormat;
+
+/**
+ * {@hide}
+ */
+parcelable AudioConfigBase {
+ int sampleRate;
+ /** Interpreted as audio_channel_mask_t. */
+ int channelMask;
+ AudioFormat format;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/media/libaudioclient/aidl/android/media/AudioContentType.aidl
similarity index 85%
rename from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
rename to media/libaudioclient/aidl/android/media/AudioContentType.aidl
index d305c29..f734fba 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioContentType.aidl
@@ -16,10 +16,10 @@
package android.media;
@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+enum AudioContentType {
+ UNKNOWN = 0,
+ SPEECH = 1,
+ MUSIC = 2,
+ MOVIE = 3,
+ SONIFICATION = 4,
}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/media/libaudioclient/aidl/android/media/AudioEncapsulationMode.aidl
similarity index 84%
copy from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
copy to media/libaudioclient/aidl/android/media/AudioEncapsulationMode.aidl
index d305c29..74a6141 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioEncapsulationMode.aidl
@@ -16,10 +16,8 @@
package android.media;
@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+enum AudioEncapsulationMode {
+ NONE = 0,
+ ELEMENTARY_STREAM = 1,
+ HANDLE = 2,
}
diff --git a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl b/media/libaudioclient/aidl/android/media/AudioFlag.aidl
similarity index 66%
copy from media/libaudioclient/aidl/android/media/AudioSessionType.aidl
copy to media/libaudioclient/aidl/android/media/AudioFlag.aidl
index d305c29..2602fe5 100644
--- a/media/libaudioclient/aidl/android/media/AudioSessionType.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioFlag.aidl
@@ -16,10 +16,19 @@
package android.media;
@Backing(type="int")
-enum AudioSessionType {
- DEVICE = -2,
- OUTPUT_STAGE = -1,
- OUTPUT_MIX = 0,
- ALLOCATE = 0,
- NONE = 0,
+enum AudioFlag {
+ AUDIBILITY_ENFORCED = 0,
+ SECURE = 1,
+ SCO = 2,
+ BEACON = 3,
+ HW_AV_SYNC = 4,
+ HW_HOTWORD = 5,
+ BYPASS_INTERRUPTION_POLICY = 6,
+ BYPASS_MUTE = 7,
+ LOW_LATENCY = 8,
+ DEEP_BUFFER = 9,
+ NO_MEDIA_PROJECTION = 10,
+ MUTE_HAPTIC = 11,
+ NO_SYSTEM_CAPTURE = 12,
+ CAPTURE_PRIVATE = 13,
}
diff --git a/media/libaudioclient/aidl/android/media/AudioIoFlags.aidl b/media/libaudioclient/aidl/android/media/AudioIoFlags.aidl
index 1fe2acc..f9b25bf 100644
--- a/media/libaudioclient/aidl/android/media/AudioIoFlags.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioIoFlags.aidl
@@ -19,12 +19,9 @@
/**
* {@hide}
*/
-// TODO(b/150948558): This should be a union. In the meantime, we require
-// that exactly one of the below arrays has a single element and the rest
-// are empty.
-parcelable AudioIoFlags {
+union AudioIoFlags {
/** Bitmask indexed by AudioInputFlags. */
- int[] input;
+ int input;
/** Bitmask indexed by AudioOutputFlags. */
- int[] output;
+ int output;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioOffloadInfo.aidl b/media/libaudioclient/aidl/android/media/AudioOffloadInfo.aidl
new file mode 100644
index 0000000..c86b3f0
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioOffloadInfo.aidl
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.media;
+
+import android.media.AudioConfigBase;
+import android.media.AudioEncapsulationMode;
+import android.media.AudioStreamType;
+import android.media.AudioUsage;
+import android.media.audio.common.AudioFormat;
+
+/**
+ * {@hide}
+ */
+parcelable AudioOffloadInfo {
+ /** Version of the info structure. Interpreted as a uint16_t version constant. */
+ int version;
+ /** Audio configuration. */
+ AudioConfigBase config;
+ /** Stream type. */
+ AudioStreamType streamType;
+ /** Bit rate in bits per second. */
+ int bitRate;
+ /** Duration in microseconds, -1 if unknown. */
+ long durationUs;
+ /** true if stream is tied to a video stream. */
+ boolean hasVideo;
+ /** true if streaming, false if local playback. */
+ boolean isStreaming;
+ int bitWidth;
+ /** Offload fragment size. */
+ int offloadBufferSize;
+ AudioUsage usage;
+ AudioEncapsulationMode encapsulationMode;
+ /** Content id from tuner HAL (0 if none). */
+ int contentId;
+ /** Sync id from tuner HAL (0 if none). */
+ int syncId;
+}
diff --git a/media/libaudioclient/aidl/android/media/AudioPortConfigExt.aidl b/media/libaudioclient/aidl/android/media/AudioPortConfigExt.aidl
index 83e985e..38da4f5 100644
--- a/media/libaudioclient/aidl/android/media/AudioPortConfigExt.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPortConfigExt.aidl
@@ -23,15 +23,17 @@
/**
* {@hide}
*/
-parcelable AudioPortConfigExt {
- // TODO(b/150948558): This should be a union. In the meantime, we require
- // that exactly one of the below arrays has a single element and the rest
- // are empty.
-
+union AudioPortConfigExt {
+ /**
+ * This represents an empty union. Value is ignored.
+ * TODO(ytai): replace with the canonical representation for an empty union, as soon as it is
+ * established.
+ */
+ boolean nothing;
/** Device specific info. */
- AudioPortConfigDeviceExt[] device;
+ AudioPortConfigDeviceExt device;
/** Mix specific info. */
- AudioPortConfigMixExt[] mix;
+ AudioPortConfigMixExt mix;
/** Session specific info. */
- AudioPortConfigSessionExt[] session;
+ AudioPortConfigSessionExt session;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioPortConfigMixExtUseCase.aidl b/media/libaudioclient/aidl/android/media/AudioPortConfigMixExtUseCase.aidl
index 675daf8..9e5e081 100644
--- a/media/libaudioclient/aidl/android/media/AudioPortConfigMixExtUseCase.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPortConfigMixExtUseCase.aidl
@@ -22,13 +22,16 @@
/**
* {@hide}
*/
-parcelable AudioPortConfigMixExtUseCase {
- // TODO(b/150948558): This should be a union. In the meantime, we require
- // that exactly one of the below arrays has a single element and the rest
- // are empty.
-
+union AudioPortConfigMixExtUseCase {
+ /**
+ * This to be set if the containing config has the AudioPortRole::NONE role.
+ * This represents an empty value (value is ignored).
+ * TODO(ytai): replace with the canonical representation for an empty union, as soon as it is
+ * established.
+ */
+ boolean nothing;
/** This to be set if the containing config has the AudioPortRole::SOURCE role. */
- AudioStreamType[] stream;
+ AudioStreamType stream;
/** This to be set if the containing config has the AudioPortRole::SINK role. */
- AudioSourceType[] source;
+ AudioSourceType source;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioPortConfigSessionExt.aidl b/media/libaudioclient/aidl/android/media/AudioPortConfigSessionExt.aidl
index d3261d9..a2cbf62 100644
--- a/media/libaudioclient/aidl/android/media/AudioPortConfigSessionExt.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioPortConfigSessionExt.aidl
@@ -16,11 +16,9 @@
package android.media;
-import android.media.AudioSessionType;
-
/**
* {@hide}
*/
parcelable AudioPortConfigSessionExt {
- AudioSessionType session;
+ int session;
}
diff --git a/media/libaudioclient/aidl/android/media/AudioSourceType.aidl b/media/libaudioclient/aidl/android/media/AudioSourceType.aidl
index f6ecc46..35320f8 100644
--- a/media/libaudioclient/aidl/android/media/AudioSourceType.aidl
+++ b/media/libaudioclient/aidl/android/media/AudioSourceType.aidl
@@ -17,6 +17,7 @@
@Backing(type="int")
enum AudioSourceType {
+ INVALID = -1,
DEFAULT = 0,
MIC = 1,
VOICE_UPLINK = 2,
diff --git a/media/libaudioclient/aidl/android/media/AudioUsage.aidl b/media/libaudioclient/aidl/android/media/AudioUsage.aidl
new file mode 100644
index 0000000..137e7ff
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/AudioUsage.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+package android.media;
+
+@Backing(type="int")
+enum AudioUsage {
+ UNKNOWN = 0,
+ MEDIA = 1,
+ VOICE_COMMUNICATION = 2,
+ VOICE_COMMUNICATION_SIGNALLING = 3,
+ ALARM = 4,
+ NOTIFICATION = 5,
+ NOTIFICATION_TELEPHONY_RINGTONE = 6,
+ NOTIFICATION_COMMUNICATION_REQUEST = 7,
+ NOTIFICATION_COMMUNICATION_INSTANT = 8,
+ NOTIFICATION_COMMUNICATION_DELAYED = 9,
+ NOTIFICATION_EVENT = 10,
+ ASSISTANCE_ACCESSIBILITY = 11,
+ ASSISTANCE_NAVIGATION_GUIDANCE = 12,
+ ASSISTANCE_SONIFICATION = 13,
+ GAME = 14,
+ VIRTUAL_SOURCE = 15,
+ ASSISTANT = 16,
+ CALL_ASSISTANT = 17,
+ EMERGENCY = 1000,
+ SAFETY = 1001,
+ VEHICLE_STATUS = 1002,
+ ANNOUNCEMENT = 1003,
+}
diff --git a/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl b/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl
new file mode 100644
index 0000000..6da743a
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/CreateRecordRequest.aidl
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.media;
+
+import android.media.AudioAttributesInternal;
+import android.media.AudioClient;
+import android.media.AudioConfigBase;
+
+/**
+ * CreateRecordRequest contains all input arguments sent by AudioRecord to AudioFlinger
+ * when calling createRecord() including arguments that will be updated by AudioFlinger
+ * and returned in CreateRecordResponse object.
+ *
+ * {@hide}
+ */
+parcelable CreateRecordRequest {
+ AudioAttributesInternal attr;
+ AudioConfigBase config;
+ AudioClient clientInfo;
+ @utf8InCpp String opPackageName;
+ /** Interpreted as audio_unique_id_t. */
+ int riid;
+ /** Bitmask, indexed by AudioInputFlags. */
+ int flags;
+ long frameCount;
+ long notificationFrameCount;
+ /** Interpreted as audio_port_handle_t. */
+ int selectedDeviceId;
+ int sessionId;
+}
diff --git a/media/libaudioclient/aidl/android/media/CreateRecordResponse.aidl b/media/libaudioclient/aidl/android/media/CreateRecordResponse.aidl
new file mode 100644
index 0000000..0c9d7c3
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/CreateRecordResponse.aidl
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.media;
+
+import android.media.SharedFileRegion;
+
+/**
+ * CreateRecordResponse contains all output arguments returned by AudioFlinger to AudioRecord
+ * when calling createRecord() including arguments that were passed as I/O for update by
+ * CreateRecordRequest.
+ *
+ * {@hide}
+ */
+parcelable CreateRecordResponse {
+ /** Bitmask, indexed by AudioInputFlags. */
+ int flags;
+ long frameCount;
+ long notificationFrameCount;
+ /** Interpreted as audio_port_handle_t. */
+ int selectedDeviceId;
+ int sessionId;
+ int sampleRate;
+ /** Interpreted as audio_io_handle_t. */
+ int inputId;
+ @nullable SharedFileRegion cblk;
+ @nullable SharedFileRegion buffers;
+ /** Interpreted as audio_port_handle_t. */
+ int portId;
+}
diff --git a/media/libaudioclient/aidl/android/media/CreateTrackRequest.aidl b/media/libaudioclient/aidl/android/media/CreateTrackRequest.aidl
new file mode 100644
index 0000000..014b3ca
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/CreateTrackRequest.aidl
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.media;
+
+import android.media.AudioAttributesInternal;
+import android.media.AudioClient;
+import android.media.AudioConfig;
+import android.media.IAudioTrackCallback;
+import android.media.SharedFileRegion;
+
+/**
+ * CreateTrackInput contains all input arguments sent by AudioTrack to AudioFlinger
+ * when calling createTrack() including arguments that will be updated by AudioFlinger
+ * and returned in CreateTrackResponse object.
+ *
+ * {@hide}
+ */
+parcelable CreateTrackRequest {
+ AudioAttributesInternal attr;
+ AudioConfig config;
+ AudioClient clientInfo;
+ @nullable SharedFileRegion sharedBuffer;
+ int notificationsPerBuffer;
+ float speed;
+ IAudioTrackCallback audioTrackCallback;
+ @utf8InCpp String opPackageName;
+ /** Bitmask, indexed by AudioOutputFlags. */
+ int flags;
+ long frameCount;
+ long notificationFrameCount;
+ /** Interpreted as audio_port_handle_t. */
+ int selectedDeviceId;
+ int sessionId;
+}
diff --git a/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl b/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl
new file mode 100644
index 0000000..494e63f
--- /dev/null
+++ b/media/libaudioclient/aidl/android/media/CreateTrackResponse.aidl
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+package android.media;
+
+/**
+ * CreateTrackOutput contains all output arguments returned by AudioFlinger to AudioTrack
+ * when calling createTrack() including arguments that were passed as I/O for update by
+ * CreateTrackRequest.
+ *
+ * {@hide}
+ */
+parcelable CreateTrackResponse {
+ /** Bitmask, indexed by AudioOutputFlags. */
+ int flags;
+ long frameCount;
+ long notificationFrameCount;
+ /** Interpreted as audio_port_handle_t. */
+ int selectedDeviceId;
+ int sessionId;
+ int sampleRate;
+ long afFrameCount;
+ int afSampleRate;
+ int afLatencyMs;
+ /** Interpreted as audio_io_handle_t. */
+ int outputId;
+ /** Interpreted as audio_port_handle_t. */
+ int portId;
+}
diff --git a/media/libaudioclient/aidl/android/media/IPlayer.aidl b/media/libaudioclient/aidl/android/media/IPlayer.aidl
index a90fcdd..8c2c471 100644
--- a/media/libaudioclient/aidl/android/media/IPlayer.aidl
+++ b/media/libaudioclient/aidl/android/media/IPlayer.aidl
@@ -16,8 +16,8 @@
package android.media;
-import android.media.VolumeShaper.Configuration;
-import android.media.VolumeShaper.Operation;
+import android.media.VolumeShaperConfiguration;
+import android.media.VolumeShaperOperation;
/**
* @hide
@@ -29,6 +29,6 @@
oneway void setVolume(float vol);
oneway void setPan(float pan);
oneway void setStartDelayMs(int delayMs);
- oneway void applyVolumeShaper(in Configuration configuration,
- in Operation operation);
+ oneway void applyVolumeShaper(in VolumeShaperConfiguration configuration,
+ in VolumeShaperOperation operation);
}
diff --git a/media/libaudioclient/aidl/android/media/VolumeShaper/Configuration.aidl b/media/libaudioclient/aidl/android/media/VolumeShaper/Configuration.aidl
deleted file mode 100644
index fd0e60f..0000000
--- a/media/libaudioclient/aidl/android/media/VolumeShaper/Configuration.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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.
- */
-
-package android.media.VolumeShaper;
-
-parcelable Configuration cpp_header "media/VolumeShaper.h";
diff --git a/media/libaudioclient/aidl/android/media/VolumeShaper/Operation.aidl b/media/libaudioclient/aidl/android/media/VolumeShaper/Operation.aidl
deleted file mode 100644
index 4290d9d..0000000
--- a/media/libaudioclient/aidl/android/media/VolumeShaper/Operation.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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.
- */
-
-package android.media.VolumeShaper;
-
-parcelable Operation cpp_header "media/VolumeShaper.h";
diff --git a/media/libaudioclient/aidl/android/media/VolumeShaper/State.aidl b/media/libaudioclient/aidl/android/media/VolumeShaper/State.aidl
deleted file mode 100644
index f6a22b8..0000000
--- a/media/libaudioclient/aidl/android/media/VolumeShaper/State.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * 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.
- */
-
-package android.media.VolumeShaper;
-
-parcelable State cpp_header "media/VolumeShaper.h";
diff --git a/media/libaudioclient/include/media/AidlConversion.h b/media/libaudioclient/include/media/AidlConversion.h
index a1b9b82..4df8083 100644
--- a/media/libaudioclient/include/media/AidlConversion.h
+++ b/media/libaudioclient/include/media/AidlConversion.h
@@ -16,9 +16,18 @@
#pragma once
+#include <limits>
+#include <type_traits>
+
#include <system/audio.h>
-#include <android-base/result.h>
+#include <android-base/expected.h>
+
+#include <android/media/AudioAttributesInternal.h>
+#include <android/media/AudioClient.h>
+#include <android/media/AudioConfig.h>
+#include <android/media/AudioConfigBase.h>
+#include <android/media/AudioFlag.h>
#include <android/media/AudioGainMode.h>
#include <android/media/AudioInputFlags.h>
#include <android/media/AudioIoConfigEvent.h>
@@ -26,6 +35,10 @@
#include <android/media/AudioOutputFlags.h>
#include <android/media/AudioPortConfigType.h>
+#include <android/media/SharedFileRegion.h>
+
+#include <binder/IMemory.h>
+#include <media/AudioClient.h>
#include <media/AudioIoDescriptor.h>
namespace android {
@@ -33,6 +46,63 @@
template <typename T>
using ConversionResult = base::expected<T, status_t>;
+// Convenience macros for working with ConversionResult, useful for writing converted for aggregate
+// types.
+
+#define VALUE_OR_RETURN(result) \
+ ({ \
+ auto _tmp = (result); \
+ if (!_tmp.ok()) return base::unexpected(_tmp.error()); \
+ std::move(_tmp.value()); \
+ })
+
+#define RETURN_IF_ERROR(result) \
+ if (status_t _tmp = (result); _tmp != OK) return base::unexpected(_tmp);
+
+/**
+ * A generic template to safely cast between integral types, respecting limits of the destination
+ * type.
+ */
+template<typename To, typename From>
+ConversionResult<To> convertIntegral(From from) {
+ // Special handling is required for signed / vs. unsigned comparisons, since otherwise we may
+ // have the signed converted to unsigned and produce wrong results.
+ if (std::is_signed_v<From> && !std::is_signed_v<To>) {
+ if (from < 0 || from > std::numeric_limits<To>::max()) {
+ return base::unexpected(BAD_VALUE);
+ }
+ } else if (std::is_signed_v<To> && !std::is_signed_v<From>) {
+ if (from > std::numeric_limits<To>::max()) {
+ return base::unexpected(BAD_VALUE);
+ }
+ } else {
+ if (from < std::numeric_limits<To>::min() || from > std::numeric_limits<To>::max()) {
+ return base::unexpected(BAD_VALUE);
+ }
+ }
+ return static_cast<To>(from);
+}
+
+// maxSize is the size of the C-string buffer (including the 0-terminator), NOT the max length of
+// the string.
+status_t aidl2legacy_string(std::string_view aidl, char* dest, size_t maxSize);
+ConversionResult<std::string> legacy2aidl_string(const char* legacy, size_t maxSize);
+
+ConversionResult<audio_module_handle_t> aidl2legacy_int32_t_audio_module_handle_t(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_audio_module_handle_t_int32_t(audio_module_handle_t legacy);
+
+ConversionResult<audio_io_handle_t> aidl2legacy_int32_t_audio_io_handle_t(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_audio_io_handle_t_int32_t(audio_io_handle_t legacy);
+
+ConversionResult<audio_port_handle_t> aidl2legacy_int32_t_audio_port_handle_t(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_audio_port_handle_t_int32_t(audio_port_handle_t legacy);
+
+ConversionResult<audio_patch_handle_t> aidl2legacy_int32_t_audio_patch_handle_t(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_audio_patch_handle_t_int32_t(audio_patch_handle_t legacy);
+
+ConversionResult<audio_unique_id_t> aidl2legacy_int32_t_audio_unique_id_t(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_audio_unique_id_t_int32_t(audio_unique_id_t legacy);
+
// The legacy enum is unnamed. Thus, we use int.
ConversionResult<int> aidl2legacy_AudioPortConfigType(media::AudioPortConfigType aidl);
// The legacy enum is unnamed. Thus, we use int.
@@ -44,6 +114,15 @@
ConversionResult<audio_channel_mask_t> aidl2legacy_int32_t_audio_channel_mask_t(int32_t aidl);
ConversionResult<int32_t> legacy2aidl_audio_channel_mask_t_int32_t(audio_channel_mask_t legacy);
+ConversionResult<pid_t> aidl2legacy_int32_t_pid_t(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_pid_t_int32_t(pid_t legacy);
+
+ConversionResult<uid_t> aidl2legacy_int32_t_uid_t(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_uid_t_int32_t(uid_t legacy);
+
+ConversionResult<String16> aidl2legacy_string_view_String16(std::string_view aidl);
+ConversionResult<std::string> legacy2aidl_String16_string(const String16& legacy);
+
ConversionResult<audio_io_config_event> aidl2legacy_AudioIoConfigEvent_audio_io_config_event(
media::AudioIoConfigEvent aidl);
ConversionResult<media::AudioIoConfigEvent> legacy2aidl_audio_io_config_event_AudioIoConfigEvent(
@@ -114,10 +193,8 @@
ConversionResult<media::AudioSourceType> legacy2aidl_audio_source_t_AudioSourceType(
audio_source_t legacy);
-ConversionResult<audio_session_t> aidl2legacy_AudioSessionType_audio_session_t(
- media::AudioSessionType aidl);
-ConversionResult<media::AudioSessionType> legacy2aidl_audio_session_t_AudioSessionType(
- audio_session_t legacy);
+ConversionResult<audio_session_t> aidl2legacy_int32_t_audio_session_t(int32_t aidl);
+ConversionResult<int32_t> legacy2aidl_audio_session_t_int32_t(audio_session_t legacy);
ConversionResult<audio_port_config_mix_ext> aidl2legacy_AudioPortConfigMixExt(
const media::AudioPortConfigMixExt& aidl, media::AudioPortRole role);
@@ -141,7 +218,66 @@
ConversionResult<sp<AudioIoDescriptor>> aidl2legacy_AudioIoDescriptor_AudioIoDescriptor(
const media::AudioIoDescriptor& aidl);
+
ConversionResult<media::AudioIoDescriptor> legacy2aidl_AudioIoDescriptor_AudioIoDescriptor(
const sp<AudioIoDescriptor>& legacy);
+ConversionResult<AudioClient> aidl2legacy_AudioClient(const media::AudioClient& aidl);
+ConversionResult<media::AudioClient> legacy2aidl_AudioClient(const AudioClient& legacy);
+
+ConversionResult<audio_content_type_t>
+aidl2legacy_AudioContentType_audio_content_type_t(media::AudioContentType aidl);
+ConversionResult<media::AudioContentType>
+legacy2aidl_audio_content_type_t_AudioContentType(audio_content_type_t legacy);
+
+ConversionResult<audio_usage_t>
+aidl2legacy_AudioUsage_audio_usage_t(media::AudioUsage aidl);
+ConversionResult<media::AudioUsage>
+legacy2aidl_audio_usage_t_AudioUsage(audio_usage_t legacy);
+
+ConversionResult<audio_flags_mask_t>
+aidl2legacy_AudioFlag_audio_flags_mask_t(media::AudioFlag aidl);
+ConversionResult<media::AudioFlag>
+legacy2aidl_audio_flags_mask_t_AudioFlag(audio_flags_mask_t legacy);
+
+ConversionResult<audio_flags_mask_t>
+aidl2legacy_int32_t_audio_flags_mask_t_mask(int32_t aidl);
+ConversionResult<int32_t>
+legacy2aidl_audio_flags_mask_t_int32_t_mask(audio_flags_mask_t legacy);
+
+ConversionResult<audio_attributes_t>
+aidl2legacy_AudioAttributesInternal_audio_attributes_t(const media::AudioAttributesInternal& aidl);
+ConversionResult<media::AudioAttributesInternal>
+legacy2aidl_audio_attributes_t_AudioAttributesInternal(const audio_attributes_t& legacy);
+
+ConversionResult<audio_encapsulation_mode_t>
+aidl2legacy_audio_encapsulation_mode_t_AudioEncapsulationMode(media::AudioEncapsulationMode aidl);
+ConversionResult<media::AudioEncapsulationMode>
+legacy2aidl_AudioEncapsulationMode_audio_encapsulation_mode_t(audio_encapsulation_mode_t legacy);
+
+ConversionResult<audio_offload_info_t>
+aidl2legacy_AudioOffloadInfo_audio_offload_info_t(const media::AudioOffloadInfo& aidl);
+ConversionResult<media::AudioOffloadInfo>
+legacy2aidl_audio_offload_info_t_AudioOffloadInfo(const audio_offload_info_t& legacy);
+
+ConversionResult<audio_config_t>
+aidl2legacy_AudioConfig_audio_config_t(const media::AudioConfig& aidl);
+ConversionResult<media::AudioConfig>
+legacy2aidl_audio_config_t_AudioConfig(const audio_config_t& legacy);
+
+ConversionResult<audio_config_base_t>
+aidl2legacy_AudioConfigBase_audio_config_base_t(const media::AudioConfigBase& aidl);
+ConversionResult<media::AudioConfigBase>
+legacy2aidl_audio_config_base_t_AudioConfigBase(const audio_config_base_t& legacy);
+
+ConversionResult<sp<IMemory>>
+aidl2legacy_SharedFileRegion_IMemory(const media::SharedFileRegion& aidl);
+ConversionResult<media::SharedFileRegion>
+legacy2aidl_IMemory_SharedFileRegion(const sp<IMemory>& legacy);
+
+ConversionResult<sp<IMemory>>
+aidl2legacy_NullableSharedFileRegion_IMemory(const std::optional<media::SharedFileRegion>& aidl);
+ConversionResult<std::optional<media::SharedFileRegion>>
+legacy2aidl_NullableIMemory_SharedFileRegion(const sp<IMemory>& legacy);
+
} // namespace android
diff --git a/media/libaudioclient/include/media/AudioClient.h b/media/libaudioclient/include/media/AudioClient.h
index 247af9e..0b89d15 100644
--- a/media/libaudioclient/include/media/AudioClient.h
+++ b/media/libaudioclient/include/media/AudioClient.h
@@ -18,14 +18,12 @@
#ifndef ANDROID_AUDIO_CLIENT_H
#define ANDROID_AUDIO_CLIENT_H
-#include <binder/Parcel.h>
-#include <binder/Parcelable.h>
-#include <system/audio.h>
+#include <sys/types.h>
#include <utils/String16.h>
namespace android {
-class AudioClient : public Parcelable {
+class AudioClient {
public:
AudioClient() :
clientUid(-1), clientPid(-1), clientTid(-1), packageName("") {}
@@ -34,22 +32,6 @@
pid_t clientPid;
pid_t clientTid;
String16 packageName;
-
- status_t readFromParcel(const Parcel *parcel) override {
- clientUid = parcel->readInt32();
- clientPid = parcel->readInt32();
- clientTid = parcel->readInt32();
- packageName = parcel->readString16();
- return NO_ERROR;
- }
-
- status_t writeToParcel(Parcel *parcel) const override {
- parcel->writeInt32(clientUid);
- parcel->writeInt32(clientPid);
- parcel->writeInt32(clientTid);
- parcel->writeString16(packageName);
- return NO_ERROR;
- }
};
}; // namespace android
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index 413db71..3491fda 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -26,6 +26,7 @@
#include <binder/IInterface.h>
#include <binder/Parcel.h>
#include <binder/Parcelable.h>
+#include <media/AidlConversion.h>
#include <media/AudioClient.h>
#include <media/DeviceDescriptorBase.h>
#include <media/IAudioTrack.h>
@@ -37,6 +38,10 @@
#include <string>
#include <vector>
+#include "android/media/CreateRecordRequest.h"
+#include "android/media/CreateRecordResponse.h"
+#include "android/media/CreateTrackRequest.h"
+#include "android/media/CreateTrackResponse.h"
#include "android/media/IAudioRecord.h"
#include "android/media/IAudioFlingerClient.h"
#include "android/media/IAudioTrackCallback.h"
@@ -56,76 +61,8 @@
* when calling createTrack() including arguments that will be updated by AudioFlinger
* and returned in CreateTrackOutput object
*/
- class CreateTrackInput : public Parcelable {
+ class CreateTrackInput {
public:
- status_t readFromParcel(const Parcel *parcel) override {
- /* input arguments*/
- memset(&attr, 0, sizeof(audio_attributes_t));
- if (parcel->read(&attr, sizeof(audio_attributes_t)) != NO_ERROR) {
- return DEAD_OBJECT;
- }
- attr.tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE -1] = '\0';
- memset(&config, 0, sizeof(audio_config_t));
- if (parcel->read(&config, sizeof(audio_config_t)) != NO_ERROR) {
- return DEAD_OBJECT;
- }
- if (clientInfo.readFromParcel(parcel) != NO_ERROR) {
- return DEAD_OBJECT;
- }
- if (parcel->readInt32() != 0) {
- // TODO: Using unsecurePointer() has some associated security
- // pitfalls (see declaration for details).
- // Either document why it is safe in this case or address
- // the issue (e.g. by copying).
- sharedBuffer = interface_cast<IMemory>(parcel->readStrongBinder());
- if (sharedBuffer == 0 || sharedBuffer->unsecurePointer() == NULL) {
- return BAD_VALUE;
- }
- }
- notificationsPerBuffer = parcel->readInt32();
- speed = parcel->readFloat();
- audioTrackCallback = interface_cast<media::IAudioTrackCallback>(
- parcel->readStrongBinder());
- const char* opPackageNamePtr = parcel->readCString();
- if (opPackageNamePtr == nullptr) {
- return FAILED_TRANSACTION;
- }
- opPackageName = opPackageNamePtr;
-
- /* input/output arguments*/
- (void)parcel->read(&flags, sizeof(audio_output_flags_t));
- frameCount = parcel->readInt64();
- notificationFrameCount = parcel->readInt64();
- (void)parcel->read(&selectedDeviceId, sizeof(audio_port_handle_t));
- (void)parcel->read(&sessionId, sizeof(audio_session_t));
- return NO_ERROR;
- }
-
- status_t writeToParcel(Parcel *parcel) const override {
- /* input arguments*/
- (void)parcel->write(&attr, sizeof(audio_attributes_t));
- (void)parcel->write(&config, sizeof(audio_config_t));
- (void)clientInfo.writeToParcel(parcel);
- if (sharedBuffer != 0) {
- (void)parcel->writeInt32(1);
- (void)parcel->writeStrongBinder(IInterface::asBinder(sharedBuffer));
- } else {
- (void)parcel->writeInt32(0);
- }
- (void)parcel->writeInt32(notificationsPerBuffer);
- (void)parcel->writeFloat(speed);
- (void)parcel->writeStrongBinder(IInterface::asBinder(audioTrackCallback));
- (void)parcel->writeCString(opPackageName.c_str());
-
- /* input/output arguments*/
- (void)parcel->write(&flags, sizeof(audio_output_flags_t));
- (void)parcel->writeInt64(frameCount);
- (void)parcel->writeInt64(notificationFrameCount);
- (void)parcel->write(&selectedDeviceId, sizeof(audio_port_handle_t));
- (void)parcel->write(&sessionId, sizeof(audio_session_t));
- return NO_ERROR;
- }
-
/* input */
audio_attributes_t attr;
audio_config_t config;
@@ -142,50 +79,17 @@
size_t notificationFrameCount;
audio_port_handle_t selectedDeviceId;
audio_session_t sessionId;
+
+ ConversionResult<media::CreateTrackRequest> toAidl() const;
+ static ConversionResult<CreateTrackInput> fromAidl(const media::CreateTrackRequest& aidl);
};
/* CreateTrackOutput contains all output arguments returned by AudioFlinger to AudioTrack
* when calling createTrack() including arguments that were passed as I/O for update by
* CreateTrackInput.
*/
- class CreateTrackOutput : public Parcelable {
+ class CreateTrackOutput {
public:
- status_t readFromParcel(const Parcel *parcel) override {
- /* input/output arguments*/
- (void)parcel->read(&flags, sizeof(audio_output_flags_t));
- frameCount = parcel->readInt64();
- notificationFrameCount = parcel->readInt64();
- (void)parcel->read(&selectedDeviceId, sizeof(audio_port_handle_t));
- (void)parcel->read(&sessionId, sizeof(audio_session_t));
-
- /* output arguments*/
- sampleRate = parcel->readUint32();
- afFrameCount = parcel->readInt64();
- afSampleRate = parcel->readInt64();
- afLatencyMs = parcel->readInt32();
- (void)parcel->read(&outputId, sizeof(audio_io_handle_t));
- (void)parcel->read(&portId, sizeof(audio_port_handle_t));
- return NO_ERROR;
- }
-
- status_t writeToParcel(Parcel *parcel) const override {
- /* input/output arguments*/
- (void)parcel->write(&flags, sizeof(audio_output_flags_t));
- (void)parcel->writeInt64(frameCount);
- (void)parcel->writeInt64(notificationFrameCount);
- (void)parcel->write(&selectedDeviceId, sizeof(audio_port_handle_t));
- (void)parcel->write(&sessionId, sizeof(audio_session_t));
-
- /* output arguments*/
- (void)parcel->writeUint32(sampleRate);
- (void)parcel->writeInt64(afFrameCount);
- (void)parcel->writeInt64(afSampleRate);
- (void)parcel->writeInt32(afLatencyMs);
- (void)parcel->write(&outputId, sizeof(audio_io_handle_t));
- (void)parcel->write(&portId, sizeof(audio_port_handle_t));
- return NO_ERROR;
- }
-
/* input/output */
audio_output_flags_t flags;
size_t frameCount;
@@ -200,59 +104,17 @@
uint32_t afLatencyMs;
audio_io_handle_t outputId;
audio_port_handle_t portId;
+
+ ConversionResult<media::CreateTrackResponse> toAidl() const;
+ static ConversionResult<CreateTrackOutput> fromAidl(const media::CreateTrackResponse& aidl);
};
/* CreateRecordInput contains all input arguments sent by AudioRecord to AudioFlinger
* when calling createRecord() including arguments that will be updated by AudioFlinger
* and returned in CreateRecordOutput object
*/
- class CreateRecordInput : public Parcelable {
+ class CreateRecordInput {
public:
- status_t readFromParcel(const Parcel *parcel) override {
- /* input arguments*/
- memset(&attr, 0, sizeof(audio_attributes_t));
- if (parcel->read(&attr, sizeof(audio_attributes_t)) != NO_ERROR) {
- return DEAD_OBJECT;
- }
- attr.tags[AUDIO_ATTRIBUTES_TAGS_MAX_SIZE -1] = '\0';
- memset(&config, 0, sizeof(audio_config_base_t));
- if (parcel->read(&config, sizeof(audio_config_base_t)) != NO_ERROR) {
- return DEAD_OBJECT;
- }
- if (clientInfo.readFromParcel(parcel) != NO_ERROR) {
- return DEAD_OBJECT;
- }
- opPackageName = parcel->readString16();
- if (parcel->read(&riid, sizeof(audio_unique_id_t)) != NO_ERROR) {
- return DEAD_OBJECT;
- }
-
- /* input/output arguments*/
- (void)parcel->read(&flags, sizeof(audio_input_flags_t));
- frameCount = parcel->readInt64();
- notificationFrameCount = parcel->readInt64();
- (void)parcel->read(&selectedDeviceId, sizeof(audio_port_handle_t));
- (void)parcel->read(&sessionId, sizeof(audio_session_t));
- return NO_ERROR;
- }
-
- status_t writeToParcel(Parcel *parcel) const override {
- /* input arguments*/
- (void)parcel->write(&attr, sizeof(audio_attributes_t));
- (void)parcel->write(&config, sizeof(audio_config_base_t));
- (void)clientInfo.writeToParcel(parcel);
- (void)parcel->writeString16(opPackageName);
- (void)parcel->write(&riid, sizeof(audio_unique_id_t));
-
- /* input/output arguments*/
- (void)parcel->write(&flags, sizeof(audio_input_flags_t));
- (void)parcel->writeInt64(frameCount);
- (void)parcel->writeInt64(notificationFrameCount);
- (void)parcel->write(&selectedDeviceId, sizeof(audio_port_handle_t));
- (void)parcel->write(&sessionId, sizeof(audio_session_t));
- return NO_ERROR;
- }
-
/* input */
audio_attributes_t attr;
audio_config_base_t config;
@@ -266,77 +128,17 @@
size_t notificationFrameCount;
audio_port_handle_t selectedDeviceId;
audio_session_t sessionId;
+
+ ConversionResult<media::CreateRecordRequest> toAidl() const;
+ static ConversionResult<CreateRecordInput> fromAidl(const media::CreateRecordRequest& aidl);
};
/* CreateRecordOutput contains all output arguments returned by AudioFlinger to AudioRecord
* when calling createRecord() including arguments that were passed as I/O for update by
* CreateRecordInput.
*/
- class CreateRecordOutput : public Parcelable {
+ class CreateRecordOutput {
public:
- status_t readFromParcel(const Parcel *parcel) override {
- /* input/output arguments*/
- (void)parcel->read(&flags, sizeof(audio_input_flags_t));
- frameCount = parcel->readInt64();
- notificationFrameCount = parcel->readInt64();
- (void)parcel->read(&selectedDeviceId, sizeof(audio_port_handle_t));
- (void)parcel->read(&sessionId, sizeof(audio_session_t));
-
- /* output arguments*/
- sampleRate = parcel->readUint32();
- (void)parcel->read(&inputId, sizeof(audio_io_handle_t));
- if (parcel->readInt32() != 0) {
- cblk = interface_cast<IMemory>(parcel->readStrongBinder());
- // TODO: Using unsecurePointer() has some associated security
- // pitfalls (see declaration for details).
- // Either document why it is safe in this case or address
- // the issue (e.g. by copying).
- if (cblk == 0 || cblk->unsecurePointer() == NULL) {
- return BAD_VALUE;
- }
- }
- if (parcel->readInt32() != 0) {
- buffers = interface_cast<IMemory>(parcel->readStrongBinder());
- // TODO: Using unsecurePointer() has some associated security
- // pitfalls (see declaration for details).
- // Either document why it is safe in this case or address
- // the issue (e.g. by copying).
- if (buffers == 0 || buffers->unsecurePointer() == NULL) {
- return BAD_VALUE;
- }
- }
- (void)parcel->read(&portId, sizeof(audio_port_handle_t));
- return NO_ERROR;
- }
-
- status_t writeToParcel(Parcel *parcel) const override {
- /* input/output arguments*/
- (void)parcel->write(&flags, sizeof(audio_input_flags_t));
- (void)parcel->writeInt64(frameCount);
- (void)parcel->writeInt64(notificationFrameCount);
- (void)parcel->write(&selectedDeviceId, sizeof(audio_port_handle_t));
- (void)parcel->write(&sessionId, sizeof(audio_session_t));
-
- /* output arguments*/
- (void)parcel->writeUint32(sampleRate);
- (void)parcel->write(&inputId, sizeof(audio_io_handle_t));
- if (cblk != 0) {
- (void)parcel->writeInt32(1);
- (void)parcel->writeStrongBinder(IInterface::asBinder(cblk));
- } else {
- (void)parcel->writeInt32(0);
- }
- if (buffers != 0) {
- (void)parcel->writeInt32(1);
- (void)parcel->writeStrongBinder(IInterface::asBinder(buffers));
- } else {
- (void)parcel->writeInt32(0);
- }
- (void)parcel->write(&portId, sizeof(audio_port_handle_t));
-
- return NO_ERROR;
- }
-
/* input/output */
audio_input_flags_t flags;
size_t frameCount;
@@ -350,6 +152,9 @@
sp<IMemory> cblk;
sp<IMemory> buffers;
audio_port_handle_t portId;
+
+ ConversionResult<media::CreateRecordResponse> toAidl() const;
+ static ConversionResult<CreateRecordOutput> fromAidl(const media::CreateRecordResponse& aidl);
};
// invariant on exit for all APIs that return an sp<>:
@@ -358,13 +163,13 @@
/* create an audio track and registers it with AudioFlinger.
* return null if the track cannot be created.
*/
- virtual sp<IAudioTrack> createTrack(const CreateTrackInput& input,
- CreateTrackOutput& output,
- status_t *status) = 0;
+ virtual sp<IAudioTrack> createTrack(const media::CreateTrackRequest& input,
+ media::CreateTrackResponse& output,
+ status_t* status) = 0;
- virtual sp<media::IAudioRecord> createRecord(const CreateRecordInput& input,
- CreateRecordOutput& output,
- status_t *status) = 0;
+ virtual sp<media::IAudioRecord> createRecord(const media::CreateRecordRequest& input,
+ media::CreateRecordResponse& output,
+ status_t* status) = 0;
// FIXME Surprisingly, format/latency don't work for input handles
diff --git a/media/libaudioclient/include/media/PlayerBase.h b/media/libaudioclient/include/media/PlayerBase.h
index e7a8abc..4aad9b4 100644
--- a/media/libaudioclient/include/media/PlayerBase.h
+++ b/media/libaudioclient/include/media/PlayerBase.h
@@ -19,6 +19,7 @@
#include <audiomanager/AudioManager.h>
#include <audiomanager/IAudioManager.h>
+#include <utils/Mutex.h>
#include "android/media/BnPlayer.h"
@@ -40,8 +41,8 @@
virtual binder::Status setPan(float pan) override;
virtual binder::Status setStartDelayMs(int32_t delayMs) override;
virtual binder::Status applyVolumeShaper(
- const media::VolumeShaper::Configuration& configuration,
- const media::VolumeShaper::Operation& operation) override;
+ const media::VolumeShaperConfiguration& configuration,
+ const media::VolumeShaperOperation& operation) override;
status_t startWithStatus();
status_t pauseWithStatus();
diff --git a/media/libaudioclient/include/media/TrackPlayerBase.h b/media/libaudioclient/include/media/TrackPlayerBase.h
index 66e9b3b..6d26e63 100644
--- a/media/libaudioclient/include/media/TrackPlayerBase.h
+++ b/media/libaudioclient/include/media/TrackPlayerBase.h
@@ -33,8 +33,8 @@
//IPlayer implementation
virtual binder::Status applyVolumeShaper(
- const media::VolumeShaper::Configuration& configuration,
- const media::VolumeShaper::Operation& operation);
+ const media::VolumeShaperConfiguration& configuration,
+ const media::VolumeShaperOperation& operation);
//FIXME move to protected field, so far made public to minimize changes to AudioTrack logic
sp<AudioTrack> mAudioTrack;
diff --git a/media/libaudioprocessing/include/media/AudioResamplerPublic.h b/media/libaudioprocessing/include/media/AudioResamplerPublic.h
index 1b39067..200a4c8 100644
--- a/media/libaudioprocessing/include/media/AudioResamplerPublic.h
+++ b/media/libaudioprocessing/include/media/AudioResamplerPublic.h
@@ -59,7 +59,7 @@
static inline bool isAudioPlaybackRateValid(const AudioPlaybackRate &playbackRate) {
if (playbackRate.mFallbackMode == AUDIO_TIMESTRETCH_FALLBACK_FAIL &&
- (playbackRate.mStretchMode == AUDIO_TIMESTRETCH_STRETCH_SPEECH ||
+ (playbackRate.mStretchMode == AUDIO_TIMESTRETCH_STRETCH_VOICE ||
playbackRate.mStretchMode == AUDIO_TIMESTRETCH_STRETCH_DEFAULT)) {
//test sonic specific constraints
return playbackRate.mSpeed >= TIMESTRETCH_SONIC_SPEED_MIN &&
diff --git a/media/libaudioprocessing/tests/fuzzer/Android.bp b/media/libaudioprocessing/tests/fuzzer/Android.bp
index 1df47b7..2a0dec4 100644
--- a/media/libaudioprocessing/tests/fuzzer/Android.bp
+++ b/media/libaudioprocessing/tests/fuzzer/Android.bp
@@ -8,3 +8,14 @@
"libsndfile",
],
}
+
+cc_fuzz {
+ name: "libaudioprocessing_record_buffer_converter_fuzzer",
+ srcs: [
+ "libaudioprocessing_record_buffer_converter_fuzzer.cpp",
+ ],
+ defaults: ["libaudioprocessing_test_defaults"],
+ static_libs: [
+ "libsndfile",
+ ],
+}
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_fuzz_utils.h b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_fuzz_utils.h
new file mode 100644
index 0000000..5165925
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_fuzz_utils.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2021 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_LIBAUDIOPROCESSING_FUZZ_UTILS_H
+#define ANDROID_LIBAUDIOPROCESSING_FUZZ_UTILS_H
+
+#include <media/AudioBufferProvider.h>
+#include <system/audio.h>
+
+namespace android {
+
+class Provider : public AudioBufferProvider {
+ const void* mAddr; // base address
+ const size_t mNumFrames; // total frames
+ const size_t mFrameSize; // size of each frame in bytes
+ size_t mNextFrame; // index of next frame to provide
+ size_t mUnrel; // number of frames not yet released
+ public:
+ Provider(const void* addr, size_t frames, size_t frameSize)
+ : mAddr(addr),
+ mNumFrames(frames),
+ mFrameSize(frameSize),
+ mNextFrame(0),
+ mUnrel(0) {}
+ status_t getNextBuffer(Buffer* buffer) override {
+ if (buffer->frameCount > mNumFrames - mNextFrame) {
+ buffer->frameCount = mNumFrames - mNextFrame;
+ }
+ mUnrel = buffer->frameCount;
+ if (buffer->frameCount > 0) {
+ buffer->raw = (char*)mAddr + mFrameSize * mNextFrame;
+ return NO_ERROR;
+ } else {
+ buffer->raw = nullptr;
+ return NOT_ENOUGH_DATA;
+ }
+ }
+ void releaseBuffer(Buffer* buffer) override {
+ if (buffer->frameCount > mUnrel) {
+ mNextFrame += mUnrel;
+ mUnrel = 0;
+ } else {
+ mNextFrame += buffer->frameCount;
+ mUnrel -= buffer->frameCount;
+ }
+ buffer->frameCount = 0;
+ buffer->raw = nullptr;
+ }
+ void reset() { mNextFrame = 0; }
+};
+
+} // namespace android
+
+#endif // ANDROID_LIBAUDIOPROCESSING_FUZZ_UTILS_H
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_record_buffer_converter_fuzzer.cpp b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_record_buffer_converter_fuzzer.cpp
new file mode 100644
index 0000000..017598c
--- /dev/null
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_record_buffer_converter_fuzzer.cpp
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2020 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 "libaudioprocessing_fuzz_utils.h"
+#include "fuzzer/FuzzedDataProvider.h"
+#include <media/AudioResampler.h>
+#include <media/RecordBufferConverter.h>
+#include <stddef.h>
+#include <stdint.h>
+
+using namespace android;
+
+constexpr int MAX_FRAMES = 1024;
+
+#define AUDIO_FORMAT_PCM_MAIN 0
+
+// Copied and simplified from audio-hal-enums.h?l=571
+constexpr uint32_t FUZZ_AUDIO_FORMATS[] = {
+ AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_16_BIT,
+ AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_8_BIT,
+ AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_32_BIT,
+ AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_8_24_BIT,
+ AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_FLOAT,
+ AUDIO_FORMAT_PCM_MAIN | AUDIO_FORMAT_PCM_SUB_24_BIT_PACKED,
+ 0x01000000u,
+ 0x02000000u,
+ 0x03000000u,
+ 0x04000000u,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_MAIN,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_LC,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_SSR,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_LTP,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_HE_V1,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_SCALABLE,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_ERLC,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_LD,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_HE_V2,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_ELD,
+ AUDIO_FORMAT_AAC | AUDIO_FORMAT_AAC_SUB_XHE,
+ 0x05000000u,
+ 0x06000000u,
+ 0x07000000u,
+ 0x08000000u,
+ 0x09000000u,
+ 0x0A000000u,
+ AUDIO_FORMAT_E_AC3 | AUDIO_FORMAT_E_AC3_SUB_JOC,
+ 0x0B000000u,
+ 0x0C000000u,
+ 0x0D000000u,
+ 0x0E000000u,
+ 0x10000000u,
+ 0x11000000u,
+ 0x12000000u,
+ 0x13000000u,
+ 0x14000000u,
+ 0x15000000u,
+ 0x16000000u,
+ 0x17000000u,
+ 0x18000000u,
+ 0x19000000u,
+ 0x1A000000u,
+ 0x1B000000u,
+ 0x1C000000u,
+ 0x1D000000u,
+ 0x1E000000u,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_MAIN,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_LC,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_SSR,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_LTP,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_HE_V1,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_SCALABLE,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_ERLC,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_LD,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_HE_V2,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_ELD,
+ AUDIO_FORMAT_AAC_ADTS | AUDIO_FORMAT_AAC_SUB_XHE,
+ 0x1F000000u,
+ 0x20000000u,
+ 0x21000000u,
+ 0x22000000u,
+ 0x23000000u,
+ 0x24000000u,
+ AUDIO_FORMAT_MAT | AUDIO_FORMAT_MAT_SUB_1_0,
+ AUDIO_FORMAT_MAT | AUDIO_FORMAT_MAT_SUB_2_0,
+ AUDIO_FORMAT_MAT | AUDIO_FORMAT_MAT_SUB_2_1,
+ 0x25000000u,
+ AUDIO_FORMAT_AAC_LATM | AUDIO_FORMAT_AAC_SUB_LC,
+ AUDIO_FORMAT_AAC_LATM | AUDIO_FORMAT_AAC_SUB_HE_V1,
+ AUDIO_FORMAT_AAC_LATM | AUDIO_FORMAT_AAC_SUB_HE_V2,
+ 0x26000000u,
+ 0x27000000u,
+ 0x28000000u,
+ 0x29000000u,
+ 0x2A000000u,
+ 0x2B000000u,
+ 0xFFFFFFFFu,
+ AUDIO_FORMAT_PCM_MAIN,
+ AUDIO_FORMAT_PCM,
+};
+constexpr size_t NUM_AUDIO_FORMATS = std::size(FUZZ_AUDIO_FORMATS);
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+ fdp.ConsumeIntegral<int>();
+
+ const audio_channel_mask_t srcChannelMask = (audio_channel_mask_t)fdp.ConsumeIntegral<int>();
+ const audio_format_t srcFormat =
+ (audio_format_t)FUZZ_AUDIO_FORMATS[fdp.ConsumeIntegralInRange<int>(0, NUM_AUDIO_FORMATS - 1)];
+ const uint32_t srcSampleRate = fdp.ConsumeIntegralInRange<int>(1, 0x7fffffff);
+ const audio_channel_mask_t dstChannelMask = (audio_channel_mask_t)fdp.ConsumeIntegral<int>();
+ const audio_format_t dstFormat =
+ (audio_format_t)FUZZ_AUDIO_FORMATS[fdp.ConsumeIntegralInRange<int>(0, NUM_AUDIO_FORMATS - 1)];
+ const uint32_t dstSampleRate = fdp.ConsumeIntegralInRange<int>(1, 0x7fffffff);
+
+ // Certain formats will result in LOG_ALWAYS_FATAL errors that aren't interesting crashes
+ // for fuzzing. Don't use those ones.
+ const uint32_t dstChannelCount = audio_channel_count_from_in_mask(dstChannelMask);
+ constexpr android::AudioResampler::src_quality quality =
+ android::AudioResampler::DEFAULT_QUALITY;
+ const int maxChannels =
+ quality < android::AudioResampler::DYN_LOW_QUALITY ? 2 : 8;
+ if (dstChannelCount < 1 || dstChannelCount > maxChannels) {
+ return 0;
+ }
+
+ const uint32_t srcChannelCount = audio_channel_count_from_in_mask(srcChannelMask);
+ if (srcChannelCount < 1 || srcChannelCount > maxChannels) {
+ return 0;
+ }
+
+ RecordBufferConverter converter(srcChannelMask, srcFormat, srcSampleRate,
+ dstChannelMask, dstFormat, dstSampleRate);
+ if (converter.initCheck() != NO_ERROR) {
+ return 0;
+ }
+
+ const uint32_t srcFrameSize = srcChannelCount * audio_bytes_per_sample(srcFormat);
+ const int srcNumFrames = fdp.ConsumeIntegralInRange<int>(0, MAX_FRAMES);
+ constexpr size_t metadataSize = 2 + 3 * sizeof(int) + 2 * sizeof(float);
+ std::vector<uint8_t> inputData = fdp.ConsumeBytes<uint8_t>(
+ metadataSize + (srcFrameSize * srcNumFrames));
+ Provider provider(inputData.data(), srcNumFrames, srcFrameSize);
+
+ const uint32_t dstFrameSize = dstChannelCount * audio_bytes_per_sample(dstFormat);
+ const size_t frames = fdp.ConsumeIntegralInRange<size_t>(0, MAX_FRAMES + 1);
+ int8_t dst[dstFrameSize * frames];
+ memset(dst, 0, sizeof(int8_t) * dstFrameSize * frames);
+
+ // Add a small number of loops to see if repeated calls to convert cause
+ // any change in behavior.
+ const int numLoops = fdp.ConsumeIntegralInRange<int>(1, 3);
+ for (int loop = 0; loop < numLoops; ++loop) {
+ switch (fdp.ConsumeIntegralInRange<int>(0, 1)) {
+ case 0:
+ converter.reset();
+ FALLTHROUGH_INTENDED;
+ case 1:
+ converter.convert(dst, &provider, frames);
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
index 938c610..65c9a3c 100644
--- a/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
+++ b/media/libaudioprocessing/tests/fuzzer/libaudioprocessing_resampler_fuzzer.cpp
@@ -34,6 +34,8 @@
#include <unistd.h>
#include <utils/Vector.h>
+#include "libaudioprocessing_fuzz_utils.h"
+
#include <memory>
using namespace android;
@@ -53,46 +55,6 @@
AudioResampler::DYN_HIGH_QUALITY,
};
-class Provider : public AudioBufferProvider {
- const void* mAddr; // base address
- const size_t mNumFrames; // total frames
- const size_t mFrameSize; // size of each frame in bytes
- size_t mNextFrame; // index of next frame to provide
- size_t mUnrel; // number of frames not yet released
- public:
- Provider(const void* addr, size_t frames, size_t frameSize)
- : mAddr(addr),
- mNumFrames(frames),
- mFrameSize(frameSize),
- mNextFrame(0),
- mUnrel(0) {}
- status_t getNextBuffer(Buffer* buffer) override {
- if (buffer->frameCount > mNumFrames - mNextFrame) {
- buffer->frameCount = mNumFrames - mNextFrame;
- }
- mUnrel = buffer->frameCount;
- if (buffer->frameCount > 0) {
- buffer->raw = (char*)mAddr + mFrameSize * mNextFrame;
- return NO_ERROR;
- } else {
- buffer->raw = nullptr;
- return NOT_ENOUGH_DATA;
- }
- }
- virtual void releaseBuffer(Buffer* buffer) {
- if (buffer->frameCount > mUnrel) {
- mNextFrame += mUnrel;
- mUnrel = 0;
- } else {
- mNextFrame += buffer->frameCount;
- mUnrel -= buffer->frameCount;
- }
- buffer->frameCount = 0;
- buffer->raw = nullptr;
- }
- void reset() { mNextFrame = 0; }
-};
-
audio_format_t chooseFormat(AudioResampler::src_quality quality,
uint8_t input_byte) {
switch (quality) {
diff --git a/media/libeffects/lvm/benchmarks/Android.bp b/media/libeffects/lvm/benchmarks/Android.bp
new file mode 100644
index 0000000..420e172
--- /dev/null
+++ b/media/libeffects/lvm/benchmarks/Android.bp
@@ -0,0 +1,16 @@
+cc_benchmark {
+ name: "lvm_benchmark",
+ vendor: true,
+ srcs: ["lvm_benchmark.cpp"],
+ static_libs: [
+ "libbundlewrapper",
+ "libmusicbundle",
+ ],
+ shared_libs: [
+ "libaudioutils",
+ "liblog",
+ ],
+ header_libs: [
+ "libhardware_headers",
+ ],
+}
diff --git a/media/libeffects/lvm/benchmarks/lvm_benchmark.cpp b/media/libeffects/lvm/benchmarks/lvm_benchmark.cpp
new file mode 100644
index 0000000..ee9da3f
--- /dev/null
+++ b/media/libeffects/lvm/benchmarks/lvm_benchmark.cpp
@@ -0,0 +1,168 @@
+/*
+ * Copyright 2020 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 <array>
+#include <climits>
+#include <cstdlib>
+#include <random>
+#include <vector>
+#include <log/log.h>
+#include <benchmark/benchmark.h>
+#include <hardware/audio_effect.h>
+#include <system/audio.h>
+
+extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
+constexpr effect_uuid_t kEffectUuids[] = {
+ // NXP SW BassBoost
+ {0x8631f300, 0x72e2, 0x11df, 0xb57e, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ // NXP SW Virtualizer
+ {0x1d4033c0, 0x8557, 0x11df, 0x9f2d, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ // NXP SW Equalizer
+ {0xce772f20, 0x847d, 0x11df, 0xbb17, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+ // NXP SW Volume
+ {0x119341a0, 0x8469, 0x11df, 0x81f9, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}},
+};
+
+constexpr size_t kNumEffectUuids = std::size(kEffectUuids);
+
+constexpr size_t kFrameCount = 2048;
+
+constexpr audio_channel_mask_t kChMasks[] = {
+ AUDIO_CHANNEL_OUT_MONO, AUDIO_CHANNEL_OUT_STEREO, AUDIO_CHANNEL_OUT_2POINT1,
+ AUDIO_CHANNEL_OUT_QUAD, AUDIO_CHANNEL_OUT_PENTA, AUDIO_CHANNEL_OUT_5POINT1,
+ AUDIO_CHANNEL_OUT_6POINT1, AUDIO_CHANNEL_OUT_7POINT1,
+};
+
+constexpr size_t kNumChMasks = std::size(kChMasks);
+constexpr int kSampleRate = 44100;
+// TODO(b/131240940) Remove once effects are updated to produce mono output
+constexpr size_t kMinOutputChannelCount = 2;
+
+/*******************************************************************
+ * A test result running on Pixel 3 for comparison.
+ * The first parameter indicates the number of channels.
+ * The second parameter indicates the effect.
+ * 0: Bass Boost, 1: Virtualizer, 2: Equalizer, 3: Volume
+ * -----------------------------------------------------
+ * Benchmark Time CPU Iterations
+ * -----------------------------------------------------
+ * BM_LVM/2/0 131279 ns 130855 ns 5195
+ * BM_LVM/2/1 184814 ns 184219 ns 3799
+ * BM_LVM/2/2 91935 ns 91649 ns 7647
+ * BM_LVM/2/3 26707 ns 26623 ns 26281
+ * BM_LVM/3/0 172130 ns 171562 ns 4085
+ * BM_LVM/3/1 192443 ns 191923 ns 3644
+ * BM_LVM/3/2 127444 ns 127107 ns 5483
+ * BM_LVM/3/3 26811 ns 26730 ns 26163
+ * BM_LVM/4/0 223688 ns 223076 ns 3133
+ * BM_LVM/4/1 204961 ns 204408 ns 3425
+ * BM_LVM/4/2 169162 ns 168708 ns 4143
+ * BM_LVM/4/3 37330 ns 37225 ns 18795
+ * BM_LVM/5/0 272628 ns 271668 ns 2568
+ * BM_LVM/5/1 218487 ns 217883 ns 3212
+ * BM_LVM/5/2 211049 ns 210479 ns 3324
+ * BM_LVM/5/3 46962 ns 46835 ns 15051
+ * BM_LVM/6/0 318881 ns 317734 ns 2216
+ * BM_LVM/6/1 231899 ns 231244 ns 3028
+ * BM_LVM/6/2 252655 ns 251963 ns 2771
+ * BM_LVM/6/3 54944 ns 54794 ns 12799
+ * BM_LVM/7/0 366622 ns 365262 ns 1916
+ * BM_LVM/7/1 245076 ns 244388 ns 2866
+ * BM_LVM/7/2 295105 ns 294304 ns 2379
+ * BM_LVM/7/3 63595 ns 63420 ns 11070
+ * BM_LVM/8/0 410957 ns 409387 ns 1706
+ * BM_LVM/8/1 257824 ns 257098 ns 2723
+ * BM_LVM/8/2 342546 ns 341530 ns 2059
+ * BM_LVM/8/3 72896 ns 72700 ns 9685
+ *******************************************************************/
+
+static void BM_LVM(benchmark::State& state) {
+ const size_t chMask = kChMasks[state.range(0) - 1];
+ const effect_uuid_t uuid = kEffectUuids[state.range(1)];
+ const size_t channelCount = audio_channel_count_from_out_mask(chMask);
+
+ // Initialize input buffer with deterministic pseudo-random values
+ std::minstd_rand gen(chMask);
+ std::uniform_real_distribution<> dis(-1.0f, 1.0f);
+ std::vector<float> input(kFrameCount * channelCount);
+ for (auto& in : input) {
+ in = dis(gen);
+ }
+
+ effect_handle_t effectHandle = nullptr;
+ if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.create_effect(&uuid, 1, 1, &effectHandle);
+ status != 0) {
+ ALOGE("create_effect returned an error = %d\n", status);
+ return;
+ }
+
+ effect_config_t config{};
+ config.inputCfg.samplingRate = config.outputCfg.samplingRate = kSampleRate;
+ config.inputCfg.channels = config.outputCfg.channels = chMask;
+ config.inputCfg.format = config.outputCfg.format = AUDIO_FORMAT_PCM_FLOAT;
+
+ int reply = 0;
+ uint32_t replySize = sizeof(reply);
+ if (int status = (*effectHandle)
+ ->command(effectHandle, EFFECT_CMD_SET_CONFIG, sizeof(effect_config_t),
+ &config, &replySize, &reply);
+ status != 0) {
+ ALOGE("command returned an error = %d\n", status);
+ return;
+ }
+
+ if (int status =
+ (*effectHandle)
+ ->command(effectHandle, EFFECT_CMD_ENABLE, 0, nullptr, &replySize, &reply);
+ status != 0) {
+ ALOGE("Command enable call returned error %d\n", reply);
+ return;
+ }
+
+ // Run the test
+ for (auto _ : state) {
+ std::vector<float> output(kFrameCount * std::max(channelCount, kMinOutputChannelCount));
+
+ benchmark::DoNotOptimize(input.data());
+ benchmark::DoNotOptimize(output.data());
+
+ audio_buffer_t inBuffer = {.frameCount = kFrameCount, .f32 = input.data()};
+ audio_buffer_t outBuffer = {.frameCount = kFrameCount, .f32 = output.data()};
+ (*effectHandle)->process(effectHandle, &inBuffer, &outBuffer);
+
+ benchmark::ClobberMemory();
+ }
+
+ state.SetComplexityN(state.range(0));
+
+ if (int status = AUDIO_EFFECT_LIBRARY_INFO_SYM.release_effect(effectHandle); status != 0) {
+ ALOGE("release_effect returned an error = %d\n", status);
+ return;
+ }
+}
+
+static void LVMArgs(benchmark::internal::Benchmark* b) {
+ // TODO(b/131240940) Test single channel once effects are updated to process mono data
+ for (int i = 2; i <= kNumChMasks; i++) {
+ for (int j = 0; j < kNumEffectUuids; ++j) {
+ b->Args({i, j});
+ }
+ }
+}
+
+BENCHMARK(BM_LVM)->Apply(LVMArgs);
+
+BENCHMARK_MAIN();
diff --git a/media/libeffects/lvm/wrapper/Android.bp b/media/libeffects/lvm/wrapper/Android.bp
index f08caec..be60aae 100644
--- a/media/libeffects/lvm/wrapper/Android.bp
+++ b/media/libeffects/lvm/wrapper/Android.bp
@@ -1,5 +1,5 @@
// music bundle wrapper
-cc_library_shared {
+cc_library {
name: "libbundlewrapper",
arch: {
diff --git a/media/libeffects/preprocessing/Android.bp b/media/libeffects/preprocessing/Android.bp
index 16cd0ad..5217cf9 100644
--- a/media/libeffects/preprocessing/Android.bp
+++ b/media/libeffects/preprocessing/Android.bp
@@ -1,6 +1,6 @@
// audio preprocessing wrapper
cc_library_shared {
- name: "libaudiopreprocessing",
+ name: "libaudiopreprocessing_legacy",
vendor: true,
@@ -17,6 +17,7 @@
cflags: [
"-DWEBRTC_POSIX",
+ "-DWEBRTC_LEGACY",
"-fvisibility=hidden",
"-Wall",
"-Werror",
@@ -27,3 +28,34 @@
"libhardware_headers",
],
}
+
+cc_library_shared {
+ name: "libaudiopreprocessing",
+ vendor: true,
+ relative_install_path: "soundfx",
+ srcs: ["PreProcessing.cpp"],
+ local_include_dirs: [
+ ".",
+ ],
+ cflags: [
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ "-Wno-unused-parameter",
+ ],
+
+ shared_libs: [
+ "liblog",
+ "libutils",
+ ],
+
+ static_libs: [
+ "webrtc_audio_processing",
+ ],
+
+ header_libs: [
+ "libaudioeffects",
+ "libhardware_headers",
+ "libwebrtc_absl_headers",
+ ],
+}
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index c7afe2f..f2f74a5 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -23,10 +23,15 @@
#include <hardware/audio_effect.h>
#include <audio_effects/effect_aec.h>
#include <audio_effects/effect_agc.h>
+#ifndef WEBRTC_LEGACY
+#include <audio_effects/effect_agc2.h>
+#endif
#include <audio_effects/effect_ns.h>
#include <module_common_types.h>
#include <audio_processing.h>
+#ifdef WEBRTC_LEGACY
#include "speex/speex_resampler.h"
+#endif
// undefine to perform multi channels API functional tests
//#define DUAL_MIC_TEST
@@ -42,6 +47,9 @@
enum preproc_id
{
PREPROC_AGC, // Automatic Gain Control
+#ifndef WEBRTC_LEGACY
+ PREPROC_AGC2, // Automatic Gain Control 2
+#endif
PREPROC_AEC, // Acoustic Echo Canceler
PREPROC_NS, // Noise Suppressor
PREPROC_NUM_EFFECTS
@@ -103,6 +111,10 @@
int id; // audio session ID
int io; // handle of input stream this session is on
webrtc::AudioProcessing* apm; // handle on webRTC audio processing module (APM)
+#ifndef WEBRTC_LEGACY
+ // Audio Processing module builder
+ webrtc::AudioProcessingBuilder ap_builder;
+#endif
size_t apmFrameCount; // buffer size for webRTC process (10 ms)
uint32_t apmSamplingRate; // webRTC APM sampling rate (8/16 or 32 kHz)
size_t frameCount; // buffer size before input resampler ( <=> apmFrameCount)
@@ -113,25 +125,42 @@
uint32_t enabledMsk; // bit field containing IDs of enabled pre processors
uint32_t processedMsk; // bit field containing IDs of pre processors already
// processed in current round
+#ifdef WEBRTC_LEGACY
webrtc::AudioFrame *procFrame; // audio frame passed to webRTC AMP ProcessStream()
+#else
+ // audio config strucutre
+ webrtc::AudioProcessing::Config config;
+ webrtc::StreamConfig inputConfig; // input stream configuration
+ webrtc::StreamConfig outputConfig; // output stream configuration
+#endif
int16_t *inBuf; // input buffer used when resampling
size_t inBufSize; // input buffer size in frames
size_t framesIn; // number of frames in input buffer
+#ifdef WEBRTC_LEGACY
SpeexResamplerState *inResampler; // handle on input speex resampler
+#endif
int16_t *outBuf; // output buffer used when resampling
size_t outBufSize; // output buffer size in frames
size_t framesOut; // number of frames in output buffer
+#ifdef WEBRTC_LEGACY
SpeexResamplerState *outResampler; // handle on output speex resampler
+#endif
uint32_t revChannelCount; // number of channels on reverse stream
uint32_t revEnabledMsk; // bit field containing IDs of enabled pre processors
// with reverse channel
uint32_t revProcessedMsk; // bit field containing IDs of pre processors with reverse
// channel already processed in current round
+#ifdef WEBRTC_LEGACY
webrtc::AudioFrame *revFrame; // audio frame passed to webRTC AMP AnalyzeReverseStream()
+#else
+ webrtc::StreamConfig revConfig; // reverse stream configuration.
+#endif
int16_t *revBuf; // reverse channel input buffer
size_t revBufSize; // reverse channel input buffer size
size_t framesRev; // number of frames in reverse channel input buffer
+#ifdef WEBRTC_LEGACY
SpeexResamplerState *revResampler; // handle on reverse channel input speex resampler
+#endif
};
#ifdef DUAL_MIC_TEST
@@ -188,6 +217,20 @@
"The Android Open Source Project"
};
+#ifndef WEBRTC_LEGACY
+// Automatic Gain Control 2
+static const effect_descriptor_t sAgc2Descriptor = {
+ { 0xae3c653b, 0xbe18, 0x4ab8, 0x8938, { 0x41, 0x8f, 0x0a, 0x7f, 0x06, 0xac } }, // type
+ { 0x89f38e65, 0xd4d2, 0x4d64, 0xad0e, { 0x2b, 0x3e, 0x79, 0x9e, 0xa8, 0x86 } }, // uuid
+ EFFECT_CONTROL_API_VERSION,
+ (EFFECT_FLAG_TYPE_PRE_PROC|EFFECT_FLAG_DEVICE_IND),
+ 0, //FIXME indicate CPU load
+ 0, //FIXME indicate memory usage
+ "Automatic Gain Control 2",
+ "The Android Open Source Project"
+};
+#endif
+
// Acoustic Echo Cancellation
static const effect_descriptor_t sAecDescriptor = {
{ 0x7b491460, 0x8d4d, 0x11e0, 0xbd61, { 0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b } }, // type
@@ -215,6 +258,9 @@
static const effect_descriptor_t *sDescriptors[PREPROC_NUM_EFFECTS] = {
&sAgcDescriptor,
+#ifndef WEBRTC_LEGACY
+ &sAgc2Descriptor,
+#endif
&sAecDescriptor,
&sNsDescriptor
};
@@ -225,6 +271,9 @@
const effect_uuid_t * const sUuidToPreProcTable[PREPROC_NUM_EFFECTS] = {
FX_IID_AGC,
+#ifndef WEBRTC_LEGACY
+ FX_IID_AGC2,
+#endif
FX_IID_AEC,
FX_IID_NS
};
@@ -266,19 +315,50 @@
static const int kAgcDefaultCompGain = 9;
static const bool kAgcDefaultLimiter = true;
+#ifndef WEBRTC_LEGACY
+int Agc2Init (preproc_effect_t *effect)
+{
+ ALOGV("Agc2Init");
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.gain_controller2.fixed_digital.gain_db = 0.f;
+ effect->session->config.gain_controller2.adaptive_digital.level_estimator =
+ effect->session->config.gain_controller2.kRms;
+ effect->session->config.gain_controller2.adaptive_digital.extra_saturation_margin_db = 2.f;
+ effect->session->apm->ApplyConfig(effect->session->config);
+ return 0;
+}
+#endif
+
int AgcInit (preproc_effect_t *effect)
{
ALOGV("AgcInit");
+#ifdef WEBRTC_LEGACY
webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
agc->set_mode(webrtc::GainControl::kFixedDigital);
agc->set_target_level_dbfs(kAgcDefaultTargetLevel);
agc->set_compression_gain_db(kAgcDefaultCompGain);
agc->enable_limiter(kAgcDefaultLimiter);
+#else
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.gain_controller1.target_level_dbfs = kAgcDefaultTargetLevel;
+ effect->session->config.gain_controller1.compression_gain_db = kAgcDefaultCompGain;
+ effect->session->config.gain_controller1.enable_limiter = kAgcDefaultLimiter;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
return 0;
}
+#ifndef WEBRTC_LEGACY
+int Agc2Create(preproc_effect_t *effect)
+{
+ Agc2Init(effect);
+ return 0;
+}
+#endif
+
int AgcCreate(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
webrtc::GainControl *agc = effect->session->apm->gain_control();
ALOGV("AgcCreate got agc %p", agc);
if (agc == NULL) {
@@ -286,10 +366,93 @@
return -ENOMEM;
}
effect->engine = static_cast<preproc_fx_handle_t>(agc);
+#endif
AgcInit(effect);
return 0;
}
+#ifndef WEBRTC_LEGACY
+int Agc2GetParameter(preproc_effect_t *effect,
+ void *pParam,
+ uint32_t *pValueSize,
+ void *pValue)
+{
+ int status = 0;
+ uint32_t param = *(uint32_t *)pParam;
+ agc2_settings_t *pProperties = (agc2_settings_t *)pValue;
+
+ switch (param) {
+ case AGC2_PARAM_FIXED_DIGITAL_GAIN:
+ if (*pValueSize < sizeof(float)) {
+ *pValueSize = 0.f;
+ return -EINVAL;
+ }
+ break;
+ case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR:
+ if (*pValueSize < sizeof(int32_t)) {
+ *pValueSize = 0;
+ return -EINVAL;
+ }
+ break;
+ case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN:
+ if (*pValueSize < sizeof(float)) {
+ *pValueSize = 0.f;
+ return -EINVAL;
+ }
+ break;
+ case AGC2_PARAM_PROPERTIES:
+ if (*pValueSize < sizeof(agc2_settings_t)) {
+ *pValueSize = 0;
+ return -EINVAL;
+ }
+ break;
+
+ default:
+ ALOGW("Agc2GetParameter() unknown param %08x", param);
+ status = -EINVAL;
+ break;
+ }
+
+ effect->session->config = effect->session->apm->GetConfig();
+ switch (param) {
+ case AGC2_PARAM_FIXED_DIGITAL_GAIN:
+ *(float *) pValue =
+ (float)(effect->session->config.gain_controller2.fixed_digital.gain_db);
+ ALOGV("Agc2GetParameter() target level %f dB", *(float *) pValue);
+ break;
+ case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR:
+ *(uint32_t *) pValue =
+ (uint32_t)(effect->session->config.gain_controller2.adaptive_digital.
+ level_estimator);
+ ALOGV("Agc2GetParameter() level estimator %d",
+ *(webrtc::AudioProcessing::Config::GainController2::LevelEstimator *) pValue);
+ break;
+ case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN:
+ *(float *) pValue =
+ (float)(effect->session->config.gain_controller2.adaptive_digital.
+ extra_saturation_margin_db);
+ ALOGV("Agc2GetParameter() extra saturation margin %f dB", *(float *) pValue);
+ break;
+ case AGC2_PARAM_PROPERTIES:
+ pProperties->fixedDigitalGain =
+ (float)(effect->session->config.gain_controller2.fixed_digital.gain_db);
+ pProperties->level_estimator =
+ (uint32_t)(effect->session->config.gain_controller2.adaptive_digital.
+ level_estimator);
+ pProperties->extraSaturationMargin =
+ (float)(effect->session->config.gain_controller2.adaptive_digital.
+ extra_saturation_margin_db);
+ break;
+ default:
+ ALOGW("Agc2GetParameter() unknown param %d", param);
+ status = -EINVAL;
+ break;
+ }
+
+ return status;
+}
+#endif
+
int AgcGetParameter(preproc_effect_t *effect,
void *pParam,
uint32_t *pValueSize,
@@ -298,7 +461,9 @@
int status = 0;
uint32_t param = *(uint32_t *)pParam;
t_agc_settings *pProperties = (t_agc_settings *)pValue;
+#ifdef WEBRTC_LEGACY
webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
+#endif
switch (param) {
case AGC_PARAM_TARGET_LEVEL:
@@ -327,6 +492,7 @@
break;
}
+#ifdef WEBRTC_LEGACY
switch (param) {
case AGC_PARAM_TARGET_LEVEL:
*(int16_t *) pValue = (int16_t)(agc->target_level_dbfs() * -100);
@@ -351,12 +517,98 @@
status = -EINVAL;
break;
}
+#else
+ effect->session->config = effect->session->apm->GetConfig();
+ switch (param) {
+ case AGC_PARAM_TARGET_LEVEL:
+ *(int16_t *) pValue =
+ (int16_t)(effect->session->config.gain_controller1.target_level_dbfs * -100);
+ ALOGV("AgcGetParameter() target level %d milliBels", *(int16_t *) pValue);
+ break;
+ case AGC_PARAM_COMP_GAIN:
+ *(int16_t *) pValue =
+ (int16_t)(effect->session->config.gain_controller1.compression_gain_db * -100);
+ ALOGV("AgcGetParameter() comp gain %d milliBels", *(int16_t *) pValue);
+ break;
+ case AGC_PARAM_LIMITER_ENA:
+ *(bool *) pValue =
+ (bool)(effect->session->config.gain_controller1.enable_limiter);
+ ALOGV("AgcGetParameter() limiter enabled %s",
+ (*(int16_t *) pValue != 0) ? "true" : "false");
+ break;
+ case AGC_PARAM_PROPERTIES:
+ pProperties->targetLevel =
+ (int16_t)(effect->session->config.gain_controller1.target_level_dbfs * -100);
+ pProperties->compGain =
+ (int16_t)(effect->session->config.gain_controller1.compression_gain_db * -100);
+ pProperties->limiterEnabled =
+ (bool)(effect->session->config.gain_controller1.enable_limiter);
+ break;
+ default:
+ ALOGW("AgcGetParameter() unknown param %d", param);
+ status = -EINVAL;
+ break;
+ }
+#endif
return status;
}
+#ifndef WEBRTC_LEGACY
+int Agc2SetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
+{
+ int status = 0;
+ uint32_t param = *(uint32_t *)pParam;
+ float valueFloat = 0.f;
+ agc2_settings_t *pProperties = (agc2_settings_t *)pValue;
+ effect->session->config = effect->session->apm->GetConfig();
+ switch (param) {
+ case AGC2_PARAM_FIXED_DIGITAL_GAIN:
+ valueFloat = (float)(*(int32_t *) pValue);
+ ALOGV("Agc2SetParameter() fixed digital gain %f dB", valueFloat);
+ effect->session->config.gain_controller2.fixed_digital.gain_db = valueFloat;
+ break;
+ case AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR:
+ ALOGV("Agc2SetParameter() level estimator %d", *(webrtc::AudioProcessing::Config::
+ GainController2::LevelEstimator *) pValue);
+ effect->session->config.gain_controller2.adaptive_digital.level_estimator =
+ (*(webrtc::AudioProcessing::Config::GainController2::LevelEstimator *) pValue);
+ break;
+ case AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN:
+ valueFloat = (float)(*(int32_t *) pValue);
+ ALOGV("Agc2SetParameter() extra saturation margin %f dB", valueFloat);
+ effect->session->config.gain_controller2.adaptive_digital.extra_saturation_margin_db =
+ valueFloat;
+ break;
+ case AGC2_PARAM_PROPERTIES:
+ ALOGV("Agc2SetParameter() properties gain %f, level %d margin %f",
+ pProperties->fixedDigitalGain,
+ pProperties->level_estimator,
+ pProperties->extraSaturationMargin);
+ effect->session->config.gain_controller2.fixed_digital.gain_db =
+ pProperties->fixedDigitalGain;
+ effect->session->config.gain_controller2.adaptive_digital.level_estimator =
+ (webrtc::AudioProcessing::Config::GainController2::LevelEstimator)pProperties->
+ level_estimator;
+ effect->session->config.gain_controller2.adaptive_digital.extra_saturation_margin_db =
+ pProperties->extraSaturationMargin;
+ break;
+ default:
+ ALOGW("Agc2SetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
+ status = -EINVAL;
+ break;
+ }
+ effect->session->apm->ApplyConfig(effect->session->config);
+
+ ALOGV("Agc2SetParameter() done status %d", status);
+
+ return status;
+}
+#endif
+
int AgcSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
{
int status = 0;
+#ifdef WEBRTC_LEGACY
uint32_t param = *(uint32_t *)pParam;
t_agc_settings *pProperties = (t_agc_settings *)pValue;
webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
@@ -390,27 +642,95 @@
status = -EINVAL;
break;
}
+#else
+ uint32_t param = *(uint32_t *)pParam;
+ t_agc_settings *pProperties = (t_agc_settings *)pValue;
+ effect->session->config = effect->session->apm->GetConfig();
+ switch (param) {
+ case AGC_PARAM_TARGET_LEVEL:
+ ALOGV("AgcSetParameter() target level %d milliBels", *(int16_t *)pValue);
+ effect->session->config.gain_controller1.target_level_dbfs =
+ (-(*(int16_t *)pValue / 100));
+ break;
+ case AGC_PARAM_COMP_GAIN:
+ ALOGV("AgcSetParameter() comp gain %d milliBels", *(int16_t *)pValue);
+ effect->session->config.gain_controller1.compression_gain_db =
+ (*(int16_t *)pValue / 100);
+ break;
+ case AGC_PARAM_LIMITER_ENA:
+ ALOGV("AgcSetParameter() limiter enabled %s", *(bool *)pValue ? "true" : "false");
+ effect->session->config.gain_controller1.enable_limiter =
+ (*(bool *)pValue);
+ break;
+ case AGC_PARAM_PROPERTIES:
+ ALOGV("AgcSetParameter() properties level %d, gain %d limiter %d",
+ pProperties->targetLevel,
+ pProperties->compGain,
+ pProperties->limiterEnabled);
+ effect->session->config.gain_controller1.target_level_dbfs =
+ -(pProperties->targetLevel / 100);
+ effect->session->config.gain_controller1.compression_gain_db =
+ pProperties->compGain / 100;
+ effect->session->config.gain_controller1.enable_limiter =
+ pProperties->limiterEnabled;
+ break;
+ default:
+ ALOGW("AgcSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
+ status = -EINVAL;
+ break;
+ }
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
ALOGV("AgcSetParameter() done status %d", status);
return status;
}
+#ifndef WEBRTC_LEGACY
+void Agc2Enable(preproc_effect_t *effect)
+{
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.gain_controller2.enabled = true;
+ effect->session->apm->ApplyConfig(effect->session->config);
+}
+#endif
+
void AgcEnable(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
ALOGV("AgcEnable agc %p", agc);
agc->Enable(true);
+#else
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.gain_controller1.enabled = true;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
}
+#ifndef WEBRTC_LEGACY
+void Agc2Disable(preproc_effect_t *effect)
+{
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.gain_controller2.enabled = false;
+ effect->session->apm->ApplyConfig(effect->session->config);
+}
+#endif
+
void AgcDisable(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
ALOGV("AgcDisable");
webrtc::GainControl *agc = static_cast<webrtc::GainControl *>(effect->engine);
agc->Enable(false);
+#else
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.gain_controller1.enabled = false;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
}
-
static const preproc_ops_t sAgcOps = {
AgcCreate,
AgcInit,
@@ -422,26 +742,48 @@
NULL
};
+#ifndef WEBRTC_LEGACY
+static const preproc_ops_t sAgc2Ops = {
+ Agc2Create,
+ Agc2Init,
+ NULL,
+ Agc2Enable,
+ Agc2Disable,
+ Agc2SetParameter,
+ Agc2GetParameter,
+ NULL
+};
+#endif
//------------------------------------------------------------------------------
// Acoustic Echo Canceler (AEC)
//------------------------------------------------------------------------------
+#ifdef WEBRTC_LEGACY
static const webrtc::EchoControlMobile::RoutingMode kAecDefaultMode =
webrtc::EchoControlMobile::kEarpiece;
static const bool kAecDefaultComfortNoise = true;
+#endif
int AecInit (preproc_effect_t *effect)
{
ALOGV("AecInit");
+#ifdef WEBRTC_LEGACY
webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
aec->set_routing_mode(kAecDefaultMode);
aec->enable_comfort_noise(kAecDefaultComfortNoise);
+#else
+ effect->session->config =
+ effect->session->apm->GetConfig() ;
+ effect->session->config.echo_canceller.mobile_mode = false;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
return 0;
}
int AecCreate(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
webrtc::EchoControlMobile *aec = effect->session->apm->echo_control_mobile();
ALOGV("AecCreate got aec %p", aec);
if (aec == NULL) {
@@ -449,6 +791,7 @@
return -ENOMEM;
}
effect->engine = static_cast<preproc_fx_handle_t>(aec);
+#endif
AecInit (effect);
return 0;
}
@@ -470,6 +813,14 @@
*(uint32_t *)pValue = 1000 * effect->session->apm->stream_delay_ms();
ALOGV("AecGetParameter() echo delay %d us", *(uint32_t *)pValue);
break;
+#ifndef WEBRTC_LEGACY
+ case AEC_PARAM_MOBILE_MODE:
+ effect->session->config =
+ effect->session->apm->GetConfig() ;
+ *(uint32_t *)pValue = effect->session->config.echo_canceller.mobile_mode;
+ ALOGV("AecGetParameter() mobile mode %d us", *(uint32_t *)pValue);
+ break;
+#endif
default:
ALOGW("AecGetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
status = -EINVAL;
@@ -490,6 +841,15 @@
status = effect->session->apm->set_stream_delay_ms(value/1000);
ALOGV("AecSetParameter() echo delay %d us, status %d", value, status);
break;
+#ifndef WEBRTC_LEGACY
+ case AEC_PARAM_MOBILE_MODE:
+ effect->session->config =
+ effect->session->apm->GetConfig() ;
+ effect->session->config.echo_canceller.mobile_mode = value;
+ ALOGV("AecSetParameter() mobile mode %d us", value);
+ effect->session->apm->ApplyConfig(effect->session->config);
+ break;
+#endif
default:
ALOGW("AecSetParameter() unknown param %08x value %08x", param, *(uint32_t *)pValue);
status = -EINVAL;
@@ -500,28 +860,43 @@
void AecEnable(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
ALOGV("AecEnable aec %p", aec);
aec->Enable(true);
+#else
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.echo_canceller.enabled = true;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
}
void AecDisable(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
ALOGV("AecDisable");
webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
aec->Enable(false);
+#else
+ effect->session->config = effect->session->apm->GetConfig();
+ effect->session->config.echo_canceller.enabled = false;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
}
int AecSetDevice(preproc_effect_t *effect, uint32_t device)
{
ALOGV("AecSetDevice %08x", device);
+#ifdef WEBRTC_LEGACY
webrtc::EchoControlMobile *aec = static_cast<webrtc::EchoControlMobile *>(effect->engine);
webrtc::EchoControlMobile::RoutingMode mode = webrtc::EchoControlMobile::kQuietEarpieceOrHeadset;
+#endif
if (audio_is_input_device(device)) {
return 0;
}
+#ifdef WEBRTC_LEGACY
switch(device) {
case AUDIO_DEVICE_OUT_EARPIECE:
mode = webrtc::EchoControlMobile::kEarpiece;
@@ -536,6 +911,7 @@
break;
}
aec->set_routing_mode(mode);
+#endif
return 0;
}
@@ -554,11 +930,17 @@
// Noise Suppression (NS)
//------------------------------------------------------------------------------
+#ifdef WEBRTC_LEGACY
static const webrtc::NoiseSuppression::Level kNsDefaultLevel = webrtc::NoiseSuppression::kModerate;
+#else
+static const webrtc::AudioProcessing::Config::NoiseSuppression::Level kNsDefaultLevel =
+ webrtc::AudioProcessing::Config::NoiseSuppression::kModerate;
+#endif
int NsInit (preproc_effect_t *effect)
{
ALOGV("NsInit");
+#ifdef WEBRTC_LEGACY
webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
ns->set_level(kNsDefaultLevel);
webrtc::Config config;
@@ -575,12 +957,20 @@
config.Set<webrtc::Beamforming>(
new webrtc::Beamforming(false, geometry));
effect->session->apm->SetExtraOptions(config);
+#else
+ effect->session->config =
+ effect->session->apm->GetConfig() ;
+ effect->session->config.noise_suppression.level =
+ kNsDefaultLevel;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
effect->type = NS_TYPE_SINGLE_CHANNEL;
return 0;
}
int NsCreate(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
webrtc::NoiseSuppression *ns = effect->session->apm->noise_suppression();
ALOGV("NsCreate got ns %p", ns);
if (ns == NULL) {
@@ -588,6 +978,7 @@
return -ENOMEM;
}
effect->engine = static_cast<preproc_fx_handle_t>(ns);
+#endif
NsInit (effect);
return 0;
}
@@ -604,6 +995,7 @@
int NsSetParameter (preproc_effect_t *effect, void *pParam, void *pValue)
{
int status = 0;
+#ifdef WEBRTC_LEGACY
webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
uint32_t param = *(uint32_t *)pParam;
uint32_t value = *(uint32_t *)pValue;
@@ -629,12 +1021,30 @@
ALOGW("NsSetParameter() unknown param %08x value %08x", param, value);
status = -EINVAL;
}
+#else
+ uint32_t param = *(uint32_t *)pParam;
+ uint32_t value = *(uint32_t *)pValue;
+ effect->session->config =
+ effect->session->apm->GetConfig();
+ switch (param) {
+ case NS_PARAM_LEVEL:
+ effect->session->config.noise_suppression.level =
+ (webrtc::AudioProcessing::Config::NoiseSuppression::Level)value;
+ ALOGV("NsSetParameter() level %d", value);
+ break;
+ default:
+ ALOGW("NsSetParameter() unknown param %08x value %08x", param, value);
+ status = -EINVAL;
+ }
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
return status;
}
void NsEnable(preproc_effect_t *effect)
{
+#ifdef WEBRTC_LEGACY
webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
ALOGV("NsEnable ns %p", ns);
ns->Enable(true);
@@ -644,17 +1054,30 @@
config.Set<webrtc::Beamforming>(new webrtc::Beamforming(true, geometry));
effect->session->apm->SetExtraOptions(config);
}
+#else
+ effect->session->config =
+ effect->session->apm->GetConfig();
+ effect->session->config.noise_suppression.enabled = true;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
}
void NsDisable(preproc_effect_t *effect)
{
ALOGV("NsDisable");
+#ifdef WEBRTC_LEGACY
webrtc::NoiseSuppression *ns = static_cast<webrtc::NoiseSuppression *>(effect->engine);
ns->Enable(false);
webrtc::Config config;
std::vector<webrtc::Point> geometry;
config.Set<webrtc::Beamforming>(new webrtc::Beamforming(false, geometry));
effect->session->apm->SetExtraOptions(config);
+#else
+ effect->session->config =
+ effect->session->apm->GetConfig();
+ effect->session->config.noise_suppression.enabled = false;
+ effect->session->apm->ApplyConfig(effect->session->config);
+#endif
}
static const preproc_ops_t sNsOps = {
@@ -669,8 +1092,12 @@
};
+
static const preproc_ops_t *sPreProcOps[PREPROC_NUM_EFFECTS] = {
&sAgcOps,
+#ifndef WEBRTC_LEGACY
+ &sAgc2Ops,
+#endif
&sAecOps,
&sNsOps
};
@@ -812,7 +1239,9 @@
session->id = 0;
session->io = 0;
session->createdMsk = 0;
+#ifdef WEBRTC_LEGACY
session->apm = NULL;
+#endif
for (i = 0; i < PREPROC_NUM_EFFECTS && status == 0; i++) {
status = Effect_Init(&session->effects[i], i);
}
@@ -829,6 +1258,7 @@
ALOGV("Session_CreateEffect procId %d, createdMsk %08x", procId, session->createdMsk);
if (session->createdMsk == 0) {
+#ifdef WEBRTC_LEGACY
session->apm = webrtc::AudioProcessing::Create();
if (session->apm == NULL) {
ALOGW("Session_CreateEffect could not get apm engine");
@@ -850,28 +1280,53 @@
ALOGW("Session_CreateEffect could not allocate reverse audio frame");
goto error;
}
+#else
+ session->apm = session->ap_builder.Create();
+ if (session->apm == NULL) {
+ ALOGW("Session_CreateEffect could not get apm engine");
+ goto error;
+ }
+#endif
session->apmSamplingRate = kPreprocDefaultSr;
session->apmFrameCount = (kPreprocDefaultSr) / 100;
session->frameCount = session->apmFrameCount;
session->samplingRate = kPreprocDefaultSr;
session->inChannelCount = kPreProcDefaultCnl;
session->outChannelCount = kPreProcDefaultCnl;
+#ifdef WEBRTC_LEGACY
session->procFrame->sample_rate_hz_ = kPreprocDefaultSr;
session->procFrame->num_channels_ = kPreProcDefaultCnl;
+#else
+ session->inputConfig.set_sample_rate_hz(kPreprocDefaultSr);
+ session->inputConfig.set_num_channels(kPreProcDefaultCnl);
+ session->outputConfig.set_sample_rate_hz(kPreprocDefaultSr);
+ session->outputConfig.set_num_channels(kPreProcDefaultCnl);
+#endif
session->revChannelCount = kPreProcDefaultCnl;
+#ifdef WEBRTC_LEGACY
session->revFrame->sample_rate_hz_ = kPreprocDefaultSr;
session->revFrame->num_channels_ = kPreProcDefaultCnl;
+#else
+ session->revConfig.set_sample_rate_hz(kPreprocDefaultSr);
+ session->revConfig.set_num_channels(kPreProcDefaultCnl);
+#endif
session->enabledMsk = 0;
session->processedMsk = 0;
session->revEnabledMsk = 0;
session->revProcessedMsk = 0;
+#ifdef WEBRTC_LEGACY
session->inResampler = NULL;
+#endif
session->inBuf = NULL;
session->inBufSize = 0;
+#ifdef WEBRTC_LEGACY
session->outResampler = NULL;
+#endif
session->outBuf = NULL;
session->outBufSize = 0;
+#ifdef WEBRTC_LEGACY
session->revResampler = NULL;
+#endif
session->revBuf = NULL;
session->revBufSize = 0;
}
@@ -885,12 +1340,17 @@
error:
if (session->createdMsk == 0) {
+#ifdef WEBRTC_LEGACY
delete session->revFrame;
session->revFrame = NULL;
delete session->procFrame;
session->procFrame = NULL;
delete session->apm;
session->apm = NULL; // NOLINT(clang-analyzer-cplusplus.NewDelete)
+#else
+ delete session->apm;
+ session->apm = NULL;
+#endif
}
return status;
}
@@ -901,6 +1361,7 @@
ALOGW_IF(Effect_Release(fx) != 0, " Effect_Release() failed for proc ID %d", fx->procId);
session->createdMsk &= ~(1<<fx->procId);
if (session->createdMsk == 0) {
+#ifdef WEBRTC_LEGACY
delete session->apm;
session->apm = NULL;
delete session->procFrame;
@@ -919,6 +1380,10 @@
speex_resampler_destroy(session->revResampler);
session->revResampler = NULL;
}
+#else
+ delete session->apm;
+ session->apm = NULL;
+#endif
delete session->inBuf;
session->inBuf = NULL;
delete session->outBuf;
@@ -946,7 +1411,9 @@
ALOGV("Session_SetConfig sr %d cnl %08x",
config->inputCfg.samplingRate, config->inputCfg.channels);
+#ifdef WEBRTC_LEGACY
int status;
+#endif
// AEC implementation is limited to 16kHz
if (config->inputCfg.samplingRate >= 32000 && !(session->createdMsk & (1 << PREPROC_AEC))) {
@@ -958,6 +1425,7 @@
session->apmSamplingRate = 8000;
}
+#ifdef WEBRTC_LEGACY
const webrtc::ProcessingConfig processing_config = {
{{static_cast<int>(session->apmSamplingRate), inCnl},
{static_cast<int>(session->apmSamplingRate), outCnl},
@@ -967,23 +1435,41 @@
if (status < 0) {
return -EINVAL;
}
+#endif
session->samplingRate = config->inputCfg.samplingRate;
session->apmFrameCount = session->apmSamplingRate / 100;
if (session->samplingRate == session->apmSamplingRate) {
session->frameCount = session->apmFrameCount;
} else {
+#ifdef WEBRTC_LEGACY
session->frameCount = (session->apmFrameCount * session->samplingRate) /
session->apmSamplingRate + 1;
+#else
+ session->frameCount = (session->apmFrameCount * session->samplingRate) /
+ session->apmSamplingRate;
+#endif
}
session->inChannelCount = inCnl;
session->outChannelCount = outCnl;
+#ifdef WEBRTC_LEGACY
session->procFrame->num_channels_ = inCnl;
session->procFrame->sample_rate_hz_ = session->apmSamplingRate;
+#else
+ session->inputConfig.set_sample_rate_hz(session->samplingRate);
+ session->inputConfig.set_num_channels(inCnl);
+ session->outputConfig.set_sample_rate_hz(session->samplingRate);
+ session->outputConfig.set_num_channels(inCnl);
+#endif
session->revChannelCount = inCnl;
+#ifdef WEBRTC_LEGACY
session->revFrame->num_channels_ = inCnl;
session->revFrame->sample_rate_hz_ = session->apmSamplingRate;
+#else
+ session->revConfig.set_sample_rate_hz(session->samplingRate);
+ session->revConfig.set_num_channels(inCnl);
+#endif
// force process buffer reallocation
session->inBufSize = 0;
@@ -992,6 +1478,7 @@
session->framesOut = 0;
+#ifdef WEBRTC_LEGACY
if (session->inResampler != NULL) {
speex_resampler_destroy(session->inResampler);
session->inResampler = NULL;
@@ -1043,6 +1530,7 @@
return -EINVAL;
}
}
+#endif
session->state = PREPROC_SESSION_STATE_CONFIG;
return 0;
@@ -1079,6 +1567,7 @@
return -EINVAL;
}
uint32_t inCnl = audio_channel_count_from_out_mask(config->inputCfg.channels);
+#ifdef WEBRTC_LEGACY
const webrtc::ProcessingConfig processing_config = {
{{static_cast<int>(session->apmSamplingRate), session->inChannelCount},
{static_cast<int>(session->apmSamplingRate), session->outChannelCount},
@@ -1088,9 +1577,12 @@
if (status < 0) {
return -EINVAL;
}
+#endif
session->revChannelCount = inCnl;
+#ifdef WEBRTC_LEGACY
session->revFrame->num_channels_ = inCnl;
session->revFrame->sample_rate_hz_ = session->apmSamplingRate;
+#endif
// force process buffer reallocation
session->revBufSize = 0;
session->framesRev = 0;
@@ -1114,6 +1606,7 @@
if (enabled) {
if(session->enabledMsk == 0) {
session->framesIn = 0;
+#ifdef WEBRTC_LEGACY
if (session->inResampler != NULL) {
speex_resampler_reset_mem(session->inResampler);
}
@@ -1121,13 +1614,16 @@
if (session->outResampler != NULL) {
speex_resampler_reset_mem(session->outResampler);
}
+#endif
}
session->enabledMsk |= (1 << procId);
if (HasReverseStream(procId)) {
session->framesRev = 0;
+#ifdef WEBRTC_LEGACY
if (session->revResampler != NULL) {
speex_resampler_reset_mem(session->revResampler);
}
+#endif
session->revEnabledMsk |= (1 << procId);
}
} else {
@@ -1252,6 +1748,7 @@
return 0;
}
+#ifdef WEBRTC_LEGACY
if (session->inResampler != NULL) {
size_t fr = session->frameCount - session->framesIn;
if (inBuffer->frameCount < fr) {
@@ -1335,6 +1832,28 @@
session->procFrame->samples_per_channel_ = session->apmFrameCount;
effect->session->apm->ProcessStream(session->procFrame);
+#else
+ size_t fr = session->frameCount - session->framesIn;
+ if (inBuffer->frameCount < fr) {
+ fr = inBuffer->frameCount;
+ }
+ session->framesIn += fr;
+ inBuffer->frameCount = fr;
+ if (session->framesIn < session->frameCount) {
+ return 0;
+ }
+ session->framesIn = 0;
+ if (int status = effect->session->apm->ProcessStream(
+ (const int16_t* const)inBuffer->s16,
+ (const webrtc::StreamConfig)effect->session->inputConfig,
+ (const webrtc::StreamConfig)effect->session->outputConfig,
+ (int16_t* const)outBuffer->s16);
+ status != 0) {
+ ALOGE("Process Stream failed with error %d\n", status);
+ return status;
+ }
+ outBuffer->frameCount = inBuffer->frameCount;
+#endif
if (session->outBufSize < session->framesOut + session->frameCount) {
int16_t *buf;
@@ -1350,6 +1869,7 @@
session->outBuf = buf;
}
+#ifdef WEBRTC_LEGACY
if (session->outResampler != NULL) {
spx_uint32_t frIn = session->apmFrameCount;
spx_uint32_t frOut = session->frameCount;
@@ -1375,6 +1895,9 @@
session->framesOut += session->frameCount;
}
size_t fr = session->framesOut;
+#else
+ fr = session->framesOut;
+#endif
if (framesRq - framesWr < fr) {
fr = framesRq - framesWr;
}
@@ -1794,6 +2317,7 @@
if ((session->revProcessedMsk & session->revEnabledMsk) == session->revEnabledMsk) {
effect->session->revProcessedMsk = 0;
+#ifdef WEBRTC_LEGACY
if (session->revResampler != NULL) {
size_t fr = session->frameCount - session->framesRev;
if (inBuffer->frameCount < fr) {
@@ -1858,6 +2382,27 @@
}
session->revFrame->samples_per_channel_ = session->apmFrameCount;
effect->session->apm->AnalyzeReverseStream(session->revFrame);
+#else
+ size_t fr = session->frameCount - session->framesRev;
+ if (inBuffer->frameCount < fr) {
+ fr = inBuffer->frameCount;
+ }
+ session->framesRev += fr;
+ inBuffer->frameCount = fr;
+ if (session->framesRev < session->frameCount) {
+ return 0;
+ }
+ session->framesRev = 0;
+ if (int status = effect->session->apm->ProcessReverseStream(
+ (const int16_t* const)inBuffer->s16,
+ (const webrtc::StreamConfig)effect->session->revConfig,
+ (const webrtc::StreamConfig)effect->session->revConfig,
+ (int16_t* const)outBuffer->s16);
+ status != 0) {
+ ALOGE("Process Reverse Stream failed with error %d\n", status);
+ return status;
+ }
+#endif
return 0;
} else {
return -ENODATA;
diff --git a/media/libeffects/preprocessing/tests/Android.bp b/media/libeffects/preprocessing/tests/Android.bp
index 71f6e8f..045b0d3 100644
--- a/media/libeffects/preprocessing/tests/Android.bp
+++ b/media/libeffects/preprocessing/tests/Android.bp
@@ -1,5 +1,37 @@
// audio preprocessing unit test
cc_test {
+ name: "AudioPreProcessingLegacyTest",
+
+ vendor: true,
+
+ relative_install_path: "soundfx",
+
+ srcs: ["PreProcessingTest.cpp"],
+
+ shared_libs: [
+ "libaudiopreprocessing_legacy",
+ "libaudioutils",
+ "liblog",
+ "libutils",
+ "libwebrtc_audio_preprocessing",
+ ],
+
+ cflags: [
+ "-DWEBRTC_POSIX",
+ "-DWEBRTC_LEGACY",
+ "-fvisibility=default",
+ "-Wall",
+ "-Werror",
+ "-Wextra",
+ ],
+
+ header_libs: [
+ "libaudioeffects",
+ "libhardware_headers",
+ ],
+}
+
+cc_test {
name: "AudioPreProcessingTest",
vendor: true,
@@ -13,16 +45,7 @@
"libaudioutils",
"liblog",
"libutils",
- "libwebrtc_audio_preprocessing",
],
-
- cflags: [
- "-DWEBRTC_POSIX",
- "-fvisibility=default",
- "-Wall",
- "-Werror",
- ],
-
header_libs: [
"libaudioeffects",
"libhardware_headers",
diff --git a/media/libeffects/preprocessing/tests/PreProcessingTest.cpp b/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
index 5c81d78..3244c1f 100644
--- a/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
+++ b/media/libeffects/preprocessing/tests/PreProcessingTest.cpp
@@ -14,23 +14,19 @@
* limitations under the License.
*/
+#include <getopt.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <sys/stat.h>
+#include <vector>
+
#include <audio_effects/effect_aec.h>
#include <audio_effects/effect_agc.h>
+#ifndef WEBRTC_LEGACY
+#include <audio_effects/effect_agc2.h>
+#endif
#include <audio_effects/effect_ns.h>
-#include <audio_processing.h>
-#include <getopt.h>
-#include <hardware/audio_effect.h>
-#include <module_common_types.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <utils/Log.h>
-#include <utils/Timers.h>
-
-#include <audio_utils/channels.h>
-#include <audio_utils/primitives.h>
#include <log/log.h>
-#include <system/audio.h>
// This is the only symbol that needs to be imported
extern audio_effect_library_t AUDIO_EFFECT_LIBRARY_INFO_SYM;
@@ -42,6 +38,9 @@
// types of pre processing modules
enum PreProcId {
PREPROC_AGC, // Automatic Gain Control
+#ifndef WEBRTC_LEGACY
+ PREPROC_AGC2, // Automatic Gain Control 2
+#endif
PREPROC_AEC, // Acoustic Echo Canceler
PREPROC_NS, // Noise Suppressor
PREPROC_NUM_EFFECTS
@@ -58,6 +57,12 @@
ARG_AGC_COMP_LVL,
ARG_AEC_DELAY,
ARG_NS_LVL,
+#ifndef WEBRTC_LEGACY
+ ARG_AEC_MOBILE,
+ ARG_AGC2_GAIN,
+ ARG_AGC2_LVL,
+ ARG_AGC2_SAT_MGN
+#endif
};
struct preProcConfigParams_t {
@@ -66,11 +71,19 @@
int nsLevel = 0; // a value between 0-3
int agcTargetLevel = 3; // in dB
int agcCompLevel = 9; // in dB
+#ifndef WEBRTC_LEGACY
+ float agc2Gain = 0.f; // in dB
+ float agc2SaturationMargin = 2.f; // in dB
+ int agc2Level = 0; // either kRms(0) or kPeak(1)
+#endif
int aecDelay = 0; // in ms
};
const effect_uuid_t kPreProcUuids[PREPROC_NUM_EFFECTS] = {
{0xaa8130e0, 0x66fc, 0x11e0, 0xbad0, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // agc uuid
+#ifndef WEBRTC_LEGACY
+ {0x89f38e65, 0xd4d2, 0x4d64, 0xad0e, {0x2b, 0x3e, 0x79, 0x9e, 0xa8, 0x86}}, // agc2 uuid
+#endif
{0xbb392ec0, 0x8d4d, 0x11e0, 0xa896, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // aec uuid
{0xc06c8400, 0x8e06, 0x11e0, 0x9cb6, {0x00, 0x02, 0xa5, 0xd5, 0xc5, 0x1b}}, // ns uuid
};
@@ -126,14 +139,30 @@
printf("\n Enable Noise Suppression, default disabled");
printf("\n --agc");
printf("\n Enable Gain Control, default disabled");
+#ifndef WEBRTC_LEGACY
+ printf("\n --agc2");
+ printf("\n Enable Gain Controller 2, default disabled");
+#endif
printf("\n --ns_lvl <ns_level>");
printf("\n Noise Suppression level in dB, default value 0dB");
printf("\n --agc_tgt_lvl <target_level>");
printf("\n AGC Target Level in dB, default value 3dB");
printf("\n --agc_comp_lvl <comp_level>");
printf("\n AGC Comp Level in dB, default value 9dB");
+#ifndef WEBRTC_LEGACY
+ printf("\n --agc2_gain <fixed_digital_gain>");
+ printf("\n AGC Fixed Digital Gain in dB, default value 0dB");
+ printf("\n --agc2_lvl <level_estimator>");
+ printf("\n AGC Adaptive Digital Level Estimator, default value kRms");
+ printf("\n --agc2_sat_mgn <saturation_margin>");
+ printf("\n AGC Adaptive Digital Saturation Margin in dB, default value 2dB");
+#endif
printf("\n --aec_delay <delay>");
printf("\n AEC delay value in ms, default value 0ms");
+#ifndef WEBRTC_LEGACY
+ printf("\n --aec_mobile");
+ printf("\n Enable mobile mode of echo canceller, default disabled");
+#endif
printf("\n");
}
@@ -184,6 +213,9 @@
const char *outputFile = nullptr;
const char *farFile = nullptr;
int effectEn[PREPROC_NUM_EFFECTS] = {0};
+#ifndef WEBRTC_LEGACY
+ int aecMobileMode = 0;
+#endif
const option long_opts[] = {
{"help", no_argument, nullptr, ARG_HELP},
@@ -194,11 +226,22 @@
{"ch_mask", required_argument, nullptr, ARG_CH_MASK},
{"agc_tgt_lvl", required_argument, nullptr, ARG_AGC_TGT_LVL},
{"agc_comp_lvl", required_argument, nullptr, ARG_AGC_COMP_LVL},
+#ifndef WEBRTC_LEGACY
+ {"agc2_gain", required_argument, nullptr, ARG_AGC2_GAIN},
+ {"agc2_lvl", required_argument, nullptr, ARG_AGC2_LVL},
+ {"agc2_sat_mgn", required_argument, nullptr, ARG_AGC2_SAT_MGN},
+#endif
{"aec_delay", required_argument, nullptr, ARG_AEC_DELAY},
{"ns_lvl", required_argument, nullptr, ARG_NS_LVL},
{"aec", no_argument, &effectEn[PREPROC_AEC], 1},
{"agc", no_argument, &effectEn[PREPROC_AGC], 1},
+#ifndef WEBRTC_LEGACY
+ {"agc2", no_argument, &effectEn[PREPROC_AGC2], 1},
+#endif
{"ns", no_argument, &effectEn[PREPROC_NS], 1},
+#ifndef WEBRTC_LEGACY
+ {"aec_mobile", no_argument, &aecMobileMode, 1},
+#endif
{nullptr, 0, nullptr, 0},
};
struct preProcConfigParams_t preProcCfgParams {};
@@ -246,6 +289,20 @@
preProcCfgParams.agcCompLevel = atoi(optarg);
break;
}
+#ifndef WEBRTC_LEGACY
+ case ARG_AGC2_GAIN: {
+ preProcCfgParams.agc2Gain = atof(optarg);
+ break;
+ }
+ case ARG_AGC2_LVL: {
+ preProcCfgParams.agc2Level = atoi(optarg);
+ break;
+ }
+ case ARG_AGC2_SAT_MGN: {
+ preProcCfgParams.agc2SaturationMargin = atof(optarg);
+ break;
+ }
+#endif
case ARG_AEC_DELAY: {
preProcCfgParams.aecDelay = atoi(optarg);
break;
@@ -342,6 +399,31 @@
return EXIT_FAILURE;
}
}
+#ifndef WEBRTC_LEGACY
+ if (effectEn[PREPROC_AGC2]) {
+ if (int status = preProcSetConfigParam(AGC2_PARAM_FIXED_DIGITAL_GAIN,
+ (float)preProcCfgParams.agc2Gain,
+ effectHandle[PREPROC_AGC2]);
+ status != 0) {
+ ALOGE("Invalid AGC2 Fixed Digital Gain. Error %d\n", status);
+ return EXIT_FAILURE;
+ }
+ if (int status = preProcSetConfigParam(AGC2_PARAM_ADAPT_DIGI_LEVEL_ESTIMATOR,
+ (uint32_t)preProcCfgParams.agc2Level,
+ effectHandle[PREPROC_AGC2]);
+ status != 0) {
+ ALOGE("Invalid AGC2 Level Estimator. Error %d\n", status);
+ return EXIT_FAILURE;
+ }
+ if (int status = preProcSetConfigParam(AGC2_PARAM_ADAPT_DIGI_EXTRA_SATURATION_MARGIN,
+ (float)preProcCfgParams.agc2SaturationMargin,
+ effectHandle[PREPROC_AGC2]);
+ status != 0) {
+ ALOGE("Invalid AGC2 Saturation Margin. Error %d\n", status);
+ return EXIT_FAILURE;
+ }
+ }
+#endif
if (effectEn[PREPROC_NS]) {
if (int status = preProcSetConfigParam(NS_PARAM_LEVEL, (uint32_t)preProcCfgParams.nsLevel,
effectHandle[PREPROC_NS]);
@@ -350,6 +432,16 @@
return EXIT_FAILURE;
}
}
+#ifndef WEBRTC_LEGACY
+ if (effectEn[PREPROC_AEC]) {
+ if (int status = preProcSetConfigParam(AEC_PARAM_MOBILE_MODE, (uint32_t)aecMobileMode,
+ effectHandle[PREPROC_AEC]);
+ status != 0) {
+ ALOGE("Invalid AEC mobile mode value %d\n", status);
+ return EXIT_FAILURE;
+ }
+ }
+#endif
// Process Call
const int frameLength = (int)(preProcCfgParams.samplingFreq * kTenMilliSecVal);
diff --git a/media/libmedia/Android.bp b/media/libmedia/Android.bp
index 39523de..1a7eb6f 100644
--- a/media/libmedia/Android.bp
+++ b/media/libmedia/Android.bp
@@ -322,6 +322,8 @@
shared_libs: [
"android.hidl.token@1.0-utils",
+ "audioclient-types-aidl-unstable-cpp",
+ "av-types-aidl-unstable-cpp",
"liblog",
"libcutils",
"libprocessgroup",
diff --git a/media/libmedia/TEST_MAPPING b/media/libmedia/TEST_MAPPING
new file mode 100644
index 0000000..65390ed
--- /dev/null
+++ b/media/libmedia/TEST_MAPPING
@@ -0,0 +1,6 @@
+// test_mapping for frameworks/av/media/libmedia
+{
+ "presubmit": [
+ { "name": "CodecListTest" }
+ ]
+}
diff --git a/media/libmedia/tests/codeclist/Android.bp b/media/libmedia/tests/codeclist/Android.bp
new file mode 100644
index 0000000..a930d6e
--- /dev/null
+++ b/media/libmedia/tests/codeclist/Android.bp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2020 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.
+ */
+
+cc_test {
+ name: "CodecListTest",
+ test_suites: ["device-tests"],
+ gtest: true,
+
+ srcs: [
+ "CodecListTest.cpp",
+ ],
+
+ shared_libs: [
+ "libbinder",
+ "liblog",
+ "libmedia_codeclist",
+ "libstagefright",
+ "libstagefright_foundation",
+ "libstagefright_xmlparser",
+ "libutils",
+ ],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ sanitize: {
+ cfi: true,
+ misc_undefined: [
+ "unsigned-integer-overflow",
+ "signed-integer-overflow",
+ ],
+ },
+}
diff --git a/media/libmedia/tests/codeclist/CodecListTest.cpp b/media/libmedia/tests/codeclist/CodecListTest.cpp
new file mode 100644
index 0000000..bd2adf7
--- /dev/null
+++ b/media/libmedia/tests/codeclist/CodecListTest.cpp
@@ -0,0 +1,222 @@
+/*
+ * Copyright (C) 2020 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 "CodecListTest"
+#include <utils/Log.h>
+
+#include <gtest/gtest.h>
+
+#include <binder/Parcel.h>
+#include <media/stagefright/MediaCodecConstants.h>
+#include <media/stagefright/MediaCodecList.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AString.h>
+#include <media/stagefright/xmlparser/MediaCodecsXmlParser.h>
+
+#define kSwCodecXmlPath "/apex/com.android.media.swcodec/etc/"
+
+using namespace android;
+
+struct CddReq {
+ CddReq(const char *type, bool encoder) {
+ mediaType = type;
+ isEncoder = encoder;
+ }
+
+ const char *mediaType;
+ bool isEncoder;
+};
+
+TEST(CodecListTest, CodecListSanityTest) {
+ sp<IMediaCodecList> list = MediaCodecList::getInstance();
+ ASSERT_NE(list, nullptr) << "Unable to get MediaCodecList instance.";
+ EXPECT_GT(list->countCodecs(), 0) << "No codecs in CodecList";
+ for (size_t i = 0; i < list->countCodecs(); ++i) {
+ sp<MediaCodecInfo> info = list->getCodecInfo(i);
+ ASSERT_NE(info, nullptr) << "CodecInfo is null";
+ ssize_t index = list->findCodecByName(info->getCodecName());
+ EXPECT_GE(index, 0) << "Wasn't able to find existing codec: " << info->getCodecName();
+ }
+}
+
+TEST(CodecListTest, CodecListByTypeTest) {
+ sp<IMediaCodecList> list = MediaCodecList::getInstance();
+ ASSERT_NE(list, nullptr) << "Unable to get MediaCodecList instance.";
+
+ std::vector<CddReq> cddReq{
+ // media type, isEncoder
+ CddReq(MIMETYPE_AUDIO_AAC, false),
+ CddReq(MIMETYPE_AUDIO_AAC, true),
+
+ CddReq(MIMETYPE_VIDEO_AVC, false),
+ CddReq(MIMETYPE_VIDEO_HEVC, false),
+ CddReq(MIMETYPE_VIDEO_MPEG4, false),
+ CddReq(MIMETYPE_VIDEO_VP8, false),
+ CddReq(MIMETYPE_VIDEO_VP9, false),
+
+ CddReq(MIMETYPE_VIDEO_AVC, true),
+ CddReq(MIMETYPE_VIDEO_VP8, true),
+ };
+
+ for (CddReq codecReq : cddReq) {
+ ssize_t index = list->findCodecByType(codecReq.mediaType, codecReq.isEncoder);
+ EXPECT_GE(index, 0) << "Wasn't able to find codec for media type: " << codecReq.mediaType
+ << (codecReq.isEncoder ? " encoder" : " decoder");
+ }
+}
+
+TEST(CodecInfoTest, ListInfoTest) {
+ ALOGV("Compare CodecInfo with info in XML");
+ MediaCodecsXmlParser parser;
+ status_t status = parser.parseXmlFilesInSearchDirs();
+ ASSERT_EQ(status, OK) << "XML Parsing failed for default paths";
+
+ const std::vector<std::string> &xmlFiles = MediaCodecsXmlParser::getDefaultXmlNames();
+ const std::vector<std::string> &searchDirsApex{std::string(kSwCodecXmlPath)};
+ status = parser.parseXmlFilesInSearchDirs(xmlFiles, searchDirsApex);
+ ASSERT_EQ(status, OK) << "XML Parsing of " << kSwCodecXmlPath << " failed";
+
+ MediaCodecsXmlParser::CodecMap codecMap = parser.getCodecMap();
+
+ sp<IMediaCodecList> list = MediaCodecList::getInstance();
+ ASSERT_NE(list, nullptr) << "Unable to get MediaCodecList instance";
+
+ // Compare CodecMap from XML to CodecList
+ for (auto mapIter : codecMap) {
+ ssize_t index = list->findCodecByName(mapIter.first.c_str());
+ if (index < 0) {
+ std::cout << "[ WARN ] " << mapIter.first << " not found in CodecList \n";
+ continue;
+ }
+
+ sp<MediaCodecInfo> info = list->getCodecInfo(index);
+ ASSERT_NE(info, nullptr) << "CodecInfo is null";
+
+ MediaCodecsXmlParser::CodecProperties codecProperties = mapIter.second;
+ ASSERT_EQ(codecProperties.isEncoder, info->isEncoder()) << "Encoder property mismatch";
+
+ ALOGV("codec name: %s", info->getCodecName());
+ ALOGV("codec rank: %d", info->getRank());
+ ALOGV("codec ownername: %s", info->getOwnerName());
+ ALOGV("codec isEncoder: %d", info->isEncoder());
+
+ ALOGV("attributeFlags: kFlagIsHardwareAccelerated, kFlagIsSoftwareOnly, kFlagIsVendor, "
+ "kFlagIsEncoder");
+ std::bitset<4> attr(info->getAttributes());
+ ALOGV("codec attributes: %s", attr.to_string().c_str());
+
+ Vector<AString> mediaTypes;
+ info->getSupportedMediaTypes(&mediaTypes);
+ ALOGV("supported media types count: %zu", mediaTypes.size());
+ ASSERT_FALSE(mediaTypes.isEmpty())
+ << "no media type supported by codec: " << info->getCodecName();
+
+ MediaCodecsXmlParser::TypeMap typeMap = codecProperties.typeMap;
+ for (auto mediaType : mediaTypes) {
+ ALOGV("codec mediaTypes: %s", mediaType.c_str());
+ auto searchTypeMap = typeMap.find(mediaType.c_str());
+ ASSERT_NE(searchTypeMap, typeMap.end())
+ << "CodecList doesn't contain codec media type: " << mediaType.c_str();
+ MediaCodecsXmlParser::AttributeMap attributeMap = searchTypeMap->second;
+
+ const sp<MediaCodecInfo::Capabilities> &capabilities =
+ info->getCapabilitiesFor(mediaType.c_str());
+
+ Vector<uint32_t> colorFormats;
+ capabilities->getSupportedColorFormats(&colorFormats);
+ for (auto colorFormat : colorFormats) {
+ ALOGV("supported color formats: %d", colorFormat);
+ }
+
+ Vector<MediaCodecInfo::ProfileLevel> profileLevels;
+ capabilities->getSupportedProfileLevels(&profileLevels);
+ if (!profileLevels.empty()) {
+ ALOGV("supported profilelevel for media type: %s", mediaType.c_str());
+ }
+ for (auto profileLevel : profileLevels) {
+ ALOGV("profile: %d, level: %d", profileLevel.mProfile, profileLevel.mLevel);
+ }
+
+ sp<AMessage> details = capabilities->getDetails();
+ ASSERT_NE(details, nullptr) << "Details in codec capabilities is null";
+ ALOGV("no. of entries in details: %zu", details->countEntries());
+
+ for (size_t idxDetail = 0; idxDetail < details->countEntries(); idxDetail++) {
+ AMessage::Type type;
+ const char *name = details->getEntryNameAt(idxDetail, &type);
+ ALOGV("details entry name: %s", name);
+ AMessage::ItemData itemData = details->getEntryAt(idxDetail);
+ switch (type) {
+ case AMessage::kTypeInt32:
+ int32_t val32;
+ if (itemData.find(&val32)) {
+ ALOGV("entry int val: %d", val32);
+ auto searchAttr = attributeMap.find(name);
+ if (searchAttr == attributeMap.end()) {
+ ALOGW("Parser doesn't have key: %s", name);
+ } else if (stoi(searchAttr->second) != val32) {
+ ALOGW("Values didn't match for key: %s", name);
+ ALOGV("Values act/exp: %d / %d", val32, stoi(searchAttr->second));
+ }
+ }
+ break;
+ case AMessage::kTypeString:
+ if (AString valStr; itemData.find(&valStr)) {
+ ALOGV("entry str val: %s", valStr.c_str());
+ auto searchAttr = attributeMap.find(name);
+ if (searchAttr == attributeMap.end()) {
+ ALOGW("Parser doesn't have key: %s", name);
+ } else if (searchAttr->second != valStr.c_str()) {
+ ALOGW("Values didn't match for key: %s", name);
+ ALOGV("Values act/exp: %s / %s", valStr.c_str(),
+ searchAttr->second.c_str());
+ }
+ }
+ break;
+ default:
+ ALOGV("data type: %d shouldn't be present in details", type);
+ break;
+ }
+ }
+ }
+
+ Parcel *codecInfoParcel = new Parcel();
+ ASSERT_NE(codecInfoParcel, nullptr) << "Unable to create parcel";
+
+ status_t status = info->writeToParcel(codecInfoParcel);
+ ASSERT_EQ(status, OK) << "Writing to parcel failed";
+
+ codecInfoParcel->setDataPosition(0);
+ sp<MediaCodecInfo> parcelCodecInfo = info->FromParcel(*codecInfoParcel);
+ ASSERT_NE(parcelCodecInfo, nullptr) << "CodecInfo from parcel is null";
+ delete codecInfoParcel;
+
+ EXPECT_STREQ(info->getCodecName(), parcelCodecInfo->getCodecName())
+ << "Returned codec name in info doesn't match";
+ EXPECT_EQ(info->getRank(), parcelCodecInfo->getRank())
+ << "Returned component rank in info doesn't match";
+ }
+}
+
+TEST(CodecListTest, CodecListGlobalSettingsTest) {
+ sp<IMediaCodecList> list = MediaCodecList::getInstance();
+ ASSERT_NE(list, nullptr) << "Unable to get MediaCodecList instance";
+
+ sp<AMessage> globalSettings = list->getGlobalSettings();
+ ASSERT_NE(globalSettings, nullptr) << "GlobalSettings AMessage is null";
+ ALOGV("global settings: %s", globalSettings->debugString(0).c_str());
+}
diff --git a/media/libmediaplayerservice/Android.bp b/media/libmediaplayerservice/Android.bp
index 324f4ae..b62317a 100644
--- a/media/libmediaplayerservice/Android.bp
+++ b/media/libmediaplayerservice/Android.bp
@@ -15,6 +15,7 @@
shared_libs: [
"android.hardware.media.c2@1.0",
"android.hardware.media.omx@1.0",
+ "av-types-aidl-unstable-cpp",
"libbase",
"libandroid_net",
"libaudioclient",
diff --git a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
index 09b9145..02fb6bb 100644
--- a/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
+++ b/media/libmediaplayerservice/StagefrightMetadataRetriever.cpp
@@ -174,9 +174,7 @@
ALOGV("getting track %zu of %zu, meta=%s", i, n, meta->toString().c_str());
const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
-
- if (!strncasecmp(mime, "image/", 6)) {
+ if (meta->findCString(kKeyMIMEType, &mime) && !strncasecmp(mime, "image/", 6)) {
int32_t isPrimary;
if ((index < 0 && meta->findInt32(
kKeyTrackIsDefault, &isPrimary) && isPrimary)
@@ -208,12 +206,19 @@
}
const char *mime;
- CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
+ if (!trackMeta->findCString(kKeyMIMEType, &mime)) {
+ ALOGE("image track has no mime type");
+ return NULL;
+ }
ALOGV("extracting from %s track", mime);
if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC)) {
mime = MEDIA_MIMETYPE_VIDEO_HEVC;
trackMeta = new MetaData(*trackMeta);
trackMeta->setCString(kKeyMIMEType, mime);
+ } else if (!strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_AVIF)) {
+ mime = MEDIA_MIMETYPE_VIDEO_AV1;
+ trackMeta = new MetaData(*trackMeta);
+ trackMeta->setCString(kKeyMIMEType, mime);
}
bool preferhw = property_get_bool(
@@ -299,9 +304,7 @@
}
const char *mime;
- CHECK(meta->findCString(kKeyMIMEType, &mime));
-
- if (!strncasecmp(mime, "video/", 6)) {
+ if (meta->findCString(kKeyMIMEType, &mime) && !strncasecmp(mime, "video/", 6)) {
break;
}
}
@@ -337,7 +340,10 @@
}
const char *mime;
- CHECK(trackMeta->findCString(kKeyMIMEType, &mime));
+ if (!trackMeta->findCString(kKeyMIMEType, &mime)) {
+ ALOGE("video track has no mime information.");
+ return NULL;
+ }
bool preferhw = property_get_bool(
"media.stagefright.thumbnail.prefer_hw_codecs", false);
@@ -531,7 +537,7 @@
int32_t audioBitrate = -1;
int32_t rotationAngle = -1;
int32_t imageCount = 0;
- int32_t imagePrimary = 0;
+ int32_t imagePrimary = -1;
int32_t imageWidth = -1;
int32_t imageHeight = -1;
int32_t imageRotation = -1;
@@ -574,29 +580,33 @@
mMetaData.add(METADATA_KEY_SAMPLERATE, String8(tmp));
}
} else if (!hasVideo && !strncasecmp("video/", mime, 6)) {
- hasVideo = true;
- videoMime = String8(mime);
-
- CHECK(trackMeta->findInt32(kKeyWidth, &videoWidth));
- CHECK(trackMeta->findInt32(kKeyHeight, &videoHeight));
if (!trackMeta->findInt32(kKeyRotation, &rotationAngle)) {
rotationAngle = 0;
}
if (!trackMeta->findInt32(kKeyFrameCount, &videoFrameCount)) {
videoFrameCount = 0;
}
-
- parseColorAspects(trackMeta);
+ if (trackMeta->findInt32(kKeyWidth, &videoWidth)
+ && trackMeta->findInt32(kKeyHeight, &videoHeight)) {
+ hasVideo = true;
+ videoMime = String8(mime);
+ parseColorAspects(trackMeta);
+ } else {
+ ALOGE("video track ignored for missing dimensions");
+ }
} else if (!strncasecmp("image/", mime, 6)) {
int32_t isPrimary;
if (trackMeta->findInt32(
kKeyTrackIsDefault, &isPrimary) && isPrimary) {
- imagePrimary = imageCount;
- CHECK(trackMeta->findInt32(kKeyWidth, &imageWidth));
- CHECK(trackMeta->findInt32(kKeyHeight, &imageHeight));
if (!trackMeta->findInt32(kKeyRotation, &imageRotation)) {
imageRotation = 0;
}
+ if (trackMeta->findInt32(kKeyWidth, &imageWidth)
+ && trackMeta->findInt32(kKeyHeight, &imageHeight)) {
+ imagePrimary = imageCount;
+ } else {
+ ALOGE("primary image track ignored for missing dimensions");
+ }
}
imageCount++;
} else if (!strcasecmp(mime, MEDIA_MIMETYPE_TEXT_3GPP)) {
@@ -629,9 +639,11 @@
if (hasVideo) {
mMetaData.add(METADATA_KEY_HAS_VIDEO, String8("yes"));
+ CHECK(videoWidth >= 0);
sprintf(tmp, "%d", videoWidth);
mMetaData.add(METADATA_KEY_VIDEO_WIDTH, String8(tmp));
+ CHECK(videoHeight >= 0);
sprintf(tmp, "%d", videoHeight);
mMetaData.add(METADATA_KEY_VIDEO_HEIGHT, String8(tmp));
@@ -646,7 +658,8 @@
}
}
- if (imageCount > 0) {
+ // only if we have a primary image
+ if (imageCount > 0 && imagePrimary >= 0) {
mMetaData.add(METADATA_KEY_HAS_IMAGE, String8("yes"));
sprintf(tmp, "%d", imageCount);
@@ -655,9 +668,11 @@
sprintf(tmp, "%d", imagePrimary);
mMetaData.add(METADATA_KEY_IMAGE_PRIMARY, String8(tmp));
+ CHECK(imageWidth >= 0);
sprintf(tmp, "%d", imageWidth);
mMetaData.add(METADATA_KEY_IMAGE_WIDTH, String8(tmp));
+ CHECK(imageHeight >= 0);
sprintf(tmp, "%d", imageHeight);
mMetaData.add(METADATA_KEY_IMAGE_HEIGHT, String8(tmp));
@@ -685,10 +700,9 @@
!strcasecmp(fileMIME, "video/x-matroska")) {
sp<MetaData> trackMeta = mExtractor->getTrackMetaData(0);
const char *trackMIME;
- if (trackMeta != nullptr) {
- CHECK(trackMeta->findCString(kKeyMIMEType, &trackMIME));
- }
- if (!strncasecmp("audio/", trackMIME, 6)) {
+ if (trackMeta != nullptr
+ && trackMeta->findCString(kKeyMIMEType, &trackMIME)
+ && !strncasecmp("audio/", trackMIME, 6)) {
// The matroska file only contains a single audio track,
// rewrite its mime type.
mMetaData.add(
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
index 13e1933..6a8c708 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerRenderer.cpp
@@ -922,6 +922,11 @@
firstEntry = false;
int64_t mediaTimeUs;
CHECK(entry->mBuffer->meta()->findInt64("timeUs", &mediaTimeUs));
+ if (mediaTimeUs < 0) {
+ ALOGD("fillAudioBuffer: reset negative media time %.2f secs to zero",
+ mediaTimeUs / 1E6);
+ mediaTimeUs = 0;
+ }
ALOGV("fillAudioBuffer: rendering audio at media time %.2f secs", mediaTimeUs / 1E6);
setAudioFirstAnchorTimeIfNeeded_l(mediaTimeUs);
}
diff --git a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
index 83da092..9533ae5 100644
--- a/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
+++ b/media/libmediaplayerservice/nuplayer/RTSPSource.cpp
@@ -146,7 +146,9 @@
}
// Close socket before posting message to RTSPSource message handler.
- close(mHandler->getARTSPConnection()->getSocket());
+ if (mHandler != NULL) {
+ close(mHandler->getARTSPConnection()->getSocket());
+ }
sp<AMessage> msg = new AMessage(kWhatDisconnect, this);
diff --git a/media/libmediatranscoding/TranscodingSessionController.cpp b/media/libmediatranscoding/TranscodingSessionController.cpp
index 2306395..1c3ee7e 100644
--- a/media/libmediatranscoding/TranscodingSessionController.cpp
+++ b/media/libmediatranscoding/TranscodingSessionController.cpp
@@ -66,6 +66,7 @@
mUidSortedList.push_back(OFFLINE_UID);
mOfflineUidIterator = mUidSortedList.begin();
mSessionQueues.emplace(OFFLINE_UID, SessionQueueType());
+ mUidPackageNames[OFFLINE_UID] = "(offline)";
}
TranscodingSessionController::~TranscodingSessionController() {}
@@ -83,13 +84,6 @@
result.append(buffer);
std::vector<int32_t> uids(mUidSortedList.begin(), mUidSortedList.end());
- // Exclude last uid, which is for offline queue
- uids.pop_back();
- std::vector<std::string> packageNames;
- if (TranscodingUidPolicy::getNamesForUids(uids, &packageNames)) {
- uids.push_back(OFFLINE_UID);
- packageNames.push_back("(offline)");
- }
for (int32_t i = 0; i < uids.size(); i++) {
const uid_t uid = uids[i];
@@ -98,7 +92,7 @@
continue;
}
snprintf(buffer, SIZE, " Uid: %d, pkg: %s\n", uid,
- packageNames.empty() ? "(unknown)" : packageNames[i].c_str());
+ mUidPackageNames.count(uid) > 0 ? mUidPackageNames[uid].c_str() : "(unknown)");
result.append(buffer);
snprintf(buffer, SIZE, " Num of sessions: %zu\n", mSessionQueues[uid].size());
result.append(buffer);
@@ -120,6 +114,12 @@
result.append(buffer);
snprintf(buffer, SIZE, " Dst: %s\n", request.destinationFilePath.c_str());
result.append(buffer);
+ // For the offline queue, print out the original client.
+ if (uid == OFFLINE_UID) {
+ snprintf(buffer, SIZE, " Original Client: %s\n",
+ request.clientPackageName.c_str());
+ result.append(buffer);
+ }
}
}
@@ -274,6 +274,11 @@
return false;
}
+ // Add the uid package name to the store of package names we already know.
+ if (mUidPackageNames.count(uid) == 0) {
+ mUidPackageNames.emplace(uid, request.clientPackageName);
+ }
+
// TODO(chz): only support offline vs real-time for now. All kUnspecified sessions
// go to offline queue.
if (request.priority == TranscodingSessionPriority::kUnspecified) {
diff --git a/media/libmediatranscoding/TranscodingUidPolicy.cpp b/media/libmediatranscoding/TranscodingUidPolicy.cpp
index 9763921..084a871 100644
--- a/media/libmediatranscoding/TranscodingUidPolicy.cpp
+++ b/media/libmediatranscoding/TranscodingUidPolicy.cpp
@@ -114,28 +114,6 @@
////////////////////////////////////////////////////////////////////////////
//static
-bool TranscodingUidPolicy::getNamesForUids(const std::vector<int32_t>& uids,
- std::vector<std::string>* names) {
- names->clear();
- sp<IServiceManager> sm(defaultServiceManager());
- sp<IBinder> binder(sm->getService(String16("package_native")));
- if (binder == nullptr) {
- ALOGE("getService package_native failed");
- return false;
- }
-
- sp<content::pm::IPackageManagerNative> packageMgr =
- interface_cast<content::pm::IPackageManagerNative>(binder);
- binder::Status status = packageMgr->getNamesForUids(uids, names);
-
- if (!status.isOk() || names->size() != uids.size()) {
- names->clear();
- return false;
- }
- return true;
-}
-
-//static
status_t TranscodingUidPolicy::getUidForPackage(String16 packageName, /*inout*/ uid_t& uid) {
PermissionController pc;
uid = pc.getPackageUid(packageName, 0);
diff --git a/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl b/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
index 03c24f0..4b19f6a 100644
--- a/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
+++ b/media/libmediatranscoding/aidl/android/media/TranscodingRequestParcel.aidl
@@ -53,6 +53,11 @@
int clientPid = -1;
/**
+ * The package name of the client whom this transcoding request is for.
+ */
+ @utf8InCpp String clientPackageName;
+
+ /**
* Type of the transcoding.
*/
TranscodingType transcodingType;
diff --git a/media/libmediatranscoding/include/media/TranscodingRequest.h b/media/libmediatranscoding/include/media/TranscodingRequest.h
index aae621f..485403f 100644
--- a/media/libmediatranscoding/include/media/TranscodingRequest.h
+++ b/media/libmediatranscoding/include/media/TranscodingRequest.h
@@ -39,6 +39,7 @@
destinationFilePath = parcel.destinationFilePath;
clientUid = parcel.clientUid;
clientPid = parcel.clientPid;
+ clientPackageName = parcel.clientPackageName;
transcodingType = parcel.transcodingType;
requestedVideoTrackFormat = parcel.requestedVideoTrackFormat;
priority = parcel.priority;
diff --git a/media/libmediatranscoding/include/media/TranscodingSessionController.h b/media/libmediatranscoding/include/media/TranscodingSessionController.h
index 9ab3518..c082074 100644
--- a/media/libmediatranscoding/include/media/TranscodingSessionController.h
+++ b/media/libmediatranscoding/include/media/TranscodingSessionController.h
@@ -107,6 +107,7 @@
// previous top app, etc.
std::list<uid_t> mUidSortedList;
std::list<uid_t>::iterator mOfflineUidIterator;
+ std::map<uid_t, std::string> mUidPackageNames;
std::shared_ptr<TranscoderInterface> mTranscoder;
std::shared_ptr<UidPolicyInterface> mUidPolicy;
diff --git a/media/libmediatranscoding/include/media/TranscodingUidPolicy.h b/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
index 946770c..4c642de 100644
--- a/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
+++ b/media/libmediatranscoding/include/media/TranscodingUidPolicy.h
@@ -49,7 +49,6 @@
void setCallback(const std::shared_ptr<UidPolicyCallbackInterface>& cb) override;
// ~UidPolicyInterface
- static bool getNamesForUids(const std::vector<int32_t>& uids, std::vector<std::string>* names);
static status_t getUidForPackage(String16 packageName, /*inout*/ uid_t& uid);
private:
diff --git a/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp b/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
index ede86cf..465632f 100644
--- a/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
+++ b/media/libmediatranscoding/transcoder/benchmark/MediaTranscoderBenchmark.cpp
@@ -247,6 +247,17 @@
false /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
}
+static void BM_TranscodeAvc2AvcAV2AV720P(benchmark::State& state) {
+ TranscodeMediaFile(state, "video_1280x720_3648frame_h264_16Mbps_30fps_aac.mp4",
+ "video_1280x720_3648frame_h264_16Mbps_30fps_aac_transcoded_AV.mp4",
+ true /* includeAudio */, true /* transcodeVideo */);
+}
+
+static void BM_TranscodeAvc2AvcAV2AV720PMaxOperatingRate(benchmark::State& state) {
+ TranscodeMediaFile(state, "video_1280x720_3648frame_h264_16Mbps_30fps_aac.mp4",
+ "video_1280x720_3648frame_h264_16Mbps_30fps_aac_transcoded_AV.mp4",
+ true /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
+}
//-------------------------------- HEVC to AVC Benchmarks ------------------------------------------
static void BM_TranscodeHevc2AvcAudioVideo2AudioVideo(benchmark::State& state) {
@@ -273,6 +284,18 @@
false /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
}
+static void BM_TranscodeHevc2AvcAV2AV720P(benchmark::State& state) {
+ TranscodeMediaFile(state, "video_1280x720_3863frame_hevc_16Mbps_30fps_aac.mp4",
+ "video_1280x720_3863frame_hevc_16Mbps_30fps_aac_transcoded_AV.mp4",
+ true /* includeAudio */, true /* transcodeVideo */);
+}
+
+static void BM_TranscodeHevc2AvcAV2AV720PMaxOperatingRate(benchmark::State& state) {
+ TranscodeMediaFile(state, "video_1280x720_3863frame_hevc_16Mbps_30fps_aac.mp4",
+ "video_1280x720_3863frame_hevc_16Mbps_30fps_aac_transcoded_AV.mp4",
+ true /* includeAudio */, true /* transcodeVideo */, SetMaxOperatingRate);
+}
+
//-------------------------------- Passthrough Benchmarks ------------------------------------------
static void BM_TranscodeAudioVideoPassthrough(benchmark::State& state) {
@@ -296,11 +319,15 @@
TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcVideo2Video);
TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAV2AVMaxOperatingRate);
TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcV2VMaxOperatingRate);
+TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAV2AV720P);
+TRANSCODER_BENCHMARK(BM_TranscodeAvc2AvcAV2AV720PMaxOperatingRate);
TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcAudioVideo2AudioVideo);
TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcVideo2Video);
TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcAV2AVMaxOperatingRate);
TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcV2VMaxOperatingRate);
+TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcAV2AV720P);
+TRANSCODER_BENCHMARK(BM_TranscodeHevc2AvcAV2AV720PMaxOperatingRate);
TRANSCODER_BENCHMARK(BM_TranscodeAudioVideoPassthrough);
TRANSCODER_BENCHMARK(BM_TranscodeVideoPassthrough);
diff --git a/media/libshmem/Android.bp b/media/libshmem/Android.bp
index c8d2284..b549b5d 100644
--- a/media/libshmem/Android.bp
+++ b/media/libshmem/Android.bp
@@ -1,6 +1,9 @@
aidl_interface {
name: "shared-file-region-aidl",
unstable: true,
+ host_supported: true,
+ vendor_available: true,
+ double_loadable: true,
local_include_dir: "aidl",
srcs: [
"aidl/android/media/SharedFileRegion.aidl",
diff --git a/media/libshmem/ShmemCompat.cpp b/media/libshmem/ShmemCompat.cpp
index 44fe39c..246cb24 100644
--- a/media/libshmem/ShmemCompat.cpp
+++ b/media/libshmem/ShmemCompat.cpp
@@ -49,8 +49,10 @@
return false;
}
+ uint32_t flags = !shmem.writeable ? IMemoryHeap::READ_ONLY : 0;
+
const sp<MemoryHeapBase> heap =
- new MemoryHeapBase(shmem.fd.get(), heapSize, 0, heapStartOffset);
+ new MemoryHeapBase(shmem.fd.get(), heapSize, flags, heapStartOffset);
*result = sp<MemoryBase>::make(heap,
shmem.offset - heapStartOffset,
shmem.size);
@@ -89,6 +91,7 @@
result->fd.reset(base::unique_fd(fd));
result->size = size;
result->offset = heap->getOffset() + offset;
+ result->writeable = (heap->getFlags() & IMemoryHeap::READ_ONLY) == 0;
}
return true;
}
diff --git a/media/libshmem/ShmemTest.cpp b/media/libshmem/ShmemTest.cpp
index d076ad0..874f34c 100644
--- a/media/libshmem/ShmemTest.cpp
+++ b/media/libshmem/ShmemTest.cpp
@@ -44,10 +44,11 @@
return shmem;
}
-sp<IMemory> makeIMemory(const std::vector<uint8_t>& content) {
+sp<IMemory> makeIMemory(const std::vector<uint8_t>& content, bool writeable = true) {
constexpr size_t kOffset = 19;
- sp<MemoryHeapBase> heap = new MemoryHeapBase(content.size());
+ sp<MemoryHeapBase> heap = new MemoryHeapBase(content.size(),
+ !writeable ? IMemoryHeap::READ_ONLY : 0);
sp<IMemory> result = sp<MemoryBase>::make(heap, kOffset, content.size());
memcpy(result->unsecurePointer(), content.data(), content.size());
return result;
@@ -69,9 +70,31 @@
ASSERT_TRUE(convertIMemoryToSharedFileRegion(imem, &shmem));
ASSERT_EQ(3, shmem.size);
ASSERT_GE(shmem.fd.get(), 0);
+ ASSERT_TRUE(shmem.writeable);
ASSERT_TRUE(convertSharedFileRegionToIMemory(shmem, &reconstructed));
}
ASSERT_EQ(3, reconstructed->size());
+ ASSERT_EQ(reconstructed->getMemory()->getFlags() & IMemoryHeap::READ_ONLY, 0);
+ const uint8_t* p =
+ reinterpret_cast<const uint8_t*>(reconstructed->unsecurePointer());
+ EXPECT_EQ(6, p[0]);
+ EXPECT_EQ(5, p[1]);
+ EXPECT_EQ(3, p[2]);
+}
+
+TEST(ShmemTest, ConversionReadOnly) {
+ sp<IMemory> reconstructed;
+ {
+ SharedFileRegion shmem;
+ sp<IMemory> imem = makeIMemory({6, 5, 3}, false);
+ ASSERT_TRUE(convertIMemoryToSharedFileRegion(imem, &shmem));
+ ASSERT_EQ(3, shmem.size);
+ ASSERT_GE(shmem.fd.get(), 0);
+ ASSERT_FALSE(shmem.writeable);
+ ASSERT_TRUE(convertSharedFileRegionToIMemory(shmem, &reconstructed));
+ }
+ ASSERT_EQ(3, reconstructed->size());
+ ASSERT_NE(reconstructed->getMemory()->getFlags() & IMemoryHeap::READ_ONLY, 0);
const uint8_t* p =
reinterpret_cast<const uint8_t*>(reconstructed->unsecurePointer());
EXPECT_EQ(6, p[0]);
diff --git a/media/libshmem/aidl/android/media/SharedFileRegion.aidl b/media/libshmem/aidl/android/media/SharedFileRegion.aidl
index a910e69..199b647 100644
--- a/media/libshmem/aidl/android/media/SharedFileRegion.aidl
+++ b/media/libshmem/aidl/android/media/SharedFileRegion.aidl
@@ -34,4 +34,6 @@
long offset;
/** Size, in bytes of the memory region. Must be non-negative. */
long size;
+ /** Whether the region is writeable. */
+ boolean writeable;
}
diff --git a/media/libstagefright/ACodec.cpp b/media/libstagefright/ACodec.cpp
index b9f9173..44ee2ac 100644
--- a/media/libstagefright/ACodec.cpp
+++ b/media/libstagefright/ACodec.cpp
@@ -5834,17 +5834,19 @@
case ACodec::kWhatSetSurface:
{
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
-
sp<RefBase> obj;
CHECK(msg->findObject("surface", &obj));
status_t err = mCodec->handleSetSurface(static_cast<Surface *>(obj.get()));
- sp<AMessage> response = new AMessage;
- response->setInt32("err", err);
- response->postReply(replyID);
+ sp<AReplyToken> replyID;
+ if (msg->senderAwaitsResponse(&replyID)) {
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", err);
+ response->postReply(replyID);
+ } else if (err != OK) {
+ mCodec->signalError(OMX_ErrorUndefined, err);
+ }
break;
}
@@ -8353,6 +8355,23 @@
break;
}
+ case kWhatSetSurface:
+ {
+ ALOGV("[%s] Deferring setSurface", mCodec->mComponentName.c_str());
+
+ sp<AReplyToken> replyID;
+ CHECK(msg->senderAwaitsResponse(&replyID));
+
+ mCodec->deferMessage(msg);
+
+ sp<AMessage> response = new AMessage;
+ response->setInt32("err", OK);
+ response->postReply(replyID);
+
+ handled = true;
+ break;
+ }
+
case kWhatCheckIfStuck:
{
int32_t generation = 0;
diff --git a/media/libstagefright/FrameDecoder.cpp b/media/libstagefright/FrameDecoder.cpp
index 965b6dd..e783578 100644
--- a/media/libstagefright/FrameDecoder.cpp
+++ b/media/libstagefright/FrameDecoder.cpp
@@ -121,15 +121,23 @@
false /*allocRotated*/, true /*metaOnly*/);
}
+bool isAvif(const sp<MetaData> &trackMeta) {
+ const char *mime;
+ return trackMeta->findCString(kKeyMIMEType, &mime)
+ && (!strcasecmp(mime, MEDIA_MIMETYPE_VIDEO_AV1)
+ || !strcasecmp(mime, MEDIA_MIMETYPE_IMAGE_AVIF));
+}
+
bool findThumbnailInfo(
const sp<MetaData> &trackMeta, int32_t *width, int32_t *height,
uint32_t *type = NULL, const void **data = NULL, size_t *size = NULL) {
uint32_t dummyType;
const void *dummyData;
size_t dummySize;
+ int codecConfigKey = isAvif(trackMeta) ? kKeyThumbnailAV1C : kKeyThumbnailHVCC;
return trackMeta->findInt32(kKeyThumbnailWidth, width)
&& trackMeta->findInt32(kKeyThumbnailHeight, height)
- && trackMeta->findData(kKeyThumbnailHVCC,
+ && trackMeta->findData(codecConfigKey,
type ?: &dummyType, data ?: &dummyData, size ?: &dummySize);
}
@@ -752,7 +760,10 @@
overrideMeta->remove(kKeyDisplayHeight);
overrideMeta->setInt32(kKeyWidth, mWidth);
overrideMeta->setInt32(kKeyHeight, mHeight);
- overrideMeta->setData(kKeyHVCC, type, data, size);
+ // The AV1 codec configuration data is passed via CSD0 to the AV1
+ // decoder.
+ const int codecConfigKey = isAvif(trackMeta()) ? kKeyOpaqueCSD0 : kKeyHVCC;
+ overrideMeta->setData(codecConfigKey, type, data, size);
options->setSeekTo(-1);
} else {
CHECK(trackMeta()->findInt32(kKeyWidth, &mWidth));
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 1a4f3d3..da8f024 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -639,6 +639,9 @@
mDequeueInputReplyID(0),
mDequeueOutputTimeoutGeneration(0),
mDequeueOutputReplyID(0),
+ mTunneledInputWidth(0),
+ mTunneledInputHeight(0),
+ mTunneled(false),
mHaveInputSurface(false),
mHavePendingInputBuffers(false),
mCpuBoostRequested(false),
@@ -2867,6 +2870,14 @@
extractCSD(format);
+ int32_t tunneled;
+ if (format->findInt32("feature-tunneled-playback", &tunneled) && tunneled != 0) {
+ ALOGI("Configuring TUNNELED video playback.");
+ mTunneled = true;
+ } else {
+ mTunneled = false;
+ }
+
mCodec->initiateConfigureComponent(format);
break;
}
@@ -3952,7 +3963,18 @@
if (hasCryptoOrDescrambler() && !c2Buffer && !memory) {
AString *errorDetailMsg;
CHECK(msg->findPointer("errorDetailMsg", (void **)&errorDetailMsg));
-
+ // Notify mCrypto of video resolution changes
+ if (mTunneled && mCrypto != NULL) {
+ int32_t width, height;
+ if (mInputFormat->findInt32("width", &width) &&
+ mInputFormat->findInt32("height", &height) && width > 0 && height > 0) {
+ if (width != mTunneledInputWidth || height != mTunneledInputHeight) {
+ mTunneledInputWidth = width;
+ mTunneledInputHeight = height;
+ mCrypto->notifyResolution(width, height);
+ }
+ }
+ }
err = mBufferChannel->queueSecureInputBuffer(
buffer,
(mFlags & kFlagIsSecure),
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index 3d152bc..48b3255 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -770,6 +770,7 @@
{ "text-format-data", kKeyTextFormatData },
{ "thumbnail-csd-hevc", kKeyThumbnailHVCC },
{ "slow-motion-markers", kKeySlowMotionMarkers },
+ { "thumbnail-csd-av1c", kKeyThumbnailAV1C },
}
};
@@ -1905,7 +1906,8 @@
std::vector<uint8_t> hvcc(csd0size + 1024);
size_t outsize = reassembleHVCC(csd0, hvcc.data(), hvcc.size(), 4);
meta->setData(kKeyHVCC, kTypeHVCC, hvcc.data(), outsize);
- } else if (mime == MEDIA_MIMETYPE_VIDEO_AV1) {
+ } else if (mime == MEDIA_MIMETYPE_VIDEO_AV1 ||
+ mime == MEDIA_MIMETYPE_IMAGE_AVIF) {
meta->setData(kKeyAV1C, 0, csd0->data(), csd0->size());
} else if (mime == MEDIA_MIMETYPE_VIDEO_DOLBY_VISION) {
if (msg->findBuffer("csd-2", &csd2)) {
diff --git a/media/libstagefright/codecs/amrnb/enc/fuzzer/Android.bp b/media/libstagefright/codecs/amrnb/enc/fuzzer/Android.bp
new file mode 100644
index 0000000..e88e5eb
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/fuzzer/Android.bp
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 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.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+cc_fuzz {
+ name: "amrnb_enc_fuzzer",
+ host_supported: true,
+
+ srcs: [
+ "amrnb_enc_fuzzer.cpp",
+ ],
+
+ static_libs: [
+ "liblog",
+ "libstagefright_amrnbenc",
+ "libstagefright_amrnb_common",
+ ],
+
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
diff --git a/media/libstagefright/codecs/amrnb/enc/fuzzer/README.md b/media/libstagefright/codecs/amrnb/enc/fuzzer/README.md
new file mode 100644
index 0000000..239b4a8
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/fuzzer/README.md
@@ -0,0 +1,60 @@
+# Fuzzer for libstagefright_amrnbenc encoder
+
+## Plugin Design Considerations
+The fuzzer plugin for AMR-NB is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+AMR-WB supports the following parameters:
+1. Output Format (parameter name: `outputFormat`)
+2. Mode (parameter name: `mode`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `outputFormat` | 0. `AMR_TX_WMF` 1. `AMR_TX_IF2` 2. `AMR_TX_ETS` | Bits 0, 1 and 2 of 1st byte of data. |
+| `mode` | 0. `MR475` 1. `MR515` 2. `MR59` 3. `MR67` 4. `MR74 ` 5. `MR795` 6. `MR102` 7. `MR122` 8. `MRDTX` | Bits 3, 4, 5 and 6 of 1st byte of data. |
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec using a loop.
+If the encode operation was successful, the input is advanced by the frame size.
+If the encode operation was un-successful, the input is still advanced by frame size so
+that the fuzzer can proceed to feed the next frame.
+
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build amrnb_enc_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) amrnb_enc_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some pcm files to that folder
+Push this directory to device.
+
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/amrnb_enc_fuzzer/amrnb_enc_fuzzer CORPUS_DIR
+```
+To run on host
+```
+ $ $ANDROID_HOST_OUT/fuzz/x86_64/amrnb_enc_fuzzer/amrnb_enc_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/media/libstagefright/codecs/amrnb/enc/fuzzer/amrnb_enc_fuzzer.cpp b/media/libstagefright/codecs/amrnb/enc/fuzzer/amrnb_enc_fuzzer.cpp
new file mode 100644
index 0000000..2fcbf24
--- /dev/null
+++ b/media/libstagefright/codecs/amrnb/enc/fuzzer/amrnb_enc_fuzzer.cpp
@@ -0,0 +1,105 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 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.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+#include <string.h>
+#include <utils/Log.h>
+#include <algorithm>
+#include "gsmamr_enc.h"
+
+// Constants for AMR-NB
+const int32_t kNumInputSamples = L_FRAME; // 160 samples
+const int32_t kOutputBufferSize = 2 * kNumInputSamples * sizeof(Word16);
+const Mode kModes[9] = {MR475, /* 4.75 kbps */
+ MR515, /* 5.15 kbps */
+ MR59, /* 5.90 kbps */
+ MR67, /* 6.70 kbps */
+ MR74, /* 7.40 kbps */
+ MR795, /* 7.95 kbps */
+ MR102, /* 10.2 kbps */
+ MR122, /* 12.2 kbps */
+ MRDTX, /* DTX */};
+const Word16 kOutputFormat[3] = {AMR_TX_WMF, AMR_TX_IF2, AMR_TX_ETS};
+
+class Codec {
+ public:
+ Codec() = default;
+ ~Codec() { deInitEncoder(); }
+ Word16 initEncoder(const uint8_t *data);
+ void deInitEncoder();
+ void encodeFrames(const uint8_t *data, size_t size);
+
+ private:
+ void *mEncState = nullptr;
+ void *mSidState = nullptr;
+};
+
+Word16 Codec::initEncoder(const uint8_t *data) {
+ return AMREncodeInit(&mEncState, &mSidState, (*data >> 1) & 0x01 /* dtx_enable flag */);
+}
+
+void Codec::deInitEncoder() {
+ if (mEncState) {
+ AMREncodeExit(&mEncState, &mSidState);
+ mEncState = nullptr;
+ mSidState = nullptr;
+ }
+}
+
+void Codec::encodeFrames(const uint8_t *data, size_t size) {
+ AMREncodeReset(mEncState, mSidState);
+ uint8_t startByte = *data;
+ int modeIndex = ((startByte >> 3) % 9);
+ int outputFormatIndex = (startByte % 3);
+ Mode mode = kModes[modeIndex];
+ Word16 outputFormat = kOutputFormat[outputFormatIndex];
+
+ // Consume startByte
+ data++;
+ size--;
+
+ while (size > 0) {
+ Frame_Type_3GPP frameType = (Frame_Type_3GPP)mode;
+
+ Word16 inputBuf[kNumInputSamples] = {};
+ int32_t minSize = std::min(size, sizeof(inputBuf));
+
+ uint8_t outputBuf[kOutputBufferSize] = {};
+ memcpy(inputBuf, data, minSize);
+
+ AMREncode(mEncState, mSidState, mode, inputBuf, outputBuf, &frameType, outputFormat);
+
+ data += minSize;
+ size -= minSize;
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size < 1) {
+ return 0;
+ }
+ Codec *codec = new Codec();
+ if (!codec) {
+ return 0;
+ }
+ if (codec->initEncoder(data) == 0) {
+ codec->encodeFrames(data, size);
+ }
+ delete codec;
+ return 0;
+}
diff --git a/media/libstagefright/codecs/amrwbenc/fuzzer/Android.bp b/media/libstagefright/codecs/amrwbenc/fuzzer/Android.bp
new file mode 100644
index 0000000..e3473d6
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/fuzzer/Android.bp
@@ -0,0 +1,41 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 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.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+
+cc_fuzz {
+ name: "amrwb_enc_fuzzer",
+ host_supported: true,
+
+ srcs: [
+ "amrwb_enc_fuzzer.cpp",
+ ],
+
+ static_libs: [
+ "liblog",
+ "libstagefright_amrwbenc",
+ "libstagefright_enc_common",
+ ],
+
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
diff --git a/media/libstagefright/codecs/amrwbenc/fuzzer/README.md b/media/libstagefright/codecs/amrwbenc/fuzzer/README.md
new file mode 100644
index 0000000..447fbfa
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/fuzzer/README.md
@@ -0,0 +1,60 @@
+# Fuzzer for libstagefright_amrwbenc encoder
+
+## Plugin Design Considerations
+The fuzzer plugin for AMR-WB is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+AMR-WB supports the following parameters:
+1. Frame Type (parameter name: `frameType`)
+2. Mode (parameter name: `mode`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `frameType` | 0. `VOAMRWB_DEFAULT` 1. `VOAMRWB_ITU` 2. `VOAMRWB_RFC3267` | Bits 0, 1 and 2 of 1st byte of data. |
+| `mode` | 0. `VOAMRWB_MD66` 1. `VOAMRWB_MD885` 2. `VOAMRWB_MD1265` 3. `VOAMRWB_MD1425` 4. `VOAMRWB_MD1585 ` 5. `VOAMRWB_MD1825` 6. `VOAMRWB_MD1985` 7. `VOAMRWB_MD2305` 8. `VOAMRWB_MD2385` 9. `VOAMRWB_N_MODES` | Bits 4, 5, 6 and 7 of 1st byte of data. |
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec using a loop.
+If the encode operation was successful, the input is advanced by the frame size.
+If the encode operation was un-successful, the input is still advanced by frame size so
+that the fuzzer can proceed to feed the next frame.
+
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build amrwb_enc_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) amrwb_enc_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some pcm files to that folder
+Push this directory to device.
+
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/amrwb_enc_fuzzer/amrwb_enc_fuzzer CORPUS_DIR
+```
+To run on host
+```
+ $ $ANDROID_HOST_OUT/fuzz/x86_64/amrwb_enc_fuzzer/amrwb_enc_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/media/libstagefright/codecs/amrwbenc/fuzzer/amrwb_enc_fuzzer.cpp b/media/libstagefright/codecs/amrwbenc/fuzzer/amrwb_enc_fuzzer.cpp
new file mode 100644
index 0000000..4773a1f
--- /dev/null
+++ b/media/libstagefright/codecs/amrwbenc/fuzzer/amrwb_enc_fuzzer.cpp
@@ -0,0 +1,142 @@
+/******************************************************************************
+ *
+ * Copyright (C) 2020 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.
+ *
+ *****************************************************************************
+ * Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
+ */
+#include <string.h>
+#include <utils/Log.h>
+#include <algorithm>
+#include "cmnMemory.h"
+#include "voAMRWB.h"
+#include "cnst.h"
+
+typedef int(VO_API *VOGETAUDIOENCAPI)(VO_AUDIO_CODECAPI *pEncHandle);
+const int32_t kInputBufferSize = L_FRAME16k * sizeof(int16_t) * 2;
+const int32_t kOutputBufferSize = 2 * kInputBufferSize;
+const int32_t kModes[] = {VOAMRWB_MD66 /* 6.60kbps */, VOAMRWB_MD885 /* 8.85kbps */,
+ VOAMRWB_MD1265 /* 12.65kbps */, VOAMRWB_MD1425 /* 14.25kbps */,
+ VOAMRWB_MD1585 /* 15.85kbps */, VOAMRWB_MD1825 /* 18.25kbps */,
+ VOAMRWB_MD1985 /* 19.85kbps */, VOAMRWB_MD2305 /* 23.05kbps */,
+ VOAMRWB_MD2385 /* 23.85kbps */, VOAMRWB_N_MODES /* Invalid Mode */};
+const VOAMRWBFRAMETYPE kFrameTypes[] = {VOAMRWB_DEFAULT, VOAMRWB_ITU, VOAMRWB_RFC3267};
+
+class Codec {
+ public:
+ Codec() = default;
+ ~Codec() { deInitEncoder(); }
+ bool initEncoder(const uint8_t *data);
+ void deInitEncoder();
+ void encodeFrames(const uint8_t *data, size_t size);
+
+ private:
+ VO_AUDIO_CODECAPI *mApiHandle = nullptr;
+ VO_MEM_OPERATOR *mMemOperator = nullptr;
+ VO_HANDLE mEncoderHandle = nullptr;
+};
+
+bool Codec::initEncoder(const uint8_t *data) {
+ uint8_t startByte = *data;
+ int32_t mode = kModes[(startByte >> 4) % 10];
+ VOAMRWBFRAMETYPE frameType = kFrameTypes[startByte % 3];
+ mMemOperator = new VO_MEM_OPERATOR;
+ if (!mMemOperator) {
+ return false;
+ }
+
+ mMemOperator->Alloc = cmnMemAlloc;
+ mMemOperator->Copy = cmnMemCopy;
+ mMemOperator->Free = cmnMemFree;
+ mMemOperator->Set = cmnMemSet;
+ mMemOperator->Check = cmnMemCheck;
+
+ VO_CODEC_INIT_USERDATA userData;
+ memset(&userData, 0, sizeof(userData));
+ userData.memflag = VO_IMF_USERMEMOPERATOR;
+ userData.memData = (VO_PTR)mMemOperator;
+
+ mApiHandle = new VO_AUDIO_CODECAPI;
+ if (!mApiHandle) {
+ return false;
+ }
+ if (VO_ERR_NONE != voGetAMRWBEncAPI(mApiHandle)) {
+ // Failed to get api handle
+ return false;
+ }
+ if (VO_ERR_NONE != mApiHandle->Init(&mEncoderHandle, VO_AUDIO_CodingAMRWB, &userData)) {
+ // Failed to init AMRWB encoder
+ return false;
+ }
+ if (VO_ERR_NONE != mApiHandle->SetParam(mEncoderHandle, VO_PID_AMRWB_FRAMETYPE, &frameType)) {
+ // Failed to set AMRWB encoder frame type
+ return false;
+ }
+ if (VO_ERR_NONE != mApiHandle->SetParam(mEncoderHandle, VO_PID_AMRWB_MODE, &mode)) {
+ // Failed to set AMRWB encoder mode
+ return false;
+ }
+ return true;
+}
+
+void Codec::deInitEncoder() {
+ if (mEncoderHandle) {
+ mApiHandle->Uninit(mEncoderHandle);
+ mEncoderHandle = nullptr;
+ }
+ if (mApiHandle) {
+ delete mApiHandle;
+ mApiHandle = nullptr;
+ }
+ if (mMemOperator) {
+ delete mMemOperator;
+ mMemOperator = nullptr;
+ }
+}
+
+void Codec::encodeFrames(const uint8_t *data, size_t size) {
+ do {
+ int32_t minSize = std::min((int32_t)size, kInputBufferSize);
+ uint8_t outputBuf[kOutputBufferSize] = {};
+ VO_CODECBUFFER inData;
+ VO_CODECBUFFER outData;
+ VO_AUDIO_OUTPUTINFO outFormat;
+ inData.Buffer = (unsigned char *)data;
+ inData.Length = minSize;
+ outData.Buffer = outputBuf;
+ mApiHandle->SetInputData(mEncoderHandle, &inData);
+ mApiHandle->GetOutputData(mEncoderHandle, &outData, &outFormat);
+ data += minSize;
+ size -= minSize;
+ } while (size > 0);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size < 1) {
+ return 0;
+ }
+ Codec *codec = new Codec();
+ if (!codec) {
+ return 0;
+ }
+ if (codec->initEncoder(data)) {
+ // Consume first byte
+ ++data;
+ --size;
+ codec->encodeFrames(data, size);
+ }
+ delete codec;
+ return 0;
+}
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
index a11f55e..335846c 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/vop.cpp
@@ -24,7 +24,6 @@
#define OSCL_DISABLE_WARNING_CONV_POSSIBLE_LOSS_OF_DATA
-#ifdef PV_SUPPORT_MAIN_PROFILE
/* INTRA */
const static int mpeg_iqmat_def[NCOEFF_BLOCK] =
{
@@ -50,7 +49,6 @@
22, 23, 24, 26, 27, 28, 30, 31,
23, 24, 25, 27, 28, 30, 31, 33
};
-#endif
/* ======================================================================== */
/* Function : CalcNumBits() */
@@ -86,9 +84,7 @@
BitstreamDecVideo *stream;
uint32 tmpvar, vol_shape;
uint32 startCode;
-#ifdef PV_SUPPORT_MAIN_PROFILE
int *qmat, i, j;
-#endif
int version_id = 1;
#ifdef PV_TOLERATE_VOL_ERRORS
uint32 profile = 0x01;
@@ -317,7 +313,8 @@
}
else
{
- if (tmpvar != 0x01) return PV_FAIL;
+ // Simple and advanced simple (for quant-type 1)
+ if (tmpvar != 0x01 && tmpvar != 0x11) return PV_FAIL;
}
/* version id specified? */
@@ -486,7 +483,6 @@
currVol->quantType = BitstreamRead1Bits(stream);
if (currVol->quantType)
{
-#ifdef PV_SUPPORT_MAIN_PROFILE
/* load quantization matrices. 5/22/2000 */
/* load_intra_quant_mat (1 bit) */
qmat = currVol->iqmat;
@@ -531,9 +527,6 @@
{
oscl_memcpy(qmat, mpeg_nqmat_def, 64*sizeof(int));
}
-#else
- return PV_FAIL;
-#endif
}
if (version_id != 1)
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml b/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml
index 47e10ca..f572b0c 100755
--- a/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/AndroidTest.xml
@@ -19,7 +19,7 @@
<option name="cleanup" value="true" />
<option name="push" value="Mpeg4H263DecoderTest->/data/local/tmp/Mpeg4H263DecoderTest" />
<option name="push-file"
- key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder.zip?unzip=true"
+ key="https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder-1.1.zip?unzip=true"
value="/data/local/tmp/Mpeg4H263DecoderTestRes/" />
</target_preparer>
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp b/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp
index 967c1ea..53d66ea 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263DecoderTest.cpp
@@ -404,6 +404,9 @@
make_tuple("swirl_352x288_h263.h263", "swirl_352x288_h263.info", false),
make_tuple("bbb_352x288_h263.h263", "bbb_352x288_h263.info", false),
make_tuple("bbb_352x288_mpeg4.m4v", "bbb_352x288_mpeg4.info", true),
+ make_tuple("qtype0_mpeg4.m4v", "qtype0_mpeg4.info", true),
+ make_tuple("qtype1_mpeg4.m4v", "qtype1_mpeg4.info", true),
+ make_tuple("qtype1_qmatrix_mpeg4.m4v", "qtype1_qmatrix_mpeg4.info", true),
make_tuple("swirl_128x128_mpeg4.m4v", "swirl_128x128_mpeg4.info", true),
make_tuple("swirl_130x132_mpeg4.m4v", "swirl_130x132_mpeg4.info", true),
make_tuple("swirl_132x130_mpeg4.m4v", "swirl_132x130_mpeg4.info", true),
diff --git a/media/libstagefright/codecs/m4v_h263/dec/test/README.md b/media/libstagefright/codecs/m4v_h263/dec/test/README.md
index 7e4aea1..38ac567 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/test/README.md
+++ b/media/libstagefright/codecs/m4v_h263/dec/test/README.md
@@ -22,7 +22,8 @@
adb push ${OUT}/data/nativetest/Mpeg4H263DecoderTest/Mpeg4H263DecoderTest /data/local/tmp/
```
-The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder.zip). Download, unzip and push these files into device for testing.
+The resource file for the tests is taken from [here](https://storage.googleapis.com/android_media/frameworks/av/media/libstagefright/codecs/m4v_h263/dec/test/Mpeg4H263Decoder-1.1.zip).
+Download, unzip and push these files into device for testing.
```
adb push Mpeg4H263Decoder /data/local/tmp/
diff --git a/media/libstagefright/codecs/m4v_h263/enc/Android.bp b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
index b8bc24e..13d310d 100644
--- a/media/libstagefright/codecs/m4v_h263/enc/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/enc/Android.bp
@@ -6,6 +6,12 @@
"com.android.media.swcodec",
],
min_sdk_version: "29",
+ host_supported: true,
+ target: {
+ darwin: {
+ enabled: false,
+ },
+ },
srcs: [
"src/bitstream_io.cpp",
diff --git a/media/libstagefright/codecs/m4v_h263/fuzzer/Android.bp b/media/libstagefright/codecs/m4v_h263/fuzzer/Android.bp
index 56fc782..778dafb 100644
--- a/media/libstagefright/codecs/m4v_h263/fuzzer/Android.bp
+++ b/media/libstagefright/codecs/m4v_h263/fuzzer/Android.bp
@@ -18,25 +18,24 @@
* Originally developed and contributed by Ittiam Systems Pvt. Ltd, Bangalore
*/
-cc_fuzz {
- name: "mpeg4_dec_fuzzer",
+cc_defaults {
+ name: "mpeg4_h263_dec_fuzz_defaults",
+
host_supported: true,
+
srcs: [
"mpeg4_h263_dec_fuzzer.cpp",
],
+
static_libs: [
"libstagefright_m4vh263dec",
"liblog",
],
+
cflags: [
"-DOSCL_IMPORT_REF=",
- "-DMPEG4",
],
- target: {
- darwin: {
- enabled: false,
- },
- },
+
fuzz_config: {
cc: [
"android-media-fuzzing-reports@google.com",
@@ -46,23 +45,45 @@
}
cc_fuzz {
- name: "h263_dec_fuzzer",
- host_supported: true,
- srcs: [
- "mpeg4_h263_dec_fuzzer.cpp",
+ name: "mpeg4_dec_fuzzer",
+
+ defaults: [
+ "mpeg4_h263_dec_fuzz_defaults",
],
- static_libs: [
- "libstagefright_m4vh263dec",
+
+ cflags: [
+ "-DMPEG4",
+ ],
+}
+
+cc_fuzz {
+ name: "h263_dec_fuzzer",
+
+ defaults: [
+ "mpeg4_h263_dec_fuzz_defaults",
+ ],
+}
+
+cc_defaults {
+ name: "mpeg4_h263_enc_fuzz_defaults",
+
+ host_supported: true,
+
+ srcs: ["mpeg4_h263_enc_fuzzer.cpp"],
+
+ shared_libs: [
+ "libutils",
"liblog",
],
- cflags: [
- "-DOSCL_IMPORT_REF=",
+
+ static_libs: [
+ "libstagefright_m4vh263enc",
],
- target: {
- darwin: {
- enabled: false,
- },
- },
+
+ cflags: [
+ "-Wall",
+ "-Werror",
+ ],
fuzz_config: {
cc: [
"android-media-fuzzing-reports@google.com",
@@ -70,3 +91,21 @@
componentid: 155276,
},
}
+
+cc_fuzz {
+ name: "mpeg4_enc_fuzzer",
+
+ defaults: [
+ "mpeg4_h263_enc_fuzz_defaults",
+ ],
+
+ cflags: ["-DMPEG4"],
+}
+
+cc_fuzz {
+ name: "h263_enc_fuzzer",
+
+ defaults: [
+ "mpeg4_h263_enc_fuzz_defaults",
+ ],
+}
diff --git a/media/libstagefright/codecs/m4v_h263/fuzzer/README.md b/media/libstagefright/codecs/m4v_h263/fuzzer/README.md
index c2a4f69..ad4ff97 100644
--- a/media/libstagefright/codecs/m4v_h263/fuzzer/README.md
+++ b/media/libstagefright/codecs/m4v_h263/fuzzer/README.md
@@ -52,6 +52,107 @@
$ $ANDROID_HOST_OUT/fuzz/x86_64/h263_dec_fuzzer/h263_dec_fuzzer CORPUS_DIR
```
+# Fuzzer for libstagefright_m4vh263enc encoder
+
+## Plugin Design Considerations
+The fuzzer plugin for MPEG4/H263 is designed based on the understanding of the
+codec and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+MPEG4/H263 supports the following parameters:
+1. Frame Width (parameter name: `encWidth`)
+2. Frame Height (parameter name: `encHeight`)
+3. Rate control mode (parameter name: `rcType`)
+4. Number of bytes per packet (parameter name: `packetSize`)
+5. Qp for I-Vop(parameter name: `iQuant`)
+6. Qp for P-Vop (parameter name: `pQuant`)
+7. Enable RVLC mode (parameter name: `rvlcEnable`)
+8. Quantization mode (parameter name: `quantType`)
+9. Disable frame skipping (parameter name: `noFrameSkipped`)
+10. Enable scene change detection (parameter name: `sceneDetect`)
+11. Number of intra MBs in P-frame(parameter name: `numIntraMB`)
+12. Search range of ME (parameter name: `searchRange`)
+13. Enable 8x8 ME and MC (parameter name: `mv8x8Enable`)
+14. Enable AC prediction (parameter name: `useACPred`)
+15. Threshold for intra DC VLC (parameter name: `intraDCVlcTh`)
+16. Encoding Mode (parameter name: `encMode`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `rcType` | 0. `CONSTANT_Q` 1. `CBR_1` 2. `VBR_1` 3. `CBR_2` 4. `VBR_2` 5. `CBR_LOWDELAY` | All the bits of 6th byte of data modulus 6 |
+| `packetSize` | In the range `0 to 255` | All the bits of 7th byte of data |
+| `iQuant` | In the range `1 to 31` | All the bits of 8th byte of data |
+| `pQuant` | In the range `1 to 31` | All the bits of 9th byte of data |
+| `rvlcEnable` | 0. `PV_OFF` 1. `PV_ON` | bit 0 of 10th byte of data |
+| `quantType` | 0. `0` 1. `1` | bit 0 of 11th byte of data |
+| `noFrameSkipped` | 0. `PV_OFF` 1. `PV_ON` | bit 0 of 12th byte of data |
+| `sceneDetect` | 0. `PV_OFF` 1. `PV_ON` | bit 0 of 13th byte of data |
+| `numIntraMB` | In the range `0 to 7` | bit 0, 1 and 2 of 14th byte of data |
+| `searchRange` | In the range `0 to 31` | bit 0, 1, 2, 3 and 4 of 15th byte of data |
+| `mv8x8Enable` | 0. `PV_OFF` 1. `PV_ON` | bit 0 of 16th byte of data |
+| `useACPred` | 0. `PV_OFF` 1. `PV_ON` | bit 0 of 17th byte of data |
+| `intraDCVlcTh` | In the range `0 to 7` | bit 0, 1 and 2 of 18th byte of data |
+
+Following parameters are only for mpeg4_enc_fuzzer
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `encWidth` | In the range `0 to 10239` | All the bits of 1st and 2nd byte of data |
+| `encHeight` | In the range `0 to 10239` | All the bits of 3rd and 4th byte of data |
+| `encMode` | 0. `H263_MODE` 1. `H263_MODE_WITH_ERR_RES` 2. `DATA_PARTITIONING_MODE` 3. `COMBINE_MODE_NO_ERR_RES` 4. `COMBINE_MODE_WITH_ERR_RES` | All the bits of 19th byte of data modulus 5 |
+
+Following parameters are only for h263_enc_fuzzer
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `encWidth` | 0. `128` 1. `176` 2. `352` 3. `704` 4. `1408` | All the bits of 1st byte of data modulus 5|
+| `encHeight` | 0. `96` 1. `144` 2. `288` 3. `576` 4. `1152 ` | All the bits of 3rd byte of data modulus 5|
+| `encMode` | 0. `SHORT_HEADER` 1. `SHORT_HEADER_WITH_ERR_RES` | All the bits of 19th byte of data modulus 2 |
+
+This also ensures that the plugin is always deterministic for any given input.
+
+##### Maximize utilization of input data
+The plugin feeds the entire input data to the codec using a loop.
+If the encode operation was successful, the input is advanced by the frame size.
+If the encode operation was un-successful, the input is still advanced by frame size so
+that the fuzzer can proceed to feed the next frame.
+
+This ensures that the plugin tolerates any kind of input (empty, huge,
+malformed, etc) and doesnt `exit()` on any input and thereby increasing the
+chance of identifying vulnerabilities.
+
+## Build
+
+This describes steps to build mpeg4_enc_fuzzer and h263_enc_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) mpeg4_enc_fuzzer
+ $ mm -j$(nproc) h263_enc_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some yuv files to that folder
+Push this directory to device.
+
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/m4v_h263_enc_fuzzer/m4v_h263_enc_fuzzer CORPUS_DIR
+ $ adb shell /data/fuzz/arm64/h263_enc_fuzzer/h263_enc_fuzzer CORPUS_DIR
+```
+To run on host
+```
+ $ $ANDROID_HOST_OUT/fuzz/x86_64/mpeg4_enc_fuzzer/mpeg4_enc_fuzzer CORPUS_DIR
+ $ $ANDROID_HOST_OUT/fuzz/x86_64/h263_enc_fuzzer/h263_enc_fuzzer CORPUS_DIR
+```
+
## References:
* http://llvm.org/docs/LibFuzzer.html
* https://github.com/google/oss-fuzz
diff --git a/media/libstagefright/codecs/m4v_h263/fuzzer/mpeg4_h263_enc_fuzzer.cpp b/media/libstagefright/codecs/m4v_h263/fuzzer/mpeg4_h263_enc_fuzzer.cpp
new file mode 100644
index 0000000..f154706
--- /dev/null
+++ b/media/libstagefright/codecs/m4v_h263/fuzzer/mpeg4_h263_enc_fuzzer.cpp
@@ -0,0 +1,190 @@
+/*
+ * Copyright (C) 2020 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 <algorithm>
+#include "mp4enc_api.h"
+
+constexpr int8_t kIDRFrameRefreshIntervalInSec = 1;
+constexpr MP4RateControlType krcType[] = {CONSTANT_Q, CBR_1, VBR_1, CBR_2, VBR_2, CBR_LOWDELAY};
+#ifdef MPEG4
+constexpr MP4EncodingMode kEncodingMode[] = {SHORT_HEADER, SHORT_HEADER_WITH_ERR_RES,
+ DATA_PARTITIONING_MODE, COMBINE_MODE_NO_ERR_RES,
+ COMBINE_MODE_WITH_ERR_RES};
+constexpr size_t kMaxWidth = 10240;
+constexpr size_t kMaxHeight = 10240;
+#else
+constexpr MP4EncodingMode kEncodingMode[] = {H263_MODE, H263_MODE_WITH_ERR_RES};
+constexpr int kWidth[] = {128, 176, 352, 704, 1408};
+constexpr int kHeight[] = {96, 144, 288, 576, 1152};
+constexpr size_t kWidthNum = std::size(kWidth);
+constexpr size_t kHeightNum = std::size(kHeight);
+#endif
+
+constexpr size_t krcTypeNum = std::size(krcType);
+constexpr size_t kEncodingModeNum = std::size(kEncodingMode);
+constexpr size_t kMaxQP = 51;
+
+enum {
+ IDX_WD_BYTE_1,
+ IDX_WD_BYTE_2,
+ IDX_HT_BYTE_1,
+ IDX_HT_BYTE_2,
+ IDX_FRAME_RATE,
+ IDX_RC_TYPE,
+ IDX_PACKET_SIZE,
+ IDX_I_FRAME_QP,
+ IDX_P_FRAME_QP,
+ IDX_ENABLE_RVLC,
+ IDX_QUANT_TYPE,
+ IDX_NO_FRAME_SKIPPED_FLAG,
+ IDX_ENABLE_SCENE_DETECT,
+ IDX_NUM_INTRA_MB,
+ IDX_SEARCH_RANGE,
+ IDX_ENABLE_MV_8x8,
+ IDX_USE_AC_PRED,
+ IDX_INTRA_DC_VLC_THRESHOLD,
+ IDX_ENC_MODE,
+ IDX_LAST
+};
+
+class Codec {
+ public:
+ Codec() = default;
+ ~Codec() { deInitEncoder(); }
+ bool initEncoder(const uint8_t *data);
+ void encodeFrames(const uint8_t *data, size_t size);
+ void deInitEncoder();
+
+ private:
+ int32_t mFrameWidth = 352;
+ int32_t mFrameHeight = 288;
+ float mFrameRate = 25.0f;
+ VideoEncOptions *mEncodeHandle = nullptr;
+ VideoEncControls *mEncodeControl = nullptr;
+};
+
+bool Codec::initEncoder(const uint8_t *data) {
+ mEncodeHandle = new VideoEncOptions;
+ if (!mEncodeHandle) {
+ return false;
+ }
+ memset(mEncodeHandle, 0, sizeof(VideoEncOptions));
+ mEncodeControl = new VideoEncControls;
+ if (!mEncodeControl) {
+ return false;
+ }
+ memset(mEncodeControl, 0, sizeof(VideoEncControls));
+ PVGetDefaultEncOption(mEncodeHandle, 0);
+
+#ifdef MPEG4
+ mFrameWidth = ((data[IDX_WD_BYTE_1] << 8) | data[IDX_WD_BYTE_2]) % kMaxWidth;
+ mFrameHeight = ((data[IDX_HT_BYTE_1] << 8) | data[IDX_HT_BYTE_2]) % kMaxHeight;
+#else
+ mFrameWidth = kWidth[data[IDX_WD_BYTE_1] % kWidthNum];
+ mFrameHeight = kHeight[data[IDX_HT_BYTE_1] % kHeightNum];
+#endif
+ mFrameRate = data[IDX_FRAME_RATE];
+ mEncodeHandle->rcType = krcType[data[IDX_RC_TYPE] % krcTypeNum];
+ mEncodeHandle->profile_level = CORE_PROFILE_LEVEL2;
+ mEncodeHandle->packetSize = data[IDX_PACKET_SIZE];
+ mEncodeHandle->iQuant[0] = (data[IDX_I_FRAME_QP] % kMaxQP) + 1;
+ mEncodeHandle->pQuant[0] = (data[IDX_P_FRAME_QP] % kMaxQP) + 1;
+ mEncodeHandle->rvlcEnable = (data[IDX_ENABLE_RVLC] & 0x01) ? PV_OFF : PV_ON;
+ mEncodeHandle->quantType[0] = (data[IDX_QUANT_TYPE] & 0x01) ? 0 : 1;
+ mEncodeHandle->noFrameSkipped = (data[IDX_NO_FRAME_SKIPPED_FLAG] & 0x01) ? PV_OFF : PV_ON;
+ mEncodeHandle->sceneDetect = (data[IDX_ENABLE_SCENE_DETECT] & 0x01) ? PV_OFF : PV_ON;
+ mEncodeHandle->numIntraMB = data[IDX_NUM_INTRA_MB] & 0x07;
+ mEncodeHandle->searchRange = data[IDX_SEARCH_RANGE] & 0x1F;
+ mEncodeHandle->mv8x8Enable = (data[IDX_ENABLE_MV_8x8] & 0x01) ? PV_OFF : PV_ON;
+ mEncodeHandle->useACPred = (data[IDX_USE_AC_PRED] & 0x01) ? PV_OFF : PV_ON;
+ mEncodeHandle->intraDCVlcTh = data[IDX_INTRA_DC_VLC_THRESHOLD] & 0x07;
+ mEncodeHandle->encMode = kEncodingMode[data[IDX_ENC_MODE] % kEncodingModeNum];
+ mEncodeHandle->encWidth[0] = mFrameWidth;
+ mEncodeHandle->encHeight[0] = mFrameHeight;
+ mEncodeHandle->encFrameRate[0] = mFrameRate;
+ mEncodeHandle->tickPerSrc = mEncodeHandle->timeIncRes / mFrameRate;
+ mEncodeHandle->intraPeriod = (kIDRFrameRefreshIntervalInSec * mFrameRate);
+ if (!PVInitVideoEncoder(mEncodeControl, mEncodeHandle)) {
+ return false;
+ }
+ return true;
+}
+
+void Codec::deInitEncoder() {
+ if (mEncodeControl) {
+ PVCleanUpVideoEncoder(mEncodeControl);
+ delete mEncodeControl;
+ mEncodeControl = nullptr;
+ }
+ if (mEncodeHandle) {
+ delete mEncodeHandle;
+ mEncodeHandle = nullptr;
+ }
+}
+
+void Codec::encodeFrames(const uint8_t *data, size_t size) {
+ size_t inputBufferSize = (mFrameWidth * mFrameHeight * 3) / 2;
+ size_t outputBufferSize = inputBufferSize * 2;
+ uint8_t outputBuffer[outputBufferSize];
+
+ // Get VOL header.
+ int32_t sizeOutputBuffer = outputBufferSize;
+ PVGetVolHeader(mEncodeControl, outputBuffer, &sizeOutputBuffer, 0);
+
+ size_t numFrame = 0;
+ while (size > 0) {
+ size_t bytesConsumed = std::min(size, inputBufferSize);
+ uint8_t inputBuffer[inputBufferSize];
+ memcpy(inputBuffer, data, bytesConsumed);
+ if (bytesConsumed < sizeof(inputBuffer)) {
+ memset(inputBuffer + bytesConsumed, data[0], sizeof(inputBuffer) - bytesConsumed);
+ }
+ VideoEncFrameIO videoIn{}, videoOut{};
+ videoIn.height = mFrameHeight;
+ videoIn.pitch = mFrameWidth;
+ videoIn.timestamp = (numFrame * 1000) / mFrameRate;
+ videoIn.yChan = inputBuffer;
+ videoIn.uChan = videoIn.yChan + videoIn.height * videoIn.pitch;
+ videoIn.vChan = videoIn.uChan + ((videoIn.height * videoIn.pitch) >> 2);
+ uint32_t modTimeMs = 0;
+ int32_t dataLength = outputBufferSize;
+ int32_t nLayer = 0;
+ PVEncodeVideoFrame(mEncodeControl, &videoIn, &videoOut, &modTimeMs, outputBuffer,
+ &dataLength, &nLayer);
+ MP4HintTrack hintTrack;
+ PVGetHintTrack(mEncodeControl, &hintTrack);
+ PVGetOverrunBuffer(mEncodeControl);
+ ++numFrame;
+ data += bytesConsumed;
+ size -= bytesConsumed;
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ if (size < IDX_LAST) {
+ return 0;
+ }
+ Codec *codec = new Codec();
+ if (!codec) {
+ return 0;
+ }
+ if (codec->initEncoder(data)) {
+ data += IDX_LAST;
+ size -= IDX_LAST;
+ codec->encodeFrames(data, size);
+ }
+ delete codec;
+ return 0;
+}
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp
index a5c7f5e..15d2feb 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_framedecoder.cpp
@@ -219,6 +219,11 @@
if (info->error_protection)
{
+ if (!bitsAvailable(&pVars->inputStream, 16))
+ {
+ return SIDE_INFO_ERROR;
+ }
+
/*
* Get crc content
*/
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp
index d644207..1a3fca5 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_get_side_info.cpp
@@ -73,6 +73,7 @@
#include "pvmp3_get_side_info.h"
#include "pvmp3_crc.h"
+#include "pvmp3_getbits.h"
/*----------------------------------------------------------------------------
@@ -125,12 +126,22 @@
{
if (stereo == 1)
{
+ if (!bitsAvailable(inputStream, 14))
+ {
+ return SIDE_INFO_ERROR;
+ }
+
tmp = getbits_crc(inputStream, 14, crc, info->error_protection);
si->main_data_begin = (tmp << 18) >> 23; /* 9 */
si->private_bits = (tmp << 27) >> 27; /* 5 */
}
else
{
+ if (!bitsAvailable(inputStream, 12))
+ {
+ return SIDE_INFO_ERROR;
+ }
+
tmp = getbits_crc(inputStream, 12, crc, info->error_protection);
si->main_data_begin = (tmp << 20) >> 23; /* 9 */
si->private_bits = (tmp << 29) >> 29; /* 3 */
@@ -139,6 +150,11 @@
for (ch = 0; ch < stereo; ch++)
{
+ if (!bitsAvailable(inputStream, 4))
+ {
+ return SIDE_INFO_ERROR;
+ }
+
tmp = getbits_crc(inputStream, 4, crc, info->error_protection);
si->ch[ch].scfsi[0] = (tmp << 28) >> 31; /* 1 */
si->ch[ch].scfsi[1] = (tmp << 29) >> 31; /* 1 */
@@ -150,6 +166,11 @@
{
for (ch = 0; ch < stereo; ch++)
{
+ if (!bitsAvailable(inputStream, 34))
+ {
+ return SIDE_INFO_ERROR;
+ }
+
si->ch[ch].gran[gr].part2_3_length = getbits_crc(inputStream, 12, crc, info->error_protection);
tmp = getbits_crc(inputStream, 22, crc, info->error_protection);
@@ -160,6 +181,11 @@
if (si->ch[ch].gran[gr].window_switching_flag)
{
+ if (!bitsAvailable(inputStream, 22))
+ {
+ return SIDE_INFO_ERROR;
+ }
+
tmp = getbits_crc(inputStream, 22, crc, info->error_protection);
si->ch[ch].gran[gr].block_type = (tmp << 10) >> 30; /* 2 */;
@@ -192,6 +218,11 @@
}
else
{
+ if (!bitsAvailable(inputStream, 22))
+ {
+ return SIDE_INFO_ERROR;
+ }
+
tmp = getbits_crc(inputStream, 22, crc, info->error_protection);
si->ch[ch].gran[gr].table_select[0] = (tmp << 10) >> 27; /* 5 */;
@@ -204,6 +235,11 @@
si->ch[ch].gran[gr].block_type = 0;
}
+ if (!bitsAvailable(inputStream, 3))
+ {
+ return SIDE_INFO_ERROR;
+ }
+
tmp = getbits_crc(inputStream, 3, crc, info->error_protection);
si->ch[ch].gran[gr].preflag = (tmp << 29) >> 31; /* 1 */
si->ch[ch].gran[gr].scalefac_scale = (tmp << 30) >> 31; /* 1 */
@@ -213,11 +249,21 @@
}
else /* Layer 3 LSF */
{
+ if (!bitsAvailable(inputStream, 8 + stereo))
+ {
+ return SIDE_INFO_ERROR;
+ }
+
si->main_data_begin = getbits_crc(inputStream, 8, crc, info->error_protection);
si->private_bits = getbits_crc(inputStream, stereo, crc, info->error_protection);
for (ch = 0; ch < stereo; ch++)
{
+ if (!bitsAvailable(inputStream, 39))
+ {
+ return SIDE_INFO_ERROR;
+ }
+
tmp = getbits_crc(inputStream, 21, crc, info->error_protection);
si->ch[ch].gran[0].part2_3_length = (tmp << 11) >> 20; /* 12 */
si->ch[ch].gran[0].big_values = (tmp << 23) >> 23; /* 9 */
@@ -230,6 +276,11 @@
if (si->ch[ch].gran[0].window_switching_flag)
{
+ if (!bitsAvailable(inputStream, 22))
+ {
+ return SIDE_INFO_ERROR;
+ }
+
tmp = getbits_crc(inputStream, 22, crc, info->error_protection);
si->ch[ch].gran[0].block_type = (tmp << 10) >> 30; /* 2 */;
@@ -262,6 +313,11 @@
}
else
{
+ if (!bitsAvailable(inputStream, 22))
+ {
+ return SIDE_INFO_ERROR;
+ }
+
tmp = getbits_crc(inputStream, 22, crc, info->error_protection);
si->ch[ch].gran[0].table_select[0] = (tmp << 10) >> 27; /* 5 */;
@@ -274,6 +330,11 @@
si->ch[ch].gran[0].block_type = 0;
}
+ if (!bitsAvailable(inputStream, 2))
+ {
+ return SIDE_INFO_ERROR;
+ }
+
tmp = getbits_crc(inputStream, 2, crc, info->error_protection);
si->ch[ch].gran[0].scalefac_scale = tmp >> 1; /* 1 */
si->ch[ch].gran[0].count1table_select = tmp & 1; /* 1 */
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.cpp b/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.cpp
index 8ff7953..4d252ef 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.cpp
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.cpp
@@ -113,10 +113,11 @@
uint32 offset;
uint32 bitIndex;
- uint8 Elem; /* Needs to be same type as pInput->pBuffer */
- uint8 Elem1;
- uint8 Elem2;
- uint8 Elem3;
+ uint32 bytesToFetch;
+ uint8 Elem = 0; /* Needs to be same type as pInput->pBuffer */
+ uint8 Elem1 = 0;
+ uint8 Elem2 = 0;
+ uint8 Elem3 = 0;
uint32 returnValue = 0;
if (!neededBits)
@@ -126,10 +127,25 @@
offset = (ptBitStream->usedBits) >> INBUF_ARRAY_INDEX_SHIFT;
- Elem = *(ptBitStream->pBuffer + module(offset , BUFSIZE));
- Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
- Elem2 = *(ptBitStream->pBuffer + module(offset + 2, BUFSIZE));
- Elem3 = *(ptBitStream->pBuffer + module(offset + 3, BUFSIZE));
+ /* Remove extra high bits by shifting up */
+ bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH);
+
+ bytesToFetch = (bitIndex + neededBits + 7 ) >> 3 ;
+
+ switch (bytesToFetch)
+ {
+ case 4:
+ Elem3 = *(ptBitStream->pBuffer + module(offset + 3, BUFSIZE));
+ [[fallthrough]];
+ case 3:
+ Elem2 = *(ptBitStream->pBuffer + module(offset + 2, BUFSIZE));
+ [[fallthrough]];
+ case 2:
+ Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
+ [[fallthrough]];
+ case 1:
+ Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE));
+ }
returnValue = (((uint32)(Elem)) << 24) |
@@ -137,9 +153,6 @@
(((uint32)(Elem2)) << 8) |
((uint32)(Elem3));
- /* Remove extra high bits by shifting up */
- bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH);
-
/* This line is faster than to mask off the high bits. */
returnValue <<= bitIndex;
@@ -161,22 +174,32 @@
uint32 offset;
uint32 bitIndex;
- uint8 Elem; /* Needs to be same type as pInput->pBuffer */
- uint8 Elem1;
+ uint32 bytesToFetch;
+ uint8 Elem = 0; /* Needs to be same type as pInput->pBuffer */
+ uint8 Elem1 = 0;
uint16 returnValue;
offset = (ptBitStream->usedBits) >> INBUF_ARRAY_INDEX_SHIFT;
- Elem = *(ptBitStream->pBuffer + module(offset , BUFSIZE));
- Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
+ /* Remove extra high bits by shifting up */
+ bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH);
+
+ bytesToFetch = (bitIndex + neededBits + 7 ) >> 3 ;
+
+ if (bytesToFetch > 1)
+ {
+ Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE));
+ Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
+ }
+ else if (bytesToFetch > 0)
+ {
+ Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE));
+ }
returnValue = (((uint16)(Elem)) << 8) |
((uint16)(Elem1));
- /* Remove extra high bits by shifting up */
- bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH);
-
ptBitStream->usedBits += neededBits;
/* This line is faster than to mask off the high bits. */
returnValue = (returnValue << (bitIndex));
@@ -197,25 +220,40 @@
uint32 offset;
uint32 bitIndex;
- uint8 Elem; /* Needs to be same type as pInput->pBuffer */
- uint8 Elem1;
- uint8 Elem2;
+ uint32 bytesToFetch;
+ uint8 Elem = 0; /* Needs to be same type as pInput->pBuffer */
+ uint8 Elem1 = 0;
+ uint8 Elem2 = 0;
uint32 returnValue;
offset = (ptBitStream->usedBits) >> INBUF_ARRAY_INDEX_SHIFT;
- Elem = *(ptBitStream->pBuffer + module(offset , BUFSIZE));
- Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
- Elem2 = *(ptBitStream->pBuffer + module(offset + 2, BUFSIZE));
+ /* Remove extra high bits by shifting up */
+ bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH);
+
+ bytesToFetch = (bitIndex + neededBits + 7 ) >> 3 ;
+
+ if (bytesToFetch > 2)
+ {
+ Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE));
+ Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
+ Elem2 = *(ptBitStream->pBuffer + module(offset + 2, BUFSIZE));
+ }
+ else if (bytesToFetch > 1)
+ {
+ Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE));
+ Elem1 = *(ptBitStream->pBuffer + module(offset + 1, BUFSIZE));
+ }
+ else if (bytesToFetch > 0)
+ {
+ Elem = *(ptBitStream->pBuffer + module(offset, BUFSIZE));
+ }
returnValue = (((uint32)(Elem)) << 16) |
(((uint32)(Elem1)) << 8) |
((uint32)(Elem2));
- /* Remove extra high bits by shifting up */
- bitIndex = module(ptBitStream->usedBits, INBUF_BIT_WIDTH);
-
ptBitStream->usedBits += neededBits;
/* This line is faster than to mask off the high bits. */
returnValue = 0xFFFFFF & (returnValue << (bitIndex));
diff --git a/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.h b/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.h
index b058b00..b04fe6d 100644
--- a/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.h
+++ b/media/libstagefright/codecs/mp3dec/src/pvmp3_getbits.h
@@ -104,6 +104,11 @@
; Function Prototype declaration
----------------------------------------------------------------------------*/
+static inline bool bitsAvailable(tmp3Bits *inputStream, uint32 neededBits)
+{
+ return (inputStream->inputBufferCurrentLength << 3) >= (neededBits + inputStream->usedBits);
+}
+
/*----------------------------------------------------------------------------
; END
----------------------------------------------------------------------------*/
diff --git a/media/libstagefright/foundation/MediaDefs.cpp b/media/libstagefright/foundation/MediaDefs.cpp
index a08fed1..c216bc5 100644
--- a/media/libstagefright/foundation/MediaDefs.cpp
+++ b/media/libstagefright/foundation/MediaDefs.cpp
@@ -20,6 +20,7 @@
const char *MEDIA_MIMETYPE_IMAGE_JPEG = "image/jpeg";
const char *MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC = "image/vnd.android.heic";
+const char *MEDIA_MIMETYPE_IMAGE_AVIF = "image/avif";
const char *MEDIA_MIMETYPE_VIDEO_VP8 = "video/x-vnd.on2.vp8";
const char *MEDIA_MIMETYPE_VIDEO_VP9 = "video/x-vnd.on2.vp9";
diff --git a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
index 1f9e636..e96243e 100644
--- a/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
+++ b/media/libstagefright/foundation/include/media/stagefright/foundation/MediaDefs.h
@@ -22,6 +22,7 @@
extern const char *MEDIA_MIMETYPE_IMAGE_JPEG;
extern const char *MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC;
+extern const char *MEDIA_MIMETYPE_IMAGE_AVIF;
extern const char *MEDIA_MIMETYPE_VIDEO_VP8;
extern const char *MEDIA_MIMETYPE_VIDEO_VP9;
diff --git a/media/libstagefright/include/media/stagefright/MediaCodec.h b/media/libstagefright/include/media/stagefright/MediaCodec.h
index c246b36..a28d479 100644
--- a/media/libstagefright/include/media/stagefright/MediaCodec.h
+++ b/media/libstagefright/include/media/stagefright/MediaCodec.h
@@ -425,6 +425,10 @@
sp<ICrypto> mCrypto;
+ int32_t mTunneledInputWidth;
+ int32_t mTunneledInputHeight;
+ bool mTunneled;
+
sp<IDescrambler> mDescrambler;
List<sp<ABuffer> > mCSD;
diff --git a/media/libstagefright/include/media/stagefright/MetaDataBase.h b/media/libstagefright/include/media/stagefright/MetaDataBase.h
index 6b0d28f..f260510 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataBase.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataBase.h
@@ -62,6 +62,7 @@
kKeyDVCC = 'dvcc', // raw data
kKeyAV1C = 'av1c', // raw data
kKeyThumbnailHVCC = 'thvc', // raw data
+ kKeyThumbnailAV1C = 'tav1', // raw data
kKeyD263 = 'd263', // raw data
kKeyOpusHeader = 'ohdr', // raw data
kKeyOpusCodecDelay = 'ocod', // uint64_t (codec delay in ns)
diff --git a/media/libstagefright/omx/OMXUtils.cpp b/media/libstagefright/omx/OMXUtils.cpp
index d6d280f..49b2dec 100644
--- a/media/libstagefright/omx/OMXUtils.cpp
+++ b/media/libstagefright/omx/OMXUtils.cpp
@@ -172,6 +172,8 @@
"audio_decoder.ac4", "audio_encoder.ac4" },
{ MEDIA_MIMETYPE_IMAGE_ANDROID_HEIC,
"image_decoder.heic", "image_encoder.heic" },
+ { MEDIA_MIMETYPE_IMAGE_AVIF,
+ "image_decoder.avif", "image_encoder.avif" },
};
static const size_t kNumMimeToRole =
diff --git a/media/libstagefright/tests/fuzzers/Android.bp b/media/libstagefright/tests/fuzzers/Android.bp
new file mode 100644
index 0000000..49ff69a
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/Android.bp
@@ -0,0 +1,53 @@
+cc_defaults {
+ name: "libstagefright_fuzzer_defaults",
+ cflags: [
+ "-Wno-multichar",
+ "-Werror",
+ "-Wno-error=deprecated-declarations",
+ "-Wall",
+ ],
+ shared_libs: [
+ "libstagefright",
+ "libstagefright_codecbase",
+ "libutils",
+ "libstagefright_foundation",
+ "libmedia",
+ "libaudioclient",
+ "libmedia_omx",
+ "libgui",
+ "libbinder",
+ "libcutils",
+ ],
+}
+
+cc_fuzz {
+ name: "libstagefright_mediaclock_fuzzer",
+ srcs: [
+ "MediaClockFuzzer.cpp",
+ ],
+ defaults: ["libstagefright_fuzzer_defaults"],
+}
+
+cc_fuzz {
+ name: "libstagefright_mediascanner_fuzzer",
+ srcs: [
+ "StagefrightMediaScannerFuzzer.cpp",
+ ],
+ defaults: ["libstagefright_fuzzer_defaults"],
+}
+
+cc_fuzz {
+ name: "libstagefright_skipcutbuffer_fuzzer",
+ srcs: [
+ "SkipCutBufferFuzzer.cpp",
+ ],
+ defaults: ["libstagefright_fuzzer_defaults"],
+}
+
+cc_fuzz {
+ name: "libstagefright_mediamuxer_fuzzer",
+ srcs: [
+ "MediaMuxerFuzzer.cpp",
+ ],
+ defaults: ["libstagefright_fuzzer_defaults"],
+}
diff --git a/media/libstagefright/tests/fuzzers/MediaClockFuzzer.cpp b/media/libstagefright/tests/fuzzers/MediaClockFuzzer.cpp
new file mode 100644
index 0000000..e473541
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/MediaClockFuzzer.cpp
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2020 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.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+// dylan.katz@leviathansecurity.com
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <media/stagefright/MediaClock.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+namespace android {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ sp<MediaClock> mClock(new MediaClock);
+
+ bool registered = false;
+ while (fdp.remaining_bytes() > 0) {
+ switch (fdp.ConsumeIntegralInRange<uint8_t>(0, 5)) {
+ case 0: {
+ if (registered == false) {
+ mClock->init();
+ registered = true;
+ }
+ break;
+ }
+ case 1: {
+ int64_t startingTimeMediaUs = fdp.ConsumeIntegral<int64_t>();
+ mClock->setStartingTimeMedia(startingTimeMediaUs);
+ break;
+ }
+ case 2: {
+ mClock->clearAnchor();
+ break;
+ }
+ case 3: {
+ int64_t anchorTimeRealUs = fdp.ConsumeIntegral<int64_t>();
+ int64_t anchorTimeMediaUs = fdp.ConsumeIntegral<int64_t>();
+ int64_t maxTimeMediaUs = fdp.ConsumeIntegral<int64_t>();
+ mClock->updateAnchor(anchorTimeMediaUs, anchorTimeRealUs, maxTimeMediaUs);
+ break;
+ }
+ case 4: {
+ int64_t maxTimeMediaUs = fdp.ConsumeIntegral<int64_t>();
+ mClock->updateMaxTimeMedia(maxTimeMediaUs);
+ break;
+ }
+ case 5: {
+ wp<AMessage> msg(new AMessage);
+ mClock->setNotificationMessage(msg.promote());
+ }
+ }
+ }
+
+ return 0;
+}
+} // namespace android
diff --git a/media/libstagefright/tests/fuzzers/MediaMuxerFuzzer.cpp b/media/libstagefright/tests/fuzzers/MediaMuxerFuzzer.cpp
new file mode 100644
index 0000000..5df3267
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/MediaMuxerFuzzer.cpp
@@ -0,0 +1,103 @@
+/*
+ * Copyright 2020 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.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+// dylan.katz@leviathansecurity.com
+
+#include <MediaMuxerFuzzer.h>
+#include <cutils/ashmem.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <media/stagefright/MediaMuxer.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+namespace android {
+
+// Can't seem to get setBuffer or setString working. It always segfaults on a
+// null pointer read or memleaks. So that functionality is missing.
+void createMessage(AMessage *msg, FuzzedDataProvider *fdp) {
+ size_t count = fdp->ConsumeIntegralInRange<size_t>(0, 32);
+ while (fdp->remaining_bytes() > 0 && count > 0) {
+ uint8_t function_id =
+ fdp->ConsumeIntegralInRange<uint8_t>(0, amessage_setvals.size() - 1);
+ amessage_setvals[function_id](msg, fdp);
+ count--;
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+
+ size_t data_size = fdp.ConsumeIntegralInRange<size_t>(0, size);
+ int fd = ashmem_create_region("mediamuxer_fuzz_region", data_size);
+ if (fd < 0)
+ return 0;
+
+ uint8_t *sh_data = static_cast<uint8_t *>(
+ mmap(NULL, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
+ if (sh_data == MAP_FAILED)
+ return 0;
+
+ MediaMuxer::OutputFormat format =
+ (MediaMuxer::OutputFormat)fdp.ConsumeIntegralInRange<int32_t>(0, 4);
+ sp<MediaMuxer> mMuxer(new MediaMuxer(fd, format));
+
+ while (fdp.remaining_bytes() > 1) {
+ switch (fdp.ConsumeIntegralInRange<uint8_t>(0, 4)) {
+ case 0: {
+ // For some reason it only likes mp4s here...
+ if (format == 1 || format == 4)
+ break;
+
+ sp<AMessage> a_format(new AMessage);
+ createMessage(a_format.get(), &fdp);
+ mMuxer->addTrack(a_format);
+ break;
+ }
+ case 1: {
+ mMuxer->start();
+ break;
+ }
+ case 2: {
+ int degrees = fdp.ConsumeIntegral<int>();
+ mMuxer->setOrientationHint(degrees);
+ break;
+ }
+ case 3: {
+ int latitude = fdp.ConsumeIntegral<int>();
+ int longitude = fdp.ConsumeIntegral<int>();
+ mMuxer->setLocation(latitude, longitude);
+ break;
+ }
+ case 4: {
+ size_t buf_size = fdp.ConsumeIntegralInRange<size_t>(0, data_size);
+ sp<ABuffer> a_buffer(new ABuffer(buf_size));
+
+ size_t trackIndex = fdp.ConsumeIntegral<size_t>();
+ int64_t timeUs = fdp.ConsumeIntegral<int64_t>();
+ uint32_t flags = fdp.ConsumeIntegral<uint32_t>();
+ mMuxer->writeSampleData(a_buffer, trackIndex, timeUs, flags);
+ }
+ }
+ }
+
+ if (fdp.ConsumeBool())
+ mMuxer->stop();
+
+ munmap(sh_data, data_size);
+ close(fd);
+ return 0;
+}
+} // namespace android
diff --git a/media/libstagefright/tests/fuzzers/MediaMuxerFuzzer.h b/media/libstagefright/tests/fuzzers/MediaMuxerFuzzer.h
new file mode 100644
index 0000000..7d4421d
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/MediaMuxerFuzzer.h
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2020 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.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+// dylan.katz@leviathansecurity.com
+
+#pragma once
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+namespace android {
+
+// Mappings vectors are the list of attributes that the MediaMuxer
+// class looks for in the message.
+static std::vector<const char *> floatMappings{
+ "capture-rate",
+ "time-lapse-fps",
+ "frame-rate",
+};
+
+static std::vector<const char *> int64Mappings{
+ "exif-offset", "exif-size", "target-time",
+ "thumbnail-time", "timeUs", "durationUs",
+};
+
+static std::vector<const char *> int32Mappings{"loop",
+ "time-scale",
+ "crypto-mode",
+ "crypto-default-iv-size",
+ "crypto-encrypted-byte-block",
+ "crypto-skip-byte-block",
+ "frame-count",
+ "max-bitrate",
+ "pcm-big-endian",
+ "temporal-layer-count",
+ "temporal-layer-id",
+ "thumbnail-width",
+ "thumbnail-height",
+ "track-id",
+ "valid-samples",
+ "color-format",
+ "ca-system-id",
+ "is-sync-frame",
+ "bitrate",
+ "max-bitrate",
+ "width",
+ "height",
+ "sar-width",
+ "sar-height",
+ "display-width",
+ "display-height",
+ "is-default",
+ "tile-width",
+ "tile-height",
+ "grid-rows",
+ "grid-cols",
+ "rotation-degrees",
+ "channel-count",
+ "sample-rate",
+ "bits-per-sample",
+ "channel-mask",
+ "encoder-delay",
+ "encoder-padding",
+ "is-adts",
+ "frame-rate",
+ "max-height",
+ "max-width",
+ "max-input-size",
+ "haptic-channel-count",
+ "pcm-encoding",
+ "aac-profile"};
+
+static const std::vector<std::function<void(AMessage *, FuzzedDataProvider *)>>
+ amessage_setvals = {
+ [](AMessage *msg, FuzzedDataProvider *fdp) -> void {
+ msg->setRect("crop", fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<int32_t>(),
+ fdp->ConsumeIntegral<int32_t>());
+ },
+ [](AMessage *msg, FuzzedDataProvider *fdp) -> void {
+ msg->setFloat(floatMappings[fdp->ConsumeIntegralInRange<size_t>(
+ 0, floatMappings.size() - 1)],
+ fdp->ConsumeFloatingPoint<float>());
+ },
+ [](AMessage *msg, FuzzedDataProvider *fdp) -> void {
+ msg->setInt64(int64Mappings[fdp->ConsumeIntegralInRange<size_t>(
+ 0, int64Mappings.size() - 1)],
+ fdp->ConsumeIntegral<int64_t>());
+ },
+ [](AMessage *msg, FuzzedDataProvider *fdp) -> void {
+ msg->setInt32(int32Mappings[fdp->ConsumeIntegralInRange<size_t>(
+ 0, int32Mappings.size() - 1)],
+ fdp->ConsumeIntegral<int32_t>());
+ }};
+} // namespace android
diff --git a/media/libstagefright/tests/fuzzers/SkipCutBufferFuzzer.cpp b/media/libstagefright/tests/fuzzers/SkipCutBufferFuzzer.cpp
new file mode 100644
index 0000000..1f78e6d
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/SkipCutBufferFuzzer.cpp
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2020 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.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+// dylan.katz@leviathansecurity.com
+
+#include <fuzzer/FuzzedDataProvider.h>
+#include <media/stagefright/MediaBuffer.h>
+#include <media/stagefright/SkipCutBuffer.h>
+#include <media/stagefright/foundation/ABuffer.h>
+#include <media/stagefright/foundation/AMessage.h>
+
+namespace android {
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ size_t skip = fdp.ConsumeIntegral<size_t>();
+ size_t cut = fdp.ConsumeIntegral<size_t>();
+ size_t num16Channels = fdp.ConsumeIntegral<size_t>();
+ sp<SkipCutBuffer> sBuffer(new SkipCutBuffer(skip, cut, num16Channels));
+
+ while (fdp.remaining_bytes() > 0) {
+ // Cap size to 1024 to limit max amount allocated.
+ size_t buf_size = fdp.ConsumeIntegralInRange<size_t>(0, 1024);
+ size_t range = fdp.ConsumeIntegralInRange<size_t>(0, buf_size);
+ size_t length = fdp.ConsumeIntegralInRange<size_t>(0, buf_size - range);
+
+ switch (fdp.ConsumeIntegralInRange<uint8_t>(0, 4)) {
+ case 0: {
+ sp<ABuffer> a_buffer(new ABuffer(buf_size));
+ sp<AMessage> format(new AMessage);
+ sp<MediaCodecBuffer> s_buffer(new MediaCodecBuffer(format, a_buffer));
+ s_buffer->setRange(range, length);
+ sBuffer->submit(s_buffer);
+ break;
+ }
+ case 1: {
+ std::unique_ptr<MediaBufferBase> m_buffer(new MediaBuffer(buf_size));
+ m_buffer->set_range(range, length);
+ sBuffer->submit(reinterpret_cast<MediaBuffer *>(m_buffer.get()));
+ break;
+ }
+ case 2: {
+ sp<ABuffer> a_buffer(new ABuffer(buf_size));
+ sp<AMessage> format(new AMessage);
+ sp<MediaCodecBuffer> s_buffer(new MediaCodecBuffer(format, a_buffer));
+ a_buffer->setRange(range, length);
+ sBuffer->submit(a_buffer);
+ break;
+ }
+ case 3: {
+ sBuffer->clear();
+ break;
+ }
+ case 4: {
+ sBuffer->size();
+ }
+ }
+ }
+ return 0;
+}
+} // namespace android
diff --git a/media/libstagefright/tests/fuzzers/StagefrightMediaScannerFuzzer.cpp b/media/libstagefright/tests/fuzzers/StagefrightMediaScannerFuzzer.cpp
new file mode 100644
index 0000000..a072b7c
--- /dev/null
+++ b/media/libstagefright/tests/fuzzers/StagefrightMediaScannerFuzzer.cpp
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2020 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.
+ */
+// Authors: corbin.souffrant@leviathansecurity.com
+// dylan.katz@leviathansecurity.com
+
+#include <cutils/ashmem.h>
+#include <fuzzer/FuzzedDataProvider.h>
+#include <media/stagefright/StagefrightMediaScanner.h>
+
+#include <cstdio>
+
+namespace android {
+class FuzzMediaScannerClient : public MediaScannerClient {
+public:
+ virtual status_t scanFile(const char *, long long, long long, bool, bool) {
+ return 0;
+ }
+
+ virtual status_t handleStringTag(const char *, const char *) { return 0; }
+
+ virtual status_t setMimeType(const char *) { return 0; }
+};
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+ FuzzedDataProvider fdp = FuzzedDataProvider(data, size);
+ StagefrightMediaScanner mScanner = StagefrightMediaScanner();
+ // Without this, the fuzzer crashes for some reason.
+ mScanner.setLocale("");
+
+ size_t data_size = fdp.ConsumeIntegralInRange<size_t>(0, size);
+ int fd =
+ ashmem_create_region("stagefrightmediascanner_fuzz_region", data_size);
+ if (fd < 0)
+ return 0;
+
+ uint8_t *sh_data = static_cast<uint8_t *>(
+ mmap(NULL, data_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd, 0));
+ if (sh_data == MAP_FAILED)
+ return 0;
+
+ while (fdp.remaining_bytes() > 8) {
+ switch (fdp.ConsumeIntegralInRange<uint8_t>(0, 1)) {
+ case 0: {
+ std::string path = fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
+ std::string mimeType =
+ fdp.ConsumeRandomLengthString(fdp.remaining_bytes());
+ std::shared_ptr<MediaScannerClient> client(new FuzzMediaScannerClient());
+ mScanner.processFile(path.c_str(), mimeType.c_str(), *client);
+ break;
+ }
+ case 1: {
+ size_t to_copy = fdp.ConsumeIntegralInRange<size_t>(1, data_size);
+ std::vector<uint8_t> rand_buf = fdp.ConsumeBytes<uint8_t>(to_copy);
+
+ // If fdp doesn't have enough bytes left it will just make a shorter
+ // vector.
+ to_copy = std::min(rand_buf.size(), data_size);
+
+ std::copy(sh_data, sh_data + to_copy, rand_buf.begin());
+ mScanner.extractAlbumArt(fd);
+ }
+ }
+ }
+
+ munmap(sh_data, data_size);
+ close(fd);
+ return 0;
+}
+} // namespace android
diff --git a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
index 3be5e74..dbdb43c 100644
--- a/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
+++ b/media/libstagefright/xmlparser/MediaCodecsXmlParser.cpp
@@ -493,7 +493,7 @@
mPath(path),
mStatus(NO_INIT) {
// determine href_base
- std::string::size_type end = path.rfind("/");
+ std::string::size_type end = path.rfind('/');
if (end != std::string::npos) {
mHrefBase = path.substr(0, end + 1);
}
diff --git a/media/mtp/tests/Android.bp b/media/mtp/tests/MtpFfsHandleTest/Android.bp
similarity index 71%
copy from media/mtp/tests/Android.bp
copy to media/mtp/tests/MtpFfsHandleTest/Android.bp
index 0750208..e393067 100644
--- a/media/mtp/tests/Android.bp
+++ b/media/mtp/tests/MtpFfsHandleTest/Android.bp
@@ -1,5 +1,5 @@
//
-// Copyright (C) 2017 The Android Open Source Project
+// Copyright (C) 2020 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.
@@ -30,18 +30,3 @@
],
}
-cc_test {
- name: "posix_async_io_test",
- test_suites: ["device-tests"],
- srcs: ["PosixAsyncIO_test.cpp"],
- shared_libs: [
- "libbase",
- "libmtp",
- "liblog",
- ],
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- ],
-}
diff --git a/media/mtp/tests/AndroidTest.xml b/media/mtp/tests/MtpFfsHandleTest/AndroidTest.xml
similarity index 95%
rename from media/mtp/tests/AndroidTest.xml
rename to media/mtp/tests/MtpFfsHandleTest/AndroidTest.xml
index c1f4753..38bab27 100644
--- a/media/mtp/tests/AndroidTest.xml
+++ b/media/mtp/tests/MtpFfsHandleTest/AndroidTest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2020 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.
diff --git a/media/mtp/tests/MtpFfsHandle_test.cpp b/media/mtp/tests/MtpFfsHandleTest/MtpFfsHandle_test.cpp
similarity index 100%
rename from media/mtp/tests/MtpFfsHandle_test.cpp
rename to media/mtp/tests/MtpFfsHandleTest/MtpFfsHandle_test.cpp
diff --git a/media/mtp/tests/MtpFuzzer/Android.bp b/media/mtp/tests/MtpFuzzer/Android.bp
new file mode 100644
index 0000000..9cd4669
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/Android.bp
@@ -0,0 +1,31 @@
+cc_fuzz {
+ name: "mtp_fuzzer",
+ srcs: [
+ "mtp_fuzzer.cpp",
+ "MtpMockDatabase.cpp",
+ ],
+ shared_libs: [
+ "libmtp",
+ "libbase",
+ "liblog",
+ "libutils",
+ ],
+ cflags: [
+ "-Wall",
+ "-Wextra",
+ "-Werror",
+ "-DMTP_DEVICE",
+ "-Wno-unused-parameter",
+ ],
+ dictionary: "mtp_fuzzer.dict",
+ corpus: ["corpus/*"],
+
+ fuzz_config: {
+
+ cc: ["jameswei@google.com"],
+ componentid: 1344,
+ acknowledgement: [
+ "Grant Hernandez of Google",
+ ],
+ },
+}
diff --git a/media/mtp/tests/MtpFuzzer/MtpMockDatabase.cpp b/media/mtp/tests/MtpFuzzer/MtpMockDatabase.cpp
new file mode 100644
index 0000000..5d95aa2
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/MtpMockDatabase.cpp
@@ -0,0 +1,315 @@
+/*
+ * Copyright (C) 2020 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 <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <string>
+
+#define LOG_TAG "MtpFuzzer"
+
+#include <log/log.h>
+
+#include "MtpDebug.h"
+#include "MtpMockDatabase.h"
+#include "MtpObjectInfo.h"
+
+namespace android {
+
+MtpMockDatabase::MtpMockDatabase() : mLastObjectHandle(0) {}
+
+MtpMockDatabase::~MtpMockDatabase() {
+ for (MtpObjectInfo* i : mObjects) {
+ delete i;
+ }
+ mObjects.clear();
+}
+
+void MtpMockDatabase::addObject(MtpObjectInfo* info) {
+ assert(hasStorage(info->storageID));
+
+ // we take ownership
+ mObjects.push_back(info);
+
+ return;
+}
+
+MtpObjectHandle MtpMockDatabase::allocateObjectHandle() {
+ // this is in sync with our mObjects database
+ return mLastObjectHandle++;
+}
+
+// Called from SendObjectInfo to reserve a database entry for the incoming file.
+MtpObjectHandle MtpMockDatabase::beginSendObject(const char* path, MtpObjectFormat format,
+ MtpObjectHandle parent, MtpStorageID storage) {
+ if (!hasStorage(storage)) {
+ ALOGW("%s: Tried to lookup storageID %u, but doesn't exist\n", __func__, storage);
+ return kInvalidObjectHandle;
+ }
+
+ ALOGD("MockDatabase %s: path=%s oformat=0x%04x parent_handle=%u "
+ "storage_id=%u\n",
+ __func__, path, format, parent, storage);
+
+ return mLastObjectHandle;
+}
+
+// Called to report success or failure of the SendObject file transfer.
+void MtpMockDatabase::endSendObject(MtpObjectHandle handle, bool succeeded) {
+ ALOGD("MockDatabase %s: ohandle=%u succeeded=%d\n", __func__, handle, succeeded);
+}
+
+// Called to rescan a file, such as after an edit.
+void MtpMockDatabase::rescanFile(const char* path, MtpObjectHandle handle, MtpObjectFormat format) {
+ ALOGD("MockDatabase %s: path=%s ohandle=%u, oformat=0x%04x\n", __func__, path, handle, format);
+}
+
+MtpObjectHandleList* MtpMockDatabase::getObjectList(MtpStorageID storageID, MtpObjectFormat format,
+ MtpObjectHandle parent) {
+ ALOGD("MockDatabase %s: storage_id=%u oformat=0x%04x ohandle=%u\n", __func__, storageID, format,
+ parent);
+ return nullptr;
+}
+
+int MtpMockDatabase::getNumObjects(MtpStorageID storageID, MtpObjectFormat format,
+ MtpObjectHandle parent) {
+ ALOGD("MockDatabase %s: storage_id=%u oformat=0x%04x ohandle=%u\n", __func__, storageID, format,
+ parent);
+ // TODO: return MTP_RESPONSE_OK when it stops segfaulting
+ return 0;
+}
+
+// callee should delete[] the results from these
+// results can be NULL
+MtpObjectFormatList* MtpMockDatabase::getSupportedPlaybackFormats() {
+ ALOGD("MockDatabase %s\n", __func__);
+ return nullptr;
+}
+MtpObjectFormatList* MtpMockDatabase::getSupportedCaptureFormats() {
+ ALOGD("MockDatabase %s\n", __func__);
+ return nullptr;
+}
+MtpObjectPropertyList* MtpMockDatabase::getSupportedObjectProperties(MtpObjectFormat format) {
+ ALOGD("MockDatabase %s: oformat=0x%04x\n", __func__, format);
+ return nullptr;
+}
+MtpDevicePropertyList* MtpMockDatabase::getSupportedDeviceProperties() {
+ ALOGD("MockDatabase %s\n", __func__);
+ return nullptr;
+}
+
+MtpResponseCode MtpMockDatabase::getObjectPropertyValue(MtpObjectHandle handle,
+ MtpObjectProperty property,
+ MtpDataPacket& packet) {
+ ALOGD("MockDatabase %s: ohandle=%u property=%s\n", __func__, handle,
+ MtpDebug::getObjectPropCodeName(property));
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::setObjectPropertyValue(MtpObjectHandle handle,
+ MtpObjectProperty property,
+ MtpDataPacket& packet) {
+ ALOGD("MockDatabase %s: ohandle=%u property=%s\n", __func__, handle,
+ MtpDebug::getObjectPropCodeName(property));
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::getDevicePropertyValue(MtpDeviceProperty property,
+ MtpDataPacket& packet) {
+ ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::setDevicePropertyValue(MtpDeviceProperty property,
+ MtpDataPacket& packet) {
+ ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::resetDeviceProperty(MtpDeviceProperty property) {
+ ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::getObjectPropertyList(MtpObjectHandle handle, uint32_t format,
+ uint32_t property, int groupCode, int depth,
+ MtpDataPacket& packet) {
+ ALOGD("MockDatabase %s: ohandle=%u format=%s property=%s groupCode=%d "
+ "depth=%d\n",
+ __func__, handle, MtpDebug::getFormatCodeName(format),
+ MtpDebug::getObjectPropCodeName(property), groupCode, depth);
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info) {
+ ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
+
+ // used for the root
+ if (handle == kInvalidObjectHandle) {
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+ } else {
+ if (mObjects.size() == 0) {
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+ }
+
+ // this is used to let the fuzzer make progress, otherwise
+ // it has to brute-force a 32-bit handle
+ MtpObjectHandle reducedHandle = handle % mObjects.size();
+ MtpObjectInfo* obj = mObjects[reducedHandle];
+
+ // make a copy, but make sure to maintain ownership of string pointers
+ info = *obj;
+
+ // fixup the response handle
+ info.mHandle = handle;
+
+ if (obj->mName) info.mName = strdup(obj->mName);
+ if (obj->mKeywords) info.mKeywords = strdup(obj->mKeywords);
+
+ return MTP_RESPONSE_OK;
+ }
+}
+
+void* MtpMockDatabase::getThumbnail(MtpObjectHandle handle, size_t& outThumbSize) {
+ ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
+
+ size_t allocSize = handle % 0x1000;
+ void* data = calloc(allocSize, sizeof(uint8_t));
+ if (!data) {
+ return nullptr;
+ } else {
+ ALOGD("MockDatabase %s\n", __func__);
+ outThumbSize = allocSize;
+ return data;
+ }
+}
+
+MtpResponseCode MtpMockDatabase::getObjectFilePath(MtpObjectHandle handle,
+ MtpStringBuffer& outFilePath,
+ int64_t& outFileLength,
+ MtpObjectFormat& outFormat) {
+ ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
+
+ if (mObjects.size() == 0) {
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+ }
+
+ // this is used to let the fuzzer make progress, otherwise
+ // it has to brute-force a 32-bit handle
+ MtpObjectHandle reducedHandle = handle % mObjects.size();
+ MtpObjectInfo* obj = mObjects[reducedHandle];
+ MtpStorage* storage = mStorage[obj->mStorageID];
+
+ // walk up the tree to build a full path of the object
+ MtpObjectHandle currentHandle = reducedHandle;
+ std::string path = "";
+
+ while (currentHandle != MTP_PARENT_ROOT) {
+ MtpObjectInfo* next = mObjects[currentHandle];
+
+ // prepend the name
+ if (path == "")
+ path = std::string(next->mName);
+ else
+ path = std::string(next->mName) + "/" + path;
+
+ currentHandle = next->mParent;
+ }
+
+ outFilePath.set(storage->getPath());
+ outFilePath.append("/");
+ outFilePath.append(path.c_str());
+
+ outFormat = obj->mFormat;
+
+ ALOGD("MockDatabase %s: get file %s\n", __func__, (const char*)outFilePath);
+
+ struct stat sstat;
+ // this should not happen unless our database view of the filesystem is out of
+ // sync
+ if (stat((const char*)outFilePath, &sstat) < 0) {
+ ALOGE("MockDatabase %s: unable to stat %s\n", __func__, (const char*)outFilePath);
+
+ return MTP_RESPONSE_INVALID_OBJECT_HANDLE;
+ }
+
+ outFileLength = sstat.st_size;
+
+ return MTP_RESPONSE_OK;
+}
+
+MtpResponseCode MtpMockDatabase::beginDeleteObject(MtpObjectHandle handle) {
+ ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
+ return MTP_RESPONSE_OK;
+}
+void MtpMockDatabase::endDeleteObject(MtpObjectHandle handle, bool succeeded) {
+ ALOGD("MockDatabase %s: ohandle=%u succeeded=%d\n", __func__, handle, succeeded);
+ return;
+}
+
+MtpObjectHandleList* MtpMockDatabase::getObjectReferences(MtpObjectHandle handle) {
+ ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
+ return nullptr;
+}
+
+MtpResponseCode MtpMockDatabase::setObjectReferences(MtpObjectHandle handle,
+ MtpObjectHandleList* references) {
+ ALOGD("MockDatabase %s: ohandle=%u\n", __func__, handle);
+ return MTP_RESPONSE_OK;
+}
+
+MtpProperty* MtpMockDatabase::getObjectPropertyDesc(MtpObjectProperty property,
+ MtpObjectFormat format) {
+ ALOGD("MockDatabase %s: property=%s format=%s\n", __func__,
+ MtpDebug::getObjectPropCodeName(property), MtpDebug::getFormatCodeName(format));
+
+ return nullptr;
+}
+
+MtpProperty* MtpMockDatabase::getDevicePropertyDesc(MtpDeviceProperty property) {
+ ALOGD("MockDatabase %s: property=%s\n", __func__, MtpDebug::getDevicePropCodeName(property));
+ return nullptr;
+}
+
+MtpResponseCode MtpMockDatabase::beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+ MtpStorageID newStorage) {
+ ALOGD("MockDatabase %s: ohandle=%u newParent=%u newStorage=%u\n", __func__, handle, newParent,
+ newStorage);
+ return MTP_RESPONSE_OK;
+}
+
+void MtpMockDatabase::endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
+ MtpStorageID oldStorage, MtpStorageID newStorage,
+ MtpObjectHandle handle, bool succeeded) {
+ ALOGD("MockDatabase %s: oldParent=%u newParent=%u oldStorage=%u newStorage=%u "
+ "ohandle=%u succeeded=%d\n",
+ __func__, oldParent, newParent, oldStorage, newStorage, handle, succeeded);
+ return;
+}
+
+MtpResponseCode MtpMockDatabase::beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+ MtpStorageID newStorage) {
+ ALOGD("MockDatabase %s: ohandle=%u newParent=%u newStorage=%u\n", __func__, handle, newParent,
+ newStorage);
+ return MTP_RESPONSE_OK;
+}
+
+void MtpMockDatabase::endCopyObject(MtpObjectHandle handle, bool succeeded) {
+ ALOGD("MockDatabase %s: ohandle=%u succeeded=%d\n", __func__, handle, succeeded);
+}
+
+}; // namespace android
diff --git a/media/mtp/tests/MtpFuzzer/MtpMockDatabase.h b/media/mtp/tests/MtpFuzzer/MtpMockDatabase.h
new file mode 100644
index 0000000..876719e
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/MtpMockDatabase.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 2020 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_MOCK_DATABASE_H
+#define _MTP_MOCK_DATABASE_H
+
+#include <map>
+
+#include "IMtpDatabase.h"
+#include "MtpStorage.h"
+
+namespace android {
+
+class MtpMockDatabase : public IMtpDatabase {
+ std::map<MtpStorageID, MtpStorage*> mStorage;
+ std::vector<MtpObjectInfo*> mObjects;
+ uint32_t mLastObjectHandle;
+
+public:
+ MtpMockDatabase();
+ virtual ~MtpMockDatabase();
+
+ // MtpFuzzer methods
+ void addStorage(MtpStorage* storage) {
+ // we don't own this
+ mStorage[storage->getStorageID()] = storage;
+ }
+
+ bool hasStorage(MtpStorageID storage) { return mStorage.find(storage) != mStorage.end(); }
+
+ void addObject(MtpObjectInfo* info);
+ MtpObjectHandle allocateObjectHandle();
+
+ // libmtp interface methods
+ // Called from SendObjectInfo to reserve a database entry for the incoming
+ // file.
+ MtpObjectHandle beginSendObject(const char* path, MtpObjectFormat format,
+ MtpObjectHandle parent, MtpStorageID storage);
+
+ // Called to report success or failure of the SendObject file transfer.
+ void endSendObject(MtpObjectHandle handle, bool succeeded);
+
+ // Called to rescan a file, such as after an edit.
+ void rescanFile(const char* path, MtpObjectHandle handle, MtpObjectFormat format);
+
+ MtpObjectHandleList* getObjectList(MtpStorageID storageID, MtpObjectFormat format,
+ MtpObjectHandle parent);
+
+ int getNumObjects(MtpStorageID storageID, MtpObjectFormat format, MtpObjectHandle parent);
+
+ // callee should delete[] the results from these
+ // results can be NULL
+ MtpObjectFormatList* getSupportedPlaybackFormats();
+ MtpObjectFormatList* getSupportedCaptureFormats();
+ MtpObjectPropertyList* getSupportedObjectProperties(MtpObjectFormat format);
+ MtpDevicePropertyList* getSupportedDeviceProperties();
+
+ MtpResponseCode getObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property,
+ MtpDataPacket& packet);
+
+ MtpResponseCode setObjectPropertyValue(MtpObjectHandle handle, MtpObjectProperty property,
+ MtpDataPacket& packet);
+
+ MtpResponseCode getDevicePropertyValue(MtpDeviceProperty property, MtpDataPacket& packet);
+
+ MtpResponseCode setDevicePropertyValue(MtpDeviceProperty property, MtpDataPacket& packet);
+
+ MtpResponseCode resetDeviceProperty(MtpDeviceProperty property);
+
+ MtpResponseCode getObjectPropertyList(MtpObjectHandle handle, uint32_t format,
+ uint32_t property, int groupCode, int depth,
+ MtpDataPacket& packet);
+
+ MtpResponseCode getObjectInfo(MtpObjectHandle handle, MtpObjectInfo& info);
+
+ void* getThumbnail(MtpObjectHandle handle, size_t& outThumbSize);
+
+ MtpResponseCode getObjectFilePath(MtpObjectHandle handle, MtpStringBuffer& outFilePath,
+ int64_t& outFileLength, MtpObjectFormat& outFormat);
+
+ MtpResponseCode beginDeleteObject(MtpObjectHandle handle);
+ void endDeleteObject(MtpObjectHandle handle, bool succeeded);
+
+ MtpObjectHandleList* getObjectReferences(MtpObjectHandle handle);
+
+ MtpResponseCode setObjectReferences(MtpObjectHandle handle, MtpObjectHandleList* references);
+
+ MtpProperty* getObjectPropertyDesc(MtpObjectProperty property, MtpObjectFormat format);
+
+ MtpProperty* getDevicePropertyDesc(MtpDeviceProperty property);
+
+ MtpResponseCode beginMoveObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+ MtpStorageID newStorage);
+
+ void endMoveObject(MtpObjectHandle oldParent, MtpObjectHandle newParent,
+ MtpStorageID oldStorage, MtpStorageID newStorage, MtpObjectHandle handle,
+ bool succeeded);
+
+ MtpResponseCode beginCopyObject(MtpObjectHandle handle, MtpObjectHandle newParent,
+ MtpStorageID newStorage);
+ void endCopyObject(MtpObjectHandle handle, bool succeeded);
+};
+
+}; // namespace android
+
+#endif // _MTP_MOCK_DATABASE_H
diff --git a/media/mtp/tests/MtpFuzzer/MtpMockHandle.h b/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
new file mode 100644
index 0000000..111485c
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/MtpMockHandle.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2020 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_MOCK_HANDLE_H
+#define _MTP_MOCK_HANDLE_H
+
+#include <vector>
+
+typedef std::vector<uint8_t> packet_t;
+
+namespace android {
+class MtpMockHandle : public IMtpHandle {
+private:
+ size_t mPacketNumber;
+ size_t mPacketOffset;
+ std::vector<packet_t> mPackets;
+
+public:
+ MtpMockHandle() : mPacketNumber(0), mPacketOffset(0) {}
+
+ void add_packet(packet_t pkt) { mPackets.push_back(pkt); }
+
+ // Return number of bytes read/written, or -1 and errno is set
+ int read(void *data, size_t len) {
+ if (mPacketNumber >= mPackets.size()) {
+ return 0;
+ } else {
+ int readAmt = 0;
+ packet_t pkt = mPackets[mPacketNumber];
+
+ ALOGD("%s: sz %zu, pkt %zu+%zu/%zu\n", __func__, len, mPacketNumber, mPacketOffset,
+ pkt.size());
+
+ // packet is bigger than what the caller can handle,
+ if (pkt.size() > len) {
+ memcpy(data, pkt.data() + mPacketOffset, len);
+
+ mPacketOffset += len;
+ readAmt = len;
+ // packet is equal or smaller than the caller buffer
+ } else {
+ memcpy(data, pkt.data() + mPacketOffset, pkt.size());
+
+ mPacketNumber++;
+ mPacketOffset = 0;
+ readAmt = pkt.size();
+ }
+
+ return readAmt;
+ }
+ }
+ int write(const void *data, size_t len) {
+ ALOGD("MockHandle %s: len=%zu\n", __func__, len);
+ // fake the write
+ return len;
+ }
+
+ // Return 0 if send/receive is successful, or -1 and errno is set
+ int receiveFile(mtp_file_range mfr, bool zero_packet) {
+ ALOGD("MockHandle %s\n", __func__);
+ return 0;
+ }
+ int sendFile(mtp_file_range mfr) {
+ ALOGD("MockHandle %s\n", __func__);
+ return 0;
+ }
+ int sendEvent(mtp_event me) {
+ ALOGD("MockHandle %s: len=%zu\n", __func__, me.length);
+ return 0;
+ }
+
+ // Return 0 if operation is successful, or -1 else
+ int start(bool ptp) { return 0; }
+
+ void close() {}
+
+ virtual ~MtpMockHandle() {}
+};
+}; // namespace android
+
+#endif // _MTP_MOCK_HANDLE_H
diff --git a/media/mtp/tests/MtpFuzzer/corpus/1-mtp-open_session.pkt b/media/mtp/tests/MtpFuzzer/corpus/1-mtp-open_session.pkt
new file mode 100644
index 0000000..38f8ed2
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/corpus/1-mtp-open_session.pkt
Binary files differ
diff --git a/media/mtp/tests/MtpFuzzer/corpus/2-mtp-get_device_info.pkt b/media/mtp/tests/MtpFuzzer/corpus/2-mtp-get_device_info.pkt
new file mode 100644
index 0000000..7759380
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/corpus/2-mtp-get_device_info.pkt
Binary files differ
diff --git a/media/mtp/tests/MtpFuzzer/corpus/3-mtp-get_object_handles.pkt b/media/mtp/tests/MtpFuzzer/corpus/3-mtp-get_object_handles.pkt
new file mode 100644
index 0000000..e88410f
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/corpus/3-mtp-get_object_handles.pkt
Binary files differ
diff --git a/media/mtp/tests/MtpFuzzer/corpus/4-mtp-get_object_info.pkt b/media/mtp/tests/MtpFuzzer/corpus/4-mtp-get_object_info.pkt
new file mode 100644
index 0000000..e283fb4
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/corpus/4-mtp-get_object_info.pkt
Binary files differ
diff --git a/media/mtp/tests/MtpFuzzer/corpus/5-mtp-send_object_info.pkt b/media/mtp/tests/MtpFuzzer/corpus/5-mtp-send_object_info.pkt
new file mode 100644
index 0000000..7627f88
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/corpus/5-mtp-send_object_info.pkt
Binary files differ
diff --git a/media/mtp/tests/MtpFuzzer/mtp_fuzzer.cpp b/media/mtp/tests/MtpFuzzer/mtp_fuzzer.cpp
new file mode 100644
index 0000000..f578462
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/mtp_fuzzer.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2020 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 <android-base/unique_fd.h>
+#include <stddef.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include <string>
+
+#define LOG_TAG "MtpFuzzer"
+
+#include "IMtpHandle.h"
+#include "MtpMockDatabase.h"
+#include "MtpMockHandle.h"
+#include "MtpObjectInfo.h"
+#include "MtpServer.h"
+#include "MtpStorage.h"
+#include "MtpUtils.h"
+
+const char* storage_desc = "Fuzz Storage";
+// prefer tmpfs for file operations to avoid wearing out flash
+const char* storage_path = "/storage/fuzzer/0";
+const char* source_database = "srcdb/";
+
+namespace android {
+class MtpMockServer {
+public:
+ std::unique_ptr<MtpMockHandle> mHandle;
+ std::unique_ptr<MtpStorage> mStorage;
+ std::unique_ptr<MtpMockDatabase> mDatabase;
+ std::unique_ptr<MtpServer> mMtp;
+ int mStorageId;
+
+ MtpMockServer(const char* storage_path) : mStorageId(0) {
+ bool ptp = false;
+ const char* manu = "Google";
+ const char* model = "Pixel 3XL";
+ const char* version = "1.0";
+ const char* serial = "ABDEF1231";
+
+ // This is unused in our harness
+ int controlFd = -1;
+
+ mHandle = std::make_unique<MtpMockHandle>();
+ mStorage = std::make_unique<MtpStorage>(mStorageId, storage_path, storage_desc, true,
+ 0x200000000L);
+ mDatabase = std::make_unique<MtpMockDatabase>();
+ mDatabase->addStorage(mStorage.get());
+
+ mMtp = std::make_unique<MtpServer>(mDatabase.get(), controlFd, ptp, manu, model, version,
+ serial);
+ mMtp->addStorage(mStorage.get());
+
+ // clear the old handle first, so we don't leak memory
+ delete mMtp->mHandle;
+ mMtp->mHandle = mHandle.get();
+ }
+
+ void run() { mMtp->run(); }
+
+ int createDatabaseFromSourceDir(const char* fromPath, const char* toPath,
+ MtpObjectHandle parentHandle) {
+ int ret = 0;
+ std::string fromPathStr(fromPath);
+ std::string toPathStr(toPath);
+
+ DIR* dir = opendir(fromPath);
+ if (!dir) {
+ ALOGE("opendir %s failed", fromPath);
+ return -1;
+ }
+ if (fromPathStr[fromPathStr.size() - 1] != '/') fromPathStr += '/';
+ if (toPathStr[toPathStr.size() - 1] != '/') toPathStr += '/';
+
+ struct dirent* entry;
+ while ((entry = readdir(dir))) {
+ const char* name = entry->d_name;
+
+ // ignore "." and ".."
+ if (name[0] == '.' && (name[1] == 0 || (name[1] == '.' && name[2] == 0))) {
+ continue;
+ }
+
+ std::string oldFile = fromPathStr + name;
+ std::string newFile = toPathStr + name;
+
+ if (entry->d_type == DT_DIR) {
+ ret += makeFolder(newFile.c_str());
+
+ MtpObjectInfo* objectInfo = new MtpObjectInfo(mDatabase->allocateObjectHandle());
+ objectInfo->mStorageID = mStorage->getStorageID();
+ objectInfo->mParent = parentHandle;
+ objectInfo->mFormat = MTP_FORMAT_ASSOCIATION; // folder
+ objectInfo->mName = strdup(name);
+ objectInfo->mKeywords = strdup("");
+
+ mDatabase->addObject(objectInfo);
+
+ ret += createDatabaseFromSourceDir(oldFile.c_str(), newFile.c_str(),
+ objectInfo->mHandle);
+ } else {
+ ret += copyFile(oldFile.c_str(), newFile.c_str());
+
+ MtpObjectInfo* objectInfo = new MtpObjectInfo(mDatabase->allocateObjectHandle());
+ objectInfo->mStorageID = mStorage->getStorageID();
+ objectInfo->mParent = parentHandle;
+ objectInfo->mFormat = MTP_FORMAT_TEXT;
+ objectInfo->mName = strdup(name);
+ objectInfo->mKeywords = strdup("");
+
+ mDatabase->addObject(objectInfo);
+ }
+ }
+
+ closedir(dir);
+ return ret;
+ }
+};
+}; // namespace android
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) __attribute__((optnone)) {
+ // reset our storage (from MtpUtils.h)
+ android::deletePath(storage_path);
+ android::makeFolder("/storage/fuzzer");
+ android::makeFolder(storage_path);
+
+ std::unique_ptr<android::MtpMockServer> mtp =
+ std::make_unique<android::MtpMockServer>(storage_path);
+
+ size_t off = 0;
+
+ // Packetize the input stream
+ for (size_t i = 0; i < size; i++) {
+ // A longer delimiter could be used, but this worked in practice
+ if (data[i] == '@') {
+ size_t pktsz = i - off;
+ if (pktsz > 0) {
+ packet_t pkt = packet_t((unsigned char*)data + off, (unsigned char*)data + i);
+ // insert into packet buffer
+ mtp->mHandle->add_packet(pkt);
+ off = i;
+ }
+ }
+ }
+
+ mtp->createDatabaseFromSourceDir(source_database, storage_path, MTP_PARENT_ROOT);
+ mtp->run();
+
+ return 0;
+}
diff --git a/media/mtp/tests/MtpFuzzer/mtp_fuzzer.dict b/media/mtp/tests/MtpFuzzer/mtp_fuzzer.dict
new file mode 100644
index 0000000..4c3f136
--- /dev/null
+++ b/media/mtp/tests/MtpFuzzer/mtp_fuzzer.dict
@@ -0,0 +1,74 @@
+mtp_operation_get_device_info="\x01\x10"
+mtp_operation_open_session="\x02\x10"
+mtp_operation_close_session="\x03\x10"
+mtp_operation_get_storage_ids="\x04\x10"
+mtp_operation_get_storage_info="\x05\x10"
+mtp_operation_get_num_objects="\x06\x10"
+mtp_operation_get_object_handles="\x07\x10"
+mtp_operation_get_object_info="\x08\x10"
+mtp_operation_get_object="\x09\x10"
+mtp_operation_get_thumb="\x0A\x10"
+mtp_operation_delete_object="\x0B\x10"
+mtp_operation_send_object_info="\x0C\x10"
+mtp_operation_send_object="\x0D\x10"
+mtp_operation_initiate_capture="\x0E\x10"
+mtp_operation_format_store="\x0F\x10"
+mtp_operation_reset_device="\x10\x10"
+mtp_operation_self_test="\x11\x10"
+mtp_operation_set_object_protection="\x12\x10"
+mtp_operation_power_down="\x13\x10"
+mtp_operation_get_device_prop_desc="\x14\x10"
+mtp_operation_get_device_prop_value="\x15\x10"
+mtp_operation_set_device_prop_value="\x16\x10"
+mtp_operation_reset_device_prop_value="\x17\x10"
+mtp_operation_terminate_open_capture="\x18\x10"
+mtp_operation_move_object="\x19\x10"
+mtp_operation_copy_object="\x1A\x10"
+mtp_operation_get_partial_object="\x1B\x10"
+mtp_operation_initiate_open_capture="\x1C\x10"
+mtp_operation_get_object_props_supported="\x01\x98"
+mtp_operation_get_object_prop_desc="\x02\x98"
+mtp_operation_get_object_prop_value="\x03\x98"
+mtp_operation_set_object_prop_value="\x04\x98"
+mtp_operation_get_object_prop_list="\x05\x98"
+mtp_operation_set_object_prop_list="\x06\x98"
+mtp_operation_get_interdependent_prop_desc="\x07\x98"
+mtp_operation_send_object_prop_list="\x08\x98"
+mtp_operation_get_object_references="\x10\x98"
+mtp_operation_set_object_references="\x11\x98"
+mtp_operation_skip="\x20\x98"
+mtp_operation_get_partial_object_64="\xC1\x95"
+mtp_operation_send_partial_object="\xC2\x95"
+mtp_operation_truncate_object="\xC3\x95"
+mtp_operation_begin_edit_object="\xC4\x95"
+mtp_operation_end_edit_object="\xC5\x95"
+
+# Association (for example, a folder)
+mtp_format_association="\x01\x30"
+
+# types
+mtp_type_undefined="\x00\x00"
+mtp_type_int8="\x01\x00"
+mtp_type_uint8="\x02\x00"
+mtp_type_int16="\x03\x00"
+mtp_type_uint16="\x04\x00"
+mtp_type_int32="\x05\x00"
+mtp_type_uint32="\x06\x00"
+mtp_type_int64="\x07\x00"
+mtp_type_uint64="\x08\x00"
+mtp_type_int128="\x09\x00"
+mtp_type_uint128="\x0A\x00"
+mtp_type_aint8="\x01\x40"
+mtp_type_auint8="\x02\x40"
+mtp_type_aint16="\x03\x40"
+mtp_type_auint16="\x04\x40"
+mtp_type_aint32="\x05\x40"
+mtp_type_auint32="\x06\x40"
+mtp_type_aint64="\x07\x40"
+mtp_type_auint64="\x08\x40"
+mtp_type_aint128="\x09\x40"
+mtp_type_auint128="\x0A\x40"
+mtp_type_str="\xFF\xFF"
+
+# also used for max size (>4GB)
+mtp_parent_root="\xFF\xFF\xFF\xFF"
diff --git a/media/mtp/tests/Android.bp b/media/mtp/tests/PosixAsyncIOTest/Android.bp
similarity index 71%
rename from media/mtp/tests/Android.bp
rename to media/mtp/tests/PosixAsyncIOTest/Android.bp
index 0750208..1d401b8 100644
--- a/media/mtp/tests/Android.bp
+++ b/media/mtp/tests/PosixAsyncIOTest/Android.bp
@@ -1,5 +1,5 @@
//
-// Copyright (C) 2017 The Android Open Source Project
+// Copyright (C) 2020 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.
@@ -15,22 +15,6 @@
//
cc_test {
- name: "mtp_ffs_handle_test",
- test_suites: ["device-tests"],
- srcs: ["MtpFfsHandle_test.cpp"],
- shared_libs: [
- "libbase",
- "libmtp",
- "liblog",
- ],
- cflags: [
- "-Wall",
- "-Wextra",
- "-Werror",
- ],
-}
-
-cc_test {
name: "posix_async_io_test",
test_suites: ["device-tests"],
srcs: ["PosixAsyncIO_test.cpp"],
diff --git a/media/mtp/tests/AndroidTest.xml b/media/mtp/tests/PosixAsyncIOTest/AndroidTest.xml
similarity index 77%
copy from media/mtp/tests/AndroidTest.xml
copy to media/mtp/tests/PosixAsyncIOTest/AndroidTest.xml
index c1f4753..cbb10fb 100644
--- a/media/mtp/tests/AndroidTest.xml
+++ b/media/mtp/tests/PosixAsyncIOTest/AndroidTest.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2017 The Android Open Source Project
+<!-- Copyright (C) 2020 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.
@@ -13,14 +13,14 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
-<configuration description="Config for mtp_ffs_handle_test">
+<configuration description="Config for posix_async_io_test">
<target_preparer class="com.android.tradefed.targetprep.PushFilePreparer">
<option name="cleanup" value="true" />
- <option name="push" value="mtp_ffs_handle_test->/data/local/tmp/mtp_ffs_handle_test" />
+ <option name="push" value="posix_async_io_test->/data/local/tmp/posix_async_io_test" />
</target_preparer>
<option name="test-suite-tag" value="apct" />
<test class="com.android.tradefed.testtype.GTest" >
<option name="native-test-device-path" value="/data/local/tmp" />
- <option name="module-name" value="mtp_ffs_handle_test" />
+ <option name="module-name" value="posix_async_io_test" />
</test>
</configuration>
\ No newline at end of file
diff --git a/media/mtp/tests/PosixAsyncIO_test.cpp b/media/mtp/tests/PosixAsyncIOTest/PosixAsyncIO_test.cpp
similarity index 100%
rename from media/mtp/tests/PosixAsyncIO_test.cpp
rename to media/mtp/tests/PosixAsyncIOTest/PosixAsyncIO_test.cpp
diff --git a/media/ndk/NdkMediaFormat.cpp b/media/ndk/NdkMediaFormat.cpp
index 73c52a9..47214c5 100644
--- a/media/ndk/NdkMediaFormat.cpp
+++ b/media/ndk/NdkMediaFormat.cpp
@@ -371,6 +371,7 @@
EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID = "temporal-layer-id";
EXPORT const char* AMEDIAFORMAT_KEY_TEMPORAL_LAYERING = "ts-schema";
EXPORT const char* AMEDIAFORMAT_KEY_TEXT_FORMAT_DATA = "text-format-data";
+EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_CSD_AV1C = "thumbnail-csd-av1c";
EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC = "thumbnail-csd-hevc";
EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT = "thumbnail-height";
EXPORT const char* AMEDIAFORMAT_KEY_THUMBNAIL_TIME = "thumbnail-time";
diff --git a/media/ndk/include/media/NdkMediaFormat.h b/media/ndk/include/media/NdkMediaFormat.h
index 394b972..8f39929 100644
--- a/media/ndk/include/media/NdkMediaFormat.h
+++ b/media/ndk/include/media/NdkMediaFormat.h
@@ -324,6 +324,7 @@
#if __ANDROID_API__ >= 31
extern const char* AMEDIAFORMAT_KEY_SLOW_MOTION_MARKERS __INTRODUCED_IN(31);
+extern const char* AMEDIAFORMAT_KEY_THUMBNAIL_CSD_AV1C __INTRODUCED_IN(31);
#endif /* __ANDROID_API__ >= 31 */
__END_DECLS
diff --git a/media/ndk/libmediandk.map.txt b/media/ndk/libmediandk.map.txt
index bd3337e..44c3e52 100644
--- a/media/ndk/libmediandk.map.txt
+++ b/media/ndk/libmediandk.map.txt
@@ -138,6 +138,7 @@
AMEDIAFORMAT_KEY_TEMPORAL_LAYER_ID; # var introduced=28
AMEDIAFORMAT_KEY_TEMPORAL_LAYERING; # var introduced=28
AMEDIAFORMAT_KEY_TEXT_FORMAT_DATA; # var introduced=29
+ AMEDIAFORMAT_KEY_THUMBNAIL_CSD_AV1C; # var introduced=31
AMEDIAFORMAT_KEY_THUMBNAIL_CSD_HEVC; # var introduced=29
AMEDIAFORMAT_KEY_THUMBNAIL_HEIGHT; # var introduced=29
AMEDIAFORMAT_KEY_THUMBNAIL_TIME; # var introduced=29
diff --git a/services/audioflinger/Android.bp b/services/audioflinger/Android.bp
index 261af5a..7443320 100644
--- a/services/audioflinger/Android.bp
+++ b/services/audioflinger/Android.bp
@@ -37,6 +37,7 @@
shared_libs: [
"audioflinger-aidl-unstable-cpp",
"audioclient-types-aidl-unstable-cpp",
+ "av-types-aidl-unstable-cpp",
"libaudioclient_aidl_conversion",
"libaudiofoundation",
"libaudiohal",
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index e589eb9..959e858 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -22,12 +22,14 @@
// Define AUDIO_ARRAYS_STATIC_CHECK to check all audio arrays are correct
#define AUDIO_ARRAYS_STATIC_CHECK 1
-#define VALUE_OR_FATAL(result) \
- ({ auto _tmp = (result); \
- LOG_ALWAYS_FATAL_IF(!_tmp.ok(), \
+#define VALUE_OR_FATAL(result) \
+ ({ \
+ auto _tmp = (result); \
+ LOG_ALWAYS_FATAL_IF(!_tmp.ok(), \
"Failed result (%d)", \
- _tmp.error()); \
- _tmp.value(); })
+ _tmp.error()); \
+ std::move(_tmp.value()); \
+ })
#include "Configuration.h"
#include <dirent.h>
@@ -755,10 +757,27 @@
// IAudioFlinger interface
-sp<IAudioTrack> AudioFlinger::createTrack(const CreateTrackInput& input,
- CreateTrackOutput& output,
- status_t *status)
+sp<IAudioTrack> AudioFlinger::createTrack(const media::CreateTrackRequest& _input,
+ media::CreateTrackResponse& _output,
+ status_t* status)
{
+ // Local version of VALUE_OR_RETURN, specific to this method's calling conventions.
+#define VALUE_OR_EXIT(expr) \
+ ({ \
+ auto _tmp = (expr); \
+ if (!_tmp.ok()) { \
+ *status = _tmp.error(); \
+ return nullptr; \
+ } \
+ std::move(_tmp.value()); \
+ })
+
+ CreateTrackInput input = VALUE_OR_EXIT(CreateTrackInput::fromAidl(_input));
+
+#undef VALUE_OR_EXIT
+
+ CreateTrackOutput output;
+
sp<PlaybackThread::Track> track;
sp<TrackHandle> trackHandle;
sp<Client> client;
@@ -1015,6 +1034,8 @@
AudioSystem::moveEffectsToIo(effectIds, effectThreadId);
}
+ _output = VALUE_OR_FATAL(output.toAidl());
+
// return handle to client
trackHandle = new TrackHandle(track);
@@ -1447,7 +1468,7 @@
}
-void AudioFlinger::broacastParametersToRecordThreads_l(const String8& keyValuePairs)
+void AudioFlinger::broadcastParametersToRecordThreads_l(const String8& keyValuePairs)
{
for (size_t i = 0; i < mRecordThreads.size(); i++) {
mRecordThreads.valueAt(i)->setParameters(keyValuePairs);
@@ -1605,7 +1626,7 @@
int value;
if ((param.getInt(String8(AudioParameter::keyRouting), value) == NO_ERROR) &&
(value != 0)) {
- broacastParametersToRecordThreads_l(filteredKeyValuePairs);
+ broadcastParametersToRecordThreads_l(filteredKeyValuePairs);
}
}
}
@@ -1997,10 +2018,26 @@
// ----------------------------------------------------------------------------
-sp<media::IAudioRecord> AudioFlinger::createRecord(const CreateRecordInput& input,
- CreateRecordOutput& output,
- status_t *status)
+sp<media::IAudioRecord> AudioFlinger::createRecord(const media::CreateRecordRequest& _input,
+ media::CreateRecordResponse& _output,
+ status_t* status)
{
+ // Local version of VALUE_OR_RETURN, specific to this method's calling conventions.
+#define VALUE_OR_EXIT(expr) \
+ ({ \
+ auto _tmp = (expr); \
+ if (!_tmp.ok()) { \
+ *status = _tmp.error(); \
+ return nullptr; \
+ } \
+ std::move(_tmp.value()); \
+ })
+
+ CreateRecordInput input = VALUE_OR_EXIT(CreateRecordInput::fromAidl(_input));
+
+#undef VALUE_OR_EXIT
+ CreateRecordOutput output;
+
sp<RecordThread::RecordTrack> recordTrack;
sp<RecordHandle> recordHandle;
sp<Client> client;
@@ -2138,6 +2175,8 @@
output.buffers = recordTrack->getBuffers();
output.portId = portId;
+ _output = VALUE_OR_FATAL(output.toAidl());
+
// return handle to client
recordHandle = new RecordHandle(recordTrack);
@@ -3163,7 +3202,8 @@
// dumpToThreadLog_l() must be called with AudioFlinger::mLock held
void AudioFlinger::dumpToThreadLog_l(const sp<ThreadBase> &thread)
{
- audio_utils::FdToString fdToString;
+ constexpr int THREAD_DUMP_TIMEOUT_MS = 2;
+ audio_utils::FdToString fdToString("- ", THREAD_DUMP_TIMEOUT_MS);
const int fd = fdToString.fd();
if (fd >= 0) {
thread->dump(fd, {} /* args */);
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 65d672a..cfe9264 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -135,13 +135,13 @@
virtual status_t dump(int fd, const Vector<String16>& args);
// IAudioFlinger interface, in binder opcode order
- virtual sp<IAudioTrack> createTrack(const CreateTrackInput& input,
- CreateTrackOutput& output,
- status_t *status);
+ virtual sp<IAudioTrack> createTrack(const media::CreateTrackRequest& input,
+ media::CreateTrackResponse& output,
+ status_t* status) override;
- virtual sp<media::IAudioRecord> createRecord(const CreateRecordInput& input,
- CreateRecordOutput& output,
- status_t *status);
+ virtual sp<media::IAudioRecord> createRecord(const media::CreateRecordRequest& input,
+ media::CreateRecordResponse& output,
+ status_t* status) override;
virtual uint32_t sampleRate(audio_io_handle_t ioHandle) const;
virtual audio_format_t format(audio_io_handle_t output) const;
@@ -787,7 +787,7 @@
std::vector< sp<EffectModule> > purgeStaleEffects_l();
- void broacastParametersToRecordThreads_l(const String8& keyValuePairs);
+ void broadcastParametersToRecordThreads_l(const String8& keyValuePairs);
void updateOutDevicesForRecordThreads_l(const DeviceDescriptorBaseVector& devices);
void forwardParametersToDownstreamPatches_l(
audio_io_handle_t upStream, const String8& keyValuePairs,
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index c1c3c44..b13b7be 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -7477,7 +7477,7 @@
(framesRead - part1) * mFrameSize);
}
}
- rear = mRsmpInRear += framesRead;
+ mRsmpInRear = audio_utils::safe_add_overflow(mRsmpInRear, (int32_t)framesRead);
size = activeTracks.size();
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index c51d6a9..ca29591 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -65,6 +65,9 @@
bool supportsFormat(audio_format_t format);
+ void setDynamic() { mIsDynamic = true; }
+ bool isDynamic() const { return mIsDynamic; }
+
// PolicyAudioPortConfig
virtual sp<PolicyAudioPort> getPolicyAudioPort() const {
return static_cast<PolicyAudioPort*>(const_cast<DeviceDescriptor*>(this));
@@ -97,6 +100,8 @@
std::string mTagName; // Unique human readable identifier for a device port found in conf file.
FormatVector mEncodedFormats;
audio_format_t mCurrentEncodedFormat;
+ bool mIsDynamic = false;
+ const std::string mDeclaredAddress; // Original device address
};
class DeviceVector : public SortedVector<sp<DeviceDescriptor> >
diff --git a/services/audiopolicy/common/managerdefinitions/include/HwModule.h b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
index 23f0c9a..b5b10f3 100644
--- a/services/audiopolicy/common/managerdefinitions/include/HwModule.h
+++ b/services/audiopolicy/common/managerdefinitions/include/HwModule.h
@@ -131,8 +131,17 @@
public:
sp<HwModule> getModuleFromName(const char *name) const;
+ /**
+ * @brief getModuleForDeviceType try to get a device from type / format on all modules
+ * @param device type to consider
+ * @param encodedFormat to consider
+ * @param[out] tagName if not null, if a matching device is found, will return the tagName
+ * of original device from XML file so that audio routes matchin rules work.
+ * @return valid module if considered device found, nullptr otherwise.
+ */
sp<HwModule> getModuleForDeviceType(audio_devices_t device,
- audio_format_t encodedFormat) const;
+ audio_format_t encodedFormat,
+ std::string *tagName = nullptr) const;
sp<HwModule> getModuleForDevice(const sp<DeviceDescriptor> &device,
audio_format_t encodedFormat) const;
diff --git a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
index 5f551d5..11d3a99 100644
--- a/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/IOProfile.h
@@ -112,6 +112,19 @@
}
/**
+ * @brief getTag
+ * @param deviceTypes to be considered
+ * @return tagName of first matching device for the considered types, empty string otherwise.
+ */
+ std::string getTag(const DeviceTypeSet& deviceTypes) const
+ {
+ if (supportsDeviceTypes(deviceTypes)) {
+ return mSupportedDevices.getDevicesFromTypes(deviceTypes).itemAt(0)->getTagName();
+ }
+ return {};
+ }
+
+ /**
* @brief supportsDevice
* @param device to be checked against
* forceCheckOnAddress if true, check on type and address whatever the type, otherwise
@@ -150,6 +163,12 @@
}
void removeSupportedDevice(const sp<DeviceDescriptor> &device)
{
+ ssize_t ret = mSupportedDevices.indexOf(device);
+ if (ret >= 0 && !mSupportedDevices.itemAt(ret)->isDynamic()) {
+ // devices equality checks only type, address, name and format
+ // Prevents from removing non dynamically added devices
+ return;
+ }
mSupportedDevices.remove(device);
}
void setSupportedDevices(const DeviceVector &devices)
diff --git a/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
index d2f6297..e6eef24 100644
--- a/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
+++ b/services/audiopolicy/common/managerdefinitions/include/PolicyAudioPort.h
@@ -42,6 +42,11 @@
virtual const std::string getTagName() const = 0;
+ bool equals(const sp<PolicyAudioPort> &right) const
+ {
+ return getTagName() == right->getTagName();
+ }
+
virtual sp<AudioPort> asAudioPort() const = 0;
virtual void setFlags(uint32_t flags)
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
index 2a18f19..c8e4e76 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioRoute.cpp
@@ -39,12 +39,12 @@
bool AudioRoute::supportsPatch(const sp<PolicyAudioPort> &srcPort,
const sp<PolicyAudioPort> &dstPort) const
{
- if (mSink == 0 || dstPort == 0 || dstPort != mSink) {
+ if (mSink == 0 || dstPort == 0 || !dstPort->equals(mSink)) {
return false;
}
ALOGV("%s: sinks %s matching", __FUNCTION__, mSink->getTagName().c_str());
for (const auto &sourcePort : mSources) {
- if (sourcePort == srcPort) {
+ if (sourcePort->equals(srcPort)) {
ALOGV("%s: sources %s matching", __FUNCTION__, sourcePort->getTagName().c_str());
return true;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index b450e82..6ff1a98 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -52,7 +52,8 @@
DeviceDescriptor::DeviceDescriptor(const AudioDeviceTypeAddr &deviceTypeAddr,
const std::string &tagName,
const FormatVector &encodedFormats) :
- DeviceDescriptorBase(deviceTypeAddr), mTagName(tagName), mEncodedFormats(encodedFormats)
+ DeviceDescriptorBase(deviceTypeAddr), mTagName(tagName), mEncodedFormats(encodedFormats),
+ mDeclaredAddress(deviceTypeAddr.getAddress())
{
mCurrentEncodedFormat = AUDIO_FORMAT_DEFAULT;
/* If framework runs against a pre 5.0 Audio HAL, encoded formats are absent from the config.
@@ -75,6 +76,10 @@
void DeviceDescriptor::detach() {
mId = AUDIO_PORT_HANDLE_NONE;
PolicyAudioPort::detach();
+ // The device address may have been overwritten on device connection
+ setAddress(mDeclaredAddress);
+ // Device Port does not have a name unless provided by setDeviceConnectionState
+ setName("");
}
template<typename T>
diff --git a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
index d31e443..2967014 100644
--- a/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/HwModule.cpp
@@ -271,8 +271,9 @@
return nullptr;
}
-sp <HwModule> HwModuleCollection::getModuleForDeviceType(audio_devices_t type,
- audio_format_t encodedFormat) const
+sp<HwModule> HwModuleCollection::getModuleForDeviceType(audio_devices_t type,
+ audio_format_t encodedFormat,
+ std::string *tagName) const
{
for (const auto& module : *this) {
const auto& profiles = audio_is_output_device(type) ?
@@ -284,9 +285,15 @@
sp <DeviceDescriptor> deviceDesc =
declaredDevices.getDevice(type, String8(), encodedFormat);
if (deviceDesc) {
+ if (tagName != nullptr) {
+ *tagName = deviceDesc->getTagName();
+ }
return module;
}
} else {
+ if (tagName != nullptr) {
+ *tagName = profile->getTag({type});
+ }
return module;
}
}
@@ -325,15 +332,32 @@
}
for (const auto& hwModule : *this) {
+ if (!allowToCreate) {
+ auto dynamicDevices = hwModule->getDynamicDevices();
+ auto dynamicDevice = dynamicDevices.getDevice(deviceType, devAddress, encodedFormat);
+ if (dynamicDevice) {
+ return dynamicDevice;
+ }
+ }
DeviceVector moduleDevices = hwModule->getAllDevices();
auto moduleDevice = moduleDevices.getDevice(deviceType, devAddress, encodedFormat);
+
+ // Prevent overwritting moduleDevice address if connected device does not have the same
+ // address (since getDevice with empty address ignores match on address), use dynamic device
+ if (moduleDevice && allowToCreate &&
+ (!moduleDevice->address().empty() &&
+ (moduleDevice->address().compare(devAddress.c_str()) != 0))) {
+ break;
+ }
if (moduleDevice) {
if (encodedFormat != AUDIO_FORMAT_DEFAULT) {
moduleDevice->setEncodedFormat(encodedFormat);
}
if (allowToCreate) {
moduleDevice->attach(hwModule);
+ // Name may be overwritten, restored on detach.
moduleDevice->setAddress(devAddress.string());
+ // Name may be overwritten, restored on detach.
moduleDevice->setName(name);
}
return moduleDevice;
@@ -352,18 +376,19 @@
const char *name,
const audio_format_t encodedFormat) const
{
- sp<HwModule> hwModule = getModuleForDeviceType(type, encodedFormat);
+ std::string tagName = {};
+ sp<HwModule> hwModule = getModuleForDeviceType(type, encodedFormat, &tagName);
if (hwModule == 0) {
ALOGE("%s: could not find HW module for device %04x address %s", __FUNCTION__, type,
address);
return nullptr;
}
- sp<DeviceDescriptor> device = new DeviceDescriptor(type, name, address);
+ sp<DeviceDescriptor> device = new DeviceDescriptor(type, tagName, address);
device->setName(name);
device->setEncodedFormat(encodedFormat);
-
- // Add the device to the list of dynamic devices
+ device->setDynamic();
+ // Add the device to the list of dynamic devices
hwModule->addDynamicDevice(device);
// Reciprocally attach the device to the module
device->attach(hwModule);
@@ -375,7 +400,7 @@
for (const auto &profile : profiles) {
// Add the device as supported to all profile supporting "weakly" or not the device
// according to its type
- if (profile->supportsDevice(device, false /*matchAdress*/)) {
+ if (profile->supportsDevice(device, false /*matchAddress*/)) {
// @todo quid of audio profile? import the profile from device of the same type?
const auto &isoTypeDeviceForProfile =
@@ -406,10 +431,9 @@
device->detach();
// Only remove from dynamic list, not from declared list!!!
- if (!hwModule->getDynamicDevices().contains(device)) {
+ if (!hwModule->removeDynamicDevice(device)) {
return;
}
- hwModule->removeDynamicDevice(device);
ALOGV("%s: removed dynamic device %s from module %s", __FUNCTION__,
device->toString().c_str(), hwModule->getName());
diff --git a/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py b/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py
index f060d45..5083b14 100755
--- a/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py
+++ b/services/audiopolicy/engineconfigurable/tools/buildCommonTypesStructureFile.py
@@ -126,9 +126,9 @@
ignored_values = ['CNT', 'MAX', 'ALL', 'NONE']
criteria_pattern = re.compile(
- r"\s*(?P<type>(?:"+'|'.join(component_type_mapping_table.keys()) + "))_" \
- r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*=\s*" \
- r"(?P<values>(?:0[xX])?[0-9a-fA-F]+)")
+ r"\s*V\((?P<type>(?:"+'|'.join(component_type_mapping_table.keys()) + "))_" \
+ r"(?P<literal>(?!" + '|'.join(ignored_values) + ")\w*)\s*,\s*" \
+ r"(?:AUDIO_DEVICE_BIT_IN \| )?(?P<values>(?:0[xX])[0-9a-fA-F]+|[0-9]+)")
logging.info("Checking Android Header file {}".format(androidaudiobaseheaderFile))
@@ -164,6 +164,13 @@
logging.debug("type:{}, literal:{}, values:{}.".format(component_type_name, component_type_literal, component_type_numerical_value))
+ if "stub" not in all_component_types["OutputDevicesMask"]:
+ all_component_types["OutputDevicesMask"]["stub"] = 0x40000000
+ logging.info("added stub output device mask")
+ if "stub" not in all_component_types["InputDevicesMask"]:
+ all_component_types["InputDevicesMask"]["stub"] = 0x40000000
+ logging.info("added stub input device mask")
+
# Transform input source in inclusive criterion
shift = len(all_component_types['OutputDevicesMask'])
if shift > 32:
diff --git a/services/audiopolicy/tests/Android.bp b/services/audiopolicy/tests/Android.bp
index ca03e1f..daedf31 100644
--- a/services/audiopolicy/tests/Android.bp
+++ b/services/audiopolicy/tests/Android.bp
@@ -45,6 +45,7 @@
cc_test {
name: "audio_health_tests",
+ require_root: true,
shared_libs: [
"libaudiofoundation",
diff --git a/services/audiopolicy/tests/audio_health_tests.cpp b/services/audiopolicy/tests/audio_health_tests.cpp
index b5c67a1..9a62e72 100644
--- a/services/audiopolicy/tests/audio_health_tests.cpp
+++ b/services/audiopolicy/tests/audio_health_tests.cpp
@@ -16,6 +16,7 @@
#define LOG_TAG "AudioPolicy_Boot_Test"
+#include <string>
#include <unordered_set>
#include <gtest/gtest.h>
@@ -74,3 +75,43 @@
ASSERT_NE(attachedDevices.end(), attachedDevices.find(desc->type()));
}
}
+
+TEST(AudioHealthTest, ConnectSupportedDevice) {
+ AudioPolicyManagerTestClient client;
+ AudioPolicyTestManager manager(&client);
+ manager.loadConfig();
+ ASSERT_NE("AudioPolicyConfig::setDefault", manager.getConfig().getSource());
+
+ DeviceVector devices;
+ for (const auto& hwModule : manager.getConfig().getHwModules()) {
+ for (const auto& profile : hwModule->getOutputProfiles()) {
+ devices.merge(profile->getSupportedDevices());
+ }
+ for (const auto& profile : hwModule->getInputProfiles()) {
+ devices.merge(profile->getSupportedDevices());
+ }
+ }
+ for (const auto& device : devices) {
+ if (!audio_is_bluetooth_out_sco_device(device->type()) &&
+ !audio_is_bluetooth_in_sco_device(device->type())) {
+ // There are two reasons to only test connecting BT devices.
+ // 1) It is easier to construct a fake address.
+ // 2) This test will be run in presubmit. In that case, it makes sense to make the test
+ // processing time short.
+ continue;
+ }
+ std::string address = "11:22:33:44:55:66";
+ ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ AudioSystem::getDeviceConnectionState(device->type(), address.c_str()));
+ ASSERT_EQ(NO_ERROR, AudioSystem::setDeviceConnectionState(
+ device->type(), AUDIO_POLICY_DEVICE_STATE_AVAILABLE, address.c_str(),
+ "" /*device_name*/, AUDIO_FORMAT_DEFAULT));
+ ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_AVAILABLE,
+ AudioSystem::getDeviceConnectionState(device->type(), address.c_str()));
+ ASSERT_EQ(NO_ERROR, AudioSystem::setDeviceConnectionState(
+ device->type(), AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE, address.c_str(),
+ "" /*device_name*/, AUDIO_FORMAT_DEFAULT));
+ ASSERT_EQ(AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE,
+ AudioSystem::getDeviceConnectionState(device->type(), address.c_str()));
+ }
+}
diff --git a/services/camera/libcameraservice/device3/Camera3OfflineSession.h b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
index c4c7a85..ee9ed25 100644
--- a/services/camera/libcameraservice/device3/Camera3OfflineSession.h
+++ b/services/camera/libcameraservice/device3/Camera3OfflineSession.h
@@ -36,7 +36,6 @@
#include "device3/RotateAndCropMapper.h"
#include "device3/ZoomRatioMapper.h"
#include "utils/TagMonitor.h"
-#include "utils/LatencyHistogram.h"
#include <camera_metadata_hidden.h>
namespace android {
diff --git a/services/camera/libcameraservice/device3/Camera3OutputUtils.h b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
index 9946312..3ebbc17 100644
--- a/services/camera/libcameraservice/device3/Camera3OutputUtils.h
+++ b/services/camera/libcameraservice/device3/Camera3OutputUtils.h
@@ -72,8 +72,8 @@
const String8& cameraId;
std::mutex& inflightLock;
int64_t& lastCompletedRegularFrameNumber;
- int64_t& lastCompletedZslFrameNumber;
int64_t& lastCompletedReprocessFrameNumber;
+ int64_t& lastCompletedZslFrameNumber;
InFlightRequestMap& inflightMap; // end of inflightLock scope
std::mutex& outputLock;
std::list<CaptureResult>& resultQueue;
diff --git a/services/camera/libcameraservice/fuzzer/Android.bp b/services/camera/libcameraservice/fuzzer/Android.bp
new file mode 100644
index 0000000..c5b7f00
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/Android.bp
@@ -0,0 +1,44 @@
+// Copyright 2020 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.
+
+cc_defaults {
+ name: "libcameraservice_fuzz_defaults",
+ fuzz_config: {
+ componentid: 41727
+ },
+}
+
+cc_fuzz {
+ name: "libcameraservice_distortion_mapper_fuzzer",
+ defaults: ["libcameraservice_fuzz_defaults"],
+ srcs: [
+ "DistortionMapperFuzzer.cpp",
+ ],
+ shared_libs: [
+ "libcameraservice",
+ "libcamera_client",
+ ],
+}
+
+cc_fuzz {
+ name: "libcameraservice_depth_processor_fuzzer",
+ defaults: ["libcameraservice_fuzz_defaults"],
+ srcs: [
+ "DepthProcessorFuzzer.cpp",
+ ],
+ shared_libs: [
+ "libcameraservice",
+ ],
+ corpus: ["corpus/*.jpg"],
+}
diff --git a/services/camera/libcameraservice/fuzzer/DepthProcessorFuzzer.cpp b/services/camera/libcameraservice/fuzzer/DepthProcessorFuzzer.cpp
new file mode 100644
index 0000000..650ca91
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/DepthProcessorFuzzer.cpp
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2020 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 <array>
+#include <vector>
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "common/DepthPhotoProcessor.h"
+
+using namespace android;
+using namespace android::camera3;
+
+static const size_t kTestBufferWidth = 640;
+static const size_t kTestBufferHeight = 480;
+static const size_t kTestBufferDepthSize (kTestBufferWidth * kTestBufferHeight);
+
+void generateDepth16Buffer(const uint8_t* data, size_t size, std::array<uint16_t, kTestBufferDepthSize> *depth16Buffer /*out*/) {
+ FuzzedDataProvider dataProvider(data, size);
+ for (size_t i = 0; i < depth16Buffer->size(); i++) {
+ (*depth16Buffer)[i] = dataProvider.ConsumeIntegral<uint16_t>();
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ DepthPhotoInputFrame inputFrame;
+ // Worst case both depth and confidence maps have the same size as the main color image.
+ inputFrame.mMaxJpegSize = inputFrame.mMainJpegSize * 3;
+
+ std::vector<uint8_t> depthPhotoBuffer(inputFrame.mMaxJpegSize);
+ size_t actualDepthPhotoSize = 0;
+
+ std::array<uint16_t, kTestBufferDepthSize> depth16Buffer;
+ generateDepth16Buffer(data, size, &depth16Buffer);
+
+ inputFrame.mMainJpegBuffer = reinterpret_cast<const char*> (data);
+ inputFrame.mMainJpegSize = size;
+ inputFrame.mDepthMapBuffer = depth16Buffer.data();
+ inputFrame.mDepthMapStride = kTestBufferWidth;
+ inputFrame.mDepthMapWidth = kTestBufferWidth;
+ inputFrame.mDepthMapHeight = kTestBufferHeight;
+ processDepthPhotoFrame(
+ inputFrame,
+ depthPhotoBuffer.size(),
+ depthPhotoBuffer.data(),
+ &actualDepthPhotoSize);
+
+ return 0;
+}
diff --git a/services/camera/libcameraservice/fuzzer/DistortionMapperFuzzer.cpp b/services/camera/libcameraservice/fuzzer/DistortionMapperFuzzer.cpp
new file mode 100644
index 0000000..96bab4e
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/DistortionMapperFuzzer.cpp
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 2020 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 <vector>
+
+#include <fuzzer/FuzzedDataProvider.h>
+
+#include "device3/DistortionMapper.h"
+#include <camera/CameraMetadata.h>
+
+using namespace android;
+using namespace android::camera3;
+
+int32_t testActiveArray[] = {100, 100, 1000, 750};
+float testICal[] = { 1000.f, 1000.f, 500.f, 500.f, 0.f };
+float identityDistortion[] = { 0.f, 0.f, 0.f, 0.f, 0.f};
+
+void setupTestMapper(DistortionMapper *m,
+ float distortion[5], float intrinsics[5],
+ int32_t activeArray[4], int32_t preCorrectionActiveArray[4]) {
+ CameraMetadata deviceInfo;
+
+ deviceInfo.update(ANDROID_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE,
+ preCorrectionActiveArray, 4);
+
+ deviceInfo.update(ANDROID_SENSOR_INFO_ACTIVE_ARRAY_SIZE,
+ activeArray, 4);
+
+ deviceInfo.update(ANDROID_LENS_INTRINSIC_CALIBRATION,
+ intrinsics, 5);
+
+ deviceInfo.update(ANDROID_LENS_DISTORTION,
+ distortion, 5);
+
+ m->setupStaticInfo(deviceInfo);
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fdp(data, size);
+
+ DistortionMapper m;
+ setupTestMapper(&m, identityDistortion, testICal,
+ /*activeArray*/ testActiveArray,
+ /*preCorrectionActiveArray*/ testActiveArray);
+
+ bool clamp = fdp.ConsumeBool();
+ bool simple = fdp.ConsumeBool();
+ std::vector<int32_t> input;
+ for (int index = 0; fdp.remaining_bytes() > 0; index++) {
+ input.push_back(fdp.ConsumeIntegral<int32_t>());
+ }
+
+ // The size argument counts how many coordinate pairs there are, so
+ // it is expected to be 1/2 the size of the input.
+ m.mapCorrectedToRaw(input.data(), input.size()/2, clamp, simple);
+
+ return 0;
+}
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Canon_MakerNote_variant_type_1.jpg b/services/camera/libcameraservice/fuzzer/corpus/Canon_MakerNote_variant_type_1.jpg
new file mode 100644
index 0000000..1eb37d0
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Canon_MakerNote_variant_type_1.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Fuji_MakerNote_variant_type_1.jpg b/services/camera/libcameraservice/fuzzer/corpus/Fuji_MakerNote_variant_type_1.jpg
new file mode 100644
index 0000000..75e0371
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Fuji_MakerNote_variant_type_1.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_2.jpg b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_2.jpg
new file mode 100644
index 0000000..461d613
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_2.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_3.jpg b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_3.jpg
new file mode 100644
index 0000000..42498e2
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_3.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_4.jpg b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_4.jpg
new file mode 100644
index 0000000..233ff78
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_4.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_5.jpg b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_5.jpg
new file mode 100644
index 0000000..f083f75
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Olympus_MakerNote_variant_type_5.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_2.jpg b/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_2.jpg
new file mode 100644
index 0000000..0ef0ef2
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_2.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_3.jpg b/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_3.jpg
new file mode 100644
index 0000000..d93b86f
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_3.jpg
Binary files differ
diff --git a/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_4.jpg b/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_4.jpg
new file mode 100644
index 0000000..297ea1c
--- /dev/null
+++ b/services/camera/libcameraservice/fuzzer/corpus/Pentax_MakerNote_variant_type_4.jpg
Binary files differ
diff --git a/services/medialog/Android.bp b/services/medialog/Android.bp
index 74b63d5..3a27a43 100644
--- a/services/medialog/Android.bp
+++ b/services/medialog/Android.bp
@@ -1,4 +1,4 @@
-cc_library_shared {
+cc_library {
name: "libmedialogservice",
srcs: [
diff --git a/services/medialog/fuzzer/Android.bp b/services/medialog/fuzzer/Android.bp
new file mode 100644
index 0000000..2afaaae
--- /dev/null
+++ b/services/medialog/fuzzer/Android.bp
@@ -0,0 +1,33 @@
+cc_fuzz {
+ name: "media_log_fuzzer",
+ static_libs: [
+ "libmedialogservice",
+ ],
+ srcs: [
+ "media_log_fuzzer.cpp",
+ ],
+ header_libs: [
+ "libmedia_headers",
+ ],
+ shared_libs: [
+ "libaudioutils",
+ "libbinder",
+ "liblog",
+ "libmediautils",
+ "libnblog",
+ "libutils",
+ ],
+ include_dirs: [
+ "frameworks/av/services/medialog",
+ ],
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+ fuzz_config: {
+ cc: [
+ "android-media-fuzzing-reports@google.com",
+ ],
+ componentid: 155276,
+ },
+}
diff --git a/services/medialog/fuzzer/README.md b/services/medialog/fuzzer/README.md
new file mode 100644
index 0000000..b79e5c8
--- /dev/null
+++ b/services/medialog/fuzzer/README.md
@@ -0,0 +1,50 @@
+# Fuzzer for libmedialogservice
+
+## Plugin Design Considerations
+The fuzzer plugin for libmedialogservice is designed based on the understanding of the
+service and tries to achieve the following:
+
+##### Maximize code coverage
+The configuration parameters are not hardcoded, but instead selected based on
+incoming data. This ensures more code paths are reached by the fuzzer.
+
+medialogservice supports the following parameters:
+1. Writer name (parameter name: `writerNameIdx`)
+2. Log size (parameter name: `logSize`)
+3. Enable dump before unrgister API (parameter name: `shouldDumpBeforeUnregister`)
+5. size of string for log dump (parameter name: `numberOfLines`)
+
+| Parameter| Valid Values| Configured Value|
+|------------- |-------------| ----- |
+| `writerNameIdx` | 0. `0` 1. `1` | Value obtained from FuzzedDataProvider |
+| `logSize` | In the range `256 to 65536` | Value obtained from FuzzedDataProvider |
+| `shouldDumpBeforeUnregister` | 0. `0` 1. `1` | Value obtained from FuzzedDataProvider |
+| `numberOfLines` | In the range `0 to 65535` | Value obtained from FuzzedDataProvider |
+
+This also ensures that the plugin is always deterministic for any given input.
+
+## Build
+
+This describes steps to build media_log_fuzzer binary.
+
+### Android
+
+#### Steps to build
+Build the fuzzer
+```
+ $ mm -j$(nproc) media_log_fuzzer
+```
+
+#### Steps to run
+Create a directory CORPUS_DIR and copy some files to that folder
+Push this directory to device.
+
+To run on device
+```
+ $ adb sync data
+ $ adb shell /data/fuzz/arm64/media_log_fuzzer/media_log_fuzzer CORPUS_DIR
+```
+
+## References:
+ * http://llvm.org/docs/LibFuzzer.html
+ * https://github.com/google/oss-fuzz
diff --git a/services/medialog/fuzzer/media_log_fuzzer.cpp b/services/medialog/fuzzer/media_log_fuzzer.cpp
new file mode 100644
index 0000000..bd50d0f
--- /dev/null
+++ b/services/medialog/fuzzer/media_log_fuzzer.cpp
@@ -0,0 +1,76 @@
+/**
+ * Copyright (C) 2020 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 <binder/IMemory.h>
+#include <binder/MemoryDealer.h>
+#include <private/android_filesystem_config.h>
+#include "MediaLogService.h"
+#include "fuzzer/FuzzedDataProvider.h"
+
+constexpr const char* kWriterNames[2] = {"FastMixer", "FastCapture"};
+constexpr size_t kMinSize = 0x100;
+constexpr size_t kMaxSize = 0x10000;
+constexpr size_t kLogMemorySize = 400 * 1024;
+constexpr size_t kMaxNumLines = USHRT_MAX;
+
+using namespace android;
+
+class MediaLogFuzzer {
+ public:
+ void init();
+ void process(const uint8_t* data, size_t size);
+
+ private:
+ sp<MemoryDealer> mMemoryDealer = nullptr;
+ sp<MediaLogService> mService = nullptr;
+};
+
+void MediaLogFuzzer::init() {
+ setuid(AID_MEDIA);
+ mService = new MediaLogService();
+ mMemoryDealer = new MemoryDealer(kLogMemorySize, "MediaLogFuzzer", MemoryHeapBase::READ_ONLY);
+}
+
+void MediaLogFuzzer::process(const uint8_t* data, size_t size) {
+ FuzzedDataProvider fuzzedDataProvider(data, size);
+ size_t writerNameIdx =
+ fuzzedDataProvider.ConsumeIntegralInRange<size_t>(0, std::size(kWriterNames) - 1);
+ bool shouldDumpBeforeUnregister = fuzzedDataProvider.ConsumeBool();
+ size_t logSize = fuzzedDataProvider.ConsumeIntegralInRange<size_t>(kMinSize, kMaxSize);
+ sp<IMemory> logBuffer = mMemoryDealer->allocate(NBLog::Timeline::sharedSize(logSize));
+ Vector<String16> args;
+ size_t numberOfLines = fuzzedDataProvider.ConsumeIntegralInRange<size_t>(0, kMaxNumLines);
+ for (size_t lineIdx = 0; lineIdx < numberOfLines; ++lineIdx) {
+ args.add(static_cast<String16>(fuzzedDataProvider.ConsumeRandomLengthString().c_str()));
+ }
+ const char* fileName = "logDumpFile";
+ int fd = memfd_create(fileName, MFD_ALLOW_SEALING);
+ fuzzedDataProvider.ConsumeData(logBuffer->unsecurePointer(), logBuffer->size());
+ mService->registerWriter(logBuffer, logSize, kWriterNames[writerNameIdx]);
+ if (shouldDumpBeforeUnregister) {
+ mService->dump(fd, args);
+ mService->unregisterWriter(logBuffer);
+ } else {
+ mService->unregisterWriter(logBuffer);
+ mService->dump(fd, args);
+ }
+}
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size) {
+ MediaLogFuzzer mediaLogFuzzer = MediaLogFuzzer();
+ mediaLogFuzzer.init();
+ mediaLogFuzzer.process(data, size);
+ return 0;
+}
diff --git a/services/mediametrics/Android.bp b/services/mediametrics/Android.bp
index f033d5c..91590e1 100644
--- a/services/mediametrics/Android.bp
+++ b/services/mediametrics/Android.bp
@@ -131,6 +131,7 @@
"statsd_codec.cpp",
"statsd_drm.cpp",
"statsd_extractor.cpp",
+ "statsd_mediaparser.cpp",
"statsd_nuplayer.cpp",
"statsd_recorder.cpp",
"StringUtils.cpp"
diff --git a/services/mediametrics/iface_statsd.cpp b/services/mediametrics/iface_statsd.cpp
index 6e51f72..16204de 100644
--- a/services/mediametrics/iface_statsd.cpp
+++ b/services/mediametrics/iface_statsd.cpp
@@ -64,6 +64,7 @@
{ "drmmanager", statsd_drmmanager },
{ "extractor", statsd_extractor },
{ "mediadrm", statsd_mediadrm },
+ { "mediaparser", statsd_mediaparser },
{ "nuplayer", statsd_nuplayer },
{ "nuplayer2", statsd_nuplayer },
{ "recorder", statsd_recorder },
diff --git a/services/mediametrics/iface_statsd.h b/services/mediametrics/iface_statsd.h
index 19505a4..9b49556 100644
--- a/services/mediametrics/iface_statsd.h
+++ b/services/mediametrics/iface_statsd.h
@@ -25,6 +25,7 @@
extern bool statsd_audiotrack(const mediametrics::Item *);
extern bool statsd_codec(const mediametrics::Item *);
extern bool statsd_extractor(const mediametrics::Item *);
+extern bool statsd_mediaparser(const mediametrics::Item *);
extern bool statsd_nuplayer(const mediametrics::Item *);
extern bool statsd_recorder(const mediametrics::Item *);
diff --git a/services/mediametrics/statsd_mediaparser.cpp b/services/mediametrics/statsd_mediaparser.cpp
new file mode 100644
index 0000000..3258ebf
--- /dev/null
+++ b/services/mediametrics/statsd_mediaparser.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2020 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 "statsd_mediaparser"
+#include <utils/Log.h>
+
+#include <dirent.h>
+#include <inttypes.h>
+#include <pthread.h>
+#include <pwd.h>
+#include <stdint.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <statslog.h>
+
+#include "MediaMetricsService.h"
+#include "frameworks/base/core/proto/android/stats/mediametrics/mediametrics.pb.h"
+#include "iface_statsd.h"
+
+namespace android {
+
+bool statsd_mediaparser(const mediametrics::Item *item)
+{
+ if (item == nullptr) {
+ return false;
+ }
+
+ // statsd wrapper data.
+ const nsecs_t timestamp = MediaMetricsService::roundTime(item->getTimestamp());
+ std::string pkgName = item->getPkgName();
+ int64_t pkgVersionCode = item->getPkgVersionCode();
+
+ std::string parserName;
+ item->getString("android.media.mediaparser.parserName", &parserName);
+
+ int32_t createdByName = -1;
+ item->getInt32("android.media.mediaparser.createdByName", &createdByName);
+
+ std::string parserPool;
+ item->getString("android.media.mediaparser.parserPool", &parserPool);
+
+ std::string lastException;
+ item->getString("android.media.mediaparser.lastException", &lastException);
+
+ int64_t resourceByteCount = -1;
+ item->getInt64("android.media.mediaparser.resourceByteCount", &resourceByteCount);
+
+ int64_t durationMillis = -1;
+ item->getInt64("android.media.mediaparser.durationMillis", &durationMillis);
+
+ std::string trackMimeTypes;
+ item->getString("android.media.mediaparser.trackMimeTypes", &trackMimeTypes);
+
+ std::string trackCodecs;
+ item->getString("android.media.mediaparser.trackCodecs", &trackCodecs);
+
+ std::string alteredParameters;
+ item->getString("android.media.mediaparser.alteredParameters", &alteredParameters);
+
+ int32_t videoWidth = -1;
+ item->getInt32("android.media.mediaparser.videoWidth", &videoWidth);
+
+ int32_t videoHeight = -1;
+ item->getInt32("android.media.mediaparser.videoHeight", &videoHeight);
+
+ if (enabled_statsd) {
+ (void) android::util::stats_write(android::util::MEDIAMETRICS_MEDIAPARSER_REPORTED,
+ timestamp,
+ pkgName.c_str(),
+ pkgVersionCode,
+ parserName.c_str(),
+ createdByName,
+ parserPool.c_str(),
+ lastException.c_str(),
+ resourceByteCount,
+ durationMillis,
+ trackMimeTypes.c_str(),
+ trackCodecs.c_str(),
+ alteredParameters.c_str(),
+ videoWidth,
+ videoHeight);
+ } else {
+ ALOGV("NOT sending MediaParser media metrics.");
+ }
+
+ return true;
+}
+
+} // namespace android
diff --git a/services/mediaresourcemanager/ResourceManagerService.cpp b/services/mediaresourcemanager/ResourceManagerService.cpp
index 7bb606e..32ac583 100644
--- a/services/mediaresourcemanager/ResourceManagerService.cpp
+++ b/services/mediaresourcemanager/ResourceManagerService.cpp
@@ -511,8 +511,8 @@
resource.value -= res.value;
} else {
onLastRemoved(res, info);
- info.resources.erase(resType);
actualRemoved.value = resource.value;
+ info.resources.erase(resType);
}
// Add it to the list of removed resources for observers.
diff --git a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
index 5f4f645..f4d3ff8 100644
--- a/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
+++ b/services/mediatranscoding/tests/MediaTranscodingServiceTestHelper.h
@@ -368,6 +368,7 @@
request.priority = priority;
request.clientPid = (overridePid == -1) ? mClientPid : overridePid;
request.clientUid = (overrideUid == -1) ? mClientUid : overrideUid;
+ request.clientPackageName = (overrideUid == -1) ? mPackageName : "";
if (bitrateBps > 0) {
request.requestedVideoTrackFormat.emplace(TranscodingVideoTrackFormat());
request.requestedVideoTrackFormat->bitrateBps = bitrateBps;
diff --git a/services/oboeservice/AAudioClientTracker.cpp b/services/oboeservice/AAudioClientTracker.cpp
index 3ec8dea..054a896 100644
--- a/services/oboeservice/AAudioClientTracker.cpp
+++ b/services/oboeservice/AAudioClientTracker.cpp
@@ -41,7 +41,7 @@
: Singleton<AAudioClientTracker>() {
}
-std::string AAudioClientTracker::dump() const {
+std::string AAudioClientTracker::dump() const NO_THREAD_SAFETY_ANALYSIS {
std::stringstream result;
const bool isLocked = AAudio_tryUntilTrue(
[this]()->bool { return mLock.try_lock(); } /* f */,
@@ -207,7 +207,7 @@
}
-std::string AAudioClientTracker::NotificationClient::dump() const {
+std::string AAudioClientTracker::NotificationClient::dump() const NO_THREAD_SAFETY_ANALYSIS {
std::stringstream result;
const bool isLocked = AAudio_tryUntilTrue(
[this]()->bool { return mLock.try_lock(); } /* f */,
diff --git a/services/oboeservice/AAudioClientTracker.h b/services/oboeservice/AAudioClientTracker.h
index facfc3b..2b38621 100644
--- a/services/oboeservice/AAudioClientTracker.h
+++ b/services/oboeservice/AAudioClientTracker.h
@@ -21,6 +21,7 @@
#include <mutex>
#include <set>
+#include <android-base/thread_annotations.h>
#include <utils/Singleton.h>
#include <aaudio/AAudio.h>
@@ -114,10 +115,12 @@
};
// This must be called under mLock
- android::sp<NotificationClient> getNotificationClient_l(pid_t pid);
+ android::sp<NotificationClient> getNotificationClient_l(pid_t pid)
+ REQUIRES(mLock);
mutable std::mutex mLock;
- std::map<pid_t, android::sp<NotificationClient>> mNotificationClients;
+ std::map<pid_t, android::sp<NotificationClient>> mNotificationClients
+ GUARDED_BY(mLock);
android::AAudioService *mAAudioService = nullptr;
};
diff --git a/services/oboeservice/AAudioEndpointManager.cpp b/services/oboeservice/AAudioEndpointManager.cpp
index 483a264..407f6d5 100644
--- a/services/oboeservice/AAudioEndpointManager.cpp
+++ b/services/oboeservice/AAudioEndpointManager.cpp
@@ -43,7 +43,7 @@
, mExclusiveStreams() {
}
-std::string AAudioEndpointManager::dump() const {
+std::string AAudioEndpointManager::dump() const NO_THREAD_SAFETY_ANALYSIS {
std::stringstream result;
int index = 0;
diff --git a/services/oboeservice/AAudioEndpointManager.h b/services/oboeservice/AAudioEndpointManager.h
index ae776b1..b07bcef 100644
--- a/services/oboeservice/AAudioEndpointManager.h
+++ b/services/oboeservice/AAudioEndpointManager.h
@@ -20,6 +20,8 @@
#include <map>
#include <mutex>
#include <sys/types.h>
+
+#include <android-base/thread_annotations.h>
#include <utils/Singleton.h>
#include "binding/AAudioServiceMessage.h"
@@ -70,10 +72,12 @@
const aaudio::AAudioStreamRequest &request);
android::sp<AAudioServiceEndpoint> findExclusiveEndpoint_l(
- const AAudioStreamConfiguration& configuration);
+ const AAudioStreamConfiguration& configuration)
+ REQUIRES(mExclusiveLock);
android::sp<AAudioServiceEndpointShared> findSharedEndpoint_l(
- const AAudioStreamConfiguration& configuration);
+ const AAudioStreamConfiguration& configuration)
+ REQUIRES(mSharedLock);
void closeExclusiveEndpoint(android::sp<AAudioServiceEndpoint> serviceEndpoint);
void closeSharedEndpoint(android::sp<AAudioServiceEndpoint> serviceEndpoint);
@@ -83,23 +87,25 @@
// Lock mSharedLock before mExclusiveLock.
// it is OK to only lock mExclusiveLock.
mutable std::mutex mSharedLock;
- std::vector<android::sp<AAudioServiceEndpointShared>> mSharedStreams;
+ std::vector<android::sp<AAudioServiceEndpointShared>> mSharedStreams
+ GUARDED_BY(mSharedLock);
mutable std::mutex mExclusiveLock;
- std::vector<android::sp<AAudioServiceEndpointMMAP>> mExclusiveStreams;
+ std::vector<android::sp<AAudioServiceEndpointMMAP>> mExclusiveStreams
+ GUARDED_BY(mExclusiveLock);
- // Modified under a lock.
- int32_t mExclusiveSearchCount = 0; // number of times we SEARCHED for an exclusive endpoint
- int32_t mExclusiveFoundCount = 0; // number of times we FOUND an exclusive endpoint
- int32_t mExclusiveOpenCount = 0; // number of times we OPENED an exclusive endpoint
- int32_t mExclusiveCloseCount = 0; // number of times we CLOSED an exclusive endpoint
- int32_t mExclusiveStolenCount = 0; // number of times we STOLE an exclusive endpoint
+ // Counts related to an exclusive endpoint.
+ int32_t mExclusiveSearchCount GUARDED_BY(mExclusiveLock) = 0; // # SEARCHED
+ int32_t mExclusiveFoundCount GUARDED_BY(mExclusiveLock) = 0; // # FOUND
+ int32_t mExclusiveOpenCount GUARDED_BY(mExclusiveLock) = 0; // # OPENED
+ int32_t mExclusiveCloseCount GUARDED_BY(mExclusiveLock) = 0; // # CLOSED
+ int32_t mExclusiveStolenCount GUARDED_BY(mExclusiveLock) = 0; // # STOLEN
// Same as above but for SHARED endpoints.
- int32_t mSharedSearchCount = 0;
- int32_t mSharedFoundCount = 0;
- int32_t mSharedOpenCount = 0;
- int32_t mSharedCloseCount = 0;
+ int32_t mSharedSearchCount GUARDED_BY(mSharedLock) = 0;
+ int32_t mSharedFoundCount GUARDED_BY(mSharedLock) = 0;
+ int32_t mSharedOpenCount GUARDED_BY(mSharedLock) = 0;
+ int32_t mSharedCloseCount GUARDED_BY(mSharedLock) = 0;
// For easily disabling the stealing of exclusive streams.
static constexpr bool kStealingEnabled = true;
diff --git a/services/oboeservice/AAudioServiceEndpoint.cpp b/services/oboeservice/AAudioServiceEndpoint.cpp
index b139be1..faea58f 100644
--- a/services/oboeservice/AAudioServiceEndpoint.cpp
+++ b/services/oboeservice/AAudioServiceEndpoint.cpp
@@ -38,7 +38,7 @@
using namespace android; // TODO just import names needed
using namespace aaudio; // TODO just import names needed
-std::string AAudioServiceEndpoint::dump() const {
+std::string AAudioServiceEndpoint::dump() const NO_THREAD_SAFETY_ANALYSIS {
std::stringstream result;
const bool isLocked = AAudio_tryUntilTrue(
diff --git a/services/oboeservice/AAudioServiceEndpoint.h b/services/oboeservice/AAudioServiceEndpoint.h
index 04b906a..72090c2 100644
--- a/services/oboeservice/AAudioServiceEndpoint.h
+++ b/services/oboeservice/AAudioServiceEndpoint.h
@@ -22,6 +22,8 @@
#include <mutex>
#include <vector>
+#include <android-base/thread_annotations.h>
+
#include "client/AudioStreamInternal.h"
#include "client/AudioStreamInternalPlay.h"
#include "core/AAudioStreamParameters.h"
@@ -141,7 +143,8 @@
std::vector<android::sp<AAudioServiceStreamBase>> disconnectRegisteredStreams();
mutable std::mutex mLockStreams;
- std::vector<android::sp<AAudioServiceStreamBase>> mRegisteredStreams;
+ std::vector<android::sp<AAudioServiceStreamBase>> mRegisteredStreams
+ GUARDED_BY(mLockStreams);
SimpleDoubleBuffer<Timestamp> mAtomicEndpointTimestamp;
diff --git a/services/oboeservice/AAudioServiceEndpointPlay.cpp b/services/oboeservice/AAudioServiceEndpointPlay.cpp
index 6ddc30b..4e46033 100644
--- a/services/oboeservice/AAudioServiceEndpointPlay.cpp
+++ b/services/oboeservice/AAudioServiceEndpointPlay.cpp
@@ -98,7 +98,7 @@
{
// Lock the AudioFifo to protect against close.
- std::lock_guard <std::mutex> lock(streamShared->getAudioDataQueueLock());
+ std::lock_guard <std::mutex> lock(streamShared->audioDataQueueLock);
std::shared_ptr<SharedRingBuffer> audioDataQueue
= streamShared->getAudioDataQueue_l();
std::shared_ptr<FifoBuffer> fifo;
diff --git a/services/oboeservice/AAudioServiceEndpointShared.cpp b/services/oboeservice/AAudioServiceEndpointShared.cpp
index caf6139..501e8c0 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.cpp
+++ b/services/oboeservice/AAudioServiceEndpointShared.cpp
@@ -137,24 +137,25 @@
aaudio_result_t aaudio::AAudioServiceEndpointShared::stopSharingThread() {
mCallbackEnabled.store(false);
- aaudio_result_t result = getStreamInternal()->joinThread(NULL);
- return result;
+ return getStreamInternal()->joinThread(NULL);
}
-aaudio_result_t AAudioServiceEndpointShared::startStream(sp<AAudioServiceStreamBase> sharedStream,
- audio_port_handle_t *clientHandle) {
+aaudio_result_t AAudioServiceEndpointShared::startStream(
+ sp<AAudioServiceStreamBase> sharedStream,
+ audio_port_handle_t *clientHandle)
+ NO_THREAD_SAFETY_ANALYSIS {
aaudio_result_t result = AAUDIO_OK;
{
std::lock_guard<std::mutex> lock(mLockStreams);
if (++mRunningStreamCount == 1) { // atomic
- result = getStreamInternal()->requestStart_l();
+ result = getStreamInternal()->systemStart();
if (result != AAUDIO_OK) {
--mRunningStreamCount;
} else {
result = startSharingThread_l();
if (result != AAUDIO_OK) {
- getStreamInternal()->requestStop_l();
+ getStreamInternal()->systemStopFromApp();
--mRunningStreamCount;
}
}
@@ -168,7 +169,7 @@
if (result != AAUDIO_OK) {
if (--mRunningStreamCount == 0) { // atomic
stopSharingThread();
- getStreamInternal()->requestStop_l();
+ getStreamInternal()->systemStopFromApp();
}
}
}
@@ -183,7 +184,7 @@
if (--mRunningStreamCount == 0) { // atomic
stopSharingThread(); // the sharing thread locks mLockStreams
- getStreamInternal()->requestStop_l();
+ getStreamInternal()->systemStopFromApp();
}
return AAUDIO_OK;
}
diff --git a/services/oboeservice/AAudioServiceEndpointShared.h b/services/oboeservice/AAudioServiceEndpointShared.h
index 91a86c1..8357567 100644
--- a/services/oboeservice/AAudioServiceEndpointShared.h
+++ b/services/oboeservice/AAudioServiceEndpointShared.h
@@ -20,6 +20,8 @@
#include <atomic>
#include <mutex>
+#include <android-base/thread_annotations.h>
+
#include "AAudioServiceEndpoint.h"
#include "client/AudioStreamInternal.h"
#include "client/AudioStreamInternalPlay.h"
@@ -63,7 +65,7 @@
protected:
- aaudio_result_t startSharingThread_l();
+ aaudio_result_t startSharingThread_l() REQUIRES(mLockStreams);
aaudio_result_t stopSharingThread();
diff --git a/services/oboeservice/AAudioServiceStreamBase.cpp b/services/oboeservice/AAudioServiceStreamBase.cpp
index 9736091..7edc25c 100644
--- a/services/oboeservice/AAudioServiceStreamBase.cpp
+++ b/services/oboeservice/AAudioServiceStreamBase.cpp
@@ -595,14 +595,3 @@
void AAudioServiceStreamBase::onVolumeChanged(float volume) {
sendServiceEvent(AAUDIO_SERVICE_EVENT_VOLUME, volume);
}
-
-int32_t AAudioServiceStreamBase::incrementServiceReferenceCount_l() {
- return ++mCallingCount;
-}
-
-int32_t AAudioServiceStreamBase::decrementServiceReferenceCount_l() {
- int32_t count = --mCallingCount;
- // Each call to increment should be balanced with one call to decrement.
- assert(count >= 0);
- return count;
-}
diff --git a/services/oboeservice/AAudioServiceStreamBase.h b/services/oboeservice/AAudioServiceStreamBase.h
index f9efc2a..0f752b7 100644
--- a/services/oboeservice/AAudioServiceStreamBase.h
+++ b/services/oboeservice/AAudioServiceStreamBase.h
@@ -20,6 +20,7 @@
#include <assert.h>
#include <mutex>
+#include <android-base/thread_annotations.h>
#include <media/AudioClient.h>
#include <utils/RefBase.h>
@@ -209,25 +210,6 @@
return mSuspended;
}
- /**
- * Atomically increment the number of active references to the stream by AAudioService.
- *
- * This is called under a global lock in AAudioStreamTracker.
- *
- * @return value after the increment
- */
- int32_t incrementServiceReferenceCount_l();
-
- /**
- * Atomically decrement the number of active references to the stream by AAudioService.
- * This should only be called after incrementServiceReferenceCount_l().
- *
- * This is called under a global lock in AAudioStreamTracker.
- *
- * @return value after the decrement
- */
- int32_t decrementServiceReferenceCount_l();
-
bool isCloseNeeded() const {
return mCloseNeeded.load();
}
@@ -250,11 +232,10 @@
aaudio_result_t open(const aaudio::AAudioStreamRequest &request,
aaudio_sharing_mode_t sharingMode);
- // These must be called under mLock
- virtual aaudio_result_t close_l();
- virtual aaudio_result_t pause_l();
- virtual aaudio_result_t stop_l();
- void disconnect_l();
+ virtual aaudio_result_t close_l() REQUIRES(mLock);
+ virtual aaudio_result_t pause_l() REQUIRES(mLock);
+ virtual aaudio_result_t stop_l() REQUIRES(mLock);
+ void disconnect_l() REQUIRES(mLock);
void setState(aaudio_stream_state_t state);
@@ -332,18 +313,17 @@
aaudio_handle_t mHandle = -1;
bool mFlowing = false;
- // This is modified under a global lock in AAudioStreamTracker.
- int32_t mCallingCount = 0;
-
- // This indicates that a stream that is being referenced by a binder call needs to closed.
- std::atomic<bool> mCloseNeeded{false};
+ // This indicates that a stream that is being referenced by a binder call
+ // and needs to closed.
+ std::atomic<bool> mCloseNeeded{false}; // TODO remove
// This indicate that a running stream should not be processed because of an error,
// for example a full message queue. Note that this atomic is unrelated to mCloseNeeded.
std::atomic<bool> mSuspended{false};
+protected:
// Locking order is important.
- // Always acquire mLock before acquiring AAudioServiceEndpoint::mLockStreams
+ // Acquire mLock before acquiring AAudioServiceEndpoint::mLockStreams
std::mutex mLock; // Prevent start/stop/close etcetera from colliding
};
diff --git a/services/oboeservice/AAudioServiceStreamMMAP.h b/services/oboeservice/AAudioServiceStreamMMAP.h
index 5902613..6ba1725 100644
--- a/services/oboeservice/AAudioServiceStreamMMAP.h
+++ b/services/oboeservice/AAudioServiceStreamMMAP.h
@@ -19,6 +19,7 @@
#include <atomic>
+#include <android-base/thread_annotations.h>
#include <android-base/unique_fd.h>
#include <media/audiohal/StreamHalInterface.h>
#include <media/MmapStreamCallback.h>
@@ -34,10 +35,8 @@
#include "TimestampScheduler.h"
#include "utility/MonotonicCounter.h"
-
namespace aaudio {
-
/**
* These corresponds to an EXCLUSIVE mode MMAP client stream.
* It has exclusive use of one AAudioServiceEndpointMMAP to communicate with the underlying
@@ -68,9 +67,9 @@
* This is not guaranteed to be synchronous but it currently is.
* An AAUDIO_SERVICE_EVENT_PAUSED will be sent to the client when complete.
*/
- aaudio_result_t pause_l() override;
+ aaudio_result_t pause_l() REQUIRES(mLock) override;
- aaudio_result_t stop_l() override;
+ aaudio_result_t stop_l() REQUIRES(mLock) override;
aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) override;
diff --git a/services/oboeservice/AAudioServiceStreamShared.cpp b/services/oboeservice/AAudioServiceStreamShared.cpp
index 031468e..c665cda 100644
--- a/services/oboeservice/AAudioServiceStreamShared.cpp
+++ b/services/oboeservice/AAudioServiceStreamShared.cpp
@@ -52,14 +52,26 @@
return result.str();
}
-std::string AAudioServiceStreamShared::dump() const {
+std::string AAudioServiceStreamShared::dump() const NO_THREAD_SAFETY_ANALYSIS {
std::stringstream result;
+ const bool isLocked = AAudio_tryUntilTrue(
+ [this]()->bool { return audioDataQueueLock.try_lock(); } /* f */,
+ 50 /* times */,
+ 20 /* sleepMs */);
+ if (!isLocked) {
+ result << "AAudioServiceStreamShared may be deadlocked\n";
+ }
+
result << AAudioServiceStreamBase::dump();
result << mAudioDataQueue->dump();
result << std::setw(8) << getXRunCount();
+ if (isLocked) {
+ audioDataQueueLock.unlock();
+ }
+
return result.str();
}
@@ -171,7 +183,7 @@
}
{
- std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
+ std::lock_guard<std::mutex> lock(audioDataQueueLock);
// Create audio data shared memory buffer for client.
mAudioDataQueue = std::make_shared<SharedRingBuffer>();
result = mAudioDataQueue->allocate(calculateBytesPerFrame(), getBufferCapacity());
@@ -202,7 +214,7 @@
aaudio_result_t AAudioServiceStreamShared::getAudioDataDescription(
AudioEndpointParcelable &parcelable)
{
- std::lock_guard<std::mutex> lock(mAudioDataQueueLock);
+ std::lock_guard<std::mutex> lock(audioDataQueueLock);
if (mAudioDataQueue == nullptr) {
ALOGW("%s(): mUpMessageQueue null! - stream not open", __func__);
return AAUDIO_ERROR_NULL;
@@ -260,7 +272,7 @@
int64_t clientFramesWritten = 0;
// Lock the AudioFifo to protect against close.
- std::lock_guard <std::mutex> lock(mAudioDataQueueLock);
+ std::lock_guard <std::mutex> lock(audioDataQueueLock);
if (mAudioDataQueue != nullptr) {
std::shared_ptr<FifoBuffer> fifo = mAudioDataQueue->getFifoBuffer();
diff --git a/services/oboeservice/AAudioServiceStreamShared.h b/services/oboeservice/AAudioServiceStreamShared.h
index 5b1f8da..4fae5b4 100644
--- a/services/oboeservice/AAudioServiceStreamShared.h
+++ b/services/oboeservice/AAudioServiceStreamShared.h
@@ -52,22 +52,15 @@
aaudio_result_t open(const aaudio::AAudioStreamRequest &request) override;
- /**
- * This must be locked when calling getAudioDataQueue_l() and while
- * using the FifoBuffer it contains.
- */
- std::mutex &getAudioDataQueueLock() {
- return mAudioDataQueueLock;
- }
-
void writeDataIfRoom(int64_t mmapFramesRead, const void *buffer, int32_t numFrames);
/**
* This must only be called under getAudioDataQueueLock().
* @return
*/
- std::shared_ptr<SharedRingBuffer> getAudioDataQueue_l() {
- return mAudioDataQueue;
+ std::shared_ptr<SharedRingBuffer> getAudioDataQueue_l()
+ REQUIRES(audioDataQueueLock) {
+ return mAudioDataQueue;
}
/* Keep a record of when a buffer transfer completed.
@@ -89,6 +82,10 @@
const char *getTypeText() const override { return "Shared"; }
+ // This is public so that the thread safety annotation, GUARDED_BY(),
+ // Can work when another object takes the lock.
+ mutable std::mutex audioDataQueueLock;
+
protected:
aaudio_result_t getAudioDataDescription(AudioEndpointParcelable &parcelable) override;
@@ -107,8 +104,7 @@
private:
- std::shared_ptr<SharedRingBuffer> mAudioDataQueue; // protected by mAudioDataQueueLock
- std::mutex mAudioDataQueueLock;
+ std::shared_ptr<SharedRingBuffer> mAudioDataQueue GUARDED_BY(audioDataQueueLock);
std::atomic<int64_t> mTimestampPositionOffset;
std::atomic<int32_t> mXRunCount;
diff --git a/services/oboeservice/AAudioStreamTracker.cpp b/services/oboeservice/AAudioStreamTracker.cpp
index 8e66b94..9bbbc73 100644
--- a/services/oboeservice/AAudioStreamTracker.cpp
+++ b/services/oboeservice/AAudioStreamTracker.cpp
@@ -96,7 +96,7 @@
return handle;
}
-std::string AAudioStreamTracker::dump() const {
+std::string AAudioStreamTracker::dump() const NO_THREAD_SAFETY_ANALYSIS {
std::stringstream result;
const bool isLocked = AAudio_tryUntilTrue(
[this]()->bool { return mHandleLock.try_lock(); } /* f */,
diff --git a/services/oboeservice/AAudioStreamTracker.h b/services/oboeservice/AAudioStreamTracker.h
index d1301a2..43870fc 100644
--- a/services/oboeservice/AAudioStreamTracker.h
+++ b/services/oboeservice/AAudioStreamTracker.h
@@ -17,13 +17,13 @@
#ifndef AAUDIO_AAUDIO_STREAM_TRACKER_H
#define AAUDIO_AAUDIO_STREAM_TRACKER_H
+#include <mutex>
#include <time.h>
-#include <pthread.h>
+#include <android-base/thread_annotations.h>
#include <aaudio/AAudio.h>
#include "binding/AAudioCommon.h"
-
#include "AAudioServiceStreamBase.h"
namespace aaudio {
@@ -75,11 +75,10 @@
static aaudio_handle_t bumpHandle(aaudio_handle_t handle);
// Track stream using a unique handle that wraps. Only use positive half.
- mutable std::mutex mHandleLock;
- // protected by mHandleLock
- aaudio_handle_t mPreviousHandle = 0;
- // protected by mHandleLock
- std::map<aaudio_handle_t, android::sp<aaudio::AAudioServiceStreamBase>> mStreamsByHandle;
+ mutable std::mutex mHandleLock;
+ aaudio_handle_t mPreviousHandle GUARDED_BY(mHandleLock) = 0;
+ std::map<aaudio_handle_t, android::sp<aaudio::AAudioServiceStreamBase>>
+ mStreamsByHandle GUARDED_BY(mHandleLock);
};
diff --git a/services/oboeservice/Android.bp b/services/oboeservice/Android.bp
index 31e590e..80f17f4 100644
--- a/services/oboeservice/Android.bp
+++ b/services/oboeservice/Android.bp
@@ -37,6 +37,7 @@
],
cflags: [
+ "-Wthread-safety",
"-Wno-unused-parameter",
"-Wall",
"-Werror",
diff --git a/services/tuner/Android.bp b/services/tuner/Android.bp
new file mode 100644
index 0000000..0562b45
--- /dev/null
+++ b/services/tuner/Android.bp
@@ -0,0 +1,73 @@
+filegroup {
+ name: "tv_tuner_aidl",
+ srcs: [
+ "aidl/android/media/tv/tuner/ITunerService.aidl",
+ ],
+ path: "aidl",
+}
+
+aidl_interface {
+ name: "tv_tuner_aidl_interface",
+ unstable: true,
+ local_include_dir: "aidl",
+ srcs: [
+ ":tv_tuner_aidl",
+ ],
+}
+
+cc_library {
+ name: "libtunerservice",
+
+ srcs: [
+ "TunerService.cpp",
+ ],
+
+ shared_libs: [
+ "android.hardware.tv.tuner@1.0",
+ "libbinder",
+ "libbinder_ndk",
+ "libhidlbase",
+ "liblog",
+ "libmedia",
+ "libutils",
+ "tv_tuner_aidl_interface-ndk_platform",
+ ],
+
+ include_dirs: ["frameworks/av/include"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+
+ export_include_dirs: ["."],
+}
+
+
+cc_binary {
+ name: "mediatuner",
+
+ srcs: [
+ "main_tunerservice.cpp",
+ ],
+
+ shared_libs: [
+ "android.hardware.tv.tuner@1.0",
+ "libbase",
+ "libbinder",
+ "liblog",
+ "libtunerservice",
+ "libutils",
+ ],
+
+ static_libs: [
+ "tv_tuner_aidl_interface-ndk_platform",
+ ],
+
+ init_rc: ["mediatuner.rc"],
+
+ cflags: [
+ "-Werror",
+ "-Wall",
+ ],
+}
\ No newline at end of file
diff --git a/services/tuner/OWNERS b/services/tuner/OWNERS
new file mode 100644
index 0000000..0ceb8e8
--- /dev/null
+++ b/services/tuner/OWNERS
@@ -0,0 +1,2 @@
+nchalko@google.com
+quxiangfang@google.com
diff --git a/services/tuner/TunerService.cpp b/services/tuner/TunerService.cpp
new file mode 100644
index 0000000..92008a9
--- /dev/null
+++ b/services/tuner/TunerService.cpp
@@ -0,0 +1,65 @@
+/**
+ * Copyright (c) 2020, 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 "TunerService"
+
+#include <android/binder_manager.h>
+#include <utils/Log.h>
+#include "TunerService.h"
+
+using ::android::hardware::hidl_vec;
+using ::android::hardware::tv::tuner::V1_0::FrontendId;
+using ::android::hardware::tv::tuner::V1_0::Result;
+
+namespace android {
+
+sp<ITuner> TunerService::mTuner;
+
+TunerService::TunerService() {}
+TunerService::~TunerService() {}
+
+void TunerService::instantiate() {
+ std::shared_ptr<TunerService> service =
+ ::ndk::SharedRefBase::make<TunerService>();
+ AServiceManager_addService(service->asBinder().get(), getServiceName());
+}
+
+Status TunerService::getFrontendIds(std::vector<int32_t>* ids, int32_t* /* _aidl_return */) {
+ if (mTuner == nullptr) {
+ // TODO: create a method for init.
+ mTuner = ITuner::getService();
+ if (mTuner == nullptr) {
+ ALOGE("Failed to get ITuner service.");
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(
+ static_cast<int32_t>(Result::UNAVAILABLE));
+ }
+ }
+ hidl_vec<FrontendId> feIds;
+ Result res;
+ mTuner->getFrontendIds([&](Result r, const hidl_vec<FrontendId>& frontendIds) {
+ feIds = frontendIds;
+ res = r;
+ });
+ if (res != Result::SUCCESS) {
+ return ::ndk::ScopedAStatus::fromServiceSpecificError(static_cast<int32_t>(res));
+ }
+ ids->resize(feIds.size());
+ std::copy(feIds.begin(), feIds.end(), ids->begin());
+
+ return ::ndk::ScopedAStatus::ok();
+}
+
+} // namespace android
diff --git a/services/tuner/TunerService.h b/services/tuner/TunerService.h
new file mode 100644
index 0000000..bda6c65
--- /dev/null
+++ b/services/tuner/TunerService.h
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2020, 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_TUNERSERVICE_H
+#define ANDROID_MEDIA_TUNERSERVICE_H
+
+#include <aidl/android/media/tv/tuner/BnTunerService.h>
+#include <android/hardware/tv/tuner/1.0/ITuner.h>
+
+using Status = ::ndk::ScopedAStatus;
+using ::aidl::android::media::tv::tuner::BnTunerService;
+using ::android::hardware::tv::tuner::V1_0::ITuner;
+
+namespace android {
+
+class TunerService : public BnTunerService {
+
+public:
+ static char const *getServiceName() { return "media.tuner"; }
+ static void instantiate();
+ TunerService();
+ virtual ~TunerService();
+ Status getFrontendIds(std::vector<int32_t>* ids, int32_t* _aidl_return) override;
+
+private:
+ static sp<ITuner> mTuner;
+};
+
+} // namespace android
+
+#endif // ANDROID_MEDIA_TUNERSERVICE_H
diff --git a/services/tuner/aidl/android/media/tv/OWNERS b/services/tuner/aidl/android/media/tv/OWNERS
new file mode 100644
index 0000000..0ceb8e8
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/OWNERS
@@ -0,0 +1,2 @@
+nchalko@google.com
+quxiangfang@google.com
diff --git a/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
new file mode 100644
index 0000000..53cd90d
--- /dev/null
+++ b/services/tuner/aidl/android/media/tv/tuner/ITunerService.aidl
@@ -0,0 +1,32 @@
+/**
+ * Copyright (c) 2020, 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.
+ */
+
+package android.media.tv.tuner;
+
+/**
+ * TunerService interface handles tuner related operations.
+ *
+ * {@hide}
+ */
+interface ITunerService {
+
+ /**
+ * Gets frontend IDs.
+ *
+ * @return the result code of the operation.
+ */
+ int getFrontendIds(out int[] ids);
+}
diff --git a/services/tuner/main_tunerservice.cpp b/services/tuner/main_tunerservice.cpp
new file mode 100644
index 0000000..a0e7a9f
--- /dev/null
+++ b/services/tuner/main_tunerservice.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 2020 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 <utils/Log.h>
+#include <binder/IPCThreadState.h>
+#include <binder/IServiceManager.h>
+#include <binder/ProcessState.h>
+#include <hidl/HidlTransportSupport.h>
+
+#include "TunerService.h"
+
+using namespace android;
+
+int main(int argc __unused, char** argv) {
+ ALOGD("Tuner service starting");
+
+ strcpy(argv[0], "media.tuner");
+ sp<ProcessState> proc(ProcessState::self());
+ sp<IServiceManager> sm = defaultServiceManager();
+ ALOGD("ServiceManager: %p", sm.get());
+
+ TunerService::instantiate();
+
+ ProcessState::self()->startThreadPool();
+ IPCThreadState::self()->joinThreadPool();
+}
diff --git a/services/tuner/mediatuner.rc b/services/tuner/mediatuner.rc
new file mode 100644
index 0000000..b0347be
--- /dev/null
+++ b/services/tuner/mediatuner.rc
@@ -0,0 +1,6 @@
+service media.tuner /system/bin/mediatuner
+ class main
+ user media
+ group media
+ ioprio rt 4
+ task_profiles ProcessCapacityHigh HighPerformance
\ No newline at end of file