Merge "Camera: Trace still capture requests"
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/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/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 8412812..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);
@@ -5231,9 +5383,13 @@
uint32_t cts = 0;
bool isSyncSample = false;
bool newBuffer = false;
- if (mBuffer == NULL) {
+ if (mBuffer == NULL || mCurrentSampleIndex >= mCurrentSamples.size()) {
newBuffer = true;
+ if (mBuffer != NULL) {
+ mBuffer->release();
+ mBuffer = NULL;
+ }
if (mCurrentSampleIndex >= mCurrentSamples.size()) {
// move to next fragment if there is one
if (mNextMoofOffset <= mCurrentMoofOffset) {
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/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/lvm/wrapper/Bundle/EffectBundle.cpp b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
index 04c2692..53d266a 100644
--- a/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
+++ b/media/libeffects/lvm/wrapper/Bundle/EffectBundle.cpp
@@ -1198,13 +1198,7 @@
for (int i=0; i<LVM_NR_MEMORY_REGIONS; i++){
if (MemTab.Region[i].Size != 0){
if (MemTab.Region[i].pBaseAddress != NULL){
- ALOGV("\tLvmEffect_free - START freeing %" PRIu32 " bytes for region %u at %p\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
-
free(MemTab.Region[i].pBaseAddress);
-
- ALOGV("\tLvmEffect_free - END freeing %" PRIu32 " bytes for region %u at %p\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
}else{
ALOGV("\tLVM_ERROR : LvmEffect_free - trying to free with NULL pointer %" PRIu32
" bytes for region %u at %p ERROR\n",
diff --git a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
index e1c03f9..686ec4c 100644
--- a/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
+++ b/media/libeffects/lvm/wrapper/Reverb/EffectReverb.cpp
@@ -612,13 +612,7 @@
for (int i=0; i<LVM_NR_MEMORY_REGIONS; i++){
if (MemTab.Region[i].Size != 0){
if (MemTab.Region[i].pBaseAddress != NULL){
- ALOGV("\tfree() - START freeing %" PRIu32 " bytes for region %u at %p\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
-
free(MemTab.Region[i].pBaseAddress);
-
- ALOGV("\tfree() - END freeing %" PRIu32 " bytes for region %u at %p\n",
- MemTab.Region[i].Size, i, MemTab.Region[i].pBaseAddress);
}else{
ALOGV("\tLVM_ERROR : free() - trying to free with NULL pointer %" PRIu32 " bytes "
"for region %u at %p ERROR\n",
diff --git a/media/libeffects/preprocessing/PreProcessing.cpp b/media/libeffects/preprocessing/PreProcessing.cpp
index f2844ed..b914f4b 100644
--- a/media/libeffects/preprocessing/PreProcessing.cpp
+++ b/media/libeffects/preprocessing/PreProcessing.cpp
@@ -889,7 +889,7 @@
delete session->procFrame;
session->procFrame = NULL;
delete session->apm;
- session->apm = NULL;
+ session->apm = NULL; // NOLINT(clang-analyzer-cplusplus.NewDelete)
}
return status;
}
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 2fb5a2c..bc84729 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
@@ -96,17 +96,17 @@
enum media2_info_type {
// 0xx
MEDIA2_INFO_UNKNOWN = 1,
- // The player was started because it was used as the next player for another
- // player, which just completed playback
- MEDIA2_INFO_STARTED_AS_NEXT = 2,
+ // The player just started the playback of this data source.
+ MEDIA2_INFO_DATA_SOURCE_START = 2,
// The player just pushed the very first video frame for rendering
MEDIA2_INFO_VIDEO_RENDERING_START = 3,
// The player just pushed the very first audio frame for rendering
MEDIA2_INFO_AUDIO_RENDERING_START = 4,
// The player just completed the playback of this data source
- MEDIA2_INFO_PLAYBACK_COMPLETE = 5,
- // The player just completed the playback of the full play list
- MEDIA2_INFO_PLAYLIST_END = 6,
+ MEDIA2_INFO_DATA_SOURCE_END = 5,
+ // 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,
//1xx
// The player just prepared a data source.
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
index 060b698..c649573 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2.cpp
@@ -2474,8 +2474,8 @@
if (mDriver != NULL) {
sp<NuPlayer2Driver> driver = mDriver.promote();
if (driver != NULL) {
- notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_PLAYBACK_COMPLETE, 0);
- notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_STARTED_AS_NEXT, 0);
+ notifyListener(previousSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_END, 0);
+ notifyListener(mSrcId, MEDIA2_INFO, MEDIA2_INFO_DATA_SOURCE_START, 0);
}
}
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/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/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/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/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/FastCapture.cpp b/services/audioflinger/FastCapture.cpp
index d063772..dd84bf2 100644
--- a/services/audioflinger/FastCapture.cpp
+++ b/services/audioflinger/FastCapture.cpp
@@ -20,6 +20,7 @@
#define ATRACE_TAG ATRACE_TAG_AUDIO
#include "Configuration.h"
+#include <audio_utils/format.h>
#include <linux/futex.h>
#include <sys/syscall.h>
#include <media/AudioBufferProvider.h>
@@ -161,7 +162,21 @@
const FastCaptureState * const current = (const FastCaptureState *) mCurrent;
FastCaptureDumpState * const dumpState = (FastCaptureDumpState *) mDumpState;
const FastCaptureState::Command command = mCommand;
- const size_t frameCount = current->mFrameCount;
+ size_t frameCount = current->mFrameCount;
+ AudioBufferProvider* fastPatchRecordBufferProvider = current->mFastPatchRecordBufferProvider;
+ AudioBufferProvider::Buffer patchBuffer;
+
+ if (fastPatchRecordBufferProvider != 0) {
+ patchBuffer.frameCount = ~0;
+ status_t status = fastPatchRecordBufferProvider->getNextBuffer(&patchBuffer);
+ if (status != NO_ERROR) {
+ frameCount = 0;
+ } else if (patchBuffer.frameCount < frameCount) {
+ // TODO: Make sure that it doesn't cause any issues if we just get a small available
+ // buffer from the buffer provider.
+ frameCount = patchBuffer.frameCount;
+ }
+ }
if ((command & FastCaptureState::READ) /*&& isWarm*/) {
ALOG_ASSERT(mInputSource != NULL);
@@ -176,6 +191,7 @@
mTotalNativeFramesRead += framesRead;
dumpState->mFramesRead = mTotalNativeFramesRead;
mReadBufferState = framesRead;
+ patchBuffer.frameCount = framesRead;
} else {
dumpState->mReadErrors++;
mReadBufferState = 0;
@@ -193,11 +209,18 @@
}
if (mReadBufferState > 0) {
ssize_t framesWritten = mPipeSink->write(mReadBuffer, mReadBufferState);
- // FIXME This supports at most one fast capture client.
- // To handle multiple clients this could be converted to an array,
- // or with a lot more work the control block could be shared by all clients.
audio_track_cblk_t* cblk = current->mCblk;
- if (cblk != NULL && framesWritten > 0) {
+ if (fastPatchRecordBufferProvider != 0) {
+ // This indicates the fast track is a patch record, update the cblk by
+ // calling releaseBuffer().
+ memcpy_by_audio_format(patchBuffer.raw, current->mFastPatchRecordFormat,
+ mReadBuffer, mFormat.mFormat, framesWritten * mFormat.mChannelCount);
+ patchBuffer.frameCount = framesWritten;
+ fastPatchRecordBufferProvider->releaseBuffer(&patchBuffer);
+ } else if (cblk != NULL && framesWritten > 0) {
+ // FIXME This supports at most one fast capture client.
+ // To handle multiple clients this could be converted to an array,
+ // or with a lot more work the control block could be shared by all clients.
int32_t rear = cblk->u.mStreaming.mRear;
android_atomic_release_store(framesWritten + rear, &cblk->u.mStreaming.mRear);
cblk->mServer += framesWritten;
diff --git a/services/audioflinger/FastCaptureState.h b/services/audioflinger/FastCaptureState.h
index 9bca2d4..d287232 100644
--- a/services/audioflinger/FastCaptureState.h
+++ b/services/audioflinger/FastCaptureState.h
@@ -18,6 +18,7 @@
#define ANDROID_AUDIO_FAST_CAPTURE_STATE_H
#include <media/nbaio/NBAIO.h>
+#include <media/AudioBufferProvider.h>
#include "FastThreadState.h"
#include <private/media/AudioTrackShared.h>
@@ -37,6 +38,10 @@
size_t mFrameCount; // number of frames per fast capture buffer
audio_track_cblk_t* mCblk; // control block for the single fast client, or NULL
+ audio_format_t mFastPatchRecordFormat = AUDIO_FORMAT_INVALID;
+ AudioBufferProvider* mFastPatchRecordBufferProvider = nullptr; // a reference to a patch
+ // record in fast mode
+
// Extends FastThreadState::Command
static const Command
// The following commands also process configuration changes, and can be "or"ed:
diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
index ffdc117..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>
@@ -92,9 +93,9 @@
}
// 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
- Statistics<double> wall, loadNs;
+ audio_utils::Statistics<double> wall, loadNs;
#ifdef CPU_FREQUENCY_STATISTICS
- Statistics<double> kHz, loadMHz;
+ audio_utils::Statistics<double> kHz, loadMHz;
uint32_t previousCpukHz = 0;
#endif
// Assuming a normal distribution for cycle times, three standard deviations on either side of
@@ -152,7 +153,7 @@
qsort(tail, n, sizeof(uint32_t), compare_uint32_t);
// assume same number of tail samples on each side, left and right
uint32_t count = n / kTailDenominator;
- Statistics<double> left, right;
+ audio_utils::Statistics<double> left, right;
for (uint32_t i = 0; i < count; ++i) {
left.add(tail[i]);
right.add(tail[n - (i + 1)]);
@@ -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 f044fb7..ada8572 100644
--- a/services/audioflinger/PatchPanel.cpp
+++ b/services/audioflinger/PatchPanel.cpp
@@ -431,14 +431,14 @@
// use a pseudo LCM between input and output framecount
size_t playbackFrameCount = mPlayback.thread()->frameCount();
int playbackShift = __builtin_ctz(playbackFrameCount);
- size_t recordFramecount = mRecord.thread()->frameCount();
- int shift = __builtin_ctz(recordFramecount);
+ size_t recordFrameCount = mRecord.thread()->frameCount();
+ int shift = __builtin_ctz(recordFrameCount);
if (playbackShift < shift) {
shift = playbackShift;
}
- size_t frameCount = (playbackFrameCount * recordFramecount) >> shift;
- ALOGV("%s() playframeCount %zu recordFramecount %zu frameCount %zu",
- __func__, playbackFrameCount, recordFramecount, frameCount);
+ size_t frameCount = (playbackFrameCount * recordFrameCount) >> shift;
+ ALOGV("%s() playframeCount %zu recordFrameCount %zu frameCount %zu",
+ __func__, playbackFrameCount, recordFrameCount, frameCount);
// create a special record track to capture from record thread
uint32_t channelCount = mPlayback.thread()->channelCount();
@@ -455,6 +455,17 @@
}
audio_input_flags_t inputFlags = mAudioPatch.sources[0].config_mask & AUDIO_PORT_CONFIG_FLAGS ?
mAudioPatch.sources[0].flags.input : AUDIO_INPUT_FLAG_NONE;
+ if (sampleRate == mRecord.thread()->sampleRate() &&
+ inChannelMask == mRecord.thread()->channelMask() &&
+ mRecord.thread()->fastTrackAvailable() &&
+ mRecord.thread()->hasFastCapture()) {
+ // Create a fast track if the record thread has fast capture to get better performance.
+ // Only enable fast mode when there is no resample needed.
+ inputFlags = (audio_input_flags_t) (inputFlags | AUDIO_INPUT_FLAG_FAST);
+ } else {
+ // Fast mode is not available in this case.
+ inputFlags = (audio_input_flags_t) (inputFlags & ~AUDIO_INPUT_FLAG_FAST);
+ }
sp<RecordThread::PatchRecord> tempRecordTrack = new (std::nothrow) RecordThread::PatchRecord(
mRecord.thread().get(),
sampleRate,
@@ -476,6 +487,11 @@
// "reuse one existing output mix" case
streamType = mAudioPatch.sources[1].ext.mix.usecase.stream;
}
+ if (mPlayback.thread()->hasFastMixer()) {
+ // Create a fast track if the playback thread has fast mixer to get better performance.
+ outputFlags = (audio_output_flags_t) (outputFlags | AUDIO_OUTPUT_FLAG_FAST);
+ }
+
// create a special playback track to render to playback thread.
// this track is given the same buffer as the PatchRecord buffer
sp<PlaybackThread::PatchTrack> tempPatchTrack = new (std::nothrow) PlaybackThread::PatchTrack(
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index 6c7179e..cd585f5 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>
@@ -335,9 +336,9 @@
#ifdef DEBUG_CPU_USAGE
private:
ThreadCpuUsage mCpuUsage; // instantaneous thread CPU usage in wall clock ns
- Statistics<double> mWcStats; // statistics on thread CPU usage in wall clock ns
+ audio_utils::Statistics<double> mWcStats; // statistics on thread CPU usage in wall clock ns
- Statistics<double> mHzStats; // statistics on thread CPU usage in cycles
+ audio_utils::Statistics<double> mHzStats; // statistics on thread CPU usage in cycles
int mCpuNum; // thread's current CPU number
int mCpukHz; // frequency of thread's current CPU in kHz
@@ -1763,9 +1764,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)
@@ -5141,14 +5142,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
@@ -6700,6 +6707,14 @@
}
didModify = true;
}
+ AudioBufferProvider* abp = (fastTrack != 0 && fastTrack->isPatchTrack()) ?
+ reinterpret_cast<AudioBufferProvider*>(fastTrack.get()) : nullptr;
+ if (state->mFastPatchRecordBufferProvider != abp) {
+ state->mFastPatchRecordBufferProvider = abp;
+ state->mFastPatchRecordFormat = fastTrack == 0 ?
+ AUDIO_FORMAT_INVALID : fastTrack->format();
+ didModify = true;
+ }
sq->end(didModify);
if (didModify) {
sq->push(block);
@@ -6725,8 +6740,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,
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index dc23717..2ab0bee 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -662,7 +662,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();
@@ -1108,7 +1108,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,
@@ -1530,6 +1530,8 @@
void updateMetadata_l() override;
+ bool fastTrackAvailable() const { return mFastTrackAvail; }
+
private:
// Enter standby if not already in standby, and set mStandby flag
void standbyIfNotAlreadyInStandby();
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 92f6c79..96079cc 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -4761,6 +4761,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 +4772,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 +5820,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 dbfda44..3439c9b 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -254,15 +254,6 @@
status_t AudioPolicyService::stopOutput(audio_port_handle_t portId)
{
- {
- Mutex::Autolock _l(mLock);
-
- const ssize_t index = mAudioPlaybackClients.indexOfKey(portId);
- if (index < 0) {
- ALOGE("%s AudioTrack client not found for portId %d", __FUNCTION__, portId);
- return INVALID_OPERATION;
- }
- }
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
@@ -859,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/DistortionMapper.cpp b/services/camera/libcameraservice/device3/DistortionMapper.cpp
index 4dafefd..ae7af8e 100644
--- a/services/camera/libcameraservice/device3/DistortionMapper.cpp
+++ b/services/camera/libcameraservice/device3/DistortionMapper.cpp
@@ -312,8 +312,8 @@
int32_t coords[4] = {
rects[i],
rects[i + 1],
- rects[i] + rects[i + 2],
- rects[i + 1] + rects[i + 3]
+ rects[i] + rects[i + 2] - 1,
+ rects[i + 1] + rects[i + 3] - 1
};
mapRawToCorrected(coords, 2, clamp, simple);
@@ -321,8 +321,8 @@
// Map back to (l, t, width, height)
rects[i] = coords[0];
rects[i + 1] = coords[1];
- rects[i + 2] = coords[2] - coords[0];
- rects[i + 3] = coords[3] - coords[1];
+ rects[i + 2] = coords[2] - coords[0] + 1;
+ rects[i + 3] = coords[3] - coords[1] + 1;
}
return OK;
@@ -400,8 +400,8 @@
int32_t coords[4] = {
rects[i],
rects[i + 1],
- rects[i] + rects[i + 2],
- rects[i + 1] + rects[i + 3]
+ rects[i] + rects[i + 2] - 1,
+ rects[i + 1] + rects[i + 3] - 1
};
mapCorrectedToRaw(coords, 2, clamp, simple);
@@ -409,8 +409,8 @@
// Map back to (l, t, width, height)
rects[i] = coords[0];
rects[i + 1] = coords[1];
- rects[i + 2] = coords[2] - coords[0];
- rects[i + 3] = coords[3] - coords[1];
+ rects[i + 2] = coords[2] - coords[0] + 1;
+ rects[i + 3] = coords[3] - coords[1] + 1;
}
return OK;
diff --git a/services/camera/libcameraservice/tests/DistortionMapperTest.cpp b/services/camera/libcameraservice/tests/DistortionMapperTest.cpp
index 2a689c6..54935c9 100644
--- a/services/camera/libcameraservice/tests/DistortionMapperTest.cpp
+++ b/services/camera/libcameraservice/tests/DistortionMapperTest.cpp
@@ -167,6 +167,30 @@
}
}
+TEST(DistortionMapperTest, ClampConsistency) {
+ status_t res;
+
+ std::array<int32_t, 4> activeArray = {0, 0, 4032, 3024};
+ DistortionMapper m;
+ setupTestMapper(&m, identityDistortion, testICal, /*activeArray*/ activeArray.data(),
+ /*preCorrectionActiveArray*/ activeArray.data());
+
+ auto rectsOrig = activeArray;
+ res = m.mapCorrectedRectToRaw(activeArray.data(), 1, /*clamp*/true, /*simple*/ true);
+ ASSERT_EQ(res, OK);
+
+ for (size_t i = 0; i < activeArray.size(); i++) {
+ EXPECT_EQ(activeArray[i], rectsOrig[i]);
+ }
+
+ res = m.mapRawRectToCorrected(activeArray.data(), 1, /*clamp*/true, /*simple*/ true);
+ ASSERT_EQ(res, OK);
+
+ for (size_t i = 0; i < activeArray.size(); i++) {
+ EXPECT_EQ(activeArray[i], rectsOrig[i]);
+ }
+}
+
TEST(DistortionMapperTest, SimpleTransform) {
status_t res;
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) &&