Merge "MediaPlayer2: Remove libdrmframework.so dependency."
diff --git a/camera/cameraserver/cameraserver.rc b/camera/cameraserver/cameraserver.rc
index fea5a1d..a9aae0b 100644
--- a/camera/cameraserver/cameraserver.rc
+++ b/camera/cameraserver/cameraserver.rc
@@ -4,3 +4,4 @@
group audio camera input drmrpc
ioprio rt 4
writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks
+ rlimit rtprio 10 10
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 0501006..1dfa4f7 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -2312,7 +2312,9 @@
* <p>If this device is the largest or only camera device with a given facing, then this
* position will be <code>(0, 0, 0)</code>; a camera device with a lens optical center located 3 cm
* from the main sensor along the +X axis (to the right from the user's perspective) will
- * report <code>(0.03, 0, 0)</code>.</p>
+ * report <code>(0.03, 0, 0)</code>. Note that this means that, for many computer vision
+ * applications, the position needs to be negated to convert it to a translation from the
+ * camera to the origin.</p>
* <p>To transform a pixel coordinates between two cameras facing the same direction, first
* the source camera ACAMERA_LENS_DISTORTION must be corrected for. Then the source
* camera ACAMERA_LENS_INTRINSIC_CALIBRATION needs to be applied, followed by the
@@ -2324,7 +2326,8 @@
* <p>To compare this against a real image from the destination camera, the destination camera
* image then needs to be corrected for radial distortion before comparison or sampling.</p>
* <p>When ACAMERA_LENS_POSE_REFERENCE is GYROSCOPE, then this position is relative to
- * the center of the primary gyroscope on the device.</p>
+ * the center of the primary gyroscope on the device. The axis definitions are the same as
+ * with PRIMARY_CAMERA.</p>
*
* @see ACAMERA_LENS_DISTORTION
* @see ACAMERA_LENS_INTRINSIC_CALIBRATION
@@ -2418,13 +2421,15 @@
* </code></pre>
* <p>which can then be combined with the camera pose rotation
* <code>R</code> and translation <code>t</code> (ACAMERA_LENS_POSE_ROTATION and
- * ACAMERA_LENS_POSE_TRANSLATION, respective) to calculate the
+ * ACAMERA_LENS_POSE_TRANSLATION, respectively) to calculate the
* complete transform from world coordinates to pixel
* coordinates:</p>
- * <pre><code>P = [ K 0 * [ R t
- * 0 1 ] 0 1 ]
+ * <pre><code>P = [ K 0 * [ R -Rt
+ * 0 1 ] 0 1 ]
* </code></pre>
- * <p>and with <code>p_w</code> being a point in the world coordinate system
+ * <p>(Note the negation of poseTranslation when mapping from camera
+ * to world coordinates, and multiplication by the rotation).</p>
+ * <p>With <code>p_w</code> being a point in the world coordinate system
* and <code>p_s</code> being a point in the camera active pixel array
* coordinate system, and with the mapping including the
* homogeneous division by z:</p>
@@ -2446,6 +2451,13 @@
* activeArraySize rectangle), to determine the final pixel
* coordinate of the world point for processed (non-RAW)
* output buffers.</p>
+ * <p>For camera devices, the center of pixel <code>(x,y)</code> is located at
+ * coordinate <code>(x + 0.5, y + 0.5)</code>. So on a device with a
+ * precorrection active array of size <code>(10,10)</code>, the valid pixel
+ * indices go from <code>(0,0)-(9,9)</code>, and an perfectly-built camera would
+ * have an optical center at the exact center of the pixel grid, at
+ * coordinates <code>(5.0, 5.0)</code>, which is the top-left corner of pixel
+ * <code>(5,5)</code>.</p>
*
* @see ACAMERA_LENS_DISTORTION
* @see ACAMERA_LENS_POSE_ROTATION
@@ -3059,7 +3071,7 @@
* outputs will crop horizontally (pillarbox), and 16:9
* streams will match exactly. These additional crops will
* be centered within the crop region.</p>
- * <p>If the coordinate system is android.sensor.info.activeArraysSize, the width and height
+ * <p>If the coordinate system is ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE, the width and height
* of the crop region cannot be set to be smaller than
* <code>floor( activeArraySize.width / ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM )</code> and
* <code>floor( activeArraySize.height / ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM )</code>, respectively.</p>
@@ -4675,8 +4687,8 @@
ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE = // byte (acamera_metadata_enum_android_statistics_lens_shading_map_mode_t)
ACAMERA_STATISTICS_START + 16,
/**
- * <p>A control for selecting whether OIS position information is included in output
- * result metadata.</p>
+ * <p>A control for selecting whether optical stabilization (OIS) position
+ * information is included in output result metadata.</p>
*
* <p>Type: byte (acamera_metadata_enum_android_statistics_ois_data_mode_t)</p>
*
@@ -4686,6 +4698,12 @@
* <li>ACaptureRequest</li>
* </ul></p>
*
+ * <p>Since optical image stabilization generally involves motion much faster than the duration
+ * of individualq image exposure, multiple OIS samples can be included for a single capture
+ * result. For example, if the OIS reporting operates at 200 Hz, a typical camera operating
+ * at 30fps may have 6-7 OIS samples per capture result. This information can be combined
+ * with the rolling shutter skew to account for lens motion during image exposure in
+ * post-processing algorithms.</p>
*/
ACAMERA_STATISTICS_OIS_DATA_MODE = // byte (acamera_metadata_enum_android_statistics_ois_data_mode_t)
ACAMERA_STATISTICS_START + 17,
@@ -4717,11 +4735,15 @@
* </ul></p>
*
* <p>The array contains the amount of shifts in x direction, in pixels, based on OIS samples.
- * A positive value is a shift from left to right in active array coordinate system. For
- * example, if the optical center is (1000, 500) in active array coordinates, a shift of
- * (3, 0) puts the new optical center at (1003, 500).</p>
+ * A positive value is a shift from left to right in the pre-correction active array
+ * coordinate system. For example, if the optical center is (1000, 500) in pre-correction
+ * active array coordinates, a shift of (3, 0) puts the new optical center at (1003, 500).</p>
* <p>The number of shifts must match the number of timestamps in
* ACAMERA_STATISTICS_OIS_TIMESTAMPS.</p>
+ * <p>The OIS samples are not affected by whether lens distortion correction is enabled (on
+ * supporting devices). They are always reported in pre-correction active array coordinates,
+ * since the scaling of OIS shifts would depend on the specific spot on the sensor the shift
+ * is needed.</p>
*
* @see ACAMERA_STATISTICS_OIS_TIMESTAMPS
*/
@@ -4738,11 +4760,15 @@
* </ul></p>
*
* <p>The array contains the amount of shifts in y direction, in pixels, based on OIS samples.
- * A positive value is a shift from top to bottom in active array coordinate system. For
- * example, if the optical center is (1000, 500) in active array coordinates, a shift of
- * (0, 5) puts the new optical center at (1000, 505).</p>
+ * A positive value is a shift from top to bottom in pre-correction active array coordinate
+ * system. For example, if the optical center is (1000, 500) in active array coordinates, a
+ * shift of (0, 5) puts the new optical center at (1000, 505).</p>
* <p>The number of shifts must match the number of timestamps in
* ACAMERA_STATISTICS_OIS_TIMESTAMPS.</p>
+ * <p>The OIS samples are not affected by whether lens distortion correction is enabled (on
+ * supporting devices). They are always reported in pre-correction active array coordinates,
+ * since the scaling of OIS shifts would depend on the specific spot on the sensor the shift
+ * is needed.</p>
*
* @see ACAMERA_STATISTICS_OIS_TIMESTAMPS
*/
@@ -5432,16 +5458,34 @@
* any correction at all would slow down capture rate. Every output stream will have a
* similar amount of enhancement applied.</p>
* <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
- * applied to any RAW output. Metadata coordinates such as face rectangles or metering
- * regions are also not affected by correction.</p>
+ * applied to any RAW output.</p>
* <p>This control will be on by default on devices that support this control. Applications
* disabling distortion correction need to pay extra attention with the coordinate system of
* metering regions, crop region, and face rectangles. When distortion correction is OFF,
* metadata coordinates follow the coordinate system of
* ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE. When distortion is not OFF, metadata
- * coordinates follow the coordinate system of ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE.</p>
+ * coordinates follow the coordinate system of ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE. The
+ * camera device will map these metadata fields to match the corrected image produced by the
+ * camera device, for both capture requests and results. However, this mapping is not very
+ * precise, since rectangles do not generally map to rectangles when corrected. Only linear
+ * scaling between the active array and precorrection active array coordinates is
+ * performed. Applications that require precise correction of metadata need to undo that
+ * linear scaling, and apply a more complete correction that takes into the account the app's
+ * own requirements.</p>
+ * <p>The full list of metadata that is affected in this way by distortion correction is:</p>
+ * <ul>
+ * <li>ACAMERA_CONTROL_AF_REGIONS</li>
+ * <li>ACAMERA_CONTROL_AE_REGIONS</li>
+ * <li>ACAMERA_CONTROL_AWB_REGIONS</li>
+ * <li>ACAMERA_SCALER_CROP_REGION</li>
+ * <li>android.statistics.faces</li>
+ * </ul>
*
+ * @see ACAMERA_CONTROL_AE_REGIONS
+ * @see ACAMERA_CONTROL_AF_REGIONS
+ * @see ACAMERA_CONTROL_AWB_REGIONS
* @see ACAMERA_LENS_DISTORTION
+ * @see ACAMERA_SCALER_CROP_REGION
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index d41d3fd..bddf945 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -650,7 +650,8 @@
MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
- MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, MEDIA_MIMETYPE_AUDIO_AC4
+ MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
+ MEDIA_MIMETYPE_AUDIO_EAC3, MEDIA_MIMETYPE_AUDIO_AC4
};
const char *codecType = queryDecoders? "decoder" : "encoder";
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
index 73ecda1..a2594aa 100644
--- a/drm/libmediadrm/ICrypto.cpp
+++ b/drm/libmediadrm/ICrypto.cpp
@@ -225,8 +225,13 @@
void BnCrypto::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
uint32_t size = data.readInt32();
- vector.insertAt((size_t)0, size);
- data.read(vector.editArray(), size);
+ if (vector.insertAt((size_t)0, size) < 0) {
+ vector.clear();
+ }
+ if (data.read(vector.editArray(), size) != NO_ERROR) {
+ vector.clear();
+ android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
+ }
}
void BnCrypto::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index 70c281a..8a97299 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -21,6 +21,9 @@
libsoundtriggerservice \
libutils
+LOCAL_STATIC_LIBRARIES := \
+ libjsoncpp
+
# TODO oboeservice is the old folder name for aaudioservice. It will be changed.
LOCAL_C_INCLUDES := \
frameworks/av/services/audioflinger \
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index e3da259..a721b65 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -18,6 +18,8 @@
#define LOG_TAG "FLACExtractor"
#include <utils/Log.h>
+#include <stdint.h>
+
#include "FLACExtractor.h"
// libFLAC parser
#include "FLAC/stream_decoder.h"
@@ -124,7 +126,7 @@
// media buffers
size_t mMaxBufferSize;
MediaBufferGroup *mGroup;
- void (*mCopy)(short *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
+ void (*mCopy)(int16_t *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
// handle to underlying libFLAC parser
FLAC__StreamDecoder *mDecoder;
@@ -383,7 +385,7 @@
// These are candidates for optimization if needed.
static void copyMono8(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -393,7 +395,7 @@
}
static void copyStereo8(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -403,7 +405,7 @@
}
}
-static void copyMultiCh8(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
+static void copyMultiCh8(int16_t *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -413,7 +415,7 @@
}
static void copyMono16(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -423,7 +425,7 @@
}
static void copyStereo16(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -433,7 +435,7 @@
}
}
-static void copyMultiCh16(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
+static void copyMultiCh16(int16_t *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -445,7 +447,7 @@
// 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
static void copyMono24(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -455,7 +457,7 @@
}
static void copyStereo24(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -465,7 +467,7 @@
}
}
-static void copyMultiCh24(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
+static void copyMultiCh24(int16_t *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -475,7 +477,7 @@
}
static void copyTrespass(
- short * /* dst */,
+ int16_t * /* dst */,
const int *[FLACParser::kMaxChannels] /* src */,
unsigned /* nSamples */,
unsigned /* nChannels */) {
@@ -592,7 +594,7 @@
static const struct {
unsigned mChannels;
unsigned mBitsPerSample;
- void (*mCopy)(short *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
+ void (*mCopy)(int16_t *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
} table[] = {
{ 1, 8, copyMono8 },
{ 2, 8, copyStereo8 },
@@ -635,7 +637,7 @@
{
CHECK(mGroup == NULL);
mGroup = new MediaBufferGroup;
- mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(short);
+ mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(int16_t);
mGroup->add_buffer(MediaBufferBase::Create(mMaxBufferSize));
}
@@ -688,9 +690,9 @@
if (err != OK) {
return NULL;
}
- size_t bufferSize = blocksize * getChannels() * sizeof(short);
+ size_t bufferSize = blocksize * getChannels() * sizeof(int16_t);
CHECK(bufferSize <= mMaxBufferSize);
- short *data = (short *) buffer->data();
+ int16_t *data = (int16_t *) buffer->data();
buffer->set_range(0, bufferSize);
// copy PCM from FLAC write buffer to our media buffer, with interleaving
(*mCopy)(data, mWriteBuffer, blocksize, getChannels());
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 44b6a3d..fe9f99c 100644
--- a/media/extractors/mp4/MPEG4Extractor.cpp
+++ b/media/extractors/mp4/MPEG4Extractor.cpp
@@ -313,6 +313,9 @@
case FOURCC('s', 'a', 'w', 'b'):
return MEDIA_MIMETYPE_AUDIO_AMR_WB;
+ case FOURCC('e', 'c', '-', '3'):
+ return MEDIA_MIMETYPE_AUDIO_EAC3;
+
case FOURCC('m', 'p', '4', 'v'):
return MEDIA_MIMETYPE_VIDEO_MPEG4;
@@ -2438,13 +2441,19 @@
case FOURCC('a', 'c', '-', '3'):
{
*offset += chunk_size;
- return parseAC3SampleEntry(data_offset);
+ return parseAC3SpecificBox(data_offset);
+ }
+
+ case FOURCC('e', 'c', '-', '3'):
+ {
+ *offset += chunk_size;
+ return parseEAC3SpecificBox(data_offset);
}
case FOURCC('a', 'c', '-', '4'):
{
*offset += chunk_size;
- return parseAC4SampleEntry(data_offset);
+ return parseAC4SpecificBox(data_offset);
}
case FOURCC('f', 't', 'y', 'p'):
@@ -2518,43 +2527,43 @@
return OK;
}
-status_t MPEG4Extractor::parseAC4SampleEntry(off64_t offset) {
+status_t MPEG4Extractor::parseChannelCountSampleRate(
+ off64_t *offset, uint16_t *channelCount, uint16_t *sampleRate) {
// skip 16 bytes:
// + 6-byte reserved,
// + 2-byte data reference index,
// + 8-byte reserved
- offset += 16;
- uint16_t channelCount;
- if (!mDataSource->getUInt16(offset, &channelCount)) {
- ALOGE("MPEG4Extractor: error while reading ac-4 block: cannot read channel count");
+ *offset += 16;
+ if (!mDataSource->getUInt16(*offset, channelCount)) {
+ ALOGE("MPEG4Extractor: error while reading sample entry box: cannot read channel count");
return ERROR_MALFORMED;
}
// skip 8 bytes:
// + 2-byte channelCount,
// + 2-byte sample size,
// + 4-byte reserved
- offset += 8;
- uint16_t sampleRate;
- if (!mDataSource->getUInt16(offset, &sampleRate)) {
- ALOGE("MPEG4Extractor: error while reading ac-4 block: cannot read sample rate");
+ *offset += 8;
+ if (!mDataSource->getUInt16(*offset, sampleRate)) {
+ ALOGE("MPEG4Extractor: error while reading sample entry box: cannot read sample rate");
return ERROR_MALFORMED;
}
-
// skip 4 bytes:
// + 2-byte sampleRate,
// + 2-byte reserved
- offset += 4;
-
- if (mLastTrack == NULL) {
- return ERROR_MALFORMED;
- }
- mLastTrack->meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC4);
- mLastTrack->meta.setInt32(kKeyChannelCount, channelCount);
- mLastTrack->meta.setInt32(kKeySampleRate, sampleRate);
- return parseAC4SpecificBox(offset);
+ *offset += 4;
+ return OK;
}
status_t MPEG4Extractor::parseAC4SpecificBox(off64_t offset) {
+ if (mLastTrack == NULL) {
+ return ERROR_MALFORMED;
+ }
+
+ uint16_t sampleRate, channelCount;
+ status_t status;
+ if ((status = parseChannelCountSampleRate(&offset, &channelCount, &sampleRate)) != OK) {
+ return status;
+ }
uint32_t size;
// + 4-byte size
// + 4-byte type
@@ -2593,39 +2602,185 @@
return ERROR_MALFORMED;
}
+ mLastTrack->meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC4);
+ mLastTrack->meta.setInt32(kKeyChannelCount, channelCount);
+ mLastTrack->meta.setInt32(kKeySampleRate, sampleRate);
return OK;
}
-status_t MPEG4Extractor::parseAC3SampleEntry(off64_t offset) {
- // skip 16 bytes:
- // + 6-byte reserved,
- // + 2-byte data reference index,
- // + 8-byte reserved
- offset += 16;
- uint16_t channelCount;
- if (!mDataSource->getUInt16(offset, &channelCount)) {
- return ERROR_MALFORMED;
- }
- // skip 8 bytes:
- // + 2-byte channelCount,
- // + 2-byte sample size,
- // + 4-byte reserved
- offset += 8;
- uint16_t sampleRate;
- if (!mDataSource->getUInt16(offset, &sampleRate)) {
- ALOGE("MPEG4Extractor: error while reading ac-3 block: cannot read sample rate");
+status_t MPEG4Extractor::parseEAC3SpecificBox(off64_t offset) {
+ if (mLastTrack == NULL) {
return ERROR_MALFORMED;
}
- // skip 4 bytes:
- // + 2-byte sampleRate,
- // + 2-byte reserved
+ uint16_t sampleRate, channels;
+ status_t status;
+ if ((status = parseChannelCountSampleRate(&offset, &channels, &sampleRate)) != OK) {
+ return status;
+ }
+ uint32_t size;
+ // + 4-byte size
+ // + 4-byte type
+ // + 3-byte payload
+ const uint32_t kEAC3SpecificBoxMinSize = 11;
+ // 13 + 3 + (8 * (2 + 5 + 5 + 3 + 1 + 3 + 4 + (14 * 9 + 1))) bits == 152 bytes theoretical max
+ // calculated from the required bits read below as well as the maximum number of independent
+ // and dependant sub streams you can have
+ const uint32_t kEAC3SpecificBoxMaxSize = 152;
+ if (!mDataSource->getUInt32(offset, &size) ||
+ size < kEAC3SpecificBoxMinSize ||
+ size > kEAC3SpecificBoxMaxSize) {
+ ALOGE("MPEG4Extractor: error while reading eac-3 block: cannot read specific box size");
+ return ERROR_MALFORMED;
+ }
+
offset += 4;
- return parseAC3SpecificBox(offset, sampleRate);
+ uint32_t type;
+ if (!mDataSource->getUInt32(offset, &type) || type != FOURCC('d', 'e', 'c', '3')) {
+ ALOGE("MPEG4Extractor: error while reading eac-3 specific block: header not dec3");
+ return ERROR_MALFORMED;
+ }
+
+ offset += 4;
+ uint8_t* chunk = new (std::nothrow) uint8_t[size];
+ if (chunk == NULL) {
+ return ERROR_MALFORMED;
+ }
+
+ if (mDataSource->readAt(offset, chunk, size) != (ssize_t)size) {
+ ALOGE("MPEG4Extractor: error while reading eac-3 specific block: bitstream fields");
+ delete[] chunk;
+ return ERROR_MALFORMED;
+ }
+
+ ABitReader br(chunk, size);
+ static const unsigned channelCountTable[] = {2, 1, 2, 3, 3, 4, 4, 5};
+ static const unsigned sampleRateTable[] = {48000, 44100, 32000};
+
+ if (br.numBitsLeft() < 16) {
+ delete[] chunk;
+ return ERROR_MALFORMED;
+ }
+ unsigned data_rate = br.getBits(13);
+ ALOGV("EAC3 data rate = %d", data_rate);
+
+ unsigned num_ind_sub = br.getBits(3) + 1;
+ ALOGV("EAC3 independant substreams = %d", num_ind_sub);
+ if (br.numBitsLeft() < (num_ind_sub * 23)) {
+ delete[] chunk;
+ return ERROR_MALFORMED;
+ }
+
+ unsigned channelCount = 0;
+ for (unsigned i = 0; i < num_ind_sub; i++) {
+ unsigned fscod = br.getBits(2);
+ if (fscod == 3) {
+ ALOGE("Incorrect fscod (3) in EAC3 header");
+ delete[] chunk;
+ return ERROR_MALFORMED;
+ }
+ unsigned boxSampleRate = sampleRateTable[fscod];
+ if (boxSampleRate != sampleRate) {
+ ALOGE("sample rate mismatch: boxSampleRate = %d, sampleRate = %d",
+ boxSampleRate, sampleRate);
+ delete[] chunk;
+ return ERROR_MALFORMED;
+ }
+
+ unsigned bsid = br.getBits(5);
+ if (bsid < 8) {
+ ALOGW("Incorrect bsid in EAC3 header. Possibly AC-3?");
+ delete[] chunk;
+ return ERROR_MALFORMED;
+ }
+
+ // skip
+ br.skipBits(2);
+ unsigned bsmod = br.getBits(3);
+ unsigned acmod = br.getBits(3);
+ unsigned lfeon = br.getBits(1);
+ // we currently only support the first stream
+ if (i == 0)
+ channelCount = channelCountTable[acmod] + lfeon;
+ ALOGV("bsmod = %d, acmod = %d, lfeon = %d", bsmod, acmod, lfeon);
+
+ br.skipBits(3);
+ unsigned num_dep_sub = br.getBits(4);
+ ALOGV("EAC3 dependant substreams = %d", num_dep_sub);
+ if (num_dep_sub != 0) {
+ if (br.numBitsLeft() < 9) {
+ delete[] chunk;
+ return ERROR_MALFORMED;
+ }
+ static const char* chan_loc_tbl[] = { "Lc/Rc","Lrs/Rrs","Cs","Ts","Lsd/Rsd",
+ "Lw/Rw","Lvh/Rvh","Cvh","Lfe2" };
+ unsigned chan_loc = br.getBits(9);
+ unsigned mask = 1;
+ for (unsigned j = 0; j < 9; j++, mask <<= 1) {
+ if ((chan_loc & mask) != 0) {
+ // we currently only support the first stream
+ if (i == 0) {
+ channelCount++;
+ // these are 2 channels in the mask
+ if (j == 0 || j == 1 || j == 4 || j == 5 || j == 6) {
+ channelCount++;
+ }
+ }
+ ALOGV(" %s", chan_loc_tbl[j]);
+ }
+ }
+ } else {
+ if (br.numBitsLeft() == 0) {
+ delete[] chunk;
+ return ERROR_MALFORMED;
+ }
+ br.skipBits(1);
+ }
+ }
+
+ if (br.numBitsLeft() != 0) {
+ if (br.numBitsLeft() < 8) {
+ delete[] chunk;
+ return ERROR_MALFORMED;
+ }
+ unsigned mask = br.getBits(8);
+ for (unsigned i = 0; i < 8; i++) {
+ if (((0x1 << i) && mask) == 0)
+ continue;
+
+ if (br.numBitsLeft() < 8) {
+ delete[] chunk;
+ return ERROR_MALFORMED;
+ }
+ switch (i) {
+ case 0: {
+ unsigned complexity = br.getBits(8);
+ ALOGV("Found a JOC stream with complexity = %d", complexity);
+ }break;
+ default: {
+ br.skipBits(8);
+ }break;
+ }
+ }
+ }
+ mLastTrack->meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_EAC3);
+ mLastTrack->meta.setInt32(kKeyChannelCount, channelCount);
+ mLastTrack->meta.setInt32(kKeySampleRate, sampleRate);
+
+ delete[] chunk;
+ return OK;
}
-status_t MPEG4Extractor::parseAC3SpecificBox(
- off64_t offset, uint16_t sampleRate) {
+status_t MPEG4Extractor::parseAC3SpecificBox(off64_t offset) {
+ if (mLastTrack == NULL) {
+ return ERROR_MALFORMED;
+ }
+
+ uint16_t sampleRate, channels;
+ status_t status;
+ if ((status = parseChannelCountSampleRate(&offset, &channels, &sampleRate)) != OK) {
+ return status;
+ }
uint32_t size;
// + 4-byte size
// + 4-byte type
@@ -2680,9 +2835,6 @@
unsigned lfeon = br.getBits(1);
unsigned channelCount = channelCountTable[acmod] + lfeon;
- if (mLastTrack == NULL) {
- return ERROR_MALFORMED;
- }
mLastTrack->meta.setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_AC3);
mLastTrack->meta.setInt32(kKeyChannelCount, channelCount);
mLastTrack->meta.setInt32(kKeySampleRate, sampleRate);
diff --git a/media/extractors/mp4/MPEG4Extractor.h b/media/extractors/mp4/MPEG4Extractor.h
index ed70aa7..a4a5684 100644
--- a/media/extractors/mp4/MPEG4Extractor.h
+++ b/media/extractors/mp4/MPEG4Extractor.h
@@ -139,9 +139,10 @@
Track *findTrackByMimePrefix(const char *mimePrefix);
- status_t parseAC3SampleEntry(off64_t offset);
- status_t parseAC3SpecificBox(off64_t offset, uint16_t sampleRate);
- status_t parseAC4SampleEntry(off64_t offset);
+ status_t parseChannelCountSampleRate(
+ off64_t *offset, uint16_t *channelCount, uint16_t *sampleRate);
+ status_t parseAC3SpecificBox(off64_t offset);
+ status_t parseEAC3SpecificBox(off64_t offset);
status_t parseAC4SpecificBox(off64_t offset);
MPEG4Extractor(const MPEG4Extractor &);
diff --git a/media/libaaudio/examples/loopback/src/loopback.cpp b/media/libaaudio/examples/loopback/src/loopback.cpp
index 91ebf73..84f9c22 100644
--- a/media/libaaudio/examples/loopback/src/loopback.cpp
+++ b/media/libaaudio/examples/loopback/src/loopback.cpp
@@ -338,7 +338,7 @@
aaudio_sharing_mode_t requestedInputSharingMode = AAUDIO_SHARING_MODE_SHARED;
int requestedInputChannelCount = NUM_INPUT_CHANNELS;
aaudio_format_t requestedInputFormat = AAUDIO_FORMAT_UNSPECIFIED;
- int32_t requestedInputCapacity = -1;
+ int32_t requestedInputCapacity = AAUDIO_UNSPECIFIED;
aaudio_performance_mode_t inputPerformanceLevel = AAUDIO_PERFORMANCE_MODE_LOW_LATENCY;
int32_t outputFramesPerBurst = 0;
@@ -459,15 +459,8 @@
argParser.setPerformanceMode(inputPerformanceLevel);
argParser.setChannelCount(requestedInputChannelCount);
argParser.setSharingMode(requestedInputSharingMode);
-
- // Make sure the input buffer has plenty of capacity.
- // Extra capacity on input should not increase latency if we keep it drained.
- int32_t inputBufferCapacity = requestedInputCapacity;
- if (inputBufferCapacity < 0) {
- int32_t outputBufferCapacity = AAudioStream_getBufferCapacityInFrames(outputStream);
- inputBufferCapacity = 2 * outputBufferCapacity;
- }
- argParser.setBufferCapacity(inputBufferCapacity);
+ // Warning! If you change input capacity then you may not get a FAST track on Legacy path.
+ argParser.setBufferCapacity(requestedInputCapacity);
result = recorder.open(argParser);
if (result != AAUDIO_OK) {
diff --git a/media/libaudioclient/AudioEffect.cpp b/media/libaudioclient/AudioEffect.cpp
index b1cb0e7..0641b6e 100644
--- a/media/libaudioclient/AudioEffect.cpp
+++ b/media/libaudioclient/AudioEffect.cpp
@@ -430,14 +430,15 @@
}
status_t AudioEffect::getEffectDescriptor(const effect_uuid_t *uuid,
- effect_descriptor_t *descriptor) /*const*/
+ const effect_uuid_t *type,
+ uint32_t preferredTypeFlag,
+ effect_descriptor_t *descriptor)
{
const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
if (af == 0) return PERMISSION_DENIED;
- return af->getEffectDescriptor(uuid, descriptor);
+ return af->getEffectDescriptor(uuid, type, preferredTypeFlag, descriptor);
}
-
status_t AudioEffect::queryDefaultPreProcessing(audio_session_t audioSession,
effect_descriptor_t *descriptors,
uint32_t *count)
@@ -446,6 +447,55 @@
if (aps == 0) return PERMISSION_DENIED;
return aps->queryDefaultPreProcessing(audioSession, descriptors, count);
}
+
+status_t AudioEffect::newEffectUniqueId(audio_unique_id_t* id)
+{
+ const sp<IAudioFlinger>& af = AudioSystem::get_audio_flinger();
+ if (af == 0) return PERMISSION_DENIED;
+ *id = af->newAudioUniqueId(AUDIO_UNIQUE_ID_USE_EFFECT);
+ return NO_ERROR;
+}
+
+status_t AudioEffect::addStreamDefaultEffect(const char *typeStr,
+ const String16& opPackageName,
+ const char *uuidStr,
+ int32_t priority,
+ audio_usage_t usage,
+ audio_unique_id_t *id)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+
+ if (typeStr == NULL && uuidStr == NULL) return BAD_VALUE;
+
+ // Convert type & uuid from string to effect_uuid_t.
+ effect_uuid_t type;
+ if (typeStr != NULL) {
+ status_t res = stringToGuid(typeStr, &type);
+ if (res != OK) return res;
+ } else {
+ type = *EFFECT_UUID_NULL;
+ }
+
+ effect_uuid_t uuid;
+ if (uuidStr != NULL) {
+ status_t res = stringToGuid(uuidStr, &uuid);
+ if (res != OK) return res;
+ } else {
+ uuid = *EFFECT_UUID_NULL;
+ }
+
+ return aps->addStreamDefaultEffect(&type, opPackageName, &uuid, priority, usage, id);
+}
+
+status_t AudioEffect::removeStreamDefaultEffect(audio_unique_id_t id)
+{
+ const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
+ if (aps == 0) return PERMISSION_DENIED;
+
+ return aps->removeStreamDefaultEffect(id);
+}
+
// -------------------------------------------------------------------------
status_t AudioEffect::stringToGuid(const char *str, effect_uuid_t *guid)
diff --git a/media/libaudioclient/IAudioFlinger.cpp b/media/libaudioclient/IAudioFlinger.cpp
index 84e8bee..00678c2 100644
--- a/media/libaudioclient/IAudioFlinger.cpp
+++ b/media/libaudioclient/IAudioFlinger.cpp
@@ -598,14 +598,18 @@
}
virtual status_t getEffectDescriptor(const effect_uuid_t *pUuid,
- effect_descriptor_t *pDescriptor) const
+ const effect_uuid_t *pType,
+ uint32_t preferredTypeFlag,
+ effect_descriptor_t *pDescriptor) const
{
- if (pUuid == NULL || pDescriptor == NULL) {
+ if (pUuid == NULL || pType == NULL || pDescriptor == NULL) {
return BAD_VALUE;
}
Parcel data, reply;
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
data.write(pUuid, sizeof(effect_uuid_t));
+ data.write(pType, sizeof(effect_uuid_t));
+ data.writeUint32(preferredTypeFlag);
status_t status = remote()->transact(GET_EFFECT_DESCRIPTOR, data, &reply);
if (status != NO_ERROR) {
return status;
@@ -634,10 +638,10 @@
sp<IEffect> effect;
if (pDesc == NULL) {
- return effect;
if (status != NULL) {
*status = BAD_VALUE;
}
+ return effect;
}
data.writeInterfaceToken(IAudioFlinger::getInterfaceDescriptor());
@@ -1277,8 +1281,11 @@
CHECK_INTERFACE(IAudioFlinger, data, reply);
effect_uuid_t uuid;
data.read(&uuid, sizeof(effect_uuid_t));
+ effect_uuid_t type;
+ data.read(&type, sizeof(effect_uuid_t));
+ uint32_t preferredTypeFlag = data.readUint32();
effect_descriptor_t desc = {};
- status_t status = getEffectDescriptor(&uuid, &desc);
+ status_t status = getEffectDescriptor(&uuid, &type, preferredTypeFlag, &desc);
reply->writeInt32(status);
if (status == NO_ERROR) {
reply->write(&desc, sizeof(effect_descriptor_t));
diff --git a/media/libaudioclient/IAudioPolicyService.cpp b/media/libaudioclient/IAudioPolicyService.cpp
index 73a8b74..abf74f8 100644
--- a/media/libaudioclient/IAudioPolicyService.cpp
+++ b/media/libaudioclient/IAudioPolicyService.cpp
@@ -81,7 +81,9 @@
GET_MASTER_MONO,
GET_STREAM_VOLUME_DB,
GET_SURROUND_FORMATS,
- SET_SURROUND_FORMAT_ENABLED
+ SET_SURROUND_FORMAT_ENABLED,
+ ADD_STREAM_DEFAULT_EFFECT,
+ REMOVE_STREAM_DEFAULT_EFFECT
};
#define MAX_ITEMS_PER_LIST 1024
@@ -866,6 +868,42 @@
}
return reply.readInt32();
}
+
+ virtual status_t addStreamDefaultEffect(const effect_uuid_t *type,
+ const String16& opPackageName,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ audio_usage_t usage,
+ audio_unique_id_t* id)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.write(type, sizeof(effect_uuid_t));
+ data.writeString16(opPackageName);
+ data.write(uuid, sizeof(effect_uuid_t));
+ data.writeInt32(priority);
+ data.writeInt32((int32_t) usage);
+ status_t status = remote()->transact(ADD_STREAM_DEFAULT_EFFECT, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ status = static_cast <status_t> (reply.readInt32());
+ *id = reply.readInt32();
+ return status;
+ }
+
+ virtual status_t removeStreamDefaultEffect(audio_unique_id_t id)
+ {
+ Parcel data, reply;
+ data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
+ data.writeInt32(id);
+ status_t status = remote()->transact(REMOVE_STREAM_DEFAULT_EFFECT, data, &reply);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ return static_cast <status_t> (reply.readInt32());
+ }
+
};
IMPLEMENT_META_INTERFACE(AudioPolicyService, "android.media.IAudioPolicyService");
@@ -1561,6 +1599,43 @@
return NO_ERROR;
}
+ case ADD_STREAM_DEFAULT_EFFECT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ effect_uuid_t type;
+ status_t status = data.read(&type, sizeof(effect_uuid_t));
+ if (status != NO_ERROR) {
+ return status;
+ }
+ String16 opPackageName;
+ status = data.readString16(&opPackageName);
+ if (status != NO_ERROR) {
+ return status;
+ }
+ effect_uuid_t uuid;
+ status = data.read(&uuid, sizeof(effect_uuid_t));
+ if (status != NO_ERROR) {
+ return status;
+ }
+ int32_t priority = data.readInt32();
+ audio_usage_t usage = (audio_usage_t) data.readInt32();
+ audio_unique_id_t id = 0;
+ reply->writeInt32(static_cast <int32_t>(addStreamDefaultEffect(&type,
+ opPackageName,
+ &uuid,
+ priority,
+ usage,
+ &id)));
+ reply->writeInt32(id);
+ return NO_ERROR;
+ }
+
+ case REMOVE_STREAM_DEFAULT_EFFECT: {
+ CHECK_INTERFACE(IAudioPolicyService, data, reply);
+ audio_unique_id_t id = static_cast<audio_unique_id_t>(data.readInt32());
+ reply->writeInt32(static_cast <int32_t>(removeStreamDefaultEffect(id)));
+ return NO_ERROR;
+ }
+
default:
return BBinder::onTransact(code, data, reply, flags);
}
diff --git a/media/libaudioclient/include/media/AudioEffect.h b/media/libaudioclient/include/media/AudioEffect.h
index bfc068b..c97f783 100644
--- a/media/libaudioclient/include/media/AudioEffect.h
+++ b/media/libaudioclient/include/media/AudioEffect.h
@@ -90,27 +90,34 @@
*/
static status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor);
-
/*
- * Returns the descriptor for the specified effect uuid.
+ * Returns a descriptor for the specified effect uuid or type.
+ *
+ * Lookup an effect by uuid, or if that's unspecified (EFFECT_UUID_NULL),
+ * do so by type and preferred flags instead.
*
* Parameters:
* uuid: pointer to effect uuid.
+ * type: pointer to effect type uuid.
+ * preferredTypeFlags: if multiple effects of the given type exist,
+ * one with a matching type flag will be chosen over one without.
+ * Use EFFECT_FLAG_TYPE_MASK to indicate no preference.
* descriptor: address where the effect descriptor should be returned.
*
* Returned status (from utils/Errors.h) can be:
* NO_ERROR successful operation.
* PERMISSION_DENIED could not get AudioFlinger interface
* NO_INIT effect library failed to initialize
- * BAD_VALUE invalid uuid or descriptor pointers
+ * BAD_VALUE invalid type or descriptor pointers
* NAME_NOT_FOUND no effect with this uuid found
*
* Returned value
* *descriptor updated with effect descriptor
*/
static status_t getEffectDescriptor(const effect_uuid_t *uuid,
- effect_descriptor_t *descriptor) /*const*/;
-
+ const effect_uuid_t *type,
+ uint32_t preferredTypeFlag,
+ effect_descriptor_t *descriptor);
/*
* Returns a list of descriptors corresponding to the pre processings enabled by default
@@ -144,6 +151,79 @@
uint32_t *count);
/*
+ * Gets a new system-wide unique effect id.
+ *
+ * Parameters:
+ * id: The address to return the generated id.
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * NO_ERROR successful operation.
+ * PERMISSION_DENIED could not get AudioFlinger interface
+ * or caller lacks required permissions.
+ * Returned value
+ * *id: The new unique system-wide effect id.
+ */
+ static status_t newEffectUniqueId(audio_unique_id_t* id);
+
+ /*
+ * Static methods for adding/removing system-wide effects.
+ */
+
+ /*
+ * Adds an effect to the list of default output effects for a given stream type.
+ *
+ * If the effect is no longer available when a stream of the given type
+ * is created, the system will continue without adding it.
+ *
+ * Parameters:
+ * typeStr: Type uuid of effect to be a default: can be null if uuidStr is specified.
+ * This may correspond to the OpenSL ES interface implemented by this effect,
+ * or could be some vendor-defined type.
+ * opPackageName: The package name used for app op checks.
+ * uuidStr: Uuid of effect to be a default: can be null if type is specified.
+ * This uuid corresponds to a particular implementation of an effect type.
+ * Note if both uuidStr and typeStr are specified, typeStr is ignored.
+ * priority: Requested priority for effect control: the priority level corresponds to the
+ * value of priority parameter: negative values indicate lower priorities, positive
+ * values higher priorities, 0 being the normal priority.
+ * usage: The usage this effect should be a default for. Unrecognized values will be
+ * treated as AUDIO_USAGE_UNKNOWN.
+ * id: Address where the system-wide unique id of the default effect should be returned.
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * NO_ERROR successful operation.
+ * PERMISSION_DENIED could not get AudioFlinger interface
+ * or caller lacks required permissions.
+ * NO_INIT effect library failed to initialize.
+ * BAD_VALUE invalid type uuid or implementation uuid.
+ * NAME_NOT_FOUND no effect with this uuid or type found.
+ *
+ * Returned value
+ * *id: The system-wide unique id of the added default effect.
+ */
+ static status_t addStreamDefaultEffect(const char* typeStr,
+ const String16& opPackageName,
+ const char* uuidStr,
+ int32_t priority,
+ audio_usage_t usage,
+ audio_unique_id_t* id);
+
+ /*
+ * Removes an effect from the list of default output effects for a given stream type.
+ *
+ * Parameters:
+ * id: The system-wide unique id of the effect that should no longer be a default.
+ *
+ * Returned status (from utils/Errors.h) can be:
+ * NO_ERROR successful operation.
+ * PERMISSION_DENIED could not get AudioFlinger interface
+ * or caller lacks required permissions.
+ * NO_INIT effect library failed to initialize.
+ * BAD_VALUE invalid id.
+ */
+ static status_t removeStreamDefaultEffect(audio_unique_id_t id);
+
+ /*
* Events used by callback function (effect_callback_t).
*/
enum event_type {
diff --git a/media/libaudioclient/include/media/AudioPolicyHelper.h b/media/libaudioclient/include/media/AudioPolicyHelper.h
index 73ee0a7..35d2e85 100644
--- a/media/libaudioclient/include/media/AudioPolicyHelper.h
+++ b/media/libaudioclient/include/media/AudioPolicyHelper.h
@@ -19,6 +19,43 @@
#include <system/audio.h>
static inline
+audio_stream_type_t audio_usage_to_stream_type(const audio_usage_t usage)
+{
+ switch(usage) {
+ case AUDIO_USAGE_MEDIA:
+ case AUDIO_USAGE_GAME:
+ case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
+ case AUDIO_USAGE_ASSISTANT:
+ return AUDIO_STREAM_MUSIC;
+ case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
+ return AUDIO_STREAM_ACCESSIBILITY;
+ case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
+ return AUDIO_STREAM_SYSTEM;
+ case AUDIO_USAGE_VOICE_COMMUNICATION:
+ return AUDIO_STREAM_VOICE_CALL;
+
+ case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
+ return AUDIO_STREAM_DTMF;
+
+ case AUDIO_USAGE_ALARM:
+ return AUDIO_STREAM_ALARM;
+ case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
+ return AUDIO_STREAM_RING;
+
+ case AUDIO_USAGE_NOTIFICATION:
+ case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
+ case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
+ case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
+ case AUDIO_USAGE_NOTIFICATION_EVENT:
+ return AUDIO_STREAM_NOTIFICATION;
+
+ case AUDIO_USAGE_UNKNOWN:
+ default:
+ return AUDIO_STREAM_MUSIC;
+ }
+}
+
+static inline
audio_stream_type_t audio_attributes_to_stream_type(const audio_attributes_t *attr)
{
// flags to stream type mapping
@@ -30,38 +67,7 @@
}
// usage to stream type mapping
- switch (attr->usage) {
- case AUDIO_USAGE_MEDIA:
- case AUDIO_USAGE_GAME:
- case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
- case AUDIO_USAGE_ASSISTANT:
- return AUDIO_STREAM_MUSIC;
- case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
- return AUDIO_STREAM_ACCESSIBILITY;
- case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
- return AUDIO_STREAM_SYSTEM;
- case AUDIO_USAGE_VOICE_COMMUNICATION:
- return AUDIO_STREAM_VOICE_CALL;
-
- case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
- return AUDIO_STREAM_DTMF;
-
- case AUDIO_USAGE_ALARM:
- return AUDIO_STREAM_ALARM;
- case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
- return AUDIO_STREAM_RING;
-
- case AUDIO_USAGE_NOTIFICATION:
- case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
- case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
- case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
- case AUDIO_USAGE_NOTIFICATION_EVENT:
- return AUDIO_STREAM_NOTIFICATION;
-
- case AUDIO_USAGE_UNKNOWN:
- default:
- return AUDIO_STREAM_MUSIC;
- }
+ return audio_usage_to_stream_type(attr->usage);
}
static inline
diff --git a/media/libaudioclient/include/media/IAudioFlinger.h b/media/libaudioclient/include/media/IAudioFlinger.h
index e6bf72f..31326ab 100644
--- a/media/libaudioclient/include/media/IAudioFlinger.h
+++ b/media/libaudioclient/include/media/IAudioFlinger.h
@@ -428,7 +428,9 @@
virtual status_t queryEffect(uint32_t index, effect_descriptor_t *pDescriptor) const = 0;
virtual status_t getEffectDescriptor(const effect_uuid_t *pEffectUUID,
- effect_descriptor_t *pDescriptor) const = 0;
+ const effect_uuid_t *pTypeUUID,
+ uint32_t preferredTypeFlag,
+ effect_descriptor_t *pDescriptor) const = 0;
virtual sp<IEffect> createEffect(
effect_descriptor_t *pDesc,
diff --git a/media/libaudioclient/include/media/IAudioPolicyService.h b/media/libaudioclient/include/media/IAudioPolicyService.h
index cdbb876..c2899f8 100644
--- a/media/libaudioclient/include/media/IAudioPolicyService.h
+++ b/media/libaudioclient/include/media/IAudioPolicyService.h
@@ -109,6 +109,13 @@
virtual status_t queryDefaultPreProcessing(audio_session_t audioSession,
effect_descriptor_t *descriptors,
uint32_t *count) = 0;
+ virtual status_t addStreamDefaultEffect(const effect_uuid_t *type,
+ const String16& opPackageName,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ audio_usage_t usage,
+ audio_unique_id_t* id) = 0;
+ virtual status_t removeStreamDefaultEffect(audio_unique_id_t id) = 0;
// Check if offload is possible for given format, stream type, sample rate,
// bit rate, duration, video and streaming or offload property is enabled
virtual bool isOffloadSupported(const audio_offload_info_t& info) = 0;
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index b23e018..bfa80e8 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -192,7 +192,17 @@
const native_handle *handle = hidlInfo.sharedMemory.handle();
if (handle->numFds > 0) {
info->shared_memory_fd = handle->data[0];
+#if MAJOR_VERSION == 4
+ info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
+#endif
info->buffer_size_frames = hidlInfo.bufferSizeFrames;
+ // Negative buffer size frame was a hack in O and P to
+ // indicate that the buffer is shareable to applications
+ if (info->buffer_size_frames < 0) {
+ info->buffer_size_frames *= -1;
+ info->flags = audio_mmap_buffer_flag(
+ info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
+ }
info->burst_size_frames = hidlInfo.burstSizeFrames;
// info->shared_memory_address is not needed in HIDL context
info->shared_memory_address = NULL;
diff --git a/media/libaudioprocessing/include/media/AudioResamplerPublic.h b/media/libaudioprocessing/include/media/AudioResamplerPublic.h
index 055f724..50ca33d 100644
--- a/media/libaudioprocessing/include/media/AudioResamplerPublic.h
+++ b/media/libaudioprocessing/include/media/AudioResamplerPublic.h
@@ -104,8 +104,8 @@
const AudioPlaybackRate &pr2) {
return fabs(pr1.mSpeed - pr2.mSpeed) < AUDIO_TIMESTRETCH_SPEED_MIN_DELTA &&
fabs(pr1.mPitch - pr2.mPitch) < AUDIO_TIMESTRETCH_PITCH_MIN_DELTA &&
- pr2.mStretchMode == pr2.mStretchMode &&
- pr2.mFallbackMode == pr2.mFallbackMode;
+ pr1.mStretchMode == pr2.mStretchMode &&
+ pr1.mFallbackMode == pr2.mFallbackMode;
}
static inline bool isAudioPlaybackRateValid(const AudioPlaybackRate &playbackRate) {
diff --git a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
index 9d29cf1..d61efd3 100644
--- a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
+++ b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
@@ -30,6 +30,26 @@
#include <audio_effects/effect_loudnessenhancer.h>
#include "dsp/core/dynamic_range_compression.h"
+// BUILD_FLOAT targets building a float effect instead of the legacy int16_t effect.
+#define BUILD_FLOAT
+
+#ifdef BUILD_FLOAT
+
+static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_FLOAT;
+
+#else
+
+static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_16_BIT;
+
+static inline int16_t clamp16(int32_t sample)
+{
+ if ((sample>>15) ^ (sample>>31))
+ sample = 0x7FFF ^ (sample>>31);
+ return sample;
+}
+
+#endif // BUILD_FLOAT
+
extern "C" {
// effect_handle_t interface implementation for LE effect
@@ -80,13 +100,6 @@
}
}
-static inline int16_t clamp16(int32_t sample)
-{
- if ((sample>>15) ^ (sample>>31))
- sample = 0x7FFF ^ (sample>>31);
- return sample;
-}
-
//----------------------------------------------------------------------------
// LE_setConfig()
//----------------------------------------------------------------------------
@@ -111,7 +124,7 @@
if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
- if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
+ if (pConfig->inputCfg.format != kProcessFormat) return -EINVAL;
pContext->mConfig = *pConfig;
@@ -159,7 +172,7 @@
pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
- pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ pContext->mConfig.inputCfg.format = kProcessFormat;
pContext->mConfig.inputCfg.samplingRate = 44100;
pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
@@ -167,7 +180,7 @@
pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
- pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ pContext->mConfig.outputCfg.format = kProcessFormat;
pContext->mConfig.outputCfg.samplingRate = 44100;
pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
@@ -284,18 +297,41 @@
//ALOGV("LE about to process %d samples", inBuffer->frameCount);
uint16_t inIdx;
+#ifdef BUILD_FLOAT
+ constexpr float scale = 1 << 15; // power of 2 is lossless conversion to int16_t range
+ constexpr float inverseScale = 1.f / scale;
+ const float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f) * scale;
+#else
float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f);
+#endif
float leftSample, rightSample;
for (inIdx = 0 ; inIdx < inBuffer->frameCount ; inIdx++) {
// makeup gain is applied on the input of the compressor
+#ifdef BUILD_FLOAT
+ leftSample = inputAmp * inBuffer->f32[2*inIdx];
+ rightSample = inputAmp * inBuffer->f32[2*inIdx +1];
+ pContext->mCompressor->Compress(&leftSample, &rightSample);
+ inBuffer->f32[2*inIdx] = leftSample * inverseScale;
+ inBuffer->f32[2*inIdx +1] = rightSample * inverseScale;
+#else
leftSample = inputAmp * (float)inBuffer->s16[2*inIdx];
rightSample = inputAmp * (float)inBuffer->s16[2*inIdx +1];
pContext->mCompressor->Compress(&leftSample, &rightSample);
inBuffer->s16[2*inIdx] = (int16_t) leftSample;
inBuffer->s16[2*inIdx +1] = (int16_t) rightSample;
+#endif // BUILD_FLOAT
}
if (inBuffer->raw != outBuffer->raw) {
+#ifdef BUILD_FLOAT
+ if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
+ outBuffer->f32[i] += inBuffer->f32[i];
+ }
+ } else {
+ memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(float));
+ }
+#else
if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
@@ -303,6 +339,7 @@
} else {
memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
}
+#endif // BUILD_FLOAT
}
if (pContext->mState != LOUDNESS_ENHANCER_STATE_ACTIVE) {
return -ENODATA;
diff --git a/media/libeffects/visualizer/Android.mk b/media/libeffects/visualizer/Android.mk
index 70409de..3534149 100644
--- a/media/libeffects/visualizer/Android.mk
+++ b/media/libeffects/visualizer/Android.mk
@@ -19,7 +19,8 @@
LOCAL_MODULE:= libvisualizer
LOCAL_C_INCLUDES := \
- $(call include-path-for, audio-effects)
+ $(call include-path-for, audio-effects) \
+ $(call include-path-for, audio-utils)
LOCAL_HEADER_LIBRARIES += libhardware_headers
diff --git a/media/libeffects/visualizer/EffectVisualizer.cpp b/media/libeffects/visualizer/EffectVisualizer.cpp
index 807f24d..e2ccfb7 100644
--- a/media/libeffects/visualizer/EffectVisualizer.cpp
+++ b/media/libeffects/visualizer/EffectVisualizer.cpp
@@ -24,11 +24,25 @@
#include <string.h>
#include <time.h>
+#include <algorithm> // max
#include <new>
#include <log/log.h>
#include <audio_effects/effect_visualizer.h>
+#include <audio_utils/primitives.h>
+
+#define BUILD_FLOAT
+
+#ifdef BUILD_FLOAT
+
+static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_FLOAT;
+
+#else
+
+static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_16_BIT;
+
+#endif // BUILD_FLOAT
extern "C" {
@@ -146,7 +160,7 @@
if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
- if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
+ if (pConfig->inputCfg.format != kProcessFormat) return -EINVAL;
pContext->mConfig = *pConfig;
@@ -192,7 +206,7 @@
{
pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
- pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ pContext->mConfig.inputCfg.format = kProcessFormat;
pContext->mConfig.inputCfg.samplingRate = 44100;
pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
@@ -200,7 +214,7 @@
pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
- pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ pContext->mConfig.outputCfg.format = kProcessFormat;
pContext->mConfig.outputCfg.samplingRate = 44100;
pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
@@ -301,15 +315,8 @@
//--- Effect Control Interface Implementation
//
-static inline int16_t clamp16(int32_t sample)
-{
- if ((sample>>15) ^ (sample>>31))
- sample = 0x7FFF ^ (sample>>31);
- return sample;
-}
-
int Visualizer_process(
- effect_handle_t self,audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
+ effect_handle_t self, audio_buffer_t *inBuffer, audio_buffer_t *outBuffer)
{
VisualizerContext * pContext = (VisualizerContext *)self;
@@ -324,20 +331,28 @@
return -EINVAL;
}
+ const size_t sampleLen = inBuffer->frameCount * pContext->mChannelCount;
+
// perform measurements if needed
if (pContext->mMeasurementMode & MEASUREMENT_MODE_PEAK_RMS) {
// find the peak and RMS squared for the new buffer
- uint32_t inIdx;
- int16_t maxSample = 0;
float rmsSqAcc = 0;
- for (inIdx = 0 ; inIdx < inBuffer->frameCount * pContext->mChannelCount ; inIdx++) {
- if (inBuffer->s16[inIdx] > maxSample) {
- maxSample = inBuffer->s16[inIdx];
- } else if (-inBuffer->s16[inIdx] > maxSample) {
- maxSample = -inBuffer->s16[inIdx];
- }
- rmsSqAcc += (inBuffer->s16[inIdx] * inBuffer->s16[inIdx]);
+
+#ifdef BUILD_FLOAT
+ float maxSample = 0.f;
+ for (size_t inIdx = 0; inIdx < sampleLen; ++inIdx) {
+ maxSample = fmax(maxSample, fabs(inBuffer->f32[inIdx]));
+ rmsSqAcc += inBuffer->f32[inIdx] * inBuffer->f32[inIdx];
}
+ maxSample *= 1 << 15; // scale to int16_t, with exactly 1 << 15 representing positive num.
+ rmsSqAcc *= 1 << 30; // scale to int16_t * 2
+#else
+ int maxSample = 0;
+ for (size_t inIdx = 0; inIdx < sampleLen; ++inIdx) {
+ maxSample = std::max(maxSample, std::abs(int32_t(inBuffer->s16[inIdx])));
+ rmsSqAcc += inBuffer->s16[inIdx] * inBuffer->s16[inIdx];
+ }
+#endif
// store the measurement
pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mPeakU16 = (uint16_t)maxSample;
pContext->mPastMeasurements[pContext->mMeasurementBufferIdx].mRmsSquared =
@@ -348,32 +363,59 @@
}
}
- // all code below assumes stereo 16 bit PCM output and input
+#ifdef BUILD_FLOAT
+ float fscale; // multiplicative scale
+#else
int32_t shift;
+#endif // BUILD_FLOAT
if (pContext->mScalingMode == VISUALIZER_SCALING_MODE_NORMALIZED) {
// derive capture scaling factor from peak value in current buffer
// this gives more interesting captures for display.
- shift = 32;
- int len = inBuffer->frameCount * 2;
- for (int i = 0; i < len; i++) {
+
+#ifdef BUILD_FLOAT
+ float maxSample = 0.f;
+ for (size_t inIdx = 0; inIdx < sampleLen; ++inIdx) {
+ maxSample = fmax(maxSample, fabs(inBuffer->f32[inIdx]));
+ }
+ if (maxSample > 0.f) {
+ constexpr float halfish = 127.f / 256.f;
+ fscale = halfish / maxSample;
+ int exp; // unused
+ const float significand = frexp(fscale, &exp);
+ if (significand == 0.5f) {
+ fscale *= 255.f / 256.f; // avoid returning unaltered PCM signal
+ }
+ } else {
+ // scale doesn't matter, the values are all 0.
+ fscale = 1.f;
+ }
+#else
+ int32_t orAccum = 0;
+ for (size_t i = 0; i < sampleLen; ++i) {
int32_t smp = inBuffer->s16[i];
if (smp < 0) smp = -smp - 1; // take care to keep the max negative in range
- int32_t clz = __builtin_clz(smp);
- if (shift > clz) shift = clz;
+ orAccum |= smp;
}
+
// A maximum amplitude signal will have 17 leading zeros, which we want to
// translate to a shift of 8 (for converting 16 bit to 8 bit)
- shift = 25 - shift;
+ shift = 25 - __builtin_clz(orAccum);
+
// Never scale by less than 8 to avoid returning unaltered PCM signal.
if (shift < 3) {
shift = 3;
}
// add one to combine the division by 2 needed after summing left and right channels below
shift++;
+#endif // BUILD_FLOAT
} else {
assert(pContext->mScalingMode == VISUALIZER_SCALING_MODE_AS_PLAYED);
+#ifdef BUILD_FLOAT
+ fscale = 0.5f; // default divide by 2 to account for sum of L + R.
+#else
shift = 9;
+#endif // BUILD_FLOAT
}
uint32_t captIdx;
@@ -386,9 +428,13 @@
// wrap around
captIdx = 0;
}
- int32_t smp = inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1];
- smp = smp >> shift;
+#ifdef BUILD_FLOAT
+ const float smp = (inBuffer->f32[2 * inIdx] + inBuffer->f32[2 * inIdx + 1]) * fscale;
+ buf[captIdx] = clamp8_from_float(smp);
+#else
+ const int32_t smp = (inBuffer->s16[2 * inIdx] + inBuffer->s16[2 * inIdx + 1]) >> shift;
buf[captIdx] = ((uint8_t)smp)^0x80;
+#endif // BUILD_FLOAT
}
// XXX the following two should really be atomic, though it probably doesn't
@@ -400,6 +446,15 @@
}
if (inBuffer->raw != outBuffer->raw) {
+#ifdef BUILD_FLOAT
+ if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ for (size_t i = 0; i < sampleLen; ++i) {
+ outBuffer->f32[i] += inBuffer->f32[i];
+ }
+ } else {
+ memcpy(outBuffer->raw, inBuffer->raw, sampleLen * sizeof(float));
+ }
+#else
if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
@@ -407,6 +462,7 @@
} else {
memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
}
+#endif // BUILD_FLOAT
}
if (pContext->mState != VISUALIZER_STATE_ACTIVE) {
return -ENODATA;
diff --git a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
index bc84729..211a5c0 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
@@ -107,6 +107,9 @@
// The player just completed the playback of all data sources.
// But this is not visible in native code. Just keep this entry for completeness.
MEDIA2_INFO_DATA_SOURCE_LIST_END = 6,
+ // The player just completed an iteration of playback loop. This event is sent only when
+ // looping is enabled.
+ MEDIA2_INFO_DATA_SOURCE_REPEAT = 7,
//1xx
// The player just prepared a data source.
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
index e48e388..e215965 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
@@ -372,10 +372,16 @@
timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
mDTVCCPacket->setRange(0, 0);
}
+ if (mDTVCCPacket->size() + 2 > mDTVCCPacket->capacity()) {
+ return false;
+ }
memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
br.skipBits(16);
} else if (mDTVCCPacket->size() > 0 && cc_type == 2) {
+ if (mDTVCCPacket->size() + 2 > mDTVCCPacket->capacity()) {
+ return false;
+ }
memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
br.skipBits(16);
@@ -403,6 +409,9 @@
line21CCBuf = new ABuffer((cc_count - i) * sizeof(CCData));
line21CCBuf->setRange(0, 0);
}
+ if (line21CCBuf->size() + sizeof(cc) > line21CCBuf->capacity()) {
+ return false;
+ }
memcpy(line21CCBuf->data() + line21CCBuf->size(), &cc, sizeof(cc));
line21CCBuf->setRange(0, line21CCBuf->size() + sizeof(CCData));
}
@@ -464,6 +473,9 @@
size_t trackIndex = getTrackIndex(kTrackTypeCEA708, service_number, &trackAdded);
if (mSelectedTrack == (ssize_t)trackIndex) {
sp<ABuffer> ccPacket = new ABuffer(block_size);
+ if (ccPacket->capacity() == 0) {
+ return false;
+ }
memcpy(ccPacket->data(), br.data(), block_size);
mCCMap.add(timeUs, ccPacket);
}
@@ -527,10 +539,12 @@
ccBuf = new ABuffer(size);
ccBuf->setRange(0, 0);
- for (ssize_t i = 0; i <= index; ++i) {
- sp<ABuffer> buf = mCCMap.valueAt(i);
- memcpy(ccBuf->data() + ccBuf->size(), buf->data(), buf->size());
- ccBuf->setRange(0, ccBuf->size() + buf->size());
+ if (ccBuf->capacity() > 0) {
+ for (ssize_t i = 0; i <= index; ++i) {
+ sp<ABuffer> buf = mCCMap.valueAt(i);
+ memcpy(ccBuf->data() + ccBuf->size(), buf->data(), buf->size());
+ ccBuf->setRange(0, ccBuf->size() + buf->size());
+ }
}
}
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index 03d17a5..3069f54 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -930,7 +930,12 @@
// the last little bit of audio. In looping mode, we need to restart it.
mAudioSink->start();
}
- // don't send completion event when looping
+
+ sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
+ notify->setInt64("srcId", srcId);
+ notify->setInt32("messageId", MEDIA2_INFO);
+ notify->setInt32("ext1", MEDIA2_INFO_DATA_SOURCE_REPEAT);
+ notify->post();
return;
}
if (property_get_bool("persist.debug.sf.stats", false)) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index a5f5fc6..0784939 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1120,6 +1120,7 @@
} else if (what == DecoderBase::kWhatShutdownCompleted) {
ALOGV("%s shutdown completed", audio ? "audio" : "video");
if (audio) {
+ Mutex::Autolock autoLock(mDecoderLock);
mAudioDecoder.clear();
mAudioDecoderError = false;
++mAudioDecoderGeneration;
@@ -1127,6 +1128,7 @@
CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
mFlushingAudio = SHUT_DOWN;
} else {
+ Mutex::Autolock autoLock(mDecoderLock);
mVideoDecoder.clear();
mVideoDecoderError = false;
++mVideoDecoderGeneration;
@@ -1447,29 +1449,6 @@
break;
}
- case kWhatGetStats:
- {
- ALOGV("kWhatGetStats");
-
- Vector<sp<AMessage>> *trackStats;
- CHECK(msg->findPointer("trackstats", (void**)&trackStats));
-
- trackStats->clear();
- if (mVideoDecoder != NULL) {
- trackStats->push_back(mVideoDecoder->getStats());
- }
- if (mAudioDecoder != NULL) {
- trackStats->push_back(mAudioDecoder->getStats());
- }
-
- // respond for synchronization
- sp<AMessage> response = new AMessage;
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
- break;
- }
-
default:
TRESPASS();
break;
@@ -1817,6 +1796,7 @@
(long long)currentPositionUs, forceNonOffload, needsToCreateAudioDecoder);
if (mAudioDecoder != NULL) {
mAudioDecoder->pause();
+ Mutex::Autolock autoLock(mDecoderLock);
mAudioDecoder.clear();
mAudioDecoderError = false;
++mAudioDecoderGeneration;
@@ -1935,6 +1915,8 @@
}
}
+ Mutex::Autolock autoLock(mDecoderLock);
+
if (audio) {
sp<AMessage> notify = new AMessage(kWhatAudioNotify, this);
++mAudioDecoderGeneration;
@@ -2236,13 +2218,15 @@
void NuPlayer::getStats(Vector<sp<AMessage> > *trackStats) {
CHECK(trackStats != NULL);
- ALOGV("NuPlayer::getStats()");
- sp<AMessage> msg = new AMessage(kWhatGetStats, this);
- msg->setPointer("trackstats", trackStats);
+ trackStats->clear();
- sp<AMessage> response;
- (void) msg->postAndAwaitResponse(&response);
- // response is for synchronization, ignore contents
+ Mutex::Autolock autoLock(mDecoderLock);
+ if (mVideoDecoder != NULL) {
+ trackStats->push_back(mVideoDecoder->getStats());
+ }
+ if (mAudioDecoder != NULL) {
+ trackStats->push_back(mAudioDecoder->getStats());
+ }
}
sp<MetaData> NuPlayer::getFileMeta() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index e400d16..9f5be06 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -159,7 +159,6 @@
kWhatPrepareDrm = 'pDrm',
kWhatReleaseDrm = 'rDrm',
kWhatMediaClockNotify = 'mckN',
- kWhatGetStats = 'gSts',
};
wp<NuPlayerDriver> mDriver;
@@ -175,6 +174,7 @@
sp<DecoderBase> mVideoDecoder;
bool mOffloadAudio;
sp<DecoderBase> mAudioDecoder;
+ Mutex mDecoderLock; // guard |mAudioDecoder| and |mVideoDecoder|.
sp<CCDecoder> mCCDecoder;
sp<Renderer> mRenderer;
sp<ALooper> mRendererLooper;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
index bde0862..8d876da 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDrm.cpp
@@ -239,8 +239,14 @@
size_t *encryptedbytes)
{
// size needed to store all the crypto data
- size_t cryptosize = sizeof(CryptoInfo) +
- sizeof(CryptoPlugin::SubSample) * numSubSamples;
+ size_t cryptosize;
+ // sizeof(CryptoInfo) + sizeof(CryptoPlugin::SubSample) * numSubSamples;
+ if (__builtin_mul_overflow(sizeof(CryptoPlugin::SubSample), numSubSamples, &cryptosize) ||
+ __builtin_add_overflow(cryptosize, sizeof(CryptoInfo), &cryptosize)) {
+ ALOGE("crypto size overflow");
+ return NULL;
+ }
+
CryptoInfo *ret = (CryptoInfo*) malloc(cryptosize);
if (ret == NULL) {
ALOGE("couldn't allocate %zu bytes", cryptosize);
diff --git a/media/libnblog/NBLog.cpp b/media/libnblog/NBLog.cpp
index d6fa3e3..bfc797c 100644
--- a/media/libnblog/NBLog.cpp
+++ b/media/libnblog/NBLog.cpp
@@ -64,7 +64,9 @@
// ---------------------------------------------------------------------------
/*static*/
-std::unique_ptr<NBLog::AbstractEntry> NBLog::AbstractEntry::buildEntry(const uint8_t *ptr) {
+std::unique_ptr<NBLog::AbstractEntry> NBLog::AbstractEntry::buildEntry(const uint8_t *ptr)
+{
+ if (ptr == nullptr) return nullptr;
const uint8_t type = EntryIterator(ptr)->type;
switch (type) {
case EVENT_START_FMT:
@@ -78,31 +80,33 @@
}
}
-NBLog::AbstractEntry::AbstractEntry(const uint8_t *entry) : mEntry(entry) {
+NBLog::AbstractEntry::AbstractEntry(const uint8_t *entry) : mEntry(entry)
+{
}
// ---------------------------------------------------------------------------
-NBLog::EntryIterator NBLog::FormatEntry::begin() const {
+NBLog::EntryIterator NBLog::FormatEntry::begin() const
+{
return EntryIterator(mEntry);
}
-const char *NBLog::FormatEntry::formatString() const {
+const char *NBLog::FormatEntry::formatString() const
+{
return (const char*) mEntry + offsetof(entry, data);
}
-size_t NBLog::FormatEntry::formatStringLength() const {
+size_t NBLog::FormatEntry::formatStringLength() const
+{
return mEntry[offsetof(entry, length)];
}
-NBLog::EntryIterator NBLog::FormatEntry::args() const {
+NBLog::EntryIterator NBLog::FormatEntry::args() const
+{
auto it = begin();
- // skip start fmt
- ++it;
- // skip timestamp
- ++it;
- // skip hash
- ++it;
+ ++it; // skip start fmt
+ ++it; // skip timestamp
+ ++it; // skip hash
// Skip author if present
if (it->type == EVENT_AUTHOR) {
++it;
@@ -110,33 +114,30 @@
return it;
}
-int64_t NBLog::FormatEntry::timestamp() const {
+int64_t NBLog::FormatEntry::timestamp() const
+{
auto it = begin();
- // skip start fmt
- ++it;
+ ++it; // skip start fmt
return it.payload<int64_t>();
}
-NBLog::log_hash_t NBLog::FormatEntry::hash() const {
+NBLog::log_hash_t NBLog::FormatEntry::hash() const
+{
auto it = begin();
- // skip start fmt
- ++it;
- // skip timestamp
- ++it;
+ ++it; // skip start fmt
+ ++it; // skip timestamp
// unaligned 64-bit read not supported
log_hash_t hash;
memcpy(&hash, it->data, sizeof(hash));
return hash;
}
-int NBLog::FormatEntry::author() const {
+int NBLog::FormatEntry::author() const
+{
auto it = begin();
- // skip start fmt
- ++it;
- // skip timestamp
- ++it;
- // skip hash
- ++it;
+ ++it; // skip start fmt
+ ++it; // skip timestamp
+ ++it; // skip hash
// if there is an author entry, return it, return -1 otherwise
if (it->type == EVENT_AUTHOR) {
return it.payload<int>();
@@ -145,19 +146,18 @@
}
NBLog::EntryIterator NBLog::FormatEntry::copyWithAuthor(
- std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
+ std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const
+{
auto it = begin();
- // copy fmt start entry
- it.copyTo(dst);
- // copy timestamp
- (++it).copyTo(dst); // copy hash
- (++it).copyTo(dst);
+ it.copyTo(dst); // copy fmt start entry
+ (++it).copyTo(dst); // copy timestamp
+ (++it).copyTo(dst); // copy hash
// insert author entry
- size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
+ size_t authorEntrySize = Entry::kOverhead + sizeof(author);
uint8_t authorEntry[authorEntrySize];
authorEntry[offsetof(entry, type)] = EVENT_AUTHOR;
authorEntry[offsetof(entry, length)] =
- authorEntry[authorEntrySize + NBLog::Entry::kPreviousLengthOffset] =
+ authorEntry[authorEntrySize + Entry::kPreviousLengthOffset] =
sizeof(author);
*(int*) (&authorEntry[offsetof(entry, data)]) = author;
dst->write(authorEntry, authorEntrySize);
@@ -170,76 +170,96 @@
return it;
}
-void NBLog::EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
- size_t length = ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
- dst->write(ptr, length);
+void NBLog::EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const
+{
+ size_t length = mPtr[offsetof(entry, length)] + Entry::kOverhead;
+ dst->write(mPtr, length);
}
-void NBLog::EntryIterator::copyData(uint8_t *dst) const {
- memcpy((void*) dst, ptr + offsetof(entry, data), ptr[offsetof(entry, length)]);
+void NBLog::EntryIterator::copyData(uint8_t *dst) const
+{
+ memcpy((void*) dst, mPtr + offsetof(entry, data), mPtr[offsetof(entry, length)]);
}
-NBLog::EntryIterator::EntryIterator()
- : ptr(nullptr) {}
+NBLog::EntryIterator::EntryIterator() // Dummy initialization.
+ : mPtr(nullptr)
+{
+}
NBLog::EntryIterator::EntryIterator(const uint8_t *entry)
- : ptr(entry) {}
+ : mPtr(entry)
+{
+}
NBLog::EntryIterator::EntryIterator(const NBLog::EntryIterator &other)
- : ptr(other.ptr) {}
-
-const NBLog::entry& NBLog::EntryIterator::operator*() const {
- return *(entry*) ptr;
+ : mPtr(other.mPtr)
+{
}
-const NBLog::entry* NBLog::EntryIterator::operator->() const {
- return (entry*) ptr;
+const NBLog::entry& NBLog::EntryIterator::operator*() const
+{
+ return *(entry*) mPtr;
}
-NBLog::EntryIterator& NBLog::EntryIterator::operator++() {
- ptr += ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
+const NBLog::entry* NBLog::EntryIterator::operator->() const
+{
+ return (entry*) mPtr;
+}
+
+NBLog::EntryIterator& NBLog::EntryIterator::operator++()
+{
+ mPtr += mPtr[offsetof(entry, length)] + Entry::kOverhead;
return *this;
}
-NBLog::EntryIterator& NBLog::EntryIterator::operator--() {
- ptr -= ptr[NBLog::Entry::kPreviousLengthOffset] + NBLog::Entry::kOverhead;
+NBLog::EntryIterator& NBLog::EntryIterator::operator--()
+{
+ mPtr -= mPtr[Entry::kPreviousLengthOffset] + Entry::kOverhead;
return *this;
}
-NBLog::EntryIterator NBLog::EntryIterator::next() const {
+NBLog::EntryIterator NBLog::EntryIterator::next() const
+{
EntryIterator aux(*this);
return ++aux;
}
-NBLog::EntryIterator NBLog::EntryIterator::prev() const {
+NBLog::EntryIterator NBLog::EntryIterator::prev() const
+{
EntryIterator aux(*this);
return --aux;
}
-int NBLog::EntryIterator::operator-(const NBLog::EntryIterator &other) const {
- return ptr - other.ptr;
+int NBLog::EntryIterator::operator-(const NBLog::EntryIterator &other) const
+{
+ return mPtr - other.mPtr;
}
-bool NBLog::EntryIterator::operator!=(const EntryIterator &other) const {
- return ptr != other.ptr;
+bool NBLog::EntryIterator::operator!=(const EntryIterator &other) const
+{
+ return mPtr != other.mPtr;
}
-bool NBLog::EntryIterator::hasConsistentLength() const {
- return ptr[offsetof(entry, length)] == ptr[ptr[offsetof(entry, length)] +
- NBLog::Entry::kOverhead + NBLog::Entry::kPreviousLengthOffset];
+bool NBLog::EntryIterator::hasConsistentLength() const
+{
+ return mPtr[offsetof(entry, length)] == mPtr[mPtr[offsetof(entry, length)] +
+ Entry::kOverhead + Entry::kPreviousLengthOffset];
}
// ---------------------------------------------------------------------------
-int64_t NBLog::HistogramEntry::timestamp() const {
+int64_t NBLog::HistogramEntry::timestamp() const
+{
return EntryIterator(mEntry).payload<HistTsEntry>().ts;
}
-NBLog::log_hash_t NBLog::HistogramEntry::hash() const {
+NBLog::log_hash_t NBLog::HistogramEntry::hash() const
+{
return EntryIterator(mEntry).payload<HistTsEntry>().hash;
}
-int NBLog::HistogramEntry::author() const {
+int NBLog::HistogramEntry::author() const
+{
EntryIterator it(mEntry);
if (it->length == sizeof(HistTsEntryWithAuthor)) {
return it.payload<HistTsEntryWithAuthor>().author;
@@ -249,7 +269,8 @@
}
NBLog::EntryIterator NBLog::HistogramEntry::copyWithAuthor(
- std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
+ std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const
+{
// Current histogram entry has {type, length, struct HistTsEntry, length}.
// We now want {type, length, struct HistTsEntryWithAuthor, length}
uint8_t buffer[Entry::kOverhead + sizeof(HistTsEntryWithAuthor)];
@@ -336,9 +357,7 @@
void NBLog::Writer::log(const char *string)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
size_t length = strlen(string);
if (length > Entry::kMaxLength) {
@@ -349,9 +368,7 @@
void NBLog::Writer::logf(const char *fmt, ...)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
va_list ap;
va_start(ap, fmt);
Writer::logvf(fmt, ap); // the Writer:: is needed to avoid virtual dispatch for LockedWriter
@@ -360,9 +377,7 @@
void NBLog::Writer::logvf(const char *fmt, va_list ap)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
char buffer[Entry::kMaxLength + 1 /*NUL*/];
int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
if (length >= (int) sizeof(buffer)) {
@@ -377,9 +392,7 @@
void NBLog::Writer::logTimestamp()
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
int64_t ts = get_monotonic_ns();
if (ts > 0) {
log(EVENT_TIMESTAMP, &ts, sizeof(ts));
@@ -390,41 +403,31 @@
void NBLog::Writer::logTimestamp(const int64_t ts)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
log(EVENT_TIMESTAMP, &ts, sizeof(ts));
}
void NBLog::Writer::logInteger(const int x)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
log(EVENT_INTEGER, &x, sizeof(x));
}
void NBLog::Writer::logFloat(const float x)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
log(EVENT_FLOAT, &x, sizeof(x));
}
void NBLog::Writer::logPID()
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
log(EVENT_PID, mPidTag, mPidTagSize);
}
void NBLog::Writer::logStart(const char *fmt)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
size_t length = strlen(fmt);
if (length > Entry::kMaxLength) {
length = Entry::kMaxLength;
@@ -434,26 +437,20 @@
void NBLog::Writer::logEnd()
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
Entry entry = Entry(EVENT_END_FMT, NULL, 0);
- log(&entry, true);
+ log(entry, true);
}
void NBLog::Writer::logHash(log_hash_t hash)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
log(EVENT_HASH, &hash, sizeof(hash));
}
void NBLog::Writer::logEventHistTs(Event event, log_hash_t hash)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
HistTsEntry data;
data.hash = hash;
data.ts = get_monotonic_ns();
@@ -466,10 +463,7 @@
void NBLog::Writer::logFormat(const char *fmt, log_hash_t hash, ...)
{
- if (!mEnabled) {
- return;
- }
-
+ if (!mEnabled) return;
va_list ap;
va_start(ap, hash);
Writer::logVFormat(fmt, hash, ap);
@@ -478,9 +472,7 @@
void NBLog::Writer::logVFormat(const char *fmt, log_hash_t hash, va_list argp)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
Writer::logStart(fmt);
int i;
double f;
@@ -536,9 +528,7 @@
void NBLog::Writer::log(Event event, const void *data, size_t length)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
if (data == NULL || length > Entry::kMaxLength) {
// TODO Perhaps it makes sense to display truncated data or at least a
// message that the data is too long? The current behavior can create
@@ -550,19 +540,17 @@
return;
}
Entry etr(event, data, length);
- log(&etr, true /*trusted*/);
+ log(etr, true /*trusted*/);
}
-void NBLog::Writer::log(const NBLog::Entry *etr, bool trusted)
+void NBLog::Writer::log(const NBLog::Entry &etr, bool trusted)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
if (!trusted) {
- log(etr->mEvent, etr->mData, etr->mLength);
+ log(etr.mEvent, etr.mData, etr.mLength);
return;
}
- size_t need = etr->mLength + Entry::kOverhead; // mEvent, mLength, data[mLength], mLength
+ size_t need = etr.mLength + Entry::kOverhead; // mEvent, mLength, data[mLength], mLength
// need = number of bytes written to FIFO
// FIXME optimize this using memcpy for the data part of the Entry.
@@ -571,7 +559,7 @@
uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
// write this data to temp array
for (size_t i = 0; i < need; i++) {
- temp[i] = etr->copyEntryDataAt(i);
+ temp[i] = etr.copyEntryDataAt(i);
}
// write to circular buffer
mFifoWriter->write(temp, need);
@@ -743,15 +731,14 @@
if (mFifoReader == NULL) {
return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
}
- // make a copy to avoid race condition with writer
- size_t capacity = mFifo->capacity();
// This emulates the behaviour of audio_utils_fifo_reader::read, but without incrementing the
// reader index. The index is incremented after handling corruption, to after the last complete
// entry of the buffer
size_t lost;
audio_utils_iovec iovec[2];
- ssize_t availToRead = mFifoReader->obtain(iovec, capacity, NULL /*timeout*/, &lost);
+ const ssize_t availToRead = mFifoReader->obtain(iovec, mFifo->capacity(),
+ NULL /*timeout*/, &lost);
if (availToRead <= 0) {
return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
}
@@ -800,7 +787,6 @@
snapshot->mLost = lost;
return snapshot;
-
}
// Takes raw content of the local merger FIFO, processes log entries, and
@@ -854,7 +840,7 @@
}
// FIXME: decide whether to print the warnings here or elsewhere
if (!body.isEmpty()) {
- dumpLine(timestamp, body);
+ dumpLine(×tamp, &body);
}
}
@@ -865,20 +851,22 @@
getAndProcessSnapshot(*snap);
}
-void NBLog::MergeReader::dump(int fd, int indent) {
+void NBLog::MergeReader::dump(int fd, int indent)
+{
// TODO: add a mutex around media.log dump
ReportPerformance::dump(fd, indent, mThreadPerformanceAnalysis);
}
// Writes a string to the console
-void NBLog::Reader::dumpLine(const String8 ×tamp, String8 &body)
+void NBLog::Reader::dumpLine(const String8 *timestamp, String8 *body)
{
+ if (timestamp == nullptr || body == nullptr) return;
if (mFd >= 0) {
- dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
+ dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp->string(), body->string());
} else {
- ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
+ ALOGI("%.*s%s %s", mIndent, "", timestamp->string(), body->string());
}
- body.clear();
+ body->clear();
}
bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
@@ -888,25 +876,33 @@
// ---------------------------------------------------------------------------
-void NBLog::appendTimestamp(String8 *body, const void *data) {
+void NBLog::appendTimestamp(String8 *body, const void *data)
+{
+ if (body == nullptr || data == nullptr) return;
int64_t ts;
memcpy(&ts, data, sizeof(ts));
body->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
(int) ((ts / (1000 * 1000)) % 1000));
}
-void NBLog::appendInt(String8 *body, const void *data) {
+void NBLog::appendInt(String8 *body, const void *data)
+{
+ if (body == nullptr || data == nullptr) return;
int x = *((int*) data);
body->appendFormat("<%d>", x);
}
-void NBLog::appendFloat(String8 *body, const void *data) {
+void NBLog::appendFloat(String8 *body, const void *data)
+{
+ if (body == nullptr || data == nullptr) return;
float f;
- memcpy(&f, data, sizeof(float));
+ memcpy(&f, data, sizeof(f));
body->appendFormat("<%f>", f);
}
-void NBLog::appendPID(String8 *body, const void* data, size_t length) {
+void NBLog::appendPID(String8 *body, const void* data, size_t length)
+{
+ if (body == nullptr || data == nullptr) return;
pid_t id = *((pid_t*) data);
char * name = &((char*) data)[sizeof(pid_t)];
body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
@@ -915,9 +911,9 @@
String8 NBLog::bufferDump(const uint8_t *buffer, size_t size)
{
String8 str;
+ if (buffer == nullptr) return str;
str.append("[ ");
- for(size_t i = 0; i < size; i++)
- {
+ for(size_t i = 0; i < size; i++) {
str.appendFormat("%d ", buffer[i]);
}
str.append("]");
@@ -931,7 +927,8 @@
NBLog::EntryIterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
String8 *timestamp,
- String8 *body) {
+ String8 *body)
+{
// log timestamp
int64_t ts = fmtEntry.timestamp();
timestamp->clear();
@@ -947,7 +944,7 @@
handleAuthor(fmtEntry, body);
// log string
- NBLog::EntryIterator arg = fmtEntry.args();
+ EntryIterator arg = fmtEntry.args();
const char* fmt = fmtEntry.formatString();
size_t fmt_length = fmtEntry.formatStringLength();
@@ -1026,10 +1023,11 @@
new audio_utils_fifo(size, sizeof(uint8_t),
mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL)
- {}
+{
+}
-void NBLog::Merger::addReader(const NBLog::NamedReader &reader) {
-
+void NBLog::Merger::addReader(const NBLog::NamedReader &reader)
+{
// FIXME This is called by binder thread in MediaLogService::registerWriter
// but the access to shared variable mNamedReaders is not yet protected by a lock.
mNamedReaders.push_back(reader);
@@ -1044,25 +1042,23 @@
MergeItem(int64_t ts, int index): ts(ts), index(index) {}
};
-// operators needed for priority queue in merge
-// bool operator>(const int64_t &t1, const int64_t &t2) {
-// return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec);
-// }
-
-bool operator>(const struct MergeItem &i1, const struct MergeItem &i2) {
+bool operator>(const struct MergeItem &i1, const struct MergeItem &i2)
+{
return i1.ts > i2.ts || (i1.ts == i2.ts && i1.index > i2.index);
}
// Merge registered readers, sorted by timestamp, and write data to a single FIFO in local memory
-void NBLog::Merger::merge() {
+void NBLog::Merger::merge()
+{
// FIXME This is called by merge thread
// but the access to shared variable mNamedReaders is not yet protected by a lock.
- int nLogs = mNamedReaders.size();
+ const int nLogs = mNamedReaders.size();
std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs);
- std::vector<NBLog::EntryIterator> offsets(nLogs);
+ std::vector<EntryIterator> offsets;
+ offsets.reserve(nLogs);
for (int i = 0; i < nLogs; ++i) {
snapshots[i] = mNamedReaders[i].reader()->getSnapshot();
- offsets[i] = snapshots[i]->begin();
+ offsets.push_back(snapshots[i]->begin());
}
// initialize offsets
// TODO custom heap implementation could allow to update top, improving performance
@@ -1071,17 +1067,19 @@
for (int i = 0; i < nLogs; ++i)
{
if (offsets[i] != snapshots[i]->end()) {
- int64_t ts = AbstractEntry::buildEntry(offsets[i])->timestamp();
- timestamps.emplace(ts, i);
+ std::unique_ptr<AbstractEntry> abstractEntry = AbstractEntry::buildEntry(offsets[i]);
+ if (abstractEntry == nullptr) {
+ continue;
+ }
+ timestamps.emplace(abstractEntry->timestamp(), i);
}
}
while (!timestamps.empty()) {
- // find minimum timestamp
- int index = timestamps.top().index;
+ int index = timestamps.top().index; // find minimum timestamp
// copy it to the log, increasing offset
- offsets[index] = AbstractEntry::buildEntry(offsets[index])->copyWithAuthor(mFifoWriter,
- index);
+ offsets[index] = AbstractEntry::buildEntry(offsets[index])->
+ copyWithAuthor(mFifoWriter, index);
// update data structures
timestamps.pop();
if (offsets[index] != snapshots[index]->end()) {
@@ -1091,7 +1089,8 @@
}
}
-const std::vector<NBLog::NamedReader>& NBLog::Merger::getNamedReaders() const {
+const std::vector<NBLog::NamedReader>& NBLog::Merger::getNamedReaders() const
+{
// FIXME This is returning a reference to a shared variable that needs a lock
return mNamedReaders;
}
@@ -1099,10 +1098,16 @@
// ---------------------------------------------------------------------------
NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
- : Reader(shared, size), mNamedReaders(merger.getNamedReaders()) {}
+ : Reader(shared, size), mNamedReaders(merger.getNamedReaders())
+{
+}
-void NBLog::MergeReader::handleAuthor(const NBLog::AbstractEntry &entry, String8 *body) {
+void NBLog::MergeReader::handleAuthor(const NBLog::AbstractEntry &entry, String8 *body)
+{
int author = entry.author();
+ if (author == -1) {
+ return;
+ }
// FIXME Needs a lock
const char* name = mNamedReaders[author].name();
body->appendFormat("%s: ", name);
@@ -1113,16 +1118,20 @@
NBLog::MergeThread::MergeThread(NBLog::Merger &merger, NBLog::MergeReader &mergeReader)
: mMerger(merger),
mMergeReader(mergeReader),
- mTimeoutUs(0) {}
+ mTimeoutUs(0)
+{
+}
-NBLog::MergeThread::~MergeThread() {
+NBLog::MergeThread::~MergeThread()
+{
// set exit flag, set timeout to 0 to force threadLoop to exit and wait for the thread to join
requestExit();
setTimeoutUs(0);
join();
}
-bool NBLog::MergeThread::threadLoop() {
+bool NBLog::MergeThread::threadLoop()
+{
bool doMerge;
{
AutoMutex _l(mMutex);
@@ -1144,11 +1153,13 @@
return true;
}
-void NBLog::MergeThread::wakeup() {
+void NBLog::MergeThread::wakeup()
+{
setTimeoutUs(kThreadWakeupPeriodUs);
}
-void NBLog::MergeThread::setTimeoutUs(int time) {
+void NBLog::MergeThread::setTimeoutUs(int time)
+{
AutoMutex _l(mMutex);
mTimeoutUs = time;
mCond.signal();
diff --git a/media/libnblog/include/media/nblog/NBLog.h b/media/libnblog/include/media/nblog/NBLog.h
index fb6f179..bee3ad3 100644
--- a/media/libnblog/include/media/nblog/NBLog.h
+++ b/media/libnblog/include/media/nblog/NBLog.h
@@ -98,7 +98,12 @@
// entry iterator
class EntryIterator {
public:
+ // Used for dummy initialization. Performing operations on a default-constructed
+ // EntryIterator other than assigning it to another valid EntryIterator
+ // is undefined behavior.
EntryIterator();
+ // Caller's responsibility to make sure entry is not nullptr.
+ // Passing in nullptr can result in undefined behavior.
explicit EntryIterator(const uint8_t *entry);
EntryIterator(const EntryIterator &other);
@@ -109,7 +114,9 @@
EntryIterator& operator++(); // ++i
// back to previous entry
EntryIterator& operator--(); // --i
+ // returns an EntryIterator corresponding to the next entry
EntryIterator next() const;
+ // returns an EntryIterator corresponding to the previous entry
EntryIterator prev() const;
bool operator!=(const EntryIterator &other) const;
int operator-(const EntryIterator &other) const;
@@ -120,25 +127,22 @@
template<typename T>
inline const T& payload() {
- return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
+ return *reinterpret_cast<const T *>(mPtr + offsetof(entry, data));
}
inline operator const uint8_t*() const {
- return ptr;
+ return mPtr;
}
private:
- const uint8_t *ptr;
+ const uint8_t *mPtr; // Should not be nullptr except for dummy initialization
};
class AbstractEntry {
public:
-
- // Entry starting in the given pointer
- explicit AbstractEntry(const uint8_t *entry);
virtual ~AbstractEntry() {}
- // build concrete entry of appropriate class from pointer
+ // build concrete entry of appropriate class from ptr.
static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
// get format entry timestamp
@@ -158,6 +162,8 @@
int author) const = 0;
protected:
+ // Entry starting in the given pointer, which shall not be nullptr.
+ explicit AbstractEntry(const uint8_t *entry);
// copies ordinary entry from src to dst, and returns length of entry
// size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
const uint8_t *mEntry;
@@ -360,7 +366,7 @@
// writes a single Entry to the FIFO
void log(Event event, const void *data, size_t length);
// checks validity of an event before calling log above this one
- void log(const Entry *entry, bool trusted = false);
+ void log(const Entry &entry, bool trusted = false);
Shared* const mShared; // raw pointer to shared memory
sp<IMemory> mIMemory; // ref-counted version, initialized in constructor
@@ -432,7 +438,6 @@
EntryIterator end() { return mEnd; }
private:
- friend class MergeReader;
friend class Reader;
uint8_t *mData;
size_t mLost;
@@ -454,7 +459,7 @@
protected:
// print a summary of the performance to the console
- void dumpLine(const String8& timestamp, String8& body);
+ void dumpLine(const String8 *timestamp, String8 *body);
EntryIterator handleFormat(const FormatEntry &fmtEntry,
String8 *timestamp,
String8 *body);
diff --git a/media/libstagefright/MediaCodec.cpp b/media/libstagefright/MediaCodec.cpp
index 353e407..f91c543 100644
--- a/media/libstagefright/MediaCodec.cpp
+++ b/media/libstagefright/MediaCodec.cpp
@@ -2674,7 +2674,7 @@
CHECK(msg->senderAwaitsResponse(&replyID));
if (mFlags & kFlagIsAsync) {
- ALOGE("dequeueOutputBuffer can't be used in async mode");
+ ALOGE("dequeueInputBuffer can't be used in async mode");
PostReplyWithError(replyID, INVALID_OPERATION);
break;
}
diff --git a/media/libstagefright/MetaDataUtils.cpp b/media/libstagefright/MetaDataUtils.cpp
index 04f6ade..2475e7b 100644
--- a/media/libstagefright/MetaDataUtils.cpp
+++ b/media/libstagefright/MetaDataUtils.cpp
@@ -16,8 +16,10 @@
//#define LOG_NDEBUG 0
#define LOG_TAG "MetaDataUtils"
+#include <utils/Log.h>
#include <media/stagefright/foundation/avc_utils.h>
+#include <media/stagefright/foundation/ABitReader.h>
#include <media/stagefright/foundation/ABuffer.h>
#include <media/stagefright/MediaDefs.h>
#include <media/stagefright/MetaDataUtils.h>
@@ -25,6 +27,10 @@
namespace android {
bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
+ if (data == nullptr || size == 0) {
+ return false;
+ }
+
int32_t width;
int32_t height;
int32_t sarWidth;
@@ -46,6 +52,44 @@
return true;
}
+bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size) {
+ if (data == nullptr || size < 7) {
+ return false;
+ }
+
+ ABitReader bits(data, size);
+
+ // adts_fixed_header
+
+ if (bits.getBits(12) != 0xfffu) {
+ ALOGE("Wrong atds_fixed_header");
+ return false;
+ }
+
+ bits.skipBits(4); // ID, layer, protection_absent
+
+ unsigned profile = bits.getBits(2);
+ if (profile == 3u) {
+ ALOGE("profile should not be 3");
+ return false;
+ }
+ unsigned sampling_freq_index = bits.getBits(4);
+ bits.getBits(1); // private_bit
+ unsigned channel_configuration = bits.getBits(3);
+ if (channel_configuration == 0u) {
+ ALOGE("channel_config should not be 0");
+ return false;
+ }
+
+ if (!MakeAACCodecSpecificData(
+ meta, profile, sampling_freq_index, channel_configuration)) {
+ return false;
+ }
+
+ meta.setInt32(kKeyIsADTS, true);
+ return true;
+}
+
bool MakeAACCodecSpecificData(
MetaDataBase &meta,
unsigned profile, unsigned sampling_freq_index,
diff --git a/media/libstagefright/StagefrightPluginLoader.cpp b/media/libstagefright/StagefrightPluginLoader.cpp
index 519e870..dd5903a 100644
--- a/media/libstagefright/StagefrightPluginLoader.cpp
+++ b/media/libstagefright/StagefrightPluginLoader.cpp
@@ -46,7 +46,7 @@
}
mCreateInputSurface = (CodecBase::CreateInputSurfaceFunc)dlsym(
mLibHandle, "CreateInputSurface");
- if (mCreateBuilder == nullptr) {
+ if (mCreateInputSurface == nullptr) {
ALOGD("Failed to find symbol: CreateInputSurface (%s)", dlerror());
}
}
diff --git a/media/libstagefright/Utils.cpp b/media/libstagefright/Utils.cpp
index ea778a4..ada37a6 100644
--- a/media/libstagefright/Utils.cpp
+++ b/media/libstagefright/Utils.cpp
@@ -1577,6 +1577,7 @@
{ MEDIA_MIMETYPE_AUDIO_VORBIS, AUDIO_FORMAT_VORBIS },
{ MEDIA_MIMETYPE_AUDIO_OPUS, AUDIO_FORMAT_OPUS},
{ MEDIA_MIMETYPE_AUDIO_AC3, AUDIO_FORMAT_AC3},
+ { MEDIA_MIMETYPE_AUDIO_EAC3, AUDIO_FORMAT_E_AC3},
{ MEDIA_MIMETYPE_AUDIO_AC4, AUDIO_FORMAT_AC4},
{ MEDIA_MIMETYPE_AUDIO_FLAC, AUDIO_FORMAT_FLAC},
{ 0, AUDIO_FORMAT_INVALID }
@@ -1868,4 +1869,3 @@
}
} // namespace android
-
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
index 75ca846..9c0fcfa 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
@@ -186,8 +186,8 @@
#ifdef DEC_INTERNAL_MEMORY_OPT
video->vol[idx] = IMEM_vol[idx];
video->memoryUsage += sizeof(Vol);
- oscl_memset(video->vol[idx], 0, sizeof(Vol));
if (video->vol[idx] == NULL) status = PV_FALSE;
+ else oscl_memset(video->vol[idx], 0, sizeof(Vol));
stream = IMEM_BitstreamDecVideo;
#else
video->vol[idx] = (Vol *) oscl_malloc(sizeof(Vol));
@@ -213,6 +213,7 @@
else
{
int32 buffer_size;
+ oscl_memset(stream, 0, sizeof(BitstreamDecVideo));
if ((buffer_size = BitstreamOpen(stream, idx)) < 0)
{
mp4dec_log("InitVideoDecoder(): Can't allocate bitstream buffer.\n");
@@ -339,27 +340,33 @@
#ifdef DEC_INTERNAL_MEMORY_OPT
video->currVop->yChan = IMEM_currVop_yChan; /* Allocate memory for all VOP OKA 3/2/1*/
if (video->currVop->yChan == NULL) status = PV_FALSE;
- video->currVop->uChan = video->currVop->yChan + size;
- video->currVop->vChan = video->currVop->uChan + (size >> 2);
+ else {
+ video->currVop->uChan = video->currVop->yChan + size;
+ video->currVop->vChan = video->currVop->uChan + (size >> 2);
+ }
video->prevVop->yChan = IMEM_prevVop_yChan; /* Allocate memory for all VOP OKA 3/2/1*/
if (video->prevVop->yChan == NULL) status = PV_FALSE;
- video->prevVop->uChan = video->prevVop->yChan + size;
- video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+ else {
+ video->prevVop->uChan = video->prevVop->yChan + size;
+ video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+ }
#else
if (size > INT32_MAX / 3) {
return PV_FALSE;
}
video->currVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
if (video->currVop->yChan == NULL) status = PV_FALSE;
-
- video->currVop->uChan = video->currVop->yChan + size;
- video->currVop->vChan = video->currVop->uChan + (size >> 2);
+ else {
+ video->currVop->uChan = video->currVop->yChan + size;
+ video->currVop->vChan = video->currVop->uChan + (size >> 2);
+ }
video->prevVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
if (video->prevVop->yChan == NULL) status = PV_FALSE;
-
- video->prevVop->uChan = video->prevVop->yChan + size;
- video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+ else {
+ video->prevVop->uChan = video->prevVop->yChan + size;
+ video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+ }
#endif
video->memoryUsage += (size * 3);
#endif // MEMORY_POOL
@@ -383,8 +390,10 @@
video->prevEnhcVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
if (video->prevEnhcVop->yChan == NULL) status = PV_FALSE;
- video->prevEnhcVop->uChan = video->prevEnhcVop->yChan + size;
- video->prevEnhcVop->vChan = video->prevEnhcVop->uChan + (size >> 2);
+ else {
+ video->prevEnhcVop->uChan = video->prevEnhcVop->yChan + size;
+ video->prevEnhcVop->vChan = video->prevEnhcVop->uChan + (size >> 2);
+ }
video->memoryUsage += (3 * size / 2);
#endif
}
@@ -431,10 +440,12 @@
#else
video->sliceNo = (uint8 *) oscl_malloc(nTotalMB);
if (video->sliceNo == NULL) status = PV_FALSE;
+ else oscl_memset(video->sliceNo, 0, nTotalMB);
video->memoryUsage += nTotalMB;
video->acPredFlag = (uint8 *) oscl_malloc(nTotalMB * sizeof(uint8));
if (video->acPredFlag == NULL) status = PV_FALSE;
+ else oscl_memset(video->acPredFlag, 0, nTotalMB * sizeof(uint8));
video->memoryUsage += (nTotalMB);
if ((size_t)nTotalMB > SIZE_MAX / sizeof(typeDCStore)) {
@@ -442,6 +453,7 @@
}
video->predDC = (typeDCStore *) oscl_malloc(nTotalMB * sizeof(typeDCStore));
if (video->predDC == NULL) status = PV_FALSE;
+ else oscl_memset(video->predDC, 0, nTotalMB * sizeof(typeDCStore));
video->memoryUsage += (nTotalMB * sizeof(typeDCStore));
if (nMBPerRow > INT32_MAX - 1
@@ -450,6 +462,7 @@
}
video->predDCAC_col = (typeDCACStore *) oscl_malloc((nMBPerRow + 1) * sizeof(typeDCACStore));
if (video->predDCAC_col == NULL) status = PV_FALSE;
+ else oscl_memset(video->predDCAC_col, 0, (nMBPerRow + 1) * sizeof(typeDCACStore));
video->memoryUsage += ((nMBPerRow + 1) * sizeof(typeDCACStore));
/* element zero will be used for storing vertical (col) AC coefficients */
@@ -459,9 +472,11 @@
/* Allocating HeaderInfo structure & Quantizer array */
video->headerInfo.Mode = (uint8 *) oscl_malloc(nTotalMB);
if (video->headerInfo.Mode == NULL) status = PV_FALSE;
+ else oscl_memset(video->headerInfo.Mode, 0, nTotalMB);
video->memoryUsage += nTotalMB;
video->headerInfo.CBP = (uint8 *) oscl_malloc(nTotalMB);
if (video->headerInfo.CBP == NULL) status = PV_FALSE;
+ else oscl_memset (video->headerInfo.CBP, 0, nTotalMB);
video->memoryUsage += nTotalMB;
if ((size_t)nTotalMB > SIZE_MAX / sizeof(int16)) {
@@ -469,6 +484,7 @@
}
video->QPMB = (int16 *) oscl_malloc(nTotalMB * sizeof(int16));
if (video->QPMB == NULL) status = PV_FALSE;
+ else memset(video->QPMB, 0x0, nTotalMB * sizeof(int16));
video->memoryUsage += (nTotalMB * sizeof(int));
/* Allocating macroblock space */
@@ -489,8 +505,10 @@
}
video->motX = (MOT *) oscl_malloc(sizeof(MOT) * 4 * nTotalMB);
if (video->motX == NULL) status = PV_FALSE;
+ else memset(video->motX, 0, sizeof(MOT) * 4 * nTotalMB);
video->motY = (MOT *) oscl_malloc(sizeof(MOT) * 4 * nTotalMB);
if (video->motY == NULL) status = PV_FALSE;
+ else memset(video->motY, 0, sizeof(MOT) * 4 * nTotalMB);
video->memoryUsage += (sizeof(MOT) * 8 * nTotalMB);
#endif
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 2364684..cd984f0 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -114,7 +114,7 @@
mConfig->crcEnabled = false;
uint32_t memRequirements = pvmp3_decoderMemRequirements();
- mDecoderBuf = malloc(memRequirements);
+ mDecoderBuf = calloc(1, memRequirements);
pvmp3_InitDecoder(mConfig, mDecoderBuf);
mIsFirst = true;
diff --git a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
index f173e0f..06b15b3 100644
--- a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
+++ b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
@@ -689,7 +689,6 @@
notify(OMX_EventError, OMX_ErrorUndefined, err_code, NULL);
return;
}
- mIsCodecConfigFlushRequired = true;
}
if (!mSampFreq || !mNumChannels) {
@@ -713,10 +712,14 @@
signed int bytesConsumed = 0;
int errorCode = 0;
if (mIsCodecInitialized) {
+ mIsCodecConfigFlushRequired = true;
errorCode =
decodeXAACStream(inBuffer, inBufferLength, &bytesConsumed, &numOutBytes);
- } else {
+ } else if (!mIsCodecConfigFlushRequired) {
ALOGW("Assumption that first frame after header initializes decoder failed!");
+ mSignalledError = true;
+ notify(OMX_EventError, OMX_ErrorUndefined, -1, NULL);
+ return;
}
inHeader->nFilledLen -= bytesConsumed;
inHeader->nOffset += bytesConsumed;
diff --git a/media/libstagefright/http/HTTPHelper.cpp b/media/libstagefright/http/HTTPHelper.cpp
index 77845e2..b895f03 100644
--- a/media/libstagefright/http/HTTPHelper.cpp
+++ b/media/libstagefright/http/HTTPHelper.cpp
@@ -42,11 +42,11 @@
env, env->FindClass("android/media/MediaHTTPService"));
CHECK(clazz.get() != NULL);
- jmethodID constructID = env->GetMethodID(clazz.get(), "<init>", "()V");
+ jmethodID constructID = env->GetMethodID(clazz.get(), "<init>", "(Ljava/util/List;)V");
CHECK(constructID != NULL);
ScopedLocalRef<jobject> httpServiceObj(
- env, env->NewObject(clazz.get(), constructID));
+ env, env->NewObject(clazz.get(), constructID, NULL));
sp<IMediaHTTPService> httpService;
if (httpServiceObj.get() != NULL) {
diff --git a/media/libstagefright/include/media/stagefright/MetaDataUtils.h b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
index d5a8080..4a7107d 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataUtils.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
@@ -24,6 +24,7 @@
struct ABuffer;
bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
+bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
bool MakeAACCodecSpecificData(MetaDataBase &meta, unsigned profile, unsigned sampling_freq_index,
unsigned channel_configuration);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index cc31815..fb498d4 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -775,10 +775,12 @@
ALOGV("new stream PID 0x%02x, type 0x%02x, scrambled %d, SampleEncrypted: %d",
elementaryPID, streamType, mScrambled, mSampleEncrypted);
- uint32_t flags =
- (isVideo() && mScrambled) ? ElementaryStreamQueue::kFlag_ScrambledData :
- (mSampleEncrypted) ? ElementaryStreamQueue::kFlag_SampleEncryptedData :
- 0;
+ uint32_t flags = 0;
+ if (((isVideo() || isAudio()) && mScrambled)) {
+ flags = ElementaryStreamQueue::kFlag_ScrambledData;
+ } else if (mSampleEncrypted) {
+ flags = ElementaryStreamQueue::kFlag_SampleEncryptedData;
+ }
ElementaryStreamQueue::Mode mode = ElementaryStreamQueue::INVALID;
@@ -815,6 +817,10 @@
mode = ElementaryStreamQueue::AC3;
break;
+ case STREAMTYPE_EAC3:
+ mode = ElementaryStreamQueue::EAC3;
+ break;
+
case STREAMTYPE_PES_PRIVATE_DATA:
if (mStreamTypeExt == EXT_DESCRIPTOR_DVB_AC4) {
mode = ElementaryStreamQueue::AC4;
@@ -1026,6 +1032,7 @@
case STREAMTYPE_MPEG2_AUDIO_ADTS:
case STREAMTYPE_LPCM_AC3:
case STREAMTYPE_AC3:
+ case STREAMTYPE_EAC3:
case STREAMTYPE_AAC_ENCRYPTED:
case STREAMTYPE_AC3_ENCRYPTED:
return true;
@@ -1499,7 +1506,13 @@
descrambleBytes = bytesWritten;
}
- sp<ABuffer> buffer;
+ // |buffer| points to the buffer from which we'd parse the PES header.
+ // When the output stream is scrambled, it points to mDescrambledBuffer
+ // (unless all packets in this PES are actually clear, in which case,
+ // it points to mBuffer since we never copied into mDescrambledBuffer).
+ // When the output stream is clear, it points to mBuffer, and we'll
+ // copy all descrambled data back to mBuffer.
+ sp<ABuffer> buffer = mBuffer;
if (mQueue->isScrambled()) {
// Queue subSample info for scrambled queue
sp<ABuffer> clearSizesBuffer = new ABuffer(mSubSamples.size() * 4);
@@ -1528,15 +1541,18 @@
}
// Pass the original TS subsample size now. The PES header adjust
// will be applied when the scrambled AU is dequeued.
+ // Note that if descrambleBytes is 0, it means this PES contains only
+ // all ts packets, leadingClearBytes is entire buffer size.
mQueue->appendScrambledData(
- mBuffer->data(), mBuffer->size(), sctrl,
- isSync, clearSizesBuffer, encSizesBuffer);
+ mBuffer->data(), mBuffer->size(),
+ (descrambleBytes > 0) ? descrambleBytes : mBuffer->size(),
+ sctrl, isSync, clearSizesBuffer, encSizesBuffer);
- buffer = mDescrambledBuffer;
+ if (descrambleBytes > 0) {
+ buffer = mDescrambledBuffer;
+ }
} else {
memcpy(mBuffer->data(), mDescrambledBuffer->data(), descrambleBytes);
-
- buffer = mBuffer;
}
ABitReader br(buffer->data(), buffer->size());
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index adb4fb2..a31dc46 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -154,6 +154,7 @@
// Stream type 0x83 is non-standard,
// it could be LPCM or TrueHD AC3
STREAMTYPE_LPCM_AC3 = 0x83,
+ STREAMTYPE_EAC3 = 0x87,
//Sample Encrypted types
STREAMTYPE_H264_ENCRYPTED = 0xDB,
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 34d0bcc..fb8b9fd 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -210,8 +210,81 @@
return payloadSize;
}
-static bool IsSeeminglyValidAC3Header(const uint8_t *ptr, size_t size) {
- return parseAC3SyncFrame(ptr, size, NULL) > 0;
+// Parse EAC3 header assuming the current ptr is start position of syncframe,
+// update metadata only applicable, and return the payload size
+// ATSC A/52:2012 E2.3.1
+static unsigned parseEAC3SyncFrame(
+ const uint8_t *ptr, size_t size, sp<MetaData> *metaData) {
+ static const unsigned channelCountTable[] = {2, 1, 2, 3, 3, 4, 4, 5};
+ static const unsigned samplingRateTable[] = {48000, 44100, 32000};
+ static const unsigned samplingRateTable2[] = {24000, 22050, 16000};
+
+ ABitReader bits(ptr, size);
+ if (bits.numBitsLeft() < 16) {
+ ALOGE("Not enough bits left for further parsing");
+ return 0;
+ }
+ if (bits.getBits(16) != 0x0B77) {
+ ALOGE("No valid sync word in EAC3 header");
+ return 0;
+ }
+
+ // we parse up to bsid so there needs to be at least that many bits
+ if (bits.numBitsLeft() < 2 + 3 + 11 + 2 + 2 + 3 + 1 + 5) {
+ ALOGE("Not enough bits left for further parsing");
+ return 0;
+ }
+
+ unsigned strmtyp = bits.getBits(2);
+ if (strmtyp == 3) {
+ ALOGE("Incorrect strmtyp in EAC3 header");
+ return 0;
+ }
+
+ unsigned substreamid = bits.getBits(3);
+ // only the first independent stream is supported
+ if ((strmtyp == 0 || strmtyp == 2) && substreamid != 0)
+ return 0;
+
+ unsigned frmsiz = bits.getBits(11);
+ unsigned fscod = bits.getBits(2);
+
+ unsigned samplingRate = 0;
+ if (fscod == 0x3) {
+ unsigned fscod2 = bits.getBits(2);
+ if (fscod2 == 3) {
+ ALOGW("Incorrect fscod2 in EAC3 header");
+ return 0;
+ }
+ samplingRate = samplingRateTable2[fscod2];
+ } else {
+ samplingRate = samplingRateTable[fscod];
+ unsigned numblkscod __unused = bits.getBits(2);
+ }
+
+ unsigned acmod = bits.getBits(3);
+ unsigned lfeon = bits.getBits(1);
+ unsigned bsid = bits.getBits(5);
+ if (bsid < 11 || bsid > 16) {
+ ALOGW("Incorrect bsid in EAC3 header. Could be AC-3 or some unknown EAC3 format");
+ return 0;
+ }
+
+ // we currently only support the first independant stream
+ if (metaData != NULL && (strmtyp == 0 || strmtyp == 2)) {
+ unsigned channelCount = channelCountTable[acmod] + lfeon;
+ ALOGV("EAC3 channelCount = %d", channelCount);
+ ALOGV("EAC3 samplingRate = %d", samplingRate);
+ (*metaData)->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_EAC3);
+ (*metaData)->setInt32(kKeyChannelCount, channelCount);
+ (*metaData)->setInt32(kKeySampleRate, samplingRate);
+ (*metaData)->setInt32(kKeyIsSyncFrame, 1);
+ }
+
+ unsigned payloadSize = frmsiz + 1;
+ payloadSize <<= 1; // convert from 16-bit words to bytes
+
+ return payloadSize;
}
// Parse AC4 header assuming the current ptr is start position of syncframe
@@ -366,7 +439,8 @@
ALOGE("appending data after EOS");
return ERROR_MALFORMED;
}
- if (mBuffer == NULL || mBuffer->size() == 0) {
+
+ if (!isScrambled() && (mBuffer == NULL || mBuffer->size() == 0)) {
switch (mMode) {
case H264:
case MPEG_VIDEO:
@@ -477,12 +551,19 @@
}
case AC3:
+ case EAC3:
{
uint8_t *ptr = (uint8_t *)data;
ssize_t startOffset = -1;
for (size_t i = 0; i < size; ++i) {
- if (IsSeeminglyValidAC3Header(&ptr[i], size - i)) {
+ unsigned payloadSize = 0;
+ if (mMode == AC3) {
+ payloadSize = parseAC3SyncFrame(&ptr[i], size - i, NULL);
+ } else if (mMode == EAC3) {
+ payloadSize = parseEAC3SyncFrame(&ptr[i], size - i, NULL);
+ }
+ if (payloadSize > 0) {
startOffset = i;
break;
}
@@ -493,7 +574,7 @@
}
if (startOffset > 0) {
- ALOGI("found something resembling an AC3 syncword at "
+ ALOGI("found something resembling an (E)AC3 syncword at "
"offset %zd",
startOffset);
}
@@ -526,8 +607,9 @@
}
if (startOffset > 0) {
- ALOGI("found something resembling an AC4 syncword at offset %zd",
- startOffset);
+ ALOGI("found something resembling an AC4 syncword at "
+ "offset %zd",
+ startOffset);
}
if (frameSize != size - startOffset) {
ALOGV("AC4 frame size is %u bytes, while the buffer size is %zd bytes.",
@@ -617,6 +699,7 @@
void ElementaryStreamQueue::appendScrambledData(
const void *data, size_t size,
+ size_t leadingClearBytes,
int32_t keyId, bool isSync,
sp<ABuffer> clearSizes, sp<ABuffer> encSizes) {
if (!isScrambled()) {
@@ -644,6 +727,7 @@
ScrambledRangeInfo scrambledInfo;
scrambledInfo.mLength = size;
+ scrambledInfo.mLeadingClearBytes = leadingClearBytes;
scrambledInfo.mKeyId = keyId;
scrambledInfo.mIsSync = isSync;
scrambledInfo.mClearSizes = clearSizes;
@@ -656,7 +740,6 @@
sp<ABuffer> ElementaryStreamQueue::dequeueScrambledAccessUnit() {
size_t nextScan = mBuffer->size();
- mBuffer->setRange(0, 0);
int32_t pesOffset = 0, pesScramblingControl = 0;
int64_t timeUs = fetchTimestamp(nextScan, &pesOffset, &pesScramblingControl);
if (timeUs < 0ll) {
@@ -667,6 +750,7 @@
// return scrambled unit
int32_t keyId = pesScramblingControl, isSync = 0, scrambledLength = 0;
sp<ABuffer> clearSizes, encSizes;
+ size_t leadingClearBytes;
while (mScrambledRangeInfos.size() > mRangeInfos.size()) {
auto it = mScrambledRangeInfos.begin();
ALOGV("[stream %d] fetching scrambled range: size=%zu", mMode, it->mLength);
@@ -684,6 +768,7 @@
clearSizes = it->mClearSizes;
encSizes = it->mEncSizes;
isSync = it->mIsSync;
+ leadingClearBytes = it->mLeadingClearBytes;
mScrambledRangeInfos.erase(it);
}
if (scrambledLength == 0) {
@@ -691,6 +776,70 @@
return NULL;
}
+ // Retrieve the leading clear bytes info, and use it to set the clear
+ // range on mBuffer. Note that the leading clear bytes includes the
+ // PES header portion, while mBuffer doesn't.
+ if ((int32_t)leadingClearBytes > pesOffset) {
+ mBuffer->setRange(0, leadingClearBytes - pesOffset);
+ } else {
+ mBuffer->setRange(0, 0);
+ }
+
+ // Try to parse formats, and if unavailable set up a dummy format.
+ // Only support the following modes for scrambled content for now.
+ // (will be expanded later).
+ if (mFormat == NULL) {
+ mFormat = new MetaData;
+ switch (mMode) {
+ case H264:
+ {
+ if (!MakeAVCCodecSpecificData(
+ *mFormat, mBuffer->data(), mBuffer->size())) {
+ ALOGI("Creating dummy AVC format for scrambled content");
+
+ mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+ mFormat->setInt32(kKeyWidth, 1280);
+ mFormat->setInt32(kKeyHeight, 720);
+ }
+ break;
+ }
+ case AAC:
+ {
+ if (!MakeAACCodecSpecificData(
+ *mFormat, mBuffer->data(), mBuffer->size())) {
+ ALOGI("Creating dummy AAC format for scrambled content");
+
+ MakeAACCodecSpecificData(*mFormat,
+ 1 /*profile*/, 7 /*sampling_freq_index*/, 1 /*channel_config*/);
+ mFormat->setInt32(kKeyIsADTS, true);
+ }
+
+ break;
+ }
+ case MPEG_VIDEO:
+ {
+ ALOGI("Creating dummy MPEG format for scrambled content");
+
+ mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
+ mFormat->setInt32(kKeyWidth, 1280);
+ mFormat->setInt32(kKeyHeight, 720);
+ break;
+ }
+ default:
+ {
+ ALOGE("Unknown mode for scrambled content");
+ return NULL;
+ }
+ }
+
+ // for MediaExtractor.CasInfo
+ mFormat->setInt32(kKeyCASystemID, mCASystemId);
+ mFormat->setData(kKeyCASessionID,
+ 0, mCasSessionId.data(), mCasSessionId.size());
+ }
+
+ mBuffer->setRange(0, 0);
+
// copy into scrambled access unit
sp<ABuffer> scrambledAccessUnit = ABuffer::CreateAsCopy(
mScrambledBuffer->data(), scrambledLength);
@@ -722,7 +871,11 @@
}
sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
- if ((mFlags & kFlag_AlignedData) && mMode == H264 && !isScrambled()) {
+ if (isScrambled()) {
+ return dequeueScrambledAccessUnit();
+ }
+
+ if ((mFlags & kFlag_AlignedData) && mMode == H264) {
if (mRangeInfos.empty()) {
return NULL;
}
@@ -756,7 +909,8 @@
case AAC:
return dequeueAccessUnitAAC();
case AC3:
- return dequeueAccessUnitAC3();
+ case EAC3:
+ return dequeueAccessUnitEAC3();
case AC4:
return dequeueAccessUnitAC4();
case MPEG_VIDEO:
@@ -776,34 +930,38 @@
}
}
-sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAC3() {
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitEAC3() {
unsigned syncStartPos = 0; // in bytes
unsigned payloadSize = 0;
sp<MetaData> format = new MetaData;
- ALOGV("dequeueAccessUnit_AC3[%d]: mBuffer %p(%zu)", mAUIndex, mBuffer->data(), mBuffer->size());
+ ALOGV("dequeueAccessUnitEAC3[%d]: mBuffer %p(%zu)", mAUIndex,
+ mBuffer->data(), mBuffer->size());
while (true) {
if (syncStartPos + 2 >= mBuffer->size()) {
return NULL;
}
- payloadSize = parseAC3SyncFrame(
- mBuffer->data() + syncStartPos,
- mBuffer->size() - syncStartPos,
- &format);
+ uint8_t *ptr = mBuffer->data() + syncStartPos;
+ size_t size = mBuffer->size() - syncStartPos;
+ if (mMode == AC3) {
+ payloadSize = parseAC3SyncFrame(ptr, size, &format);
+ } else if (mMode == EAC3) {
+ payloadSize = parseEAC3SyncFrame(ptr, size, &format);
+ }
if (payloadSize > 0) {
break;
}
- ALOGV("dequeueAccessUnit_AC3[%d]: syncStartPos %u payloadSize %u",
+ ALOGV("dequeueAccessUnitEAC3[%d]: syncStartPos %u payloadSize %u",
mAUIndex, syncStartPos, payloadSize);
++syncStartPos;
}
if (mBuffer->size() < syncStartPos + payloadSize) {
- ALOGV("Not enough buffer size for AC3");
+ ALOGV("Not enough buffer size for E/AC3");
return NULL;
}
@@ -811,7 +969,6 @@
mFormat = format;
}
-
int64_t timeUs = fetchTimestamp(syncStartPos + payloadSize);
if (timeUs < 0ll) {
ALOGE("negative timeUs");
@@ -820,7 +977,12 @@
// Not decrypting if key info not available (e.g., scanner/extractor parsing ts files)
if (mSampleDecryptor != NULL) {
- mSampleDecryptor->processAC3(mBuffer->data() + syncStartPos, payloadSize);
+ if (mMode == AC3) {
+ mSampleDecryptor->processAC3(mBuffer->data() + syncStartPos, payloadSize);
+ } else if (mMode == EAC3) {
+ ALOGE("EAC3 AU is encrypted and decryption is not supported");
+ return NULL;
+ }
}
mAUIndex++;
@@ -1024,25 +1186,11 @@
bool protection_absent = bits.getBits(1) != 0;
if (mFormat == NULL) {
- unsigned profile = bits.getBits(2);
- if (profile == 3u) {
- ALOGE("profile should not be 3");
- return NULL;
- }
- unsigned sampling_freq_index = bits.getBits(4);
- bits.getBits(1); // private_bit
- unsigned channel_configuration = bits.getBits(3);
- if (channel_configuration == 0u) {
- ALOGE("channel_config should not be 0");
- return NULL;
- }
- bits.skipBits(2); // original_copy, home
-
mFormat = new MetaData;
- MakeAACCodecSpecificData(*mFormat,
- profile, sampling_freq_index, channel_configuration);
-
- mFormat->setInt32(kKeyIsADTS, true);
+ if (!MakeAACCodecSpecificData(
+ *mFormat, mBuffer->data() + offset, mBuffer->size() - offset)) {
+ return NULL;
+ }
int32_t sampleRate;
int32_t numChannels;
@@ -1057,12 +1205,12 @@
ALOGI("found AAC codec config (%d Hz, %d channels)",
sampleRate, numChannels);
- } else {
- // profile_ObjectType, sampling_frequency_index, private_bits,
- // channel_configuration, original_copy, home
- bits.skipBits(12);
}
+ // profile_ObjectType, sampling_frequency_index, private_bits,
+ // channel_configuration, original_copy, home
+ bits.skipBits(12);
+
// adts_variable_header
// copyright_identification_bit, copyright_identification_start
@@ -1177,27 +1325,6 @@
}
sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
- if (isScrambled()) {
- if (mBuffer == NULL || mBuffer->size() == 0) {
- return NULL;
- }
- if (mFormat == NULL) {
- mFormat = new MetaData;
- if (!MakeAVCCodecSpecificData(*mFormat, mBuffer->data(), mBuffer->size())) {
- ALOGW("Creating dummy AVC format for scrambled content");
- mFormat = new MetaData;
- mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
- mFormat->setInt32(kKeyWidth, 1280);
- mFormat->setInt32(kKeyHeight, 720);
- }
- // for MediaExtractor.CasInfo
- mFormat->setInt32(kKeyCASystemID, mCASystemId);
- mFormat->setData(kKeyCASessionID, 0,
- mCasSessionId.data(), mCasSessionId.size());
- }
- return dequeueScrambledAccessUnit();
- }
-
const uint8_t *data = mBuffer->data();
size_t size = mBuffer->size();
@@ -1497,25 +1624,6 @@
}
sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() {
- if (isScrambled()) {
- if (mBuffer == NULL || mBuffer->size() == 0) {
- return NULL;
- }
- if (mFormat == NULL) {
- ALOGI("Creating dummy MPEG format for scrambled content");
- mFormat = new MetaData;
- mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
- mFormat->setInt32(kKeyWidth, 1280);
- mFormat->setInt32(kKeyHeight, 720);
-
- // for MediaExtractor.CasInfo
- mFormat->setInt32(kKeyCASystemID, mCASystemId);
- mFormat->setData(kKeyCASessionID, 0,
- mCasSessionId.data(), mCasSessionId.size());
- }
- return dequeueScrambledAccessUnit();
- }
-
const uint8_t *data = mBuffer->data();
size_t size = mBuffer->size();
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 399214a..3227f47 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -38,6 +38,7 @@
H264,
AAC,
AC3,
+ EAC3,
AC4,
MPEG_AUDIO,
MPEG_VIDEO,
@@ -60,6 +61,7 @@
void appendScrambledData(
const void *data, size_t size,
+ size_t leadingClearBytes,
int32_t keyId, bool isSync,
sp<ABuffer> clearSizes, sp<ABuffer> encSizes);
@@ -85,8 +87,8 @@
};
struct ScrambledRangeInfo {
- //int64_t mTimestampUs;
size_t mLength;
+ size_t mLeadingClearBytes;
int32_t mKeyId;
int32_t mIsSync;
sp<ABuffer> mClearSizes;
@@ -116,7 +118,7 @@
sp<ABuffer> dequeueAccessUnitH264();
sp<ABuffer> dequeueAccessUnitAAC();
- sp<ABuffer> dequeueAccessUnitAC3();
+ sp<ABuffer> dequeueAccessUnitEAC3();
sp<ABuffer> dequeueAccessUnitAC4();
sp<ABuffer> dequeueAccessUnitMPEGAudio();
sp<ABuffer> dequeueAccessUnitMPEGVideo();
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 6b20bca..42285f8 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -811,7 +811,13 @@
size_t *encryptedbytes) {
// size needed to store all the crypto data
- size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
+ size_t cryptosize;
+ // = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
+ if (__builtin_mul_overflow(sizeof(size_t) * 2, numsubsamples, &cryptosize) ||
+ __builtin_add_overflow(cryptosize, sizeof(AMediaCodecCryptoInfo), &cryptosize)) {
+ ALOGE("crypto size overflow");
+ return NULL;
+ }
AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
if (!ret) {
ALOGE("couldn't allocate %zu bytes", cryptosize);
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index 13b66ed..f5b3f92 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -40,6 +40,12 @@
"-Werror",
],
+ product_variables: {
+ product_is_iot: {
+ cflags: ["-DTARGET_ANDROID_THINGS"],
+ },
+ },
+
local_include_dirs: ["include"],
export_include_dirs: ["include"],
}
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 0d50be0..1c54aec 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -158,6 +158,27 @@
return ok;
}
+bool modifyDefaultAudioEffectsAllowed() {
+ static const String16 sModifyDefaultAudioEffectsAllowed(
+ "android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
+ // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
+ bool ok = PermissionCache::checkCallingPermission(sModifyDefaultAudioEffectsAllowed);
+
+#ifdef TARGET_ANDROID_THINGS
+ if (!ok) {
+ // Use a secondary permission on Android Things to allow a more lenient level of protection.
+ static const String16 sModifyDefaultAudioEffectsAndroidThingsAllowed(
+ "com.google.android.things.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
+ ok = PermissionCache::checkCallingPermission(
+ sModifyDefaultAudioEffectsAndroidThingsAllowed);
+ }
+ if (!ok) ALOGE("com.google.android.things.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
+#else
+ if (!ok) ALOGE("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
+#endif
+ return ok;
+}
+
bool dumpAllowed() {
static const String16 sDump("android.permission.DUMP");
// IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 0911744..98f54c2 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -68,6 +68,7 @@
bool captureHotwordAllowed(pid_t pid, uid_t uid);
bool settingsAllowed();
bool modifyAudioRoutingAllowed();
+bool modifyDefaultAudioEffectsAllowed();
bool dumpAllowed();
bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
status_t checkIMemory(const sp<IMemory>& iMemory);
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index c0aa477..2c26ba4 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -42,6 +42,7 @@
LOCAL_STATIC_LIBRARIES := \
libcpustats \
+ libjsoncpp \
libsndfile \
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9234364..43566b7 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -58,6 +58,8 @@
#include <audio_utils/primitives.h>
+#include <json/json.h>
+
#include <powermanager/PowerManager.h>
#include <media/IMediaLogService.h>
@@ -440,8 +442,11 @@
const bool formatJson = std::any_of(args.begin(), args.end(),
[](const String16 &arg) { return arg == String16("--json"); });
if (formatJson) {
+ Json::Value root = getJsonDump();
+ Json::FastWriter writer;
+ std::string rootStr = writer.write(root);
// XXX consider buffering if the string happens to be too long.
- dprintf(fd, "%s", getJsonString().c_str());
+ dprintf(fd, "%s", rootStr.c_str());
return NO_ERROR;
}
@@ -556,34 +561,30 @@
return NO_ERROR;
}
-std::string AudioFlinger::getJsonString()
+Json::Value AudioFlinger::getJsonDump()
{
- std::string jsonStr = "{\n";
+ Json::Value root(Json::objectValue);
const bool locked = dumpTryLock(mLock);
// failed to lock - AudioFlinger is probably deadlocked
if (!locked) {
- jsonStr += " \"deadlock_message\": ";
- jsonStr += kDeadlockedString;
- jsonStr += ",\n";
+ root["deadlock_message"] = kDeadlockedString;
}
// FIXME risky to access data structures without a lock held?
- jsonStr += " \"Playback_Threads\": [\n";
+ Json::Value playbackThreads = Json::arrayValue;
// dump playback threads
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- if (i != 0) {
- jsonStr += ",\n";
- }
- jsonStr += mPlaybackThreads.valueAt(i)->getJsonString();
+ playbackThreads.append(mPlaybackThreads.valueAt(i)->getJsonDump());
}
- jsonStr += "\n ]\n}\n";
if (locked) {
mLock.unlock();
}
- return jsonStr;
+ root["playback_threads"] = playbackThreads;
+
+ return root;
}
sp<AudioFlinger::Client> AudioFlinger::registerPid(pid_t pid)
@@ -2949,16 +2950,74 @@
}
status_t AudioFlinger::getEffectDescriptor(const effect_uuid_t *pUuid,
- effect_descriptor_t *descriptor) const
+ const effect_uuid_t *pTypeUuid,
+ uint32_t preferredTypeFlag,
+ effect_descriptor_t *descriptor) const
{
+ if (pUuid == NULL || pTypeUuid == NULL || descriptor == NULL) {
+ return BAD_VALUE;
+ }
+
Mutex::Autolock _l(mLock);
- if (mEffectsFactoryHal.get()) {
- return mEffectsFactoryHal->getDescriptor(pUuid, descriptor);
- } else {
+
+ if (!mEffectsFactoryHal.get()) {
return -ENODEV;
}
-}
+ status_t status = NO_ERROR;
+ if (!EffectsFactoryHalInterface::isNullUuid(pUuid)) {
+ // If uuid is specified, request effect descriptor from that.
+ status = mEffectsFactoryHal->getDescriptor(pUuid, descriptor);
+ } else if (!EffectsFactoryHalInterface::isNullUuid(pTypeUuid)) {
+ // If uuid is not specified, look for an available implementation
+ // of the required type instead.
+
+ // Use a temporary descriptor to avoid modifying |descriptor| in the failure case.
+ effect_descriptor_t desc;
+ desc.flags = 0; // prevent compiler warning
+
+ uint32_t numEffects = 0;
+ status = mEffectsFactoryHal->queryNumberEffects(&numEffects);
+ if (status < 0) {
+ ALOGW("getEffectDescriptor() error %d from FactoryHal queryNumberEffects", status);
+ return status;
+ }
+
+ bool found = false;
+ for (uint32_t i = 0; i < numEffects; i++) {
+ status = mEffectsFactoryHal->getDescriptor(i, &desc);
+ if (status < 0) {
+ ALOGW("getEffectDescriptor() error %d from FactoryHal getDescriptor", status);
+ continue;
+ }
+ if (memcmp(&desc.type, pTypeUuid, sizeof(effect_uuid_t)) == 0) {
+ // If matching type found save effect descriptor.
+ found = true;
+ *descriptor = desc;
+
+ // If there's no preferred flag or this descriptor matches the preferred
+ // flag, success! If this descriptor doesn't match the preferred
+ // flag, continue enumeration in case a better matching version of this
+ // effect type is available. Note that this means if no effect with a
+ // correct flag is found, the descriptor returned will correspond to the
+ // last effect that at least had a matching type uuid (if any).
+ if (preferredTypeFlag == EFFECT_FLAG_TYPE_MASK ||
+ (desc.flags & EFFECT_FLAG_TYPE_MASK) == preferredTypeFlag) {
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ status = NAME_NOT_FOUND;
+ ALOGW("getEffectDescriptor(): Effect not found by type.");
+ }
+ } else {
+ status = BAD_VALUE;
+ ALOGE("getEffectDescriptor(): Either uuid or type uuid must be non-null UUIDs.");
+ }
+ return status;
+}
sp<IEffect> AudioFlinger::createEffect(
effect_descriptor_t *pDesc,
@@ -3012,60 +3071,15 @@
}
{
- if (!EffectsFactoryHalInterface::isNullUuid(&pDesc->uuid)) {
- // if uuid is specified, request effect descriptor
- lStatus = mEffectsFactoryHal->getDescriptor(&pDesc->uuid, &desc);
- if (lStatus < 0) {
- ALOGW("createEffect() error %d from EffectGetDescriptor", lStatus);
- goto Exit;
- }
- } else {
- // if uuid is not specified, look for an available implementation
- // of the required type in effect factory
- if (EffectsFactoryHalInterface::isNullUuid(&pDesc->type)) {
- ALOGW("createEffect() no effect type");
- lStatus = BAD_VALUE;
- goto Exit;
- }
- uint32_t numEffects = 0;
- effect_descriptor_t d;
- d.flags = 0; // prevent compiler warning
- bool found = false;
-
- lStatus = mEffectsFactoryHal->queryNumberEffects(&numEffects);
- if (lStatus < 0) {
- ALOGW("createEffect() error %d from EffectQueryNumberEffects", lStatus);
- goto Exit;
- }
- for (uint32_t i = 0; i < numEffects; i++) {
- lStatus = mEffectsFactoryHal->getDescriptor(i, &desc);
- if (lStatus < 0) {
- ALOGW("createEffect() error %d from EffectQueryEffect", lStatus);
- continue;
- }
- if (memcmp(&desc.type, &pDesc->type, sizeof(effect_uuid_t)) == 0) {
- // If matching type found save effect descriptor. If the session is
- // 0 and the effect is not auxiliary, continue enumeration in case
- // an auxiliary version of this effect type is available
- found = true;
- d = desc;
- if (sessionId != AUDIO_SESSION_OUTPUT_MIX ||
- (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
- break;
- }
- }
- }
- if (!found) {
- lStatus = BAD_VALUE;
- ALOGW("createEffect() effect not found");
- goto Exit;
- }
- // For same effect type, chose auxiliary version over insert version if
- // connect to output mix (Compliance to OpenSL ES)
- if (sessionId == AUDIO_SESSION_OUTPUT_MIX &&
- (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) {
- desc = d;
- }
+ // Get the full effect descriptor from the uuid/type.
+ // If the session is the output mix, prefer an auxiliary effect,
+ // otherwise no preference.
+ uint32_t preferredType = (sessionId == AUDIO_SESSION_OUTPUT_MIX ?
+ EFFECT_FLAG_TYPE_AUXILIARY : EFFECT_FLAG_TYPE_MASK);
+ lStatus = getEffectDescriptor(&pDesc->uuid, &pDesc->type, preferredType, &desc);
+ if (lStatus < 0) {
+ ALOGW("createEffect() error %d from getEffectDescriptor", lStatus);
+ goto Exit;
}
// Do not allow auxiliary effects on a session different from 0 (output mix)
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 95b947c..e9e6e94 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -79,6 +79,7 @@
#include <powermanager/IPowerManager.h>
+#include <json/json.h>
#include <media/nblog/NBLog.h>
#include <private/media/AudioEffectShared.h>
#include <private/media/AudioTrackShared.h>
@@ -114,7 +115,7 @@
static const char* getServiceName() ANDROID_API { return "media.audio_flinger"; }
virtual status_t dump(int fd, const Vector<String16>& args);
- std::string getJsonString();
+ Json::Value getJsonDump();
// IAudioFlinger interface, in binder opcode order
virtual sp<IAudioTrack> createTrack(const CreateTrackInput& input,
@@ -208,6 +209,8 @@
virtual status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor) const;
virtual status_t getEffectDescriptor(const effect_uuid_t *pUuid,
+ const effect_uuid_t *pTypeUuid,
+ uint32_t preferredTypeFlag,
effect_descriptor_t *descriptor) const;
virtual sp<IEffect> createEffect(
diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
index e26dca1..2abfbfb 100644
--- a/services/audioflinger/FastMixerDumpState.cpp
+++ b/services/audioflinger/FastMixerDumpState.cpp
@@ -24,6 +24,7 @@
#include <cpustats/ThreadCpuUsage.h>
#endif
#endif
+#include <json/json.h>
#include <string>
#include <utils/Debug.h>
#include <utils/Log.h>
@@ -205,14 +206,13 @@
}
}
-// TODO get rid of extraneous lines and use better key names.
-// TODO may go back to using a library to do the json formatting.
-std::string FastMixerDumpState::getJsonString() const
+Json::Value FastMixerDumpState::getJsonDump() const
{
+ Json::Value root(Json::objectValue);
if (mCommand == FastMixerState::INITIAL) {
- return " {\n \"status\": \"uninitialized\"\n }";
+ root["status"] = "uninitialized";
+ return root;
}
- std::string jsonStr = " {\n";
#ifdef FAST_THREAD_STATISTICS
// find the interval of valid samples
const uint32_t bounds = mBounds;
@@ -230,31 +230,25 @@
}
// statistics for monotonic (wall clock) time, thread raw CPU load in time, CPU clock frequency,
// and adjusted CPU load in MHz normalized for CPU clock frequency
- std::string jsonWallStr = " \"wall_clock_time\":[";
- std::string jsonLoadNsStr = " \"raw_cpu_load\":[";
+ Json::Value jsonWall(Json::arrayValue);
+ Json::Value jsonLoadNs(Json::arrayValue);
// loop over all the samples
for (uint32_t j = 0; j < n; ++j) {
size_t i = oldestClosed++ & (mSamplingN - 1);
uint32_t wallNs = mMonotonicNs[i];
- if (j != 0) {
- jsonWallStr += ',';
- jsonLoadNsStr += ',';
- }
- /* jsonObject["wall"].append(wallNs); */
- jsonWallStr += std::to_string(wallNs);
+ jsonWall.append(wallNs);
uint32_t sampleLoadNs = mLoadNs[i];
- jsonLoadNsStr += std::to_string(sampleLoadNs);
+ jsonLoadNs.append(sampleLoadNs);
}
- jsonWallStr += ']';
- jsonLoadNsStr += ']';
if (n) {
- jsonStr += jsonWallStr + ",\n" + jsonLoadNsStr + "\n";
+ root["wall_clock_time_ns"] = jsonWall;
+ root["raw_cpu_load_ns"] = jsonLoadNs;
+ root["status"] = "ok";
} else {
- //dprintf(fd, " No FastMixer statistics available currently\n");
+ root["status"] = "unavailable";
}
#endif
- jsonStr += " }";
- return jsonStr;
+ return root;
}
} // android
diff --git a/services/audioflinger/FastMixerDumpState.h b/services/audioflinger/FastMixerDumpState.h
index 81c4175..69c2e4e 100644
--- a/services/audioflinger/FastMixerDumpState.h
+++ b/services/audioflinger/FastMixerDumpState.h
@@ -20,6 +20,7 @@
#include <stdint.h>
#include <string>
#include <audio_utils/TimestampVerifier.h>
+#include <json/json.h>
#include "Configuration.h"
#include "FastThreadDumpState.h"
#include "FastMixerState.h"
@@ -67,7 +68,7 @@
/*virtual*/ ~FastMixerDumpState();
void dump(int fd) const; // should only be called on a stable copy, not the original
- std::string getJsonString() const; // should only be called on a stable copy, not the original
+ Json::Value getJsonDump() const; // should only be called on a stable copy, not the original
double mLatencyMs = 0.; // measured latency, default of 0 if no valid timestamp read.
uint32_t mWriteSequence; // incremented before and after each write()
diff --git a/services/audioflinger/PatchPanel.cpp b/services/audioflinger/PatchPanel.cpp
index ada8572..7b165a1 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -547,14 +547,46 @@
// reverse due to internal biases).
//
// TODO: is this stable enough? Consider a PatchTrack synchronized version of this.
- double recordServerLatencyMs;
- if (recordTrack->getServerLatencyMs(&recordServerLatencyMs) != OK) return INVALID_OPERATION;
- double playbackTrackLatencyMs;
- if (playbackTrack->getTrackLatencyMs(&playbackTrackLatencyMs) != OK) return INVALID_OPERATION;
+ // For PCM tracks get server latency.
+ if (audio_is_linear_pcm(recordTrack->format())) {
+ double recordServerLatencyMs, playbackTrackLatencyMs;
+ if (recordTrack->getServerLatencyMs(&recordServerLatencyMs) == OK
+ && playbackTrack->getTrackLatencyMs(&playbackTrackLatencyMs) == OK) {
+ *latencyMs = recordServerLatencyMs + playbackTrackLatencyMs;
+ return OK;
+ }
+ }
- *latencyMs = recordServerLatencyMs + playbackTrackLatencyMs;
- return OK;
+ // See if kernel latencies are available.
+ // If so, do a frame diff and time difference computation to estimate
+ // the total patch latency. This requires that frame counts are reported by the
+ // HAL are matched properly in the case of record overruns and playback underruns.
+ ThreadBase::TrackBase::FrameTime recordFT{}, playFT{};
+ recordTrack->getKernelFrameTime(&recordFT);
+ playbackTrack->getKernelFrameTime(&playFT);
+ if (recordFT.timeNs > 0 && playFT.timeNs > 0) {
+ const int64_t frameDiff = recordFT.frames - playFT.frames;
+ const int64_t timeDiffNs = recordFT.timeNs - playFT.timeNs;
+
+ // It is possible that the patch track and patch record have a large time disparity because
+ // one thread runs but another is stopped. We arbitrarily choose the maximum timestamp
+ // time difference based on how often we expect the timestamps to update in normal operation
+ // (typical should be no more than 50 ms).
+ //
+ // If the timestamps aren't sampled close enough, the patch latency is not
+ // considered valid.
+ //
+ // TODO: change this based on more experiments.
+ constexpr int64_t maxValidTimeDiffNs = 200 * NANOS_PER_MILLISECOND;
+ if (std::abs(timeDiffNs) < maxValidTimeDiffNs) {
+ *latencyMs = frameDiff * 1e3 / recordTrack->sampleRate()
+ - timeDiffNs * 1e-6;
+ return OK;
+ }
+ }
+
+ return INVALID_OPERATION;
}
String8 AudioFlinger::PatchPanel::Patch::dump(audio_patch_handle_t myHandle) const
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index 269a398..2d9bd8e 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -35,6 +35,7 @@
// Must be called under AudioFlinger::mLock
status_t getLatencyMs_l(double *latencyMs) const;
+ audio_patch_handle_t getPatchHandle() const { return mPatchHandle; };
audio_io_handle_t getPlaybackThreadHandle() const { return mPlaybackThreadHandle; };
audio_io_handle_t getRecordThreadHandle() const { return mRecordThreadHandle; };
private:
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 79147af..c73a446 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -42,6 +42,7 @@
#include <audio_utils/primitives.h>
#include <audio_utils/format.h>
#include <audio_utils/minifloat.h>
+#include <json/json.h>
#include <system/audio_effects/effect_ns.h>
#include <system/audio_effects/effect_aec.h>
#include <system/audio.h>
@@ -862,6 +863,7 @@
|| mType == DIRECT
|| mType == OFFLOAD) {
dprintf(fd, " Timestamp stats: %s\n", mTimestampVerifier.toString().c_str());
+ dprintf(fd, " Timestamp corrected: %s\n", isTimestampCorrectionEnabled() ? "yes" : "no");
}
if (locked) {
@@ -1731,10 +1733,21 @@
if (mOutput->audioHwDev->canSetMasterMute()) {
mMasterMute = false;
}
+ mIsMsdDevice = strcmp(
+ mOutput->audioHwDev->moduleName(), AUDIO_HARDWARE_MODULE_ID_MSD) == 0;
}
readOutputParameters_l();
+ // TODO: We may also match on address as well as device type for
+ // AUDIO_DEVICE_OUT_BUS, AUDIO_DEVICE_OUT_ALL_A2DP, AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+ if (type == MIXER || type == DIRECT) {
+ mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
+ "audio.timestamp.corrected_output_devices",
+ (int64_t)(mIsMsdDevice ? AUDIO_DEVICE_OUT_BUS // turn on by default for MSD
+ : AUDIO_DEVICE_NONE));
+ }
+
// ++ operator does not compile
for (audio_stream_type_t stream = AUDIO_STREAM_MIN; stream < AUDIO_STREAM_FOR_POLICY_CNT;
stream = (audio_stream_type_t) (stream + 1)) {
@@ -1763,9 +1776,9 @@
mLocalLog.dump(fd, " " /* prefix */, 40 /* lines */);
}
-std::string AudioFlinger::PlaybackThread::getJsonString() const
+Json::Value AudioFlinger::PlaybackThread::getJsonDump() const
{
- return "{}";
+ return Json::Value(Json::objectValue);
}
void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args __unused)
@@ -3207,6 +3220,8 @@
if (mType == OFFLOAD || mType == DIRECT) {
mTimestampVerifier.setDiscontinuityMode(mTimestampVerifier.DISCONTINUITY_MODE_ZERO);
}
+ audio_utils::Statistics<double> downstreamLatencyStatMs(0.999 /* alpha */);
+ audio_patch_handle_t lastDownstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
while (!exitPending())
{
@@ -3218,6 +3233,46 @@
Vector< sp<EffectChain> > effectChains;
+ // If the device is AUDIO_DEVICE_OUT_BUS, check for downstream latency.
+ //
+ // Note: we access outDevice() outside of mLock.
+ if (isMsdDevice() && (outDevice() & AUDIO_DEVICE_OUT_BUS) != 0) {
+ // Here, we try for the AF lock, but do not block on it as the latency
+ // is more informational.
+ if (mAudioFlinger->mLock.tryLock() == NO_ERROR) {
+ std::vector<PatchPanel::SoftwarePatch> swPatches;
+ double latencyMs;
+ status_t status = INVALID_OPERATION;
+ audio_patch_handle_t downstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ if (mAudioFlinger->mPatchPanel.getDownstreamSoftwarePatches(id(), &swPatches) == OK
+ && swPatches.size() > 0) {
+ status = swPatches[0].getLatencyMs_l(&latencyMs);
+ downstreamPatchHandle = swPatches[0].getPatchHandle();
+ }
+ if (downstreamPatchHandle != lastDownstreamPatchHandle) {
+ downstreamLatencyStatMs.reset();
+ lastDownstreamPatchHandle = downstreamPatchHandle;
+ }
+ if (status == OK) {
+ // verify downstream latency (we assume a max reasonable
+ // latency of 1 second).
+ if (latencyMs >= 0. && latencyMs <= 1000.) {
+ ALOGV("new downstream latency %lf ms", latencyMs);
+ downstreamLatencyStatMs.add(latencyMs);
+ } else {
+ ALOGD("out of range downstream latency %lf ms", latencyMs);
+ }
+ }
+ mAudioFlinger->mLock.unlock();
+ }
+ } else {
+ if (lastDownstreamPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
+ // our device is no longer AUDIO_DEVICE_OUT_BUS, reset patch handle and stats.
+ downstreamLatencyStatMs.reset();
+ lastDownstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ }
+ }
+
{ // scope for mLock
Mutex::Autolock _l(mLock);
@@ -3247,6 +3302,33 @@
mTimestampVerifier.add(timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
mSampleRate);
+
+ if (isTimestampCorrectionEnabled()) {
+ ALOGV("TS_BEFORE: %d %lld %lld", id(),
+ (long long)timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
+ (long long)timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]);
+ auto correctedTimestamp = mTimestampVerifier.getLastCorrectedTimestamp();
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+ = correctedTimestamp.mFrames;
+ timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]
+ = correctedTimestamp.mTimeNs;
+ ALOGV("TS_AFTER: %d %lld %lld", id(),
+ (long long)timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
+ (long long)timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]);
+
+ // Note: Downstream latency only added if timestamp correction enabled.
+ if (downstreamLatencyStatMs.getN() > 0) { // we have latency info.
+ const int64_t newPosition =
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+ - int64_t(downstreamLatencyStatMs.getMean() * mSampleRate * 1e-3);
+ // prevent retrograde
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = max(
+ newPosition,
+ (mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+ - mSuspendedFrames));
+ }
+ }
+
// We always fetch the timestamp here because often the downstream
// sink will block while writing.
@@ -5141,14 +5223,20 @@
}
}
-std::string AudioFlinger::MixerThread::getJsonString() const
+Json::Value AudioFlinger::MixerThread::getJsonDump() const
{
- // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
- // while we are dumping it. It may be inconsistent, but it won't mutate!
- // This is a large object so we place it on the heap.
- // FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
- return std::unique_ptr<FastMixerDumpState>(new FastMixerDumpState(mFastMixerDumpState))
- ->getJsonString();
+ Json::Value root;
+ if (hasFastMixer()) {
+ // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
+ // while we are dumping it. It may be inconsistent, but it won't mutate!
+ // This is a large object so we place it on the heap.
+ // FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
+ const std::unique_ptr<FastMixerDumpState> copy(new FastMixerDumpState(mFastMixerDumpState));
+ root["fastmixer_stats"] = copy->getJsonDump();
+ } else {
+ root["fastmixer_stats"] = "no_fastmixer";
+ }
+ return root;
}
uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const
@@ -6361,8 +6449,20 @@
snprintf(mThreadName, kThreadNameLength, "AudioIn_%X", id);
mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
+ if (mInput != nullptr && mInput->audioHwDev != nullptr) {
+ mIsMsdDevice = strcmp(
+ mInput->audioHwDev->moduleName(), AUDIO_HARDWARE_MODULE_ID_MSD) == 0;
+ }
+
readInputParameters_l();
+ // TODO: We may also match on address as well as device type for
+ // AUDIO_DEVICE_IN_BUS, AUDIO_DEVICE_IN_BLUETOOTH_A2DP, AUDIO_DEVICE_IN_REMOTE_SUBMIX
+ mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
+ "audio.timestamp.corrected_input_devices",
+ (int64_t)(mIsMsdDevice ? AUDIO_DEVICE_IN_BUS // turn on by default for MSD
+ : AUDIO_DEVICE_NONE));
+
// create an NBAIO source for the HAL input stream, and negotiate
mInputSource = new AudioStreamInSource(input->stream);
size_t numCounterOffers = 0;
@@ -6733,8 +6833,7 @@
// If an NBAIO source is present, use it to read the normal capture's data
if (mPipeSource != 0) {
- size_t framesToRead = mBufferSize / mFrameSize;
- framesToRead = min(mRsmpInFramesOA - rear, mRsmpInFramesP2 / 2);
+ size_t framesToRead = min(mRsmpInFramesOA - rear, mRsmpInFramesP2 / 2);
// The audio fifo read() returns OVERRUN on overflow, and advances the read pointer
// to the full buffer point (clearing the overflow condition). Upon OVERRUN error,
@@ -6798,7 +6897,22 @@
int64_t position, time;
if (mStandby) {
mTimestampVerifier.discontinuity();
- } else if (mInput->stream->getCapturePosition(&position, &time) == NO_ERROR) {
+ } else if (mInput->stream->getCapturePosition(&position, &time) == NO_ERROR
+ && time > mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]) {
+
+ mTimestampVerifier.add(position, time, mSampleRate);
+
+ // Correct timestamps
+ if (isTimestampCorrectionEnabled()) {
+ ALOGV("TS_BEFORE: %d %lld %lld",
+ id(), (long long)time, (long long)position);
+ auto correctedTimestamp = mTimestampVerifier.getLastCorrectedTimestamp();
+ position = correctedTimestamp.mFrames;
+ time = correctedTimestamp.mTimeNs;
+ ALOGV("TS_AFTER: %d %lld %lld",
+ id(), (long long)time, (long long)position);
+ }
+
mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = position;
mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = time;
// Note: In general record buffers should tend to be empty in
@@ -6806,10 +6920,6 @@
//
// Also, it is not advantageous to call get_presentation_position during the read
// as the read obtains a lock, preventing the timestamp call from executing.
-
- mTimestampVerifier.add(mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
- mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
- mSampleRate);
} else {
mTimestampVerifier.error();
}
@@ -6827,6 +6937,7 @@
goto unlock;
}
ALOG_ASSERT(framesRead > 0);
+ mFramesRead += framesRead;
#ifdef TEE_SINK
(void)mTee.write((uint8_t*)mRsmpInBuffer + rear * mFrameSize, framesRead);
@@ -7451,6 +7562,7 @@
audio_input_flags_t flags = input != NULL ? input->flags : AUDIO_INPUT_FLAG_NONE;
dprintf(fd, " AudioStreamIn: %p flags %#x (%s)\n",
input, flags, inputFlagsToString(flags).c_str());
+ dprintf(fd, " Frames read: %lld\n", (long long)mFramesRead);
if (mActiveTracks.isEmpty()) {
dprintf(fd, " No active record clients\n");
}
@@ -7460,7 +7572,8 @@
(void)input->stream->dump(fd);
}
- const double latencyMs = - mTimestamp.getOutputServerLatencyMs(mSampleRate);
+ const double latencyMs = audio_is_linear_pcm(mFormat)
+ ? - mTimestamp.getOutputServerLatencyMs(mSampleRate) : 0.;
if (latencyMs != 0.) {
dprintf(fd, " NormalRecord latency ms: %.2lf\n", latencyMs);
} else {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index f0d625c..37b3870 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -393,6 +393,10 @@
void broadcast_l();
+ virtual bool isTimestampCorrectionEnabled() const { return false; }
+
+ bool isMsdDevice() const { return mIsMsdDevice; }
+
mutable Mutex mLock;
protected:
@@ -501,7 +505,8 @@
ExtendedTimestamp mTimestamp;
TimestampVerifier< // For timestamp statistics.
int64_t /* frame count */, int64_t /* time ns */> mTimestampVerifier;
-
+ audio_devices_t mTimestampCorrectedDevices = AUDIO_DEVICE_NONE;
+ bool mIsMsdDevice = false;
// A condition that must be evaluated by the thread loop has changed and
// we must not wait for async write callback in the thread loop before evaluating it
bool mSignalPending;
@@ -662,7 +667,7 @@
void dump(int fd, const Vector<String16>& args);
// returns a string of audio performance related data in JSON format.
- virtual std::string getJsonString() const;
+ virtual Json::Value getJsonDump() const;
// Thread virtuals
virtual bool threadLoop();
@@ -816,6 +821,11 @@
&& mTracks.size() < PlaybackThread::kMaxTracks;
}
+ bool isTimestampCorrectionEnabled() const override {
+ const audio_devices_t device =
+ mOutDevice & mTimestampCorrectedDevices;
+ return audio_is_output_devices(device) && popcount(device) > 0;
+ }
protected:
// updated by readOutputParameters_l()
size_t mNormalFrameCount; // normal mixer and effects
@@ -1108,7 +1118,7 @@
virtual bool checkForNewParameter_l(const String8& keyValuePair,
status_t& status);
virtual void dumpInternals(int fd, const Vector<String16>& args);
- std::string getJsonString() const override;
+ Json::Value getJsonDump() const override;
virtual bool isTrackAllowed_l(
audio_channel_mask_t channelMask, audio_format_t format,
@@ -1532,6 +1542,11 @@
bool fastTrackAvailable() const { return mFastTrackAvail; }
+ bool isTimestampCorrectionEnabled() const override {
+ // checks popcount for exactly one device.
+ return audio_is_input_device(
+ mInDevice & mTimestampCorrectedDevices);
+ }
private:
// Enter standby if not already in standby, and set mStandby flag
void standbyIfNotAlreadyInStandby();
@@ -1601,6 +1616,8 @@
bool mFastTrackAvail; // true if fast track available
// common state to all record threads
std::atomic_bool mBtNrecSuspended;
+
+ int64_t mFramesRead = 0; // continuous running counter.
};
class MmapThread : public ThreadBase
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 95da9d7..a43cb75 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -187,6 +187,19 @@
return status;
}
+ // TODO: Consider making this external.
+ struct FrameTime {
+ int64_t frames;
+ int64_t timeNs;
+ };
+
+ // KernelFrameTime is updated per "mix" period even for non-pcm tracks.
+ void getKernelFrameTime(FrameTime *ft) const {
+ *ft = mKernelFrameTime.load();
+ }
+
+ audio_format_t format() const { return mFormat; }
+
protected:
DISALLOW_COPY_AND_ASSIGN(TrackBase);
@@ -198,8 +211,6 @@
// but putting it in TrackBase avoids the complexity of virtual inheritance
virtual size_t framesReady() const { return SIZE_MAX; }
- audio_format_t format() const { return mFormat; }
-
uint32_t channelCount() const { return mChannelCount; }
audio_channel_mask_t channelMask() const { return mChannelMask; }
@@ -307,6 +318,7 @@
bool mServerLatencySupported = false;
std::atomic<bool> mServerLatencyFromTrack{}; // latency from track or server timestamp.
std::atomic<double> mServerLatencyMs{}; // last latency pushed from server thread.
+ std::atomic<FrameTime> mKernelFrameTime{}; // last frame time on kernel side.
};
// PatchProxyBufferProvider interface is implemented by PatchTrack and PatchRecord.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 8b9485f..78e6c6c 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1258,6 +1258,16 @@
void AudioFlinger::PlaybackThread::Track::updateTrackFrameInfo(
int64_t trackFramesReleased, int64_t sinkFramesWritten,
uint32_t halSampleRate, const ExtendedTimestamp &timeStamp) {
+ // Make the kernel frametime available.
+ const FrameTime ft{
+ timeStamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
+ timeStamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]};
+ // ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
+ mKernelFrameTime.store(ft);
+ if (!audio_is_linear_pcm(mFormat)) {
+ return;
+ }
+
//update frame map
mFrameMap.push(trackFramesReleased, sinkFramesWritten);
@@ -1720,7 +1730,7 @@
thread->mFastTrackAvail = false;
} else {
// TODO: only Normal Record has timestamps (Fast Record does not).
- mServerLatencySupported = true;
+ mServerLatencySupported = audio_is_linear_pcm(mFormat);
}
#ifdef TEE_SINK
mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
@@ -1886,6 +1896,16 @@
int64_t trackFramesReleased, int64_t sourceFramesRead,
uint32_t halSampleRate, const ExtendedTimestamp ×tamp)
{
+ // Make the kernel frametime available.
+ const FrameTime ft{
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
+ timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]};
+ // ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
+ mKernelFrameTime.store(ft);
+ if (!audio_is_linear_pcm(mFormat)) {
+ return;
+ }
+
ExtendedTimestamp local = timestamp;
// Convert HAL frames to server-side track frames at track sample rate.
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 92f6c79..b0e6b0f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -1514,11 +1514,6 @@
setStrategyMute(STRATEGY_SONIFICATION, true, outputDesc);
}
- if (stream == AUDIO_STREAM_ENFORCED_AUDIBLE &&
- mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
- setStrategyMute(STRATEGY_SONIFICATION, true, outputDesc);
- }
-
return NO_ERROR;
}
@@ -4761,6 +4756,7 @@
nextAudioPortGeneration();
+ audio_devices_t device = inputDesc->mDevice;
ssize_t index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
if (index >= 0) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
@@ -4771,6 +4767,12 @@
inputDesc->close();
mInputs.removeItem(input);
+
+ audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
+ if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
+ mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
+ SoundTrigger::setCaptureState(false);
+ }
}
SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(
@@ -5813,39 +5815,7 @@
return AUDIO_STREAM_TTS;
}
- // usage to stream type mapping
- switch (attr->usage) {
- case AUDIO_USAGE_MEDIA:
- case AUDIO_USAGE_GAME:
- case AUDIO_USAGE_ASSISTANT:
- case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
- return AUDIO_STREAM_MUSIC;
- case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
- return AUDIO_STREAM_ACCESSIBILITY;
- case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
- return AUDIO_STREAM_SYSTEM;
- case AUDIO_USAGE_VOICE_COMMUNICATION:
- return AUDIO_STREAM_VOICE_CALL;
-
- case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
- return AUDIO_STREAM_DTMF;
-
- case AUDIO_USAGE_ALARM:
- return AUDIO_STREAM_ALARM;
- case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
- return AUDIO_STREAM_RING;
-
- case AUDIO_USAGE_NOTIFICATION:
- case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
- case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
- case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
- case AUDIO_USAGE_NOTIFICATION_EVENT:
- return AUDIO_STREAM_NOTIFICATION;
-
- case AUDIO_USAGE_UNKNOWN:
- default:
- return AUDIO_STREAM_MUSIC;
- }
+ return audio_usage_to_stream_type(attr->usage);
}
bool AudioPolicyManager::isValidAttributes(const audio_attributes_t *paa)
diff --git a/services/audiopolicy/service/AudioPolicyEffects.cpp b/services/audiopolicy/service/AudioPolicyEffects.cpp
index fdae23b..2858aad 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.cpp
+++ b/services/audiopolicy/service/AudioPolicyEffects.cpp
@@ -23,6 +23,7 @@
#include <memory>
#include <cutils/misc.h>
#include <media/AudioEffect.h>
+#include <media/AudioPolicyHelper.h>
#include <media/EffectsConfig.h>
#include <mediautils/ServiceUtilities.h>
#include <system/audio.h>
@@ -317,6 +318,102 @@
return status;
}
+status_t AudioPolicyEffects::addStreamDefaultEffect(const effect_uuid_t *type,
+ const String16& opPackageName,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ audio_usage_t usage,
+ audio_unique_id_t* id)
+{
+ if (uuid == NULL || type == NULL) {
+ ALOGE("addStreamDefaultEffect(): Null uuid or type uuid pointer");
+ return BAD_VALUE;
+ }
+
+ audio_stream_type_t stream = audio_usage_to_stream_type(usage);
+
+ if (stream < AUDIO_STREAM_MIN || stream >= AUDIO_STREAM_PUBLIC_CNT) {
+ ALOGE("addStreamDefaultEffect(): Unsupported stream type %d", stream);
+ return BAD_VALUE;
+ }
+
+ // Check that |uuid| or |type| corresponds to an effect on the system.
+ effect_descriptor_t descriptor = {};
+ status_t res = AudioEffect::getEffectDescriptor(
+ uuid, type, EFFECT_FLAG_TYPE_INSERT, &descriptor);
+ if (res != OK) {
+ ALOGE("addStreamDefaultEffect(): Failed to find effect descriptor matching uuid/type.");
+ return res;
+ }
+
+ // Only insert effects can be added dynamically as stream defaults.
+ if ((descriptor.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_INSERT) {
+ ALOGE("addStreamDefaultEffect(): Desired effect cannot be attached "
+ "as a stream default effect.");
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mLock);
+
+ // Find the EffectDescVector for the given stream type, or create a new one if necessary.
+ ssize_t index = mOutputStreams.indexOfKey(stream);
+ EffectDescVector *desc = NULL;
+ if (index < 0) {
+ // No effects for this stream type yet.
+ desc = new EffectDescVector();
+ mOutputStreams.add(stream, desc);
+ } else {
+ desc = mOutputStreams.valueAt(index);
+ }
+
+ // Create a new effect and add it to the vector.
+ res = AudioEffect::newEffectUniqueId(id);
+ if (res != OK) {
+ ALOGE("addStreamDefaultEffect(): failed to get new unique id.");
+ return res;
+ }
+ EffectDesc *effect = new EffectDesc(
+ descriptor.name, *type, opPackageName, *uuid, priority, *id);
+ desc->mEffects.add(effect);
+ // TODO(b/71813697): Support setting params as well.
+
+ // TODO(b/71814300): Retroactively attach to any existing streams of the given type.
+ // This requires tracking the stream type of each session id in addition to what is
+ // already being tracked.
+
+ return NO_ERROR;
+}
+
+status_t AudioPolicyEffects::removeStreamDefaultEffect(audio_unique_id_t id)
+{
+ if (id == AUDIO_UNIQUE_ID_ALLOCATE) {
+ // ALLOCATE is not a unique identifier, but rather a reserved value indicating
+ // a real id has not been assigned. For default effects, this value is only used
+ // by system-owned defaults from the loaded config, which cannot be removed.
+ return BAD_VALUE;
+ }
+
+ Mutex::Autolock _l(mLock);
+
+ // Check each stream type.
+ size_t numStreams = mOutputStreams.size();
+ for (size_t i = 0; i < numStreams; ++i) {
+ // Check each effect for each stream.
+ EffectDescVector* descVector = mOutputStreams[i];
+ for (auto desc = descVector->mEffects.begin(); desc != descVector->mEffects.end(); ++desc) {
+ if ((*desc)->mId == id) {
+ // Found it!
+ // TODO(b/71814300): Remove from any streams the effect was attached to.
+ descVector->mEffects.erase(desc);
+ // Handles are unique; there can only be one match, so return early.
+ return NO_ERROR;
+ }
+ }
+ }
+
+ // Effect wasn't found, so it's been trivially removed successfully.
+ return NO_ERROR;
+}
void AudioPolicyEffects::EffectVector::setProcessorEnabled(bool enabled)
{
diff --git a/services/audiopolicy/service/AudioPolicyEffects.h b/services/audiopolicy/service/AudioPolicyEffects.h
index 623180e..69367b1 100644
--- a/services/audiopolicy/service/AudioPolicyEffects.h
+++ b/services/audiopolicy/service/AudioPolicyEffects.h
@@ -64,7 +64,6 @@
status_t releaseInputEffects(audio_io_handle_t input,
audio_session_t audioSession);
-
// Return a list of effect descriptors for default output effects
// associated with audioSession
status_t queryDefaultOutputSessionEffects(audio_session_t audioSession,
@@ -82,18 +81,49 @@
audio_stream_type_t stream,
audio_session_t audioSession);
+ // Add the effect to the list of default effects for streams of type |stream|.
+ status_t addStreamDefaultEffect(const effect_uuid_t *type,
+ const String16& opPackageName,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ audio_usage_t usage,
+ audio_unique_id_t* id);
+
+ // Remove the default stream effect from wherever it's attached.
+ status_t removeStreamDefaultEffect(audio_unique_id_t id);
+
private:
// class to store the description of an effects and its parameters
// as defined in audio_effects.conf
class EffectDesc {
public:
- EffectDesc(const char *name, const effect_uuid_t& uuid) :
+ EffectDesc(const char *name,
+ const effect_uuid_t& typeUuid,
+ const String16& opPackageName,
+ const effect_uuid_t& uuid,
+ uint32_t priority,
+ audio_unique_id_t id) :
mName(strdup(name)),
- mUuid(uuid) { }
+ mTypeUuid(typeUuid),
+ mOpPackageName(opPackageName),
+ mUuid(uuid),
+ mPriority(priority),
+ mId(id) { }
+ EffectDesc(const char *name, const effect_uuid_t& uuid) :
+ EffectDesc(name,
+ *EFFECT_UUID_NULL,
+ String16(""),
+ uuid,
+ 0,
+ AUDIO_UNIQUE_ID_ALLOCATE) { }
EffectDesc(const EffectDesc& orig) :
mName(strdup(orig.mName)),
- mUuid(orig.mUuid) {
+ mTypeUuid(orig.mTypeUuid),
+ mOpPackageName(orig.mOpPackageName),
+ mUuid(orig.mUuid),
+ mPriority(orig.mPriority),
+ mId(orig.mId) {
// deep copy mParams
for (size_t k = 0; k < orig.mParams.size(); k++) {
effect_param_t *origParam = orig.mParams[k];
@@ -116,7 +146,11 @@
}
}
char *mName;
+ effect_uuid_t mTypeUuid;
+ String16 mOpPackageName;
effect_uuid_t mUuid;
+ int32_t mPriority;
+ audio_unique_id_t mId;
Vector <effect_param_t *> mParams;
};
diff --git a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
index f564641..3439c9b 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -850,6 +850,50 @@
(audio_session_t)audioSession, descriptors, count);
}
+status_t AudioPolicyService::addStreamDefaultEffect(const effect_uuid_t *type,
+ const String16& opPackageName,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ audio_usage_t usage,
+ audio_unique_id_t* id)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!modifyDefaultAudioEffectsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ sp<AudioPolicyEffects>audioPolicyEffects;
+ {
+ Mutex::Autolock _l(mLock);
+ audioPolicyEffects = mAudioPolicyEffects;
+ }
+ if (audioPolicyEffects == 0) {
+ return NO_INIT;
+ }
+ return audioPolicyEffects->addStreamDefaultEffect(
+ type, opPackageName, uuid, priority, usage, id);
+}
+
+status_t AudioPolicyService::removeStreamDefaultEffect(audio_unique_id_t id)
+{
+ if (mAudioPolicyManager == NULL) {
+ return NO_INIT;
+ }
+ if (!modifyDefaultAudioEffectsAllowed()) {
+ return PERMISSION_DENIED;
+ }
+ sp<AudioPolicyEffects>audioPolicyEffects;
+ {
+ Mutex::Autolock _l(mLock);
+ audioPolicyEffects = mAudioPolicyEffects;
+ }
+ if (audioPolicyEffects == 0) {
+ return NO_INIT;
+ }
+ return audioPolicyEffects->removeStreamDefaultEffect(id);
+}
+
bool AudioPolicyService::isOffloadSupported(const audio_offload_info_t& info)
{
if (mAudioPolicyManager == NULL) {
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index 6a25668..44c0347 100644
--- a/services/audiopolicy/service/AudioPolicyService.h
+++ b/services/audiopolicy/service/AudioPolicyService.h
@@ -126,6 +126,14 @@
virtual status_t queryDefaultPreProcessing(audio_session_t audioSession,
effect_descriptor_t *descriptors,
uint32_t *count);
+ virtual status_t addStreamDefaultEffect(const effect_uuid_t *type,
+ const String16& opPackageName,
+ const effect_uuid_t *uuid,
+ int32_t priority,
+ audio_usage_t usage,
+ audio_unique_id_t* id);
+ virtual status_t removeStreamDefaultEffect(audio_unique_id_t id);
+
virtual status_t onTransact(
uint32_t code,
const Parcel& data,
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c41de82..b85dd51 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -582,7 +582,7 @@
Status CameraService::makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
- bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+ int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
/*out*/sp<BasicClient>* client) {
if (halVersion < 0 || halVersion == deviceVersion) {
@@ -594,7 +594,7 @@
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new CameraClient(cameraService, tmp, packageName,
api1CameraId, facing, clientPid, clientUid,
- getpid(), legacyMode);
+ getpid());
} else { // Camera2 API route
ALOGW("Camera using old HAL version: %d", deviceVersion);
return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
@@ -612,7 +612,7 @@
*client = new Camera2Client(cameraService, tmp, packageName,
cameraId, api1CameraId,
facing, clientPid, clientUid,
- servicePid, legacyMode);
+ servicePid);
} else { // Camera2 API route
sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
@@ -636,7 +636,7 @@
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new CameraClient(cameraService, tmp, packageName,
api1CameraId, facing, clientPid, clientUid,
- servicePid, legacyMode);
+ servicePid);
} else {
// Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
@@ -735,8 +735,7 @@
sp<ICameraClient>{nullptr}, id, cameraId,
static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED),
internalPackageName, uid, USE_CALLING_PID,
- API_1, /*legacyMode*/ false, /*shimUpdateOnly*/ true,
- /*out*/ tmp)
+ API_1, /*shimUpdateOnly*/ true, /*out*/ tmp)
).isOk()) {
ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().string());
}
@@ -1200,8 +1199,7 @@
sp<Client> client = nullptr;
ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId,
CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, clientPid, API_1,
- /*legacyMode*/ false, /*shimUpdateOnly*/ false,
- /*out*/client);
+ /*shimUpdateOnly*/ false, /*out*/client);
if(!ret.isOk()) {
logRejected(id, getCallingPid(), String8(clientPackageName),
@@ -1227,8 +1225,7 @@
Status ret = Status::ok();
sp<Client> client = nullptr;
ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId, halVersion,
- clientPackageName, clientUid, USE_CALLING_PID, API_1,
- /*legacyMode*/ true, /*shimUpdateOnly*/ false,
+ clientPackageName, clientUid, USE_CALLING_PID, API_1, /*shimUpdateOnly*/ false,
/*out*/client);
if(!ret.isOk()) {
@@ -1256,9 +1253,7 @@
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
/*api1CameraId*/-1,
CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
- clientUid, USE_CALLING_PID, API_2,
- /*legacyMode*/ false, /*shimUpdateOnly*/ false,
- /*out*/client);
+ clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, /*out*/client);
if(!ret.isOk()) {
logRejected(id, getCallingPid(), String8(clientPackageName),
@@ -1273,7 +1268,7 @@
template<class CALLBACK, class CLIENT>
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
int api1CameraId, int halVersion, const String16& clientPackageName, int clientUid,
- int clientPid, apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
+ int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly,
/*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
@@ -1358,7 +1353,7 @@
sp<BasicClient> tmp = nullptr;
if(!(ret = makeClient(this, cameraCb, clientPackageName,
cameraId, api1CameraId, facing,
- clientPid, clientUid, getpid(), legacyMode,
+ clientPid, clientUid, getpid(),
halVersion, deviceVersion, effectiveApiLevel,
/*out*/&tmp)).isOk()) {
return ret;
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 8d4bcdb..e4a18d3 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -585,8 +585,7 @@
template<class CALLBACK, class CLIENT>
binder::Status connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
int api1CameraId, int halVersion, const String16& clientPackageName,
- int clientUid, int clientPid,
- apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
+ int clientUid, int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly,
/*out*/sp<CLIENT>& device);
// Lock guarding camera service state
@@ -844,7 +843,7 @@
static binder::Status makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
- bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+ int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
/*out*/sp<BasicClient>* client);
status_t checkCameraAccess(const String16& opPackageName);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index c8b3c2f..261cdbf 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -54,8 +54,7 @@
int cameraFacing,
int clientPid,
uid_t clientUid,
- int servicePid,
- bool legacyMode):
+ int servicePid):
Camera2ClientBase(cameraService, cameraClient, clientPackageName,
cameraDeviceId, api1CameraId, cameraFacing,
clientPid, clientUid, servicePid),
@@ -65,8 +64,6 @@
SharedParameters::Lock l(mParameters);
l.mParameters.state = Parameters::DISCONNECTED;
-
- mLegacyMode = legacyMode;
}
status_t Camera2Client::initialize(sp<CameraProviderManager> manager, const String8& monitorTags) {
@@ -1443,7 +1440,7 @@
return OK;
}
-status_t Camera2Client::takePicture(int msgType) {
+status_t Camera2Client::takePicture(int /*msgType*/) {
ATRACE_CALL();
Mutex::Autolock icl(mBinderSerializationLock);
status_t res;
@@ -1542,7 +1539,7 @@
// Need HAL to have correct settings before (possibly) triggering precapture
syncWithDevice();
- res = mCaptureSequencer->startCapture(msgType);
+ res = mCaptureSequencer->startCapture();
if (res != OK) {
ALOGE("%s: Camera %d: Unable to start capture: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
@@ -1662,27 +1659,6 @@
return OK;
}
- // the camera2 api legacy mode can unconditionally disable the shutter sound
- if (mLegacyMode) {
- ALOGV("%s: Disable shutter sound in legacy mode", __FUNCTION__);
- l.mParameters.playShutterSound = false;
- return OK;
- }
-
- // Disabling shutter sound may not be allowed. In that case only
- // allow the mediaserver process to disable the sound.
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.camera.sound.forced", value, "0");
- if (strncmp(value, "0", 2) != 0) {
- // Disabling shutter sound is not allowed. Deny if the current
- // process is not mediaserver.
- if (getCallingPid() != getpid()) {
- ALOGE("Failed to disable shutter sound. Permission denied (pid %d)",
- getCallingPid());
- return PERMISSION_DENIED;
- }
- }
-
l.mParameters.playShutterSound = false;
return OK;
}
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 44929c3..a9ea271 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -96,8 +96,7 @@
int cameraFacing,
int clientPid,
uid_t clientUid,
- int servicePid,
- bool legacyMode);
+ int servicePid);
virtual ~Camera2Client();
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index f1203f9..ce44efe 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -40,7 +40,7 @@
const String16& clientPackageName,
int cameraId, int cameraFacing,
int clientPid, int clientUid,
- int servicePid, bool legacyMode):
+ int servicePid):
Client(cameraService, cameraClient, clientPackageName,
String8::format("%d", cameraId), cameraId, cameraFacing, clientPid,
clientUid, servicePid)
@@ -57,7 +57,6 @@
// Callback is disabled by default
mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
- mLegacyMode = legacyMode;
mPlayShutterSound = true;
LOG1("CameraClient::CameraClient X (pid %d, id %d)", callingPid, cameraId);
}
@@ -715,26 +714,6 @@
return OK;
}
- // the camera2 api legacy mode can unconditionally disable the shutter sound
- if (mLegacyMode) {
- ALOGV("%s: Disable shutter sound in legacy mode", __FUNCTION__);
- mPlayShutterSound = false;
- return OK;
- }
-
- // Disabling shutter sound may not be allowed. In that case only
- // allow the mediaserver process to disable the sound.
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.camera.sound.forced", value, "0");
- if (strcmp(value, "0") != 0) {
- // Disabling shutter sound is not allowed. Deny if the current
- // process is not mediaserver.
- if (getCallingPid() != getpid()) {
- ALOGE("Failed to disable shutter sound. Permission denied (pid %d)", getCallingPid());
- return PERMISSION_DENIED;
- }
- }
-
mPlayShutterSound = false;
return OK;
}
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 1910536..9530b6c 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -68,8 +68,7 @@
int cameraFacing,
int clientPid,
int clientUid,
- int servicePid,
- bool legacyMode = false);
+ int servicePid);
~CameraClient();
virtual status_t initialize(sp<CameraProviderManager> manager,
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 1ee216f..f42cdd3 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -50,8 +50,7 @@
mStateTransitionCount(0),
mTriggerId(0),
mTimeoutCount(0),
- mCaptureId(Camera2Client::kCaptureRequestIdStart),
- mMsgType(0) {
+ mCaptureId(Camera2Client::kCaptureRequestIdStart) {
ALOGV("%s", __FUNCTION__);
}
@@ -64,7 +63,7 @@
mZslProcessor = processor;
}
-status_t CaptureSequencer::startCapture(int msgType) {
+status_t CaptureSequencer::startCapture() {
ALOGV("%s", __FUNCTION__);
ATRACE_CALL();
Mutex::Autolock l(mInputMutex);
@@ -73,7 +72,6 @@
return INVALID_OPERATION;
}
if (!mStartCapture) {
- mMsgType = msgType;
mStartCapture = true;
mStartCaptureSignal.signal();
}
@@ -386,7 +384,7 @@
SharedParameters::Lock l(client->getParameters());
/* warning: this also locks a SharedCameraCallbacks */
- shutterNotifyLocked(l.mParameters, client, mMsgType);
+ shutterNotifyLocked(l.mParameters, client);
mShutterNotified = true;
mTimeoutCount = kMaxTimeoutsForCaptureEnd;
return STANDARD_CAPTURE_WAIT;
@@ -610,7 +608,7 @@
if (!mShutterNotified) {
SharedParameters::Lock l(client->getParameters());
/* warning: this also locks a SharedCameraCallbacks */
- shutterNotifyLocked(l.mParameters, client, mMsgType);
+ shutterNotifyLocked(l.mParameters, client);
mShutterNotified = true;
}
} else if (mTimeoutCount <= 0) {
@@ -715,12 +713,11 @@
}
/*static*/ void CaptureSequencer::shutterNotifyLocked(const Parameters ¶ms,
- const sp<Camera2Client>& client, int msgType) {
+ const sp<Camera2Client>& client) {
ATRACE_CALL();
if (params.state == Parameters::STILL_CAPTURE
- && params.playShutterSound
- && (msgType & CAMERA_MSG_SHUTTER)) {
+ && params.playShutterSound) {
client->getCameraService()->playSound(CameraService::SOUND_SHUTTER);
}
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index f2e3750..c23b12d 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -51,7 +51,7 @@
void setZslProcessor(const wp<ZslProcessor>& processor);
// Begin still image capture
- status_t startCapture(int msgType);
+ status_t startCapture();
// Wait until current image capture completes; returns immediately if no
// capture is active. Returns TIMED_OUT if capture does not complete during
@@ -145,7 +145,6 @@
bool mAeInPrecapture;
int32_t mCaptureId;
- int mMsgType;
// Main internal methods
@@ -172,7 +171,7 @@
// Emit Shutter/Raw callback to java, and maybe play a shutter sound
static void shutterNotifyLocked(const Parameters ¶ms,
- const sp<Camera2Client>& client, int msgType);
+ const sp<Camera2Client>& client);
};
}; // namespace camera2
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index 491ed72..4c6718c 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2738,13 +2738,13 @@
status_t Camera3Device::registerInFlight(uint32_t frameNumber,
int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
bool hasAppCallback, nsecs_t maxExpectedDuration,
- std::set<String8>& physicalCameraIds) {
+ std::set<String8>& physicalCameraIds, bool isStillCapture) {
ATRACE_CALL();
Mutex::Autolock l(mInFlightLock);
ssize_t res;
res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers, resultExtras, hasInput,
- hasAppCallback, maxExpectedDuration, physicalCameraIds));
+ hasAppCallback, maxExpectedDuration, physicalCameraIds, isStillCapture));
if (res < 0) return res;
if (mInFlightMap.size() == 1) {
@@ -2810,6 +2810,10 @@
if (request.numBuffersLeft == 0 &&
(request.skipResultMetadata ||
(request.haveResultMetadata && shutterTimestamp != 0))) {
+ if (request.stillCapture) {
+ ATRACE_ASYNC_END("still capture", frameNumber);
+ }
+
ATRACE_ASYNC_END("frame capture", frameNumber);
// Sanity check - if sensor timestamp matches shutter timestamp in the
@@ -4939,12 +4943,21 @@
if (batchedRequest && i != mNextRequests.size()-1) {
hasCallback = false;
}
+ bool isStillCapture = false;
+ if (!mNextRequests[0].captureRequest->mSettingsList.begin()->metadata.isEmpty()) {
+ camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t();
+ find_camera_metadata_ro_entry(halRequest->settings, ANDROID_CONTROL_CAPTURE_INTENT, &e);
+ if ((e.count > 0) && (e.data.u8[0] == ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE)) {
+ isStillCapture = true;
+ ATRACE_ASYNC_BEGIN("still capture", mNextRequests[i].halRequest.frame_number);
+ }
+ }
res = parent->registerInFlight(halRequest->frame_number,
totalNumBuffers, captureRequest->mResultExtras,
/*hasInput*/halRequest->input_buffer != NULL,
hasCallback,
calculateMaxExpectedDuration(halRequest->settings),
- requestedPhysicalCameras);
+ requestedPhysicalCameras, isStillCapture);
ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
", burstId = %" PRId32 ".",
__FUNCTION__,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 96212ab..51e1fb0 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -994,6 +994,9 @@
// Map of physicalCameraId <-> Metadata
std::vector<PhysicalCaptureResultInfo> physicalMetadatas;
+ // Indicates a still capture request.
+ bool stillCapture;
+
// Default constructor needed by KeyedVector
InFlightRequest() :
shutterTimestamp(0),
@@ -1004,12 +1007,13 @@
hasInputBuffer(false),
hasCallback(true),
maxExpectedDuration(kDefaultExpectedDuration),
- skipResultMetadata(false) {
+ skipResultMetadata(false),
+ stillCapture(false) {
}
InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput,
bool hasAppCallback, nsecs_t maxDuration,
- const std::set<String8>& physicalCameraIdSet) :
+ const std::set<String8>& physicalCameraIdSet, bool isStillCapture) :
shutterTimestamp(0),
sensorTimestamp(0),
requestStatus(OK),
@@ -1020,7 +1024,8 @@
hasCallback(hasAppCallback),
maxExpectedDuration(maxDuration),
skipResultMetadata(false),
- physicalCameraIds(physicalCameraIdSet) {
+ physicalCameraIds(physicalCameraIdSet),
+ stillCapture(isStillCapture) {
}
};
@@ -1034,10 +1039,10 @@
nsecs_t mExpectedInflightDuration = 0;
int mInFlightStatusId;
-
status_t registerInFlight(uint32_t frameNumber,
int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
- bool callback, nsecs_t maxExpectedDuration, std::set<String8>& physicalCameraIds);
+ bool callback, nsecs_t maxExpectedDuration, std::set<String8>& physicalCameraIds,
+ bool isStillCapture);
/**
* Returns the maximum expected time it'll take for all currently in-flight
diff --git a/services/camera/libcameraservice/utils/TagMonitor.cpp b/services/camera/libcameraservice/utils/TagMonitor.cpp
index c0a353f..f4c49ec 100644
--- a/services/camera/libcameraservice/utils/TagMonitor.cpp
+++ b/services/camera/libcameraservice/utils/TagMonitor.cpp
@@ -49,7 +49,8 @@
std::lock_guard<std::mutex> lock(mMonitorMutex);
// Expand shorthands
- if (ssize_t idx = tagNames.find("3a") != -1) {
+ ssize_t idx = tagNames.find("3a");
+ if (idx != -1) {
ssize_t end = tagNames.find(",", idx);
char* start = tagNames.lockBuffer(tagNames.size());
start[idx] = '\0';
diff --git a/services/oboeservice/AAudioServiceEndpointMMAP.cpp b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
index f9e21fb..f30f9bb 100644
--- a/services/oboeservice/AAudioServiceEndpointMMAP.cpp
+++ b/services/oboeservice/AAudioServiceEndpointMMAP.cpp
@@ -189,6 +189,7 @@
minSizeFrames = AAUDIO_BUFFER_CAPACITY_MIN;
}
status = mMmapStream->createMmapBuffer(minSizeFrames, &mMmapBufferinfo);
+ bool isBufferShareable = mMmapBufferinfo.flags & AUDIO_MMAP_APPLICATION_SHAREABLE;
if (status != OK) {
ALOGE("%s() - createMmapBuffer() failed with status %d %s",
__func__, status, strerror(-status));
@@ -198,18 +199,13 @@
ALOGD("%s() createMmapBuffer() returned = %d, buffer_size = %d, burst_size %d"
", Sharable FD: %s",
__func__, status,
- abs(mMmapBufferinfo.buffer_size_frames),
+ mMmapBufferinfo.buffer_size_frames,
mMmapBufferinfo.burst_size_frames,
- mMmapBufferinfo.buffer_size_frames < 0 ? "Yes" : "No");
+ isBufferShareable ? "Yes" : "No");
}
setBufferCapacity(mMmapBufferinfo.buffer_size_frames);
- // The audio HAL indicates if the shared memory fd can be shared outside of audioserver
- // by returning a negative buffer size
- if (getBufferCapacity() < 0) {
- // Exclusive mode can be used by client or service.
- setBufferCapacity(-getBufferCapacity());
- } else {
+ if (!isBufferShareable) {
// Exclusive mode can only be used by the service because the FD cannot be shared.
uid_t audioServiceUid = getuid();
if ((mMmapClient.clientUid != audioServiceUid) &&