Merge "Check for crypto size overflow"
diff --git a/camera/cameraserver/cameraserver.rc b/camera/cameraserver/cameraserver.rc
index fea5a1d..a9aae0b 100644
--- a/camera/cameraserver/cameraserver.rc
+++ b/camera/cameraserver/cameraserver.rc
@@ -4,3 +4,4 @@
group audio camera input drmrpc
ioprio rt 4
writepid /dev/cpuset/camera-daemon/tasks /dev/stune/top-app/tasks
+ rlimit rtprio 10 10
diff --git a/camera/ndk/include/camera/NdkCameraMetadataTags.h b/camera/ndk/include/camera/NdkCameraMetadataTags.h
index 0501006..1dfa4f7 100644
--- a/camera/ndk/include/camera/NdkCameraMetadataTags.h
+++ b/camera/ndk/include/camera/NdkCameraMetadataTags.h
@@ -2312,7 +2312,9 @@
* <p>If this device is the largest or only camera device with a given facing, then this
* position will be <code>(0, 0, 0)</code>; a camera device with a lens optical center located 3 cm
* from the main sensor along the +X axis (to the right from the user's perspective) will
- * report <code>(0.03, 0, 0)</code>.</p>
+ * report <code>(0.03, 0, 0)</code>. Note that this means that, for many computer vision
+ * applications, the position needs to be negated to convert it to a translation from the
+ * camera to the origin.</p>
* <p>To transform a pixel coordinates between two cameras facing the same direction, first
* the source camera ACAMERA_LENS_DISTORTION must be corrected for. Then the source
* camera ACAMERA_LENS_INTRINSIC_CALIBRATION needs to be applied, followed by the
@@ -2324,7 +2326,8 @@
* <p>To compare this against a real image from the destination camera, the destination camera
* image then needs to be corrected for radial distortion before comparison or sampling.</p>
* <p>When ACAMERA_LENS_POSE_REFERENCE is GYROSCOPE, then this position is relative to
- * the center of the primary gyroscope on the device.</p>
+ * the center of the primary gyroscope on the device. The axis definitions are the same as
+ * with PRIMARY_CAMERA.</p>
*
* @see ACAMERA_LENS_DISTORTION
* @see ACAMERA_LENS_INTRINSIC_CALIBRATION
@@ -2418,13 +2421,15 @@
* </code></pre>
* <p>which can then be combined with the camera pose rotation
* <code>R</code> and translation <code>t</code> (ACAMERA_LENS_POSE_ROTATION and
- * ACAMERA_LENS_POSE_TRANSLATION, respective) to calculate the
+ * ACAMERA_LENS_POSE_TRANSLATION, respectively) to calculate the
* complete transform from world coordinates to pixel
* coordinates:</p>
- * <pre><code>P = [ K 0 * [ R t
- * 0 1 ] 0 1 ]
+ * <pre><code>P = [ K 0 * [ R -Rt
+ * 0 1 ] 0 1 ]
* </code></pre>
- * <p>and with <code>p_w</code> being a point in the world coordinate system
+ * <p>(Note the negation of poseTranslation when mapping from camera
+ * to world coordinates, and multiplication by the rotation).</p>
+ * <p>With <code>p_w</code> being a point in the world coordinate system
* and <code>p_s</code> being a point in the camera active pixel array
* coordinate system, and with the mapping including the
* homogeneous division by z:</p>
@@ -2446,6 +2451,13 @@
* activeArraySize rectangle), to determine the final pixel
* coordinate of the world point for processed (non-RAW)
* output buffers.</p>
+ * <p>For camera devices, the center of pixel <code>(x,y)</code> is located at
+ * coordinate <code>(x + 0.5, y + 0.5)</code>. So on a device with a
+ * precorrection active array of size <code>(10,10)</code>, the valid pixel
+ * indices go from <code>(0,0)-(9,9)</code>, and an perfectly-built camera would
+ * have an optical center at the exact center of the pixel grid, at
+ * coordinates <code>(5.0, 5.0)</code>, which is the top-left corner of pixel
+ * <code>(5,5)</code>.</p>
*
* @see ACAMERA_LENS_DISTORTION
* @see ACAMERA_LENS_POSE_ROTATION
@@ -3059,7 +3071,7 @@
* outputs will crop horizontally (pillarbox), and 16:9
* streams will match exactly. These additional crops will
* be centered within the crop region.</p>
- * <p>If the coordinate system is android.sensor.info.activeArraysSize, the width and height
+ * <p>If the coordinate system is ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE, the width and height
* of the crop region cannot be set to be smaller than
* <code>floor( activeArraySize.width / ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM )</code> and
* <code>floor( activeArraySize.height / ACAMERA_SCALER_AVAILABLE_MAX_DIGITAL_ZOOM )</code>, respectively.</p>
@@ -4675,8 +4687,8 @@
ACAMERA_STATISTICS_LENS_SHADING_MAP_MODE = // byte (acamera_metadata_enum_android_statistics_lens_shading_map_mode_t)
ACAMERA_STATISTICS_START + 16,
/**
- * <p>A control for selecting whether OIS position information is included in output
- * result metadata.</p>
+ * <p>A control for selecting whether optical stabilization (OIS) position
+ * information is included in output result metadata.</p>
*
* <p>Type: byte (acamera_metadata_enum_android_statistics_ois_data_mode_t)</p>
*
@@ -4686,6 +4698,12 @@
* <li>ACaptureRequest</li>
* </ul></p>
*
+ * <p>Since optical image stabilization generally involves motion much faster than the duration
+ * of individualq image exposure, multiple OIS samples can be included for a single capture
+ * result. For example, if the OIS reporting operates at 200 Hz, a typical camera operating
+ * at 30fps may have 6-7 OIS samples per capture result. This information can be combined
+ * with the rolling shutter skew to account for lens motion during image exposure in
+ * post-processing algorithms.</p>
*/
ACAMERA_STATISTICS_OIS_DATA_MODE = // byte (acamera_metadata_enum_android_statistics_ois_data_mode_t)
ACAMERA_STATISTICS_START + 17,
@@ -4717,11 +4735,15 @@
* </ul></p>
*
* <p>The array contains the amount of shifts in x direction, in pixels, based on OIS samples.
- * A positive value is a shift from left to right in active array coordinate system. For
- * example, if the optical center is (1000, 500) in active array coordinates, a shift of
- * (3, 0) puts the new optical center at (1003, 500).</p>
+ * A positive value is a shift from left to right in the pre-correction active array
+ * coordinate system. For example, if the optical center is (1000, 500) in pre-correction
+ * active array coordinates, a shift of (3, 0) puts the new optical center at (1003, 500).</p>
* <p>The number of shifts must match the number of timestamps in
* ACAMERA_STATISTICS_OIS_TIMESTAMPS.</p>
+ * <p>The OIS samples are not affected by whether lens distortion correction is enabled (on
+ * supporting devices). They are always reported in pre-correction active array coordinates,
+ * since the scaling of OIS shifts would depend on the specific spot on the sensor the shift
+ * is needed.</p>
*
* @see ACAMERA_STATISTICS_OIS_TIMESTAMPS
*/
@@ -4738,11 +4760,15 @@
* </ul></p>
*
* <p>The array contains the amount of shifts in y direction, in pixels, based on OIS samples.
- * A positive value is a shift from top to bottom in active array coordinate system. For
- * example, if the optical center is (1000, 500) in active array coordinates, a shift of
- * (0, 5) puts the new optical center at (1000, 505).</p>
+ * A positive value is a shift from top to bottom in pre-correction active array coordinate
+ * system. For example, if the optical center is (1000, 500) in active array coordinates, a
+ * shift of (0, 5) puts the new optical center at (1000, 505).</p>
* <p>The number of shifts must match the number of timestamps in
* ACAMERA_STATISTICS_OIS_TIMESTAMPS.</p>
+ * <p>The OIS samples are not affected by whether lens distortion correction is enabled (on
+ * supporting devices). They are always reported in pre-correction active array coordinates,
+ * since the scaling of OIS shifts would depend on the specific spot on the sensor the shift
+ * is needed.</p>
*
* @see ACAMERA_STATISTICS_OIS_TIMESTAMPS
*/
@@ -5432,16 +5458,34 @@
* any correction at all would slow down capture rate. Every output stream will have a
* similar amount of enhancement applied.</p>
* <p>The correction only applies to processed outputs such as YUV, JPEG, or DEPTH16; it is not
- * applied to any RAW output. Metadata coordinates such as face rectangles or metering
- * regions are also not affected by correction.</p>
+ * applied to any RAW output.</p>
* <p>This control will be on by default on devices that support this control. Applications
* disabling distortion correction need to pay extra attention with the coordinate system of
* metering regions, crop region, and face rectangles. When distortion correction is OFF,
* metadata coordinates follow the coordinate system of
* ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE. When distortion is not OFF, metadata
- * coordinates follow the coordinate system of ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE.</p>
+ * coordinates follow the coordinate system of ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE. The
+ * camera device will map these metadata fields to match the corrected image produced by the
+ * camera device, for both capture requests and results. However, this mapping is not very
+ * precise, since rectangles do not generally map to rectangles when corrected. Only linear
+ * scaling between the active array and precorrection active array coordinates is
+ * performed. Applications that require precise correction of metadata need to undo that
+ * linear scaling, and apply a more complete correction that takes into the account the app's
+ * own requirements.</p>
+ * <p>The full list of metadata that is affected in this way by distortion correction is:</p>
+ * <ul>
+ * <li>ACAMERA_CONTROL_AF_REGIONS</li>
+ * <li>ACAMERA_CONTROL_AE_REGIONS</li>
+ * <li>ACAMERA_CONTROL_AWB_REGIONS</li>
+ * <li>ACAMERA_SCALER_CROP_REGION</li>
+ * <li>android.statistics.faces</li>
+ * </ul>
*
+ * @see ACAMERA_CONTROL_AE_REGIONS
+ * @see ACAMERA_CONTROL_AF_REGIONS
+ * @see ACAMERA_CONTROL_AWB_REGIONS
* @see ACAMERA_LENS_DISTORTION
+ * @see ACAMERA_SCALER_CROP_REGION
* @see ACAMERA_SENSOR_INFO_ACTIVE_ARRAY_SIZE
* @see ACAMERA_SENSOR_INFO_PRE_CORRECTION_ACTIVE_ARRAY_SIZE
*/
diff --git a/cmds/stagefright/stagefright.cpp b/cmds/stagefright/stagefright.cpp
index d41d3fd..bddf945 100644
--- a/cmds/stagefright/stagefright.cpp
+++ b/cmds/stagefright/stagefright.cpp
@@ -650,7 +650,8 @@
MEDIA_MIMETYPE_AUDIO_MPEG, MEDIA_MIMETYPE_AUDIO_G711_MLAW,
MEDIA_MIMETYPE_AUDIO_G711_ALAW, MEDIA_MIMETYPE_AUDIO_VORBIS,
MEDIA_MIMETYPE_VIDEO_VP8, MEDIA_MIMETYPE_VIDEO_VP9,
- MEDIA_MIMETYPE_VIDEO_DOLBY_VISION, MEDIA_MIMETYPE_AUDIO_AC4
+ MEDIA_MIMETYPE_VIDEO_DOLBY_VISION,
+ MEDIA_MIMETYPE_AUDIO_EAC3, MEDIA_MIMETYPE_AUDIO_AC4
};
const char *codecType = queryDecoders? "decoder" : "encoder";
diff --git a/drm/libmediadrm/ICrypto.cpp b/drm/libmediadrm/ICrypto.cpp
index 73ecda1..a2594aa 100644
--- a/drm/libmediadrm/ICrypto.cpp
+++ b/drm/libmediadrm/ICrypto.cpp
@@ -225,8 +225,13 @@
void BnCrypto::readVector(const Parcel &data, Vector<uint8_t> &vector) const {
uint32_t size = data.readInt32();
- vector.insertAt((size_t)0, size);
- data.read(vector.editArray(), size);
+ if (vector.insertAt((size_t)0, size) < 0) {
+ vector.clear();
+ }
+ if (data.read(vector.editArray(), size) != NO_ERROR) {
+ vector.clear();
+ android_errorWriteWithInfoLog(0x534e4554, "62872384", -1, NULL, 0);
+ }
}
void BnCrypto::writeVector(Parcel *reply, Vector<uint8_t> const &vector) const {
diff --git a/media/audioserver/Android.mk b/media/audioserver/Android.mk
index 70c281a..8a97299 100644
--- a/media/audioserver/Android.mk
+++ b/media/audioserver/Android.mk
@@ -21,6 +21,9 @@
libsoundtriggerservice \
libutils
+LOCAL_STATIC_LIBRARIES := \
+ libjsoncpp
+
# TODO oboeservice is the old folder name for aaudioservice. It will be changed.
LOCAL_C_INCLUDES := \
frameworks/av/services/audioflinger \
diff --git a/media/extractors/flac/FLACExtractor.cpp b/media/extractors/flac/FLACExtractor.cpp
index e3da259..a721b65 100644
--- a/media/extractors/flac/FLACExtractor.cpp
+++ b/media/extractors/flac/FLACExtractor.cpp
@@ -18,6 +18,8 @@
#define LOG_TAG "FLACExtractor"
#include <utils/Log.h>
+#include <stdint.h>
+
#include "FLACExtractor.h"
// libFLAC parser
#include "FLAC/stream_decoder.h"
@@ -124,7 +126,7 @@
// media buffers
size_t mMaxBufferSize;
MediaBufferGroup *mGroup;
- void (*mCopy)(short *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
+ void (*mCopy)(int16_t *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
// handle to underlying libFLAC parser
FLAC__StreamDecoder *mDecoder;
@@ -383,7 +385,7 @@
// These are candidates for optimization if needed.
static void copyMono8(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -393,7 +395,7 @@
}
static void copyStereo8(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -403,7 +405,7 @@
}
}
-static void copyMultiCh8(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
+static void copyMultiCh8(int16_t *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -413,7 +415,7 @@
}
static void copyMono16(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -423,7 +425,7 @@
}
static void copyStereo16(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -433,7 +435,7 @@
}
}
-static void copyMultiCh16(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
+static void copyMultiCh16(int16_t *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -445,7 +447,7 @@
// 24-bit versions should do dithering or noise-shaping, here or in AudioFlinger
static void copyMono24(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -455,7 +457,7 @@
}
static void copyStereo24(
- short *dst,
+ int16_t *dst,
const int * src[FLACParser::kMaxChannels],
unsigned nSamples,
unsigned /* nChannels */) {
@@ -465,7 +467,7 @@
}
}
-static void copyMultiCh24(short *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
+static void copyMultiCh24(int16_t *dst, const int * src[FLACParser::kMaxChannels], unsigned nSamples, unsigned nChannels)
{
for (unsigned i = 0; i < nSamples; ++i) {
for (unsigned c = 0; c < nChannels; ++c) {
@@ -475,7 +477,7 @@
}
static void copyTrespass(
- short * /* dst */,
+ int16_t * /* dst */,
const int *[FLACParser::kMaxChannels] /* src */,
unsigned /* nSamples */,
unsigned /* nChannels */) {
@@ -592,7 +594,7 @@
static const struct {
unsigned mChannels;
unsigned mBitsPerSample;
- void (*mCopy)(short *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
+ void (*mCopy)(int16_t *dst, const int * src[kMaxChannels], unsigned nSamples, unsigned nChannels);
} table[] = {
{ 1, 8, copyMono8 },
{ 2, 8, copyStereo8 },
@@ -635,7 +637,7 @@
{
CHECK(mGroup == NULL);
mGroup = new MediaBufferGroup;
- mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(short);
+ mMaxBufferSize = getMaxBlockSize() * getChannels() * sizeof(int16_t);
mGroup->add_buffer(MediaBufferBase::Create(mMaxBufferSize));
}
@@ -688,9 +690,9 @@
if (err != OK) {
return NULL;
}
- size_t bufferSize = blocksize * getChannels() * sizeof(short);
+ size_t bufferSize = blocksize * getChannels() * sizeof(int16_t);
CHECK(bufferSize <= mMaxBufferSize);
- short *data = (short *) buffer->data();
+ int16_t *data = (int16_t *) buffer->data();
buffer->set_range(0, bufferSize);
// copy PCM from FLAC write buffer to our media buffer, with interleaving
(*mCopy)(data, mWriteBuffer, blocksize, getChannels());
diff --git a/media/extractors/mp4/MPEG4Extractor.cpp b/media/extractors/mp4/MPEG4Extractor.cpp
index 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/AudioSystem.cpp b/media/libaudioclient/AudioSystem.cpp
index cb4bcfc..e260fd8 100644
--- a/media/libaudioclient/AudioSystem.cpp
+++ b/media/libaudioclient/AudioSystem.cpp
@@ -1238,18 +1238,18 @@
status_t AudioSystem::startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_patch_handle_t *handle)
+ audio_port_handle_t *portId)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- return aps->startAudioSource(source, attributes, handle);
+ return aps->startAudioSource(source, attributes, portId);
}
-status_t AudioSystem::stopAudioSource(audio_patch_handle_t handle)
+status_t AudioSystem::stopAudioSource(audio_port_handle_t portId)
{
const sp<IAudioPolicyService>& aps = AudioSystem::get_audio_policy_service();
if (aps == 0) return PERMISSION_DENIED;
- return aps->stopAudioSource(handle);
+ return aps->stopAudioSource(portId);
}
status_t AudioSystem::setMasterMono(bool mono)
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 e229f4c..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
@@ -740,11 +742,11 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_patch_handle_t *handle)
+ audio_port_handle_t *portId)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
- if (source == NULL || attributes == NULL || handle == NULL) {
+ if (source == NULL || attributes == NULL || portId == NULL) {
return BAD_VALUE;
}
data.write(source, sizeof(struct audio_port_config));
@@ -757,15 +759,15 @@
if (status != NO_ERROR) {
return status;
}
- *handle = (audio_patch_handle_t)reply.readInt32();
+ *portId = (audio_port_handle_t)reply.readInt32();
return status;
}
- virtual status_t stopAudioSource(audio_patch_handle_t handle)
+ virtual status_t stopAudioSource(audio_port_handle_t portId)
{
Parcel data, reply;
data.writeInterfaceToken(IAudioPolicyService::getInterfaceDescriptor());
- data.writeInt32(handle);
+ data.writeInt32(portId);
status_t status = remote()->transact(STOP_AUDIO_SOURCE, data, &reply);
if (status != NO_ERROR) {
return status;
@@ -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");
@@ -1472,17 +1510,17 @@
audio_attributes_t attributes = {};
data.read(&attributes, sizeof(audio_attributes_t));
sanetizeAudioAttributes(&attributes);
- audio_patch_handle_t handle = AUDIO_PATCH_HANDLE_NONE;
- status_t status = startAudioSource(&source, &attributes, &handle);
+ audio_port_handle_t portId = AUDIO_PORT_HANDLE_NONE;
+ status_t status = startAudioSource(&source, &attributes, &portId);
reply->writeInt32(status);
- reply->writeInt32(handle);
+ reply->writeInt32(portId);
return NO_ERROR;
} break;
case STOP_AUDIO_SOURCE: {
CHECK_INTERFACE(IAudioPolicyService, data, reply);
- audio_patch_handle_t handle = (audio_patch_handle_t) data.readInt32();
- status_t status = stopAudioSource(handle);
+ audio_port_handle_t portId = (audio_port_handle_t) data.readInt32();
+ status_t status = stopAudioSource(portId);
reply->writeInt32(status);
return NO_ERROR;
} break;
@@ -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/AudioSystem.h b/media/libaudioclient/include/media/AudioSystem.h
index 10d6e92..adfee8b 100644
--- a/media/libaudioclient/include/media/AudioSystem.h
+++ b/media/libaudioclient/include/media/AudioSystem.h
@@ -322,9 +322,9 @@
static status_t registerPolicyMixes(const Vector<AudioMix>& mixes, bool registration);
static status_t startAudioSource(const struct audio_port_config *source,
- const audio_attributes_t *attributes,
- audio_patch_handle_t *handle);
- static status_t stopAudioSource(audio_patch_handle_t handle);
+ const audio_attributes_t *attributes,
+ audio_port_handle_t *portId);
+ static status_t stopAudioSource(audio_port_handle_t portId);
static status_t setMasterMono(bool mono);
static status_t getMasterMono(bool *mono);
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 6c017a3..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;
@@ -153,8 +160,8 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_patch_handle_t *handle) = 0;
- virtual status_t stopAudioSource(audio_patch_handle_t handle) = 0;
+ audio_port_handle_t *portId) = 0;
+ virtual status_t stopAudioSource(audio_port_handle_t portId) = 0;
virtual status_t setMasterMono(bool mono) = 0;
virtual status_t getMasterMono(bool *mono) = 0;
diff --git a/media/libaudiohal/impl/StreamHalHidl.cpp b/media/libaudiohal/impl/StreamHalHidl.cpp
index b23e018..bfa80e8 100644
--- a/media/libaudiohal/impl/StreamHalHidl.cpp
+++ b/media/libaudiohal/impl/StreamHalHidl.cpp
@@ -192,7 +192,17 @@
const native_handle *handle = hidlInfo.sharedMemory.handle();
if (handle->numFds > 0) {
info->shared_memory_fd = handle->data[0];
+#if MAJOR_VERSION == 4
+ info->flags = audio_mmap_buffer_flag(hidlInfo.flags);
+#endif
info->buffer_size_frames = hidlInfo.bufferSizeFrames;
+ // Negative buffer size frame was a hack in O and P to
+ // indicate that the buffer is shareable to applications
+ if (info->buffer_size_frames < 0) {
+ info->buffer_size_frames *= -1;
+ info->flags = audio_mmap_buffer_flag(
+ info->flags | AUDIO_MMAP_APPLICATION_SHAREABLE);
+ }
info->burst_size_frames = hidlInfo.burstSizeFrames;
// info->shared_memory_address is not needed in HIDL context
info->shared_memory_address = NULL;
diff --git a/media/libaudioprocessing/AudioMixer.cpp b/media/libaudioprocessing/AudioMixer.cpp
index f6f817a..f3ea826 100644
--- a/media/libaudioprocessing/AudioMixer.cpp
+++ b/media/libaudioprocessing/AudioMixer.cpp
@@ -875,7 +875,7 @@
t->hook = Track::getTrackHook(TRACKTYPE_RESAMPLE, t->mMixerChannelCount,
t->mMixerInFormat, t->mMixerFormat);
ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
- "Track %d needs downmix + resample", i);
+ "Track %d needs downmix + resample", name);
} else {
if ((n & NEEDS_CHANNEL_COUNT__MASK) == NEEDS_CHANNEL_1){
t->hook = Track::getTrackHook(
@@ -890,7 +890,7 @@
t->hook = Track::getTrackHook(TRACKTYPE_NORESAMPLE, t->mMixerChannelCount,
t->mMixerInFormat, t->mMixerFormat);
ALOGV_IF((n & NEEDS_CHANNEL_COUNT__MASK) > NEEDS_CHANNEL_2,
- "Track %d needs downmix", i);
+ "Track %d needs downmix", name);
}
}
}
diff --git a/media/libaudioprocessing/include/media/AudioResamplerPublic.h b/media/libaudioprocessing/include/media/AudioResamplerPublic.h
index 055f724..50ca33d 100644
--- a/media/libaudioprocessing/include/media/AudioResamplerPublic.h
+++ b/media/libaudioprocessing/include/media/AudioResamplerPublic.h
@@ -104,8 +104,8 @@
const AudioPlaybackRate &pr2) {
return fabs(pr1.mSpeed - pr2.mSpeed) < AUDIO_TIMESTRETCH_SPEED_MIN_DELTA &&
fabs(pr1.mPitch - pr2.mPitch) < AUDIO_TIMESTRETCH_PITCH_MIN_DELTA &&
- pr2.mStretchMode == pr2.mStretchMode &&
- pr2.mFallbackMode == pr2.mFallbackMode;
+ pr1.mStretchMode == pr2.mStretchMode &&
+ pr1.mFallbackMode == pr2.mFallbackMode;
}
static inline bool isAudioPlaybackRateValid(const AudioPlaybackRate &playbackRate) {
diff --git a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
index 9d29cf1..d61efd3 100644
--- a/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
+++ b/media/libeffects/loudness/EffectLoudnessEnhancer.cpp
@@ -30,6 +30,26 @@
#include <audio_effects/effect_loudnessenhancer.h>
#include "dsp/core/dynamic_range_compression.h"
+// BUILD_FLOAT targets building a float effect instead of the legacy int16_t effect.
+#define BUILD_FLOAT
+
+#ifdef BUILD_FLOAT
+
+static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_FLOAT;
+
+#else
+
+static constexpr audio_format_t kProcessFormat = AUDIO_FORMAT_PCM_16_BIT;
+
+static inline int16_t clamp16(int32_t sample)
+{
+ if ((sample>>15) ^ (sample>>31))
+ sample = 0x7FFF ^ (sample>>31);
+ return sample;
+}
+
+#endif // BUILD_FLOAT
+
extern "C" {
// effect_handle_t interface implementation for LE effect
@@ -80,13 +100,6 @@
}
}
-static inline int16_t clamp16(int32_t sample)
-{
- if ((sample>>15) ^ (sample>>31))
- sample = 0x7FFF ^ (sample>>31);
- return sample;
-}
-
//----------------------------------------------------------------------------
// LE_setConfig()
//----------------------------------------------------------------------------
@@ -111,7 +124,7 @@
if (pConfig->inputCfg.channels != AUDIO_CHANNEL_OUT_STEREO) return -EINVAL;
if (pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_WRITE &&
pConfig->outputCfg.accessMode != EFFECT_BUFFER_ACCESS_ACCUMULATE) return -EINVAL;
- if (pConfig->inputCfg.format != AUDIO_FORMAT_PCM_16_BIT) return -EINVAL;
+ if (pConfig->inputCfg.format != kProcessFormat) return -EINVAL;
pContext->mConfig = *pConfig;
@@ -159,7 +172,7 @@
pContext->mConfig.inputCfg.accessMode = EFFECT_BUFFER_ACCESS_READ;
pContext->mConfig.inputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
- pContext->mConfig.inputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ pContext->mConfig.inputCfg.format = kProcessFormat;
pContext->mConfig.inputCfg.samplingRate = 44100;
pContext->mConfig.inputCfg.bufferProvider.getBuffer = NULL;
pContext->mConfig.inputCfg.bufferProvider.releaseBuffer = NULL;
@@ -167,7 +180,7 @@
pContext->mConfig.inputCfg.mask = EFFECT_CONFIG_ALL;
pContext->mConfig.outputCfg.accessMode = EFFECT_BUFFER_ACCESS_ACCUMULATE;
pContext->mConfig.outputCfg.channels = AUDIO_CHANNEL_OUT_STEREO;
- pContext->mConfig.outputCfg.format = AUDIO_FORMAT_PCM_16_BIT;
+ pContext->mConfig.outputCfg.format = kProcessFormat;
pContext->mConfig.outputCfg.samplingRate = 44100;
pContext->mConfig.outputCfg.bufferProvider.getBuffer = NULL;
pContext->mConfig.outputCfg.bufferProvider.releaseBuffer = NULL;
@@ -284,18 +297,41 @@
//ALOGV("LE about to process %d samples", inBuffer->frameCount);
uint16_t inIdx;
+#ifdef BUILD_FLOAT
+ constexpr float scale = 1 << 15; // power of 2 is lossless conversion to int16_t range
+ constexpr float inverseScale = 1.f / scale;
+ const float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f) * scale;
+#else
float inputAmp = pow(10, pContext->mTargetGainmB/2000.0f);
+#endif
float leftSample, rightSample;
for (inIdx = 0 ; inIdx < inBuffer->frameCount ; inIdx++) {
// makeup gain is applied on the input of the compressor
+#ifdef BUILD_FLOAT
+ leftSample = inputAmp * inBuffer->f32[2*inIdx];
+ rightSample = inputAmp * inBuffer->f32[2*inIdx +1];
+ pContext->mCompressor->Compress(&leftSample, &rightSample);
+ inBuffer->f32[2*inIdx] = leftSample * inverseScale;
+ inBuffer->f32[2*inIdx +1] = rightSample * inverseScale;
+#else
leftSample = inputAmp * (float)inBuffer->s16[2*inIdx];
rightSample = inputAmp * (float)inBuffer->s16[2*inIdx +1];
pContext->mCompressor->Compress(&leftSample, &rightSample);
inBuffer->s16[2*inIdx] = (int16_t) leftSample;
inBuffer->s16[2*inIdx +1] = (int16_t) rightSample;
+#endif // BUILD_FLOAT
}
if (inBuffer->raw != outBuffer->raw) {
+#ifdef BUILD_FLOAT
+ if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
+ for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
+ outBuffer->f32[i] += inBuffer->f32[i];
+ }
+ } else {
+ memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(float));
+ }
+#else
if (pContext->mConfig.outputCfg.accessMode == EFFECT_BUFFER_ACCESS_ACCUMULATE) {
for (size_t i = 0; i < outBuffer->frameCount*2; i++) {
outBuffer->s16[i] = clamp16(outBuffer->s16[i] + inBuffer->s16[i]);
@@ -303,6 +339,7 @@
} else {
memcpy(outBuffer->raw, inBuffer->raw, outBuffer->frameCount * 2 * sizeof(int16_t));
}
+#endif // BUILD_FLOAT
}
if (pContext->mState != LOUDNESS_ENHANCER_STATE_ACTIVE) {
return -ENODATA;
diff --git a/media/libeffects/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..211a5c0 100644
--- a/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
+++ b/media/libmediaplayer2/include/mediaplayer2/MediaPlayer2Types.h
@@ -96,17 +96,20 @@
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,
+ // The player just completed an iteration of playback loop. This event is sent only when
+ // looping is enabled.
+ MEDIA2_INFO_DATA_SOURCE_REPEAT = 7,
//1xx
// The player just prepared a data source.
diff --git a/media/libmediaplayer2/nuplayer2/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/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
index e48e388..e215965 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2CCDecoder.cpp
@@ -372,10 +372,16 @@
timeUs, mDTVCCPacket->data(), mDTVCCPacket->size());
mDTVCCPacket->setRange(0, 0);
}
+ if (mDTVCCPacket->size() + 2 > mDTVCCPacket->capacity()) {
+ return false;
+ }
memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
br.skipBits(16);
} else if (mDTVCCPacket->size() > 0 && cc_type == 2) {
+ if (mDTVCCPacket->size() + 2 > mDTVCCPacket->capacity()) {
+ return false;
+ }
memcpy(mDTVCCPacket->data() + mDTVCCPacket->size(), br.data(), 2);
mDTVCCPacket->setRange(0, mDTVCCPacket->size() + 2);
br.skipBits(16);
@@ -403,6 +409,9 @@
line21CCBuf = new ABuffer((cc_count - i) * sizeof(CCData));
line21CCBuf->setRange(0, 0);
}
+ if (line21CCBuf->size() + sizeof(cc) > line21CCBuf->capacity()) {
+ return false;
+ }
memcpy(line21CCBuf->data() + line21CCBuf->size(), &cc, sizeof(cc));
line21CCBuf->setRange(0, line21CCBuf->size() + sizeof(CCData));
}
@@ -464,6 +473,9 @@
size_t trackIndex = getTrackIndex(kTrackTypeCEA708, service_number, &trackAdded);
if (mSelectedTrack == (ssize_t)trackIndex) {
sp<ABuffer> ccPacket = new ABuffer(block_size);
+ if (ccPacket->capacity() == 0) {
+ return false;
+ }
memcpy(ccPacket->data(), br.data(), block_size);
mCCMap.add(timeUs, ccPacket);
}
@@ -527,10 +539,12 @@
ccBuf = new ABuffer(size);
ccBuf->setRange(0, 0);
- for (ssize_t i = 0; i <= index; ++i) {
- sp<ABuffer> buf = mCCMap.valueAt(i);
- memcpy(ccBuf->data() + ccBuf->size(), buf->data(), buf->size());
- ccBuf->setRange(0, ccBuf->size() + buf->size());
+ if (ccBuf->capacity() > 0) {
+ for (ssize_t i = 0; i <= index; ++i) {
+ sp<ABuffer> buf = mCCMap.valueAt(i);
+ memcpy(ccBuf->data() + ccBuf->size(), buf->data(), buf->size());
+ ccBuf->setRange(0, ccBuf->size() + buf->size());
+ }
}
}
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
index 645138a..931b86e 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Decoder.cpp
@@ -1088,6 +1088,12 @@
static_cast<MediaBufferHolder*>(holder.get())->mediaBuffer() : nullptr;
}
if (mediaBuf != NULL) {
+ if (mediaBuf->size() > codecBuffer->capacity()) {
+ handleError(ERROR_BUFFER_TOO_SMALL);
+ mDequeuedInputBuffers.push_back(bufferIx);
+ return false;
+ }
+
codecBuffer->setRange(0, mediaBuf->size());
memcpy(codecBuffer->data(), mediaBuf->data(), mediaBuf->size());
diff --git a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
index 03d17a5..3069f54 100644
--- a/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
+++ b/media/libmediaplayer2/nuplayer2/NuPlayer2Driver.cpp
@@ -930,7 +930,12 @@
// the last little bit of audio. In looping mode, we need to restart it.
mAudioSink->start();
}
- // don't send completion event when looping
+
+ sp<AMessage> notify = new AMessage(kWhatNotifyListener, this);
+ notify->setInt64("srcId", srcId);
+ notify->setInt32("messageId", MEDIA2_INFO);
+ notify->setInt32("ext1", MEDIA2_INFO_DATA_SOURCE_REPEAT);
+ notify->post();
return;
}
if (property_get_bool("persist.debug.sf.stats", false)) {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
index a5f5fc6..0784939 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.cpp
@@ -1120,6 +1120,7 @@
} else if (what == DecoderBase::kWhatShutdownCompleted) {
ALOGV("%s shutdown completed", audio ? "audio" : "video");
if (audio) {
+ Mutex::Autolock autoLock(mDecoderLock);
mAudioDecoder.clear();
mAudioDecoderError = false;
++mAudioDecoderGeneration;
@@ -1127,6 +1128,7 @@
CHECK_EQ((int)mFlushingAudio, (int)SHUTTING_DOWN_DECODER);
mFlushingAudio = SHUT_DOWN;
} else {
+ Mutex::Autolock autoLock(mDecoderLock);
mVideoDecoder.clear();
mVideoDecoderError = false;
++mVideoDecoderGeneration;
@@ -1447,29 +1449,6 @@
break;
}
- case kWhatGetStats:
- {
- ALOGV("kWhatGetStats");
-
- Vector<sp<AMessage>> *trackStats;
- CHECK(msg->findPointer("trackstats", (void**)&trackStats));
-
- trackStats->clear();
- if (mVideoDecoder != NULL) {
- trackStats->push_back(mVideoDecoder->getStats());
- }
- if (mAudioDecoder != NULL) {
- trackStats->push_back(mAudioDecoder->getStats());
- }
-
- // respond for synchronization
- sp<AMessage> response = new AMessage;
- sp<AReplyToken> replyID;
- CHECK(msg->senderAwaitsResponse(&replyID));
- response->postReply(replyID);
- break;
- }
-
default:
TRESPASS();
break;
@@ -1817,6 +1796,7 @@
(long long)currentPositionUs, forceNonOffload, needsToCreateAudioDecoder);
if (mAudioDecoder != NULL) {
mAudioDecoder->pause();
+ Mutex::Autolock autoLock(mDecoderLock);
mAudioDecoder.clear();
mAudioDecoderError = false;
++mAudioDecoderGeneration;
@@ -1935,6 +1915,8 @@
}
}
+ Mutex::Autolock autoLock(mDecoderLock);
+
if (audio) {
sp<AMessage> notify = new AMessage(kWhatAudioNotify, this);
++mAudioDecoderGeneration;
@@ -2236,13 +2218,15 @@
void NuPlayer::getStats(Vector<sp<AMessage> > *trackStats) {
CHECK(trackStats != NULL);
- ALOGV("NuPlayer::getStats()");
- sp<AMessage> msg = new AMessage(kWhatGetStats, this);
- msg->setPointer("trackstats", trackStats);
+ trackStats->clear();
- sp<AMessage> response;
- (void) msg->postAndAwaitResponse(&response);
- // response is for synchronization, ignore contents
+ Mutex::Autolock autoLock(mDecoderLock);
+ if (mVideoDecoder != NULL) {
+ trackStats->push_back(mVideoDecoder->getStats());
+ }
+ if (mAudioDecoder != NULL) {
+ trackStats->push_back(mAudioDecoder->getStats());
+ }
}
sp<MetaData> NuPlayer::getFileMeta() {
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayer.h b/media/libmediaplayerservice/nuplayer/NuPlayer.h
index e400d16..9f5be06 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayer.h
+++ b/media/libmediaplayerservice/nuplayer/NuPlayer.h
@@ -159,7 +159,6 @@
kWhatPrepareDrm = 'pDrm',
kWhatReleaseDrm = 'rDrm',
kWhatMediaClockNotify = 'mckN',
- kWhatGetStats = 'gSts',
};
wp<NuPlayerDriver> mDriver;
@@ -175,6 +174,7 @@
sp<DecoderBase> mVideoDecoder;
bool mOffloadAudio;
sp<DecoderBase> mAudioDecoder;
+ Mutex mDecoderLock; // guard |mAudioDecoder| and |mVideoDecoder|.
sp<CCDecoder> mCCDecoder;
sp<Renderer> mRenderer;
sp<ALooper> mRendererLooper;
diff --git a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
index 69cd82e..050e4fb 100644
--- a/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
+++ b/media/libmediaplayerservice/nuplayer/NuPlayerDecoder.cpp
@@ -1069,6 +1069,12 @@
static_cast<MediaBufferHolder*>(holder.get())->mediaBuffer() : nullptr;
}
if (mediaBuf != NULL) {
+ if (mediaBuf->size() > codecBuffer->capacity()) {
+ handleError(ERROR_BUFFER_TOO_SMALL);
+ mDequeuedInputBuffers.push_back(bufferIx);
+ return false;
+ }
+
codecBuffer->setRange(0, mediaBuf->size());
memcpy(codecBuffer->data(), mediaBuf->data(), mediaBuf->size());
diff --git a/media/libnblog/NBLog.cpp b/media/libnblog/NBLog.cpp
index d6fa3e3..bfc797c 100644
--- a/media/libnblog/NBLog.cpp
+++ b/media/libnblog/NBLog.cpp
@@ -64,7 +64,9 @@
// ---------------------------------------------------------------------------
/*static*/
-std::unique_ptr<NBLog::AbstractEntry> NBLog::AbstractEntry::buildEntry(const uint8_t *ptr) {
+std::unique_ptr<NBLog::AbstractEntry> NBLog::AbstractEntry::buildEntry(const uint8_t *ptr)
+{
+ if (ptr == nullptr) return nullptr;
const uint8_t type = EntryIterator(ptr)->type;
switch (type) {
case EVENT_START_FMT:
@@ -78,31 +80,33 @@
}
}
-NBLog::AbstractEntry::AbstractEntry(const uint8_t *entry) : mEntry(entry) {
+NBLog::AbstractEntry::AbstractEntry(const uint8_t *entry) : mEntry(entry)
+{
}
// ---------------------------------------------------------------------------
-NBLog::EntryIterator NBLog::FormatEntry::begin() const {
+NBLog::EntryIterator NBLog::FormatEntry::begin() const
+{
return EntryIterator(mEntry);
}
-const char *NBLog::FormatEntry::formatString() const {
+const char *NBLog::FormatEntry::formatString() const
+{
return (const char*) mEntry + offsetof(entry, data);
}
-size_t NBLog::FormatEntry::formatStringLength() const {
+size_t NBLog::FormatEntry::formatStringLength() const
+{
return mEntry[offsetof(entry, length)];
}
-NBLog::EntryIterator NBLog::FormatEntry::args() const {
+NBLog::EntryIterator NBLog::FormatEntry::args() const
+{
auto it = begin();
- // skip start fmt
- ++it;
- // skip timestamp
- ++it;
- // skip hash
- ++it;
+ ++it; // skip start fmt
+ ++it; // skip timestamp
+ ++it; // skip hash
// Skip author if present
if (it->type == EVENT_AUTHOR) {
++it;
@@ -110,33 +114,30 @@
return it;
}
-int64_t NBLog::FormatEntry::timestamp() const {
+int64_t NBLog::FormatEntry::timestamp() const
+{
auto it = begin();
- // skip start fmt
- ++it;
+ ++it; // skip start fmt
return it.payload<int64_t>();
}
-NBLog::log_hash_t NBLog::FormatEntry::hash() const {
+NBLog::log_hash_t NBLog::FormatEntry::hash() const
+{
auto it = begin();
- // skip start fmt
- ++it;
- // skip timestamp
- ++it;
+ ++it; // skip start fmt
+ ++it; // skip timestamp
// unaligned 64-bit read not supported
log_hash_t hash;
memcpy(&hash, it->data, sizeof(hash));
return hash;
}
-int NBLog::FormatEntry::author() const {
+int NBLog::FormatEntry::author() const
+{
auto it = begin();
- // skip start fmt
- ++it;
- // skip timestamp
- ++it;
- // skip hash
- ++it;
+ ++it; // skip start fmt
+ ++it; // skip timestamp
+ ++it; // skip hash
// if there is an author entry, return it, return -1 otherwise
if (it->type == EVENT_AUTHOR) {
return it.payload<int>();
@@ -145,19 +146,18 @@
}
NBLog::EntryIterator NBLog::FormatEntry::copyWithAuthor(
- std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
+ std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const
+{
auto it = begin();
- // copy fmt start entry
- it.copyTo(dst);
- // copy timestamp
- (++it).copyTo(dst); // copy hash
- (++it).copyTo(dst);
+ it.copyTo(dst); // copy fmt start entry
+ (++it).copyTo(dst); // copy timestamp
+ (++it).copyTo(dst); // copy hash
// insert author entry
- size_t authorEntrySize = NBLog::Entry::kOverhead + sizeof(author);
+ size_t authorEntrySize = Entry::kOverhead + sizeof(author);
uint8_t authorEntry[authorEntrySize];
authorEntry[offsetof(entry, type)] = EVENT_AUTHOR;
authorEntry[offsetof(entry, length)] =
- authorEntry[authorEntrySize + NBLog::Entry::kPreviousLengthOffset] =
+ authorEntry[authorEntrySize + Entry::kPreviousLengthOffset] =
sizeof(author);
*(int*) (&authorEntry[offsetof(entry, data)]) = author;
dst->write(authorEntry, authorEntrySize);
@@ -170,76 +170,96 @@
return it;
}
-void NBLog::EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const {
- size_t length = ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
- dst->write(ptr, length);
+void NBLog::EntryIterator::copyTo(std::unique_ptr<audio_utils_fifo_writer> &dst) const
+{
+ size_t length = mPtr[offsetof(entry, length)] + Entry::kOverhead;
+ dst->write(mPtr, length);
}
-void NBLog::EntryIterator::copyData(uint8_t *dst) const {
- memcpy((void*) dst, ptr + offsetof(entry, data), ptr[offsetof(entry, length)]);
+void NBLog::EntryIterator::copyData(uint8_t *dst) const
+{
+ memcpy((void*) dst, mPtr + offsetof(entry, data), mPtr[offsetof(entry, length)]);
}
-NBLog::EntryIterator::EntryIterator()
- : ptr(nullptr) {}
+NBLog::EntryIterator::EntryIterator() // Dummy initialization.
+ : mPtr(nullptr)
+{
+}
NBLog::EntryIterator::EntryIterator(const uint8_t *entry)
- : ptr(entry) {}
+ : mPtr(entry)
+{
+}
NBLog::EntryIterator::EntryIterator(const NBLog::EntryIterator &other)
- : ptr(other.ptr) {}
-
-const NBLog::entry& NBLog::EntryIterator::operator*() const {
- return *(entry*) ptr;
+ : mPtr(other.mPtr)
+{
}
-const NBLog::entry* NBLog::EntryIterator::operator->() const {
- return (entry*) ptr;
+const NBLog::entry& NBLog::EntryIterator::operator*() const
+{
+ return *(entry*) mPtr;
}
-NBLog::EntryIterator& NBLog::EntryIterator::operator++() {
- ptr += ptr[offsetof(entry, length)] + NBLog::Entry::kOverhead;
+const NBLog::entry* NBLog::EntryIterator::operator->() const
+{
+ return (entry*) mPtr;
+}
+
+NBLog::EntryIterator& NBLog::EntryIterator::operator++()
+{
+ mPtr += mPtr[offsetof(entry, length)] + Entry::kOverhead;
return *this;
}
-NBLog::EntryIterator& NBLog::EntryIterator::operator--() {
- ptr -= ptr[NBLog::Entry::kPreviousLengthOffset] + NBLog::Entry::kOverhead;
+NBLog::EntryIterator& NBLog::EntryIterator::operator--()
+{
+ mPtr -= mPtr[Entry::kPreviousLengthOffset] + Entry::kOverhead;
return *this;
}
-NBLog::EntryIterator NBLog::EntryIterator::next() const {
+NBLog::EntryIterator NBLog::EntryIterator::next() const
+{
EntryIterator aux(*this);
return ++aux;
}
-NBLog::EntryIterator NBLog::EntryIterator::prev() const {
+NBLog::EntryIterator NBLog::EntryIterator::prev() const
+{
EntryIterator aux(*this);
return --aux;
}
-int NBLog::EntryIterator::operator-(const NBLog::EntryIterator &other) const {
- return ptr - other.ptr;
+int NBLog::EntryIterator::operator-(const NBLog::EntryIterator &other) const
+{
+ return mPtr - other.mPtr;
}
-bool NBLog::EntryIterator::operator!=(const EntryIterator &other) const {
- return ptr != other.ptr;
+bool NBLog::EntryIterator::operator!=(const EntryIterator &other) const
+{
+ return mPtr != other.mPtr;
}
-bool NBLog::EntryIterator::hasConsistentLength() const {
- return ptr[offsetof(entry, length)] == ptr[ptr[offsetof(entry, length)] +
- NBLog::Entry::kOverhead + NBLog::Entry::kPreviousLengthOffset];
+bool NBLog::EntryIterator::hasConsistentLength() const
+{
+ return mPtr[offsetof(entry, length)] == mPtr[mPtr[offsetof(entry, length)] +
+ Entry::kOverhead + Entry::kPreviousLengthOffset];
}
// ---------------------------------------------------------------------------
-int64_t NBLog::HistogramEntry::timestamp() const {
+int64_t NBLog::HistogramEntry::timestamp() const
+{
return EntryIterator(mEntry).payload<HistTsEntry>().ts;
}
-NBLog::log_hash_t NBLog::HistogramEntry::hash() const {
+NBLog::log_hash_t NBLog::HistogramEntry::hash() const
+{
return EntryIterator(mEntry).payload<HistTsEntry>().hash;
}
-int NBLog::HistogramEntry::author() const {
+int NBLog::HistogramEntry::author() const
+{
EntryIterator it(mEntry);
if (it->length == sizeof(HistTsEntryWithAuthor)) {
return it.payload<HistTsEntryWithAuthor>().author;
@@ -249,7 +269,8 @@
}
NBLog::EntryIterator NBLog::HistogramEntry::copyWithAuthor(
- std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const {
+ std::unique_ptr<audio_utils_fifo_writer> &dst, int author) const
+{
// Current histogram entry has {type, length, struct HistTsEntry, length}.
// We now want {type, length, struct HistTsEntryWithAuthor, length}
uint8_t buffer[Entry::kOverhead + sizeof(HistTsEntryWithAuthor)];
@@ -336,9 +357,7 @@
void NBLog::Writer::log(const char *string)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
LOG_ALWAYS_FATAL_IF(string == NULL, "Attempted to log NULL string");
size_t length = strlen(string);
if (length > Entry::kMaxLength) {
@@ -349,9 +368,7 @@
void NBLog::Writer::logf(const char *fmt, ...)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
va_list ap;
va_start(ap, fmt);
Writer::logvf(fmt, ap); // the Writer:: is needed to avoid virtual dispatch for LockedWriter
@@ -360,9 +377,7 @@
void NBLog::Writer::logvf(const char *fmt, va_list ap)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
char buffer[Entry::kMaxLength + 1 /*NUL*/];
int length = vsnprintf(buffer, sizeof(buffer), fmt, ap);
if (length >= (int) sizeof(buffer)) {
@@ -377,9 +392,7 @@
void NBLog::Writer::logTimestamp()
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
int64_t ts = get_monotonic_ns();
if (ts > 0) {
log(EVENT_TIMESTAMP, &ts, sizeof(ts));
@@ -390,41 +403,31 @@
void NBLog::Writer::logTimestamp(const int64_t ts)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
log(EVENT_TIMESTAMP, &ts, sizeof(ts));
}
void NBLog::Writer::logInteger(const int x)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
log(EVENT_INTEGER, &x, sizeof(x));
}
void NBLog::Writer::logFloat(const float x)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
log(EVENT_FLOAT, &x, sizeof(x));
}
void NBLog::Writer::logPID()
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
log(EVENT_PID, mPidTag, mPidTagSize);
}
void NBLog::Writer::logStart(const char *fmt)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
size_t length = strlen(fmt);
if (length > Entry::kMaxLength) {
length = Entry::kMaxLength;
@@ -434,26 +437,20 @@
void NBLog::Writer::logEnd()
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
Entry entry = Entry(EVENT_END_FMT, NULL, 0);
- log(&entry, true);
+ log(entry, true);
}
void NBLog::Writer::logHash(log_hash_t hash)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
log(EVENT_HASH, &hash, sizeof(hash));
}
void NBLog::Writer::logEventHistTs(Event event, log_hash_t hash)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
HistTsEntry data;
data.hash = hash;
data.ts = get_monotonic_ns();
@@ -466,10 +463,7 @@
void NBLog::Writer::logFormat(const char *fmt, log_hash_t hash, ...)
{
- if (!mEnabled) {
- return;
- }
-
+ if (!mEnabled) return;
va_list ap;
va_start(ap, hash);
Writer::logVFormat(fmt, hash, ap);
@@ -478,9 +472,7 @@
void NBLog::Writer::logVFormat(const char *fmt, log_hash_t hash, va_list argp)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
Writer::logStart(fmt);
int i;
double f;
@@ -536,9 +528,7 @@
void NBLog::Writer::log(Event event, const void *data, size_t length)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
if (data == NULL || length > Entry::kMaxLength) {
// TODO Perhaps it makes sense to display truncated data or at least a
// message that the data is too long? The current behavior can create
@@ -550,19 +540,17 @@
return;
}
Entry etr(event, data, length);
- log(&etr, true /*trusted*/);
+ log(etr, true /*trusted*/);
}
-void NBLog::Writer::log(const NBLog::Entry *etr, bool trusted)
+void NBLog::Writer::log(const NBLog::Entry &etr, bool trusted)
{
- if (!mEnabled) {
- return;
- }
+ if (!mEnabled) return;
if (!trusted) {
- log(etr->mEvent, etr->mData, etr->mLength);
+ log(etr.mEvent, etr.mData, etr.mLength);
return;
}
- size_t need = etr->mLength + Entry::kOverhead; // mEvent, mLength, data[mLength], mLength
+ size_t need = etr.mLength + Entry::kOverhead; // mEvent, mLength, data[mLength], mLength
// need = number of bytes written to FIFO
// FIXME optimize this using memcpy for the data part of the Entry.
@@ -571,7 +559,7 @@
uint8_t temp[Entry::kMaxLength + Entry::kOverhead];
// write this data to temp array
for (size_t i = 0; i < need; i++) {
- temp[i] = etr->copyEntryDataAt(i);
+ temp[i] = etr.copyEntryDataAt(i);
}
// write to circular buffer
mFifoWriter->write(temp, need);
@@ -743,15 +731,14 @@
if (mFifoReader == NULL) {
return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
}
- // make a copy to avoid race condition with writer
- size_t capacity = mFifo->capacity();
// This emulates the behaviour of audio_utils_fifo_reader::read, but without incrementing the
// reader index. The index is incremented after handling corruption, to after the last complete
// entry of the buffer
size_t lost;
audio_utils_iovec iovec[2];
- ssize_t availToRead = mFifoReader->obtain(iovec, capacity, NULL /*timeout*/, &lost);
+ const ssize_t availToRead = mFifoReader->obtain(iovec, mFifo->capacity(),
+ NULL /*timeout*/, &lost);
if (availToRead <= 0) {
return std::unique_ptr<NBLog::Reader::Snapshot>(new Snapshot());
}
@@ -800,7 +787,6 @@
snapshot->mLost = lost;
return snapshot;
-
}
// Takes raw content of the local merger FIFO, processes log entries, and
@@ -854,7 +840,7 @@
}
// FIXME: decide whether to print the warnings here or elsewhere
if (!body.isEmpty()) {
- dumpLine(timestamp, body);
+ dumpLine(×tamp, &body);
}
}
@@ -865,20 +851,22 @@
getAndProcessSnapshot(*snap);
}
-void NBLog::MergeReader::dump(int fd, int indent) {
+void NBLog::MergeReader::dump(int fd, int indent)
+{
// TODO: add a mutex around media.log dump
ReportPerformance::dump(fd, indent, mThreadPerformanceAnalysis);
}
// Writes a string to the console
-void NBLog::Reader::dumpLine(const String8 ×tamp, String8 &body)
+void NBLog::Reader::dumpLine(const String8 *timestamp, String8 *body)
{
+ if (timestamp == nullptr || body == nullptr) return;
if (mFd >= 0) {
- dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp.string(), body.string());
+ dprintf(mFd, "%.*s%s %s\n", mIndent, "", timestamp->string(), body->string());
} else {
- ALOGI("%.*s%s %s", mIndent, "", timestamp.string(), body.string());
+ ALOGI("%.*s%s %s", mIndent, "", timestamp->string(), body->string());
}
- body.clear();
+ body->clear();
}
bool NBLog::Reader::isIMemory(const sp<IMemory>& iMemory) const
@@ -888,25 +876,33 @@
// ---------------------------------------------------------------------------
-void NBLog::appendTimestamp(String8 *body, const void *data) {
+void NBLog::appendTimestamp(String8 *body, const void *data)
+{
+ if (body == nullptr || data == nullptr) return;
int64_t ts;
memcpy(&ts, data, sizeof(ts));
body->appendFormat("[%d.%03d]", (int) (ts / (1000 * 1000 * 1000)),
(int) ((ts / (1000 * 1000)) % 1000));
}
-void NBLog::appendInt(String8 *body, const void *data) {
+void NBLog::appendInt(String8 *body, const void *data)
+{
+ if (body == nullptr || data == nullptr) return;
int x = *((int*) data);
body->appendFormat("<%d>", x);
}
-void NBLog::appendFloat(String8 *body, const void *data) {
+void NBLog::appendFloat(String8 *body, const void *data)
+{
+ if (body == nullptr || data == nullptr) return;
float f;
- memcpy(&f, data, sizeof(float));
+ memcpy(&f, data, sizeof(f));
body->appendFormat("<%f>", f);
}
-void NBLog::appendPID(String8 *body, const void* data, size_t length) {
+void NBLog::appendPID(String8 *body, const void* data, size_t length)
+{
+ if (body == nullptr || data == nullptr) return;
pid_t id = *((pid_t*) data);
char * name = &((char*) data)[sizeof(pid_t)];
body->appendFormat("<PID: %d, name: %.*s>", id, (int) (length - sizeof(pid_t)), name);
@@ -915,9 +911,9 @@
String8 NBLog::bufferDump(const uint8_t *buffer, size_t size)
{
String8 str;
+ if (buffer == nullptr) return str;
str.append("[ ");
- for(size_t i = 0; i < size; i++)
- {
+ for(size_t i = 0; i < size; i++) {
str.appendFormat("%d ", buffer[i]);
}
str.append("]");
@@ -931,7 +927,8 @@
NBLog::EntryIterator NBLog::Reader::handleFormat(const FormatEntry &fmtEntry,
String8 *timestamp,
- String8 *body) {
+ String8 *body)
+{
// log timestamp
int64_t ts = fmtEntry.timestamp();
timestamp->clear();
@@ -947,7 +944,7 @@
handleAuthor(fmtEntry, body);
// log string
- NBLog::EntryIterator arg = fmtEntry.args();
+ EntryIterator arg = fmtEntry.args();
const char* fmt = fmtEntry.formatString();
size_t fmt_length = fmtEntry.formatStringLength();
@@ -1026,10 +1023,11 @@
new audio_utils_fifo(size, sizeof(uint8_t),
mShared->mBuffer, mShared->mRear, NULL /*throttlesFront*/) : NULL),
mFifoWriter(mFifo != NULL ? new audio_utils_fifo_writer(*mFifo) : NULL)
- {}
+{
+}
-void NBLog::Merger::addReader(const NBLog::NamedReader &reader) {
-
+void NBLog::Merger::addReader(const NBLog::NamedReader &reader)
+{
// FIXME This is called by binder thread in MediaLogService::registerWriter
// but the access to shared variable mNamedReaders is not yet protected by a lock.
mNamedReaders.push_back(reader);
@@ -1044,25 +1042,23 @@
MergeItem(int64_t ts, int index): ts(ts), index(index) {}
};
-// operators needed for priority queue in merge
-// bool operator>(const int64_t &t1, const int64_t &t2) {
-// return t1.tv_sec > t2.tv_sec || (t1.tv_sec == t2.tv_sec && t1.tv_nsec > t2.tv_nsec);
-// }
-
-bool operator>(const struct MergeItem &i1, const struct MergeItem &i2) {
+bool operator>(const struct MergeItem &i1, const struct MergeItem &i2)
+{
return i1.ts > i2.ts || (i1.ts == i2.ts && i1.index > i2.index);
}
// Merge registered readers, sorted by timestamp, and write data to a single FIFO in local memory
-void NBLog::Merger::merge() {
+void NBLog::Merger::merge()
+{
// FIXME This is called by merge thread
// but the access to shared variable mNamedReaders is not yet protected by a lock.
- int nLogs = mNamedReaders.size();
+ const int nLogs = mNamedReaders.size();
std::vector<std::unique_ptr<NBLog::Reader::Snapshot>> snapshots(nLogs);
- std::vector<NBLog::EntryIterator> offsets(nLogs);
+ std::vector<EntryIterator> offsets;
+ offsets.reserve(nLogs);
for (int i = 0; i < nLogs; ++i) {
snapshots[i] = mNamedReaders[i].reader()->getSnapshot();
- offsets[i] = snapshots[i]->begin();
+ offsets.push_back(snapshots[i]->begin());
}
// initialize offsets
// TODO custom heap implementation could allow to update top, improving performance
@@ -1071,17 +1067,19 @@
for (int i = 0; i < nLogs; ++i)
{
if (offsets[i] != snapshots[i]->end()) {
- int64_t ts = AbstractEntry::buildEntry(offsets[i])->timestamp();
- timestamps.emplace(ts, i);
+ std::unique_ptr<AbstractEntry> abstractEntry = AbstractEntry::buildEntry(offsets[i]);
+ if (abstractEntry == nullptr) {
+ continue;
+ }
+ timestamps.emplace(abstractEntry->timestamp(), i);
}
}
while (!timestamps.empty()) {
- // find minimum timestamp
- int index = timestamps.top().index;
+ int index = timestamps.top().index; // find minimum timestamp
// copy it to the log, increasing offset
- offsets[index] = AbstractEntry::buildEntry(offsets[index])->copyWithAuthor(mFifoWriter,
- index);
+ offsets[index] = AbstractEntry::buildEntry(offsets[index])->
+ copyWithAuthor(mFifoWriter, index);
// update data structures
timestamps.pop();
if (offsets[index] != snapshots[index]->end()) {
@@ -1091,7 +1089,8 @@
}
}
-const std::vector<NBLog::NamedReader>& NBLog::Merger::getNamedReaders() const {
+const std::vector<NBLog::NamedReader>& NBLog::Merger::getNamedReaders() const
+{
// FIXME This is returning a reference to a shared variable that needs a lock
return mNamedReaders;
}
@@ -1099,10 +1098,16 @@
// ---------------------------------------------------------------------------
NBLog::MergeReader::MergeReader(const void *shared, size_t size, Merger &merger)
- : Reader(shared, size), mNamedReaders(merger.getNamedReaders()) {}
+ : Reader(shared, size), mNamedReaders(merger.getNamedReaders())
+{
+}
-void NBLog::MergeReader::handleAuthor(const NBLog::AbstractEntry &entry, String8 *body) {
+void NBLog::MergeReader::handleAuthor(const NBLog::AbstractEntry &entry, String8 *body)
+{
int author = entry.author();
+ if (author == -1) {
+ return;
+ }
// FIXME Needs a lock
const char* name = mNamedReaders[author].name();
body->appendFormat("%s: ", name);
@@ -1113,16 +1118,20 @@
NBLog::MergeThread::MergeThread(NBLog::Merger &merger, NBLog::MergeReader &mergeReader)
: mMerger(merger),
mMergeReader(mergeReader),
- mTimeoutUs(0) {}
+ mTimeoutUs(0)
+{
+}
-NBLog::MergeThread::~MergeThread() {
+NBLog::MergeThread::~MergeThread()
+{
// set exit flag, set timeout to 0 to force threadLoop to exit and wait for the thread to join
requestExit();
setTimeoutUs(0);
join();
}
-bool NBLog::MergeThread::threadLoop() {
+bool NBLog::MergeThread::threadLoop()
+{
bool doMerge;
{
AutoMutex _l(mMutex);
@@ -1144,11 +1153,13 @@
return true;
}
-void NBLog::MergeThread::wakeup() {
+void NBLog::MergeThread::wakeup()
+{
setTimeoutUs(kThreadWakeupPeriodUs);
}
-void NBLog::MergeThread::setTimeoutUs(int time) {
+void NBLog::MergeThread::setTimeoutUs(int time)
+{
AutoMutex _l(mMutex);
mTimeoutUs = time;
mCond.signal();
diff --git a/media/libnblog/include/media/nblog/NBLog.h b/media/libnblog/include/media/nblog/NBLog.h
index fb6f179..bee3ad3 100644
--- a/media/libnblog/include/media/nblog/NBLog.h
+++ b/media/libnblog/include/media/nblog/NBLog.h
@@ -98,7 +98,12 @@
// entry iterator
class EntryIterator {
public:
+ // Used for dummy initialization. Performing operations on a default-constructed
+ // EntryIterator other than assigning it to another valid EntryIterator
+ // is undefined behavior.
EntryIterator();
+ // Caller's responsibility to make sure entry is not nullptr.
+ // Passing in nullptr can result in undefined behavior.
explicit EntryIterator(const uint8_t *entry);
EntryIterator(const EntryIterator &other);
@@ -109,7 +114,9 @@
EntryIterator& operator++(); // ++i
// back to previous entry
EntryIterator& operator--(); // --i
+ // returns an EntryIterator corresponding to the next entry
EntryIterator next() const;
+ // returns an EntryIterator corresponding to the previous entry
EntryIterator prev() const;
bool operator!=(const EntryIterator &other) const;
int operator-(const EntryIterator &other) const;
@@ -120,25 +127,22 @@
template<typename T>
inline const T& payload() {
- return *reinterpret_cast<const T *>(ptr + offsetof(entry, data));
+ return *reinterpret_cast<const T *>(mPtr + offsetof(entry, data));
}
inline operator const uint8_t*() const {
- return ptr;
+ return mPtr;
}
private:
- const uint8_t *ptr;
+ const uint8_t *mPtr; // Should not be nullptr except for dummy initialization
};
class AbstractEntry {
public:
-
- // Entry starting in the given pointer
- explicit AbstractEntry(const uint8_t *entry);
virtual ~AbstractEntry() {}
- // build concrete entry of appropriate class from pointer
+ // build concrete entry of appropriate class from ptr.
static std::unique_ptr<AbstractEntry> buildEntry(const uint8_t *ptr);
// get format entry timestamp
@@ -158,6 +162,8 @@
int author) const = 0;
protected:
+ // Entry starting in the given pointer, which shall not be nullptr.
+ explicit AbstractEntry(const uint8_t *entry);
// copies ordinary entry from src to dst, and returns length of entry
// size_t copyEntry(audio_utils_fifo_writer *dst, const iterator &it);
const uint8_t *mEntry;
@@ -360,7 +366,7 @@
// writes a single Entry to the FIFO
void log(Event event, const void *data, size_t length);
// checks validity of an event before calling log above this one
- void log(const Entry *entry, bool trusted = false);
+ void log(const Entry &entry, bool trusted = false);
Shared* const mShared; // raw pointer to shared memory
sp<IMemory> mIMemory; // ref-counted version, initialized in constructor
@@ -432,7 +438,6 @@
EntryIterator end() { return mEnd; }
private:
- friend class MergeReader;
friend class Reader;
uint8_t *mData;
size_t mLost;
@@ -454,7 +459,7 @@
protected:
// print a summary of the performance to the console
- void dumpLine(const String8& timestamp, String8& body);
+ void dumpLine(const String8 *timestamp, String8 *body);
EntryIterator handleFormat(const FormatEntry &fmtEntry,
String8 *timestamp,
String8 *body);
diff --git a/media/libstagefright/CameraSource.cpp b/media/libstagefright/CameraSource.cpp
index db37021..41f5db0 100644
--- a/media/libstagefright/CameraSource.cpp
+++ b/media/libstagefright/CameraSource.cpp
@@ -217,6 +217,7 @@
mNumFramesReceived(0),
mLastFrameTimestampUs(0),
mStarted(false),
+ mEos(false),
mNumFramesEncoded(0),
mTimeBetweenFrameCaptureUs(0),
mFirstFrameTimeUs(0),
@@ -880,6 +881,7 @@
{
Mutex::Autolock autoLock(mLock);
mStarted = false;
+ mEos = false;
mStopSystemTimeUs = -1;
mFrameAvailableCondition.signal();
@@ -1075,7 +1077,7 @@
{
Mutex::Autolock autoLock(mLock);
- while (mStarted && mFramesReceived.empty()) {
+ while (mStarted && !mEos && mFramesReceived.empty()) {
if (NO_ERROR !=
mFrameAvailableCondition.waitRelative(mLock,
mTimeBetweenFrameCaptureUs * 1000LL + CAMERA_SOURCE_TIMEOUT_NS)) {
@@ -1091,6 +1093,9 @@
if (!mStarted) {
return OK;
}
+ if (mFramesReceived.empty()) {
+ return ERROR_END_OF_STREAM;
+ }
frame = *mFramesReceived.begin();
mFramesReceived.erase(mFramesReceived.begin());
@@ -1129,6 +1134,8 @@
if (mStopSystemTimeUs != -1 && timestampUs >= mStopSystemTimeUs) {
ALOGV("Drop Camera frame at %lld stop time: %lld us",
(long long)timestampUs, (long long)mStopSystemTimeUs);
+ mEos = true;
+ mFrameAvailableCondition.signal();
return true;
}
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/VideoFrameScheduler.cpp b/media/libstagefright/VideoFrameScheduler.cpp
index 6819bba..9020fc1 100644
--- a/media/libstagefright/VideoFrameScheduler.cpp
+++ b/media/libstagefright/VideoFrameScheduler.cpp
@@ -475,7 +475,16 @@
nextVsyncTime += mVsyncPeriod;
if (vsyncsForLastFrame < ULONG_MAX)
++vsyncsForLastFrame;
+ } else if (mTimeCorrection < -correctionLimit * 2
+ || mTimeCorrection > correctionLimit * 2) {
+ ALOGW("correction beyond limit: %lld vs %lld (vsyncs for last frame: %zu, min: %zu)"
+ " restarting. render=%lld",
+ (long long)mTimeCorrection, (long long)correctionLimit,
+ vsyncsForLastFrame, minVsyncsPerFrame, (long long)origRenderTime);
+ restart();
+ return origRenderTime;
}
+
ATRACE_INT("FRAME_VSYNCS", vsyncsForLastFrame);
}
mLastVsyncTime = nextVsyncTime;
diff --git a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
index 75ca846..9c0fcfa 100644
--- a/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
+++ b/media/libstagefright/codecs/m4v_h263/dec/src/pvdec_api.cpp
@@ -186,8 +186,8 @@
#ifdef DEC_INTERNAL_MEMORY_OPT
video->vol[idx] = IMEM_vol[idx];
video->memoryUsage += sizeof(Vol);
- oscl_memset(video->vol[idx], 0, sizeof(Vol));
if (video->vol[idx] == NULL) status = PV_FALSE;
+ else oscl_memset(video->vol[idx], 0, sizeof(Vol));
stream = IMEM_BitstreamDecVideo;
#else
video->vol[idx] = (Vol *) oscl_malloc(sizeof(Vol));
@@ -213,6 +213,7 @@
else
{
int32 buffer_size;
+ oscl_memset(stream, 0, sizeof(BitstreamDecVideo));
if ((buffer_size = BitstreamOpen(stream, idx)) < 0)
{
mp4dec_log("InitVideoDecoder(): Can't allocate bitstream buffer.\n");
@@ -339,27 +340,33 @@
#ifdef DEC_INTERNAL_MEMORY_OPT
video->currVop->yChan = IMEM_currVop_yChan; /* Allocate memory for all VOP OKA 3/2/1*/
if (video->currVop->yChan == NULL) status = PV_FALSE;
- video->currVop->uChan = video->currVop->yChan + size;
- video->currVop->vChan = video->currVop->uChan + (size >> 2);
+ else {
+ video->currVop->uChan = video->currVop->yChan + size;
+ video->currVop->vChan = video->currVop->uChan + (size >> 2);
+ }
video->prevVop->yChan = IMEM_prevVop_yChan; /* Allocate memory for all VOP OKA 3/2/1*/
if (video->prevVop->yChan == NULL) status = PV_FALSE;
- video->prevVop->uChan = video->prevVop->yChan + size;
- video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+ else {
+ video->prevVop->uChan = video->prevVop->yChan + size;
+ video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+ }
#else
if (size > INT32_MAX / 3) {
return PV_FALSE;
}
video->currVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
if (video->currVop->yChan == NULL) status = PV_FALSE;
-
- video->currVop->uChan = video->currVop->yChan + size;
- video->currVop->vChan = video->currVop->uChan + (size >> 2);
+ else {
+ video->currVop->uChan = video->currVop->yChan + size;
+ video->currVop->vChan = video->currVop->uChan + (size >> 2);
+ }
video->prevVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
if (video->prevVop->yChan == NULL) status = PV_FALSE;
-
- video->prevVop->uChan = video->prevVop->yChan + size;
- video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+ else {
+ video->prevVop->uChan = video->prevVop->yChan + size;
+ video->prevVop->vChan = video->prevVop->uChan + (size >> 2);
+ }
#endif
video->memoryUsage += (size * 3);
#endif // MEMORY_POOL
@@ -383,8 +390,10 @@
video->prevEnhcVop->yChan = (PIXEL *) oscl_malloc(size * 3 / 2); /* Allocate memory for all VOP OKA 3/2/1*/
if (video->prevEnhcVop->yChan == NULL) status = PV_FALSE;
- video->prevEnhcVop->uChan = video->prevEnhcVop->yChan + size;
- video->prevEnhcVop->vChan = video->prevEnhcVop->uChan + (size >> 2);
+ else {
+ video->prevEnhcVop->uChan = video->prevEnhcVop->yChan + size;
+ video->prevEnhcVop->vChan = video->prevEnhcVop->uChan + (size >> 2);
+ }
video->memoryUsage += (3 * size / 2);
#endif
}
@@ -431,10 +440,12 @@
#else
video->sliceNo = (uint8 *) oscl_malloc(nTotalMB);
if (video->sliceNo == NULL) status = PV_FALSE;
+ else oscl_memset(video->sliceNo, 0, nTotalMB);
video->memoryUsage += nTotalMB;
video->acPredFlag = (uint8 *) oscl_malloc(nTotalMB * sizeof(uint8));
if (video->acPredFlag == NULL) status = PV_FALSE;
+ else oscl_memset(video->acPredFlag, 0, nTotalMB * sizeof(uint8));
video->memoryUsage += (nTotalMB);
if ((size_t)nTotalMB > SIZE_MAX / sizeof(typeDCStore)) {
@@ -442,6 +453,7 @@
}
video->predDC = (typeDCStore *) oscl_malloc(nTotalMB * sizeof(typeDCStore));
if (video->predDC == NULL) status = PV_FALSE;
+ else oscl_memset(video->predDC, 0, nTotalMB * sizeof(typeDCStore));
video->memoryUsage += (nTotalMB * sizeof(typeDCStore));
if (nMBPerRow > INT32_MAX - 1
@@ -450,6 +462,7 @@
}
video->predDCAC_col = (typeDCACStore *) oscl_malloc((nMBPerRow + 1) * sizeof(typeDCACStore));
if (video->predDCAC_col == NULL) status = PV_FALSE;
+ else oscl_memset(video->predDCAC_col, 0, (nMBPerRow + 1) * sizeof(typeDCACStore));
video->memoryUsage += ((nMBPerRow + 1) * sizeof(typeDCACStore));
/* element zero will be used for storing vertical (col) AC coefficients */
@@ -459,9 +472,11 @@
/* Allocating HeaderInfo structure & Quantizer array */
video->headerInfo.Mode = (uint8 *) oscl_malloc(nTotalMB);
if (video->headerInfo.Mode == NULL) status = PV_FALSE;
+ else oscl_memset(video->headerInfo.Mode, 0, nTotalMB);
video->memoryUsage += nTotalMB;
video->headerInfo.CBP = (uint8 *) oscl_malloc(nTotalMB);
if (video->headerInfo.CBP == NULL) status = PV_FALSE;
+ else oscl_memset (video->headerInfo.CBP, 0, nTotalMB);
video->memoryUsage += nTotalMB;
if ((size_t)nTotalMB > SIZE_MAX / sizeof(int16)) {
@@ -469,6 +484,7 @@
}
video->QPMB = (int16 *) oscl_malloc(nTotalMB * sizeof(int16));
if (video->QPMB == NULL) status = PV_FALSE;
+ else memset(video->QPMB, 0x0, nTotalMB * sizeof(int16));
video->memoryUsage += (nTotalMB * sizeof(int));
/* Allocating macroblock space */
@@ -489,8 +505,10 @@
}
video->motX = (MOT *) oscl_malloc(sizeof(MOT) * 4 * nTotalMB);
if (video->motX == NULL) status = PV_FALSE;
+ else memset(video->motX, 0, sizeof(MOT) * 4 * nTotalMB);
video->motY = (MOT *) oscl_malloc(sizeof(MOT) * 4 * nTotalMB);
if (video->motY == NULL) status = PV_FALSE;
+ else memset(video->motY, 0, sizeof(MOT) * 4 * nTotalMB);
video->memoryUsage += (sizeof(MOT) * 8 * nTotalMB);
#endif
diff --git a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
index 2364684..cd984f0 100644
--- a/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
+++ b/media/libstagefright/codecs/mp3dec/SoftMP3.cpp
@@ -114,7 +114,7 @@
mConfig->crcEnabled = false;
uint32_t memRequirements = pvmp3_decoderMemRequirements();
- mDecoderBuf = malloc(memRequirements);
+ mDecoderBuf = calloc(1, memRequirements);
pvmp3_InitDecoder(mConfig, mDecoderBuf);
mIsFirst = true;
diff --git a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
index f173e0f..06b15b3 100644
--- a/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
+++ b/media/libstagefright/codecs/xaacdec/SoftXAAC.cpp
@@ -689,7 +689,6 @@
notify(OMX_EventError, OMX_ErrorUndefined, err_code, NULL);
return;
}
- mIsCodecConfigFlushRequired = true;
}
if (!mSampFreq || !mNumChannels) {
@@ -713,10 +712,14 @@
signed int bytesConsumed = 0;
int errorCode = 0;
if (mIsCodecInitialized) {
+ mIsCodecConfigFlushRequired = true;
errorCode =
decodeXAACStream(inBuffer, inBufferLength, &bytesConsumed, &numOutBytes);
- } else {
+ } else if (!mIsCodecConfigFlushRequired) {
ALOGW("Assumption that first frame after header initializes decoder failed!");
+ mSignalledError = true;
+ notify(OMX_EventError, OMX_ErrorUndefined, -1, NULL);
+ return;
}
inHeader->nFilledLen -= bytesConsumed;
inHeader->nOffset += bytesConsumed;
diff --git a/media/libstagefright/http/HTTPHelper.cpp b/media/libstagefright/http/HTTPHelper.cpp
index 77845e2..b895f03 100644
--- a/media/libstagefright/http/HTTPHelper.cpp
+++ b/media/libstagefright/http/HTTPHelper.cpp
@@ -42,11 +42,11 @@
env, env->FindClass("android/media/MediaHTTPService"));
CHECK(clazz.get() != NULL);
- jmethodID constructID = env->GetMethodID(clazz.get(), "<init>", "()V");
+ jmethodID constructID = env->GetMethodID(clazz.get(), "<init>", "(Ljava/util/List;)V");
CHECK(constructID != NULL);
ScopedLocalRef<jobject> httpServiceObj(
- env, env->NewObject(clazz.get(), constructID));
+ env, env->NewObject(clazz.get(), constructID, NULL));
sp<IMediaHTTPService> httpService;
if (httpServiceObj.get() != NULL) {
diff --git a/media/libstagefright/include/media/stagefright/CameraSource.h b/media/libstagefright/include/media/stagefright/CameraSource.h
index 475976b..3037b72 100644
--- a/media/libstagefright/include/media/stagefright/CameraSource.h
+++ b/media/libstagefright/include/media/stagefright/CameraSource.h
@@ -204,6 +204,7 @@
int32_t mNumFramesReceived;
int64_t mLastFrameTimestampUs;
bool mStarted;
+ bool mEos;
int32_t mNumFramesEncoded;
// Time between capture of two frames.
diff --git a/media/libstagefright/include/media/stagefright/MetaDataUtils.h b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
index d5a8080..4a7107d 100644
--- a/media/libstagefright/include/media/stagefright/MetaDataUtils.h
+++ b/media/libstagefright/include/media/stagefright/MetaDataUtils.h
@@ -24,6 +24,7 @@
struct ABuffer;
bool MakeAVCCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
+bool MakeAACCodecSpecificData(MetaDataBase &meta, const uint8_t *data, size_t size);
bool MakeAACCodecSpecificData(MetaDataBase &meta, unsigned profile, unsigned sampling_freq_index,
unsigned channel_configuration);
diff --git a/media/libstagefright/mpeg2ts/ATSParser.cpp b/media/libstagefright/mpeg2ts/ATSParser.cpp
index cc31815..fb498d4 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.cpp
+++ b/media/libstagefright/mpeg2ts/ATSParser.cpp
@@ -775,10 +775,12 @@
ALOGV("new stream PID 0x%02x, type 0x%02x, scrambled %d, SampleEncrypted: %d",
elementaryPID, streamType, mScrambled, mSampleEncrypted);
- uint32_t flags =
- (isVideo() && mScrambled) ? ElementaryStreamQueue::kFlag_ScrambledData :
- (mSampleEncrypted) ? ElementaryStreamQueue::kFlag_SampleEncryptedData :
- 0;
+ uint32_t flags = 0;
+ if (((isVideo() || isAudio()) && mScrambled)) {
+ flags = ElementaryStreamQueue::kFlag_ScrambledData;
+ } else if (mSampleEncrypted) {
+ flags = ElementaryStreamQueue::kFlag_SampleEncryptedData;
+ }
ElementaryStreamQueue::Mode mode = ElementaryStreamQueue::INVALID;
@@ -815,6 +817,10 @@
mode = ElementaryStreamQueue::AC3;
break;
+ case STREAMTYPE_EAC3:
+ mode = ElementaryStreamQueue::EAC3;
+ break;
+
case STREAMTYPE_PES_PRIVATE_DATA:
if (mStreamTypeExt == EXT_DESCRIPTOR_DVB_AC4) {
mode = ElementaryStreamQueue::AC4;
@@ -1026,6 +1032,7 @@
case STREAMTYPE_MPEG2_AUDIO_ADTS:
case STREAMTYPE_LPCM_AC3:
case STREAMTYPE_AC3:
+ case STREAMTYPE_EAC3:
case STREAMTYPE_AAC_ENCRYPTED:
case STREAMTYPE_AC3_ENCRYPTED:
return true;
@@ -1499,7 +1506,13 @@
descrambleBytes = bytesWritten;
}
- sp<ABuffer> buffer;
+ // |buffer| points to the buffer from which we'd parse the PES header.
+ // When the output stream is scrambled, it points to mDescrambledBuffer
+ // (unless all packets in this PES are actually clear, in which case,
+ // it points to mBuffer since we never copied into mDescrambledBuffer).
+ // When the output stream is clear, it points to mBuffer, and we'll
+ // copy all descrambled data back to mBuffer.
+ sp<ABuffer> buffer = mBuffer;
if (mQueue->isScrambled()) {
// Queue subSample info for scrambled queue
sp<ABuffer> clearSizesBuffer = new ABuffer(mSubSamples.size() * 4);
@@ -1528,15 +1541,18 @@
}
// Pass the original TS subsample size now. The PES header adjust
// will be applied when the scrambled AU is dequeued.
+ // Note that if descrambleBytes is 0, it means this PES contains only
+ // all ts packets, leadingClearBytes is entire buffer size.
mQueue->appendScrambledData(
- mBuffer->data(), mBuffer->size(), sctrl,
- isSync, clearSizesBuffer, encSizesBuffer);
+ mBuffer->data(), mBuffer->size(),
+ (descrambleBytes > 0) ? descrambleBytes : mBuffer->size(),
+ sctrl, isSync, clearSizesBuffer, encSizesBuffer);
- buffer = mDescrambledBuffer;
+ if (descrambleBytes > 0) {
+ buffer = mDescrambledBuffer;
+ }
} else {
memcpy(mBuffer->data(), mDescrambledBuffer->data(), descrambleBytes);
-
- buffer = mBuffer;
}
ABitReader br(buffer->data(), buffer->size());
diff --git a/media/libstagefright/mpeg2ts/ATSParser.h b/media/libstagefright/mpeg2ts/ATSParser.h
index adb4fb2..a31dc46 100644
--- a/media/libstagefright/mpeg2ts/ATSParser.h
+++ b/media/libstagefright/mpeg2ts/ATSParser.h
@@ -154,6 +154,7 @@
// Stream type 0x83 is non-standard,
// it could be LPCM or TrueHD AC3
STREAMTYPE_LPCM_AC3 = 0x83,
+ STREAMTYPE_EAC3 = 0x87,
//Sample Encrypted types
STREAMTYPE_H264_ENCRYPTED = 0xDB,
diff --git a/media/libstagefright/mpeg2ts/ESQueue.cpp b/media/libstagefright/mpeg2ts/ESQueue.cpp
index 34d0bcc..fb8b9fd 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.cpp
+++ b/media/libstagefright/mpeg2ts/ESQueue.cpp
@@ -210,8 +210,81 @@
return payloadSize;
}
-static bool IsSeeminglyValidAC3Header(const uint8_t *ptr, size_t size) {
- return parseAC3SyncFrame(ptr, size, NULL) > 0;
+// Parse EAC3 header assuming the current ptr is start position of syncframe,
+// update metadata only applicable, and return the payload size
+// ATSC A/52:2012 E2.3.1
+static unsigned parseEAC3SyncFrame(
+ const uint8_t *ptr, size_t size, sp<MetaData> *metaData) {
+ static const unsigned channelCountTable[] = {2, 1, 2, 3, 3, 4, 4, 5};
+ static const unsigned samplingRateTable[] = {48000, 44100, 32000};
+ static const unsigned samplingRateTable2[] = {24000, 22050, 16000};
+
+ ABitReader bits(ptr, size);
+ if (bits.numBitsLeft() < 16) {
+ ALOGE("Not enough bits left for further parsing");
+ return 0;
+ }
+ if (bits.getBits(16) != 0x0B77) {
+ ALOGE("No valid sync word in EAC3 header");
+ return 0;
+ }
+
+ // we parse up to bsid so there needs to be at least that many bits
+ if (bits.numBitsLeft() < 2 + 3 + 11 + 2 + 2 + 3 + 1 + 5) {
+ ALOGE("Not enough bits left for further parsing");
+ return 0;
+ }
+
+ unsigned strmtyp = bits.getBits(2);
+ if (strmtyp == 3) {
+ ALOGE("Incorrect strmtyp in EAC3 header");
+ return 0;
+ }
+
+ unsigned substreamid = bits.getBits(3);
+ // only the first independent stream is supported
+ if ((strmtyp == 0 || strmtyp == 2) && substreamid != 0)
+ return 0;
+
+ unsigned frmsiz = bits.getBits(11);
+ unsigned fscod = bits.getBits(2);
+
+ unsigned samplingRate = 0;
+ if (fscod == 0x3) {
+ unsigned fscod2 = bits.getBits(2);
+ if (fscod2 == 3) {
+ ALOGW("Incorrect fscod2 in EAC3 header");
+ return 0;
+ }
+ samplingRate = samplingRateTable2[fscod2];
+ } else {
+ samplingRate = samplingRateTable[fscod];
+ unsigned numblkscod __unused = bits.getBits(2);
+ }
+
+ unsigned acmod = bits.getBits(3);
+ unsigned lfeon = bits.getBits(1);
+ unsigned bsid = bits.getBits(5);
+ if (bsid < 11 || bsid > 16) {
+ ALOGW("Incorrect bsid in EAC3 header. Could be AC-3 or some unknown EAC3 format");
+ return 0;
+ }
+
+ // we currently only support the first independant stream
+ if (metaData != NULL && (strmtyp == 0 || strmtyp == 2)) {
+ unsigned channelCount = channelCountTable[acmod] + lfeon;
+ ALOGV("EAC3 channelCount = %d", channelCount);
+ ALOGV("EAC3 samplingRate = %d", samplingRate);
+ (*metaData)->setCString(kKeyMIMEType, MEDIA_MIMETYPE_AUDIO_EAC3);
+ (*metaData)->setInt32(kKeyChannelCount, channelCount);
+ (*metaData)->setInt32(kKeySampleRate, samplingRate);
+ (*metaData)->setInt32(kKeyIsSyncFrame, 1);
+ }
+
+ unsigned payloadSize = frmsiz + 1;
+ payloadSize <<= 1; // convert from 16-bit words to bytes
+
+ return payloadSize;
}
// Parse AC4 header assuming the current ptr is start position of syncframe
@@ -366,7 +439,8 @@
ALOGE("appending data after EOS");
return ERROR_MALFORMED;
}
- if (mBuffer == NULL || mBuffer->size() == 0) {
+
+ if (!isScrambled() && (mBuffer == NULL || mBuffer->size() == 0)) {
switch (mMode) {
case H264:
case MPEG_VIDEO:
@@ -477,12 +551,19 @@
}
case AC3:
+ case EAC3:
{
uint8_t *ptr = (uint8_t *)data;
ssize_t startOffset = -1;
for (size_t i = 0; i < size; ++i) {
- if (IsSeeminglyValidAC3Header(&ptr[i], size - i)) {
+ unsigned payloadSize = 0;
+ if (mMode == AC3) {
+ payloadSize = parseAC3SyncFrame(&ptr[i], size - i, NULL);
+ } else if (mMode == EAC3) {
+ payloadSize = parseEAC3SyncFrame(&ptr[i], size - i, NULL);
+ }
+ if (payloadSize > 0) {
startOffset = i;
break;
}
@@ -493,7 +574,7 @@
}
if (startOffset > 0) {
- ALOGI("found something resembling an AC3 syncword at "
+ ALOGI("found something resembling an (E)AC3 syncword at "
"offset %zd",
startOffset);
}
@@ -526,8 +607,9 @@
}
if (startOffset > 0) {
- ALOGI("found something resembling an AC4 syncword at offset %zd",
- startOffset);
+ ALOGI("found something resembling an AC4 syncword at "
+ "offset %zd",
+ startOffset);
}
if (frameSize != size - startOffset) {
ALOGV("AC4 frame size is %u bytes, while the buffer size is %zd bytes.",
@@ -617,6 +699,7 @@
void ElementaryStreamQueue::appendScrambledData(
const void *data, size_t size,
+ size_t leadingClearBytes,
int32_t keyId, bool isSync,
sp<ABuffer> clearSizes, sp<ABuffer> encSizes) {
if (!isScrambled()) {
@@ -644,6 +727,7 @@
ScrambledRangeInfo scrambledInfo;
scrambledInfo.mLength = size;
+ scrambledInfo.mLeadingClearBytes = leadingClearBytes;
scrambledInfo.mKeyId = keyId;
scrambledInfo.mIsSync = isSync;
scrambledInfo.mClearSizes = clearSizes;
@@ -656,7 +740,6 @@
sp<ABuffer> ElementaryStreamQueue::dequeueScrambledAccessUnit() {
size_t nextScan = mBuffer->size();
- mBuffer->setRange(0, 0);
int32_t pesOffset = 0, pesScramblingControl = 0;
int64_t timeUs = fetchTimestamp(nextScan, &pesOffset, &pesScramblingControl);
if (timeUs < 0ll) {
@@ -667,6 +750,7 @@
// return scrambled unit
int32_t keyId = pesScramblingControl, isSync = 0, scrambledLength = 0;
sp<ABuffer> clearSizes, encSizes;
+ size_t leadingClearBytes;
while (mScrambledRangeInfos.size() > mRangeInfos.size()) {
auto it = mScrambledRangeInfos.begin();
ALOGV("[stream %d] fetching scrambled range: size=%zu", mMode, it->mLength);
@@ -684,6 +768,7 @@
clearSizes = it->mClearSizes;
encSizes = it->mEncSizes;
isSync = it->mIsSync;
+ leadingClearBytes = it->mLeadingClearBytes;
mScrambledRangeInfos.erase(it);
}
if (scrambledLength == 0) {
@@ -691,6 +776,70 @@
return NULL;
}
+ // Retrieve the leading clear bytes info, and use it to set the clear
+ // range on mBuffer. Note that the leading clear bytes includes the
+ // PES header portion, while mBuffer doesn't.
+ if ((int32_t)leadingClearBytes > pesOffset) {
+ mBuffer->setRange(0, leadingClearBytes - pesOffset);
+ } else {
+ mBuffer->setRange(0, 0);
+ }
+
+ // Try to parse formats, and if unavailable set up a dummy format.
+ // Only support the following modes for scrambled content for now.
+ // (will be expanded later).
+ if (mFormat == NULL) {
+ mFormat = new MetaData;
+ switch (mMode) {
+ case H264:
+ {
+ if (!MakeAVCCodecSpecificData(
+ *mFormat, mBuffer->data(), mBuffer->size())) {
+ ALOGI("Creating dummy AVC format for scrambled content");
+
+ mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
+ mFormat->setInt32(kKeyWidth, 1280);
+ mFormat->setInt32(kKeyHeight, 720);
+ }
+ break;
+ }
+ case AAC:
+ {
+ if (!MakeAACCodecSpecificData(
+ *mFormat, mBuffer->data(), mBuffer->size())) {
+ ALOGI("Creating dummy AAC format for scrambled content");
+
+ MakeAACCodecSpecificData(*mFormat,
+ 1 /*profile*/, 7 /*sampling_freq_index*/, 1 /*channel_config*/);
+ mFormat->setInt32(kKeyIsADTS, true);
+ }
+
+ break;
+ }
+ case MPEG_VIDEO:
+ {
+ ALOGI("Creating dummy MPEG format for scrambled content");
+
+ mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
+ mFormat->setInt32(kKeyWidth, 1280);
+ mFormat->setInt32(kKeyHeight, 720);
+ break;
+ }
+ default:
+ {
+ ALOGE("Unknown mode for scrambled content");
+ return NULL;
+ }
+ }
+
+ // for MediaExtractor.CasInfo
+ mFormat->setInt32(kKeyCASystemID, mCASystemId);
+ mFormat->setData(kKeyCASessionID,
+ 0, mCasSessionId.data(), mCasSessionId.size());
+ }
+
+ mBuffer->setRange(0, 0);
+
// copy into scrambled access unit
sp<ABuffer> scrambledAccessUnit = ABuffer::CreateAsCopy(
mScrambledBuffer->data(), scrambledLength);
@@ -722,7 +871,11 @@
}
sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnit() {
- if ((mFlags & kFlag_AlignedData) && mMode == H264 && !isScrambled()) {
+ if (isScrambled()) {
+ return dequeueScrambledAccessUnit();
+ }
+
+ if ((mFlags & kFlag_AlignedData) && mMode == H264) {
if (mRangeInfos.empty()) {
return NULL;
}
@@ -756,7 +909,8 @@
case AAC:
return dequeueAccessUnitAAC();
case AC3:
- return dequeueAccessUnitAC3();
+ case EAC3:
+ return dequeueAccessUnitEAC3();
case AC4:
return dequeueAccessUnitAC4();
case MPEG_VIDEO:
@@ -776,34 +930,38 @@
}
}
-sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitAC3() {
+sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitEAC3() {
unsigned syncStartPos = 0; // in bytes
unsigned payloadSize = 0;
sp<MetaData> format = new MetaData;
- ALOGV("dequeueAccessUnit_AC3[%d]: mBuffer %p(%zu)", mAUIndex, mBuffer->data(), mBuffer->size());
+ ALOGV("dequeueAccessUnitEAC3[%d]: mBuffer %p(%zu)", mAUIndex,
+ mBuffer->data(), mBuffer->size());
while (true) {
if (syncStartPos + 2 >= mBuffer->size()) {
return NULL;
}
- payloadSize = parseAC3SyncFrame(
- mBuffer->data() + syncStartPos,
- mBuffer->size() - syncStartPos,
- &format);
+ uint8_t *ptr = mBuffer->data() + syncStartPos;
+ size_t size = mBuffer->size() - syncStartPos;
+ if (mMode == AC3) {
+ payloadSize = parseAC3SyncFrame(ptr, size, &format);
+ } else if (mMode == EAC3) {
+ payloadSize = parseEAC3SyncFrame(ptr, size, &format);
+ }
if (payloadSize > 0) {
break;
}
- ALOGV("dequeueAccessUnit_AC3[%d]: syncStartPos %u payloadSize %u",
+ ALOGV("dequeueAccessUnitEAC3[%d]: syncStartPos %u payloadSize %u",
mAUIndex, syncStartPos, payloadSize);
++syncStartPos;
}
if (mBuffer->size() < syncStartPos + payloadSize) {
- ALOGV("Not enough buffer size for AC3");
+ ALOGV("Not enough buffer size for E/AC3");
return NULL;
}
@@ -811,7 +969,6 @@
mFormat = format;
}
-
int64_t timeUs = fetchTimestamp(syncStartPos + payloadSize);
if (timeUs < 0ll) {
ALOGE("negative timeUs");
@@ -820,7 +977,12 @@
// Not decrypting if key info not available (e.g., scanner/extractor parsing ts files)
if (mSampleDecryptor != NULL) {
- mSampleDecryptor->processAC3(mBuffer->data() + syncStartPos, payloadSize);
+ if (mMode == AC3) {
+ mSampleDecryptor->processAC3(mBuffer->data() + syncStartPos, payloadSize);
+ } else if (mMode == EAC3) {
+ ALOGE("EAC3 AU is encrypted and decryption is not supported");
+ return NULL;
+ }
}
mAUIndex++;
@@ -1024,25 +1186,11 @@
bool protection_absent = bits.getBits(1) != 0;
if (mFormat == NULL) {
- unsigned profile = bits.getBits(2);
- if (profile == 3u) {
- ALOGE("profile should not be 3");
- return NULL;
- }
- unsigned sampling_freq_index = bits.getBits(4);
- bits.getBits(1); // private_bit
- unsigned channel_configuration = bits.getBits(3);
- if (channel_configuration == 0u) {
- ALOGE("channel_config should not be 0");
- return NULL;
- }
- bits.skipBits(2); // original_copy, home
-
mFormat = new MetaData;
- MakeAACCodecSpecificData(*mFormat,
- profile, sampling_freq_index, channel_configuration);
-
- mFormat->setInt32(kKeyIsADTS, true);
+ if (!MakeAACCodecSpecificData(
+ *mFormat, mBuffer->data() + offset, mBuffer->size() - offset)) {
+ return NULL;
+ }
int32_t sampleRate;
int32_t numChannels;
@@ -1057,12 +1205,12 @@
ALOGI("found AAC codec config (%d Hz, %d channels)",
sampleRate, numChannels);
- } else {
- // profile_ObjectType, sampling_frequency_index, private_bits,
- // channel_configuration, original_copy, home
- bits.skipBits(12);
}
+ // profile_ObjectType, sampling_frequency_index, private_bits,
+ // channel_configuration, original_copy, home
+ bits.skipBits(12);
+
// adts_variable_header
// copyright_identification_bit, copyright_identification_start
@@ -1177,27 +1325,6 @@
}
sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitH264() {
- if (isScrambled()) {
- if (mBuffer == NULL || mBuffer->size() == 0) {
- return NULL;
- }
- if (mFormat == NULL) {
- mFormat = new MetaData;
- if (!MakeAVCCodecSpecificData(*mFormat, mBuffer->data(), mBuffer->size())) {
- ALOGW("Creating dummy AVC format for scrambled content");
- mFormat = new MetaData;
- mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_AVC);
- mFormat->setInt32(kKeyWidth, 1280);
- mFormat->setInt32(kKeyHeight, 720);
- }
- // for MediaExtractor.CasInfo
- mFormat->setInt32(kKeyCASystemID, mCASystemId);
- mFormat->setData(kKeyCASessionID, 0,
- mCasSessionId.data(), mCasSessionId.size());
- }
- return dequeueScrambledAccessUnit();
- }
-
const uint8_t *data = mBuffer->data();
size_t size = mBuffer->size();
@@ -1497,25 +1624,6 @@
}
sp<ABuffer> ElementaryStreamQueue::dequeueAccessUnitMPEGVideo() {
- if (isScrambled()) {
- if (mBuffer == NULL || mBuffer->size() == 0) {
- return NULL;
- }
- if (mFormat == NULL) {
- ALOGI("Creating dummy MPEG format for scrambled content");
- mFormat = new MetaData;
- mFormat->setCString(kKeyMIMEType, MEDIA_MIMETYPE_VIDEO_MPEG2);
- mFormat->setInt32(kKeyWidth, 1280);
- mFormat->setInt32(kKeyHeight, 720);
-
- // for MediaExtractor.CasInfo
- mFormat->setInt32(kKeyCASystemID, mCASystemId);
- mFormat->setData(kKeyCASessionID, 0,
- mCasSessionId.data(), mCasSessionId.size());
- }
- return dequeueScrambledAccessUnit();
- }
-
const uint8_t *data = mBuffer->data();
size_t size = mBuffer->size();
diff --git a/media/libstagefright/mpeg2ts/ESQueue.h b/media/libstagefright/mpeg2ts/ESQueue.h
index 399214a..3227f47 100644
--- a/media/libstagefright/mpeg2ts/ESQueue.h
+++ b/media/libstagefright/mpeg2ts/ESQueue.h
@@ -38,6 +38,7 @@
H264,
AAC,
AC3,
+ EAC3,
AC4,
MPEG_AUDIO,
MPEG_VIDEO,
@@ -60,6 +61,7 @@
void appendScrambledData(
const void *data, size_t size,
+ size_t leadingClearBytes,
int32_t keyId, bool isSync,
sp<ABuffer> clearSizes, sp<ABuffer> encSizes);
@@ -85,8 +87,8 @@
};
struct ScrambledRangeInfo {
- //int64_t mTimestampUs;
size_t mLength;
+ size_t mLeadingClearBytes;
int32_t mKeyId;
int32_t mIsSync;
sp<ABuffer> mClearSizes;
@@ -116,7 +118,7 @@
sp<ABuffer> dequeueAccessUnitH264();
sp<ABuffer> dequeueAccessUnitAAC();
- sp<ABuffer> dequeueAccessUnitAC3();
+ sp<ABuffer> dequeueAccessUnitEAC3();
sp<ABuffer> dequeueAccessUnitAC4();
sp<ABuffer> dequeueAccessUnitMPEGAudio();
sp<ABuffer> dequeueAccessUnitMPEGVideo();
diff --git a/media/ndk/NdkMediaCodec.cpp b/media/ndk/NdkMediaCodec.cpp
index 6b20bca..42285f8 100644
--- a/media/ndk/NdkMediaCodec.cpp
+++ b/media/ndk/NdkMediaCodec.cpp
@@ -811,7 +811,13 @@
size_t *encryptedbytes) {
// size needed to store all the crypto data
- size_t cryptosize = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
+ size_t cryptosize;
+ // = sizeof(AMediaCodecCryptoInfo) + sizeof(size_t) * numsubsamples * 2;
+ if (__builtin_mul_overflow(sizeof(size_t) * 2, numsubsamples, &cryptosize) ||
+ __builtin_add_overflow(cryptosize, sizeof(AMediaCodecCryptoInfo), &cryptosize)) {
+ ALOGE("crypto size overflow");
+ return NULL;
+ }
AMediaCodecCryptoInfo *ret = (AMediaCodecCryptoInfo*) malloc(cryptosize);
if (!ret) {
ALOGE("couldn't allocate %zu bytes", cryptosize);
diff --git a/media/utils/Android.bp b/media/utils/Android.bp
index 13b66ed..f5b3f92 100644
--- a/media/utils/Android.bp
+++ b/media/utils/Android.bp
@@ -40,6 +40,12 @@
"-Werror",
],
+ product_variables: {
+ product_is_iot: {
+ cflags: ["-DTARGET_ANDROID_THINGS"],
+ },
+ },
+
local_include_dirs: ["include"],
export_include_dirs: ["include"],
}
diff --git a/media/utils/ServiceUtilities.cpp b/media/utils/ServiceUtilities.cpp
index 0d50be0..1c54aec 100644
--- a/media/utils/ServiceUtilities.cpp
+++ b/media/utils/ServiceUtilities.cpp
@@ -158,6 +158,27 @@
return ok;
}
+bool modifyDefaultAudioEffectsAllowed() {
+ static const String16 sModifyDefaultAudioEffectsAllowed(
+ "android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
+ // IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
+ bool ok = PermissionCache::checkCallingPermission(sModifyDefaultAudioEffectsAllowed);
+
+#ifdef TARGET_ANDROID_THINGS
+ if (!ok) {
+ // Use a secondary permission on Android Things to allow a more lenient level of protection.
+ static const String16 sModifyDefaultAudioEffectsAndroidThingsAllowed(
+ "com.google.android.things.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
+ ok = PermissionCache::checkCallingPermission(
+ sModifyDefaultAudioEffectsAndroidThingsAllowed);
+ }
+ if (!ok) ALOGE("com.google.android.things.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
+#else
+ if (!ok) ALOGE("android.permission.MODIFY_DEFAULT_AUDIO_EFFECTS");
+#endif
+ return ok;
+}
+
bool dumpAllowed() {
static const String16 sDump("android.permission.DUMP");
// IMPORTANT: Use PermissionCache - not a runtime permission and may not change.
diff --git a/media/utils/include/mediautils/ServiceUtilities.h b/media/utils/include/mediautils/ServiceUtilities.h
index 0911744..98f54c2 100644
--- a/media/utils/include/mediautils/ServiceUtilities.h
+++ b/media/utils/include/mediautils/ServiceUtilities.h
@@ -68,6 +68,7 @@
bool captureHotwordAllowed(pid_t pid, uid_t uid);
bool settingsAllowed();
bool modifyAudioRoutingAllowed();
+bool modifyDefaultAudioEffectsAllowed();
bool dumpAllowed();
bool modifyPhoneStateAllowed(pid_t pid, uid_t uid);
status_t checkIMemory(const sp<IMemory>& iMemory);
diff --git a/services/audioflinger/Android.mk b/services/audioflinger/Android.mk
index c0aa477..2c26ba4 100644
--- a/services/audioflinger/Android.mk
+++ b/services/audioflinger/Android.mk
@@ -42,6 +42,7 @@
LOCAL_STATIC_LIBRARIES := \
libcpustats \
+ libjsoncpp \
libsndfile \
LOCAL_MULTILIB := $(AUDIOSERVER_MULTILIB)
diff --git a/services/audioflinger/AudioFlinger.cpp b/services/audioflinger/AudioFlinger.cpp
index 9234364..43566b7 100644
--- a/services/audioflinger/AudioFlinger.cpp
+++ b/services/audioflinger/AudioFlinger.cpp
@@ -58,6 +58,8 @@
#include <audio_utils/primitives.h>
+#include <json/json.h>
+
#include <powermanager/PowerManager.h>
#include <media/IMediaLogService.h>
@@ -440,8 +442,11 @@
const bool formatJson = std::any_of(args.begin(), args.end(),
[](const String16 &arg) { return arg == String16("--json"); });
if (formatJson) {
+ Json::Value root = getJsonDump();
+ Json::FastWriter writer;
+ std::string rootStr = writer.write(root);
// XXX consider buffering if the string happens to be too long.
- dprintf(fd, "%s", getJsonString().c_str());
+ dprintf(fd, "%s", rootStr.c_str());
return NO_ERROR;
}
@@ -556,34 +561,30 @@
return NO_ERROR;
}
-std::string AudioFlinger::getJsonString()
+Json::Value AudioFlinger::getJsonDump()
{
- std::string jsonStr = "{\n";
+ Json::Value root(Json::objectValue);
const bool locked = dumpTryLock(mLock);
// failed to lock - AudioFlinger is probably deadlocked
if (!locked) {
- jsonStr += " \"deadlock_message\": ";
- jsonStr += kDeadlockedString;
- jsonStr += ",\n";
+ root["deadlock_message"] = kDeadlockedString;
}
// FIXME risky to access data structures without a lock held?
- jsonStr += " \"Playback_Threads\": [\n";
+ Json::Value playbackThreads = Json::arrayValue;
// dump playback threads
for (size_t i = 0; i < mPlaybackThreads.size(); i++) {
- if (i != 0) {
- jsonStr += ",\n";
- }
- jsonStr += mPlaybackThreads.valueAt(i)->getJsonString();
+ playbackThreads.append(mPlaybackThreads.valueAt(i)->getJsonDump());
}
- jsonStr += "\n ]\n}\n";
if (locked) {
mLock.unlock();
}
- return jsonStr;
+ root["playback_threads"] = playbackThreads;
+
+ return root;
}
sp<AudioFlinger::Client> AudioFlinger::registerPid(pid_t pid)
@@ -2949,16 +2950,74 @@
}
status_t AudioFlinger::getEffectDescriptor(const effect_uuid_t *pUuid,
- effect_descriptor_t *descriptor) const
+ const effect_uuid_t *pTypeUuid,
+ uint32_t preferredTypeFlag,
+ effect_descriptor_t *descriptor) const
{
+ if (pUuid == NULL || pTypeUuid == NULL || descriptor == NULL) {
+ return BAD_VALUE;
+ }
+
Mutex::Autolock _l(mLock);
- if (mEffectsFactoryHal.get()) {
- return mEffectsFactoryHal->getDescriptor(pUuid, descriptor);
- } else {
+
+ if (!mEffectsFactoryHal.get()) {
return -ENODEV;
}
-}
+ status_t status = NO_ERROR;
+ if (!EffectsFactoryHalInterface::isNullUuid(pUuid)) {
+ // If uuid is specified, request effect descriptor from that.
+ status = mEffectsFactoryHal->getDescriptor(pUuid, descriptor);
+ } else if (!EffectsFactoryHalInterface::isNullUuid(pTypeUuid)) {
+ // If uuid is not specified, look for an available implementation
+ // of the required type instead.
+
+ // Use a temporary descriptor to avoid modifying |descriptor| in the failure case.
+ effect_descriptor_t desc;
+ desc.flags = 0; // prevent compiler warning
+
+ uint32_t numEffects = 0;
+ status = mEffectsFactoryHal->queryNumberEffects(&numEffects);
+ if (status < 0) {
+ ALOGW("getEffectDescriptor() error %d from FactoryHal queryNumberEffects", status);
+ return status;
+ }
+
+ bool found = false;
+ for (uint32_t i = 0; i < numEffects; i++) {
+ status = mEffectsFactoryHal->getDescriptor(i, &desc);
+ if (status < 0) {
+ ALOGW("getEffectDescriptor() error %d from FactoryHal getDescriptor", status);
+ continue;
+ }
+ if (memcmp(&desc.type, pTypeUuid, sizeof(effect_uuid_t)) == 0) {
+ // If matching type found save effect descriptor.
+ found = true;
+ *descriptor = desc;
+
+ // If there's no preferred flag or this descriptor matches the preferred
+ // flag, success! If this descriptor doesn't match the preferred
+ // flag, continue enumeration in case a better matching version of this
+ // effect type is available. Note that this means if no effect with a
+ // correct flag is found, the descriptor returned will correspond to the
+ // last effect that at least had a matching type uuid (if any).
+ if (preferredTypeFlag == EFFECT_FLAG_TYPE_MASK ||
+ (desc.flags & EFFECT_FLAG_TYPE_MASK) == preferredTypeFlag) {
+ break;
+ }
+ }
+ }
+
+ if (!found) {
+ status = NAME_NOT_FOUND;
+ ALOGW("getEffectDescriptor(): Effect not found by type.");
+ }
+ } else {
+ status = BAD_VALUE;
+ ALOGE("getEffectDescriptor(): Either uuid or type uuid must be non-null UUIDs.");
+ }
+ return status;
+}
sp<IEffect> AudioFlinger::createEffect(
effect_descriptor_t *pDesc,
@@ -3012,60 +3071,15 @@
}
{
- if (!EffectsFactoryHalInterface::isNullUuid(&pDesc->uuid)) {
- // if uuid is specified, request effect descriptor
- lStatus = mEffectsFactoryHal->getDescriptor(&pDesc->uuid, &desc);
- if (lStatus < 0) {
- ALOGW("createEffect() error %d from EffectGetDescriptor", lStatus);
- goto Exit;
- }
- } else {
- // if uuid is not specified, look for an available implementation
- // of the required type in effect factory
- if (EffectsFactoryHalInterface::isNullUuid(&pDesc->type)) {
- ALOGW("createEffect() no effect type");
- lStatus = BAD_VALUE;
- goto Exit;
- }
- uint32_t numEffects = 0;
- effect_descriptor_t d;
- d.flags = 0; // prevent compiler warning
- bool found = false;
-
- lStatus = mEffectsFactoryHal->queryNumberEffects(&numEffects);
- if (lStatus < 0) {
- ALOGW("createEffect() error %d from EffectQueryNumberEffects", lStatus);
- goto Exit;
- }
- for (uint32_t i = 0; i < numEffects; i++) {
- lStatus = mEffectsFactoryHal->getDescriptor(i, &desc);
- if (lStatus < 0) {
- ALOGW("createEffect() error %d from EffectQueryEffect", lStatus);
- continue;
- }
- if (memcmp(&desc.type, &pDesc->type, sizeof(effect_uuid_t)) == 0) {
- // If matching type found save effect descriptor. If the session is
- // 0 and the effect is not auxiliary, continue enumeration in case
- // an auxiliary version of this effect type is available
- found = true;
- d = desc;
- if (sessionId != AUDIO_SESSION_OUTPUT_MIX ||
- (desc.flags & EFFECT_FLAG_TYPE_MASK) == EFFECT_FLAG_TYPE_AUXILIARY) {
- break;
- }
- }
- }
- if (!found) {
- lStatus = BAD_VALUE;
- ALOGW("createEffect() effect not found");
- goto Exit;
- }
- // For same effect type, chose auxiliary version over insert version if
- // connect to output mix (Compliance to OpenSL ES)
- if (sessionId == AUDIO_SESSION_OUTPUT_MIX &&
- (d.flags & EFFECT_FLAG_TYPE_MASK) != EFFECT_FLAG_TYPE_AUXILIARY) {
- desc = d;
- }
+ // Get the full effect descriptor from the uuid/type.
+ // If the session is the output mix, prefer an auxiliary effect,
+ // otherwise no preference.
+ uint32_t preferredType = (sessionId == AUDIO_SESSION_OUTPUT_MIX ?
+ EFFECT_FLAG_TYPE_AUXILIARY : EFFECT_FLAG_TYPE_MASK);
+ lStatus = getEffectDescriptor(&pDesc->uuid, &pDesc->type, preferredType, &desc);
+ if (lStatus < 0) {
+ ALOGW("createEffect() error %d from getEffectDescriptor", lStatus);
+ goto Exit;
}
// Do not allow auxiliary effects on a session different from 0 (output mix)
diff --git a/services/audioflinger/AudioFlinger.h b/services/audioflinger/AudioFlinger.h
index 95b947c..e9e6e94 100644
--- a/services/audioflinger/AudioFlinger.h
+++ b/services/audioflinger/AudioFlinger.h
@@ -79,6 +79,7 @@
#include <powermanager/IPowerManager.h>
+#include <json/json.h>
#include <media/nblog/NBLog.h>
#include <private/media/AudioEffectShared.h>
#include <private/media/AudioTrackShared.h>
@@ -114,7 +115,7 @@
static const char* getServiceName() ANDROID_API { return "media.audio_flinger"; }
virtual status_t dump(int fd, const Vector<String16>& args);
- std::string getJsonString();
+ Json::Value getJsonDump();
// IAudioFlinger interface, in binder opcode order
virtual sp<IAudioTrack> createTrack(const CreateTrackInput& input,
@@ -208,6 +209,8 @@
virtual status_t queryEffect(uint32_t index, effect_descriptor_t *descriptor) const;
virtual status_t getEffectDescriptor(const effect_uuid_t *pUuid,
+ const effect_uuid_t *pTypeUuid,
+ uint32_t preferredTypeFlag,
effect_descriptor_t *descriptor) const;
virtual sp<IEffect> createEffect(
diff --git a/services/audioflinger/Configuration.h b/services/audioflinger/Configuration.h
index 64bb426..34cd821 100644
--- a/services/audioflinger/Configuration.h
+++ b/services/audioflinger/Configuration.h
@@ -27,7 +27,7 @@
//#define AUDIO_WATCHDOG
// uncomment to display CPU load adjusted for CPU frequency
-#define CPU_FREQUENCY_STATISTICS
+//define CPU_FREQUENCY_STATISTICS
// uncomment to enable fast threads to take performance samples for later statistical analysis
#define FAST_THREAD_STATISTICS
diff --git a/services/audioflinger/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/FastMixer.cpp b/services/audioflinger/FastMixer.cpp
index ad35264..a42d6b3 100644
--- a/services/audioflinger/FastMixer.cpp
+++ b/services/audioflinger/FastMixer.cpp
@@ -32,7 +32,7 @@
#include <utils/Trace.h>
#include <system/audio.h>
#ifdef FAST_THREAD_STATISTICS
-#include <cpustats/CentralTendencyStatistics.h>
+#include <audio_utils/Statistics.h>
#ifdef CPU_FREQUENCY_STATISTICS
#include <cpustats/ThreadCpuUsage.h>
#endif
diff --git a/services/audioflinger/FastMixerDumpState.cpp b/services/audioflinger/FastMixerDumpState.cpp
index c0f9f0f..2abfbfb 100644
--- a/services/audioflinger/FastMixerDumpState.cpp
+++ b/services/audioflinger/FastMixerDumpState.cpp
@@ -19,11 +19,12 @@
#include "Configuration.h"
#ifdef FAST_THREAD_STATISTICS
-#include <cpustats/CentralTendencyStatistics.h>
+#include <audio_utils/Statistics.h>
#ifdef CPU_FREQUENCY_STATISTICS
#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
- CentralTendencyStatistics wall, loadNs;
+ audio_utils::Statistics<double> wall, loadNs;
#ifdef CPU_FREQUENCY_STATISTICS
- CentralTendencyStatistics 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
@@ -109,18 +110,18 @@
if (tail != NULL) {
tail[j] = wallNs;
}
- wall.sample(wallNs);
+ wall.add(wallNs);
uint32_t sampleLoadNs = mLoadNs[i];
- loadNs.sample(sampleLoadNs);
+ loadNs.add(sampleLoadNs);
#ifdef CPU_FREQUENCY_STATISTICS
uint32_t sampleCpukHz = mCpukHz[i];
// skip bad kHz samples
if ((sampleCpukHz & ~0xF) != 0) {
- kHz.sample(sampleCpukHz >> 4);
+ kHz.add(sampleCpukHz >> 4);
if (sampleCpukHz == previousCpukHz) {
double megacycles = (double) sampleLoadNs * (double) (sampleCpukHz >> 4) * 1e-12;
double adjMHz = megacycles / mixPeriodSec; // _not_ wallNs * 1e9
- loadMHz.sample(adjMHz);
+ loadMHz.add(adjMHz);
}
}
previousCpukHz = sampleCpukHz;
@@ -128,42 +129,42 @@
}
if (n) {
dprintf(fd, " Simple moving statistics over last %.1f seconds:\n",
- wall.n() * mixPeriodSec);
+ wall.getN() * mixPeriodSec);
dprintf(fd, " wall clock time in ms per mix cycle:\n"
" mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
- wall.mean()*1e-6, wall.minimum()*1e-6, wall.maximum()*1e-6,
- wall.stddev()*1e-6);
+ wall.getMean()*1e-6, wall.getMin()*1e-6, wall.getMax()*1e-6,
+ wall.getStdDev()*1e-6);
dprintf(fd, " raw CPU load in us per mix cycle:\n"
" mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
- loadNs.mean()*1e-3, loadNs.minimum()*1e-3, loadNs.maximum()*1e-3,
- loadNs.stddev()*1e-3);
+ loadNs.getMean()*1e-3, loadNs.getMin()*1e-3, loadNs.getMax()*1e-3,
+ loadNs.getStdDev()*1e-3);
} else {
dprintf(fd, " No FastMixer statistics available currently\n");
}
#ifdef CPU_FREQUENCY_STATISTICS
dprintf(fd, " CPU clock frequency in MHz:\n"
" mean=%.0f min=%.0f max=%.0f stddev=%.0f\n",
- kHz.mean()*1e-3, kHz.minimum()*1e-3, kHz.maximum()*1e-3, kHz.stddev()*1e-3);
+ kHz.getMean()*1e-3, kHz.getMin()*1e-3, kHz.getMax()*1e-3, kHz.getStdDev()*1e-3);
dprintf(fd, " adjusted CPU load in MHz (i.e. normalized for CPU clock frequency):\n"
" mean=%.1f min=%.1f max=%.1f stddev=%.1f\n",
- loadMHz.mean(), loadMHz.minimum(), loadMHz.maximum(), loadMHz.stddev());
+ loadMHz.getMean(), loadMHz.getMin(), loadMHz.getMax(), loadMHz.getStdDev());
#endif
if (tail != NULL) {
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;
- CentralTendencyStatistics left, right;
+ audio_utils::Statistics<double> left, right;
for (uint32_t i = 0; i < count; ++i) {
- left.sample(tail[i]);
- right.sample(tail[n - (i + 1)]);
+ left.add(tail[i]);
+ right.add(tail[n - (i + 1)]);
}
dprintf(fd, " Distribution of mix cycle times in ms for the tails "
"(> ~3 stddev outliers):\n"
" left tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n"
" right tail: mean=%.2f min=%.2f max=%.2f stddev=%.2f\n",
- left.mean()*1e-6, left.minimum()*1e-6, left.maximum()*1e-6, left.stddev()*1e-6,
- right.mean()*1e-6, right.minimum()*1e-6, right.maximum()*1e-6,
- right.stddev()*1e-6);
+ left.getMean()*1e-6, left.getMin()*1e-6, left.getMax()*1e-6, left.getStdDev()*1e-6,
+ right.getMean()*1e-6, right.getMin()*1e-6, right.getMax()*1e-6,
+ right.getStdDev()*1e-6);
delete[] tail;
}
#endif
@@ -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..7b165a1 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(
@@ -531,14 +547,46 @@
// reverse due to internal biases).
//
// TODO: is this stable enough? Consider a PatchTrack synchronized version of this.
- double recordServerLatencyMs;
- if (recordTrack->getServerLatencyMs(&recordServerLatencyMs) != OK) return INVALID_OPERATION;
- double playbackTrackLatencyMs;
- if (playbackTrack->getTrackLatencyMs(&playbackTrackLatencyMs) != OK) return INVALID_OPERATION;
+ // For PCM tracks get server latency.
+ if (audio_is_linear_pcm(recordTrack->format())) {
+ double recordServerLatencyMs, playbackTrackLatencyMs;
+ if (recordTrack->getServerLatencyMs(&recordServerLatencyMs) == OK
+ && playbackTrack->getTrackLatencyMs(&playbackTrackLatencyMs) == OK) {
+ *latencyMs = recordServerLatencyMs + playbackTrackLatencyMs;
+ return OK;
+ }
+ }
- *latencyMs = recordServerLatencyMs + playbackTrackLatencyMs;
- return OK;
+ // See if kernel latencies are available.
+ // If so, do a frame diff and time difference computation to estimate
+ // the total patch latency. This requires that frame counts are reported by the
+ // HAL are matched properly in the case of record overruns and playback underruns.
+ ThreadBase::TrackBase::FrameTime recordFT{}, playFT{};
+ recordTrack->getKernelFrameTime(&recordFT);
+ playbackTrack->getKernelFrameTime(&playFT);
+ if (recordFT.timeNs > 0 && playFT.timeNs > 0) {
+ const int64_t frameDiff = recordFT.frames - playFT.frames;
+ const int64_t timeDiffNs = recordFT.timeNs - playFT.timeNs;
+
+ // It is possible that the patch track and patch record have a large time disparity because
+ // one thread runs but another is stopped. We arbitrarily choose the maximum timestamp
+ // time difference based on how often we expect the timestamps to update in normal operation
+ // (typical should be no more than 50 ms).
+ //
+ // If the timestamps aren't sampled close enough, the patch latency is not
+ // considered valid.
+ //
+ // TODO: change this based on more experiments.
+ constexpr int64_t maxValidTimeDiffNs = 200 * NANOS_PER_MILLISECOND;
+ if (std::abs(timeDiffNs) < maxValidTimeDiffNs) {
+ *latencyMs = frameDiff * 1e3 / recordTrack->sampleRate()
+ - timeDiffNs * 1e-6;
+ return OK;
+ }
+ }
+
+ return INVALID_OPERATION;
}
String8 AudioFlinger::PatchPanel::Patch::dump(audio_patch_handle_t myHandle) const
diff --git a/services/audioflinger/PatchPanel.h b/services/audioflinger/PatchPanel.h
index 269a398..2d9bd8e 100644
--- a/services/audioflinger/PatchPanel.h
+++ b/services/audioflinger/PatchPanel.h
@@ -35,6 +35,7 @@
// Must be called under AudioFlinger::mLock
status_t getLatencyMs_l(double *latencyMs) const;
+ audio_patch_handle_t getPatchHandle() const { return mPatchHandle; };
audio_io_handle_t getPlaybackThreadHandle() const { return mPlaybackThreadHandle; };
audio_io_handle_t getRecordThreadHandle() const { return mRecordThreadHandle; };
private:
diff --git a/services/audioflinger/Threads.cpp b/services/audioflinger/Threads.cpp
index d55da1b..c73a446 100644
--- a/services/audioflinger/Threads.cpp
+++ b/services/audioflinger/Threads.cpp
@@ -42,6 +42,7 @@
#include <audio_utils/primitives.h>
#include <audio_utils/format.h>
#include <audio_utils/minifloat.h>
+#include <json/json.h>
#include <system/audio_effects/effect_ns.h>
#include <system/audio_effects/effect_aec.h>
#include <system/audio.h>
@@ -73,7 +74,7 @@
#endif
#ifdef DEBUG_CPU_USAGE
-#include <cpustats/CentralTendencyStatistics.h>
+#include <audio_utils/Statistics.h>
#include <cpustats/ThreadCpuUsage.h>
#endif
@@ -335,9 +336,9 @@
#ifdef DEBUG_CPU_USAGE
private:
ThreadCpuUsage mCpuUsage; // instantaneous thread CPU usage in wall clock ns
- CentralTendencyStatistics mWcStats; // statistics on thread CPU usage in wall clock ns
+ audio_utils::Statistics<double> mWcStats; // statistics on thread CPU usage in wall clock ns
- CentralTendencyStatistics 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
@@ -363,7 +364,7 @@
// record sample for wall clock statistics
if (valid) {
- mWcStats.sample(wcNs);
+ mWcStats.add(wcNs);
}
// get the current CPU number
@@ -382,26 +383,26 @@
// if no change in CPU number or frequency, then record sample for cycle statistics
if (valid && mCpukHz > 0) {
- double cycles = wcNs * cpukHz * 0.000001;
- mHzStats.sample(cycles);
+ const double cycles = wcNs * cpukHz * 0.000001;
+ mHzStats.add(cycles);
}
- unsigned n = mWcStats.n();
+ const unsigned n = mWcStats.getN();
// mCpuUsage.elapsed() is expensive, so don't call it every loop
if ((n & 127) == 1) {
- long long elapsed = mCpuUsage.elapsed();
+ const long long elapsed = mCpuUsage.elapsed();
if (elapsed >= DEBUG_CPU_USAGE * 1000000000LL) {
- double perLoop = elapsed / (double) n;
- double perLoop100 = perLoop * 0.01;
- double perLoop1k = perLoop * 0.001;
- double mean = mWcStats.mean();
- double stddev = mWcStats.stddev();
- double minimum = mWcStats.minimum();
- double maximum = mWcStats.maximum();
- double meanCycles = mHzStats.mean();
- double stddevCycles = mHzStats.stddev();
- double minCycles = mHzStats.minimum();
- double maxCycles = mHzStats.maximum();
+ const double perLoop = elapsed / (double) n;
+ const double perLoop100 = perLoop * 0.01;
+ const double perLoop1k = perLoop * 0.001;
+ const double mean = mWcStats.getMean();
+ const double stddev = mWcStats.getStdDev();
+ const double minimum = mWcStats.getMin();
+ const double maximum = mWcStats.getMax();
+ const double meanCycles = mHzStats.getMean();
+ const double stddevCycles = mHzStats.getStdDev();
+ const double minCycles = mHzStats.getMin();
+ const double maxCycles = mHzStats.getMax();
mCpuUsage.resetElapsed();
mWcStats.reset();
mHzStats.reset();
@@ -862,6 +863,7 @@
|| mType == DIRECT
|| mType == OFFLOAD) {
dprintf(fd, " Timestamp stats: %s\n", mTimestampVerifier.toString().c_str());
+ dprintf(fd, " Timestamp corrected: %s\n", isTimestampCorrectionEnabled() ? "yes" : "no");
}
if (locked) {
@@ -1731,10 +1733,21 @@
if (mOutput->audioHwDev->canSetMasterMute()) {
mMasterMute = false;
}
+ mIsMsdDevice = strcmp(
+ mOutput->audioHwDev->moduleName(), AUDIO_HARDWARE_MODULE_ID_MSD) == 0;
}
readOutputParameters_l();
+ // TODO: We may also match on address as well as device type for
+ // AUDIO_DEVICE_OUT_BUS, AUDIO_DEVICE_OUT_ALL_A2DP, AUDIO_DEVICE_OUT_REMOTE_SUBMIX
+ if (type == MIXER || type == DIRECT) {
+ mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
+ "audio.timestamp.corrected_output_devices",
+ (int64_t)(mIsMsdDevice ? AUDIO_DEVICE_OUT_BUS // turn on by default for MSD
+ : AUDIO_DEVICE_NONE));
+ }
+
// ++ operator does not compile
for (audio_stream_type_t stream = AUDIO_STREAM_MIN; stream < AUDIO_STREAM_FOR_POLICY_CNT;
stream = (audio_stream_type_t) (stream + 1)) {
@@ -1763,9 +1776,9 @@
mLocalLog.dump(fd, " " /* prefix */, 40 /* lines */);
}
-std::string AudioFlinger::PlaybackThread::getJsonString() const
+Json::Value AudioFlinger::PlaybackThread::getJsonDump() const
{
- return "{}";
+ return Json::Value(Json::objectValue);
}
void AudioFlinger::PlaybackThread::dumpTracks(int fd, const Vector<String16>& args __unused)
@@ -3207,6 +3220,8 @@
if (mType == OFFLOAD || mType == DIRECT) {
mTimestampVerifier.setDiscontinuityMode(mTimestampVerifier.DISCONTINUITY_MODE_ZERO);
}
+ audio_utils::Statistics<double> downstreamLatencyStatMs(0.999 /* alpha */);
+ audio_patch_handle_t lastDownstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
while (!exitPending())
{
@@ -3218,6 +3233,46 @@
Vector< sp<EffectChain> > effectChains;
+ // If the device is AUDIO_DEVICE_OUT_BUS, check for downstream latency.
+ //
+ // Note: we access outDevice() outside of mLock.
+ if (isMsdDevice() && (outDevice() & AUDIO_DEVICE_OUT_BUS) != 0) {
+ // Here, we try for the AF lock, but do not block on it as the latency
+ // is more informational.
+ if (mAudioFlinger->mLock.tryLock() == NO_ERROR) {
+ std::vector<PatchPanel::SoftwarePatch> swPatches;
+ double latencyMs;
+ status_t status = INVALID_OPERATION;
+ audio_patch_handle_t downstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ if (mAudioFlinger->mPatchPanel.getDownstreamSoftwarePatches(id(), &swPatches) == OK
+ && swPatches.size() > 0) {
+ status = swPatches[0].getLatencyMs_l(&latencyMs);
+ downstreamPatchHandle = swPatches[0].getPatchHandle();
+ }
+ if (downstreamPatchHandle != lastDownstreamPatchHandle) {
+ downstreamLatencyStatMs.reset();
+ lastDownstreamPatchHandle = downstreamPatchHandle;
+ }
+ if (status == OK) {
+ // verify downstream latency (we assume a max reasonable
+ // latency of 1 second).
+ if (latencyMs >= 0. && latencyMs <= 1000.) {
+ ALOGV("new downstream latency %lf ms", latencyMs);
+ downstreamLatencyStatMs.add(latencyMs);
+ } else {
+ ALOGD("out of range downstream latency %lf ms", latencyMs);
+ }
+ }
+ mAudioFlinger->mLock.unlock();
+ }
+ } else {
+ if (lastDownstreamPatchHandle != AUDIO_PATCH_HANDLE_NONE) {
+ // our device is no longer AUDIO_DEVICE_OUT_BUS, reset patch handle and stats.
+ downstreamLatencyStatMs.reset();
+ lastDownstreamPatchHandle = AUDIO_PATCH_HANDLE_NONE;
+ }
+ }
+
{ // scope for mLock
Mutex::Autolock _l(mLock);
@@ -3247,6 +3302,33 @@
mTimestampVerifier.add(timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
mSampleRate);
+
+ if (isTimestampCorrectionEnabled()) {
+ ALOGV("TS_BEFORE: %d %lld %lld", id(),
+ (long long)timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
+ (long long)timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]);
+ auto correctedTimestamp = mTimestampVerifier.getLastCorrectedTimestamp();
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+ = correctedTimestamp.mFrames;
+ timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]
+ = correctedTimestamp.mTimeNs;
+ ALOGV("TS_AFTER: %d %lld %lld", id(),
+ (long long)timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
+ (long long)timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]);
+
+ // Note: Downstream latency only added if timestamp correction enabled.
+ if (downstreamLatencyStatMs.getN() > 0) { // we have latency info.
+ const int64_t newPosition =
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+ - int64_t(downstreamLatencyStatMs.getMean() * mSampleRate * 1e-3);
+ // prevent retrograde
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = max(
+ newPosition,
+ (mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL]
+ - mSuspendedFrames));
+ }
+ }
+
// We always fetch the timestamp here because often the downstream
// sink will block while writing.
@@ -5141,14 +5223,20 @@
}
}
-std::string AudioFlinger::MixerThread::getJsonString() const
+Json::Value AudioFlinger::MixerThread::getJsonDump() const
{
- // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
- // while we are dumping it. It may be inconsistent, but it won't mutate!
- // This is a large object so we place it on the heap.
- // FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
- return std::unique_ptr<FastMixerDumpState>(new FastMixerDumpState(mFastMixerDumpState))
- ->getJsonString();
+ Json::Value root;
+ if (hasFastMixer()) {
+ // Make a non-atomic copy of fast mixer dump state so it won't change underneath us
+ // while we are dumping it. It may be inconsistent, but it won't mutate!
+ // This is a large object so we place it on the heap.
+ // FIXME 25972958: Need an intelligent copy constructor that does not touch unused pages.
+ const std::unique_ptr<FastMixerDumpState> copy(new FastMixerDumpState(mFastMixerDumpState));
+ root["fastmixer_stats"] = copy->getJsonDump();
+ } else {
+ root["fastmixer_stats"] = "no_fastmixer";
+ }
+ return root;
}
uint32_t AudioFlinger::MixerThread::idleSleepTimeUs() const
@@ -6361,8 +6449,20 @@
snprintf(mThreadName, kThreadNameLength, "AudioIn_%X", id);
mNBLogWriter = audioFlinger->newWriter_l(kLogSize, mThreadName);
+ if (mInput != nullptr && mInput->audioHwDev != nullptr) {
+ mIsMsdDevice = strcmp(
+ mInput->audioHwDev->moduleName(), AUDIO_HARDWARE_MODULE_ID_MSD) == 0;
+ }
+
readInputParameters_l();
+ // TODO: We may also match on address as well as device type for
+ // AUDIO_DEVICE_IN_BUS, AUDIO_DEVICE_IN_BLUETOOTH_A2DP, AUDIO_DEVICE_IN_REMOTE_SUBMIX
+ mTimestampCorrectedDevices = (audio_devices_t)property_get_int64(
+ "audio.timestamp.corrected_input_devices",
+ (int64_t)(mIsMsdDevice ? AUDIO_DEVICE_IN_BUS // turn on by default for MSD
+ : AUDIO_DEVICE_NONE));
+
// create an NBAIO source for the HAL input stream, and negotiate
mInputSource = new AudioStreamInSource(input->stream);
size_t numCounterOffers = 0;
@@ -6700,6 +6800,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 +6833,7 @@
// If an NBAIO source is present, use it to read the normal capture's data
if (mPipeSource != 0) {
- size_t framesToRead = mBufferSize / mFrameSize;
- framesToRead = min(mRsmpInFramesOA - rear, mRsmpInFramesP2 / 2);
+ size_t framesToRead = min(mRsmpInFramesOA - rear, mRsmpInFramesP2 / 2);
// The audio fifo read() returns OVERRUN on overflow, and advances the read pointer
// to the full buffer point (clearing the overflow condition). Upon OVERRUN error,
@@ -6790,7 +6897,22 @@
int64_t position, time;
if (mStandby) {
mTimestampVerifier.discontinuity();
- } else if (mInput->stream->getCapturePosition(&position, &time) == NO_ERROR) {
+ } else if (mInput->stream->getCapturePosition(&position, &time) == NO_ERROR
+ && time > mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]) {
+
+ mTimestampVerifier.add(position, time, mSampleRate);
+
+ // Correct timestamps
+ if (isTimestampCorrectionEnabled()) {
+ ALOGV("TS_BEFORE: %d %lld %lld",
+ id(), (long long)time, (long long)position);
+ auto correctedTimestamp = mTimestampVerifier.getLastCorrectedTimestamp();
+ position = correctedTimestamp.mFrames;
+ time = correctedTimestamp.mTimeNs;
+ ALOGV("TS_AFTER: %d %lld %lld",
+ id(), (long long)time, (long long)position);
+ }
+
mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL] = position;
mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL] = time;
// Note: In general record buffers should tend to be empty in
@@ -6798,10 +6920,6 @@
//
// Also, it is not advantageous to call get_presentation_position during the read
// as the read obtains a lock, preventing the timestamp call from executing.
-
- mTimestampVerifier.add(mTimestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
- mTimestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL],
- mSampleRate);
} else {
mTimestampVerifier.error();
}
@@ -6819,6 +6937,7 @@
goto unlock;
}
ALOG_ASSERT(framesRead > 0);
+ mFramesRead += framesRead;
#ifdef TEE_SINK
(void)mTee.write((uint8_t*)mRsmpInBuffer + rear * mFrameSize, framesRead);
@@ -7443,6 +7562,7 @@
audio_input_flags_t flags = input != NULL ? input->flags : AUDIO_INPUT_FLAG_NONE;
dprintf(fd, " AudioStreamIn: %p flags %#x (%s)\n",
input, flags, inputFlagsToString(flags).c_str());
+ dprintf(fd, " Frames read: %lld\n", (long long)mFramesRead);
if (mActiveTracks.isEmpty()) {
dprintf(fd, " No active record clients\n");
}
@@ -7452,7 +7572,8 @@
(void)input->stream->dump(fd);
}
- const double latencyMs = - mTimestamp.getOutputServerLatencyMs(mSampleRate);
+ const double latencyMs = audio_is_linear_pcm(mFormat)
+ ? - mTimestamp.getOutputServerLatencyMs(mSampleRate) : 0.;
if (latencyMs != 0.) {
dprintf(fd, " NormalRecord latency ms: %.2lf\n", latencyMs);
} else {
diff --git a/services/audioflinger/Threads.h b/services/audioflinger/Threads.h
index dc23717..37b3870 100644
--- a/services/audioflinger/Threads.h
+++ b/services/audioflinger/Threads.h
@@ -393,6 +393,10 @@
void broadcast_l();
+ virtual bool isTimestampCorrectionEnabled() const { return false; }
+
+ bool isMsdDevice() const { return mIsMsdDevice; }
+
mutable Mutex mLock;
protected:
@@ -501,7 +505,8 @@
ExtendedTimestamp mTimestamp;
TimestampVerifier< // For timestamp statistics.
int64_t /* frame count */, int64_t /* time ns */> mTimestampVerifier;
-
+ audio_devices_t mTimestampCorrectedDevices = AUDIO_DEVICE_NONE;
+ bool mIsMsdDevice = false;
// A condition that must be evaluated by the thread loop has changed and
// we must not wait for async write callback in the thread loop before evaluating it
bool mSignalPending;
@@ -662,7 +667,7 @@
void dump(int fd, const Vector<String16>& args);
// returns a string of audio performance related data in JSON format.
- virtual std::string getJsonString() const;
+ virtual Json::Value getJsonDump() const;
// Thread virtuals
virtual bool threadLoop();
@@ -816,6 +821,11 @@
&& mTracks.size() < PlaybackThread::kMaxTracks;
}
+ bool isTimestampCorrectionEnabled() const override {
+ const audio_devices_t device =
+ mOutDevice & mTimestampCorrectedDevices;
+ return audio_is_output_devices(device) && popcount(device) > 0;
+ }
protected:
// updated by readOutputParameters_l()
size_t mNormalFrameCount; // normal mixer and effects
@@ -1108,7 +1118,7 @@
virtual bool checkForNewParameter_l(const String8& keyValuePair,
status_t& status);
virtual void dumpInternals(int fd, const Vector<String16>& args);
- std::string getJsonString() const override;
+ Json::Value getJsonDump() const override;
virtual bool isTrackAllowed_l(
audio_channel_mask_t channelMask, audio_format_t format,
@@ -1530,6 +1540,13 @@
void updateMetadata_l() override;
+ bool fastTrackAvailable() const { return mFastTrackAvail; }
+
+ bool isTimestampCorrectionEnabled() const override {
+ // checks popcount for exactly one device.
+ return audio_is_input_device(
+ mInDevice & mTimestampCorrectedDevices);
+ }
private:
// Enter standby if not already in standby, and set mStandby flag
void standbyIfNotAlreadyInStandby();
@@ -1599,6 +1616,8 @@
bool mFastTrackAvail; // true if fast track available
// common state to all record threads
std::atomic_bool mBtNrecSuspended;
+
+ int64_t mFramesRead = 0; // continuous running counter.
};
class MmapThread : public ThreadBase
diff --git a/services/audioflinger/TrackBase.h b/services/audioflinger/TrackBase.h
index 95da9d7..a43cb75 100644
--- a/services/audioflinger/TrackBase.h
+++ b/services/audioflinger/TrackBase.h
@@ -187,6 +187,19 @@
return status;
}
+ // TODO: Consider making this external.
+ struct FrameTime {
+ int64_t frames;
+ int64_t timeNs;
+ };
+
+ // KernelFrameTime is updated per "mix" period even for non-pcm tracks.
+ void getKernelFrameTime(FrameTime *ft) const {
+ *ft = mKernelFrameTime.load();
+ }
+
+ audio_format_t format() const { return mFormat; }
+
protected:
DISALLOW_COPY_AND_ASSIGN(TrackBase);
@@ -198,8 +211,6 @@
// but putting it in TrackBase avoids the complexity of virtual inheritance
virtual size_t framesReady() const { return SIZE_MAX; }
- audio_format_t format() const { return mFormat; }
-
uint32_t channelCount() const { return mChannelCount; }
audio_channel_mask_t channelMask() const { return mChannelMask; }
@@ -307,6 +318,7 @@
bool mServerLatencySupported = false;
std::atomic<bool> mServerLatencyFromTrack{}; // latency from track or server timestamp.
std::atomic<double> mServerLatencyMs{}; // last latency pushed from server thread.
+ std::atomic<FrameTime> mKernelFrameTime{}; // last frame time on kernel side.
};
// PatchProxyBufferProvider interface is implemented by PatchTrack and PatchRecord.
diff --git a/services/audioflinger/Tracks.cpp b/services/audioflinger/Tracks.cpp
index 8b9485f..78e6c6c 100644
--- a/services/audioflinger/Tracks.cpp
+++ b/services/audioflinger/Tracks.cpp
@@ -1258,6 +1258,16 @@
void AudioFlinger::PlaybackThread::Track::updateTrackFrameInfo(
int64_t trackFramesReleased, int64_t sinkFramesWritten,
uint32_t halSampleRate, const ExtendedTimestamp &timeStamp) {
+ // Make the kernel frametime available.
+ const FrameTime ft{
+ timeStamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
+ timeStamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]};
+ // ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
+ mKernelFrameTime.store(ft);
+ if (!audio_is_linear_pcm(mFormat)) {
+ return;
+ }
+
//update frame map
mFrameMap.push(trackFramesReleased, sinkFramesWritten);
@@ -1720,7 +1730,7 @@
thread->mFastTrackAvail = false;
} else {
// TODO: only Normal Record has timestamps (Fast Record does not).
- mServerLatencySupported = true;
+ mServerLatencySupported = audio_is_linear_pcm(mFormat);
}
#ifdef TEE_SINK
mTee.setId(std::string("_") + std::to_string(mThreadIoHandle)
@@ -1886,6 +1896,16 @@
int64_t trackFramesReleased, int64_t sourceFramesRead,
uint32_t halSampleRate, const ExtendedTimestamp ×tamp)
{
+ // Make the kernel frametime available.
+ const FrameTime ft{
+ timestamp.mPosition[ExtendedTimestamp::LOCATION_KERNEL],
+ timestamp.mTimeNs[ExtendedTimestamp::LOCATION_KERNEL]};
+ // ALOGD("FrameTime: %lld %lld", (long long)ft.frames, (long long)ft.timeNs);
+ mKernelFrameTime.store(ft);
+ if (!audio_is_linear_pcm(mFormat)) {
+ return;
+ }
+
ExtendedTimestamp local = timestamp;
// Convert HAL frames to server-side track frames at track sample rate.
diff --git a/services/audiopolicy/AudioPolicyInterface.h b/services/audiopolicy/AudioPolicyInterface.h
index fe49483..d4c49d9 100644
--- a/services/audiopolicy/AudioPolicyInterface.h
+++ b/services/audiopolicy/AudioPolicyInterface.h
@@ -124,17 +124,11 @@
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId) = 0;
// indicates to the audio policy manager that the output starts being used by corresponding stream.
- virtual status_t startOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session) = 0;
+ virtual status_t startOutput(audio_port_handle_t portId) = 0;
// indicates to the audio policy manager that the output stops being used by corresponding stream.
- virtual status_t stopOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session) = 0;
+ virtual status_t stopOutput(audio_port_handle_t portId) = 0;
// releases the output.
- virtual void releaseOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session) = 0;
+ virtual void releaseOutput(audio_port_handle_t portId) = 0;
// request an input appropriate for record from the supplied device with supplied parameters.
virtual status_t getInputForAttr(const audio_attributes_t *attr,
@@ -147,16 +141,13 @@
input_type_t *inputType,
audio_port_handle_t *portId) = 0;
// indicates to the audio policy manager that the input starts being used.
- virtual status_t startInput(audio_io_handle_t input,
- audio_session_t session,
+ virtual status_t startInput(audio_port_handle_t portId,
bool silenced,
concurrency_type__mask_t *concurrency) = 0;
// indicates to the audio policy manager that the input stops being used.
- virtual status_t stopInput(audio_io_handle_t input,
- audio_session_t session) = 0;
+ virtual status_t stopInput(audio_port_handle_t portId) = 0;
// releases the input.
- virtual void releaseInput(audio_io_handle_t input,
- audio_session_t session) = 0;
+ virtual void releaseInput(audio_port_handle_t portId) = 0;
//
// volume control functions
@@ -235,9 +226,9 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_patch_handle_t *handle,
+ audio_port_handle_t *portId,
uid_t uid) = 0;
- virtual status_t stopAudioSource(audio_patch_handle_t handle) = 0;
+ virtual status_t stopAudioSource(audio_port_handle_t portId) = 0;
virtual status_t setMasterMono(bool mono) = 0;
virtual status_t getMasterMono(bool *mono) = 0;
diff --git a/services/audiopolicy/common/managerdefinitions/Android.mk b/services/audiopolicy/common/managerdefinitions/Android.mk
index 09dbb32..9b8f095 100644
--- a/services/audiopolicy/common/managerdefinitions/Android.mk
+++ b/services/audiopolicy/common/managerdefinitions/Android.mk
@@ -18,7 +18,6 @@
src/EffectDescriptor.cpp \
src/SoundTriggerSession.cpp \
src/SessionRoute.cpp \
- src/AudioSourceDescriptor.cpp \
src/VolumeCurve.cpp \
src/TypeConverter.cpp \
src/AudioSession.cpp \
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
index ca837c4..44662e5 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioInputDescriptor.h
@@ -19,6 +19,7 @@
#include "AudioIODescriptorInterface.h"
#include "AudioPort.h"
#include "AudioSession.h"
+#include "ClientDescriptor.h"
#include <utils/Errors.h>
#include <system/audio.h>
#include <utils/SortedVector.h>
@@ -88,7 +89,10 @@
void stop();
void close();
-private:
+ RecordClientMap& clients() { return mClients; }
+ RecordClientVector getClientsForSession(audio_session_t session);
+
+ private:
void updateSessionRecordingConfiguration(int event, const sp<AudioSession>& audioSession);
@@ -105,6 +109,8 @@
SortedVector<audio_session_t> mPreemptedSessions;
AudioPolicyClientInterface *mClientInterface;
uint32_t mGlobalRefCount; // non-session-specific ref count
+
+ RecordClientMap mClients;
};
class AudioInputCollection :
@@ -128,6 +134,8 @@
audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
+ sp<AudioInputDescriptor> getInputForClient(audio_port_handle_t portId);
+
status_t dump(int fd) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
index 292e59f..ff0201a 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioOutputDescriptor.h
@@ -17,14 +17,14 @@
#pragma once
#include <sys/types.h>
-#include "AudioPort.h"
-#include <RoutingStrategy.h>
#include <utils/Errors.h>
#include <utils/Timers.h>
#include <utils/KeyedVector.h>
#include <system/audio.h>
+#include <RoutingStrategy.h>
#include "AudioIODescriptorInterface.h"
-#include "AudioSourceDescriptor.h"
+#include "AudioPort.h"
+#include "ClientDescriptor.h"
namespace android {
@@ -78,7 +78,9 @@
audio_patch_handle_t getPatchHandle() const override;
void setPatchHandle(audio_patch_handle_t handle) override;
- sp<AudioPort> mPort;
+ TrackClientMap& clients() { return mClients; }
+
+ sp<AudioPort> mPort;
audio_devices_t mDevice; // current device this output is routed to
uint32_t mRefCount[AUDIO_STREAM_CNT]; // number of streams of each type using this output
nsecs_t mStopTime[AUDIO_STREAM_CNT];
@@ -91,6 +93,7 @@
protected:
audio_patch_handle_t mPatchHandle;
audio_port_handle_t mId;
+ TrackClientMap mClients;
};
// Audio output driven by a software mixer in audio flinger.
@@ -155,7 +158,7 @@
class HwAudioOutputDescriptor: public AudioOutputDescriptor
{
public:
- HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+ HwAudioOutputDescriptor(const sp<SourceClientDescriptor>& source,
AudioPolicyClientInterface *clientInterface);
virtual ~HwAudioOutputDescriptor() {}
@@ -172,7 +175,7 @@
const struct audio_port_config *srcConfig = NULL) const;
virtual void toAudioPort(struct audio_port *port) const;
- const sp<AudioSourceDescriptor> mSource;
+ const sp<SourceClientDescriptor> mSource;
};
@@ -226,6 +229,8 @@
audio_devices_t getSupportedDevices(audio_io_handle_t handle) const;
+ sp<SwAudioOutputDescriptor> getOutputForClient(audio_port_handle_t portId);
+
status_t dump(int fd) const;
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
index d2fc6a3..a1ee708 100644
--- a/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
+++ b/services/audiopolicy/common/managerdefinitions/include/AudioProfile.h
@@ -16,13 +16,14 @@
#pragma once
-#include "policy.h"
-#include <utils/String8.h>
-#include <utils/SortedVector.h>
-#include <utils/RefBase.h>
-#include <utils/Errors.h>
+#include <vector>
+
#include <system/audio.h>
-#include <cutils/config_utils.h>
+#include <utils/RefBase.h>
+#include <utils/SortedVector.h>
+#include <utils/String8.h>
+
+#include "policy.h"
namespace android {
@@ -69,71 +70,30 @@
public:
static sp<AudioProfile> createFullDynamic();
- AudioProfile(audio_format_t format,
- audio_channel_mask_t channelMasks,
- uint32_t samplingRate) :
- mName(String8("")),
- mFormat(format)
- {
- mChannelMasks.add(channelMasks);
- mSamplingRates.add(samplingRate);
- }
-
+ AudioProfile(audio_format_t format, audio_channel_mask_t channelMasks, uint32_t samplingRate);
AudioProfile(audio_format_t format,
const ChannelsVector &channelMasks,
- const SampleRateVector &samplingRateCollection) :
- mName(String8("")),
- mFormat(format),
- mChannelMasks(channelMasks),
- mSamplingRates(samplingRateCollection)
- {}
+ const SampleRateVector &samplingRateCollection);
audio_format_t getFormat() const { return mFormat; }
-
- void setChannels(const ChannelsVector &channelMasks)
- {
- if (mIsDynamicChannels) {
- mChannelMasks = channelMasks;
- }
- }
const ChannelsVector &getChannels() const { return mChannelMasks; }
-
- void setSampleRates(const SampleRateVector &sampleRates)
- {
- if (mIsDynamicRate) {
- mSamplingRates = sampleRates;
- }
- }
const SampleRateVector &getSampleRates() const { return mSamplingRates; }
+ void setChannels(const ChannelsVector &channelMasks);
+ void setSampleRates(const SampleRateVector &sampleRates);
+ void clear();
bool isValid() const { return hasValidFormat() && hasValidRates() && hasValidChannels(); }
-
- void clear()
- {
- if (mIsDynamicChannels) {
- mChannelMasks.clear();
- }
- if (mIsDynamicRate) {
- mSamplingRates.clear();
- }
- }
-
- inline bool supportsChannels(audio_channel_mask_t channels) const
+ bool supportsChannels(audio_channel_mask_t channels) const
{
return mChannelMasks.indexOf(channels) >= 0;
}
- inline bool supportsRate(uint32_t rate) const
- {
- return mSamplingRates.indexOf(rate) >= 0;
- }
+ bool supportsRate(uint32_t rate) const { return mSamplingRates.indexOf(rate) >= 0; }
status_t checkExact(uint32_t rate, audio_channel_mask_t channels, audio_format_t format) const;
-
status_t checkCompatibleChannelMask(audio_channel_mask_t channelMask,
audio_channel_mask_t &updatedChannelMask,
audio_port_type_t portType,
audio_port_role_t portRole) const;
-
status_t checkCompatibleSamplingRate(uint32_t samplingRate,
uint32_t &updatedSamplingRate) const;
@@ -169,223 +129,48 @@
class AudioProfileVector : public Vector<sp<AudioProfile> >
{
public:
- ssize_t add(const sp<AudioProfile> &profile)
- {
- ssize_t index = Vector::add(profile);
- // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
- // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
- // [](const audio_format_t *format1, const audio_format_t *format2) {
- // return compareFormats(*format1, *format2);
- // }
- sort(compareFormats);
- return index;
- }
-
+ ssize_t add(const sp<AudioProfile> &profile);
// This API is intended to be used by the policy manager once retrieving capabilities
// for a profile with dynamic format, rate and channels attributes
- ssize_t addProfileFromHal(const sp<AudioProfile> &profileToAdd)
- {
- // Check valid profile to add:
- if (!profileToAdd->hasValidFormat()) {
- return -1;
- }
- if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
- FormatVector formats;
- formats.add(profileToAdd->getFormat());
- setFormats(FormatVector(formats));
- return 0;
- }
- if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
- setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
- return 0;
- }
- if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
- setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
- return 0;
- }
- // Go through the list of profile to avoid duplicates
- for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
- const sp<AudioProfile> &profile = itemAt(profileIndex);
- if (profile->isValid() && profile == profileToAdd) {
- // Nothing to do
- return profileIndex;
- }
- }
- profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
- return add(profileToAdd);
- }
-
- sp<AudioProfile> getFirstValidProfile() const
- {
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->isValid()) {
- return itemAt(i);
- }
- }
- return 0;
- }
-
- sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const
- {
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->isValid() && itemAt(i)->getFormat() == format) {
- return itemAt(i);
- }
- }
- return 0;
- }
-
- bool hasValidProfile() const { return getFirstValidProfile() != 0; }
+ ssize_t addProfileFromHal(const sp<AudioProfile> &profileToAdd);
status_t checkExactProfile(uint32_t samplingRate, audio_channel_mask_t channelMask,
audio_format_t format) const;
-
status_t checkCompatibleProfile(uint32_t &samplingRate, audio_channel_mask_t &channelMask,
audio_format_t &format,
audio_port_type_t portType,
audio_port_role_t portRole) const;
+ void clearProfiles();
+ // Assuming that this profile vector contains input profiles,
+ // find the best matching config from 'outputProfiles', according to
+ // the given preferences for audio formats and channel masks.
+ // Note: std::vectors are used because specialized containers for formats
+ // and channels can be sorted and use their own ordering.
+ status_t findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
+ const std::vector<audio_format_t>& preferredFormats, // order: most pref -> least pref
+ const std::vector<audio_channel_mask_t>& preferredOutputChannels,
+ bool preferHigherSamplingRates,
+ audio_config_base *bestOutputConfig) const;
- FormatVector getSupportedFormats() const
- {
- FormatVector supportedFormats;
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->hasValidFormat()) {
- supportedFormats.add(itemAt(i)->getFormat());
- }
- }
- return supportedFormats;
- }
+ sp<AudioProfile> getFirstValidProfile() const;
+ sp<AudioProfile> getFirstValidProfileFor(audio_format_t format) const;
+ bool hasValidProfile() const { return getFirstValidProfile() != 0; }
- bool hasDynamicProfile() const
- {
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->isDynamic()) {
- return true;
- }
- }
- return false;
- }
-
- bool hasDynamicFormat() const
- {
- return getProfileFor(gDynamicFormat) != 0;
- }
-
- bool hasDynamicChannelsFor(audio_format_t format) const
- {
- for (size_t i = 0; i < size(); i++) {
- sp<AudioProfile> profile = itemAt(i);
- if (profile->getFormat() == format && profile->isDynamicChannels()) {
- return true;
- }
- }
- return false;
- }
-
- bool hasDynamicRateFor(audio_format_t format) const
- {
- for (size_t i = 0; i < size(); i++) {
- sp<AudioProfile> profile = itemAt(i);
- if (profile->getFormat() == format && profile->isDynamicRate()) {
- return true;
- }
- }
- return false;
- }
+ FormatVector getSupportedFormats() const;
+ bool hasDynamicChannelsFor(audio_format_t format) const;
+ bool hasDynamicFormat() const { return getProfileFor(gDynamicFormat) != 0; }
+ bool hasDynamicProfile() const;
+ bool hasDynamicRateFor(audio_format_t format) const;
// One audio profile will be added for each format supported by Audio HAL
- void setFormats(const FormatVector &formats)
- {
- // Only allow to change the format of dynamic profile
- sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
- if (dynamicFormatProfile == 0) {
- return;
- }
- for (size_t i = 0; i < formats.size(); i++) {
- sp<AudioProfile> profile = new AudioProfile(formats[i],
- dynamicFormatProfile->getChannels(),
- dynamicFormatProfile->getSampleRates());
- profile->setDynamicFormat(true);
- profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
- profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
- add(profile);
- }
- }
+ void setFormats(const FormatVector &formats);
- void clearProfiles()
- {
- for (size_t i = size(); i != 0; ) {
- sp<AudioProfile> profile = itemAt(--i);
- if (profile->isDynamicFormat() && profile->hasValidFormat()) {
- removeAt(i);
- continue;
- }
- profile->clear();
- }
- }
-
- void dump(int fd, int spaces) const
- {
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "%*s- Profiles:\n", spaces, "");
- write(fd, buffer, strlen(buffer));
- for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "%*sProfile %zu:", spaces + 4, "", i);
- write(fd, buffer, strlen(buffer));
- itemAt(i)->dump(fd, spaces + 8);
- }
- }
+ void dump(int fd, int spaces) const;
private:
- void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format)
- {
- for (size_t i = 0; i < size(); i++) {
- sp<AudioProfile> profile = itemAt(i);
- if (profile->getFormat() == format && profile->isDynamicRate()) {
- if (profile->hasValidRates()) {
- // Need to create a new profile with same format
- sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
- sampleRates);
- profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
- add(profileToAdd);
- } else {
- profile->setSampleRates(sampleRates);
- }
- return;
- }
- }
- }
-
- void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
- {
- for (size_t i = 0; i < size(); i++) {
- sp<AudioProfile> profile = itemAt(i);
- if (profile->getFormat() == format && profile->isDynamicChannels()) {
- if (profile->hasValidChannels()) {
- // Need to create a new profile with same format
- sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
- profile->getSampleRates());
- profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
- add(profileToAdd);
- } else {
- profile->setChannels(channelMasks);
- }
- return;
- }
- }
- }
-
- sp<AudioProfile> getProfileFor(audio_format_t format) const
- {
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->getFormat() == format) {
- return itemAt(i);
- }
- }
- return 0;
- }
+ sp<AudioProfile> getProfileFor(audio_format_t format) const;
+ void setSampleRatesFor(const SampleRateVector &sampleRates, audio_format_t format);
+ void setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format);
static int compareFormats(const sp<AudioProfile> *profile1, const sp<AudioProfile> *profile2);
};
diff --git a/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
deleted file mode 100644
index 0d90f42..0000000
--- a/services/audiopolicy/common/managerdefinitions/include/AudioSourceDescriptor.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#pragma once
-
-#include <system/audio.h>
-#include <utils/Errors.h>
-#include <utils/KeyedVector.h>
-#include <utils/RefBase.h>
-#include <RoutingStrategy.h>
-#include <AudioPatch.h>
-
-namespace android {
-
-class SwAudioOutputDescriptor;
-class HwAudioOutputDescriptor;
-class DeviceDescriptor;
-
-class AudioSourceDescriptor: public RefBase
-{
-public:
- AudioSourceDescriptor(const sp<DeviceDescriptor> device, const audio_attributes_t *attributes,
- uid_t uid) :
- mDevice(device), mAttributes(*attributes), mUid(uid) {}
- virtual ~AudioSourceDescriptor() {}
-
- audio_patch_handle_t getHandle() const { return mPatchDesc->mHandle; }
-
- status_t dump(int fd);
-
- const sp<DeviceDescriptor> mDevice;
- const audio_attributes_t mAttributes;
- uid_t mUid;
- sp<AudioPatch> mPatchDesc;
- wp<SwAudioOutputDescriptor> mSwOutput;
- wp<HwAudioOutputDescriptor> mHwOutput;
-};
-
-class AudioSourceCollection :
- public DefaultKeyedVector< audio_patch_handle_t, sp<AudioSourceDescriptor> >
-{
-public:
- status_t dump(int fd) const;
-};
-
-} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
index fb09932..9efe57f 100644
--- a/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/ClientDescriptor.h
@@ -16,15 +16,24 @@
#pragma once
+#include <vector>
+#include <map>
#include <unistd.h>
#include <sys/types.h>
#include <system/audio.h>
#include <utils/Errors.h>
+#include <utils/KeyedVector.h>
#include <utils/RefBase.h>
+#include <utils/String8.h>
+#include "AudioPatch.h"
namespace android {
+class DeviceDescriptor;
+class HwAudioOutputDescriptor;
+class SwAudioOutputDescriptor;
+
class ClientDescriptor: public RefBase
{
public:
@@ -35,7 +44,8 @@
mConfig(config), mPreferredDeviceId(preferredDeviceId), mActive(false) {}
~ClientDescriptor() override = default;
- virtual status_t dump(int fd);
+ status_t dump(int fd, int spaces, int index);
+ virtual status_t dump(String8& dst, int spaces, int index);
audio_port_handle_t portId() const { return mPortId; }
uid_t uid() const { return mUid; }
@@ -54,6 +64,10 @@
const audio_config_base_t mConfig;
const audio_port_handle_t mPreferredDeviceId; // selected input device port ID
bool mActive;
+
+protected:
+ // FIXME: use until other descriptor classes have a dump to String8 method
+ int mDumpFd;
};
class TrackClientDescriptor: public ClientDescriptor
@@ -67,7 +81,8 @@
mStream(stream), mFlags(flags) {}
~TrackClientDescriptor() override = default;
- status_t dump(int fd) override;
+ using ClientDescriptor::dump;
+ status_t dump(String8& dst, int spaces, int index) override;
audio_output_flags_t flags() const { return mFlags; }
audio_stream_type_t stream() const { return mStream; }
@@ -88,7 +103,8 @@
mSource(source), mFlags(flags) {}
~RecordClientDescriptor() override = default;
- status_t dump(int fd) override;
+ using ClientDescriptor::dump;
+ status_t dump(String8& dst, int spaces, int index) override;
audio_source_t source() const { return mSource; }
audio_input_flags_t flags() const { return mFlags; }
@@ -98,4 +114,41 @@
const audio_input_flags_t mFlags;
};
+class SourceClientDescriptor: public TrackClientDescriptor
+{
+public:
+ SourceClientDescriptor(audio_port_handle_t portId, uid_t uid, audio_attributes_t attributes,
+ const sp<AudioPatch>& patchDesc, const sp<DeviceDescriptor>& srcDevice,
+ audio_stream_type_t stream);
+ ~SourceClientDescriptor() override = default;
+
+ sp<AudioPatch> patchDesc() const { return mPatchDesc; }
+ sp<DeviceDescriptor> srcDevice() const { return mSrcDevice; };
+ wp<SwAudioOutputDescriptor> swOutput() const { return mSwOutput; }
+ void setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput);
+ wp<HwAudioOutputDescriptor> hwOutput() const { return mHwOutput; }
+ void setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput);
+
+ using ClientDescriptor::dump;
+ status_t dump(String8& dst, int spaces, int index) override;
+
+ private:
+ const sp<AudioPatch> mPatchDesc;
+ const sp<DeviceDescriptor> mSrcDevice;
+ wp<SwAudioOutputDescriptor> mSwOutput;
+ wp<HwAudioOutputDescriptor> mHwOutput;
+};
+
+class SourceClientCollection :
+ public DefaultKeyedVector< audio_port_handle_t, sp<SourceClientDescriptor> >
+{
+public:
+ status_t dump(int fd) const;
+};
+
+typedef std::vector< sp<TrackClientDescriptor> > TrackClientVector;
+typedef std::map< audio_port_handle_t, sp<TrackClientDescriptor> > TrackClientMap;
+typedef std::vector< sp<RecordClientDescriptor> > RecordClientVector;
+typedef std::map< audio_port_handle_t, sp<RecordClientDescriptor> > RecordClientMap;
+
} // namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
index 2325e4f..c08e752 100644
--- a/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
+++ b/services/audiopolicy/common/managerdefinitions/include/DeviceDescriptor.h
@@ -82,8 +82,8 @@
DeviceVector getDevicesFromTypeMask(audio_devices_t types) const;
sp<DeviceDescriptor> getDeviceFromId(audio_port_handle_t id) const;
sp<DeviceDescriptor> getDeviceFromTagName(const String8 &tagName) const;
-
- audio_devices_t getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
+ DeviceVector getDevicesFromHwModule(audio_module_handle_t moduleHandle) const;
+ audio_devices_t getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const;
status_t dump(int fd, const String8 &tag, int spaces = 0, bool verbose = true) const;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
index b9895a9..2770e74 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioInputDescriptor.cpp
@@ -340,6 +340,18 @@
&config, mPatchHandle);
}
+RecordClientVector AudioInputDescriptor::getClientsForSession(
+ audio_session_t session)
+{
+ RecordClientVector clients;
+ for (const auto &client : mClients) {
+ if (client.second->session() == session) {
+ clients.push_back(client.second);
+ }
+ }
+ return clients;
+}
+
status_t AudioInputDescriptor::dump(int fd)
{
const size_t SIZE = 256;
@@ -361,6 +373,13 @@
mSessions.dump(fd, 1);
+ size_t index = 0;
+ result = " AudioRecord clients:\n";
+ for (const auto& client: mClients) {
+ client.second->dump(result, 2, index++);
+ }
+ result.append(" \n");
+ write(fd, result.string(), result.size());
return NO_ERROR;
}
@@ -423,6 +442,19 @@
return devices;
}
+sp<AudioInputDescriptor> AudioInputCollection::getInputForClient(audio_port_handle_t portId)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioInputDescriptor> inputDesc = valueAt(i);
+ for (const auto& client : inputDesc->clients()) {
+ if (client.second->portId() == portId) {
+ return inputDesc;
+ }
+ }
+ }
+ return 0;
+}
+
status_t AudioInputCollection::dump(int fd) const
{
const size_t SIZE = 256;
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
index 3c69de5..39fce4d 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioOutputDescriptor.cpp
@@ -224,6 +224,13 @@
i, mCurVolume[i], mRefCount[i], mMuteCount[i]);
result.append(buffer);
}
+
+ result.append(" AudioTrack clients:\n");
+ size_t index = 0;
+ for (const auto& client : mClients) {
+ client.second->dump(result, 2, index++);
+ }
+ result.append(" \n");
write(fd, result.string(), result.size());
return NO_ERROR;
@@ -551,9 +558,9 @@
}
// HwAudioOutputDescriptor implementation
-HwAudioOutputDescriptor::HwAudioOutputDescriptor(const sp<AudioSourceDescriptor>& source,
+HwAudioOutputDescriptor::HwAudioOutputDescriptor(const sp<SourceClientDescriptor>& source,
AudioPolicyClientInterface *clientInterface)
- : AudioOutputDescriptor(source->mDevice, clientInterface),
+ : AudioOutputDescriptor(source->srcDevice(), clientInterface),
mSource(source)
{
}
@@ -569,7 +576,7 @@
snprintf(buffer, SIZE, "Source:\n");
result.append(buffer);
write(fd, result.string(), result.size());
- mSource->dump(fd);
+ mSource->dump(fd, 0, 0);
return NO_ERROR;
}
@@ -583,13 +590,13 @@
struct audio_port_config *dstConfig,
const struct audio_port_config *srcConfig) const
{
- mSource->mDevice->toAudioPortConfig(dstConfig, srcConfig);
+ mSource->srcDevice()->toAudioPortConfig(dstConfig, srcConfig);
}
void HwAudioOutputDescriptor::toAudioPort(
struct audio_port *port) const
{
- mSource->mDevice->toAudioPort(port);
+ mSource->srcDevice()->toAudioPort(port);
}
@@ -731,6 +738,18 @@
return devices;
}
+sp<SwAudioOutputDescriptor> SwAudioOutputCollection::getOutputForClient(audio_port_handle_t portId)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<SwAudioOutputDescriptor> outputDesc = valueAt(i);
+ for (const auto& client : outputDesc->clients()) {
+ if (client.second->portId() == portId) {
+ return outputDesc;
+ }
+ }
+ }
+ return 0;
+}
status_t SwAudioOutputCollection::dump(int fd) const
{
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
index e8fe5ff..d04beec 100644
--- a/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/AudioProfile.cpp
@@ -14,17 +14,21 @@
* limitations under the License.
*/
+#include <algorithm>
+#include <set>
+#include <string>
+
#define LOG_TAG "APM::AudioProfile"
//#define LOG_NDEBUG 0
-#include "AudioProfile.h"
-#include "AudioPort.h"
-#include "HwModule.h"
-#include "AudioGain.h"
-#include <utils/SortedVector.h>
-#include "TypeConverter.h"
#include <media/AudioResamplerPublic.h>
-#include <algorithm>
+#include <utils/Errors.h>
+
+#include "AudioGain.h"
+#include "AudioPort.h"
+#include "AudioProfile.h"
+#include "HwModule.h"
+#include "TypeConverter.h"
namespace android {
@@ -50,6 +54,13 @@
return outMaskVector;
}
+bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
+{
+ return (left.getFormat() == compareTo.getFormat()) &&
+ (left.getChannels() == compareTo.getChannels()) &&
+ (left.getSampleRates() == compareTo.getSampleRates());
+}
+
static AudioProfile* createFullDynamicImpl()
{
AudioProfile* dynamicProfile = new AudioProfile(gDynamicFormat,
@@ -67,6 +78,48 @@
return dynamicProfile;
}
+AudioProfile::AudioProfile(audio_format_t format,
+ audio_channel_mask_t channelMasks,
+ uint32_t samplingRate) :
+ mName(String8("")),
+ mFormat(format)
+{
+ mChannelMasks.add(channelMasks);
+ mSamplingRates.add(samplingRate);
+}
+
+AudioProfile::AudioProfile(audio_format_t format,
+ const ChannelsVector &channelMasks,
+ const SampleRateVector &samplingRateCollection) :
+ mName(String8("")),
+ mFormat(format),
+ mChannelMasks(channelMasks),
+ mSamplingRates(samplingRateCollection) {}
+
+void AudioProfile::setChannels(const ChannelsVector &channelMasks)
+{
+ if (mIsDynamicChannels) {
+ mChannelMasks = channelMasks;
+ }
+}
+
+void AudioProfile::setSampleRates(const SampleRateVector &sampleRates)
+{
+ if (mIsDynamicRate) {
+ mSamplingRates = sampleRates;
+ }
+}
+
+void AudioProfile::clear()
+{
+ if (mIsDynamicChannels) {
+ mChannelMasks.clear();
+ }
+ if (mIsDynamicRate) {
+ mSamplingRates.clear();
+ }
+}
+
status_t AudioProfile::checkExact(uint32_t samplingRate, audio_channel_mask_t channelMask,
audio_format_t format) const
{
@@ -78,13 +131,6 @@
return BAD_VALUE;
}
-bool operator == (const AudioProfile &left, const AudioProfile &compareTo)
-{
- return (left.getFormat() == compareTo.getFormat()) &&
- (left.getChannels() == compareTo.getChannels()) &&
- (left.getSampleRates() == compareTo.getSampleRates());
-}
-
status_t AudioProfile::checkCompatibleSamplingRate(uint32_t samplingRate,
uint32_t &updatedSamplingRate) const
{
@@ -250,6 +296,50 @@
write(fd, result.string(), result.size());
}
+ssize_t AudioProfileVector::add(const sp<AudioProfile> &profile)
+{
+ ssize_t index = Vector::add(profile);
+ // we sort from worst to best, so that AUDIO_FORMAT_DEFAULT is always the first entry.
+ // TODO: compareFormats could be a lambda to convert between pointer-to-format to format:
+ // [](const audio_format_t *format1, const audio_format_t *format2) {
+ // return compareFormats(*format1, *format2);
+ // }
+ sort(compareFormats);
+ return index;
+}
+
+ssize_t AudioProfileVector::addProfileFromHal(const sp<AudioProfile> &profileToAdd)
+{
+ // Check valid profile to add:
+ if (!profileToAdd->hasValidFormat()) {
+ return -1;
+ }
+ if (!profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+ FormatVector formats;
+ formats.add(profileToAdd->getFormat());
+ setFormats(FormatVector(formats));
+ return 0;
+ }
+ if (!profileToAdd->hasValidChannels() && profileToAdd->hasValidRates()) {
+ setSampleRatesFor(profileToAdd->getSampleRates(), profileToAdd->getFormat());
+ return 0;
+ }
+ if (profileToAdd->hasValidChannels() && !profileToAdd->hasValidRates()) {
+ setChannelsFor(profileToAdd->getChannels(), profileToAdd->getFormat());
+ return 0;
+ }
+ // Go through the list of profile to avoid duplicates
+ for (size_t profileIndex = 0; profileIndex < size(); profileIndex++) {
+ const sp<AudioProfile> &profile = itemAt(profileIndex);
+ if (profile->isValid() && profile == profileToAdd) {
+ // Nothing to do
+ return profileIndex;
+ }
+ }
+ profileToAdd->setDynamicFormat(true); // set the format as dynamic to allow removal
+ return add(profileToAdd);
+}
+
status_t AudioProfileVector::checkExactProfile(uint32_t samplingRate,
audio_channel_mask_t channelMask,
audio_format_t format) const
@@ -306,6 +396,233 @@
return BAD_VALUE;
}
+void AudioProfileVector::clearProfiles()
+{
+ for (size_t i = size(); i != 0; ) {
+ sp<AudioProfile> profile = itemAt(--i);
+ if (profile->isDynamicFormat() && profile->hasValidFormat()) {
+ removeAt(i);
+ continue;
+ }
+ profile->clear();
+ }
+}
+
+// Returns an intersection between two possibly unsorted vectors and the contents of 'order'.
+// The result is ordered according to 'order'.
+template<typename T, typename Order>
+std::vector<typename T::value_type> intersectFilterAndOrder(
+ const T& input1, const T& input2, const Order& order)
+{
+ std::set<typename T::value_type> set1{input1.begin(), input1.end()};
+ std::set<typename T::value_type> set2{input2.begin(), input2.end()};
+ std::set<typename T::value_type> common;
+ std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
+ std::inserter(common, common.begin()));
+ std::vector<typename T::value_type> result;
+ for (const auto& e : order) {
+ if (common.find(e) != common.end()) result.push_back(e);
+ }
+ return result;
+}
+
+// Intersect two possibly unsorted vectors, return common elements according to 'comp' ordering.
+// 'comp' is a comparator function.
+template<typename T, typename Compare>
+std::vector<typename T::value_type> intersectAndOrder(
+ const T& input1, const T& input2, Compare comp)
+{
+ std::set<typename T::value_type, Compare> set1{input1.begin(), input1.end(), comp};
+ std::set<typename T::value_type, Compare> set2{input2.begin(), input2.end(), comp};
+ std::vector<typename T::value_type> result;
+ std::set_intersection(set1.begin(), set1.end(), set2.begin(), set2.end(),
+ std::back_inserter(result), comp);
+ return result;
+}
+
+status_t AudioProfileVector::findBestMatchingOutputConfig(const AudioProfileVector& outputProfiles,
+ const std::vector<audio_format_t>& preferredFormats,
+ const std::vector<audio_channel_mask_t>& preferredOutputChannels,
+ bool preferHigherSamplingRates,
+ audio_config_base *bestOutputConfig) const
+{
+ auto formats = intersectFilterAndOrder(getSupportedFormats(),
+ outputProfiles.getSupportedFormats(), preferredFormats);
+ // Pick the best compatible profile.
+ for (const auto& f : formats) {
+ sp<AudioProfile> inputProfile = getFirstValidProfileFor(f);
+ sp<AudioProfile> outputProfile = outputProfiles.getFirstValidProfileFor(f);
+ if (inputProfile == nullptr || outputProfile == nullptr) {
+ continue;
+ }
+ auto channels = intersectFilterAndOrder(inputProfile->getChannels().asOutMask(),
+ outputProfile->getChannels(), preferredOutputChannels);
+ if (channels.empty()) {
+ continue;
+ }
+ auto sampleRates = preferHigherSamplingRates ?
+ intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
+ std::greater<typename SampleRateVector::value_type>()) :
+ intersectAndOrder(inputProfile->getSampleRates(), outputProfile->getSampleRates(),
+ std::less<typename SampleRateVector::value_type>());
+ if (sampleRates.empty()) {
+ continue;
+ }
+ ALOGD("%s() found channel mask %#x and sample rate %d for format %#x.",
+ __func__, *channels.begin(), *sampleRates.begin(), f);
+ bestOutputConfig->format = f;
+ bestOutputConfig->sample_rate = *sampleRates.begin();
+ bestOutputConfig->channel_mask = *channels.begin();
+ return NO_ERROR;
+ }
+ return BAD_VALUE;
+}
+
+sp<AudioProfile> AudioProfileVector::getFirstValidProfile() const
+{
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->isValid()) {
+ return itemAt(i);
+ }
+ }
+ return 0;
+}
+
+sp<AudioProfile> AudioProfileVector::getFirstValidProfileFor(audio_format_t format) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->isValid() && itemAt(i)->getFormat() == format) {
+ return itemAt(i);
+ }
+ }
+ return 0;
+}
+
+FormatVector AudioProfileVector::getSupportedFormats() const
+{
+ FormatVector supportedFormats;
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->hasValidFormat()) {
+ supportedFormats.add(itemAt(i)->getFormat());
+ }
+ }
+ return supportedFormats;
+}
+
+bool AudioProfileVector::hasDynamicChannelsFor(audio_format_t format) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicChannels()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioProfileVector::hasDynamicProfile() const
+{
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->isDynamic()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool AudioProfileVector::hasDynamicRateFor(audio_format_t format) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicRate()) {
+ return true;
+ }
+ }
+ return false;
+}
+
+void AudioProfileVector::setFormats(const FormatVector &formats)
+{
+ // Only allow to change the format of dynamic profile
+ sp<AudioProfile> dynamicFormatProfile = getProfileFor(gDynamicFormat);
+ if (dynamicFormatProfile == 0) {
+ return;
+ }
+ for (size_t i = 0; i < formats.size(); i++) {
+ sp<AudioProfile> profile = new AudioProfile(formats[i],
+ dynamicFormatProfile->getChannels(),
+ dynamicFormatProfile->getSampleRates());
+ profile->setDynamicFormat(true);
+ profile->setDynamicChannels(dynamicFormatProfile->isDynamicChannels());
+ profile->setDynamicRate(dynamicFormatProfile->isDynamicRate());
+ add(profile);
+ }
+}
+
+void AudioProfileVector::dump(int fd, int spaces) const
+{
+ const size_t SIZE = 256;
+ char buffer[SIZE];
+
+ snprintf(buffer, SIZE, "%*s- Profiles:\n", spaces, "");
+ write(fd, buffer, strlen(buffer));
+ for (size_t i = 0; i < size(); i++) {
+ snprintf(buffer, SIZE, "%*sProfile %zu:", spaces + 4, "", i);
+ write(fd, buffer, strlen(buffer));
+ itemAt(i)->dump(fd, spaces + 8);
+ }
+}
+
+sp<AudioProfile> AudioProfileVector::getProfileFor(audio_format_t format) const
+{
+ for (size_t i = 0; i < size(); i++) {
+ if (itemAt(i)->getFormat() == format) {
+ return itemAt(i);
+ }
+ }
+ return 0;
+}
+
+void AudioProfileVector::setSampleRatesFor(
+ const SampleRateVector &sampleRates, audio_format_t format)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicRate()) {
+ if (profile->hasValidRates()) {
+ // Need to create a new profile with same format
+ sp<AudioProfile> profileToAdd = new AudioProfile(format, profile->getChannels(),
+ sampleRates);
+ profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+ add(profileToAdd);
+ } else {
+ profile->setSampleRates(sampleRates);
+ }
+ return;
+ }
+ }
+}
+
+void AudioProfileVector::setChannelsFor(const ChannelsVector &channelMasks, audio_format_t format)
+{
+ for (size_t i = 0; i < size(); i++) {
+ sp<AudioProfile> profile = itemAt(i);
+ if (profile->getFormat() == format && profile->isDynamicChannels()) {
+ if (profile->hasValidChannels()) {
+ // Need to create a new profile with same format
+ sp<AudioProfile> profileToAdd = new AudioProfile(format, channelMasks,
+ profile->getSampleRates());
+ profileToAdd->setDynamicFormat(true); // need to set to allow cleaning
+ add(profileToAdd);
+ } else {
+ profile->setChannels(channelMasks);
+ }
+ return;
+ }
+ }
+}
+
+// static
int AudioProfileVector::compareFormats(const sp<AudioProfile> *profile1,
const sp<AudioProfile> *profile2)
{
diff --git a/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
deleted file mode 100644
index ba33e57..0000000
--- a/services/audiopolicy/common/managerdefinitions/src/AudioSourceDescriptor.cpp
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * Copyright (C) 2015 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#define LOG_TAG "APM::AudioSourceDescriptor"
-//#define LOG_NDEBUG 0
-
-#include <utils/Log.h>
-#include <utils/String8.h>
-#include <media/AudioPolicyHelper.h>
-#include <HwModule.h>
-#include <AudioGain.h>
-#include <AudioSourceDescriptor.h>
-#include <DeviceDescriptor.h>
-#include <IOProfile.h>
-#include <AudioOutputDescriptor.h>
-
-namespace android {
-
-status_t AudioSourceDescriptor::dump(int fd)
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, "mStream: %d\n", audio_attributes_to_stream_type(&mAttributes));
- result.append(buffer);
- snprintf(buffer, SIZE, "mDevice:\n");
- result.append(buffer);
- write(fd, result.string(), result.size());
- mDevice->dump(fd, 2 , 0);
- return NO_ERROR;
-}
-
-
-status_t AudioSourceCollection::dump(int fd) const
-{
- const size_t SIZE = 256;
- char buffer[SIZE];
-
- snprintf(buffer, SIZE, "\nAudio sources dump:\n");
- write(fd, buffer, strlen(buffer));
- for (size_t i = 0; i < size(); i++) {
- snprintf(buffer, SIZE, "- Source %d dump:\n", keyAt(i));
- write(fd, buffer, strlen(buffer));
- valueAt(i)->dump(fd);
- }
-
- return NO_ERROR;
-}
-
-}; //namespace android
diff --git a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
index 1e64d2e..5aca3cc 100644
--- a/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/ClientDescriptor.cpp
@@ -17,60 +17,105 @@
#define LOG_TAG "APM_ClientDescriptor"
//#define LOG_NDEBUG 0
+#include <utils/Log.h>
#include <utils/String8.h>
+#include "AudioGain.h"
+#include "AudioOutputDescriptor.h"
+#include "AudioPatch.h"
#include "ClientDescriptor.h"
+#include "DeviceDescriptor.h"
+#include "HwModule.h"
+#include "IOProfile.h"
namespace android {
-status_t ClientDescriptor::dump(int fd)
+status_t ClientDescriptor::dump(int fd, int spaces, int index)
{
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
+ String8 out;
- snprintf(buffer, SIZE, " Port ID: %d Session Id: %d UID: %d\n", mPortId, mSessionId, mUid);
- result.append(buffer);
- snprintf(buffer, SIZE, " Format: %08x Sampling rate: %d Channels: %08x\n",
+ // FIXME: use until other descriptor classes have a dump to String8 method
+ mDumpFd = fd;
+
+ status_t status = dump(out, spaces, index);
+ if (status == NO_ERROR) {
+ write(fd, out.string(), out.size());
+ }
+
+ return status;
+}
+
+status_t ClientDescriptor::dump(String8& out, int spaces, int index)
+{
+ out.appendFormat("%*sClient %d:\n", spaces, "", index+1);
+ out.appendFormat("%*s- Port ID: %d Session Id: %d UID: %d\n", spaces, "",
+ mPortId, mSessionId, mUid);
+ out.appendFormat("%*s- Format: %08x Sampling rate: %d Channels: %08x\n", spaces, "",
mConfig.format, mConfig.sample_rate, mConfig.channel_mask);
- result.append(buffer);
- snprintf(buffer, SIZE, " Preferred Device Id: %08x\n", mPreferredDeviceId);
- result.append(buffer);
- snprintf(buffer, SIZE, " State: %s\n", mActive ? "Active" : "Inactive");
- result.append(buffer);
+ out.appendFormat("%*s- Preferred Device Id: %08x\n", spaces, "", mPreferredDeviceId);
+ out.appendFormat("%*s- State: %s\n", spaces, "", mActive ? "Active" : "Inactive");
+ return NO_ERROR;
+}
- write(fd, result.string(), result.size());
+status_t TrackClientDescriptor::dump(String8& out, int spaces, int index)
+{
+ ClientDescriptor::dump(out, spaces, index);
+
+ out.appendFormat("%*s- Stream: %d flags: %08x\n", spaces, "", mStream, mFlags);
return NO_ERROR;
}
-status_t TrackClientDescriptor::dump(int fd)
+status_t RecordClientDescriptor::dump(String8& out, int spaces, int index)
{
- ClientDescriptor::dump(fd);
+ ClientDescriptor::dump(out, spaces, index);
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
-
- snprintf(buffer, SIZE, " Stream: %d flags: %08x\n", mStream, mFlags);
- result.append(buffer);
-
- write(fd, result.string(), result.size());
+ out.appendFormat("%*s- Source: %d flags: %08x\n", spaces, "", mSource, mFlags);
return NO_ERROR;
}
-status_t RecordClientDescriptor::dump(int fd)
+SourceClientDescriptor::SourceClientDescriptor(audio_port_handle_t portId, uid_t uid,
+ audio_attributes_t attributes, const sp<AudioPatch>& patchDesc,
+ const sp<DeviceDescriptor>& srcDevice, audio_stream_type_t stream) :
+ TrackClientDescriptor::TrackClientDescriptor(portId, uid, AUDIO_SESSION_NONE, attributes,
+ AUDIO_CONFIG_BASE_INITIALIZER, AUDIO_PORT_HANDLE_NONE, stream, AUDIO_OUTPUT_FLAG_NONE),
+ mPatchDesc(patchDesc), mSrcDevice(srcDevice)
{
- ClientDescriptor::dump(fd);
+}
- const size_t SIZE = 256;
- char buffer[SIZE];
- String8 result;
+void SourceClientDescriptor::setSwOutput(const sp<SwAudioOutputDescriptor>& swOutput)
+{
+ mSwOutput = swOutput;
+}
- snprintf(buffer, SIZE, " Source: %d flags: %08x\n", mSource, mFlags);
- result.append(buffer);
+void SourceClientDescriptor::setHwOutput(const sp<HwAudioOutputDescriptor>& hwOutput)
+{
+ mHwOutput = hwOutput;
+}
- write(fd, result.string(), result.size());
+status_t SourceClientDescriptor::dump(String8& out, int spaces, int index)
+{
+ TrackClientDescriptor::dump(out, spaces, index);
+
+ if (mDumpFd >= 0) {
+ out.appendFormat("%*s- Device:\n", spaces, "");
+ write(mDumpFd, out.string(), out.size());
+
+ mSrcDevice->dump(mDumpFd, 2, 0);
+ mDumpFd = -1;
+ }
+
+ return NO_ERROR;
+}
+
+status_t SourceClientCollection::dump(int fd) const
+{
+ String8 out;
+ out.append("\nAudio sources:\n");
+ write(fd, out.string(), out.size());
+ for (size_t i = 0; i < size(); i++) {
+ valueAt(i)->dump(fd, 2, i);
+ }
return NO_ERROR;
}
diff --git a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
index d3cc8b9..1638645 100644
--- a/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
+++ b/services/audiopolicy/common/managerdefinitions/src/DeviceDescriptor.cpp
@@ -121,17 +121,28 @@
return ret;
}
-audio_devices_t DeviceVector::getDevicesFromHwModule(audio_module_handle_t moduleHandle) const
+DeviceVector DeviceVector::getDevicesFromHwModule(audio_module_handle_t moduleHandle) const
{
- audio_devices_t devices = AUDIO_DEVICE_NONE;
- for (size_t i = 0; i < size(); i++) {
- if (itemAt(i)->getModuleHandle() == moduleHandle) {
- devices |= itemAt(i)->type();
+ DeviceVector devices;
+ for (const auto& device : *this) {
+ if (device->getModuleHandle() == moduleHandle) {
+ devices.add(device);
}
}
return devices;
}
+audio_devices_t DeviceVector::getDeviceTypesFromHwModule(audio_module_handle_t moduleHandle) const
+{
+ audio_devices_t deviceTypes = AUDIO_DEVICE_NONE;
+ for (const auto& device : *this) {
+ if (device->getModuleHandle() == moduleHandle) {
+ deviceTypes |= device->type();
+ }
+ }
+ return deviceTypes;
+}
+
sp<DeviceDescriptor> DeviceVector::getDevice(audio_devices_t type, const String8& address) const
{
sp<DeviceDescriptor> device;
diff --git a/services/audiopolicy/enginedefault/src/Engine.cpp b/services/audiopolicy/enginedefault/src/Engine.cpp
index ca64d86..30f275f 100644
--- a/services/audiopolicy/enginedefault/src/Engine.cpp
+++ b/services/audiopolicy/enginedefault/src/Engine.cpp
@@ -313,7 +313,7 @@
audio_devices_t txDevice = getDeviceForInputSource(AUDIO_SOURCE_VOICE_COMMUNICATION);
sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
audio_devices_t availPrimaryInputDevices =
- availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle());
+ availableInputDevices.getDeviceTypesFromHwModule(primaryOutput->getModuleHandle());
// TODO: getPrimaryOutput return only devices from first module in
// audio_policy_configuration.xml, hearing aid is not there, but it's
@@ -668,9 +668,8 @@
if ((getPhoneState() == AUDIO_MODE_IN_CALL) &&
(availableOutputDevices.types() & AUDIO_DEVICE_OUT_TELEPHONY_TX) == 0) {
sp<AudioOutputDescriptor> primaryOutput = outputs.getPrimaryOutput();
- availableDeviceTypes =
- availableInputDevices.getDevicesFromHwModule(primaryOutput->getModuleHandle())
- & ~AUDIO_DEVICE_BIT_IN;
+ availableDeviceTypes = availableInputDevices.getDeviceTypesFromHwModule(
+ primaryOutput->getModuleHandle()) & ~AUDIO_DEVICE_BIT_IN;
}
switch (mForceUse[AUDIO_POLICY_FORCE_FOR_COMMUNICATION]) {
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
index 856bcb3..b0e6b0f 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.cpp
@@ -31,6 +31,7 @@
#include <inttypes.h>
#include <math.h>
+#include <vector>
#include <AudioPolicyManagerInterface.h>
#include <AudioPolicyEngineInstance.h>
@@ -38,7 +39,6 @@
#include <utils/Log.h>
#include <media/AudioParameter.h>
#include <media/AudioPolicyHelper.h>
-#include <media/PatchBuilder.h>
#include <private/android_filesystem_config.h>
#include <soundtrigger/SoundTrigger.h>
#include <system/audio.h>
@@ -82,6 +82,16 @@
AUDIO_FORMAT_AAC_XHE,
};
+// Compressed formats for MSD module, ordered from most preferred to least preferred.
+static const std::vector<audio_format_t> compressedFormatsOrder = {{
+ AUDIO_FORMAT_MAT_2_1, AUDIO_FORMAT_MAT_2_0, AUDIO_FORMAT_E_AC3,
+ AUDIO_FORMAT_AC3, AUDIO_FORMAT_PCM_16_BIT }};
+// Channel masks for MSD module, 3D > 2D > 1D ordering (most preferred to least preferred).
+static const std::vector<audio_channel_mask_t> surroundChannelMasksOrder = {{
+ AUDIO_CHANNEL_OUT_3POINT1POINT2, AUDIO_CHANNEL_OUT_3POINT0POINT2,
+ AUDIO_CHANNEL_OUT_2POINT1POINT2, AUDIO_CHANNEL_OUT_2POINT0POINT2,
+ AUDIO_CHANNEL_OUT_5POINT1, AUDIO_CHANNEL_OUT_STEREO }};
+
// ----------------------------------------------------------------------------
// AudioPolicyInterface implementation
// ----------------------------------------------------------------------------
@@ -225,6 +235,7 @@
audio_devices_t newDevice = getNewOutputDevice(mPrimaryOutput, false /*fromCache*/);
updateCallRouting(newDevice);
}
+ const audio_devices_t msdOutDevice = getMsdAudioOutDeviceTypes();
for (size_t i = 0; i < mOutputs.size(); i++) {
sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(i);
if ((mEngine->getPhoneState() != AUDIO_MODE_IN_CALL) || (desc != mPrimaryOutput)) {
@@ -232,7 +243,8 @@
// do not force device change on duplicated output because if device is 0, it will
// also force a device 0 for the two outputs it is duplicated to which may override
// a valid device selection on those outputs.
- bool force = !desc->isDuplicated()
+ bool force = (msdOutDevice == AUDIO_DEVICE_NONE || msdOutDevice != desc->device())
+ && !desc->isDuplicated()
&& (!device_distinguishes_on_address(device)
// always force when disconnecting (a non-duplicated device)
|| (state == AUDIO_POLICY_DEVICE_STATE_UNAVAILABLE));
@@ -505,13 +517,7 @@
// symmetric to the one in startInput()
for (const auto& activeDesc : mInputs.getActiveInputs()) {
if (activeDesc->hasSameHwModuleAs(txSourceDeviceDesc)) {
- AudioSessionCollection activeSessions =
- activeDesc->getAudioSessions(true /*activeOnly*/);
- for (size_t j = 0; j < activeSessions.size(); j++) {
- audio_session_t activeSession = activeSessions.keyAt(j);
- stopInput(activeDesc->mIoHandle, activeSession);
- releaseInput(activeDesc->mIoHandle, activeSession);
- }
+ closeSessions(activeDesc, true /*activeOnly*/);
}
}
}
@@ -531,7 +537,7 @@
}
sp<DeviceDescriptor> AudioPolicyManager::findDevice(
- const DeviceVector& devices, audio_devices_t device) {
+ const DeviceVector& devices, audio_devices_t device) const {
DeviceVector deviceList = devices.getDevicesFromTypeMask(device);
ALOG_ASSERT(!deviceList.isEmpty(),
"%s() selected device type %#x is not in devices list", __func__, device);
@@ -779,6 +785,12 @@
audio_port_handle_t *portId)
{
audio_attributes_t attributes;
+ DeviceVector outputDevices;
+ routing_strategy strategy;
+ audio_devices_t device;
+ audio_port_handle_t requestedDeviceId = *selectedDeviceId;
+ audio_devices_t msdDevice = getMsdAudioOutDeviceTypes();
+
if (attr != NULL) {
if (!isValidAttributes(attr)) {
ALOGE("getOutputForAttr() invalid attributes: usage=%d content=%d flags=0x%x tags=[%s]",
@@ -820,7 +832,7 @@
*stream = streamTypefromAttributesInt(&attributes);
*output = desc->mIoHandle;
ALOGV("getOutputForAttr() returns output %d", *output);
- return NO_ERROR;
+ goto exit;
}
// Virtual sources must always be dynamicaly or explicitly routed
@@ -844,8 +856,8 @@
// explicit route. Is that the intended and necessary behavior?
mOutputRoutes.addRoute(session, *stream, SessionRoute::SOURCE_TYPE_NA, deviceDesc, uid);
- routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
- audio_devices_t device = getDeviceForStrategy(strategy, false /*fromCache*/);
+ strategy = (routing_strategy) getStrategyForAttr(&attributes);
+ device = getDeviceForStrategy(strategy, false /*fromCache*/);
if ((attributes.flags & AUDIO_FLAG_HW_AV_SYNC) != 0) {
*flags = (audio_output_flags_t)(*flags | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
@@ -870,17 +882,41 @@
"flags %#x",
device, config->sample_rate, config->format, config->channel_mask, *flags);
- *output = getOutputForDevice(device, session, *stream, config, flags);
+ *output = AUDIO_IO_HANDLE_NONE;
+ if (msdDevice != AUDIO_DEVICE_NONE) {
+ *output = getOutputForDevice(msdDevice, session, *stream, config, flags);
+ if (*output != AUDIO_IO_HANDLE_NONE && setMsdPatch(device) == NO_ERROR) {
+ ALOGV("%s() Using MSD device 0x%x instead of device 0x%x",
+ __func__, msdDevice, device);
+ device = msdDevice;
+ } else {
+ *output = AUDIO_IO_HANDLE_NONE;
+ }
+ }
+ if (*output == AUDIO_IO_HANDLE_NONE) {
+ *output = getOutputForDevice(device, session, *stream, config, flags);
+ }
if (*output == AUDIO_IO_HANDLE_NONE) {
mOutputRoutes.removeRoute(session);
return INVALID_OPERATION;
}
- DeviceVector outputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(device);
+ outputDevices = mAvailableOutputDevices.getDevicesFromTypeMask(device);
*selectedDeviceId = outputDevices.size() > 0 ? outputDevices.itemAt(0)->getId()
: AUDIO_PORT_HANDLE_NONE;
- ALOGV(" getOutputForAttr() returns output %d selectedDeviceId %d", *output, *selectedDeviceId);
+exit:
+ audio_config_base_t clientConfig = {.sample_rate = config->sample_rate,
+ .format = config->format,
+ .channel_mask = config->channel_mask };
+ sp<TrackClientDescriptor> clientDesc =
+ new TrackClientDescriptor(*portId, uid, session,
+ attributes, clientConfig, requestedDeviceId, *stream, *flags);
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueFor(*output);
+ outputDesc->clients().emplace(*portId, clientDesc);
+
+ ALOGV(" getOutputForAttr() returns output %d selectedDeviceId %d for port ID %d",
+ *output, *selectedDeviceId, *portId);
return NO_ERROR;
}
@@ -1042,6 +1078,164 @@
return output;
}
+sp<DeviceDescriptor> AudioPolicyManager::getMsdAudioInDevice() const {
+ sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+ if (msdModule != 0) {
+ DeviceVector msdInputDevices = mAvailableInputDevices.getDevicesFromHwModule(
+ msdModule->getHandle());
+ if (!msdInputDevices.isEmpty()) return msdInputDevices.itemAt(0);
+ }
+ return 0;
+}
+
+audio_devices_t AudioPolicyManager::getMsdAudioOutDeviceTypes() const {
+ sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+ if (msdModule != 0) {
+ return mAvailableOutputDevices.getDeviceTypesFromHwModule(msdModule->getHandle());
+ }
+ return AUDIO_DEVICE_NONE;
+}
+
+const AudioPatchCollection AudioPolicyManager::getMsdPatches() const {
+ AudioPatchCollection msdPatches;
+ audio_module_handle_t msdModuleHandle = mHwModules.getModuleFromName(
+ AUDIO_HARDWARE_MODULE_ID_MSD)->getHandle();
+ if (msdModuleHandle == AUDIO_MODULE_HANDLE_NONE) return msdPatches;
+ for (size_t i = 0; i < mAudioPatches.size(); ++i) {
+ sp<AudioPatch> patch = mAudioPatches.valueAt(i);
+ for (size_t j = 0; j < patch->mPatch.num_sources; ++j) {
+ const struct audio_port_config *source = &patch->mPatch.sources[j];
+ if (source->type == AUDIO_PORT_TYPE_DEVICE &&
+ source->ext.device.hw_module == msdModuleHandle) {
+ msdPatches.addAudioPatch(patch->mHandle, patch);
+ }
+ }
+ }
+ return msdPatches;
+}
+
+status_t AudioPolicyManager::getBestMsdAudioProfileFor(audio_devices_t outputDevice,
+ bool hwAvSync, audio_port_config *sourceConfig, audio_port_config *sinkConfig) const
+{
+ sp<HwModule> msdModule = mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD);
+ if (msdModule == nullptr) {
+ ALOGE("%s() unable to get MSD module", __func__);
+ return NO_INIT;
+ }
+ sp<HwModule> deviceModule = mHwModules.getModuleForDevice(outputDevice);
+ if (deviceModule == nullptr) {
+ ALOGE("%s() unable to get module for %#x", __func__, outputDevice);
+ return NO_INIT;
+ }
+ const InputProfileCollection &inputProfiles = msdModule->getInputProfiles();
+ if (inputProfiles.isEmpty()) {
+ ALOGE("%s() no input profiles for MSD module", __func__);
+ return NO_INIT;
+ }
+ const OutputProfileCollection &outputProfiles = deviceModule->getOutputProfiles();
+ if (outputProfiles.isEmpty()) {
+ ALOGE("%s() no output profiles for device %#x", __func__, outputDevice);
+ return NO_INIT;
+ }
+ AudioProfileVector msdProfiles;
+ // Each IOProfile represents a MixPort from audio_policy_configuration.xml
+ for (const auto &inProfile : inputProfiles) {
+ if (hwAvSync == ((inProfile->getFlags() & AUDIO_INPUT_FLAG_HW_AV_SYNC) != 0)) {
+ msdProfiles.appendVector(inProfile->getAudioProfiles());
+ }
+ }
+ AudioProfileVector deviceProfiles;
+ for (const auto &outProfile : outputProfiles) {
+ if (hwAvSync == ((outProfile->getFlags() & AUDIO_OUTPUT_FLAG_HW_AV_SYNC) != 0)) {
+ deviceProfiles.appendVector(outProfile->getAudioProfiles());
+ }
+ }
+ struct audio_config_base bestSinkConfig;
+ status_t result = msdProfiles.findBestMatchingOutputConfig(deviceProfiles,
+ compressedFormatsOrder, surroundChannelMasksOrder, true /*preferHigherSamplingRates*/,
+ &bestSinkConfig);
+ if (result != NO_ERROR) {
+ ALOGD("%s() no matching profiles found for device: %#x, hwAvSync: %d",
+ __func__, outputDevice, hwAvSync);
+ return result;
+ }
+ sinkConfig->sample_rate = bestSinkConfig.sample_rate;
+ sinkConfig->channel_mask = bestSinkConfig.channel_mask;
+ sinkConfig->format = bestSinkConfig.format;
+ // For encoded streams force direct flag to prevent downstream mixing.
+ sinkConfig->flags.output = static_cast<audio_output_flags_t>(
+ sinkConfig->flags.output | AUDIO_OUTPUT_FLAG_DIRECT);
+ sourceConfig->sample_rate = bestSinkConfig.sample_rate;
+ // Specify exact channel mask to prevent guessing by bit count in PatchPanel.
+ sourceConfig->channel_mask = audio_channel_mask_out_to_in(bestSinkConfig.channel_mask);
+ sourceConfig->format = bestSinkConfig.format;
+ // Copy input stream directly without any processing (e.g. resampling).
+ sourceConfig->flags.input = static_cast<audio_input_flags_t>(
+ sourceConfig->flags.input | AUDIO_INPUT_FLAG_DIRECT);
+ if (hwAvSync) {
+ sinkConfig->flags.output = static_cast<audio_output_flags_t>(
+ sinkConfig->flags.output | AUDIO_OUTPUT_FLAG_HW_AV_SYNC);
+ sourceConfig->flags.input = static_cast<audio_input_flags_t>(
+ sourceConfig->flags.input | AUDIO_INPUT_FLAG_HW_AV_SYNC);
+ }
+ const unsigned int config_mask = AUDIO_PORT_CONFIG_SAMPLE_RATE |
+ AUDIO_PORT_CONFIG_CHANNEL_MASK | AUDIO_PORT_CONFIG_FORMAT | AUDIO_PORT_CONFIG_FLAGS;
+ sinkConfig->config_mask |= config_mask;
+ sourceConfig->config_mask |= config_mask;
+ return NO_ERROR;
+}
+
+PatchBuilder AudioPolicyManager::buildMsdPatch(audio_devices_t outputDevice) const
+{
+ PatchBuilder patchBuilder;
+ patchBuilder.addSource(getMsdAudioInDevice()).
+ addSink(findDevice(mAvailableOutputDevices, outputDevice));
+ audio_port_config sourceConfig = patchBuilder.patch()->sources[0];
+ audio_port_config sinkConfig = patchBuilder.patch()->sinks[0];
+ // TODO: Figure out whether MSD module has HW_AV_SYNC flag set in the AP config file.
+ // For now, we just forcefully try with HwAvSync first.
+ status_t res = getBestMsdAudioProfileFor(outputDevice, true /*hwAvSync*/,
+ &sourceConfig, &sinkConfig) == NO_ERROR ? NO_ERROR :
+ getBestMsdAudioProfileFor(
+ outputDevice, false /*hwAvSync*/, &sourceConfig, &sinkConfig);
+ if (res == NO_ERROR) {
+ // Found a matching profile for encoded audio. Re-create PatchBuilder with this config.
+ return (PatchBuilder()).addSource(sourceConfig).addSink(sinkConfig);
+ }
+ ALOGV("%s() no matching profile found. Fall through to default PCM patch"
+ " supporting PCM format conversion.", __func__);
+ return patchBuilder;
+}
+
+status_t AudioPolicyManager::setMsdPatch(audio_devices_t outputDevice) {
+ ALOGV("%s() for outputDevice %#x", __func__, outputDevice);
+ if (outputDevice == AUDIO_DEVICE_NONE) {
+ // Use media strategy for unspecified output device. This should only
+ // occur on checkForDeviceAndOutputChanges(). Device connection events may
+ // therefore invalidate explicit routing requests.
+ outputDevice = getDeviceForStrategy(STRATEGY_MEDIA, false /*fromCache*/);
+ }
+ PatchBuilder patchBuilder = buildMsdPatch(outputDevice);
+ const struct audio_patch* patch = patchBuilder.patch();
+ const AudioPatchCollection msdPatches = getMsdPatches();
+ if (!msdPatches.isEmpty()) {
+ LOG_ALWAYS_FATAL_IF(msdPatches.size() > 1,
+ "The current MSD prototype only supports one output patch");
+ sp<AudioPatch> currentPatch = msdPatches.valueAt(0);
+ if (audio_patches_are_equal(¤tPatch->mPatch, patch)) {
+ return NO_ERROR;
+ }
+ releaseAudioPatch(currentPatch->mHandle, mUidCached);
+ }
+ status_t status = installPatch(__func__, -1 /*index*/, nullptr /*patchHandle*/,
+ patch, 0 /*delayMs*/, mUidCached, nullptr /*patchDescPtr*/);
+ ALOGE_IF(status != NO_ERROR, "%s() error %d creating MSD audio patch", __func__, status);
+ ALOGI_IF(status == NO_ERROR, "%s() Patch created from MSD_IN to "
+ "device:%#x (format:%#x channels:%#x samplerate:%d)", __func__, outputDevice,
+ patch->sources[0].format, patch->sources[0].channel_mask, patch->sources[0].sample_rate);
+ return status;
+}
+
audio_io_handle_t AudioPolicyManager::selectOutput(const SortedVector<audio_io_handle_t>& outputs,
audio_output_flags_t flags,
audio_format_t format)
@@ -1122,19 +1316,21 @@
return outputs[0];
}
-status_t AudioPolicyManager::startOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session)
+status_t AudioPolicyManager::startOutput(audio_port_handle_t portId)
{
- ALOGV("startOutput() output %d, stream %d, session %d",
- output, stream, session);
- ssize_t index = mOutputs.indexOfKey(output);
- if (index < 0) {
- ALOGW("startOutput() unknown output %d", output);
+ ALOGV("%s portId %d", __FUNCTION__, portId);
+
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
+ if (outputDesc == 0) {
+ ALOGW("startOutput() no output for client %d", portId);
return BAD_VALUE;
}
+ sp<TrackClientDescriptor> client = outputDesc->clients()[portId];
+ audio_stream_type_t stream = client->stream();
+ audio_session_t session = client->session();
- sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
+ ALOGV("startOutput() output %d, stream %d, session %d",
+ outputDesc->mIoHandle, stream, session);
status_t status = outputDesc->start();
if (status != NO_ERROR) {
@@ -1158,7 +1354,7 @@
} else if (mOutputRoutes.getAndClearRouteChanged(session)) {
newDevice = getNewOutputDevice(outputDesc, false /*fromCache*/);
if (newDevice != outputDesc->device()) {
- checkStrategyRoute(getStrategy(stream), output);
+ checkStrategyRoute(getStrategy(stream), outputDesc->mIoHandle);
}
} else {
newDevice = AUDIO_DEVICE_NONE;
@@ -1318,27 +1514,23 @@
setStrategyMute(STRATEGY_SONIFICATION, true, outputDesc);
}
- if (stream == AUDIO_STREAM_ENFORCED_AUDIBLE &&
- mEngine->getForceUse(AUDIO_POLICY_FORCE_FOR_SYSTEM) == AUDIO_POLICY_FORCE_SYSTEM_ENFORCED) {
- setStrategyMute(STRATEGY_SONIFICATION, true, outputDesc);
- }
-
return NO_ERROR;
}
-
-status_t AudioPolicyManager::stopOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session)
+status_t AudioPolicyManager::stopOutput(audio_port_handle_t portId)
{
- ALOGV("stopOutput() output %d, stream %d, session %d", output, stream, session);
- ssize_t index = mOutputs.indexOfKey(output);
- if (index < 0) {
- ALOGW("stopOutput() unknown output %d", output);
+ ALOGV("%s portId %d", __FUNCTION__, portId);
+
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
+ if (outputDesc == 0) {
+ ALOGW("stopOutput() no output for client %d", portId);
return BAD_VALUE;
}
+ sp<TrackClientDescriptor> client = outputDesc->clients()[portId];
+ audio_stream_type_t stream = client->stream();
+ audio_session_t session = client->session();
- sp<SwAudioOutputDescriptor> outputDesc = mOutputs.valueAt(index);
+ ALOGV("stopOutput() output %d, stream %d, session %d", outputDesc->mIoHandle, stream, session);
if (outputDesc->mRefCount[stream] == 1) {
// Automatically disable the remote submix input when output is stopped on a
@@ -1435,32 +1627,35 @@
}
}
-void AudioPolicyManager::releaseOutput(audio_io_handle_t output,
- audio_stream_type_t stream __unused,
- audio_session_t session __unused)
+void AudioPolicyManager::releaseOutput(audio_port_handle_t portId)
{
- ALOGV("releaseOutput() %d", output);
- ssize_t index = mOutputs.indexOfKey(output);
- if (index < 0) {
- ALOGW("releaseOutput() releasing unknown output %d", output);
+ ALOGV("%s portId %d", __FUNCTION__, portId);
+
+ sp<SwAudioOutputDescriptor> outputDesc = mOutputs.getOutputForClient(portId);
+ if (outputDesc == 0) {
+ ALOGW("releaseOutput() no output for client %d", portId);
return;
}
+ sp<TrackClientDescriptor> client = outputDesc->clients()[portId];
+ audio_session_t session = client->session();
+
+ ALOGV("releaseOutput() %d", outputDesc->mIoHandle);
// Routing
mOutputRoutes.removeRoute(session);
- sp<SwAudioOutputDescriptor> desc = mOutputs.valueAt(index);
- if (desc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
- if (desc->mDirectOpenCount <= 0) {
+ if (outputDesc->mFlags & AUDIO_OUTPUT_FLAG_DIRECT) {
+ if (outputDesc->mDirectOpenCount <= 0) {
ALOGW("releaseOutput() invalid open count %d for output %d",
- desc->mDirectOpenCount, output);
+ outputDesc->mDirectOpenCount, outputDesc->mIoHandle);
return;
}
- if (--desc->mDirectOpenCount == 0) {
- closeOutput(output);
+ if (--outputDesc->mDirectOpenCount == 0) {
+ closeOutput(outputDesc->mIoHandle);
mpClientInterface->onAudioPortListUpdate();
}
}
+ outputDesc->clients().erase(portId);
}
@@ -1485,6 +1680,9 @@
audio_source_t inputSource = attr->source;
AudioMix *policyMix = NULL;
DeviceVector inputDevices;
+ sp<AudioInputDescriptor> inputDesc;
+ sp<RecordClientDescriptor> clientDesc;
+ audio_port_handle_t requestedDeviceId = *selectedDeviceId;
if (inputSource == AUDIO_SOURCE_DEFAULT) {
inputSource = AUDIO_SOURCE_MIC;
@@ -1540,7 +1738,7 @@
: AUDIO_PORT_HANDLE_NONE;
ALOGI("%s reusing MMAP input %d for session %d", __FUNCTION__, *input, session);
- return NO_ERROR;
+ goto exit;
}
*input = AUDIO_IO_HANDLE_NONE;
@@ -1606,8 +1804,14 @@
*selectedDeviceId = inputDevices.size() > 0 ? inputDevices.itemAt(0)->getId()
: AUDIO_PORT_HANDLE_NONE;
- ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d",
- *input, *inputType, *selectedDeviceId);
+exit:
+ clientDesc = new RecordClientDescriptor(*portId, uid, session,
+ *attr, *config, requestedDeviceId, inputSource, flags);
+ inputDesc = mInputs.valueFor(*input);
+ inputDesc->clients().emplace(*portId, clientDesc);
+
+ ALOGV("getInputForAttr() returns input %d type %d selectedDeviceId %d for port ID %d",
+ *input, *inputType, *selectedDeviceId, *portId);
return NO_ERROR;
@@ -1810,24 +2014,26 @@
}
-status_t AudioPolicyManager::startInput(audio_io_handle_t input,
- audio_session_t session,
+status_t AudioPolicyManager::startInput(audio_port_handle_t portId,
bool silenced,
concurrency_type__mask_t *concurrency)
{
+ *concurrency = API_INPUT_CONCURRENCY_NONE;
+
+ ALOGV("%s portId %d", __FUNCTION__, portId);
+
+ sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
+ if (inputDesc == 0) {
+ ALOGW("startInput() no input for client %d", portId);
+ return BAD_VALUE;
+ }
+ sp<RecordClientDescriptor> client = inputDesc->clients()[portId];
+ audio_session_t session = client->session();
+ audio_io_handle_t input = inputDesc->mIoHandle;
ALOGV("AudioPolicyManager::startInput(input:%d, session:%d, silenced:%d, concurrency:%d)",
input, session, silenced, *concurrency);
- *concurrency = API_INPUT_CONCURRENCY_NONE;
-
- ssize_t index = mInputs.indexOfKey(input);
- if (index < 0) {
- ALOGW("startInput() unknown input %d", input);
- return BAD_VALUE;
- }
- sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
-
sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
if (audioSession == 0) {
ALOGW("startInput() unknown session %d on input %d", session, input);
@@ -1858,11 +2064,8 @@
true /*activeOnly*/);
sp<AudioSession> activeSession = activeSessions.valueAt(0);
if (activeSession->isSilenced()) {
- audio_io_handle_t activeInput = activeDesc->mIoHandle;
- audio_session_t activeSessionId = activeSession->session();
- stopInput(activeInput, activeSessionId);
- releaseInput(activeInput, activeSessionId);
- ALOGV("startInput(%d) stopping silenced input %d", input, activeInput);
+ closeSession(activeDesc, activeSession);
+ ALOGV("startInput() session %d stopping silenced session %d", session, activeSession->session());
activeInputs = mInputs.getActiveInputs();
}
}
@@ -1916,14 +2119,12 @@
if (activeSource == AUDIO_SOURCE_HOTWORD) {
AudioSessionCollection activeSessions =
activeDesc->getAudioSessions(true /*activeOnly*/);
- audio_session_t activeSession = activeSessions.keyAt(0);
- audio_io_handle_t activeHandle = activeDesc->mIoHandle;
+ sp<AudioSession> activeSession = activeSessions[0];
SortedVector<audio_session_t> sessions = activeDesc->getPreemptedSessions();
*concurrency |= API_INPUT_CONCURRENCY_PREEMPT;
- sessions.add(activeSession);
+ sessions.add(activeSession->session());
inputDesc->setPreemptedSessions(sessions);
- stopInput(activeHandle, activeSession);
- releaseInput(activeHandle, activeSession);
+ closeSession(inputDesc, activeSession);
ALOGV("startInput(%d) for HOTWORD preempting HOTWORD input %d",
input, activeDesc->mIoHandle);
}
@@ -1991,22 +2192,22 @@
return NO_ERROR;
}
-status_t AudioPolicyManager::stopInput(audio_io_handle_t input,
- audio_session_t session)
+status_t AudioPolicyManager::stopInput(audio_port_handle_t portId)
{
- ALOGV("stopInput() input %d", input);
- ssize_t index = mInputs.indexOfKey(input);
- if (index < 0) {
- ALOGW("stopInput() unknown input %d", input);
+ ALOGV("%s portId %d", __FUNCTION__, portId);
+
+ sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
+ if (inputDesc == 0) {
+ ALOGW("stopInput() no input for client %d", portId);
return BAD_VALUE;
}
- sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
+ sp<RecordClientDescriptor> client = inputDesc->clients()[portId];
+ audio_session_t session = client->session();
+ audio_io_handle_t input = inputDesc->mIoHandle;
+
+ ALOGV("stopInput() input %d", input);
sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
- if (index < 0) {
- ALOGW("stopInput() unknown session %d on input %d", session, input);
- return BAD_VALUE;
- }
if (audioSession->activeCount() == 0) {
ALOGW("stopInput() input %d already stopped", input);
@@ -2062,22 +2263,24 @@
return NO_ERROR;
}
-void AudioPolicyManager::releaseInput(audio_io_handle_t input,
- audio_session_t session)
+void AudioPolicyManager::releaseInput(audio_port_handle_t portId)
{
- ALOGV("releaseInput() %d", input);
- ssize_t index = mInputs.indexOfKey(input);
- if (index < 0) {
- ALOGW("releaseInput() releasing unknown input %d", input);
+ ALOGV("%s portId %d", __FUNCTION__, portId);
+
+ sp<AudioInputDescriptor> inputDesc = mInputs.getInputForClient(portId);
+ if (inputDesc == 0) {
+ ALOGW("releaseInput() no input for client %d", portId);
return;
}
+ sp<RecordClientDescriptor> client = inputDesc->clients()[portId];
+ audio_session_t session = client->session();
+ audio_io_handle_t input = inputDesc->mIoHandle;
+
+ ALOGV("releaseInput() %d", input);
// Routing
mInputRoutes.removeRoute(session);
- sp<AudioInputDescriptor> inputDesc = mInputs.valueAt(index);
- ALOG_ASSERT(inputDesc != 0);
-
sp<AudioSession> audioSession = inputDesc->getAudioSession(session);
if (audioSession == 0) {
ALOGW("releaseInput() unknown session %d on input %d", session, input);
@@ -2100,10 +2303,31 @@
}
closeInput(input);
+ inputDesc->clients().erase(portId);
mpClientInterface->onAudioPortListUpdate();
ALOGV("releaseInput() exit");
}
+void AudioPolicyManager::closeSessions(const sp<AudioInputDescriptor>& input, bool activeOnly)
+{
+ AudioSessionCollection sessions = input->getAudioSessions(activeOnly /*activeOnly*/);
+ for (size_t i = 0; i < sessions.size(); i++) {
+ closeSession(input, sessions[i]);
+ }
+}
+
+void AudioPolicyManager::closeSession(const sp<AudioInputDescriptor>& input,
+ const sp<AudioSession>& session)
+{
+ RecordClientVector clients = input->getClientsForSession(session->session());
+
+ for (const auto& client : clients) {
+ stopInput(client->portId());
+ releaseInput(client->portId());
+ }
+}
+
+
void AudioPolicyManager::closeAllInputs() {
bool patchRemoved = false;
@@ -2565,6 +2789,7 @@
mEffects.dump(fd);
mAudioPatches.dump(fd);
mPolicyMixes.dump(fd);
+ mAudioSources.dump(fd);
return NO_ERROR;
}
@@ -3207,8 +3432,8 @@
void AudioPolicyManager::clearAudioSources(uid_t uid)
{
for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--) {
- sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
- if (sourceDesc->mUid == uid) {
+ sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ if (sourceDesc->uid() == uid) {
stopAudioSource(mAudioSources.keyAt(i));
}
}
@@ -3226,20 +3451,23 @@
}
status_t AudioPolicyManager::startAudioSource(const struct audio_port_config *source,
- const audio_attributes_t *attributes,
- audio_patch_handle_t *handle,
- uid_t uid)
+ const audio_attributes_t *attributes,
+ audio_port_handle_t *portId,
+ uid_t uid)
{
- ALOGV("%s source %p attributes %p handle %p", __FUNCTION__, source, attributes, handle);
- if (source == NULL || attributes == NULL || handle == NULL) {
+ ALOGV("%s", __FUNCTION__);
+ *portId = AUDIO_PORT_HANDLE_NONE;
+
+ if (source == NULL || attributes == NULL || portId == NULL) {
+ ALOGW("%s invalid argument: source %p attributes %p handle %p",
+ __FUNCTION__, source, attributes, portId);
return BAD_VALUE;
}
- *handle = AUDIO_PATCH_HANDLE_NONE;
-
if (source->role != AUDIO_PORT_ROLE_SOURCE ||
source->type != AUDIO_PORT_TYPE_DEVICE) {
- ALOGV("%s INVALID_OPERATION source->role %d source->type %d", __FUNCTION__, source->role, source->type);
+ ALOGW("%s INVALID_OPERATION source->role %d source->type %d",
+ __FUNCTION__, source->role, source->type);
return INVALID_OPERATION;
}
@@ -3247,34 +3475,37 @@
mAvailableInputDevices.getDevice(source->ext.device.type,
String8(source->ext.device.address));
if (srcDeviceDesc == 0) {
- ALOGV("%s source->ext.device.type %08x not found", __FUNCTION__, source->ext.device.type);
+ ALOGW("%s source->ext.device.type %08x not found", __FUNCTION__, source->ext.device.type);
return BAD_VALUE;
}
- sp<AudioSourceDescriptor> sourceDesc =
- new AudioSourceDescriptor(srcDeviceDesc, attributes, uid);
+
+ *portId = AudioPort::getNextUniqueId();
struct audio_patch dummyPatch = {};
sp<AudioPatch> patchDesc = new AudioPatch(&dummyPatch, uid);
- sourceDesc->mPatchDesc = patchDesc;
+
+ sp<SourceClientDescriptor> sourceDesc =
+ new SourceClientDescriptor(*portId, uid, *attributes, patchDesc, srcDeviceDesc,
+ streamTypefromAttributesInt(attributes));
status_t status = connectAudioSource(sourceDesc);
if (status == NO_ERROR) {
- mAudioSources.add(sourceDesc->getHandle(), sourceDesc);
- *handle = sourceDesc->getHandle();
+ mAudioSources.add(*portId, sourceDesc);
}
return status;
}
-status_t AudioPolicyManager::connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+status_t AudioPolicyManager::connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
{
- ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+ ALOGV("%s handle %d", __FUNCTION__, sourceDesc->portId());
// make sure we only have one patch per source.
disconnectAudioSource(sourceDesc);
- routing_strategy strategy = (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
- audio_stream_type_t stream = streamTypefromAttributesInt(&sourceDesc->mAttributes);
- sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->mDevice;
+ audio_attributes_t attributes = sourceDesc->attributes();
+ routing_strategy strategy = (routing_strategy) getStrategyForAttr(&attributes);
+ audio_stream_type_t stream = sourceDesc->stream();
+ sp<DeviceDescriptor> srcDeviceDesc = sourceDesc->srcDevice();
audio_devices_t sinkDevice = getDeviceForStrategy(strategy, true);
sp<DeviceDescriptor> sinkDeviceDesc =
@@ -3319,7 +3550,7 @@
0);
ALOGV("%s patch panel returned %d patchHandle %d", __FUNCTION__,
status, afPatchHandle);
- sourceDesc->mPatchDesc->mPatch = *patchBuilder.patch();
+ sourceDesc->patchDesc()->mPatch = *patchBuilder.patch();
if (status != NO_ERROR) {
ALOGW("%s patch panel could not connect device patch, error %d",
__FUNCTION__, status);
@@ -3329,32 +3560,32 @@
status = startSource(outputDesc, stream, sinkDevice, NULL, &delayMs);
if (status != NO_ERROR) {
- mpClientInterface->releaseAudioPatch(sourceDesc->mPatchDesc->mAfPatchHandle, 0);
+ mpClientInterface->releaseAudioPatch(sourceDesc->patchDesc()->mAfPatchHandle, 0);
return status;
}
- sourceDesc->mSwOutput = outputDesc;
+ sourceDesc->setSwOutput(outputDesc);
if (delayMs != 0) {
usleep(delayMs * 1000);
}
}
- sourceDesc->mPatchDesc->mAfPatchHandle = afPatchHandle;
- addAudioPatch(sourceDesc->mPatchDesc->mHandle, sourceDesc->mPatchDesc);
+ sourceDesc->patchDesc()->mAfPatchHandle = afPatchHandle;
+ addAudioPatch(sourceDesc->patchDesc()->mHandle, sourceDesc->patchDesc());
return NO_ERROR;
}
-status_t AudioPolicyManager::stopAudioSource(audio_patch_handle_t handle)
+status_t AudioPolicyManager::stopAudioSource(audio_port_handle_t portId)
{
- sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueFor(handle);
- ALOGV("%s handle %d", __FUNCTION__, handle);
+ sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueFor(portId);
+ ALOGV("%s port ID %d", __FUNCTION__, portId);
if (sourceDesc == 0) {
- ALOGW("%s unknown source for handle %d", __FUNCTION__, handle);
+ ALOGW("%s unknown source for port ID %d", __FUNCTION__, portId);
return BAD_VALUE;
}
status_t status = disconnectAudioSource(sourceDesc);
- mAudioSources.removeItem(handle);
+ mAudioSources.removeItem(portId);
return status;
}
@@ -3688,20 +3919,20 @@
}
}
-status_t AudioPolicyManager::disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc)
+status_t AudioPolicyManager::disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc)
{
- ALOGV("%s handle %d", __FUNCTION__, sourceDesc->getHandle());
+ ALOGV("%s port Id %d", __FUNCTION__, sourceDesc->portId());
- sp<AudioPatch> patchDesc = mAudioPatches.valueFor(sourceDesc->mPatchDesc->mHandle);
+ sp<AudioPatch> patchDesc = mAudioPatches.valueFor(sourceDesc->patchDesc()->mHandle);
if (patchDesc == 0) {
ALOGW("%s source has no patch with handle %d", __FUNCTION__,
- sourceDesc->mPatchDesc->mHandle);
+ sourceDesc->patchDesc()->mHandle);
return BAD_VALUE;
}
- removeAudioPatch(sourceDesc->mPatchDesc->mHandle);
+ removeAudioPatch(sourceDesc->patchDesc()->mHandle);
- audio_stream_type_t stream = streamTypefromAttributesInt(&sourceDesc->mAttributes);
- sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->mSwOutput.promote();
+ audio_stream_type_t stream = sourceDesc->stream();
+ sp<SwAudioOutputDescriptor> swOutputDesc = sourceDesc->swOutput().promote();
if (swOutputDesc != 0) {
status_t status = stopSource(swOutputDesc, stream, false);
if (status == NO_ERROR) {
@@ -3709,7 +3940,7 @@
}
mpClientInterface->releaseAudioPatch(patchDesc->mAfPatchHandle, 0);
} else {
- sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->mHwOutput.promote();
+ sp<HwAudioOutputDescriptor> hwOutputDesc = sourceDesc->hwOutput().promote();
if (hwOutputDesc != 0) {
// release patch between src device and output device
// close Hwoutput and remove from mHwOutputs
@@ -3720,15 +3951,16 @@
return NO_ERROR;
}
-sp<AudioSourceDescriptor> AudioPolicyManager::getSourceForStrategyOnOutput(
+sp<SourceClientDescriptor> AudioPolicyManager::getSourceForStrategyOnOutput(
audio_io_handle_t output, routing_strategy strategy)
{
- sp<AudioSourceDescriptor> source;
+ sp<SourceClientDescriptor> source;
for (size_t i = 0; i < mAudioSources.size(); i++) {
- sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ audio_attributes_t attributes = sourceDesc->attributes();
routing_strategy sourceStrategy =
- (routing_strategy) getStrategyForAttr(&sourceDesc->mAttributes);
- sp<SwAudioOutputDescriptor> outputDesc = sourceDesc->mSwOutput.promote();
+ (routing_strategy) getStrategyForAttr(&attributes);
+ sp<SwAudioOutputDescriptor> outputDesc = sourceDesc->swOutput().promote();
if (sourceStrategy == strategy && outputDesc != 0 && outputDesc->mIoHandle == output) {
source = sourceDesc;
break;
@@ -4524,6 +4756,7 @@
nextAudioPortGeneration();
+ audio_devices_t device = inputDesc->mDevice;
ssize_t index = mAudioPatches.indexOfKey(inputDesc->getPatchHandle());
if (index >= 0) {
sp<AudioPatch> patchDesc = mAudioPatches.valueAt(index);
@@ -4534,6 +4767,12 @@
inputDesc->close();
mInputs.removeItem(input);
+
+ audio_devices_t primaryInputDevices = availablePrimaryInputDevices();
+ if (((device & primaryInputDevices & ~AUDIO_DEVICE_BIT_IN) != 0) &&
+ mInputs.activeInputsCountOnDevices(primaryInputDevices) == 0) {
+ SoundTrigger::setCaptureState(false);
+ }
}
SortedVector<audio_io_handle_t> AudioPolicyManager::getOutputsForDevice(
@@ -4555,19 +4794,17 @@
return outputs;
}
-void AudioPolicyManager::checkForDeviceAndOutputChanges()
-{
- checkForDeviceAndOutputChanges([](){ return false; });
-}
-
void AudioPolicyManager::checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked)
{
// checkA2dpSuspend must run before checkOutputForAllStrategies so that A2DP
// output is suspended before any tracks are moved to it
checkA2dpSuspend();
checkOutputForAllStrategies();
- if (onOutputsChecked()) checkA2dpSuspend();
+ if (onOutputsChecked != nullptr && onOutputsChecked()) checkA2dpSuspend();
updateDevicesAndOutputs();
+ if (mHwModules.getModuleFromName(AUDIO_HARDWARE_MODULE_ID_MSD) != 0) {
+ setMsdPatch();
+ }
}
void AudioPolicyManager::checkOutputForStrategy(routing_strategy strategy)
@@ -4614,7 +4851,7 @@
setStrategyMute(strategy, true, desc);
setStrategyMute(strategy, false, desc, maxLatency * LATENCY_MUTE_FACTOR, newDevice);
}
- sp<AudioSourceDescriptor> source =
+ sp<SourceClientDescriptor> source =
getSourceForStrategyOnOutput(srcOut, strategy);
if (source != 0){
connectAudioSource(source);
@@ -5578,39 +5815,7 @@
return AUDIO_STREAM_TTS;
}
- // usage to stream type mapping
- switch (attr->usage) {
- case AUDIO_USAGE_MEDIA:
- case AUDIO_USAGE_GAME:
- case AUDIO_USAGE_ASSISTANT:
- case AUDIO_USAGE_ASSISTANCE_NAVIGATION_GUIDANCE:
- return AUDIO_STREAM_MUSIC;
- case AUDIO_USAGE_ASSISTANCE_ACCESSIBILITY:
- return AUDIO_STREAM_ACCESSIBILITY;
- case AUDIO_USAGE_ASSISTANCE_SONIFICATION:
- return AUDIO_STREAM_SYSTEM;
- case AUDIO_USAGE_VOICE_COMMUNICATION:
- return AUDIO_STREAM_VOICE_CALL;
-
- case AUDIO_USAGE_VOICE_COMMUNICATION_SIGNALLING:
- return AUDIO_STREAM_DTMF;
-
- case AUDIO_USAGE_ALARM:
- return AUDIO_STREAM_ALARM;
- case AUDIO_USAGE_NOTIFICATION_TELEPHONY_RINGTONE:
- return AUDIO_STREAM_RING;
-
- case AUDIO_USAGE_NOTIFICATION:
- case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_REQUEST:
- case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_INSTANT:
- case AUDIO_USAGE_NOTIFICATION_COMMUNICATION_DELAYED:
- case AUDIO_USAGE_NOTIFICATION_EVENT:
- return AUDIO_STREAM_NOTIFICATION;
-
- case AUDIO_USAGE_UNKNOWN:
- default:
- return AUDIO_STREAM_MUSIC;
- }
+ return audio_usage_to_stream_type(attr->usage);
}
bool AudioPolicyManager::isValidAttributes(const audio_attributes_t *paa)
@@ -5695,10 +5900,10 @@
void AudioPolicyManager::cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc)
{
for (ssize_t i = (ssize_t)mAudioSources.size() - 1; i >= 0; i--) {
- sp<AudioSourceDescriptor> sourceDesc = mAudioSources.valueAt(i);
- if (sourceDesc->mDevice->equals(deviceDesc)) {
- ALOGV("%s releasing audio source %d", __FUNCTION__, sourceDesc->getHandle());
- stopAudioSource(sourceDesc->getHandle());
+ sp<SourceClientDescriptor> sourceDesc = mAudioSources.valueAt(i);
+ if (sourceDesc->srcDevice()->equals(deviceDesc)) {
+ ALOGV("%s releasing audio source %d", __FUNCTION__, sourceDesc->portId());
+ stopAudioSource(sourceDesc->portId());
}
}
diff --git a/services/audiopolicy/managerdefault/AudioPolicyManager.h b/services/audiopolicy/managerdefault/AudioPolicyManager.h
index e412645..9436767 100644
--- a/services/audiopolicy/managerdefault/AudioPolicyManager.h
+++ b/services/audiopolicy/managerdefault/AudioPolicyManager.h
@@ -31,6 +31,7 @@
#include <utils/SortedVector.h>
#include <media/AudioParameter.h>
#include <media/AudioPolicy.h>
+#include <media/PatchBuilder.h>
#include "AudioPolicyInterface.h"
#include <AudioPolicyManagerInterface.h>
@@ -120,15 +121,9 @@
audio_output_flags_t *flags,
audio_port_handle_t *selectedDeviceId,
audio_port_handle_t *portId);
- virtual status_t startOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session);
- virtual status_t stopOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session);
- virtual void releaseOutput(audio_io_handle_t output,
- audio_stream_type_t stream,
- audio_session_t session);
+ virtual status_t startOutput(audio_port_handle_t portId);
+ virtual status_t stopOutput(audio_port_handle_t portId);
+ virtual void releaseOutput(audio_port_handle_t portId);
virtual status_t getInputForAttr(const audio_attributes_t *attr,
audio_io_handle_t *input,
audio_session_t session,
@@ -140,16 +135,13 @@
audio_port_handle_t *portId);
// indicates to the audio policy manager that the input starts being used.
- virtual status_t startInput(audio_io_handle_t input,
- audio_session_t session,
+ virtual status_t startInput(audio_port_handle_t portId,
bool silenced,
concurrency_type__mask_t *concurrency);
// indicates to the audio policy manager that the input stops being used.
- virtual status_t stopInput(audio_io_handle_t input,
- audio_session_t session);
- virtual void releaseInput(audio_io_handle_t input,
- audio_session_t session);
+ virtual status_t stopInput(audio_port_handle_t portId);
+ virtual void releaseInput(audio_port_handle_t portId);
virtual void closeAllInputs();
virtual void initStreamVolume(audio_stream_type_t stream,
int indexMin,
@@ -231,9 +223,9 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_patch_handle_t *handle,
+ audio_port_handle_t *portId,
uid_t uid);
- virtual status_t stopAudioSource(audio_patch_handle_t handle);
+ virtual status_t stopAudioSource(audio_port_handle_t portId);
virtual status_t setMasterMono(bool mono);
virtual status_t getMasterMono(bool *mono);
@@ -416,8 +408,7 @@
// if 'onOutputsChecked' callback is provided, it is executed after the outputs
// check via 'checkOutputForAllStrategies'. If the callback returns 'true',
// A2DP suspend status is rechecked.
- void checkForDeviceAndOutputChanges();
- void checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked);
+ void checkForDeviceAndOutputChanges(std::function<bool()> onOutputsChecked = nullptr);
// checks and if necessary changes outputs used for all strategies.
// must be called every time a condition that affects the output choice for a given strategy
@@ -508,13 +499,14 @@
if (!hasPrimaryOutput()) {
return AUDIO_DEVICE_NONE;
}
- return mAvailableInputDevices.getDevicesFromHwModule(mPrimaryOutput->getModuleHandle());
+ return mAvailableInputDevices.getDeviceTypesFromHwModule(
+ mPrimaryOutput->getModuleHandle());
}
uint32_t updateCallRouting(audio_devices_t rxDevice, uint32_t delayMs = 0);
sp<AudioPatch> createTelephonyPatch(bool isRx, audio_devices_t device, uint32_t delayMs);
sp<DeviceDescriptor> findDevice(
- const DeviceVector& devices, audio_devices_t device);
+ const DeviceVector& devices, audio_devices_t device) const;
// if argument "device" is different from AUDIO_DEVICE_NONE, startSource() will force
// the re-evaluation of the output device.
@@ -533,10 +525,10 @@
status_t hasPrimaryOutput() const { return mPrimaryOutput != 0; }
- status_t connectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
- status_t disconnectAudioSource(const sp<AudioSourceDescriptor>& sourceDesc);
+ status_t connectAudioSource(const sp<SourceClientDescriptor>& sourceDesc);
+ status_t disconnectAudioSource(const sp<SourceClientDescriptor>& sourceDesc);
- sp<AudioSourceDescriptor> getSourceForStrategyOnOutput(audio_io_handle_t output,
+ sp<SourceClientDescriptor> getSourceForStrategyOnOutput(audio_io_handle_t output,
routing_strategy strategy);
void cleanUpForDevice(const sp<DeviceDescriptor>& deviceDesc);
@@ -551,6 +543,10 @@
static bool streamsMatchForvolume(audio_stream_type_t stream1,
audio_stream_type_t stream2);
+ void closeSessions(const sp<AudioInputDescriptor>& input, bool activeOnly);
+ void closeSession(const sp<AudioInputDescriptor>& input,
+ const sp<AudioSession>& session);
+
const uid_t mUidCached; // AID_AUDIOSERVER
AudioPolicyClientInterface *mpClientInterface; // audio policy client interface
sp<SwAudioOutputDescriptor> mPrimaryOutput; // primary output descriptor
@@ -591,7 +587,7 @@
sp<AudioPatch> mCallRxPatch;
HwAudioOutputCollection mHwOutputs;
- AudioSourceCollection mAudioSources;
+ SourceClientCollection mAudioSources;
// for supporting "beacon" streams, i.e. streams that only play on speaker, and never
// when something other than STREAM_TTS (a.k.a. "Transmitted Through Speaker") is playing
@@ -624,6 +620,17 @@
status_t getSupportedFormats(audio_io_handle_t ioHandle, FormatVector& formats);
+ // Support for Multi-Stream Decoder (MSD) module
+ sp<DeviceDescriptor> getMsdAudioInDevice() const;
+ audio_devices_t getMsdAudioOutDeviceTypes() const;
+ const AudioPatchCollection getMsdPatches() const;
+ status_t getBestMsdAudioProfileFor(audio_devices_t outputDevice,
+ bool hwAvSync,
+ audio_port_config *sourceConfig,
+ audio_port_config *sinkConfig) const;
+ PatchBuilder buildMsdPatch(audio_devices_t outputDevice) const;
+ status_t setMsdPatch(audio_devices_t outputDevice = AUDIO_DEVICE_NONE);
+
// If any, resolve any "dynamic" fields of an Audio Profiles collection
void updateAudioProfiles(audio_devices_t device, audio_io_handle_t ioHandle,
AudioProfileVector &profiles);
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 859072b..3439c9b 100644
--- a/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
+++ b/services/audiopolicy/service/AudioPolicyInterfaceImpl.cpp
@@ -200,7 +200,7 @@
!modifyPhoneStateAllowed(pid, uid)) {
// If the app tries to play music through the telephony device and doesn't have permission
// the fallback to the default output device.
- mAudioPolicyManager->releaseOutput(*output, *stream, session);
+ mAudioPolicyManager->releaseOutput(*portId);
flags = originalFlags;
*selectedDeviceId = AUDIO_PORT_HANDLE_NONE;
*portId = AUDIO_PORT_HANDLE_NONE;
@@ -245,8 +245,7 @@
}
Mutex::Autolock _l(mLock);
AutoCallerClear acc;
- status_t status = mAudioPolicyManager->startOutput(
- client->io, client->stream, client->session);
+ status_t status = mAudioPolicyManager->startOutput(portId);
if (status == NO_ERROR) {
client->active = true;
}
@@ -255,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;
}
@@ -298,8 +288,7 @@
}
Mutex::Autolock _l(mLock);
AutoCallerClear acc;
- status_t status = mAudioPolicyManager->stopOutput(
- client->io, client->stream, client->session);
+ status_t status = mAudioPolicyManager->stopOutput(portId);
if (status == NO_ERROR) {
client->active = false;
}
@@ -328,8 +317,7 @@
mAudioRecordClients.removeItem(portId);
// called from internal thread: no need to clear caller identity
- mAudioPolicyManager->releaseOutput(
- client->io, client->stream, client->session);
+ mAudioPolicyManager->releaseOutput(portId);
}
status_t AudioPolicyService::getInputForAttr(const audio_attributes_t *attr,
@@ -433,7 +421,7 @@
if (status != NO_ERROR) {
if (status == PERMISSION_DENIED) {
AutoCallerClear acc;
- mAudioPolicyManager->releaseInput(*input, session);
+ mAudioPolicyManager->releaseInput(*portId);
}
return status;
}
@@ -527,8 +515,7 @@
status_t status;
{
AutoCallerClear acc;
- status = mAudioPolicyManager->startInput(
- client->io, client->session, *silenced, &concurrency);
+ status = mAudioPolicyManager->startInput(portId, *silenced, &concurrency);
}
@@ -641,7 +628,7 @@
// finish the recording app op
finishRecording(client->opPackageName, client->uid);
AutoCallerClear acc;
- return mAudioPolicyManager->stopInput(client->io, client->session);
+ return mAudioPolicyManager->stopInput(portId);
}
void AudioPolicyService::releaseInput(audio_port_handle_t portId)
@@ -674,7 +661,7 @@
{
Mutex::Autolock _l(mLock);
AutoCallerClear acc;
- mAudioPolicyManager->releaseInput(client->io, client->session);
+ mAudioPolicyManager->releaseInput(portId);
}
}
@@ -863,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) {
@@ -994,26 +1025,26 @@
}
status_t AudioPolicyService::startAudioSource(const struct audio_port_config *source,
- const audio_attributes_t *attributes,
- audio_patch_handle_t *handle)
+ const audio_attributes_t *attributes,
+ audio_port_handle_t *portId)
{
Mutex::Autolock _l(mLock);
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
AutoCallerClear acc;
- return mAudioPolicyManager->startAudioSource(source, attributes, handle,
+ return mAudioPolicyManager->startAudioSource(source, attributes, portId,
IPCThreadState::self()->getCallingUid());
}
-status_t AudioPolicyService::stopAudioSource(audio_patch_handle_t handle)
+status_t AudioPolicyService::stopAudioSource(audio_port_handle_t portId)
{
Mutex::Autolock _l(mLock);
if (mAudioPolicyManager == NULL) {
return NO_INIT;
}
AutoCallerClear acc;
- return mAudioPolicyManager->stopAudioSource(handle);
+ return mAudioPolicyManager->stopAudioSource(portId);
}
status_t AudioPolicyService::setMasterMono(bool mono)
diff --git a/services/audiopolicy/service/AudioPolicyService.h b/services/audiopolicy/service/AudioPolicyService.h
index d41069e..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,
@@ -184,8 +192,8 @@
virtual status_t startAudioSource(const struct audio_port_config *source,
const audio_attributes_t *attributes,
- audio_patch_handle_t *handle);
- virtual status_t stopAudioSource(audio_patch_handle_t handle);
+ audio_port_handle_t *portId);
+ virtual status_t stopAudioSource(audio_port_handle_t portId);
virtual status_t setMasterMono(bool mono);
virtual status_t getMasterMono(bool *mono);
diff --git a/services/camera/libcameraservice/CameraService.cpp b/services/camera/libcameraservice/CameraService.cpp
index c41de82..b85dd51 100644
--- a/services/camera/libcameraservice/CameraService.cpp
+++ b/services/camera/libcameraservice/CameraService.cpp
@@ -582,7 +582,7 @@
Status CameraService::makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
- bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+ int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
/*out*/sp<BasicClient>* client) {
if (halVersion < 0 || halVersion == deviceVersion) {
@@ -594,7 +594,7 @@
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new CameraClient(cameraService, tmp, packageName,
api1CameraId, facing, clientPid, clientUid,
- getpid(), legacyMode);
+ getpid());
} else { // Camera2 API route
ALOGW("Camera using old HAL version: %d", deviceVersion);
return STATUS_ERROR_FMT(ERROR_DEPRECATED_HAL,
@@ -612,7 +612,7 @@
*client = new Camera2Client(cameraService, tmp, packageName,
cameraId, api1CameraId,
facing, clientPid, clientUid,
- servicePid, legacyMode);
+ servicePid);
} else { // Camera2 API route
sp<hardware::camera2::ICameraDeviceCallbacks> tmp =
static_cast<hardware::camera2::ICameraDeviceCallbacks*>(cameraCb.get());
@@ -636,7 +636,7 @@
sp<ICameraClient> tmp = static_cast<ICameraClient*>(cameraCb.get());
*client = new CameraClient(cameraService, tmp, packageName,
api1CameraId, facing, clientPid, clientUid,
- servicePid, legacyMode);
+ servicePid);
} else {
// Other combinations (e.g. HAL3.x open as HAL2.x) are not supported yet.
ALOGE("Invalid camera HAL version %x: HAL %x device can only be"
@@ -735,8 +735,7 @@
sp<ICameraClient>{nullptr}, id, cameraId,
static_cast<int>(CAMERA_HAL_API_VERSION_UNSPECIFIED),
internalPackageName, uid, USE_CALLING_PID,
- API_1, /*legacyMode*/ false, /*shimUpdateOnly*/ true,
- /*out*/ tmp)
+ API_1, /*shimUpdateOnly*/ true, /*out*/ tmp)
).isOk()) {
ALOGE("%s: Error initializing shim metadata: %s", __FUNCTION__, ret.toString8().string());
}
@@ -1200,8 +1199,7 @@
sp<Client> client = nullptr;
ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId,
CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName, clientUid, clientPid, API_1,
- /*legacyMode*/ false, /*shimUpdateOnly*/ false,
- /*out*/client);
+ /*shimUpdateOnly*/ false, /*out*/client);
if(!ret.isOk()) {
logRejected(id, getCallingPid(), String8(clientPackageName),
@@ -1227,8 +1225,7 @@
Status ret = Status::ok();
sp<Client> client = nullptr;
ret = connectHelper<ICameraClient,Client>(cameraClient, id, api1CameraId, halVersion,
- clientPackageName, clientUid, USE_CALLING_PID, API_1,
- /*legacyMode*/ true, /*shimUpdateOnly*/ false,
+ clientPackageName, clientUid, USE_CALLING_PID, API_1, /*shimUpdateOnly*/ false,
/*out*/client);
if(!ret.isOk()) {
@@ -1256,9 +1253,7 @@
ret = connectHelper<hardware::camera2::ICameraDeviceCallbacks,CameraDeviceClient>(cameraCb, id,
/*api1CameraId*/-1,
CAMERA_HAL_API_VERSION_UNSPECIFIED, clientPackageName,
- clientUid, USE_CALLING_PID, API_2,
- /*legacyMode*/ false, /*shimUpdateOnly*/ false,
- /*out*/client);
+ clientUid, USE_CALLING_PID, API_2, /*shimUpdateOnly*/ false, /*out*/client);
if(!ret.isOk()) {
logRejected(id, getCallingPid(), String8(clientPackageName),
@@ -1273,7 +1268,7 @@
template<class CALLBACK, class CLIENT>
Status CameraService::connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
int api1CameraId, int halVersion, const String16& clientPackageName, int clientUid,
- int clientPid, apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
+ int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly,
/*out*/sp<CLIENT>& device) {
binder::Status ret = binder::Status::ok();
@@ -1358,7 +1353,7 @@
sp<BasicClient> tmp = nullptr;
if(!(ret = makeClient(this, cameraCb, clientPackageName,
cameraId, api1CameraId, facing,
- clientPid, clientUid, getpid(), legacyMode,
+ clientPid, clientUid, getpid(),
halVersion, deviceVersion, effectiveApiLevel,
/*out*/&tmp)).isOk()) {
return ret;
diff --git a/services/camera/libcameraservice/CameraService.h b/services/camera/libcameraservice/CameraService.h
index 8d4bcdb..e4a18d3 100644
--- a/services/camera/libcameraservice/CameraService.h
+++ b/services/camera/libcameraservice/CameraService.h
@@ -585,8 +585,7 @@
template<class CALLBACK, class CLIENT>
binder::Status connectHelper(const sp<CALLBACK>& cameraCb, const String8& cameraId,
int api1CameraId, int halVersion, const String16& clientPackageName,
- int clientUid, int clientPid,
- apiLevel effectiveApiLevel, bool legacyMode, bool shimUpdateOnly,
+ int clientUid, int clientPid, apiLevel effectiveApiLevel, bool shimUpdateOnly,
/*out*/sp<CLIENT>& device);
// Lock guarding camera service state
@@ -844,7 +843,7 @@
static binder::Status makeClient(const sp<CameraService>& cameraService,
const sp<IInterface>& cameraCb, const String16& packageName, const String8& cameraId,
int api1CameraId, int facing, int clientPid, uid_t clientUid, int servicePid,
- bool legacyMode, int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
+ int halVersion, int deviceVersion, apiLevel effectiveApiLevel,
/*out*/sp<BasicClient>* client);
status_t checkCameraAccess(const String16& opPackageName);
diff --git a/services/camera/libcameraservice/api1/Camera2Client.cpp b/services/camera/libcameraservice/api1/Camera2Client.cpp
index c8b3c2f..261cdbf 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.cpp
+++ b/services/camera/libcameraservice/api1/Camera2Client.cpp
@@ -54,8 +54,7 @@
int cameraFacing,
int clientPid,
uid_t clientUid,
- int servicePid,
- bool legacyMode):
+ int servicePid):
Camera2ClientBase(cameraService, cameraClient, clientPackageName,
cameraDeviceId, api1CameraId, cameraFacing,
clientPid, clientUid, servicePid),
@@ -65,8 +64,6 @@
SharedParameters::Lock l(mParameters);
l.mParameters.state = Parameters::DISCONNECTED;
-
- mLegacyMode = legacyMode;
}
status_t Camera2Client::initialize(sp<CameraProviderManager> manager, const String8& monitorTags) {
@@ -1443,7 +1440,7 @@
return OK;
}
-status_t Camera2Client::takePicture(int msgType) {
+status_t Camera2Client::takePicture(int /*msgType*/) {
ATRACE_CALL();
Mutex::Autolock icl(mBinderSerializationLock);
status_t res;
@@ -1542,7 +1539,7 @@
// Need HAL to have correct settings before (possibly) triggering precapture
syncWithDevice();
- res = mCaptureSequencer->startCapture(msgType);
+ res = mCaptureSequencer->startCapture();
if (res != OK) {
ALOGE("%s: Camera %d: Unable to start capture: %s (%d)",
__FUNCTION__, mCameraId, strerror(-res), res);
@@ -1662,27 +1659,6 @@
return OK;
}
- // the camera2 api legacy mode can unconditionally disable the shutter sound
- if (mLegacyMode) {
- ALOGV("%s: Disable shutter sound in legacy mode", __FUNCTION__);
- l.mParameters.playShutterSound = false;
- return OK;
- }
-
- // Disabling shutter sound may not be allowed. In that case only
- // allow the mediaserver process to disable the sound.
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.camera.sound.forced", value, "0");
- if (strncmp(value, "0", 2) != 0) {
- // Disabling shutter sound is not allowed. Deny if the current
- // process is not mediaserver.
- if (getCallingPid() != getpid()) {
- ALOGE("Failed to disable shutter sound. Permission denied (pid %d)",
- getCallingPid());
- return PERMISSION_DENIED;
- }
- }
-
l.mParameters.playShutterSound = false;
return OK;
}
diff --git a/services/camera/libcameraservice/api1/Camera2Client.h b/services/camera/libcameraservice/api1/Camera2Client.h
index 44929c3..a9ea271 100644
--- a/services/camera/libcameraservice/api1/Camera2Client.h
+++ b/services/camera/libcameraservice/api1/Camera2Client.h
@@ -96,8 +96,7 @@
int cameraFacing,
int clientPid,
uid_t clientUid,
- int servicePid,
- bool legacyMode);
+ int servicePid);
virtual ~Camera2Client();
diff --git a/services/camera/libcameraservice/api1/CameraClient.cpp b/services/camera/libcameraservice/api1/CameraClient.cpp
index f1203f9..ce44efe 100644
--- a/services/camera/libcameraservice/api1/CameraClient.cpp
+++ b/services/camera/libcameraservice/api1/CameraClient.cpp
@@ -40,7 +40,7 @@
const String16& clientPackageName,
int cameraId, int cameraFacing,
int clientPid, int clientUid,
- int servicePid, bool legacyMode):
+ int servicePid):
Client(cameraService, cameraClient, clientPackageName,
String8::format("%d", cameraId), cameraId, cameraFacing, clientPid,
clientUid, servicePid)
@@ -57,7 +57,6 @@
// Callback is disabled by default
mPreviewCallbackFlag = CAMERA_FRAME_CALLBACK_FLAG_NOOP;
mOrientation = getOrientation(0, mCameraFacing == CAMERA_FACING_FRONT);
- mLegacyMode = legacyMode;
mPlayShutterSound = true;
LOG1("CameraClient::CameraClient X (pid %d, id %d)", callingPid, cameraId);
}
@@ -715,26 +714,6 @@
return OK;
}
- // the camera2 api legacy mode can unconditionally disable the shutter sound
- if (mLegacyMode) {
- ALOGV("%s: Disable shutter sound in legacy mode", __FUNCTION__);
- mPlayShutterSound = false;
- return OK;
- }
-
- // Disabling shutter sound may not be allowed. In that case only
- // allow the mediaserver process to disable the sound.
- char value[PROPERTY_VALUE_MAX];
- property_get("ro.camera.sound.forced", value, "0");
- if (strcmp(value, "0") != 0) {
- // Disabling shutter sound is not allowed. Deny if the current
- // process is not mediaserver.
- if (getCallingPid() != getpid()) {
- ALOGE("Failed to disable shutter sound. Permission denied (pid %d)", getCallingPid());
- return PERMISSION_DENIED;
- }
- }
-
mPlayShutterSound = false;
return OK;
}
diff --git a/services/camera/libcameraservice/api1/CameraClient.h b/services/camera/libcameraservice/api1/CameraClient.h
index 1910536..9530b6c 100644
--- a/services/camera/libcameraservice/api1/CameraClient.h
+++ b/services/camera/libcameraservice/api1/CameraClient.h
@@ -68,8 +68,7 @@
int cameraFacing,
int clientPid,
int clientUid,
- int servicePid,
- bool legacyMode = false);
+ int servicePid);
~CameraClient();
virtual status_t initialize(sp<CameraProviderManager> manager,
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
index 1ee216f..f42cdd3 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.cpp
@@ -50,8 +50,7 @@
mStateTransitionCount(0),
mTriggerId(0),
mTimeoutCount(0),
- mCaptureId(Camera2Client::kCaptureRequestIdStart),
- mMsgType(0) {
+ mCaptureId(Camera2Client::kCaptureRequestIdStart) {
ALOGV("%s", __FUNCTION__);
}
@@ -64,7 +63,7 @@
mZslProcessor = processor;
}
-status_t CaptureSequencer::startCapture(int msgType) {
+status_t CaptureSequencer::startCapture() {
ALOGV("%s", __FUNCTION__);
ATRACE_CALL();
Mutex::Autolock l(mInputMutex);
@@ -73,7 +72,6 @@
return INVALID_OPERATION;
}
if (!mStartCapture) {
- mMsgType = msgType;
mStartCapture = true;
mStartCaptureSignal.signal();
}
@@ -386,7 +384,7 @@
SharedParameters::Lock l(client->getParameters());
/* warning: this also locks a SharedCameraCallbacks */
- shutterNotifyLocked(l.mParameters, client, mMsgType);
+ shutterNotifyLocked(l.mParameters, client);
mShutterNotified = true;
mTimeoutCount = kMaxTimeoutsForCaptureEnd;
return STANDARD_CAPTURE_WAIT;
@@ -610,7 +608,7 @@
if (!mShutterNotified) {
SharedParameters::Lock l(client->getParameters());
/* warning: this also locks a SharedCameraCallbacks */
- shutterNotifyLocked(l.mParameters, client, mMsgType);
+ shutterNotifyLocked(l.mParameters, client);
mShutterNotified = true;
}
} else if (mTimeoutCount <= 0) {
@@ -715,12 +713,11 @@
}
/*static*/ void CaptureSequencer::shutterNotifyLocked(const Parameters ¶ms,
- const sp<Camera2Client>& client, int msgType) {
+ const sp<Camera2Client>& client) {
ATRACE_CALL();
if (params.state == Parameters::STILL_CAPTURE
- && params.playShutterSound
- && (msgType & CAMERA_MSG_SHUTTER)) {
+ && params.playShutterSound) {
client->getCameraService()->playSound(CameraService::SOUND_SHUTTER);
}
diff --git a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
index f2e3750..c23b12d 100644
--- a/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
+++ b/services/camera/libcameraservice/api1/client2/CaptureSequencer.h
@@ -51,7 +51,7 @@
void setZslProcessor(const wp<ZslProcessor>& processor);
// Begin still image capture
- status_t startCapture(int msgType);
+ status_t startCapture();
// Wait until current image capture completes; returns immediately if no
// capture is active. Returns TIMED_OUT if capture does not complete during
@@ -145,7 +145,6 @@
bool mAeInPrecapture;
int32_t mCaptureId;
- int mMsgType;
// Main internal methods
@@ -172,7 +171,7 @@
// Emit Shutter/Raw callback to java, and maybe play a shutter sound
static void shutterNotifyLocked(const Parameters ¶ms,
- const sp<Camera2Client>& client, int msgType);
+ const sp<Camera2Client>& client);
};
}; // namespace camera2
diff --git a/services/camera/libcameraservice/device3/Camera3Device.cpp b/services/camera/libcameraservice/device3/Camera3Device.cpp
index d4f78e0..4c6718c 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Device.cpp
@@ -2173,8 +2173,14 @@
res = stream->finishConfiguration();
if (res != OK) {
- SET_ERR_L("Can't finish configuring output stream %d: %s (%d)",
- stream->getId(), strerror(-res), res);
+ // If finishConfiguration fails due to abandoned surface, do not set
+ // device to error state.
+ bool isSurfaceAbandoned =
+ (res == NO_INIT || res == DEAD_OBJECT) && stream->isAbandoned();
+ if (!isSurfaceAbandoned) {
+ SET_ERR_L("Can't finish configuring output stream %d: %s (%d)",
+ stream->getId(), strerror(-res), res);
+ }
return res;
}
}
@@ -2391,9 +2397,16 @@
//present streams end up with outstanding buffers that will
//not get drained.
internalUpdateStatusLocked(STATUS_ACTIVE);
+ } else if (rc == DEAD_OBJECT) {
+ // DEAD_OBJECT can be returned if either the consumer surface is
+ // abandoned, or the HAL has died.
+ // - If the HAL has died, configureStreamsLocked call will set
+ // device to error state,
+ // - If surface is abandoned, we should not set device to error
+ // state.
+ ALOGE("Failed to re-configure camera due to abandoned surface");
} else {
- setErrorStateLocked("%s: Failed to re-configure camera: %d",
- __FUNCTION__, rc);
+ SET_ERR_L("Failed to re-configure camera: %d", rc);
}
} else {
ALOGE("%s: Failed to pause streaming: %d", __FUNCTION__, rc);
@@ -2527,6 +2540,9 @@
CLOGE("Can't finish configuring input stream %d: %s (%d)",
mInputStream->getId(), strerror(-res), res);
cancelStreamsConfigurationLocked();
+ if ((res == NO_INIT || res == DEAD_OBJECT) && mInputStream->isAbandoned()) {
+ return DEAD_OBJECT;
+ }
return BAD_VALUE;
}
}
@@ -2540,6 +2556,9 @@
CLOGE("Can't finish configuring output stream %d: %s (%d)",
outputStream->getId(), strerror(-res), res);
cancelStreamsConfigurationLocked();
+ if ((res == NO_INIT || res == DEAD_OBJECT) && outputStream->isAbandoned()) {
+ return DEAD_OBJECT;
+ }
return BAD_VALUE;
}
}
@@ -2719,13 +2738,13 @@
status_t Camera3Device::registerInFlight(uint32_t frameNumber,
int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
bool hasAppCallback, nsecs_t maxExpectedDuration,
- std::set<String8>& physicalCameraIds) {
+ std::set<String8>& physicalCameraIds, bool isStillCapture) {
ATRACE_CALL();
Mutex::Autolock l(mInFlightLock);
ssize_t res;
res = mInFlightMap.add(frameNumber, InFlightRequest(numBuffers, resultExtras, hasInput,
- hasAppCallback, maxExpectedDuration, physicalCameraIds));
+ hasAppCallback, maxExpectedDuration, physicalCameraIds, isStillCapture));
if (res < 0) return res;
if (mInFlightMap.size() == 1) {
@@ -2791,6 +2810,10 @@
if (request.numBuffersLeft == 0 &&
(request.skipResultMetadata ||
(request.haveResultMetadata && shutterTimestamp != 0))) {
+ if (request.stillCapture) {
+ ATRACE_ASYNC_END("still capture", frameNumber);
+ }
+
ATRACE_ASYNC_END("frame capture", frameNumber);
// Sanity check - if sensor timestamp matches shutter timestamp in the
@@ -4920,12 +4943,21 @@
if (batchedRequest && i != mNextRequests.size()-1) {
hasCallback = false;
}
+ bool isStillCapture = false;
+ if (!mNextRequests[0].captureRequest->mSettingsList.begin()->metadata.isEmpty()) {
+ camera_metadata_ro_entry_t e = camera_metadata_ro_entry_t();
+ find_camera_metadata_ro_entry(halRequest->settings, ANDROID_CONTROL_CAPTURE_INTENT, &e);
+ if ((e.count > 0) && (e.data.u8[0] == ANDROID_CONTROL_CAPTURE_INTENT_STILL_CAPTURE)) {
+ isStillCapture = true;
+ ATRACE_ASYNC_BEGIN("still capture", mNextRequests[i].halRequest.frame_number);
+ }
+ }
res = parent->registerInFlight(halRequest->frame_number,
totalNumBuffers, captureRequest->mResultExtras,
/*hasInput*/halRequest->input_buffer != NULL,
hasCallback,
calculateMaxExpectedDuration(halRequest->settings),
- requestedPhysicalCameras);
+ requestedPhysicalCameras, isStillCapture);
ALOGVV("%s: registered in flight requestId = %" PRId32 ", frameNumber = %" PRId64
", burstId = %" PRId32 ".",
__FUNCTION__,
diff --git a/services/camera/libcameraservice/device3/Camera3Device.h b/services/camera/libcameraservice/device3/Camera3Device.h
index 96212ab..51e1fb0 100644
--- a/services/camera/libcameraservice/device3/Camera3Device.h
+++ b/services/camera/libcameraservice/device3/Camera3Device.h
@@ -994,6 +994,9 @@
// Map of physicalCameraId <-> Metadata
std::vector<PhysicalCaptureResultInfo> physicalMetadatas;
+ // Indicates a still capture request.
+ bool stillCapture;
+
// Default constructor needed by KeyedVector
InFlightRequest() :
shutterTimestamp(0),
@@ -1004,12 +1007,13 @@
hasInputBuffer(false),
hasCallback(true),
maxExpectedDuration(kDefaultExpectedDuration),
- skipResultMetadata(false) {
+ skipResultMetadata(false),
+ stillCapture(false) {
}
InFlightRequest(int numBuffers, CaptureResultExtras extras, bool hasInput,
bool hasAppCallback, nsecs_t maxDuration,
- const std::set<String8>& physicalCameraIdSet) :
+ const std::set<String8>& physicalCameraIdSet, bool isStillCapture) :
shutterTimestamp(0),
sensorTimestamp(0),
requestStatus(OK),
@@ -1020,7 +1024,8 @@
hasCallback(hasAppCallback),
maxExpectedDuration(maxDuration),
skipResultMetadata(false),
- physicalCameraIds(physicalCameraIdSet) {
+ physicalCameraIds(physicalCameraIdSet),
+ stillCapture(isStillCapture) {
}
};
@@ -1034,10 +1039,10 @@
nsecs_t mExpectedInflightDuration = 0;
int mInFlightStatusId;
-
status_t registerInFlight(uint32_t frameNumber,
int32_t numBuffers, CaptureResultExtras resultExtras, bool hasInput,
- bool callback, nsecs_t maxExpectedDuration, std::set<String8>& physicalCameraIds);
+ bool callback, nsecs_t maxExpectedDuration, std::set<String8>& physicalCameraIds,
+ bool isStillCapture);
/**
* Returns the maximum expected time it'll take for all currently in-flight
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.cpp b/services/camera/libcameraservice/device3/Camera3Stream.cpp
index 1105b75..6030d15 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.cpp
+++ b/services/camera/libcameraservice/device3/Camera3Stream.cpp
@@ -331,7 +331,14 @@
status_t res;
res = configureQueueLocked();
- if (res != OK) {
+ // configureQueueLocked could return error in case of abandoned surface.
+ // Treat as non-fatal error.
+ if (res == NO_INIT || res == DEAD_OBJECT) {
+ ALOGE("%s: Unable to configure stream %d queue (non-fatal): %s (%d)",
+ __FUNCTION__, mId, strerror(-res), res);
+ mState = STATE_ABANDONED;
+ return res;
+ } else if (res != OK) {
ALOGE("%s: Unable to configure stream %d queue: %s (%d)",
__FUNCTION__, mId, strerror(-res), res);
mState = STATE_ERROR;
diff --git a/services/camera/libcameraservice/device3/Camera3Stream.h b/services/camera/libcameraservice/device3/Camera3Stream.h
index a60cb56..4ddcf1a 100644
--- a/services/camera/libcameraservice/device3/Camera3Stream.h
+++ b/services/camera/libcameraservice/device3/Camera3Stream.h
@@ -482,6 +482,7 @@
// after the HAL has provided usage and max_buffers values. After this call,
// the stream must be ready to produce all buffers for registration with
// HAL.
+ // Returns NO_INIT or DEAD_OBJECT if the queue has been abandoned.
virtual status_t configureQueueLocked() = 0;
// Get the total number of buffers in the queue
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) &&